diff --git a/.dockerignore b/.dockerignore
index ba231c9..33e390a 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -3,6 +3,5 @@ npm-debug.log
.git
.gitignore
.env
-config.env
*.md
!README.md
\ No newline at end of file
diff --git a/config.env.example b/.env.example
similarity index 100%
rename from config.env.example
rename to .env.example
diff --git a/.gitignore b/.gitignore
index ba85ba8..6b42f1f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -136,11 +136,12 @@ dist
lastfm.json
sw-blocklist.txt
package-lock.json
-bun.lock
-bun.lockb
tmp/
# Executables
*.exe
yt-dlp
-ffmpeg
\ No newline at end of file
+ffmpeg
+
+# Bun
+bun.lock*
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 473f9b7..7971682 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -13,6 +13,6 @@ COPY . .
RUN chmod +x /usr/src/app/src/plugins/yt-dlp/yt-dlp
-VOLUME /usr/src/app/config.env
+VOLUME /usr/src/app/.env
CMD ["npm", "start"]
\ No newline at end of file
diff --git a/README.md b/README.md
index 71e5cff..37e61a7 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,7 @@
[](CODE_OF_CONDUCT.md)
[](https://github.com/abocn/TelegramBot/blob/main/LICENSE)
+[](https://www.typescriptlang.org)
[](https://github.com/abocn/TelegramBot/actions/workflows/github-code-scanning/codeql)
[](https://github.com/abocn/TelegramBot/actions/workflows/dependabot/dependabot-updates)
@@ -14,7 +15,7 @@ Kowalski is a a simple Telegram bot made in Node.js.
> [!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))
+- [Bun](https://bun.sh) (latest is suggested)
- 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)
@@ -27,18 +28,20 @@ First, clone the repo with Git:
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).
+Next, inside the repository directory, create an `.env` file with some content, which you can see the [example .env file](.env.example) to fill info with. To see the meaning of each one, see [the Functions section](#env-functions).
-After editing the file, save all changes and run the bot with ``npm start``.
+After editing the file, save all changes and run the bot with ``bun start``.
> [!TIP]
-> To deal with dependencies, just run ``npm install`` or ``npm i`` at any moment to install all of them.
+> To deal with dependencies, just run ``bun install`` or ``bun 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.
+---
+
> [!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.
@@ -46,7 +49,7 @@ You can also run Kowalski using Docker, which simplifies the setup process. Make
### Using Docker Compose
-1. **Make sure to setup your `config.env` file first!**
+1. **Make sure to setup your `.env` file first!**
2. **Run the container**
@@ -58,7 +61,7 @@ You can also run Kowalski using Docker, which simplifies the setup process. Make
If you prefer to use Docker directly, you can use these instructions instead.
-1. **Make sure to setup your `config.env` file first!**
+1. **Make sure to setup your `.env` file first!**
2. **Build the image**
@@ -69,12 +72,13 @@ If you prefer to use Docker directly, you can use these instructions instead.
3. **Run the container**
```bash
- docker run -d --name kowalski --restart unless-stopped -v $(pwd)/config.env:/usr/src/app/config.env:ro kowalski
+ docker run -d --name kowalski --restart unless-stopped -v $(pwd)/.env:/usr/src/app/.env:ro kowalski
```
-## config.env Functions
+## .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!
+> Take care of your ``.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.
@@ -99,7 +103,7 @@ chmod +x src/plugins/yt-dlp/yt-dlp
## Contributors
-
+
Made with [contrib.rocks](https://contrib.rocks).
diff --git a/docker-compose.yml b/docker-compose.yml
index 981d90a..0aab44a 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -4,6 +4,6 @@ services:
container_name: kowalski
restart: unless-stopped
volumes:
- - ./config.env:/usr/src/app/config.env:ro
+ - ./.env:/usr/src/app/.env:ro
environment:
- NODE_ENV=production
\ No newline at end of file
diff --git a/nodemon.json b/nodemon.json
index d7508b0..918bcb8 100644
--- a/nodemon.json
+++ b/nodemon.json
@@ -1,3 +1,6 @@
{
- "ignore": ["src/props/*.json", "src/props/*.txt"]
+ "ignore": ["src/props/*.json", "src/props/*.txt"],
+ "watch": ["src"],
+ "ext": "ts,js",
+ "exec": "bun src/bot.ts"
}
\ No newline at end of file
diff --git a/package.json b/package.json
index 379cc96..db30850 100644
--- a/package.json
+++ b/package.json
@@ -1,12 +1,13 @@
{
"scripts": {
- "start": "nodemon src/bot.js"
+ "start": "nodemon src/bot.ts"
},
"dependencies": {
- "@dotenvx/dotenvx": "^1.28.0",
- "axios": "^1.7.9",
+ "@dotenvx/dotenvx": "^1.41.0",
+ "@types/node": "^22.15.2",
+ "axios": "^1.9.0",
"node-html-parser": "^7.0.1",
- "nodemon": "^3.1.7",
+ "nodemon": "^3.1.10",
"telegraf": "^4.16.3",
"winston": "^3.17.0"
}
diff --git a/src/bot.js b/src/bot.ts
similarity index 77%
rename from src/bot.js
rename to src/bot.ts
index f053de7..3422e56 100644
--- a/src/bot.js
+++ b/src/bot.ts
@@ -1,13 +1,13 @@
-const { Telegraf } = require('telegraf');
-const path = require('path');
-const fs = require('fs');
-const { isOnSpamWatch } = require('./spamwatch/spamwatch.js');
-require('@dotenvx/dotenvx').config({ path: "config.env" });
-require('./plugins/ytDlpWrapper.js');
+import { Telegraf } from 'telegraf';
+import path from 'path';
+import fs from 'fs';
+import { isOnSpamWatch } from './spamwatch/spamwatch';
+import '@dotenvx/dotenvx';
+import './plugins/ytDlpWrapper';
// 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.')
+ console.error('Bot token is not set. Please set the bot token in the .env file.')
process.exit(1)
}
@@ -19,10 +19,13 @@ const loadCommands = () => {
const commandsPath = path.join(__dirname, 'commands');
try {
- const files = fs.readdirSync(commandsPath);
+ const files = fs.readdirSync(commandsPath)
+ .filter(file => file.endsWith('.ts') || file.endsWith('.js'));
+
files.forEach((file) => {
try {
- const command = require(path.join(commandsPath, file));
+ const commandPath = path.join(commandsPath, file);
+ const command = require(commandPath).default || require(commandPath);
if (typeof command === 'function') {
command(bot, isOnSpamWatch);
}
@@ -43,7 +46,7 @@ const startBot = async () => {
restartCount = 0;
} catch (error) {
console.error('Failed to start bot:', error.message);
- if (restartCount < maxRetries) {
+ if (restartCount < Number(maxRetries)) {
restartCount++;
console.log(`Retrying to start bot... Attempt ${restartCount}`);
setTimeout(startBot, 5000);
diff --git a/src/commands/animal.js b/src/commands/animal.ts
similarity index 67%
rename from src/commands/animal.js
rename to src/commands/animal.ts
index 332e0e3..89eecba 100644
--- a/src/commands/animal.js
+++ b/src/commands/animal.ts
@@ -1,66 +1,76 @@
-const Resources = require('../props/resources.json');
-const { getStrings } = require('../plugins/checkLang.js');
-const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
-const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
-const axios = require("axios");
+import Resources from '../props/resources.json';
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+import axios from 'axios';
+import { Context, Telegraf } from 'telegraf';
-module.exports = (bot) => {
- bot.command("duck", spamwatchMiddleware, async (ctx) => {
- const Strings = getStrings(ctx.from.language_code);
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
+
+export default (bot: Telegraf) => {
+ bot.command("duck", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ const Strings = getStrings(ctx.from?.language_code);
try {
const response = await axios(Resources.duckApi);
ctx.replyWithPhoto(response.data.url, {
caption: "🦆",
+ // reply_to_message_id works fine, using this for now to avoid errors
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
} catch (error) {
const message = Strings.duckApiErr.replace('{error}', error.message);
ctx.reply(message, {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
return;
}
});
- bot.command("fox", spamwatchMiddleware, async (ctx) => {
- const Strings = getStrings(ctx.from.language_code);
+ bot.command("fox", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ const Strings = getStrings(ctx.from?.language_code);
try {
const response = await axios(Resources.foxApi);
ctx.replyWithPhoto(response.data.image, {
caption: "🦊",
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
} catch (error) {
const message = Strings.foxApiErr.replace('{error}', error.message);
ctx.reply(message, {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
return;
}
});
- bot.command("dog", spamwatchMiddleware, async (ctx) => {
- const Strings = getStrings(ctx.from.language_code);
+ bot.command("dog", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ const Strings = getStrings(ctx.from?.language_code);
try {
const response = await axios(Resources.dogApi);
ctx.replyWithPhoto(response.data.message, {
caption: "🐶",
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
} catch (error) {
const message = Strings.foxApiErr.replace('{error}', error.message);
ctx.reply(message, {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
return;
}
});
- bot.command("cat", spamwatchMiddleware, async (ctx) => {
- const Strings = getStrings(ctx.from.language_code);
+ bot.command("cat", spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ const Strings = getStrings(ctx.from?.language_code);
const apiUrl = `${Resources.catApi}?json=true`;
const response = await axios.get(apiUrl);
const data = response.data;
@@ -70,17 +80,19 @@ module.exports = (bot) => {
await ctx.replyWithPhoto(imageUrl, {
caption: `🐱`,
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
} catch (error) {
ctx.reply(Strings.catImgErr, {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
};
});
- bot.command(['soggy', 'soggycat'], spamwatchMiddleware, async (ctx) => {
+ bot.command(['soggy', 'soggycat'], spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const userInput = ctx.message.text.split(' ')[1];
switch (true) {
@@ -89,6 +101,7 @@ module.exports = (bot) => {
Resources.soggyCat2, {
caption: Resources.soggyCat2,
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
break;
@@ -96,6 +109,7 @@ module.exports = (bot) => {
case (userInput === "3" || userInput === "sticker"):
ctx.replyWithSticker(
Resources.soggyCatSticker, {
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
break;
@@ -105,6 +119,7 @@ module.exports = (bot) => {
Resources.soggyCatAlt, {
caption: Resources.soggyCatAlt,
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
break;
@@ -114,6 +129,7 @@ module.exports = (bot) => {
Resources.soggyCat, {
caption: Resources.soggyCat,
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
break;
diff --git a/src/commands/codename.js b/src/commands/codename.ts
similarity index 62%
rename from src/commands/codename.js
rename to src/commands/codename.ts
index 138ae51..7f4a3e5 100644
--- a/src/commands/codename.js
+++ b/src/commands/codename.ts
@@ -1,11 +1,14 @@
-const Resources = require('../props/resources.json');
-const { getStrings } = require('../plugins/checkLang.js');
-const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
-const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
-const axios = require('axios');
-const { verifyInput } = require('../plugins/verifyInput.js');
+import Resources from '../props/resources.json';
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+import axios from 'axios';
+import verifyInput from '../plugins/verifyInput';
+import { Context, Telegraf } from 'telegraf';
-async function getDeviceList() {
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
+
+async function getDeviceList({ Strings, ctx }: { Strings: any, ctx: Context & { message: { text: string } } }) {
try {
const response = await axios.get(Resources.codenameApi);
return response.data
@@ -15,27 +18,29 @@ async function getDeviceList() {
return ctx.reply(message, {
parse_mode: "Markdown",
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
}
}
-module.exports = (bot) => {
- bot.command(['codename', 'whatis'], spamwatchMiddleware, async (ctx) => {
+export default (bot: Telegraf) => {
+ bot.command(['codename', 'whatis'], spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const userInput = ctx.message.text.split(" ").slice(1).join(" ");
- const Strings = getStrings(ctx.from.language_code);
+ const Strings = getStrings(ctx.from?.language_code);
const { noCodename } = Strings.codenameCheck
if(verifyInput(ctx, userInput, noCodename)){
return;
}
- const jsonRes = await getDeviceList()
+ const jsonRes = await getDeviceList({ Strings, ctx })
const phoneSearch = Object.keys(jsonRes).find((codename) => codename === userInput);
if (!phoneSearch) {
return ctx.reply(Strings.codenameCheck.notFound, {
parse_mode: "Markdown",
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
}
@@ -50,6 +55,7 @@ module.exports = (bot) => {
return ctx.reply(message, {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
})
diff --git a/src/commands/crew.js b/src/commands/crew.ts
similarity index 62%
rename from src/commands/crew.js
rename to src/commands/crew.ts
index e2282ea..c55b774 100644
--- a/src/commands/crew.js
+++ b/src/commands/crew.ts
@@ -1,9 +1,12 @@
-const { getStrings } = require('../plugins/checkLang.js');
-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');
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+import os from 'os';
+import { exec } from 'child_process';
+import { error } from 'console';
+import { Context, Telegraf } from 'telegraf';
+
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
function getGitCommitHash() {
return new Promise((resolve, reject) => {
@@ -29,7 +32,7 @@ function updateBot() {
});
}
-function formatUptime(uptime) {
+function formatUptime(uptime: number) {
const hours = Math.floor(uptime / 3600);
const minutes = Math.floor((uptime % 3600) / 60);
const seconds = Math.floor(uptime % 60);
@@ -50,152 +53,190 @@ function getSystemInfo() {
`*Uptime:* \`${formatUptime(uptime())}\`\n\n`;
}
-async function handleAdminCommand(ctx, action, successMessage, errorMessage) {
- const Strings = getStrings(ctx.from.language_code);
- const userId = ctx.from.id;
- const adminArray = JSON.parse("[" + process.env.botAdmins + "]");
- if (adminArray.includes(userId)) {
+async function handleAdminCommand(ctx: Context & { message: { text: string } }, action: () => Promise, successMessage: string, errorMessage: string) {
+ const Strings = getStrings(ctx.from?.language_code);
+ const userId = ctx.from?.id;
+ const adminArray = process.env.botAdmins ? process.env.botAdmins.split(',').map(id => parseInt(id.trim())) : [];
+ if (userId && adminArray.includes(userId)) {
try {
await action();
- ctx.reply(successMessage, {
- parse_mode: 'Markdown',
- reply_to_message_id: ctx.message.message_id
- });
+ if (successMessage) {
+ ctx.reply(successMessage, {
+ parse_mode: 'Markdown',
+ // @ts-ignore
+ reply_to_message_id: ctx.message.message_id
+ });
+ }
} catch (error) {
ctx.reply(errorMessage.replace(/{error}/g, error.message), {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
}
} else {
ctx.reply(Strings.noPermission, {
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
}
}
-module.exports = (bot) => {
- bot.command('getbotstats', spamwatchMiddleware, async (ctx) => {
- const Strings = getStrings(ctx.from.language_code);
+export default (bot: Telegraf) => {
+ bot.command('getbotstats', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ const Strings = getStrings(ctx.from?.language_code);
handleAdminCommand(ctx, async () => {
const stats = getSystemInfo();
await ctx.reply(stats, {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
}, '', Strings.errorRetrievingStats);
});
- bot.command('getbotcommit', spamwatchMiddleware, async (ctx) => {
- const Strings = getStrings(ctx.from.language_code);
+ bot.command('getbotcommit', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ const Strings = getStrings(ctx.from?.language_code);
handleAdminCommand(ctx, async () => {
try {
const commitHash = await getGitCommitHash();
await ctx.reply(Strings.gitCurrentCommit.replace(/{commitHash}/g, commitHash), {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
} catch (error) {
ctx.reply(Strings.gitErrRetrievingCommit.replace(/{error}/g, error), {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
}
}, '', Strings.gitErrRetrievingCommit);
});
- bot.command('updatebot', spamwatchMiddleware, async (ctx) => {
- const Strings = getStrings(ctx.from.language_code);
+ bot.command('updatebot', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ const Strings = getStrings(ctx.from?.language_code);
handleAdminCommand(ctx, async () => {
try {
const result = await updateBot();
await ctx.reply(Strings.botUpdated.replace(/{result}/g, result), {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
} catch (error) {
ctx.reply(Strings.errorUpdatingBot.replace(/{error}/g, error), {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
}
}, '', Strings.errorUpdatingBot);
});
- bot.command('setbotname', spamwatchMiddleware, async (ctx) => {
- const Strings = getStrings(ctx.from.language_code);
+ bot.command('setbotname', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ const Strings = getStrings(ctx.from?.language_code);
const botName = ctx.message.text.split(' ').slice(1).join(' ');
handleAdminCommand(ctx, async () => {
await ctx.telegram.setMyName(botName);
}, Strings.botNameChanged.replace(/{botName}/g, botName), Strings.botNameErr.replace(/{error}/g, error));
});
- bot.command('setbotdesc', spamwatchMiddleware, async (ctx) => {
- const Strings = getStrings(ctx.from.language_code);
+ bot.command('setbotdesc', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ const Strings = getStrings(ctx.from?.language_code);
const botDesc = ctx.message.text.split(' ').slice(1).join(' ');
handleAdminCommand(ctx, async () => {
await ctx.telegram.setMyDescription(botDesc);
}, Strings.botDescChanged.replace(/{botDesc}/g, botDesc), Strings.botDescErr.replace(/{error}/g, error));
});
- bot.command('botkickme', spamwatchMiddleware, async (ctx) => {
- const Strings = getStrings(ctx.from.language_code);
+ bot.command('botkickme', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ const Strings = getStrings(ctx.from?.language_code);
handleAdminCommand(ctx, async () => {
+ if (!ctx.chat) {
+ ctx.reply(Strings.chatNotFound, {
+ parse_mode: 'Markdown',
+ // @ts-ignore
+ reply_to_message_id: ctx.message.message_id
+ });
+ return;
+ }
ctx.reply(Strings.kickingMyself, {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
await ctx.telegram.leaveChat(ctx.chat.id);
}, '', Strings.kickingMyselfErr);
});
- bot.command('getfile', spamwatchMiddleware, async (ctx) => {
- const Strings = getStrings(ctx.from.language_code);
+ bot.command('getfile', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ const Strings = getStrings(ctx.from?.language_code);
const botFile = ctx.message.text.split(' ').slice(1).join(' ');
+
+ if (!botFile) {
+ ctx.reply(Strings.noFileProvided, {
+ parse_mode: 'Markdown',
+ // @ts-ignore
+ reply_to_message_id: ctx.message.message_id
+ });
+ return;
+ }
+
handleAdminCommand(ctx, async () => {
try {
await ctx.replyWithDocument({
+ // @ts-ignore
source: botFile,
caption: botFile
+ }, {
+ // @ts-ignore
+ reply_to_message_id: ctx.message.message_id
});
} catch (error) {
ctx.reply(Strings.unexpectedErr.replace(/{error}/g, error.message), {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
}
}, '', Strings.unexpectedErr);
});
- bot.command('run', spamwatchMiddleware, async (ctx) => {
+ bot.command('run', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const command = ctx.message.text.split(' ').slice(1).join(' ');
handleAdminCommand(ctx, async () => {
if (!command) {
- return ctx.reply('Por favor, forneça um comando para executar.');
+ ctx.reply('Por favor, forneça um comando para executar.');
+ return;
}
exec(command, (error, stdout, stderr) => {
if (error) {
return ctx.reply(`\`${error.message}\``, {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
}
if (stderr) {
return ctx.reply(`\`${stderr}\``, {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
}
ctx.reply(`\`${stdout}\``, {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
});
}, '', "Nope!");
});
- bot.command('eval', spamwatchMiddleware, async (ctx) => {
+ bot.command('eval', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
const code = ctx.message.text.split(' ').slice(1).join(' ');
if (!code) {
return ctx.reply('Por favor, forneça um código para avaliar.');
@@ -205,19 +246,21 @@ module.exports = (bot) => {
const result = eval(code);
ctx.reply(`Result: ${result}`, {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
} catch (error) {
ctx.reply(`Error: ${error.message}`, {
parse_mode: 'Markdown',
+ // @ts-ignore
reply_to_message_id: ctx.message.message_id
});
}
});
- bot.command('crash', spamwatchMiddleware, async (ctx) => {
+ bot.command('crash', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
handleAdminCommand(ctx, async () => {
- ctx.reply(null);
+ ctx.reply('Crashed!');
}, '', "Nope!");
});
};
diff --git a/src/commands/fun.js b/src/commands/fun.js
deleted file mode 100644
index 0c64bbe..0000000
--- a/src/commands/fun.js
+++ /dev/null
@@ -1,101 +0,0 @@
-const Resources = require('../props/resources.json');
-const { getStrings } = require('../plugins/checkLang.js');
-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);
- const randomNumber = Math.floor(Math.random() * 100);
- const shouldSendGif = randomNumber > 50;
-
- const caption = Strings[textKey].replace('{randomNum}', randomNumber)
-
- if (shouldSendGif) {
- ctx.replyWithAnimation(gifUrl, {
- caption,
- parse_mode: 'Markdown',
- reply_to_message_id: ctx.message.message_id
- }).catch(err => {
- gifErr = gifErr.replace('{err}', err);
- ctx.reply(Strings.gifErr, {
- parse_mode: 'Markdown',
- reply_to_message_id: ctx.message.message_id
- });
- });
- } else {
- ctx.reply(caption, {
- parse_mode: 'Markdown',
- reply_to_message_id: ctx.message.message_id
- });
- }
-}
-
-
-async function handleDiceCommand(ctx, emoji, delay) {
- const Strings = getStrings(ctx.from.language_code);
-
- const result = await ctx.sendDice({ emoji, reply_to_message_id: ctx.message.message_id });
- const botResponse = Strings.funEmojiResult
- .replace('{emoji}', result.dice.emoji)
- .replace('{value}', result.dice.value);
-
- setTimeout(() => {
- ctx.reply(botResponse, {
- parse_mode: 'Markdown',
- reply_to_message_id: ctx.message.message_id
- });
- }, delay);
-}
-
-function getRandomInt(max) {
- return Math.floor(Math.random() * (max + 1));
-}
-
-module.exports = (bot) => {
- bot.command('random', spamwatchMiddleware, async (ctx) => {
- const Strings = getStrings(ctx.from.language_code);
- const randomValue = getRandomInt(11);
- const randomVStr = Strings.randomNum.replace('{number}', randomValue);
-
- ctx.reply(
- randomVStr, {
- parse_mode: 'Markdown',
- reply_to_message_id: ctx.message.message_id
- });
- });
-
- bot.command('dice', spamwatchMiddleware, async (ctx) => {
- await handleDiceCommand(ctx, undefined, 4000);
- });
-
- bot.command('slot', spamwatchMiddleware, async (ctx) => {
- await handleDiceCommand(ctx, '🎰', 3000);
- });
-
- bot.command('ball', spamwatchMiddleware, async (ctx) => {
- await handleDiceCommand(ctx, '⚽', 3000);
- });
-
- bot.command('dart', spamwatchMiddleware, async (ctx) => {
- await handleDiceCommand(ctx, '🎯', 3000);
- });
-
- bot.command('bowling', spamwatchMiddleware, async (ctx) => {
- await handleDiceCommand(ctx, '🎳', 3000);
- });
-
- bot.command('idice', spamwatchMiddleware, async (ctx) => {
- ctx.replyWithSticker(
- Resources.infiniteDice, {
- reply_to_message_id: ctx.message.message_id
- });
- });
-
- bot.command('furry', spamwatchMiddleware, async (ctx) => {
- sendRandomReply(ctx, Resources.furryGif, 'furryAmount');
- });
-
- bot.command('gay', spamwatchMiddleware, async (ctx) => {
- sendRandomReply(ctx, Resources.gayFlag, 'gayAmount');
- });
-};
\ No newline at end of file
diff --git a/src/commands/fun.ts b/src/commands/fun.ts
new file mode 100644
index 0000000..b1437bf
--- /dev/null
+++ b/src/commands/fun.ts
@@ -0,0 +1,112 @@
+import Resources from '../props/resources.json';
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+import { Context, Telegraf } from 'telegraf';
+
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
+
+function sendRandomReply(ctx: Context & { message: { text: string } }, gifUrl: string, textKey: string) {
+ const Strings = getStrings(ctx.from?.language_code);
+ const randomNumber = Math.floor(Math.random() * 100);
+ const shouldSendGif = randomNumber > 50;
+
+ const caption = Strings[textKey].replace('{randomNum}', randomNumber)
+
+ if (shouldSendGif) {
+ ctx.replyWithAnimation(gifUrl, {
+ caption,
+ parse_mode: 'Markdown',
+ // @ts-ignore
+ reply_to_message_id: ctx.message.message_id
+ }).catch(err => {
+ const gifErr = Strings.gifErr.replace('{err}', err);
+ ctx.reply(gifErr, {
+ parse_mode: 'Markdown',
+ // @ts-ignore
+ reply_to_message_id: ctx.message.message_id
+ });
+ });
+ } else {
+ ctx.reply(caption, {
+ parse_mode: 'Markdown',
+ // @ts-ignore
+ reply_to_message_id: ctx.message.message_id
+ });
+ }
+}
+
+
+async function handleDiceCommand(ctx: Context & { message: { text: string } }, emoji: string, delay: number) {
+ const Strings = getStrings(ctx.from?.language_code);
+
+ // @ts-ignore
+ const result = await ctx.sendDice({ emoji, reply_to_message_id: ctx.message.message_id });
+ const botResponse = Strings.funEmojiResult
+ .replace('{emoji}', result.dice.emoji)
+ .replace('{value}', result.dice.value);
+
+ setTimeout(() => {
+ ctx.reply(botResponse, {
+ parse_mode: 'Markdown',
+ // @ts-ignore
+ reply_to_message_id: ctx.message.message_id
+ });
+ }, delay);
+}
+
+function getRandomInt(max) {
+ return Math.floor(Math.random() * (max + 1));
+}
+
+export default (bot: Telegraf) => {
+ bot.command('random', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ const Strings = getStrings(ctx.from?.language_code);
+ const randomValue = getRandomInt(11);
+ const randomVStr = Strings.randomNum.replace('{number}', randomValue);
+
+ ctx.reply(
+ randomVStr, {
+ parse_mode: 'Markdown',
+ // @ts-ignore
+ reply_to_message_id: ctx.message.message_id
+ });
+ });
+
+ // TODO: maybe send custom stickers to match result of the roll? i think there are pre-existing ones
+ bot.command('dice', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ await handleDiceCommand(ctx, '🎲', 4000);
+ });
+
+ bot.command('slot', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ await handleDiceCommand(ctx, '🎰', 3000);
+ });
+
+ bot.command('ball', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ await handleDiceCommand(ctx, '⚽', 3000);
+ });
+
+ bot.command('dart', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ await handleDiceCommand(ctx, '🎯', 3000);
+ });
+
+ bot.command('bowling', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ await handleDiceCommand(ctx, '🎳', 3000);
+ });
+
+ bot.command('idice', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ ctx.replyWithSticker(
+ Resources.infiniteDice, {
+ // @ts-ignore
+ reply_to_message_id: ctx.message.message_id
+ });
+ });
+
+ bot.command('furry', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ sendRandomReply(ctx, Resources.furryGif, 'furryAmount');
+ });
+
+ bot.command('gay', spamwatchMiddleware, async (ctx: Context & { message: { text: string } }) => {
+ sendRandomReply(ctx, Resources.gayFlag, 'gayAmount');
+ });
+};
\ No newline at end of file
diff --git a/src/commands/gsmarena.js b/src/commands/gsmarena.ts
similarity index 91%
rename from src/commands/gsmarena.js
rename to src/commands/gsmarena.ts
index 23478c3..43a20ed 100644
--- a/src/commands/gsmarena.js
+++ b/src/commands/gsmarena.ts
@@ -4,18 +4,23 @@
// 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('../spamwatch/spamwatch.js');
-const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+import axios from 'axios';
+import { parse } from 'node-html-parser';
-const axios = require('axios');
-const { parse } = require('node-html-parser');
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
-class PhoneSearchResult {
- constructor(name, url) {
- this.name = name;
- this.url = url;
- Object.freeze(this);
- }
+interface PhoneSearchResult {
+ name: string;
+ url: string;
+}
+
+interface PhoneDetails {
+ specs: Record>;
+ name?: string;
+ url?: string;
+ picture?: string;
}
const HEADERS = {
@@ -32,7 +37,7 @@ function getDataFromSpecs(specsData, category, attributes) {
.join("\n");
}
-function parseSpecs(specsData) {
+function parseSpecs(specsData: PhoneDetails): PhoneDetails {
const categories = {
"status": ["Launch", ["Status"]],
"network": ["Network", ["Technology"]],
@@ -69,7 +74,7 @@ function parseSpecs(specsData) {
const [cat, attrs] = categories[key];
acc[key] = getDataFromSpecs(specsData, cat, attrs) || "";
return acc;
- }, {});
+ }, { specs: {} } as PhoneDetails);
parsedData["name"] = specsData.name || "";
parsedData["url"] = specsData.url || "";
@@ -77,7 +82,7 @@ function parseSpecs(specsData) {
return parsedData;
}
-function formatPhone(phone) {
+function formatPhone(phone: PhoneDetails) {
const formattedPhone = parseSpecs(phone);
const attributesDict = {
"Status": "status",
@@ -132,7 +137,7 @@ async function fetchHtml(url) {
}
}
-async function searchPhone(phone) {
+async function searchPhone(phone: string): Promise {
try {
const searchUrl = `https://m.gsmarena.com/results.php3?sQuickSearch=yes&sName=${encodeURIComponent(phone)}`;
const htmlContent = await fetchHtml(searchUrl);
@@ -142,7 +147,7 @@ async function searchPhone(phone) {
return foundPhones.map((phoneTag) => {
const name = phoneTag.querySelector('img')?.getAttribute('title') || "";
const url = phoneTag.querySelector('a')?.getAttribute('href') || "";
- return new PhoneSearchResult(name, url);
+ return { name, url };
});
} catch (error) {
console.error("Error searching for phone:", error);
@@ -164,7 +169,7 @@ async function checkPhoneDetails(url) {
return { ...specsData, name, picture, url: `https://www.gsmarena.com/${url}` };
} catch (error) {
console.error("Error fetching phone details:", error);
- return {};
+ return { specs: {}, name: "", url: "", picture: "" };
}
}
@@ -201,7 +206,7 @@ function getUsername(ctx){
return userName;
}
-module.exports = (bot) => {
+export default (bot) => {
bot.command(['d', 'device'], spamwatchMiddleware, async (ctx) => {
const userId = ctx.from.id;
const userName = getUsername(ctx);
diff --git a/src/commands/help.js b/src/commands/help.ts
similarity index 85%
rename from src/commands/help.js
rename to src/commands/help.ts
index b4cc44b..95ea804 100644
--- a/src/commands/help.js
+++ b/src/commands/help.ts
@@ -1,6 +1,17 @@
-const { getStrings } = require('../plugins/checkLang.js');
-const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
-const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
+
+interface MessageOptions {
+ parse_mode: string;
+ disable_web_page_preview: boolean;
+ reply_markup: {
+ inline_keyboard: { text: any; callback_data: string; }[][];
+ };
+ reply_to_message_id?: number;
+}
async function sendHelpMessage(ctx, isEditing) {
const Strings = getStrings(ctx.from.language_code);
@@ -11,8 +22,8 @@ async function sendHelpMessage(ctx, isEditing) {
function getMessageId(ctx) {
return ctx.message?.message_id || ctx.callbackQuery?.message?.message_id;
};
- const createOptions = (ctx, includeReplyTo = false) => {
- const options = {
+ const createOptions = (ctx, includeReplyTo = false): MessageOptions => {
+ const options: MessageOptions = {
parse_mode: 'Markdown',
disable_web_page_preview: true,
reply_markup: {
@@ -39,9 +50,9 @@ async function sendHelpMessage(ctx, isEditing) {
};
}
-module.exports = (bot) => {
+export default (bot) => {
bot.help(spamwatchMiddleware, async (ctx) => {
- await sendHelpMessage(ctx);
+ await sendHelpMessage(ctx, false);
});
bot.command("about", spamwatchMiddleware, async (ctx) => {
diff --git a/src/commands/http.js b/src/commands/http.ts
similarity index 84%
rename from src/commands/http.js
rename to src/commands/http.ts
index 1382ad6..5e47a49 100644
--- a/src/commands/http.js
+++ b/src/commands/http.ts
@@ -1,11 +1,13 @@
-const Resources = require('../props/resources.json');
-const { getStrings } = require('../plugins/checkLang.js');
-const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
-const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
-const axios = require('axios');
-const { verifyInput } = require('../plugins/verifyInput.js');
+import Resources from '../props/resources.json';
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+import axios from 'axios';
+import verifyInput from '../plugins/verifyInput';
-module.exports = (bot) => {
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
+
+export default (bot) => {
bot.command("http", spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
const userInput = ctx.message.text.split(' ')[1];
diff --git a/src/commands/info.js b/src/commands/info.ts
similarity index 85%
rename from src/commands/info.js
rename to src/commands/info.ts
index eed4874..a19651c 100644
--- a/src/commands/info.js
+++ b/src/commands/info.ts
@@ -1,6 +1,8 @@
-const { getStrings } = require('../plugins/checkLang.js');
-const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
-const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
async function getUserInfo(ctx) {
const Strings = getStrings(ctx.from.language_code);
@@ -9,7 +11,7 @@ async function getUserInfo(ctx) {
lastName = " ";
}
- userInfo = Strings.userInfo
+ const userInfo = Strings.userInfo
.replace('{userName}', `${ctx.from.first_name} ${lastName}` || Strings.varStrings.varUnknown)
.replace('{userId}', ctx.from.id || Strings.varStrings.varUnknown)
.replace('{userHandle}', ctx.from.username ? `@${ctx.from.username}` : Strings.varStrings.varNone)
@@ -22,7 +24,7 @@ async function getUserInfo(ctx) {
async function getChatInfo(ctx) {
const Strings = getStrings(ctx.from.language_code);
if (ctx.chat.type === 'group' || ctx.chat.type === 'supergroup') {
- chatInfo = Strings.chatInfo
+ const chatInfo = Strings.chatInfo
.replace('{chatId}', ctx.chat.id || Strings.varStrings.varUnknown)
.replace('{chatName}', ctx.chat.title || Strings.varStrings.varUnknown)
.replace('{chatHandle}', ctx.chat.username ? `@${ctx.chat.username}` : Strings.varStrings.varNone)
@@ -40,7 +42,7 @@ async function getChatInfo(ctx) {
}
}
-module.exports = (bot) => {
+export default (bot) => {
bot.command('chatinfo', spamwatchMiddleware, async (ctx) => {
const chatInfo = await getChatInfo(ctx);
ctx.reply(
diff --git a/src/commands/lastfm.js b/src/commands/lastfm.ts
similarity index 92%
rename from src/commands/lastfm.js
rename to src/commands/lastfm.ts
index 1b1976f..39d6c8d 100644
--- a/src/commands/lastfm.js
+++ b/src/commands/lastfm.ts
@@ -1,9 +1,11 @@
-const Resources = require('../props/resources.json');
-const fs = require('fs');
-const axios = require('axios');
-const { getStrings } = require('../plugins/checkLang.js');
-const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
-const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
+import Resources from '../props/resources.json';
+import fs from 'fs';
+import axios from 'axios';
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
const scrobbler_url = Resources.lastFmApi;
const api_key = process.env.lastKey;
@@ -35,7 +37,7 @@ function saveUsers() {
}
}
-async function getFromMusicBrainz(mbid) {
+async function getFromMusicBrainz(mbid: string) {
try {
const response = await axios.get(`${Resources.musicBrainzApi}${mbid}`);
const imgObjLarge = response.data.images[0]?.thumbnails?.['1200'];
@@ -58,7 +60,7 @@ function getFromLast(track) {
return imageUrl;
}
-module.exports = (bot) => {
+export default (bot) => {
loadUsers();
bot.command('setuser', (ctx) => {
@@ -149,7 +151,7 @@ module.exports = (bot) => {
const artistUrl = `https://www.last.fm/music/${encodeURIComponent(artistName)}`;
const userUrl = `https://www.last.fm/user/${encodeURIComponent(lastfmUser)}`;
- let num_plays = '';
+ let num_plays = 0;
try {
const response_plays = await axios.get(scrobbler_url, {
params: {
@@ -164,11 +166,8 @@ module.exports = (bot) => {
'User-Agent': `@${botInfo.username}-node-telegram-bot`
}
});
+
num_plays = response_plays.data.track.userplaycount;
-
- if (!num_plays || num_plays === undefined) {
- num_plays = 0;
- };
} catch (err) {
console.log(err)
const message = Strings.lastFm.apiErr
diff --git a/src/commands/main.js b/src/commands/main.ts
similarity index 60%
rename from src/commands/main.js
rename to src/commands/main.ts
index 975762d..2729173 100644
--- a/src/commands/main.js
+++ b/src/commands/main.ts
@@ -1,9 +1,11 @@
-const { getStrings } = require('../plugins/checkLang.js');
-const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
-const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
-module.exports = (bot) => {
- bot.start(spamwatchMiddleware, async (ctx) => {
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
+
+export default (bot: any) => {
+ bot.start(spamwatchMiddleware, async (ctx: any) => {
const Strings = getStrings(ctx.from.language_code);
const botInfo = await ctx.telegram.getMe();
const startMsg = Strings.botWelcome.replace(/{botName}/g, botInfo.first_name);
@@ -14,7 +16,7 @@ module.exports = (bot) => {
});
});
- bot.command('privacy', spamwatchMiddleware, async (ctx) => {
+ bot.command('privacy', spamwatchMiddleware, async (ctx: any) => {
const Strings = getStrings(ctx.from.language_code);
const message = Strings.botPrivacy.replace("{botPrivacy}", process.env.botPrivacy);
diff --git a/src/commands/modarchive.js b/src/commands/modarchive.ts
similarity index 73%
rename from src/commands/modarchive.js
rename to src/commands/modarchive.ts
index 4e89370..eac76a8 100644
--- a/src/commands/modarchive.js
+++ b/src/commands/modarchive.ts
@@ -1,12 +1,19 @@
-const Resources = require('../props/resources.json');
-const axios = require('axios');
-const fs = require('fs');
-const path = require('path');
-const { getStrings } = require('../plugins/checkLang.js');
-const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
-const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
+import Resources from '../props/resources.json';
+import axios from 'axios';
+import fs from 'fs';
+import path from 'path';
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
-async function downloadModule(moduleId) {
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
+
+interface ModuleResult {
+ filePath: string;
+ fileName: string;
+}
+
+async function downloadModule(moduleId: string): Promise {
try {
const downloadUrl = `${Resources.modArchiveApi}${moduleId}`;
const response = await axios({
@@ -39,12 +46,12 @@ async function downloadModule(moduleId) {
}
}
-module.exports = (bot) => {
+export default (bot) => {
bot.command(['modarchive', 'tma'], spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
const moduleId = ctx.message.text.split(' ')[1];
- if (moduleId == NaN || null) {
+ if (Number.isNaN(moduleId) || null) {
return ctx.reply(Strings.maInvalidModule, {
parse_mode: "Markdown",
reply_to_message_id: ctx.message.message_id
diff --git a/src/commands/ponyapi.js b/src/commands/ponyapi.ts
similarity index 86%
rename from src/commands/ponyapi.js
rename to src/commands/ponyapi.ts
index e5fbf94..dfa2e1c 100644
--- a/src/commands/ponyapi.js
+++ b/src/commands/ponyapi.ts
@@ -1,15 +1,56 @@
-const Resources = require('../props/resources.json');
-const { getStrings } = require('../plugins/checkLang.js');
-const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
-const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
-const axios = require("axios");
-const { verifyInput } = require('../plugins/verifyInput.js');
+import Resources from '../props/resources.json';
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+import axios from 'axios';
+import verifyInput from '../plugins/verifyInput';
+
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
+
+interface Character {
+ id: string;
+ name: string;
+ alias: string;
+ url: string;
+ sex: string;
+ residence: string;
+ occupation: string;
+ kind: string;
+ image: string[];
+}
+
+interface Episode {
+ id: string;
+ name: string;
+ image: string;
+ url: string;
+ season: string;
+ episode: string;
+ overall: string;
+ airdate: string;
+ storyby: string;
+ writtenby: string;
+ storyboard: string;
+}
+
+interface Comic {
+ id: string;
+ name: string;
+ series: string;
+ image: string;
+ url: string;
+ writer: string;
+ artist: string;
+ colorist: string;
+ letterer: string;
+ editor: string;
+}
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
-module.exports = (bot) => {
+export default (bot) => {
bot.command("mlp", spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
@@ -34,11 +75,11 @@ module.exports = (bot) => {
try {
const response = await axios(apiUrl);
- const charactersArray = [];
+ const charactersArray: Character[] = [];
if (Array.isArray(response.data.data)) {
response.data.data.forEach(character => {
- let aliases = [];
+ let aliases: string[] = [];
if (character.alias) {
if (typeof character.alias === 'string') {
aliases.push(character.alias);
@@ -107,7 +148,7 @@ module.exports = (bot) => {
try {
const response = await axios(apiUrl);
- const episodeArray = [];
+ const episodeArray: Episode[] = [];
if (Array.isArray(response.data.data)) {
response.data.data.forEach(episode => {
@@ -175,15 +216,15 @@ module.exports = (bot) => {
try {
const response = await axios(apiUrl);
- const comicArray = [];
+ const comicArray: Comic[] = [];
if (Array.isArray(response.data.data)) {
response.data.data.forEach(comic => {
- let letterers = [];
+ let letterers: string[] = [];
if (comic.letterer) {
if (typeof comic.letterer === 'string') {
letterers.push(comic.letterer);
} else if (Array.isArray(comic.letterer)) {
- letterers = aliases.concat(comic.letterer);
+ letterers = letterers.concat(comic.letterer);
}
}
comicArray.push({
diff --git a/src/commands/quotes.ts b/src/commands/quotes.ts
new file mode 100644
index 0000000..4c59f2a
--- /dev/null
+++ b/src/commands/quotes.ts
@@ -0,0 +1,32 @@
+/*
+import Resources from '../props/resources.json';
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+import escape from 'markdown-escape';
+import axios from 'axios';
+
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
+
+export default (bot) => {
+ bot.command("quote", spamwatchMiddleware, async (ctx) => {
+ const Strings = getStrings(ctx.from.language_code);
+
+ try {
+ const response = await axios.get(Resources.quoteApi);
+ const data = response.data;
+
+ ctx.reply(escape(`${escape(Strings.quoteResult)}\n> *${escape(data.quote)}*\n_${escape(data.author)}_`), {
+ reply_to_message_id: ctx.message.message_id,
+ parse_mode: 'Markdown'
+ });
+ } catch (error) {
+ console.error(error);
+ ctx.reply(Strings.quoteErr, {
+ reply_to_message_id: ctx.message.id,
+ parse_mode: 'MarkdownV2'
+ });
+ };
+ });
+};
+*/
\ No newline at end of file
diff --git a/src/commands/randompony.js b/src/commands/randompony.ts
similarity index 72%
rename from src/commands/randompony.js
rename to src/commands/randompony.ts
index 1be1e73..0ca140d 100644
--- a/src/commands/randompony.js
+++ b/src/commands/randompony.ts
@@ -1,15 +1,17 @@
-const Resources = require('../props/resources.json');
-const { getStrings } = require('../plugins/checkLang.js');
-const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
-const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
-const axios = require("axios");
+import Resources from '../props/resources.json';
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+import axios from 'axios';
-module.exports = (bot) => {
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
+
+export default (bot) => {
bot.command(["rpony", "randompony", "mlpart"], spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
try {
const response = await axios(Resources.randomPonyApi);
- let tags = [];
+ let tags: string[] = [];
if (response.data.pony.tags) {
if (typeof response.data.pony.tags === 'string') {
diff --git a/src/commands/weather.js b/src/commands/weather.ts
similarity index 90%
rename from src/commands/weather.js
rename to src/commands/weather.ts
index be1ebe9..716726c 100644
--- a/src/commands/weather.js
+++ b/src/commands/weather.ts
@@ -2,12 +2,14 @@
// Copyright (c) 2024 BubbalooTeam. (https://github.com/BubbalooTeam)
// Minor code changes by lucmsilva (https://github.com/lucmsilva651)
-const Resources = require('../props/resources.json');
-const axios = require('axios');
-const { getStrings } = require('../plugins/checkLang.js');
-const { isOnSpamWatch } = require('../spamwatch/spamwatch.js');
-const spamwatchMiddleware = require('../spamwatch/Middleware.js')(isOnSpamWatch);
-const { verifyInput } = require('../plugins/verifyInput.js');
+import Resources from '../props/resources.json';
+import axios from 'axios';
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+import verifyInput from '../plugins/verifyInput';
+
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
const statusEmojis = {
0: '⛈', 1: '⛈', 2: '⛈', 3: '⛈', 4: '⛈', 5: '🌨', 6: '🌨', 7: '🌨',
@@ -31,7 +33,7 @@ function getLocaleUnit(countryCode) {
}
}
-module.exports = (bot) => {
+export default (bot) => {
bot.command(['clima', 'weather'], spamwatchMiddleware, async (ctx) => {
const userLang = ctx.from.language_code || "en-US";
const Strings = getStrings(userLang);
diff --git a/src/commands/wiki.ts b/src/commands/wiki.ts
new file mode 100644
index 0000000..f6ca6d0
--- /dev/null
+++ b/src/commands/wiki.ts
@@ -0,0 +1,38 @@
+/*
+import axios from "axios";
+
+function capitalizeFirstLetter(string: string) {
+ return string.charAt(0).toUpperCase() + string.slice(1);
+}
+
+function mediaWikiToMarkdown(input: string) {
+ input = input.replace(/===(.*?)===/g, '*$1*');
+ input = input.replace(/==(.*?)==/g, '*$1*');
+ input = input.replace(/=(.*?)=/g, '*$1*');
+ input = input.replace(/'''(.*?)'''/g, '**$1**');
+ input = input.replace(/''(.*?)''/g, '_$1_');
+ input = input.replace(/^\*\s/gm, '- ');
+ input = input.replace(/^\#\s/gm, '1. ');
+ input = input.replace(/{{Quote(.*?)}}/g, "```\n$1```\n");
+ input = input.replace(/\[\[(.*?)\|?(.*?)\]\]/g, (_, link, text) => {
+ const sanitizedLink = link.replace(/ /g, '_');
+ return text ? `[${text}](${sanitizedLink})` : `[${sanitizedLink}](${sanitizedLink})`;
+ });
+ input = input.replace(/\[\[File:(.*?)\|.*?\]\]/g, '');
+
+ return input;
+}
+
+export default (bot) => {
+ bot.command("wiki", async (ctx) => {
+ const userInput = capitalizeFirstLetter(ctx.message.text.split(' ')[1]);
+ const apiUrl = `https://en.wikipedia.org/w/index.php?title=${userInput}&action=raw`;
+ const response = await axios(apiUrl, { headers: { 'Accept': "text/plain" } });
+ const convertedResponse = response.data.replace(/<\/?div>/g, "").replace(/{{Infobox.*?}}/s, "");
+
+ const result = mediaWikiToMarkdown(convertedResponse).slice(0, 2048);
+
+ ctx.reply(result, { parse_mode: 'Markdown', disable_web_page_preview: true, reply_to_message_id: ctx.message.message_id });
+ });
+};
+*/
\ No newline at end of file
diff --git a/src/commands/youtube.js b/src/commands/youtube.ts
similarity index 89%
rename from src/commands/youtube.js
rename to src/commands/youtube.ts
index d3fa755..9fa6364 100644
--- a/src/commands/youtube.js
+++ b/src/commands/youtube.ts
@@ -1,10 +1,12 @@
-const { getStrings } = require('../plugins/checkLang.js');
-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');
-const path = require('path');
+import { getStrings } from '../plugins/checklang';
+import { isOnSpamWatch } from '../spamwatch/spamwatch';
+import spamwatchMiddlewareModule from '../spamwatch/Middleware';
+import { execFile } from 'child_process';
+import os from 'os';
+import fs from 'fs';
+import path from 'path';
+
+const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
const ytDlpPaths = {
linux: path.resolve(__dirname, '../plugins/yt-dlp/yt-dlp'),
@@ -28,7 +30,7 @@ const getFfmpegPath = () => {
return ffmpegPaths[platform] || ffmpegPaths.linux;
};
-const downloadFromYoutube = async (command, args) => {
+const downloadFromYoutube = async (command: string, args: string[]): Promise<{ stdout: string; stderr: string }> => {
return new Promise((resolve, reject) => {
execFile(command, args, (error, stdout, stderr) => {
if (error) {
@@ -40,8 +42,8 @@ const downloadFromYoutube = async (command, args) => {
});
};
-const getApproxSize = async (command, videoUrl) => {
- let args = [];
+const getApproxSize = async (command: string, videoUrl: string): Promise => {
+ let args: string[] = [];
if (fs.existsSync(path.resolve(__dirname, "../props/cookies.txt"))) {
args = [videoUrl, '--compat-opt', 'manifest-filesize-approx', '-O', 'filesize_approx', '--cookies', path.resolve(__dirname, "../props/cookies.txt")];
} else {
@@ -60,7 +62,7 @@ const getApproxSize = async (command, videoUrl) => {
}
};
-module.exports = (bot) => {
+export default (bot) => {
bot.command(['yt', 'ytdl', 'sdl', 'video', 'dl'], spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
const ytDlpPath = getYtDlpPath();
@@ -198,11 +200,8 @@ module.exports = (bot) => {
}
} catch (error) {
const errMsg = Strings.ytDownload.uploadErr.replace("{error}", error)
- await ctx.telegram.editMessageText(
- ctx.chat.id,
- downloadingMessage.message_id,
- null,
- errMsg, {
+ // will no longer edit the message as the message context is not outside the try block
+ await ctx.reply(errMsg, {
parse_mode: 'Markdown',
reply_to_message_id: ctx.message.message_id,
},
diff --git a/src/locales/english.json b/src/locales/english.json
index 26e1244..5e21a15 100644
--- a/src/locales/english.json
+++ b/src/locales/english.json
@@ -110,5 +110,7 @@
"notFound": "Phone not found.",
"resultMsg": "*Name:* `{name}`\n*Brand:* `{brand}`\n*Model:* `{model}`\n*Codename:* `{codename}`",
"apiErr": "An error occurred while fetching data from the API.\n\n`{err}`"
- }
+ },
+ "chatNotFound": "Chat not found.",
+ "noFileProvided": "Please provide a file to send."
}
\ No newline at end of file
diff --git a/src/plugins/checklang.js b/src/plugins/checklang.ts
similarity index 94%
rename from src/plugins/checklang.js
rename to src/plugins/checklang.ts
index bd8f126..a8d1b79 100644
--- a/src/plugins/checklang.js
+++ b/src/plugins/checklang.ts
@@ -17,6 +17,4 @@ function getStrings(languageCode) {
}
}
-module.exports = {
- getStrings
-};
\ No newline at end of file
+export { getStrings };
\ No newline at end of file
diff --git a/src/plugins/verifyInput.js b/src/plugins/verifyInput.js
deleted file mode 100644
index feae352..0000000
--- a/src/plugins/verifyInput.js
+++ /dev/null
@@ -1,14 +0,0 @@
-function verifyInput(ctx, userInput, message, verifyNaN = false) {
- if (!userInput || (verifyNaN && isNaN(userInput))) {
- ctx.reply(message, {
- parse_mode: "Markdown",
- reply_to_message_id: ctx.message.message_id
- });
- return true;
- }
- return false;
-}
-
-module.exports = {
- verifyInput
-};
\ No newline at end of file
diff --git a/src/plugins/verifyInput.ts b/src/plugins/verifyInput.ts
new file mode 100644
index 0000000..b1355fd
--- /dev/null
+++ b/src/plugins/verifyInput.ts
@@ -0,0 +1,10 @@
+export default function verifyInput(ctx: any, userInput: string, message: string, verifyNaN = false) {
+ if (!userInput || (verifyNaN && isNaN(Number(userInput)))) { // not sure why isNaN is used here, but the input should be a number
+ ctx.reply(message, {
+ parse_mode: "Markdown",
+ reply_to_message_id: ctx.message.message_id
+ });
+ return true;
+ }
+ return false;
+}
diff --git a/src/plugins/ytDlpWrapper.js b/src/plugins/ytDlpWrapper.ts
similarity index 91%
rename from src/plugins/ytDlpWrapper.js
rename to src/plugins/ytDlpWrapper.ts
index 8d2298e..2313b4c 100644
--- a/src/plugins/ytDlpWrapper.js
+++ b/src/plugins/ytDlpWrapper.ts
@@ -1,7 +1,7 @@
-const axios = require('axios');
-const fs = require('fs');
-const path = require('path');
-const os = require('os');
+import axios from 'axios';
+import fs from 'fs';
+import path from 'path';
+import os from 'os';
const downloadDir = path.resolve(__dirname, 'yt-dlp');