Compare commits
13 Commits
9dfb1342e5
...
master
Author | SHA1 | Date | |
---|---|---|---|
2e39587d3c | |||
edb3f22044 | |||
791b601dec | |||
1082dd7a71 | |||
96d457ab11 | |||
a2a352efe0 | |||
7647399159 | |||
1f4f8003f2 | |||
e6ac97bd3e | |||
79a385b9d4 | |||
2419f308fc | |||
ab073fe7ec | |||
f09b8c893d |
12
.drone.yml
12
.drone.yml
@ -3,12 +3,12 @@ type: docker
|
|||||||
name: default
|
name: default
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Build with node
|
# - name: Build with node
|
||||||
image: node:19
|
# image: node:19
|
||||||
commands:
|
# commands:
|
||||||
- yarn install
|
# - yarn install
|
||||||
- yarn build
|
# - yarn build
|
||||||
- name: Publish to docker
|
- name: Build and publish to docker
|
||||||
image: plugins/docker
|
image: plugins/docker
|
||||||
settings:
|
settings:
|
||||||
username:
|
username:
|
||||||
|
36
.github/workflows/ci.yml
vendored
Normal file
36
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# .github/workflows/ci.yml
|
||||||
|
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
MY_DOCKER_USERNAME: ${{ secrets.MY_DOCKER_USERNAME }}
|
||||||
|
MY_DOCKER_PASSWORD: ${{ secrets.MY_DOCKER_PASSWORD }}
|
||||||
|
FORCE_COLOR: 1
|
||||||
|
steps:
|
||||||
|
- uses: https://github.com/earthly/actions-setup@v1
|
||||||
|
with:
|
||||||
|
version: v0.7.0
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Put back the git branch into git (Earthly uses it for tagging)
|
||||||
|
run: |
|
||||||
|
branch=""
|
||||||
|
if [ -n "$GITHUB_HEAD_REF" ]; then
|
||||||
|
branch="$GITHUB_HEAD_REF"
|
||||||
|
else
|
||||||
|
branch="${GITHUB_REF##*/}"
|
||||||
|
fi
|
||||||
|
git checkout -b "$branch" || true
|
||||||
|
- name: Docker Login
|
||||||
|
run: docker login git.hibas.dev --username "$MY_DOCKER_USERNAME" --password "$MY_DOCKER_PASSWORD"
|
||||||
|
- name: Earthly version
|
||||||
|
run: earthly --version
|
||||||
|
- name: Run build
|
||||||
|
run: earthly --push +docker-multi
|
29
Dockerfile
29
Dockerfile
@ -1,29 +0,0 @@
|
|||||||
FROM node:19 as builder
|
|
||||||
|
|
||||||
RUN mkdir -p /app
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
COPY ["package.json", "yarn.lock", ".yarnrc.yml", "/app/"]
|
|
||||||
COPY ["src", "/app/src"]
|
|
||||||
|
|
||||||
RUN yarn install
|
|
||||||
RUN yarn build
|
|
||||||
|
|
||||||
FROM node:19
|
|
||||||
|
|
||||||
LABEL maintainer="Fabian Stamm <dev@fabianstamm.de>"
|
|
||||||
|
|
||||||
RUN mkdir -p /app
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
|
|
||||||
COPY ["package.json", "yarn.lock", ".yarnrc.yml", "/usr/src/app/"]
|
|
||||||
|
|
||||||
RUN yarn install
|
|
||||||
|
|
||||||
COPY --from=builder lib/ /app/lib
|
|
||||||
|
|
||||||
VOLUME [ "/app/logs", "/app/persist"]
|
|
||||||
|
|
||||||
CMD ["node", "lib/index.js"]
|
|
19
Earthfile
Normal file
19
Earthfile
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
VERSION 0.7
|
||||||
|
FROM node:lts-alpine3.18
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
docker-multi:
|
||||||
|
BUILD --platform linux/amd64 --platform linux/arm64 +docker
|
||||||
|
|
||||||
|
docker:
|
||||||
|
COPY package.json yarn.lock .yarnrc.yml tsconfig.json .
|
||||||
|
COPY src ./src
|
||||||
|
COPY .yarn ./.yarn
|
||||||
|
RUN ls -l
|
||||||
|
RUN yarn install
|
||||||
|
RUN yarn build
|
||||||
|
WORKDIR /build
|
||||||
|
ENTRYPOINT ["node", "lib/index.js"]
|
||||||
|
ARG EARTHLY_TARGET_TAG
|
||||||
|
ARG TAG=$EARTHLY_TARGET_TAG
|
||||||
|
SAVE IMAGE --push git.hibas.dev/hibas123/telegram-rss:$TAG
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rss-telegram-bot",
|
"name": "rss-telegram-bot",
|
||||||
"version": "1.0.8",
|
"version": "2.0.3",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"author": "Fabian Stamm <dev@fabianstamm.de>",
|
"author": "Fabian Stamm <dev@fabianstamm.de>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -42,4 +42,4 @@
|
|||||||
"typeorm": "^0.3.15"
|
"typeorm": "^0.3.15"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@3.5.0"
|
"packageManager": "yarn@3.5.0"
|
||||||
}
|
}
|
@ -41,7 +41,15 @@ function calculateHash(item: RSSFeedItem) {
|
|||||||
|
|
||||||
async function checkFeed(feed: Feed) {
|
async function checkFeed(feed: Feed) {
|
||||||
Logging.info("Fetching feed: %s", feed.url);
|
Logging.info("Fetching feed: %s", feed.url);
|
||||||
let data = await fetch(feed.url).then(res => res.text());
|
let timeoutSignal = new AbortController();
|
||||||
|
let to = setTimeout(() => {
|
||||||
|
Logging.warn("Feed %s fetch timed out", feed.url);
|
||||||
|
timeoutSignal.abort();
|
||||||
|
}, 10000);
|
||||||
|
let data = await fetch(feed.url, {
|
||||||
|
signal: timeoutSignal.signal
|
||||||
|
}).then(res => res.text());
|
||||||
|
clearTimeout(to);
|
||||||
Logging.info("Received Data");
|
Logging.info("Received Data");
|
||||||
Logging.debug(data);
|
Logging.debug(data);
|
||||||
|
|
||||||
@ -90,11 +98,12 @@ async function checkFeed(feed: Feed) {
|
|||||||
// feed.addItems(newItems);
|
// feed.addItems(newItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const FEED_CHECK_INTERVAL = 1000 * 60 * 60;
|
const FEED_CHECK_INTERVAL = 1000 * 60 * 15;
|
||||||
const FEED_CHECK_INTERVAL = 1000 * 30;
|
// const FEED_CHECK_INTERVAL = 1000 * 30;
|
||||||
|
|
||||||
export default async function checkFeeds() {
|
export default async function checkFeeds() {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
Logging.info("Checking for feeds to synchronize");
|
||||||
let feed = await AppDataSource.manager.findOne(Feed, {
|
let feed = await AppDataSource.manager.findOne(Feed, {
|
||||||
where: {
|
where: {
|
||||||
lastCheck: LessThan(new Date(Date.now() - FEED_CHECK_INTERVAL))
|
lastCheck: LessThan(new Date(Date.now() - FEED_CHECK_INTERVAL))
|
||||||
@ -105,13 +114,18 @@ export default async function checkFeeds() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!feed) {
|
if (!feed) {
|
||||||
await new Promise(y => setTimeout(y, 1000));
|
await new Promise(y => setTimeout(y, 10000));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
await checkFeed(feed);
|
|
||||||
|
|
||||||
feed.lastCheck = new Date();
|
feed.lastCheck = new Date();
|
||||||
await AppDataSource.manager.save(feed);
|
await AppDataSource.manager.save(feed);
|
||||||
|
|
||||||
|
Promise.resolve().then(async () => {
|
||||||
|
await checkFeed(feed);
|
||||||
|
}).catch(err => {
|
||||||
|
Logging.warn("Error while checking feed: %s", feed.url);
|
||||||
|
Logging.error(err);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
78
src/import_old.ts
Normal file
78
src/import_old.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { readFileSync } from "fs";
|
||||||
|
import { AppDataSource, appDataSourceReady } from "./data_source.js";
|
||||||
|
import { Feed } from "./models/Feed.js";
|
||||||
|
import { Post } from "./models/Post.js";
|
||||||
|
import { User } from "./models/User.js";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
interface IOld {
|
||||||
|
feeds: {
|
||||||
|
url: string;
|
||||||
|
oldEntries: string[];
|
||||||
|
subscriber: number[];
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
appDataSourceReady.then(async () => {
|
||||||
|
let old = JSON.parse(readFileSync("./old.json", "utf-8")) as IOld;
|
||||||
|
|
||||||
|
for (let feed of old.feeds) {
|
||||||
|
let f = await AppDataSource.manager.findOne(Feed, {
|
||||||
|
where: {
|
||||||
|
url: feed.url
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
f = AppDataSource.manager.create(Feed, {
|
||||||
|
url: feed.url,
|
||||||
|
lastCheck: new Date(0),
|
||||||
|
oldEntries: [],
|
||||||
|
subscriber: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
await AppDataSource.manager.save(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let oldEntry of feed.oldEntries) {
|
||||||
|
let existing = await AppDataSource.manager.findOne(Post, {
|
||||||
|
where: {
|
||||||
|
feed: f,
|
||||||
|
hash: oldEntry
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!existing) {
|
||||||
|
|
||||||
|
let post = AppDataSource.manager.create(Post, {
|
||||||
|
feed: f,
|
||||||
|
hash: oldEntry
|
||||||
|
})
|
||||||
|
|
||||||
|
await AppDataSource.manager.save(post);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let subscriber of feed.subscriber) {
|
||||||
|
let user = await AppDataSource.manager.findOne(User, {
|
||||||
|
where: {
|
||||||
|
chatid: subscriber
|
||||||
|
},
|
||||||
|
relations: {
|
||||||
|
feeds: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
user = AppDataSource.manager.create(User, {
|
||||||
|
chatid: subscriber,
|
||||||
|
feeds: [f],
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
user.feeds.push(f)
|
||||||
|
}
|
||||||
|
await AppDataSource.manager.save(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
@ -62,26 +62,37 @@ bot.command("delete", botHandler(async ctx => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
bot.on("callback_query", botHandler(async ctx => {
|
bot.on("callback_query", botHandler(async ctx => {
|
||||||
Logging.info("Callback Query:");
|
Logging.info("Callback Query received");
|
||||||
Logging.info(ctx.callbackQuery);
|
|
||||||
|
|
||||||
const remove_options = () => {
|
const remove_options = (message: string) => {
|
||||||
ctx.editMessageReplyMarkup({
|
ctx.editMessageReplyMarkup({
|
||||||
inline_keyboard: []
|
inline_keyboard: [],
|
||||||
})
|
})
|
||||||
|
ctx.editMessageText(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = (ctx.callbackQuery as any).data;
|
let data = (ctx.callbackQuery as any).data;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
ctx.answerCbQuery("Invalid data");
|
ctx.answerCbQuery("Invalid data");
|
||||||
remove_options();
|
remove_options("Delete failed. Invalid data received.");
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let [action, id] = data.split(":");
|
let [action, id] = data.split(":");
|
||||||
if (!action || !id) {
|
if (!action || !id) {
|
||||||
ctx.answerCbQuery("Invalid data");
|
ctx.answerCbQuery("Invalid data");
|
||||||
remove_options();
|
remove_options("Delete failed. Invalid data received.");
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let feed = await AppDataSource.manager.findOne(Feed, {
|
||||||
|
where: {
|
||||||
|
id: Number(id)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!feed) {
|
||||||
|
ctx.answerCbQuery("Invalid action");
|
||||||
|
remove_options("Delete failed. Feed not available.");
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,12 +112,12 @@ bot.on("callback_query", botHandler(async ctx => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx.answerCbQuery("Invalid action");
|
ctx.answerCbQuery("Invalid action");
|
||||||
remove_options();
|
remove_options("Delete failed. Invalid data received.");
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.answerCbQuery("Success");
|
ctx.answerCbQuery("Success");
|
||||||
remove_options();
|
remove_options("Deleted feed: " + feed.url);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
bot.on(message("text", "entities"), botHandler(async ctx => {
|
bot.on(message("text", "entities"), botHandler(async ctx => {
|
||||||
|
Reference in New Issue
Block a user