Compare commits
67 Commits
4fb335cd7b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f72b04d49b | |||
| 8157ca00a8 | |||
| 5c5e2ee5ba | |||
| cc4abb3385 | |||
| 299530b0dd | |||
| b8db58a71a | |||
| 8dce37fe08 | |||
| 593083d994 | |||
| d816568522 | |||
| 1361fab0ad | |||
| f6db2d5d7a | |||
| df433c1951 | |||
| c088d7c4a5 | |||
| 66fb9cef85 | |||
| 789803da59 | |||
| 8d8b7f4c3a | |||
| 0177aae79a | |||
| 8076b984f5 | |||
| 2050e61706 | |||
| 465fbf96c9 | |||
| 30546606d7 | |||
| 98f954aa82 | |||
| a0107eeb27 | |||
| 74d32d518e | |||
| 926df56972 | |||
| 59ff831b45 | |||
| f2aa778722 | |||
| 3a03bbc47b | |||
| 2ba2cec399 | |||
| 20a72ed0f3 | |||
| 82476d4e1f | |||
| 845c5cd7df | |||
| d71e736bee | |||
| 10d8f02160 | |||
| e0754cd03b | |||
| 10c84e1582 | |||
| b8d966410a | |||
| 8021a9561e | |||
| 1b38aad76a | |||
| bfc0f1e59a | |||
| 57b64e9b5e | |||
| aa0be3b56c | |||
| 10126edd2b | |||
| f7751b23a8 | |||
| ffad9bfe90 | |||
| d7e71600a6 | |||
| c2ea85acd1 | |||
| c16c46ceeb | |||
| 1f22a05944 | |||
| 1d7d38927d | |||
| 191c1ceb91 | |||
| 98376d93d6 | |||
| 5f55806497 | |||
| 370f601bd8 | |||
| 3ab71df73f | |||
| 2a8a054385 | |||
| b8ab3af485 | |||
| 3ed97ecabc | |||
| db9079c8ea | |||
| f061275ce6 | |||
| 5d5c96147c | |||
| 0c2e08854e | |||
| 07c7cec668 | |||
| dd06eb3f7c | |||
| f18685c371 | |||
| 850a156e1d | |||
| 6f8d49b21b |
@@ -8,3 +8,6 @@ SERVER_HOST=localhost
|
||||
SERVER_PORT=3000
|
||||
BOT_ADMINS=[1]
|
||||
GROUP_IDS=-
|
||||
GRAPHQL_URL=http://localhost:3000/api/graphql
|
||||
GRAPHQL_API_TOKEN="token-here"
|
||||
GRAPHQL_MUTATION_KEY="token-here"
|
||||
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
|
||||
env:
|
||||
REGISTRY: gitea.lucids-cove.duckdns.org
|
||||
OWNER: lcm
|
||||
OWNER: wkc
|
||||
IMAGE_NAME: no-twitter-bot
|
||||
|
||||
jobs:
|
||||
@@ -18,7 +18,6 @@ jobs:
|
||||
matrix:
|
||||
node-version: [20.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: "Base requirements"
|
||||
run: |
|
||||
# packages
|
||||
@@ -26,6 +25,7 @@ jobs:
|
||||
# ansible collections
|
||||
ansible-galaxy collection install community.general --force
|
||||
ansible-galaxy collection install ansible.posix --force
|
||||
- uses: actions/checkout@v4
|
||||
- name: Enable Corepack
|
||||
run: npm install -g corepack && corepack enable
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
@@ -34,6 +34,8 @@ jobs:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ env.OWNER }}
|
||||
password: ${{ secrets.TOKEN }}
|
||||
- name: Docker Hub Login
|
||||
run: echo "${{ secrets.DOCKER_HUB_TOKEN }}" | docker login -u "${{ secrets.DOCKER_HUB_USERNAME }}" --password-stdin
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Setup Docker buildx
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -136,3 +136,5 @@ data/
|
||||
# Ignore SQLite database
|
||||
*.db
|
||||
*.db-journal
|
||||
|
||||
build
|
||||
@@ -1,9 +1,21 @@
|
||||
services:
|
||||
bot:
|
||||
no-twitter-bot:
|
||||
image: gitea.lucids-cove.duckdns.org/wkc/no-twitter-bot:latest
|
||||
container_name: no-twitter-bot
|
||||
environment:
|
||||
- BOT_TOKEN=${BOT_TOKEN}
|
||||
- BOT_MODE=${BOT_MODE}
|
||||
- LOG_LEVEL=${LOG_LEVEL}
|
||||
- DEBUG=${DEBUG}
|
||||
- BOT_WEBHOOK=${BOT_WEBHOOK}
|
||||
- BOT_WEBHOOK_SECRET=${BOT_WEBHOOK_SECRET}
|
||||
- SERVER_HOST=${SERVER_HOST}
|
||||
- SERVER_PORT=${SERVER_PORT}
|
||||
- BOT_ADMINS=${BOT_ADMINS}
|
||||
- GROUP_IDS=${GROUP_IDS}
|
||||
- GRAPHQL_URL=${GRAPHQL_URL}
|
||||
ports:
|
||||
- "3000:80"
|
||||
volumes:
|
||||
- ".:/usr/src"
|
||||
env_file:
|
||||
- .env.bot.dev
|
||||
command: npm run dev
|
||||
|
||||
@@ -1,4 +1,19 @@
|
||||
services:
|
||||
bot:
|
||||
env_file:
|
||||
- .env.bot.prod
|
||||
no-twitter-bot:
|
||||
image: gitea.lucids-cove.duckdns.org/wkc/no-twitter-bot:latest
|
||||
container_name: no-twitter-bot
|
||||
# env_file: stack.env
|
||||
environment:
|
||||
- BOT_TOKEN=${BOT_TOKEN}
|
||||
- BOT_MODE=${BOT_MODE}
|
||||
- LOG_LEVEL=${LOG_LEVEL}
|
||||
- DEBUG=${DEBUG}
|
||||
- BOT_WEBHOOK=${BOT_WEBHOOK}
|
||||
- BOT_WEBHOOK_SECRET=${BOT_WEBHOOK_SECRET}
|
||||
- SERVER_HOST=${SERVER_HOST}
|
||||
- SERVER_PORT=${SERVER_PORT}
|
||||
- BOT_ADMINS=${BOT_ADMINS}
|
||||
- GROUP_IDS=${GROUP_IDS}
|
||||
- GRAPHQL_URL=${GRAPHQL_URL}
|
||||
build:
|
||||
context: .
|
||||
|
||||
17
compose.yml
17
compose.yml
@@ -1,6 +1,19 @@
|
||||
services:
|
||||
bot:
|
||||
no-twitter-bot:
|
||||
image: gitea.lucids-cove.duckdns.org/wkc/no-twitter-bot:latest
|
||||
container_name: no-twitter-bot
|
||||
env_file: stack.env
|
||||
# env_file: stack.env
|
||||
environment:
|
||||
- BOT_TOKEN=${BOT_TOKEN}
|
||||
- BOT_MODE=${BOT_MODE}
|
||||
- LOG_LEVEL=${LOG_LEVEL}
|
||||
- DEBUG=${DEBUG}
|
||||
- BOT_WEBHOOK=${BOT_WEBHOOK}
|
||||
- BOT_WEBHOOK_SECRET=${BOT_WEBHOOK_SECRET}
|
||||
- SERVER_HOST=${SERVER_HOST}
|
||||
- SERVER_PORT=${SERVER_PORT}
|
||||
- BOT_ADMINS=${BOT_ADMINS}
|
||||
- GROUP_IDS=${GROUP_IDS}
|
||||
- GRAPHQL_URL=${GRAPHQL_URL}
|
||||
build:
|
||||
context: .
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import globals from "globals";
|
||||
import pluginJs from "@eslint/js";
|
||||
import { defineConfig, globalIgnores } from "eslint/config";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
export default defineConfig([
|
||||
globalIgnores(["build/"]),
|
||||
{ files: ["**/*.{js,mjs,cjs,ts}"] },
|
||||
{ languageOptions: { globals: globals.browser } },
|
||||
pluginJs.configs.recommended,
|
||||
@@ -22,4 +24,4 @@ export default [
|
||||
]
|
||||
}
|
||||
}
|
||||
];
|
||||
]);
|
||||
|
||||
43
package.json
43
package.json
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"name": "no-twitter-bot",
|
||||
"type": "module",
|
||||
"version": "2.0.0",
|
||||
"version": "3.1.0",
|
||||
"private": true,
|
||||
"packageManager": "yarn@4.9.2",
|
||||
"packageManager": "yarn@4.12.0",
|
||||
"description": "This grammY powered Telegram bot is designed to delete Twitter/X links and reformat services from whitelisted groups. This one is the main bot for the LCM Telegram groups/communities.",
|
||||
"imports": {
|
||||
"#root/*": "./build/src/*"
|
||||
},
|
||||
"author": "Lucid Kobold (Lucid Creations Media) <social@lucidcreations.media>",
|
||||
"author": "Lucid (Werewolf Kid Creations) <social@werewolfkid.monster>",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.0.0",
|
||||
@@ -27,30 +27,35 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@grammyjs/auto-chat-action": "0.1.1",
|
||||
"@grammyjs/commands": "1.0.8",
|
||||
"@grammyjs/hydrate": "1.4.1",
|
||||
"@grammyjs/commands": "1.2.0",
|
||||
"@grammyjs/hydrate": "1.6.0",
|
||||
"@grammyjs/i18n": "1.1.2",
|
||||
"@grammyjs/parse-mode": "1.11.1",
|
||||
"@grammyjs/runner": "2.0.3",
|
||||
"@grammyjs/types": "3.20.0",
|
||||
"@hono/node-server": "1.14.2",
|
||||
"@grammyjs/types": "3.23.0",
|
||||
"@hono/node-server": "1.19.9",
|
||||
"@urql/core": "^6.0.1",
|
||||
"axios": "^1.13.3",
|
||||
"callback-data": "1.1.1",
|
||||
"grammy": "1.36.1",
|
||||
"hono": "4.7.9",
|
||||
"grammy": "1.39.3",
|
||||
"hono": "4.11.6",
|
||||
"iso-639-1": "3.1.5",
|
||||
"pino": "9.6.0",
|
||||
"pino-pretty": "13.0.0",
|
||||
"tsx": "4.19.4",
|
||||
"valibot": "0.42.1"
|
||||
"pino": "10.3.0",
|
||||
"pino-pretty": "13.1.3",
|
||||
"tsx": "4.21.0",
|
||||
"valibot": "1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "4.12.0",
|
||||
"@types/node": "^22.15.21",
|
||||
"eslint": "^9.27.0",
|
||||
"@antfu/eslint-config": "7.2.0",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@types/node": "^25.0.10",
|
||||
"eslint": "^9.39.2",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^15.5.1",
|
||||
"tsc-watch": "^6.3.1",
|
||||
"typescript": "^5.8.3"
|
||||
"lint-staged": "^16.2.7",
|
||||
"prettier": "3.8.1",
|
||||
"tsc-watch": "^7.2.0",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.54.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.ts": "eslint"
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { chatAction } from "@grammyjs/auto-chat-action";
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
// import { isAdmin } from "#root/bot/filters/is-admin.js";
|
||||
import { setCommandsHandler } from "#root/bot/handlers/commands/setcommands.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType("private");
|
||||
// .filter(ctx => isAdmin(ctx.config.botAdmins)(ctx));
|
||||
|
||||
feature.command(
|
||||
"setcommands",
|
||||
logHandle("command-setcommands"),
|
||||
chatAction("typing"),
|
||||
setCommandsHandler
|
||||
);
|
||||
|
||||
export { composer as adminFeature };
|
||||
@@ -1,28 +1,73 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import { urql } from "#root/main.js";
|
||||
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType(["group", "supergroup", "private"]);
|
||||
|
||||
// const GROUP_IDS = process.env.GROUP_IDS
|
||||
// ? process.env.GROUP_IDS.split(",")
|
||||
// : undefined;
|
||||
const feature = composer.chatType(["private", "group", "supergroup"]);
|
||||
|
||||
/**
|
||||
* What triggers this feature and adds to the log when it has been triggered.
|
||||
* The trigger is the command "/botInfo"
|
||||
*/
|
||||
feature.hears(
|
||||
"/botInfo",
|
||||
/^\/botInfo/,
|
||||
logHandle("bot-info-command"),
|
||||
async (ctx: Context) => {
|
||||
if (ctx.chat && ctx.msg) {
|
||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||
|
||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||
|
||||
// Checks if the context includes a message property.
|
||||
if (ctx.msg && ctx.chat && ctx.msg.from) {
|
||||
// Doesn't respond to regular users in groups. This is to prevent users spamming the command.
|
||||
if (ctx.chat.type !== "private") {
|
||||
const chatMember = await ctx.getChatMember(ctx.msg.from.id);
|
||||
|
||||
if (!["creator", "administrator"].includes(chatMember.status)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await urql
|
||||
.mutation(increment, { command: true, mutationKey })
|
||||
.toPromise()
|
||||
.then(async () => {
|
||||
if (ctx.msg) {
|
||||
// Replies to the message.
|
||||
await ctx.reply(
|
||||
`I am a bot designed to delete any Twitter/X links and reformatting services within groups\\. I now check embedded links\\! By default I only work with whitelisted group IDs\\.\n\nYou can fork me from this link: https://github\\.com/lucid\\-creations\\-media/no\\-twitter\\-bot and deploy me for use in your own groups\\!`,
|
||||
`I am a bot designed to delete any Twitter/X and Meta links along with corresponding reformatting services\\. I now check embedded links\\!`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
await ctx.reply(
|
||||
`[Lucid](https://werewolfkid.monster) made this bot as a protest against the enshittification and Nazi\\-fication of Twitter\\ ever since Elon Musk took it over. The final straw aws when he did a Nazi salute at a Trump Rally celebrating Trump\\'s second inauguration\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
await ctx.reply(
|
||||
`There have been reports of extremist right\\-wing individuals doxxing and harassing anyone left of center\\. The victims have come out to state that they\\'ve had several accounts hacked into\\, including onces with unique passwords\\. It is clear that these assholes are using some kind of script kiddie malware to capture\\/steal credentials and possibly even stored passwords\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
return await ctx.reply(
|
||||
`Lucid decided it was time to make a statement\\. Twitter\\/X is not safe anymore\\. The fandom doesn\\'t need it\\. It should be boycotted and not allowed anymore\\. Thus they decided to try making this bot public\\-use to test it's viability\\. Feel free to add this bot into your own group\\. All it needs is an admin role with the permission to delete messages\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
53
src/bot/features/botStatsSiteCommand.ts
Normal file
53
src/bot/features/botStatsSiteCommand.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import { urql } from "#root/main.js";
|
||||
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType(["private", "group", "supergroup"]);
|
||||
|
||||
/**
|
||||
* What triggers this feature and adds to the log when it has been triggered.
|
||||
* The trigger is the command "/botInfo"
|
||||
*/
|
||||
feature.hears(
|
||||
/^\/botStats/,
|
||||
logHandle("site-stats-command"),
|
||||
async (ctx: Context) => {
|
||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||
|
||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||
|
||||
// Checks if the context includes a message property.
|
||||
if (ctx.msg && ctx.chat && ctx.msg.from) {
|
||||
// Doesn't respond to regular users in groups. This is to prevent users spamming the command.
|
||||
if (ctx.chat.type !== "private") {
|
||||
const chatMember = await ctx.getChatMember(ctx.msg.from.id);
|
||||
|
||||
if (!["creator", "administrator"].includes(chatMember.status)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await urql
|
||||
.mutation(increment, { command: true, mutationKey })
|
||||
.toPromise()
|
||||
.then(async () => {
|
||||
if (ctx.msg) {
|
||||
// Replies to the message.
|
||||
return await ctx.reply(
|
||||
`The bot statistics website can be found at https://bot\\-stats\\.werewolfkid\\.monster/\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { composer as statsSiteCommand };
|
||||
@@ -3,6 +3,11 @@ import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import metaLinkCheck from "#root/lib/metaLinkCheck.js";
|
||||
import twitterLinkCheck from "#root/lib/twitterLinkCheck.js";
|
||||
import { urql } from "#root/main.js";
|
||||
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||
import addGroup from "#root/lib/graphql/mutations/addGroupMutation.js";
|
||||
import incrementGroup from "#root/lib/graphql/mutations/incrementGroupMutation.js";
|
||||
import tiktokLinkCheck from "#root/lib/tiktokLinkCheck.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
@@ -13,123 +18,83 @@ const feature = composer.chatType(["group", "supergroup"]);
|
||||
* The trigger is anytime an embedded url is detected.
|
||||
*/
|
||||
feature.on("message::url", logHandle("embed-check"), async (ctx: Context) => {
|
||||
if (ctx.chat && ctx.msg) {
|
||||
// Pulling the group IDs from the env variables.
|
||||
const GROUP_IDS = process.env.GROUP_IDS
|
||||
? process.env.GROUP_IDS.split(",")
|
||||
: undefined;
|
||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||
|
||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||
|
||||
if (ctx.chat && ctx.msg) {
|
||||
if (GROUP_IDS !== undefined) {
|
||||
// Checking if the message is from a whitelisted group.
|
||||
const groupID = ctx.chat.id;
|
||||
const flag = GROUP_IDS.includes(`${groupID}`);
|
||||
const groupName = ctx.chat?.title || "";
|
||||
const groupID = ctx.chat?.id.toString() || "";
|
||||
const groupUsername = ctx.chat?.username || "";
|
||||
let deletedLinks = 0;
|
||||
|
||||
const username = ctx.msg.from?.username;
|
||||
|
||||
if (flag) {
|
||||
// Filters every message/caption entity that is a url into a new array.
|
||||
const embeds = ctx.msg.entities
|
||||
? ctx.msg.entities.filter(e => e.type === "text_link")
|
||||
: null;
|
||||
: [];
|
||||
const captionEmbeds = ctx.msg.caption_entities
|
||||
? ctx.msg.caption_entities.filter(e => e.type === "text_link")
|
||||
: null;
|
||||
: [];
|
||||
const allEmbeds = embeds.concat(captionEmbeds);
|
||||
|
||||
// If the caption embeds array isn't empty filter through them to check if any is a Twitter/X or Meta url.
|
||||
if (captionEmbeds !== null && captionEmbeds.length) {
|
||||
const metaLinks = captionEmbeds.filter(({ url }) =>
|
||||
metaLinkCheck(url)
|
||||
);
|
||||
const twitterLinks = captionEmbeds.filter(({ url }) =>
|
||||
twitterLinkCheck(url)
|
||||
);
|
||||
if (allEmbeds.length) {
|
||||
const metaLinks = allEmbeds.filter(({ url }) => metaLinkCheck(url));
|
||||
const twitterLinks = allEmbeds.filter(({ url }) => twitterLinkCheck(url));
|
||||
const tiktokLinks = allEmbeds.filter(({ url }) => tiktokLinkCheck(url));
|
||||
|
||||
// Handle action and response if both meta and Twitter/X links are detected.
|
||||
if (metaLinks.length && twitterLinks.length) {
|
||||
// Deletes the offending message.
|
||||
ctx.msg.delete();
|
||||
// Replies to the user informing them of the action.
|
||||
return await ctx.reply(
|
||||
`@${username} Twitter and X links along with reformatting services for Twitter posts are not allowed here\\. Also Facebook and meta links along with with links to meta\\-owned services are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.\n\nIf this was forwarded from a channel consider forwarding without the caption so the media isn't deleted\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
}
|
||||
|
||||
// Handle action and response if only meta links are detected.
|
||||
// Handles Meta & Facebook Links
|
||||
if (metaLinks.length) {
|
||||
// Deletes the offending message.
|
||||
ctx.msg.delete();
|
||||
// Replies to the user informing them of the action.
|
||||
return await ctx.reply(
|
||||
`@${username} Facebook and meta links along with with links to meta\\-owned services are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\\n\nIf this was forwarded from a channel consider forwarding without the caption so the media isn't deleted\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
deletedLinks += metaLinks.length;
|
||||
}
|
||||
|
||||
// Handle action and response if only Twitter/X links are detected.
|
||||
// Handles Twitter/X links.
|
||||
if (twitterLinks.length) {
|
||||
// Deletes the offending message.
|
||||
ctx.msg.delete();
|
||||
// Replies to the user informing them of the action.
|
||||
return await ctx.reply(
|
||||
`@${username} Twitter and X links along with reformatting services for Twitter posts are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.\n\nIf this was forwarded from a channel consider forwarding without the caption so the media isn't deleted\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
}
|
||||
}
|
||||
// If the embeds array isn't empty filter through them to check if any is a Twitter/X or Meta url.
|
||||
if (embeds !== null && embeds.length) {
|
||||
const metaLinks = embeds.filter(({ url }) => metaLinkCheck(url));
|
||||
const twitterLinks = embeds.filter(({ url }) =>
|
||||
twitterLinkCheck(url)
|
||||
);
|
||||
|
||||
// Handle action and response if both meta and Twitter/X links are detected.
|
||||
if (metaLinks.length && twitterLinks.length) {
|
||||
// Deletes the offending message.
|
||||
ctx.msg.delete();
|
||||
// Replies to the user informing them of the action.
|
||||
return await ctx.reply(
|
||||
`@${username} Twitter and X links along with reformatting services for Twitter posts are not allowed here\\. Also Facebook and meta links along with with links to meta\\-owned services are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
deletedLinks += twitterLinks.length;
|
||||
}
|
||||
|
||||
// Handle action and response if only meta links are detected.
|
||||
if (metaLinks.length) {
|
||||
// Deletes the offending message.
|
||||
ctx.msg.delete();
|
||||
// Replies to the user informing them of the action.
|
||||
return await ctx.reply(
|
||||
`@${username} Facebook and meta links along with with links to meta\\-owned services are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
}
|
||||
|
||||
// Handle action and response if only Twitter/X links are detected.
|
||||
if (twitterLinks.length) {
|
||||
// Deletes the offending message.
|
||||
ctx.msg.delete();
|
||||
// Replies to the user informing them of the action.
|
||||
return await ctx.reply(
|
||||
`@${username} Twitter and X links along with reformatting services for Twitter posts are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
}
|
||||
}
|
||||
// Handles TikTok links.
|
||||
if (tiktokLinks.length) {
|
||||
deletedLinks += tiktokLinks.length;
|
||||
}
|
||||
}
|
||||
|
||||
if (!GROUP_IDS) {
|
||||
console.info("Group IDS:", process.env.GROUP_IDS);
|
||||
if (deletedLinks) {
|
||||
ctx.msg.delete();
|
||||
|
||||
return await urql
|
||||
.mutation(addGroup, {
|
||||
groupID,
|
||||
groupName,
|
||||
groupUsername,
|
||||
mutationKey
|
||||
})
|
||||
.toPromise()
|
||||
.then(() =>
|
||||
urql
|
||||
.mutation(incrementGroup, {
|
||||
groupID,
|
||||
linksDeleted: deletedLinks,
|
||||
mutationKey
|
||||
})
|
||||
.then(
|
||||
async () =>
|
||||
await urql
|
||||
.mutation(increment, { link: deletedLinks, mutationKey })
|
||||
.toPromise()
|
||||
.then(async () => {
|
||||
if (ctx.msg) {
|
||||
// Replies to the user informing them of the action.
|
||||
await ctx.reply(
|
||||
`There was a problem retrieving the whitelist\\. Check the env variables and try again\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
`@${username} One or more links in your last message were on the banlist\\. Remember TikTok, Meta & Facebook, and Twitter\\/X links along with any reformatting services for them are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\.\n\nNo administration action was taken against you other than the message being deleted\\.\n\nIf this was forwarded from a channel consider forwarding without the caption so the media isn't deleted\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType(["group", "supergroup"]);
|
||||
|
||||
feature.hears(
|
||||
"/getGroupID",
|
||||
logHandle("get-group-id"),
|
||||
async (ctx: Context) => {
|
||||
const GROUP_IDS = process.env.GROUP_IDS
|
||||
? process.env.GROUP_IDS.split(",")
|
||||
: undefined;
|
||||
|
||||
if (ctx.chat && ctx.msg) {
|
||||
if (GROUP_IDS !== undefined) {
|
||||
const groupID = ctx.chat.id;
|
||||
const flag = GROUP_IDS.includes(`${groupID}`);
|
||||
if (flag) {
|
||||
await ctx.reply(`The group id is: \`${groupID}\``, {
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { composer as getGroupIDCommand };
|
||||
96
src/bot/features/getGroupStatsCommand.ts
Normal file
96
src/bot/features/getGroupStatsCommand.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import { urql } from "#root/main.js";
|
||||
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||
import getGroupStats from "#root/lib/graphql/queries/getGroupStatsQuery.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType(["group", "supergroup"]);
|
||||
|
||||
/**
|
||||
* What triggers this feature and adds to the log when it has been triggered.
|
||||
* The trigger is the command "/groupStats"
|
||||
*/
|
||||
feature.hears(
|
||||
/^\/groupStats/,
|
||||
logHandle("groups-stats-command"),
|
||||
async (ctx: Context) => {
|
||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||
|
||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||
|
||||
// Checks if the context includes a message property.
|
||||
if (ctx.msg && ctx.chat && ctx.msg.from) {
|
||||
// Doesn't respond to regular users in groups. This is to prevent users spamming the command.
|
||||
const chatMember = await ctx.getChatMember(ctx.msg.from.id);
|
||||
if (!["creator", "administrator"].includes(chatMember.status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stringify the groupID
|
||||
const groupID = ctx.chat?.id.toString() || "";
|
||||
|
||||
// Query to get group stats.
|
||||
await urql
|
||||
.query(getGroupStats, {
|
||||
groupID
|
||||
})
|
||||
.toPromise()
|
||||
.then(async res => {
|
||||
// Replies to the message.
|
||||
if (ctx.msg) {
|
||||
// Check if the group has a document in the database and respond accordingly.
|
||||
if (res.data.getGroupStats !== null) {
|
||||
const { name, username, linksDeleted } = res.data.getGroupStats;
|
||||
|
||||
await ctx.reply(
|
||||
`Your group is registered in the database as "${name}" ${
|
||||
username.length
|
||||
? `with a username of ${name}`
|
||||
: `without a public username`
|
||||
}\\.\n\nThe bot has successfully deleted ${linksDeleted} links from your group\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
|
||||
return await ctx.reply(
|
||||
`If you need to update this information you can use the \\/registerGroup command\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Default response //
|
||||
|
||||
await ctx.reply(
|
||||
`Your group was not found in the database\\. You can use the \\/registerGroup command to add your group to the database\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
|
||||
return await ctx.reply(
|
||||
`This is optional\\. If the bot ever removes a link in your group then the group information will be added to the database and tracked from then on\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return await urql
|
||||
.mutation(increment, { command: true, mutationKey })
|
||||
.toPromise();
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { composer as getGroupStats };
|
||||
@@ -1,28 +1,42 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import { urql } from "#root/main.js";
|
||||
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||
import getCommandsList, { Commands } from "#root/lib/getCommandsList.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType(["group", "supergroup"]);
|
||||
const feature = composer.chatType(["group", "supergroup", "private"]);
|
||||
|
||||
feature.hears(
|
||||
"/help",
|
||||
logHandle("blacklist-detection"),
|
||||
async (ctx: Context) => {
|
||||
const GROUP_IDS = process.env.GROUP_IDS
|
||||
? process.env.GROUP_IDS.split(",")
|
||||
: undefined;
|
||||
/**
|
||||
* What triggers this feature and adds to the log when it has been triggered.
|
||||
* The trigger is the command "/help"
|
||||
*/
|
||||
feature.hears(/^\/help/, logHandle("help"), async (ctx: Context) => {
|
||||
const apiKey = process.env.GRAPHQL_API_TOKEN || "";
|
||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||
const statsSite = process.env.STATS_SITE || "";
|
||||
|
||||
if (ctx.chat && ctx.msg) {
|
||||
if (GROUP_IDS !== undefined) {
|
||||
const groupID = ctx.chat.id;
|
||||
const flag = GROUP_IDS.includes(`${groupID}`);
|
||||
// const username = ctx.msg.from?.username;
|
||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||
const commandsListArr = await getCommandsList(`${statsSite}api/bot`, apiKey);
|
||||
|
||||
if (flag) {
|
||||
// const GROUP_IDS = process.env.GROUP_IDS
|
||||
// ? process.env.GROUP_IDS.split(",")
|
||||
// : undefined;
|
||||
|
||||
// Checks there is a chat and msg property in the context.
|
||||
if (ctx.chat && ctx.msg && ctx.msg.from) {
|
||||
await urql
|
||||
.mutation(increment, { command: true, mutationKey })
|
||||
.toPromise()
|
||||
.then(async () => {
|
||||
if (ctx.msg && ctx.chat && ctx.msg.from) {
|
||||
// Checks if the chat is private
|
||||
if (ctx.chat.type === "private") {
|
||||
// Responds with message.
|
||||
await ctx.reply(
|
||||
`**Here are the availible commands you can use:**\n\n/getGroupID \\- replied with the ID of the group I am in\\.\n\n/isLCMGRoup \\- Checks if this group's ID is on the whitelist and responds accordingly\\.\n\n/botInfo \\- Info about me and how to fork me to deploy for your own use\\.\n\n/help \\- Displays this help message\\.`,
|
||||
`I require no configuration\\. Simply add me to a group and make me an admin with the permission to delete messages\\. From there I will start deleting any Twitter\\/X and Meta links I detect\\. I also check embeds and forwards\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
@@ -30,35 +44,58 @@ feature.hears(
|
||||
);
|
||||
}
|
||||
|
||||
if (!flag) {
|
||||
// Checks if chat is a group.
|
||||
if (ctx.chat.type !== "private") {
|
||||
const chatMember = await ctx.getChatMember(ctx.msg.from.id);
|
||||
|
||||
// Checks if the user is an admin.
|
||||
if (["creator", "administrator"].includes(chatMember.status)) {
|
||||
// Respond with message.
|
||||
await ctx.reply(
|
||||
`**Since this is not a whitelisted group the features are limited\\!\\!**\n\nHere are the availible commands you can use:\n\n/isLCMGRoup \\- Checks if this group's ID is on the whitelist and responds accordingly\\.\n\n/botInfo \\- Info about me and how to fork me to deploy for your own use\\.\n\n/help \\- Displays this help message\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
await ctx.reply(
|
||||
`This group is NOT in the whitelisted and is NOT a part of the LCM Telegram groups/communities\\. I am a bot designed to delete any Twitter/X links and reformatting services within groups\\. You can fork me from this link: https://github\\.com/lucid\\-creations\\-media/no\\-twitter\\-bot and deploy me for use in your own groups\\!`,
|
||||
`I require no configuration\\. If I am not working\\, make sure I have an admin role with the permission to delete messages\\. I should already be deleting any Twitter\\/X and Meta links I detect\\. I also check embeds and forwards\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
} else {
|
||||
/**
|
||||
* Doesn't respond to regular users in groups. This is to prevent users spamming the command.
|
||||
* Especially since this one includes some political opinions/messages.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!GROUP_IDS) {
|
||||
const commandsListStr = commandsListArr.reduce((prev, curr) => {
|
||||
const { command, description, groups } = curr;
|
||||
|
||||
return (prev += `**Command**: ${command} \\- ${description}\\.\nGroups: ${groups ? "✔️" : "❌"} \\| Private: ${curr.private ? "✔️" : "❌"}\n\n`);
|
||||
}, "Here are a list of my commands:\n\n");
|
||||
|
||||
await ctx.reply(commandsListStr, {
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
});
|
||||
|
||||
await ctx.reply(
|
||||
`There was a problem retrieving the whitelist. Check the env variables and try again\\.`,
|
||||
`In the future a public GitHub repo will be set up with a mirror of the private git that the bot code is stored on\\. That repo will be used to handle bug reports and feature requests\\. Including requests to check for more domains\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
|
||||
// return await ctx.reply(
|
||||
// `Down with fascism\\! Fuck MAGA\\! Fuck Trump\\! Fuck Nazis\\! Trans rights are human rights\\! Trans women are women\\! Trans men are men\\! Never let them take away your happiness\\!`,
|
||||
// {
|
||||
// parse_mode: "MarkdownV2",
|
||||
// reply_parameters: { message_id: ctx.msg.message_id }
|
||||
// }
|
||||
// );
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
export { composer as helpCommand };
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType(["group", "supergroup"]);
|
||||
|
||||
feature.hears(
|
||||
"/isLCMGroup",
|
||||
logHandle("is-LCM-group"),
|
||||
async (ctx: Context) => {
|
||||
const GROUP_IDS = process.env.GROUP_IDS
|
||||
? process.env.GROUP_IDS.split(",")
|
||||
: undefined;
|
||||
|
||||
if (ctx.chat && ctx.msg) {
|
||||
const groupID = ctx.chat.id;
|
||||
|
||||
if (GROUP_IDS !== undefined) {
|
||||
const flag = GROUP_IDS.includes(`${groupID}`);
|
||||
|
||||
if (flag) {
|
||||
await ctx.reply(
|
||||
`This group is in the whitelisted and is a part of the LCM Telegram groups/communities\\. I should be deleting any Twitter/X links and reformatting services within this group\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (!flag) {
|
||||
await ctx.reply(
|
||||
`This group is NOT in the whitelisted and is NOT a part of the LCM Telegram groups/communities\\. I am a bot designed to delete any Twitter/X links and reformatting services within groups\\. You can fork me from this link: https://github\\.com/lucid\\-creations\\-media/no\\-twitter\\-bot and deploy me for use in your own groups\\!`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!GROUP_IDS) {
|
||||
await ctx.reply(
|
||||
`There was a problem retrieving the whitelist\\. Check the env variables and try again\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { composer as isLCMGroup };
|
||||
@@ -1,36 +0,0 @@
|
||||
import { Composer } from "grammy";
|
||||
import { changeLanguageData } from "#root/bot/callback-data/change-language.js";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import { i18n } from "#root/bot/i18n.js";
|
||||
import { createChangeLanguageKeyboard } from "#root/bot/keyboards/change-language.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType("private");
|
||||
|
||||
feature.command("language", logHandle("command-language"), async ctx => {
|
||||
return ctx.reply(ctx.t("language-select"), {
|
||||
reply_markup: await createChangeLanguageKeyboard(ctx)
|
||||
});
|
||||
});
|
||||
|
||||
feature.callbackQuery(
|
||||
changeLanguageData.filter(),
|
||||
logHandle("keyboard-language-select"),
|
||||
async ctx => {
|
||||
const { code: languageCode } = changeLanguageData.unpack(
|
||||
ctx.callbackQuery.data
|
||||
);
|
||||
|
||||
if (i18n.locales.includes(languageCode)) {
|
||||
await ctx.i18n.setLocale(languageCode);
|
||||
|
||||
return ctx.editMessageText(ctx.t("language-changed"), {
|
||||
reply_markup: await createChangeLanguageKeyboard(ctx)
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { composer as languageFeature };
|
||||
67
src/bot/features/metaBanlist.ts
Normal file
67
src/bot/features/metaBanlist.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import { metaRegex } from "#root/lib/metaLinkCheck.js";
|
||||
import { urql } from "#root/main.js";
|
||||
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||
import addGroup from "#root/lib/graphql/mutations/addGroupMutation.js";
|
||||
import incrementGroup from "#root/lib/graphql/mutations/incrementGroupMutation.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType(["group", "supergroup"]);
|
||||
|
||||
/**
|
||||
* What triggers this feature and adds to the log when it has been triggered.
|
||||
* The trigger uses the global Twitter regex to detect Twitter and X links within messages.
|
||||
*/
|
||||
feature.hears(
|
||||
metaRegex,
|
||||
logHandle("banlist-detection-meta"),
|
||||
async (ctx: Context) => {
|
||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||
|
||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||
|
||||
if (ctx.chat && ctx.msg) {
|
||||
const username = ctx.msg.from?.username;
|
||||
// Deletes the offending message.
|
||||
ctx.msg.delete();
|
||||
|
||||
return await urql
|
||||
.mutation(increment, { link: 1, mutationKey })
|
||||
.toPromise()
|
||||
.then(async () => {
|
||||
if (ctx.msg && ctx.chat) {
|
||||
// Replies to the user informing them of the action.
|
||||
await ctx.reply(
|
||||
`@${username} Facebook and meta links along with with links to meta\\-owned services are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
|
||||
const groupName = ctx.chat?.title || "";
|
||||
const groupID = ctx.chat?.id.toString() || "";
|
||||
const groupUsername = ctx.chat?.username || "";
|
||||
|
||||
return await urql
|
||||
.mutation(addGroup, {
|
||||
groupID,
|
||||
groupName,
|
||||
groupUsername,
|
||||
mutationKey
|
||||
})
|
||||
.toPromise()
|
||||
.then(() =>
|
||||
urql.mutation(incrementGroup, {
|
||||
groupID,
|
||||
linksDeleted: 1,
|
||||
mutationKey
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { composer as metaBanlist };
|
||||
@@ -1,56 +0,0 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import { metaRegex } from "#root/lib/metaLinkCheck.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType(["group", "supergroup"]);
|
||||
|
||||
/**
|
||||
* What triggers this feature and adds to the log when it has been triggered.
|
||||
* The trigger uses the global Twitter regex to detect Twitter and X links within messages.
|
||||
*/
|
||||
feature.hears(
|
||||
metaRegex,
|
||||
logHandle("blacklist-detection-meta"),
|
||||
async (ctx: Context) => {
|
||||
// Pulling the group IDs from the env variables.
|
||||
const GROUP_IDS = process.env.GROUP_IDS
|
||||
? process.env.GROUP_IDS.split(",")
|
||||
: undefined;
|
||||
|
||||
if (ctx.chat && ctx.msg) {
|
||||
if (GROUP_IDS !== undefined) {
|
||||
// Checking if the message is from a whitelisted group.
|
||||
const groupID = ctx.chat.id;
|
||||
const flag = GROUP_IDS.includes(`${groupID}`);
|
||||
const username = ctx.msg.from?.username;
|
||||
|
||||
if (flag) {
|
||||
// Deletes the offending message.
|
||||
ctx.msg.delete();
|
||||
// Replies to the user informing them of the action.
|
||||
return await ctx.reply(
|
||||
`@${username} Facebook and meta links along with with links to meta\\-owned services are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If the env variables are misconfigured an error is sent to the group.
|
||||
if (!GROUP_IDS) {
|
||||
console.info("Group IDS:", process.env.GROUP_IDS);
|
||||
return await ctx.reply(
|
||||
`There was a problem retrieving the whitelist\\. Check the env variables and try again\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { composer as metaBlacklist };
|
||||
65
src/bot/features/registerGroupCommand.ts
Normal file
65
src/bot/features/registerGroupCommand.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import { urql } from "#root/main.js";
|
||||
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||
import addGroup from "#root/lib/graphql/mutations/addGroupMutation.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType(["group", "supergroup"]);
|
||||
|
||||
/**
|
||||
* What triggers this feature and adds to the log when it has been triggered.
|
||||
* The trigger is the command "/registerGroup"
|
||||
*/
|
||||
feature.hears(
|
||||
/^\/registerGroup/,
|
||||
logHandle("register-group-command"),
|
||||
async (ctx: Context) => {
|
||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||
|
||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||
|
||||
// Checks if the context includes a message property.
|
||||
if (ctx.msg && ctx.chat && ctx.msg.from) {
|
||||
// Doesn't respond to regular users in groups. This is to prevent users spamming the command.
|
||||
const chatMember = await ctx.getChatMember(ctx.msg.from.id);
|
||||
if (!["creator", "administrator"].includes(chatMember.status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const groupName = ctx.chat?.title || "";
|
||||
const groupID = ctx.chat?.id.toString() || ""; // Stringify the groupID
|
||||
const groupUsername = ctx.chat?.username || "";
|
||||
|
||||
// Add or update the group
|
||||
await urql
|
||||
.mutation(addGroup, {
|
||||
groupID,
|
||||
groupName,
|
||||
groupUsername,
|
||||
mutationKey
|
||||
})
|
||||
.toPromise()
|
||||
.then(async () => {
|
||||
await urql
|
||||
.mutation(increment, { command: true, mutationKey })
|
||||
.toPromise();
|
||||
|
||||
if (ctx.msg) {
|
||||
// Replies to the message.
|
||||
return await ctx.reply(
|
||||
`Your group has been successfully added to the database\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { composer as registerGroup };
|
||||
67
src/bot/features/tiktokBanlist.ts
Normal file
67
src/bot/features/tiktokBanlist.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import { urql } from "#root/main.js";
|
||||
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||
import addGroup from "#root/lib/graphql/mutations/addGroupMutation.js";
|
||||
import incrementGroup from "#root/lib/graphql/mutations/incrementGroupMutation.js";
|
||||
import { tiktokRegex } from "#root/lib/tiktokLinkCheck.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType(["group", "supergroup"]);
|
||||
|
||||
/**
|
||||
* What triggers this feature and adds to the log when it has been triggered.
|
||||
* The trigger uses the global Twitter regex to detect TikTok links within messages.
|
||||
*/
|
||||
feature.hears(
|
||||
tiktokRegex,
|
||||
logHandle("banlist-detection-tiktok"),
|
||||
async (ctx: Context) => {
|
||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||
|
||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||
|
||||
if (ctx.chat && ctx.msg) {
|
||||
const username = ctx.msg.from?.username;
|
||||
// Deletes the offending message.
|
||||
ctx.msg.delete();
|
||||
|
||||
return await urql
|
||||
.mutation(increment, { link: 1, mutationKey })
|
||||
.toPromise()
|
||||
.then(async () => {
|
||||
if (ctx.msg && ctx.chat) {
|
||||
// Replies to the user informing them of the action.
|
||||
await ctx.reply(
|
||||
`@${username} TikTok links are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
|
||||
const groupName = ctx.chat?.title || "";
|
||||
const groupID = ctx.chat?.id.toString() || "";
|
||||
const groupUsername = ctx.chat?.username || "";
|
||||
|
||||
return await urql
|
||||
.mutation(addGroup, {
|
||||
groupID,
|
||||
groupName,
|
||||
groupUsername,
|
||||
mutationKey
|
||||
})
|
||||
.toPromise()
|
||||
.then(() =>
|
||||
urql.mutation(incrementGroup, {
|
||||
groupID,
|
||||
linksDeleted: 1,
|
||||
mutationKey
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { composer as tiktokBanlist };
|
||||
67
src/bot/features/twitterBanlist.ts
Normal file
67
src/bot/features/twitterBanlist.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import { twitterRegex } from "#root/lib/twitterLinkCheck.js";
|
||||
import { urql } from "#root/main.js";
|
||||
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||
import addGroup from "#root/lib/graphql/mutations/addGroupMutation.js";
|
||||
import incrementGroup from "#root/lib/graphql/mutations/incrementGroupMutation.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType(["group", "supergroup"]);
|
||||
|
||||
/**
|
||||
* What triggers this feature and adds to the log when it has been triggered.
|
||||
* The trigger uses the global Twitter regex to detect Twitter and X links within messages.
|
||||
*/
|
||||
feature.hears(
|
||||
twitterRegex,
|
||||
logHandle("banlist-detection-twitter"),
|
||||
async (ctx: Context) => {
|
||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||
|
||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||
|
||||
if (ctx.chat && ctx.msg) {
|
||||
const username = ctx.msg.from?.username;
|
||||
// Deletes the offending message.
|
||||
ctx.msg.delete();
|
||||
|
||||
return await urql
|
||||
.mutation(increment, { link: 1, mutationKey })
|
||||
.toPromise()
|
||||
.then(async () => {
|
||||
if (ctx.msg && ctx.chat) {
|
||||
// Replies to the user informing them of the action.
|
||||
await ctx.reply(
|
||||
`@${username} Twitter and X links along with reformatting services for Twitter posts are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
|
||||
const groupName = ctx.chat?.title || "";
|
||||
const groupID = ctx.chat?.id.toString() || "";
|
||||
const groupUsername = ctx.chat?.username || "";
|
||||
|
||||
return await urql
|
||||
.mutation(addGroup, {
|
||||
groupID,
|
||||
groupName,
|
||||
groupUsername,
|
||||
mutationKey
|
||||
})
|
||||
.toPromise()
|
||||
.then(() =>
|
||||
urql.mutation(incrementGroup, {
|
||||
groupID,
|
||||
linksDeleted: 1,
|
||||
mutationKey
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { composer as twitterBanlist };
|
||||
@@ -1,61 +0,0 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import { twitterRegex } from "#root/lib/twitterLinkCheck.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType(["group", "supergroup"]);
|
||||
|
||||
/**
|
||||
* What triggers this feature and adds to the log when it has been triggered.
|
||||
* The trigger uses the global Twitter regex to detect Twitter and X links within messages.
|
||||
*/
|
||||
feature.hears(
|
||||
twitterRegex,
|
||||
logHandle("blacklist-detection-twitter"),
|
||||
async (ctx: Context) => {
|
||||
// Pulling the group IDs from the env variables.
|
||||
const GROUP_IDS = process.env.GROUP_IDS
|
||||
? process.env.GROUP_IDS.split(",")
|
||||
: undefined;
|
||||
|
||||
if (ctx.chat && ctx.msg) {
|
||||
if (GROUP_IDS !== undefined) {
|
||||
// Checking if the message is from a whitelisted group.
|
||||
const groupID = ctx.chat.id;
|
||||
const flag = GROUP_IDS.includes(`${groupID}`);
|
||||
const username = ctx.msg.from?.username;
|
||||
|
||||
if (flag) {
|
||||
// Deletes the offending message.
|
||||
ctx.msg.delete();
|
||||
// Replies to the user informing them of the action.
|
||||
return await ctx.reply(
|
||||
`@${username} Twitter and X links along with reformatting services for Twitter posts are not allowed here\\. Please consider sharing the media directly or from other social media sources or websites\\. No administration action was taken against you other than the message being deleted\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If the env variables are misconfigured an error is sent to the group.
|
||||
if (!GROUP_IDS) {
|
||||
console.info(
|
||||
"Group IDS:",
|
||||
process.env.GROUP_IDS,
|
||||
GROUP_IDS,
|
||||
GROUP_IDS !== undefined
|
||||
);
|
||||
return await ctx.reply(
|
||||
`There was a problem retrieving the whitelist\\. Check the env variables and try again\\.`,
|
||||
{
|
||||
parse_mode: "MarkdownV2",
|
||||
reply_parameters: { message_id: ctx.msg.message_id }
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { composer as twitterBlacklist };
|
||||
@@ -1,16 +1,34 @@
|
||||
import { Composer } from "grammy";
|
||||
import type { Context } from "#root/bot/context.js";
|
||||
import { logHandle } from "#root/bot/helpers/logging.js";
|
||||
import { urql } from "#root/main.js";
|
||||
import increment from "#root/lib/graphql/mutations/incrementMutation.js";
|
||||
|
||||
const composer = new Composer<Context>();
|
||||
|
||||
const feature = composer.chatType("private");
|
||||
|
||||
feature.command("start", logHandle("command-start"), ctx => {
|
||||
/**
|
||||
* What triggers this feature and adds to the log when it has been triggered.
|
||||
* The trigger is the command "/start" or "start"
|
||||
*/
|
||||
feature.command("start", logHandle("command-start"), async ctx => {
|
||||
const mutationKey = process.env.GRAPHQL_MUTATION_KEY || "";
|
||||
|
||||
await urql.mutation(increment, { trigger: true, mutationKey });
|
||||
|
||||
await urql
|
||||
.mutation(increment, { command: true, mutationKey })
|
||||
.toPromise()
|
||||
.then(async () => {
|
||||
if (ctx.msg) {
|
||||
// Responds with information about the bot.
|
||||
return ctx.reply(
|
||||
`Welcome\\! I am a bot created by Lucid for [Lucid Creations Media groups\\.](https://community.lucidcreations.media/) I am designed to delete any Twitter/X and Facebook/Meta links, links to reformatting services for Twitter posts, and other Meta products within groups\\. I now check embedded links\\! By default I only work with whitelisted group IDs\\. You can fork me from this link: https://github\\.com/lucid\\-creations\\-media/no\\-twitter\\-bot and deploy me for use in your own groups\\!\n\nLucid would consider hosting this bot for public use if crowd\\-funding would cover the hosting cost of the bot\\. Reach out if you would like to help\\.`,
|
||||
`Welcome\\! I am a bot created by Lucid for [Werewolf Kid Creations](https://werewolfkid.monster/) I am designed to delete any Twitter/X and Meta links along with corresponding reformatting services within groups\\. I also check embedded links and forwarded messages\\! I am currently in a public beta mode\\! Simply add me to a group and make me an admin with the permission to delete messages\\. From there I will start deleting any Twitter\\/X and Meta links I detect\\.`,
|
||||
{ parse_mode: "MarkdownV2" }
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export { composer as welcomeFeature };
|
||||
|
||||
@@ -2,12 +2,10 @@ import type { Context } from "#root/bot/context.js";
|
||||
import type { Config } from "#root/config.js";
|
||||
import type { Logger } from "#root/logger.js";
|
||||
import type { BotConfig } from "grammy";
|
||||
// import { adminFeature } from "#root/bot/features/admin.js";
|
||||
import { languageFeature } from "#root/bot/features/language.js";
|
||||
import { unhandledFeature } from "#root/bot/features/unhandled.js";
|
||||
import { welcomeFeature } from "#root/bot/features/welcome.js";
|
||||
import { errorHandler } from "#root/bot/handlers/error.js";
|
||||
import { i18n, isMultipleLocales } from "#root/bot/i18n.js";
|
||||
import { i18n } from "#root/bot/i18n.js";
|
||||
import { session } from "#root/bot/middlewares/session.js";
|
||||
import { updateLogger } from "#root/bot/middlewares/update-logger.js";
|
||||
import { autoChatAction } from "@grammyjs/auto-chat-action";
|
||||
@@ -15,13 +13,15 @@ import { hydrate } from "@grammyjs/hydrate";
|
||||
import { hydrateReply, parseMode } from "@grammyjs/parse-mode";
|
||||
import { sequentialize } from "@grammyjs/runner";
|
||||
import { MemorySessionStorage, Bot as TelegramBot } from "grammy";
|
||||
import { twitterBlacklist } from "./features/twitterBlacklist.js";
|
||||
import { metaBlacklist } from "./features/metaBlacklist.js";
|
||||
import { twitterBanlist } from "./features/twitterBanlist.js";
|
||||
import { metaBanlist } from "./features/metaBanlist.js";
|
||||
import { tiktokBanlist } from "./features/tiktokBanlist.js";
|
||||
import { botInfoCommand } from "./features/botInfoCommand.js";
|
||||
import { getGroupIDCommand } from "./features/getGroupIDCommand.js";
|
||||
import { helpCommand } from "./features/helpCommand.js";
|
||||
import { isLCMGroup } from "./features/isLCMGroup.js";
|
||||
import { embedCheck } from "./features/embedCheck.js";
|
||||
import { registerGroup } from "./features/registerGroupCommand.js";
|
||||
import { getGroupStats } from "./features/getGroupStatsCommand.js";
|
||||
import { statsSiteCommand } from "./features/botStatsSiteCommand.js";
|
||||
|
||||
interface Dependencies {
|
||||
config: Config;
|
||||
@@ -70,18 +70,18 @@ export function createBot(
|
||||
|
||||
// Handlers
|
||||
protectedBot.use(welcomeFeature);
|
||||
// protectedBot.use(adminFeature);
|
||||
if (isMultipleLocales) protectedBot.use(languageFeature);
|
||||
|
||||
// Commands
|
||||
protectedBot.use(botInfoCommand);
|
||||
protectedBot.use(getGroupIDCommand);
|
||||
protectedBot.use(isLCMGroup);
|
||||
protectedBot.use(helpCommand);
|
||||
protectedBot.use(registerGroup);
|
||||
protectedBot.use(getGroupStats);
|
||||
protectedBot.use(statsSiteCommand);
|
||||
|
||||
// Blacklist Feature
|
||||
protectedBot.use(twitterBlacklist);
|
||||
protectedBot.use(metaBlacklist);
|
||||
// banlist Feature
|
||||
protectedBot.use(twitterBanlist);
|
||||
protectedBot.use(metaBanlist);
|
||||
protectedBot.use(tiktokBanlist);
|
||||
protectedBot.use(embedCheck);
|
||||
|
||||
// must be the last handler
|
||||
|
||||
30
src/lib/getCommandsList.ts
Normal file
30
src/lib/getCommandsList.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import axios from "axios";
|
||||
|
||||
export interface Commands {
|
||||
command: String;
|
||||
description: String;
|
||||
groups: boolean;
|
||||
private: boolean;
|
||||
}
|
||||
|
||||
const fetchCommandsList = async (
|
||||
url: string,
|
||||
apiKey: string
|
||||
): Promise<Commands[]> => {
|
||||
let commandsList = [] as Commands[];
|
||||
|
||||
await axios
|
||||
.get(url, {
|
||||
headers: { "x-api-key": apiKey }
|
||||
})
|
||||
.then(res => {
|
||||
commandsList = res.data;
|
||||
})
|
||||
.catch(res => {
|
||||
console.error(res);
|
||||
});
|
||||
|
||||
return commandsList;
|
||||
};
|
||||
|
||||
export default fetchCommandsList;
|
||||
22
src/lib/graphql/mutations/addGroupMutation.ts
Normal file
22
src/lib/graphql/mutations/addGroupMutation.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { gql } from "@urql/core";
|
||||
|
||||
const addGroup = gql`
|
||||
mutation addGroup(
|
||||
$groupID: String!
|
||||
$groupName: String!
|
||||
$groupUsername: String
|
||||
$mutationKey: String
|
||||
) {
|
||||
addGroup(
|
||||
groupID: $groupID
|
||||
groupName: $groupName
|
||||
groupUsername: $groupUsername
|
||||
mutationKey: $mutationKey
|
||||
) {
|
||||
name
|
||||
username
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default addGroup;
|
||||
21
src/lib/graphql/mutations/incrementGroupMutation.ts
Normal file
21
src/lib/graphql/mutations/incrementGroupMutation.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { gql } from "@urql/core";
|
||||
|
||||
const incrementGroup = gql`
|
||||
mutation incrementGroup(
|
||||
$groupID: String!
|
||||
$linksDeleted: Int!
|
||||
$mutationKey: String
|
||||
) {
|
||||
incrementGroup(
|
||||
groupID: $groupID
|
||||
linksDeleted: $linksDeleted
|
||||
mutationKey: $mutationKey
|
||||
) {
|
||||
name
|
||||
username
|
||||
linksDeleted
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default incrementGroup;
|
||||
22
src/lib/graphql/mutations/incrementMutation.ts
Normal file
22
src/lib/graphql/mutations/incrementMutation.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { gql } from "@urql/core";
|
||||
|
||||
const increment = gql`
|
||||
mutation increment(
|
||||
$command: Boolean
|
||||
$link: Int
|
||||
$trigger: Boolean
|
||||
$mutationKey: String
|
||||
) {
|
||||
increment(
|
||||
command: $command
|
||||
link: $link
|
||||
trigger: $trigger
|
||||
mutationKey: $mutationKey
|
||||
) {
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default increment;
|
||||
13
src/lib/graphql/queries/getGroupStatsQuery.ts
Normal file
13
src/lib/graphql/queries/getGroupStatsQuery.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { gql } from "@urql/core";
|
||||
|
||||
const getGroupStats = gql`
|
||||
query getGroupStats($groupID: String!) {
|
||||
getGroupStats(groupID: $groupID) {
|
||||
name
|
||||
username
|
||||
linksDeleted
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default getGroupStats;
|
||||
@@ -5,7 +5,7 @@ const metaRegex =
|
||||
/**
|
||||
* This function will check if a url matches Meta services links using regex.
|
||||
*
|
||||
* @param linkUrl representing a suspected blacklisted url
|
||||
* @param linkUrl representing a suspected url on the banlist
|
||||
* @returns flag
|
||||
*/
|
||||
const metaLinkCheck = (linkUrl: string): boolean => {
|
||||
|
||||
21
src/lib/tiktokLinkCheck.ts
Normal file
21
src/lib/tiktokLinkCheck.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
// Global regex used to detect TikTok links.
|
||||
const tiktokRegex = /(tiktok\.com)/gi;
|
||||
|
||||
/**
|
||||
* This function will check if a url matches TikTok services links using regex.
|
||||
*
|
||||
* @param linkUrl representing a suspected url on the banlist
|
||||
* @return flag
|
||||
*/
|
||||
const tiktokLinkCheck = (linkUrl: string): boolean => {
|
||||
let flag = false;
|
||||
|
||||
if (linkUrl.match(tiktokRegex)) {
|
||||
flag = true;
|
||||
}
|
||||
|
||||
return flag;
|
||||
};
|
||||
|
||||
export { tiktokRegex };
|
||||
export default tiktokLinkCheck;
|
||||
@@ -4,7 +4,7 @@ const twitterRegex = /(x\.com|twitter\.com)/gi;
|
||||
/**
|
||||
* This function will check if a url matches Twitter/X services links using regex.
|
||||
*
|
||||
* @param linkUrl representing a suspected blacklisted url
|
||||
* @param linkUrl representing a suspected url on the banlist
|
||||
* @return flag
|
||||
*/
|
||||
const twitterLinkCheck = (linkUrl: string): boolean => {
|
||||
|
||||
39
src/main.ts
39
src/main.ts
@@ -8,6 +8,7 @@ import { config } from "#root/config.js";
|
||||
import { logger } from "#root/logger.js";
|
||||
import { createServer, createServerManager } from "#root/server/index.js";
|
||||
import { run } from "@grammyjs/runner";
|
||||
import { cacheExchange, Client, fetchExchange } from "@urql/core";
|
||||
|
||||
async function startPolling(config: PollingConfig) {
|
||||
const bot = createBot(config.botToken, {
|
||||
@@ -64,21 +65,31 @@ async function startWebhook(config: WebhookConfig) {
|
||||
// to prevent receiving updates before the bot is ready
|
||||
await bot.init();
|
||||
|
||||
const setWebhook = async (): Promise<void> => {
|
||||
// set webhook
|
||||
return await bot.api
|
||||
.setWebhook(config.botWebhook, {
|
||||
allowed_updates: config.botAllowedUpdates,
|
||||
secret_token: config.botWebhookSecret
|
||||
})
|
||||
.then(() => {
|
||||
logger.info({
|
||||
msg: "Webhook was set",
|
||||
url: config.botWebhook
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// start server
|
||||
const info = await serverManager.start();
|
||||
const info = await serverManager.start().then(async info => {
|
||||
logger.info({
|
||||
msg: "Server started",
|
||||
url: info.url
|
||||
});
|
||||
|
||||
// set webhook
|
||||
await bot.api.setWebhook(config.botWebhook, {
|
||||
allowed_updates: config.botAllowedUpdates,
|
||||
secret_token: config.botWebhookSecret
|
||||
});
|
||||
logger.info({
|
||||
msg: "Webhook was set",
|
||||
url: config.botWebhook
|
||||
setTimeout(async () => {
|
||||
await setWebhook();
|
||||
}, 10000);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -102,3 +113,13 @@ function onShutdown(cleanUp: () => Promise<void>) {
|
||||
process.on("SIGINT", handleShutdown);
|
||||
process.on("SIGTERM", handleShutdown);
|
||||
}
|
||||
|
||||
export const urql = new Client({
|
||||
url: process.env.GRAPHQL_URL || "",
|
||||
exchanges: [fetchExchange, cacheExchange],
|
||||
fetchOptions: {
|
||||
headers: {
|
||||
"x-api-key": process.env?.GRAPHQL_API_TOKEN || ""
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user