Merge branch 'main' into main

This commit is contained in:
Lucas Gabriel 2025-04-15 19:40:34 -03:00 committed by GitHub
commit f6886ae504
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 80 additions and 72 deletions

4
.gitmodules vendored
View file

@ -1,3 +1,3 @@
[submodule "src/plugins/lib-spamwatch"]
path = src/plugins/lib-spamwatch
[submodule "src/spamwatch"]
path = src/spamwatch
url = https://github.com/ABOCN/TelegramBot-SpamWatch

View file

@ -1,7 +1,7 @@
FROM node:20-slim
# Install ffmpeg and other deps
RUN apt-get update && apt-get install -y ffmpeg && apt-get clean && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y ffmpeg git && apt-get clean && rm -rf /var/lib/apt/lists/*
WORKDIR /usr/src/app

View file

@ -1,6 +1,7 @@
BSD 3-Clause License
Copyright (c) 2024, Lucas Gabriel
Copyright (c) 2024-2025, Lucas Gabriel <lucmsilva651@gmail.com>,
ABOCN <abocn@protonmail.me> and all contributors
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

View file

@ -1,7 +1,9 @@
# Kowalski (Node.js Telegram Bot)
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md)
![GitHub License](https://img.shields.io/github/license/ABOCN/TelegramBot)
[![GitHub License](https://img.shields.io/github/license/ABOCN/TelegramBot)](https://github.com/abocn/TelegramBot/blob/main/LICENSE)
[![CodeQL](https://github.com/abocn/TelegramBot/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/abocn/TelegramBot/actions/workflows/github-code-scanning/codeql)
[![Dependabot Updates](https://github.com/abocn/TelegramBot/actions/workflows/dependabot/dependabot-updates/badge.svg)](https://github.com/abocn/TelegramBot/actions/workflows/dependabot/dependabot-updates)
Kowalski is a a simple Telegram bot made in Node.js.
@ -9,24 +11,20 @@ Kowalski is a a simple Telegram bot made in Node.js.
## Self-host requirements
- Node.js 20 or newer (you can also use [Bun](https://bun.sh))
> [!IMPORTANT]
> You will only need all of them if you are not running it dockerized. Read ["Running with Docker"](#running-with-docker) for more information.
- Node.js 23 or newer (you can also use [Bun](https://bun.sh))
- A Telegram bot (create one at [@BotFather](https://t.me/botfather))
- FFmpeg (only for the `/yt` command)
- Docker and Docker Compose (only required for Docker setup)
## Run it yourself, develop or contribute with Kowalski
## Running locally (non-Docker setup)
First, clone the repo with Git:
```bash
git clone https://github.com/ABOCN/TelegramBot
```
And now, init the submodules with these commands (this is very important):
```bash
cd TelegramBot
git submodule update --init --recursive
git clone --recurse-submodules https://github.com/ABOCN/TelegramBot
```
Next, inside the repository directory, create a `config.env` file with some content, which you can see the [example .env file](config.env.example) to fill info with. To see the meaning of each one, see [the Functions section](#configenv-functions).
@ -41,6 +39,9 @@ After editing the file, save all changes and run the bot with ``npm start``.
> [!IMPORTANT]
> Please complete the above steps to prepare your local copy for building. You do not need to install FFmpeg on your host system.
> [!NOTE]
> Using the `-d` flag when running causes Kowalski to run in the background. If you're just playing around or testing, you may not want to use this flag.
You can also run Kowalski using Docker, which simplifies the setup process. Make sure you have Docker and Docker Compose installed.
### Using Docker Compose
@ -53,9 +54,6 @@ You can also run Kowalski using Docker, which simplifies the setup process. Make
docker compose up -d
```
> [!NOTE]
> The `-d` flag causes Kowalski to run in the background. If you're just playing around, you may not want to use this flag.
### Using Docker Run
If you prefer to use Docker directly, you can use these instructions instead.
@ -74,21 +72,18 @@ If you prefer to use Docker directly, you can use these instructions instead.
docker run -d --name kowalski --restart unless-stopped -v $(pwd)/config.env:/usr/src/app/config.env:ro kowalski
```
> [!NOTE]
> The `-d` flag causes Kowalski to run in the background. If you're just playing around, you may not want to use this flag.
## config.env Functions
> [!IMPORTANT]
> Take care of your ``config.env`` file, as it is so much important and needs to be secret (like your passwords), as anyone can do whatever they want to the bot with this token!
- **botSource**: Put the link to your bot source code.
- **botPrivacy**: Put the link to your bot privacy policy.
- **maxRetries**: Maximum number of retries for a failing command on Kowalski. Default is 5. If the limit is hit, the bot will crash past this number.
- **botToken**: Put your bot token that you created at [@BotFather](https://t.me/botfather).
- **botAdmins**: Put the ID of the people responsible for managing the bot. They can use some administrative + exclusive commands on any group.
- **lastKey**: Last.fm API key, for use on `lastfm.js` functions, like see who is listening to what song and etc.
- **weatherKey**: Weather.com API key, used for the `/weather` command.
## Note
- Take care of your ``config.env`` file, as it is so much important and needs to be secret (like your passwords), as anyone can do whatever they want to the bot with this token!
## Troubleshooting
### YouTube Downloading

View file

@ -1,5 +1,12 @@
botSource = "https://github.com/change-this/to-your-repo/"
botToken = "InsertYourBotTokenHere"
botAdmins = 0000000000, 00000000, 00000000
# links for source and privacy
botPrivacy = "https://blog.lucmsilva.com/posts/lynx-privacy-policy"
botSource = "https://github.com/ABOCN/TelegramBot"
# insert token here
botToken = ""
# misc (botAdmins isnt a array here!)
maxRetries = 9999
botAdmins = 00000000, 00000000, 00000000
lastKey = "InsertYourLastFmApiKeyHere"
weatherKey = "InsertYourWeatherDotComApiKeyHere"

View file

@ -1,7 +1,7 @@
const { Telegraf } = require('telegraf');
const path = require('path');
const fs = require('fs');
const { isOnSpamWatch } = require('./plugins/lib-spamwatch/spamwatch.js');
const { isOnSpamWatch } = require('./spamwatch/spamwatch.js');
require('@dotenvx/dotenvx').config({ path: "config.env" });
require('./plugins/ytdlp-wrapper.js');
// require('./plugins/termlogger.js');

View file

@ -1,7 +1,7 @@
const Resources = require('../props/resources.json');
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
const axios = require("axios");
module.exports = (bot) => {

View file

@ -1,7 +1,7 @@
const Resources = require('../props/resources.json');
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
const axios = require('axios');
const { verifyInput } = require('../plugins/verifyInput.js');

View file

@ -1,6 +1,6 @@
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
const os = require('os');
const { exec } = require('child_process');
const { error } = require('console');

View file

@ -1,7 +1,7 @@
const Resources = require('../props/resources.json');
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
function sendRandomReply(ctx, gifUrl, textKey) {
const Strings = getStrings(ctx.from.language_code);

View file

@ -4,8 +4,8 @@
// With some help from GPT (I don't really like AI but whatever)
// If this were a kang, I would not be giving credits to him!
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
const axios = require('axios');
const { parse } = require('node-html-parser');
@ -193,14 +193,18 @@ function extractMetaData(meta, key) {
return line ? line.split('"')[1] : "";
}
module.exports = (bot) => {
bot.command(['d', 'device'], spamwatchMiddleware, async (ctx) => {
const userId = ctx.from.id;
function getUsername(ctx){
let userName = String(ctx.from.first_name);
if(userName.includes("<") && userName.includes(">")) {
userName = userName.replaceAll("<", "").replaceAll(">", "");
}
return userName;
}
module.exports = (bot) => {
bot.command(['d', 'device'], spamwatchMiddleware, async (ctx) => {
const userId = ctx.from.id;
const userName = getUsername(ctx);
const phone = ctx.message.text.split(" ").slice(1).join(" ");
if (!phone) {
@ -228,7 +232,7 @@ module.exports = (bot) => {
bot.action(/details:(.+):(.+)/, async (ctx) => {
const url = ctx.match[1];
const userId = parseInt(ctx.match[2]);
const userName = ctx.from.first_name;
const userName = getUsername(ctx);
const callbackQueryUserId = ctx.update.callback_query.from.id;

View file

@ -1,6 +1,6 @@
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
async function sendHelpMessage(ctx, isEditing) {
const Strings = getStrings(ctx.from.language_code);

View file

@ -1,7 +1,7 @@
const Resources = require('../props/resources.json');
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
const axios = require('axios');
const { verifyInput } = require('../plugins/verifyInput.js');

View file

@ -1,6 +1,6 @@
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
async function getUserInfo(ctx) {
const Strings = getStrings(ctx.from.language_code);

View file

@ -2,8 +2,8 @@ const Resources = require('../props/resources.json');
const fs = require('fs');
const axios = require('axios');
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
const scrobbler_url = Resources.lastFmApi;
const api_key = process.env.lastKey;

View file

@ -1,6 +1,6 @@
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
module.exports = (bot) => {
bot.start(spamwatchMiddleware, async (ctx) => {
@ -16,8 +16,9 @@ module.exports = (bot) => {
bot.command('privacy', spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
ctx.reply(
Strings.botPrivacy, {
const message = Strings.botPrivacy.replace("{botPrivacy}", process.env.botPrivacy);
ctx.reply(message, {
parse_mode: 'Markdown',
disable_web_page_preview: true,
reply_to_message_id: ctx.message.message_id

View file

@ -3,8 +3,8 @@ const axios = require('axios');
const fs = require('fs');
const path = require('path');
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
async function downloadModule(moduleId) {
try {

View file

@ -1,7 +1,7 @@
const Resources = require('../props/resources.json');
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
const axios = require("axios");
const { verifyInput } = require('../plugins/verifyInput.js');

View file

@ -1,7 +1,7 @@
// const Resources = require('../props/resources.json');
// const { getStrings } = require('../plugins/checklang.js');
// const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
// const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
// const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
// const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
// const escape = require('markdown-escape');
// const axios = require('axios');

View file

@ -1,7 +1,7 @@
const Resources = require('../props/resources.json');
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
const axios = require("axios");
module.exports = (bot) => {

View file

@ -5,9 +5,9 @@
const Resources = require('../props/resources.json');
const axios = require('axios');
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
const { verifyInput } = require('../plugins/verifyInput.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const statusEmojis = {
0: '⛈', 1: '⛈', 2: '⛈', 3: '⛈', 4: '⛈', 5: '🌨', 6: '🌨', 7: '🌨',

View file

@ -1,6 +1,6 @@
const { getStrings } = require('../plugins/checklang.js');
const { isOnSpamWatch } = require('../plugins/lib-spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../plugins/lib-spamwatch/Middleware.js')(isOnSpamWatch);
const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
const { execFile } = require('child_process');
const os = require('os');
const fs = require('fs');

View file

@ -1,7 +1,7 @@
{
"botWelcome": "*Hello! I'm {botName}!*\nI was made with love by some nerds who really love programming!\n\n*By using {botName}, you affirm that you have read to and agree with the privacy policy (/privacy). This helps you understand where your data goes when using this bot.*\n\nAlso, you can use /help to see the bot commands!",
"botHelp": "*Hey, I'm {botName}, a simple bot made entirely from scratch in Telegraf and Node.js by some nerds who really love programming.*\n\nClick on the buttons below to see which commands you can use!\n",
"botPrivacy": "Check out [this link](https://blog.lucmsilva.com/posts/lynx-privacy-policy) to read the bot's privacy policy.",
"botPrivacy": "Check out [this link]({botPrivacy}) to read the bot's privacy policy.",
"botAbout": "*About the bot*\n\nThe bot base was originally created by [Lucas Gabriel (lucmsilva)](https://github.com/lucmsilva651), now maintained by several people.\n\nThe bot's purpose is to bring fun to your groups here on Telegram in a relaxed and simple way. The bot also features some very useful commands, which you can see using the help command (/help).\n\nSpecial thanks to @givfnz2 for his many contributions to the bot!\n\nSee the source code: [Click here to go to GitHub]({sourceLink})",
"aboutBot": "About the bot",
"varStrings": {

View file

@ -1,7 +1,7 @@
{
"botWelcome": "*Olá! Eu sou o {botName}!*\n\n*Ao usar o {botName}, você afirma que leu e concorda com a política de privacidade (/privacy). Isso ajuda você a entender onde seus dados vão ao usar este bot.*\n\nAlém disso, você pode usar /help para ver os meus comandos!",
"botHelp": "*Oi, eu sou o {botName}, um bot simples feito do zero em Telegraf e Node.js por uns nerds que gostam de programação.*\n\nVeja o código fonte: [Clique aqui para ir ao GitHub]({sourceLink})\n\nClique nos botões abaixo para ver quais comandos você pode usar!\n",
"botPrivacy": "Acesse [este link](https://blog.lucmsilva.com/posts/lynx-privacy-policy) para ler a política de privacidade do bot.",
"botPrivacy": "Acesse [este link]({botPrivacy}) para ler a política de privacidade do bot.",
"botAbout": "*Sobre o bot*\n\nA base deste bot foi feita originalmente por [Lucas Gabriel (lucmsilva)](https://github.com/lucmsilva651), agora sendo mantido por várias pessoas.\n\nA intenção do bot é trazer diversão para os seus grupos aqui no Telegram de uma maneira bem descontraida e simples. O bot também conta com alguns comandos bem úteis, que você consegue ver com o comando de ajuda (/help).\n\nAgradecimento especial ao @givfnz2 pelas suas várias contribuições ao bot!\n\nVeja o código fonte: [Clique aqui para ir ao GitHub]({sourceLink})",
"aboutBot": "Sobre o bot",
"varStrings": {

@ -1 +0,0 @@
Subproject commit 8d35b7ec4cffb48df8d1f59485b32e2484ae64e7

1
src/spamwatch Submodule

@ -0,0 +1 @@
Subproject commit b71b3b9eab0f172c038674fc6739fce9199ad3e0