Migrate to TypeScript, minor changes and fixes #46

Merged
ihatenodejs merged 10 commits from typescript into main 2025-04-29 19:39:11 +00:00
32 changed files with 333 additions and 246 deletions
Showing only changes of commit efadb51905 - Show all commits

View file

@ -3,6 +3,5 @@ npm-debug.log
.git
.gitignore
.env
config.env
*.md
!README.md

7
.gitignore vendored
View file

@ -136,11 +136,12 @@ dist
lastfm.json
sw-blocklist.txt
package-lock.json
bun.lock
bun.lockb
tmp/
# Executables
*.exe
yt-dlp
ffmpeg
ffmpeg
# Bun
bun.lock*

View file

@ -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"]

View file

@ -27,7 +27,7 @@ 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 ``bun start``.
@ -48,7 +48,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**
@ -60,7 +60,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**
@ -71,13 +71,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.

View file

@ -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

View file

@ -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"
}

View file

@ -4,6 +4,7 @@
},
"dependencies": {
"@dotenvx/dotenvx": "^1.28.0",
"@types/node": "^22.15.0",
"axios": "^1.7.9",
"node-html-parser": "^7.0.1",
"nodemon": "^3.1.7",

View file

@ -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);

View file

@ -1,10 +1,12 @@
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("duck", spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
try {

View file

@ -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';
async function getDeviceList() {
const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
async function getDeviceList({ Strings, ctx }) {
try {
const response = await axios.get(Resources.codenameApi);
return response.data
@ -20,7 +22,7 @@ async function getDeviceList() {
}
}
module.exports = (bot) => {
export default (bot) => {
bot.command(['codename', 'whatis'], spamwatchMiddleware, async (ctx) => {
const userInput = ctx.message.text.split(" ").slice(1).join(" ");
const Strings = getStrings(ctx.from.language_code);
@ -30,7 +32,7 @@ module.exports = (bot) => {
return;
}
const jsonRes = await getDeviceList()
const jsonRes = await getDeviceList({ Strings, ctx })
const phoneSearch = Object.keys(jsonRes).find((codename) => codename === userInput);
if (!phoneSearch) {

View file

@ -1,9 +1,11 @@
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';
const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
function getGitCommitHash() {
return new Promise((resolve, reject) => {
@ -74,7 +76,7 @@ async function handleAdminCommand(ctx, action, successMessage, errorMessage) {
}
}
module.exports = (bot) => {
export default (bot) => {
bot.command('getbotstats', spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
handleAdminCommand(ctx, async () => {

View file

@ -1,7 +1,9 @@
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);
import Resources from '../props/resources.json';
import { getStrings } from '../plugins/checklang';
import { isOnSpamWatch } from '../spamwatch/spamwatch';
import spamwatchMiddlewareModule from '../spamwatch/Middleware';
const spamwatchMiddleware = spamwatchMiddlewareModule(isOnSpamWatch);
function sendRandomReply(ctx, gifUrl, textKey) {
const Strings = getStrings(ctx.from.language_code);
@ -16,8 +18,8 @@ function sendRandomReply(ctx, gifUrl, textKey) {
parse_mode: 'Markdown',
reply_to_message_id: ctx.message.message_id
}).catch(err => {
gifErr = gifErr.replace('{err}', err);
ctx.reply(Strings.gifErr, {
const gifErr = Strings.gifErr.replace('{err}', err);
ctx.reply(gifErr, {
parse_mode: 'Markdown',
reply_to_message_id: ctx.message.message_id
});
@ -51,7 +53,7 @@ function getRandomInt(max) {
return Math.floor(Math.random() * (max + 1));
}
module.exports = (bot) => {
export default (bot) => {
bot.command('random', spamwatchMiddleware, async (ctx) => {
const Strings = getStrings(ctx.from.language_code);
const randomValue = getRandomInt(11);

View file

@ -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<string, Record<string, string>>;
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<PhoneSearchResult[]> {
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);

View file

@ -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) => {

View file

@ -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];

View file

@ -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(

View file

@ -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

View file

@ -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);

View file

@ -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<ModuleResult | null> {
try {
const downloadUrl = `${Resources.modArchiveApi}${moduleId}`;
const response = await axios({
GiovaniFZ commented 2025-04-24 23:09:54 +00:00 (Migrated from github.com)

instead of using an interface like this, my recommendation is to try to use Zod to make validations better

instead of using an interface like this, my recommendation is to try to use Zod to make validations better
ihatenodejs commented 2025-04-24 23:12:39 +00:00 (Migrated from github.com)

@lucmsilva651 What do you think about this? Using Zod might make things more complex for you to maintain in terms of modifying types.

@lucmsilva651 What do you think about this? Using [Zod](https://zod.dev) might make things more complex for you to maintain in terms of modifying types.
GiovaniFZ commented 2025-04-24 23:17:47 +00:00 (Migrated from github.com)

@lucmsilva651 we discussed that if you know what is zod and how to use it, @ihatenodejs will do, otherwise not

@lucmsilva651 we discussed that if you know what is zod and how to use it, @ihatenodejs will do, otherwise not
@ -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

View file

@ -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({

View file

@ -1,28 +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);
// const escape = require('markdown-escape');
// const axios = require('axios');
// module.exports = (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'
// });
// };
// });
// };

32
src/commands/quotes.ts Normal file
View file

@ -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'
});
};
});
};
*/

View file

@ -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') {

View file

@ -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);

View file

@ -1,36 +0,0 @@
// const axios = require("axios");
// function capitalizeFirstLetter(string) {
// return string.charAt(0).toUpperCase() + string.slice(1);
// }
// function mediaWikiToMarkdown(input) {
// 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, '![$1](https://en.wikipedia.org/wiki/File:$1)');
// return input;
// }
// module.exports = (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 });
// });
// };

38
src/commands/wiki.ts Normal file
View file

@ -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, '![$1](https://en.wikipedia.org/wiki/File:$1)');
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 });
});
};
*/

View file

@ -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<number> => {
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,
},

View file

@ -17,6 +17,4 @@ function getStrings(languageCode) {
}
}
module.exports = {
getStrings
};
export { getStrings };

View file

@ -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
};

View file

@ -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;
}

View file

@ -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');