From b619892c1c0e1b82870ba23f747178a3cccddbdc Mon Sep 17 00:00:00 2001 From: Aidan Date: Mon, 14 Apr 2025 19:30:01 -0400 Subject: [PATCH 1/6] translations: change wording to enforce privacy policy --- src/locales/english.json | 2 +- src/locales/portuguese.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/english.json b/src/locales/english.json index 0a4291b..b2fb10a 100644 --- a/src/locales/english.json +++ b/src/locales/english.json @@ -1,5 +1,5 @@ { - "botWelcome": "*Hello! I am {botName}!*\nI was made with love by some nerds who really love programming!\n\n*Before using, you need to read the privacy policy (/privacy) to understand where your data goes when using this bot.*\n\nAlso, you can use /help to see the bot commands!", + "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.", "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})", diff --git a/src/locales/portuguese.json b/src/locales/portuguese.json index 570f308..6b492f2 100644 --- a/src/locales/portuguese.json +++ b/src/locales/portuguese.json @@ -1,5 +1,5 @@ { - "botWelcome": "*Olá! Eu sou o {botName}!*\n\n*Antes de usar, você precisa ler a política de privacidade (/privacy) para entender onde seus dados vão ao usar este bot.*\n\nAlém disso, você pode usar /help para ver os meus comandos!", + "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.", "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})", From 935385eb4f481f3352a9f97a1fdec86809b88bba Mon Sep 17 00:00:00 2001 From: Aidan Date: Mon, 14 Apr 2025 19:37:43 -0400 Subject: [PATCH 2/6] hf: use global regex instead --- src/commands/crew.js | 16 ++++++++-------- src/commands/help.js | 6 +++--- src/commands/main.js | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/commands/crew.js b/src/commands/crew.js index 18b0eb9..52a3703 100644 --- a/src/commands/crew.js +++ b/src/commands/crew.js @@ -62,7 +62,7 @@ async function handleAdminCommand(ctx, action, successMessage, errorMessage) { reply_to_message_id: ctx.message.message_id }); } catch (error) { - ctx.reply(errorMessage.replace('{error}', error.message), { + ctx.reply(errorMessage.replace(/{error}/g, error.message), { parse_mode: 'Markdown', reply_to_message_id: ctx.message.message_id }); @@ -91,12 +91,12 @@ module.exports = (bot) => { handleAdminCommand(ctx, async () => { try { const commitHash = await getGitCommitHash(); - await ctx.reply(Strings.gitCurrentCommit.replace('{commitHash}', commitHash), { + await ctx.reply(Strings.gitCurrentCommit.replace(/{commitHash}/g, commitHash), { parse_mode: 'Markdown', reply_to_message_id: ctx.message.message_id }); } catch (error) { - ctx.reply(Strings.gitErrRetrievingCommit.replace('{error}', error), { + ctx.reply(Strings.gitErrRetrievingCommit.replace(/{error}/g, error), { parse_mode: 'Markdown', reply_to_message_id: ctx.message.message_id }); @@ -109,12 +109,12 @@ module.exports = (bot) => { handleAdminCommand(ctx, async () => { try { const result = await updateBot(); - await ctx.reply(Strings.botUpdated.replace('{result}', result), { + await ctx.reply(Strings.botUpdated.replace(/{result}/g, result), { parse_mode: 'Markdown', reply_to_message_id: ctx.message.message_id }); } catch (error) { - ctx.reply(Strings.errorUpdatingBot.replace('{error}', error), { + ctx.reply(Strings.errorUpdatingBot.replace(/{error}/g, error), { parse_mode: 'Markdown', reply_to_message_id: ctx.message.message_id }); @@ -127,7 +127,7 @@ module.exports = (bot) => { const botName = ctx.message.text.split(' ').slice(1).join(' '); handleAdminCommand(ctx, async () => { await ctx.telegram.setMyName(botName); - }, Strings.botNameChanged.replace('{botName}', botName), Strings.botNameErr.replace('{error}', error)); + }, Strings.botNameChanged.replace(/{botName}/g, botName), Strings.botNameErr.replace(/{error}/g, error)); }); bot.command('setbotdesc', spamwatchMiddleware, async (ctx) => { @@ -135,7 +135,7 @@ module.exports = (bot) => { const botDesc = ctx.message.text.split(' ').slice(1).join(' '); handleAdminCommand(ctx, async () => { await ctx.telegram.setMyDescription(botDesc); - }, Strings.botDescChanged.replace('{botDesc}', botDesc), Strings.botDescErr.replace('{error}', error)); + }, Strings.botDescChanged.replace(/{botDesc}/g, botDesc), Strings.botDescErr.replace(/{error}/g, error)); }); bot.command('botkickme', spamwatchMiddleware, async (ctx) => { @@ -159,7 +159,7 @@ module.exports = (bot) => { caption: botFile }); } catch (error) { - ctx.reply(Strings.unexpectedErr.replace('{error}', error.message), { + ctx.reply(Strings.unexpectedErr.replace(/{error}/g, error.message), { parse_mode: 'Markdown', reply_to_message_id: ctx.message.message_id }); diff --git a/src/commands/help.js b/src/commands/help.js index 58dfa86..ab9e601 100644 --- a/src/commands/help.js +++ b/src/commands/help.js @@ -6,8 +6,8 @@ async function sendHelpMessage(ctx, isEditing) { const Strings = getStrings(ctx.from.language_code); const botInfo = await ctx.telegram.getMe(); const helpText = Strings.botHelp - .replace('{botName}', botInfo.first_name) - .replace("{sourceLink}", process.env.botSource); + .replace(/{botName}/g, botInfo.first_name) + .replace(/{sourceLink}/g, process.env.botSource); const options = { parse_mode: 'Markdown', disable_web_page_preview: true, @@ -35,7 +35,7 @@ module.exports = (bot) => { bot.command("about", spamwatchMiddleware, async (ctx) => { const Strings = getStrings(ctx.from.language_code); - const aboutMsg = Strings.botAbout.replace("{sourceLink}", `${process.env.botSource}`); + const aboutMsg = Strings.botAbout.replace(/{sourceLink}/g, `${process.env.botSource}`); ctx.reply(aboutMsg, { parse_mode: 'Markdown', diff --git a/src/commands/main.js b/src/commands/main.js index c111603..6333296 100644 --- a/src/commands/main.js +++ b/src/commands/main.js @@ -6,7 +6,7 @@ module.exports = (bot) => { bot.start(spamwatchMiddleware, async (ctx) => { const Strings = getStrings(ctx.from.language_code); const botInfo = await ctx.telegram.getMe(); - const startMsg = Strings.botWelcome.replace('{botName}', botInfo.first_name); + const startMsg = Strings.botWelcome.replace(/{botName}/g, botInfo.first_name); ctx.reply(startMsg, { parse_mode: 'Markdown', From 62e7a1393b01f09c1c95f83ce9b87508427b22f2 Mon Sep 17 00:00:00 2001 From: Aidan Date: Mon, 14 Apr 2025 19:58:36 -0400 Subject: [PATCH 3/6] feat: better error handling and fixed file size checking for /yt --- src/bot.js | 6 ++++++ src/commands/youtube.js | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/bot.js b/src/bot.js index ad909db..472bc10 100644 --- a/src/bot.js +++ b/src/bot.js @@ -6,6 +6,12 @@ require('@dotenvx/dotenvx').config({ path: "config.env" }); require('./plugins/ytdlp-wrapper.js'); // require('./plugins/termlogger.js'); +// Ensures bot token is set, and not default value +if (!process.env.botToken || process.env.botToken === 'InsertYourBotTokenHere') { + console.error('Bot token is not set. Please set the bot token in the config.env file.') + process.exit(1) +} + const bot = new Telegraf(process.env.botToken); const maxRetries = process.env.maxRetries || 5; let restartCount = 0; diff --git a/src/commands/youtube.js b/src/commands/youtube.js index 76b0d29..316385b 100644 --- a/src/commands/youtube.js +++ b/src/commands/youtube.js @@ -94,6 +94,20 @@ module.exports = (bot) => { getApproxSize(ytDlpPath, videoUrl), ]); + if (approxSizeInMB > 50) { + await ctx.telegram.editMessageText( + ctx.chat.id, + downloadingMessage.message_id, + null, + Strings.ytDownload.uploadLimit, { + parse_mode: 'Markdown', + reply_to_message_id: ctx.message.message_id, + }, + ); + + return; + } + await ctx.telegram.editMessageText( ctx.chat.id, downloadingMessage.message_id, @@ -134,7 +148,7 @@ module.exports = (bot) => { fs.unlinkSync(mp4File); } catch (error) { - if (toString(error).includes("Request Entity Too Large")) { + if (error.response.description.includes("Request Entity Too Large")) { await ctx.telegram.editMessageText( ctx.chat.id, downloadingMessage.message_id, From 429e89bf1d35b5f7246419a4ae77fb55a0cee2ef Mon Sep 17 00:00:00 2001 From: Aidan Date: Mon, 14 Apr 2025 20:09:13 -0400 Subject: [PATCH 4/6] docker/docs: dockerize and add+modify documentation --- .dockerignore | 8 ++++++++ Dockerfile | 18 ++++++++++++++++++ README.md | 45 +++++++++++++++++++++++++++++++++++++++++++-- docker-compose.yml | 9 +++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ba231c9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +node_modules +npm-debug.log +.git +.gitignore +.env +config.env +*.md +!README.md \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..56b5b32 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +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/* + +WORKDIR /usr/src/app + +COPY package*.json ./ + +RUN npm install + +COPY . . + +RUN chmod +x /usr/src/app/src/plugins/yt-dlp/yt-dlp + +VOLUME /usr/src/app/config.env + +CMD ["npm", "start"] \ No newline at end of file diff --git a/README.md b/README.md index e2e35ff..6b4fe46 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,10 @@ Kowalski is a a simple Telegram bot made in Node.js. ## Self-host requirements -- Node.js 20 or newer (you can also use Bun) +- Node.js 20 or newer (you can also use [Bun](https://bun.sh)) - A Telegram bot (create one at [@BotFather](https://t.me/botfather)) -- Latest version of Node.js - FFmpeg (only for the `/yt` command) +- Docker and Docker Compose (only required for Docker setup) ## Run it yourself, develop or contribute with Kowalski @@ -36,6 +36,47 @@ After editing the file, save all changes and run the bot with ``npm start``. > [!TIP] > To deal with dependencies, just run ``npm install`` or ``npm i`` at any moment to install all of them. +## Running with Docker + +> [!IMPORTANT] +> Please complete the above steps to prepare your local copy for building. You do not need to install FFmpeg on your host system. + +You can also run Kowalski using Docker, which simplifies the setup process. Make sure you have Docker and Docker Compose installed. + +### Using Docker Compose + +1. **Make sure to setup your `config.env` file first!** + +2. **Run the container** + + ```bash + docker compose up -d + ``` + + > [!NOTE] + > The `-d` flag causes the bot 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. + +1. **Make sure to setup your `config.env` file first!** + +2. **Build the image** + + ```bash + docker build -t kowalski . + ``` + +3. **Run the container** + + ```bash + 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 - **botSource**: Put the link to your bot source code. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..981d90a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +services: + kowalski: + build: . + container_name: kowalski + restart: unless-stopped + volumes: + - ./config.env:/usr/src/app/config.env:ro + environment: + - NODE_ENV=production \ No newline at end of file From 95114dc918a86f7e59589840c8b95a27ff7a7924 Mon Sep 17 00:00:00 2001 From: Aidan Date: Mon, 14 Apr 2025 20:11:57 -0400 Subject: [PATCH 5/6] docs: minor lint/fix --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6b4fe46..370f7d7 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,8 @@ You can also run Kowalski using Docker, which simplifies the setup process. Make docker compose up -d ``` - > [!NOTE] - > The `-d` flag causes the bot to run in the background. If you're just playing around, you may not want to use this flag. +> [!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 @@ -74,8 +74,8 @@ 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. +> [!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 From c6114c9f625e2b3bbfba3e9e3b449047a708bbba Mon Sep 17 00:00:00 2001 From: Aidan Date: Mon, 14 Apr 2025 20:18:44 -0400 Subject: [PATCH 6/6] docs: add troubleshooting section for yt commands --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 370f7d7..a154166 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,18 @@ If you prefer to use Docker directly, you can use these instructions instead. - 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 + +**Q:** I get a "Permission denied (EACCES)" error in the console when running the `/yt` command + +**A:** Make sure `src/plugins/yt-dlp/yt-dlp` is executable. You can do this on Linux like so: + +```bash +chmod +x src/plugins/yt-dlp/yt-dlp +``` + ## About/License BSD-3-Clause - 2024 Lucas Gabriel (lucmsilva).