feat: refactor and new features (#7)

* feat: refactor and new features

+ Refactored the codebase
+ OCR support in bots
+ Server sends training data every minute
+ Not using collectors for Discord feedback buttons anymore
+ Fixed grammar mistakes
+ Configs are now seperated
+ Tokens are no longer in configs
- Like feedback doesn't work for Discord yet

* feat: remove feedback button once voted

* feat: role blacklist

* feat: thread name check

* feat: error handler for training

* fix: bot crashing when a webhook msg is sent

* refactor: remove debugging lines

* feat: allow fixing mistake at votes in discord bot
This commit is contained in:
reis
2023-06-23 21:29:00 +03:00
committed by GitHub
parent f5214a6ace
commit 8b9f45dc22
60 changed files with 1962 additions and 1591 deletions

View File

@@ -0,0 +1,20 @@
import trainAISelectMenu from '../utils/trainAISelectMenu.js';
export default {
data: {
name: 'fb-dislike'
},
async execute(helper, config, interaction) {
if (
interaction.member.roles.highest.comparePositionTo(
config.discord.trainRole
) < 0
)
return interaction.reply({
content: 'You don\'t have the permission to do this.',
ephemeral: true
});
trainAISelectMenu(interaction, config, helper);
}
};

View File

@@ -0,0 +1,29 @@
export default {
data: {
name: 'fb-like'
},
async execute(helper, config, interaction) {
if (
interaction.member.roles.highest.comparePositionTo(
config.discord.trainRole
) < 0
)
return interaction.reply({
content: 'You don\'t have the permission to do this.',
ephemeral: true
});
// FIXME: somehow get the intent?
// maybe storing in a collection and fetching the msg id with its label?
/*
helper.sendTrainData(interactedMessage, i.values[0]);
i.reply({ content: 'Sent training data to server.', ephemeral: true });
interaction.message.edit({ components: [] });
*/
interaction.reply({
content: 'Feature currently not available. Please use the dislike button.',
ephemeral: true
})
}
};

View File

@@ -0,0 +1,21 @@
import { ContextMenuCommandBuilder, ApplicationCommandType } from 'discord.js';
import trainAISelectMenu from '../utils/trainAISelectMenu.js';
export default {
data: new ContextMenuCommandBuilder()
.setName('Train Message')
.setType(ApplicationCommandType.Message),
async execute(helper, config, interaction) {
if (
interaction.member.roles.highest.comparePositionTo(
interaction.member.guild.roles.cache.get(config.discord.trainRole)
) < 0
)
return interaction.reply({
content: 'You don\'t have the permission to do this.',
ephemeral: true
});
trainAISelectMenu(interaction, config, helper);
}
};

View File

@@ -0,0 +1,32 @@
{
"discord": {
"trainRole": "955220417969262612",
"botId": "1038762591805247518",
"ignoreRole": "1027874293192863765"
},
"server": {
"port": 3000,
"host": "192.168.1.6"
},
"responses": [
{
"label": "revanced_download",
"threshold": 0.85,
"reply": {
"title": "How to download ReVanced?",
"description": "You don't.",
"color": 14908858
}
}
],
"ocrResponses": [
{
"regex": "is not installed",
"reply": {
"title": "Why can't I download videos",
"description": "Because you didn't install the app.",
"color": 14908858
}
}
]
}

View File

@@ -0,0 +1,32 @@
{
"discord": {
"trainRole": "955220417969262612",
"botId": "1038762591805247518",
"ignoreRole": "1027874293192863765"
},
"server": {
"port": 3000,
"host": "127.0.0.1"
},
"responses": [
{
"label": "revanced_download",
"threshold": 0.85,
"reply": {
"title": "How to download ReVanced?",
"description": "You don't.",
"color": 14908858
}
}
],
"ocrResponses": [
{
"regex": "is not installed",
"reply": {
"title": "Why can't I download videos",
"description": "Because you didn't install the app.",
"color": 14908858
}
}
]
}

View File

@@ -0,0 +1,22 @@
import { Events } from 'discord.js';
export default {
name: Events.InteractionCreate,
once: false,
async execute(helper, config, interaction) {
const command = interaction.client.commands.get(interaction.commandName || interaction.customId);
// It's the select menu interaction (hopefully), ignore.
if (!command) return;
try {
await command.execute(helper, config, interaction);
} catch (error) {
console.error(error);
await interaction.reply({
content: 'There was an error while executing this command!',
ephemeral: true
});
}
}
};

View File

@@ -0,0 +1,19 @@
import { Events } from 'discord.js';
export default {
name: Events.MessageCreate,
once: false,
execute(helper, config, msg) {
if (!msg.guild || msg.system || msg.webhookId) return;
if (msg.member.roles.cache.some(role => role.id === config.discord.ignoreRole)) return;
if (msg.attachments.first() && msg.attachments.first().contentType.startsWith('image')) {
helper.scanImage(msg.attachments.first().url, `${msg.channelId}/${msg.id}`);
}
if (!msg.content || msg.author.bot) return;
helper.scanText(
msg.content.toLowerCase().replace(/<.*?>/g, ''),
`${msg.channelId}/${msg.id}`
);
}
};

View File

@@ -0,0 +1,9 @@
import { Events } from 'discord.js';
export default {
name: Events.ThreadCreate,
once: false,
async execute(helper, _, thread) {
helper.scanText(thread.name.toLowerCase(), thread.id);
}
};

View File

@@ -0,0 +1,72 @@
import {
EmbedBuilder,
ActionRowBuilder,
ButtonBuilder,
ButtonStyle
} from 'discord.js';
export default {
name: 'aiResponse',
once: false,
async execute(client, config, helper, aiRes) {
if (!aiRes.response) return;
if (!aiRes.response[0]) return;
try {
const ids = aiRes.id.split('/');
const intent = aiRes.response.reduce((a, b) =>
a.confidence > b.confidence ? a : b
);
const response = config.responses.find(
(res) => res.label === intent.name
);
if (response.threshold > intent.confidence) return;
if (!response.reply) return;
const embed = response.reply;
embed.footer = { text: `Confidence: ${intent.confidence}` };
const feedbackRow = new ActionRowBuilder().addComponents(
new ButtonBuilder()
.setCustomId('fb-like')
.setEmoji('👍')
.setStyle(ButtonStyle.Primary),
new ButtonBuilder()
.setCustomId('fb-dislike')
.setEmoji('👎')
.setStyle(ButtonStyle.Primary)
);
let channel = client.channels.cache.get(ids[0]);
if (!channel) {
await client.channels.fetch(ids[0]);
channel = client.channels.cache.get(ids[0]);
}
if (!ids[1]) {
channel.send({
embeds: [embed],
components: [feedbackRow]
});
} else {
let message = channel.messages.cache.get(ids[1]);
if (!message) {
await channel.messages.fetch(ids[1]);
message = channel.messages.cache.get(ids[1]);
}
message.reply({
embeds: [embed],
components: [feedbackRow]
});
}
} catch (e) {
console.log(e);
}
}
};

View File

@@ -0,0 +1,31 @@
export default {
name: 'ocrResponse',
once: false,
async execute(client, config, helper, ocrRes) {
try {
const ids = ocrRes.id.split('/');
let channel = client.channels.cache.get(ids[0]);
if (!channel) {
await client.channels.fetch(ids[0]);
channel = client.channels.cache.get(ids[0]);
}
let message = channel.messages.cache.get(ids[1]);
if (!message) {
await channel.messages.fetch(ids[1]);
message = channel.messages.cache.get(ids[1]);
}
for (const ocrReply of config.ocrResponses) {
if (ocrRes.ocrText.match(ocrReply.regex)) {
message.reply({ embeds: [ocrReply.reply] });
break;
}
}
} catch (e) {
console.log(e);
}
}
};

View File

@@ -0,0 +1,82 @@
import { Client, GatewayIntentBits, Collection } from 'discord.js';
import { readFileSync, readdirSync } from 'node:fs';
// Fix __dirname not being defined in ES modules. (https://stackoverflow.com/a/64383997)
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
import HelperClient from '@revanced-helper/helper-client';
import config from './config.json' assert { type: 'json' };
const helper = new HelperClient(config);
helper.connect();
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent
]
});
client.commands = new Collection();
client.trainingVotes = new Collection();
const commandsPath = join(__dirname, 'commands');
const commandFiles = readdirSync(commandsPath).filter((file) =>
file.endsWith('.js')
);
for (const file of commandFiles) {
const filePath = join(commandsPath, file);
const command = (await import(`file://${filePath}`)).default;
if ('data' in command && 'execute' in command) {
client.commands.set(command.data.name, command);
} else {
console.log(
`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`
);
}
}
const discordEventsPath = join(__dirname, 'events');
const discordEventFiles = readdirSync(discordEventsPath).filter((file) =>
file.endsWith('.js')
);
for (const file of discordEventFiles) {
const filePath = join(discordEventsPath, file);
const event = (await import(`file://${filePath}`)).default;
if (event.once) {
client.once(event.name, (...args) =>
event.execute(helper, config, ...args)
);
} else {
client.on(event.name, (...args) =>
event.execute(helper, config, ...args)
);
}
}
// The ReVanced Helper events.
const helperEventsPath = join(__dirname, 'helperEvents');
const helperEventFiles = readdirSync(helperEventsPath).filter((file) =>
file.endsWith('.js')
);
for (const file of helperEventFiles) {
const filePath = join(helperEventsPath, file);
const event = (await import(`file://${filePath}`)).default;
if (event.once) {
helper.once(event.name, (...args) =>
event.execute(client, config, helper, ...args)
);
} else {
helper.on(event.name, (...args) =>
event.execute(client, config, helper, ...args)
);
}
}
client.login(process.env.DISCORD_TOKEN);

685
apps/bot-discord/src/package-lock.json generated Normal file
View File

@@ -0,0 +1,685 @@
{
"name": "bot-discord",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "bot-discord",
"version": "1.0.0",
"license": "GPL-3.0-or-later",
"dependencies": {
"@revanced-helper/helper-client": "file:../../../packages/client",
"discord.js": "^14.11.0"
}
},
"../../../packages/client": {
"version": "1.0.0",
"license": "GPL-3.0-or-later",
"dependencies": {
"bson": "^4.7.0"
}
},
"node_modules/@discordjs/builders": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.3.tgz",
"integrity": "sha512-CTCh8NqED3iecTNuiz49mwSsrc2iQb4d0MjMdmS/8pb69Y4IlzJ/DIy/p5GFlgOrFbNO2WzMHkWKQSiJ3VNXaw==",
"dependencies": {
"@discordjs/formatters": "^0.3.1",
"@discordjs/util": "^0.3.1",
"@sapphire/shapeshift": "^3.8.2",
"discord-api-types": "^0.37.41",
"fast-deep-equal": "^3.1.3",
"ts-mixer": "^6.0.3",
"tslib": "^2.5.0"
},
"engines": {
"node": ">=16.9.0"
}
},
"node_modules/@discordjs/collection": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.1.tgz",
"integrity": "sha512-aWEc9DCf3TMDe9iaJoOnO2+JVAjeRNuRxPZQA6GVvBf+Z3gqUuWYBy2NWh4+5CLYq5uoc3MOvUQ5H5m8CJBqOA==",
"engines": {
"node": ">=16.9.0"
}
},
"node_modules/@discordjs/formatters": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.1.tgz",
"integrity": "sha512-M7X4IGiSeh4znwcRGcs+49B5tBkNDn4k5bmhxJDAUhRxRHTiFAOTVUNQ6yAKySu5jZTnCbSvTYHW3w0rAzV1MA==",
"dependencies": {
"discord-api-types": "^0.37.41"
},
"engines": {
"node": ">=16.9.0"
}
},
"node_modules/@discordjs/rest": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.7.1.tgz",
"integrity": "sha512-Ofa9UqT0U45G/eX86cURQnX7gzOJLG2oC28VhIk/G6IliYgQF7jFByBJEykPSHE4MxPhqCleYvmsrtfKh1nYmQ==",
"dependencies": {
"@discordjs/collection": "^1.5.1",
"@discordjs/util": "^0.3.0",
"@sapphire/async-queue": "^1.5.0",
"@sapphire/snowflake": "^3.4.2",
"discord-api-types": "^0.37.41",
"file-type": "^18.3.0",
"tslib": "^2.5.0",
"undici": "^5.22.0"
},
"engines": {
"node": ">=16.9.0"
}
},
"node_modules/@discordjs/util": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.3.1.tgz",
"integrity": "sha512-HxXKYKg7vohx2/OupUN/4Sd02Ev3PBJ5q0gtjdcvXb0ErCva8jNHWfe/v5sU3UKjIB/uxOhc+TDOnhqffj9pRA==",
"engines": {
"node": ">=16.9.0"
}
},
"node_modules/@discordjs/ws": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-0.8.3.tgz",
"integrity": "sha512-hcYtppanjHecbdNyCKQNH2I4RP9UrphDgmRgLYrATEQF1oo4sYSve7ZmGsBEXSzH72MO2tBPdWSThunbxUVk0g==",
"dependencies": {
"@discordjs/collection": "^1.5.1",
"@discordjs/rest": "^1.7.1",
"@discordjs/util": "^0.3.1",
"@sapphire/async-queue": "^1.5.0",
"@types/ws": "^8.5.4",
"@vladfrangu/async_event_emitter": "^2.2.1",
"discord-api-types": "^0.37.41",
"tslib": "^2.5.0",
"ws": "^8.13.0"
},
"engines": {
"node": ">=16.9.0"
}
},
"node_modules/@revanced-helper/helper-client": {
"resolved": "../../../packages/client",
"link": true
},
"node_modules/@sapphire/async-queue": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz",
"integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==",
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/@sapphire/shapeshift": {
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz",
"integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"lodash": "^4.17.21"
},
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/@sapphire/snowflake": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz",
"integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==",
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/@tokenizer/token": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
},
"node_modules/@types/node": {
"version": "20.2.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz",
"integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ=="
},
"node_modules/@types/ws": {
"version": "8.5.4",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
"integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@vladfrangu/async_event_emitter": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz",
"integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==",
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": {
"streamsearch": "^1.1.0"
},
"engines": {
"node": ">=10.16.0"
}
},
"node_modules/discord-api-types": {
"version": "0.37.43",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.43.tgz",
"integrity": "sha512-bBhDWU3TF9KADxR/mHp1K4Bvu/LRtFQdGyBjADu4e66F3ZnD4kp12W/SJCttIaCcMXzPV3sfty6eDGRNRph51Q=="
},
"node_modules/discord.js": {
"version": "14.11.0",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.11.0.tgz",
"integrity": "sha512-CkueWYFQ28U38YPR8HgsBR/QT35oPpMbEsTNM30Fs8loBIhnA4s70AwQEoy6JvLcpWWJO7GY0y2BUzZmuBMepQ==",
"dependencies": {
"@discordjs/builders": "^1.6.3",
"@discordjs/collection": "^1.5.1",
"@discordjs/formatters": "^0.3.1",
"@discordjs/rest": "^1.7.1",
"@discordjs/util": "^0.3.1",
"@discordjs/ws": "^0.8.3",
"@sapphire/snowflake": "^3.4.2",
"@types/ws": "^8.5.4",
"discord-api-types": "^0.37.41",
"fast-deep-equal": "^3.1.3",
"lodash.snakecase": "^4.1.1",
"tslib": "^2.5.0",
"undici": "^5.22.0",
"ws": "^8.13.0"
},
"engines": {
"node": ">=16.9.0"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"node_modules/file-type": {
"version": "18.5.0",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-18.5.0.tgz",
"integrity": "sha512-yvpl5U868+V6PqXHMmsESpg6unQ5GfnPssl4dxdJudBrr9qy7Fddt7EVX1VLlddFfe8Gj9N7goCZH22FXuSQXQ==",
"dependencies": {
"readable-web-to-node-stream": "^3.0.2",
"strtok3": "^7.0.0",
"token-types": "^5.0.1"
},
"engines": {
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sindresorhus/file-type?sponsor=1"
}
},
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.snakecase": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
"integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="
},
"node_modules/peek-readable": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz",
"integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==",
"engines": {
"node": ">=14.16"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/readable-web-to-node-stream": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz",
"integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==",
"dependencies": {
"readable-stream": "^3.6.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/strtok3": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz",
"integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==",
"dependencies": {
"@tokenizer/token": "^0.3.0",
"peek-readable": "^5.0.0"
},
"engines": {
"node": ">=14.16"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/token-types": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz",
"integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==",
"dependencies": {
"@tokenizer/token": "^0.3.0",
"ieee754": "^1.2.1"
},
"engines": {
"node": ">=14.16"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Borewit"
}
},
"node_modules/ts-mixer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz",
"integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ=="
},
"node_modules/tslib": {
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
"integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
},
"node_modules/undici": {
"version": "5.22.1",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz",
"integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==",
"dependencies": {
"busboy": "^1.6.0"
},
"engines": {
"node": ">=14.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/ws": {
"version": "8.13.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
},
"dependencies": {
"@discordjs/builders": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.3.tgz",
"integrity": "sha512-CTCh8NqED3iecTNuiz49mwSsrc2iQb4d0MjMdmS/8pb69Y4IlzJ/DIy/p5GFlgOrFbNO2WzMHkWKQSiJ3VNXaw==",
"requires": {
"@discordjs/formatters": "^0.3.1",
"@discordjs/util": "^0.3.1",
"@sapphire/shapeshift": "^3.8.2",
"discord-api-types": "^0.37.41",
"fast-deep-equal": "^3.1.3",
"ts-mixer": "^6.0.3",
"tslib": "^2.5.0"
}
},
"@discordjs/collection": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.1.tgz",
"integrity": "sha512-aWEc9DCf3TMDe9iaJoOnO2+JVAjeRNuRxPZQA6GVvBf+Z3gqUuWYBy2NWh4+5CLYq5uoc3MOvUQ5H5m8CJBqOA=="
},
"@discordjs/formatters": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.1.tgz",
"integrity": "sha512-M7X4IGiSeh4znwcRGcs+49B5tBkNDn4k5bmhxJDAUhRxRHTiFAOTVUNQ6yAKySu5jZTnCbSvTYHW3w0rAzV1MA==",
"requires": {
"discord-api-types": "^0.37.41"
}
},
"@discordjs/rest": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.7.1.tgz",
"integrity": "sha512-Ofa9UqT0U45G/eX86cURQnX7gzOJLG2oC28VhIk/G6IliYgQF7jFByBJEykPSHE4MxPhqCleYvmsrtfKh1nYmQ==",
"requires": {
"@discordjs/collection": "^1.5.1",
"@discordjs/util": "^0.3.0",
"@sapphire/async-queue": "^1.5.0",
"@sapphire/snowflake": "^3.4.2",
"discord-api-types": "^0.37.41",
"file-type": "^18.3.0",
"tslib": "^2.5.0",
"undici": "^5.22.0"
}
},
"@discordjs/util": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.3.1.tgz",
"integrity": "sha512-HxXKYKg7vohx2/OupUN/4Sd02Ev3PBJ5q0gtjdcvXb0ErCva8jNHWfe/v5sU3UKjIB/uxOhc+TDOnhqffj9pRA=="
},
"@discordjs/ws": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-0.8.3.tgz",
"integrity": "sha512-hcYtppanjHecbdNyCKQNH2I4RP9UrphDgmRgLYrATEQF1oo4sYSve7ZmGsBEXSzH72MO2tBPdWSThunbxUVk0g==",
"requires": {
"@discordjs/collection": "^1.5.1",
"@discordjs/rest": "^1.7.1",
"@discordjs/util": "^0.3.1",
"@sapphire/async-queue": "^1.5.0",
"@types/ws": "^8.5.4",
"@vladfrangu/async_event_emitter": "^2.2.1",
"discord-api-types": "^0.37.41",
"tslib": "^2.5.0",
"ws": "^8.13.0"
}
},
"@revanced-helper/helper-client": {
"version": "file:../../../packages/client",
"requires": {
"bson": "^4.7.0"
}
},
"@sapphire/async-queue": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz",
"integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA=="
},
"@sapphire/shapeshift": {
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz",
"integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==",
"requires": {
"fast-deep-equal": "^3.1.3",
"lodash": "^4.17.21"
}
},
"@sapphire/snowflake": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz",
"integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA=="
},
"@tokenizer/token": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="
},
"@types/node": {
"version": "20.2.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz",
"integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ=="
},
"@types/ws": {
"version": "8.5.4",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
"integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
"requires": {
"@types/node": "*"
}
},
"@vladfrangu/async_event_emitter": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz",
"integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ=="
},
"busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"requires": {
"streamsearch": "^1.1.0"
}
},
"discord-api-types": {
"version": "0.37.43",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.43.tgz",
"integrity": "sha512-bBhDWU3TF9KADxR/mHp1K4Bvu/LRtFQdGyBjADu4e66F3ZnD4kp12W/SJCttIaCcMXzPV3sfty6eDGRNRph51Q=="
},
"discord.js": {
"version": "14.11.0",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.11.0.tgz",
"integrity": "sha512-CkueWYFQ28U38YPR8HgsBR/QT35oPpMbEsTNM30Fs8loBIhnA4s70AwQEoy6JvLcpWWJO7GY0y2BUzZmuBMepQ==",
"requires": {
"@discordjs/builders": "^1.6.3",
"@discordjs/collection": "^1.5.1",
"@discordjs/formatters": "^0.3.1",
"@discordjs/rest": "^1.7.1",
"@discordjs/util": "^0.3.1",
"@discordjs/ws": "^0.8.3",
"@sapphire/snowflake": "^3.4.2",
"@types/ws": "^8.5.4",
"discord-api-types": "^0.37.41",
"fast-deep-equal": "^3.1.3",
"lodash.snakecase": "^4.1.1",
"tslib": "^2.5.0",
"undici": "^5.22.0",
"ws": "^8.13.0"
}
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"file-type": {
"version": "18.5.0",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-18.5.0.tgz",
"integrity": "sha512-yvpl5U868+V6PqXHMmsESpg6unQ5GfnPssl4dxdJudBrr9qy7Fddt7EVX1VLlddFfe8Gj9N7goCZH22FXuSQXQ==",
"requires": {
"readable-web-to-node-stream": "^3.0.2",
"strtok3": "^7.0.0",
"token-types": "^5.0.1"
}
},
"ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash.snakecase": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz",
"integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="
},
"peek-readable": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz",
"integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A=="
},
"readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"readable-web-to-node-stream": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz",
"integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==",
"requires": {
"readable-stream": "^3.6.0"
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
},
"strtok3": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz",
"integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==",
"requires": {
"@tokenizer/token": "^0.3.0",
"peek-readable": "^5.0.0"
}
},
"token-types": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz",
"integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==",
"requires": {
"@tokenizer/token": "^0.3.0",
"ieee754": "^1.2.1"
}
},
"ts-mixer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz",
"integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ=="
},
"tslib": {
"version": "2.5.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
"integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w=="
},
"undici": {
"version": "5.22.1",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz",
"integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==",
"requires": {
"busboy": "^1.6.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"ws": {
"version": "8.13.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
"requires": {}
}
}
}

View File

@@ -0,0 +1,14 @@
{
"name": "bot-discord",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"keywords": [],
"author": "Reis Can",
"license": "GPL-3.0-or-later",
"dependencies": {
"@revanced-helper/helper-client": "file:../../../packages/client",
"discord.js": "^14.11.0"
}
}

View File

@@ -0,0 +1,35 @@
import { REST, Routes } from 'discord.js';
import { readdirSync, readFileSync } from 'node:fs';
const configJSON = readFileSync('../config.json', 'utf-8');
const config = JSON.parse(configJSON);
const commands = [];
// Grab all the command files from the commands directory you created earlier
const commandFiles = readdirSync('./commands').filter((file) =>
file.endsWith('.js')
);
// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
for (const file of commandFiles) {
const command = await import(`./commands/${file}`);
commands.push(command.default.data.toJSON());
}
// Construct and prepare an instance of the REST module
const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);
try {
console.log(
`Started refreshing ${commands.length} application (/) commands.`
);
// The put method is used to fully refresh all commands in the guild with the current set
const data = await rest.put(Routes.applicationCommands(config.discord.botId), {
body: commands
});
console.log(`Successfully reloaded ${data.length} application (/) commands.`);
} catch (error) {
// And of course, make sure you catch and log any errors!
console.error(error);
}

View File

@@ -0,0 +1,77 @@
import {
ActionRowBuilder,
StringSelectMenuBuilder,
ComponentType
} from 'discord.js';
export default async function trainAISelectMenu(
interaction,
config,
helper
) {
const options = [];
for (const { label } of config.responses) {
options.push({
label: label,
description: `The ${label} label.`,
value: label.toLowerCase()
});
}
const row = new ActionRowBuilder().addComponents(
new StringSelectMenuBuilder()
.setCustomId('select')
.setPlaceholder('Nothing selected')
.addOptions(options)
);
let interactedMessage;
if (!interaction.isMessageContextMenuCommand()) {
try {
const channel = await interaction.client.channels.fetch(interaction.message.reference.channelId);
const message = await channel.messages.fetch(interaction.message.reference.messageId);
interactedMessage = message.content.toLowerCase();
} catch (e) {
interaction.reply({
content: 'The message that you wanted to train the bot with was deleted.',
ephemeral: true
})
}
} else {
interactedMessage = interaction.targetMessage.content.toLowerCase()
}
const reply = await interaction.reply({
content: 'Please select the corresponding label to train the bot.',
components: [row],
ephemeral: true
});
const collector = reply.createMessageComponentCollector({
componentType: ComponentType.StringSelect,
time: 15000
});
const voteId = interaction.targetMessage ? interaction.targetMessage.id :
interaction.message.reference.messageId;
collector.on('collect', (i) => {
i.reply({ content: 'Sent training data to server.', ephemeral: true });
const existingVote = interaction.client.trainingVotes.get(voteId);
if (existingVote) clearTimeout(existingVote);
interaction.client.trainingVotes.set(voteId,
setTimeout(() => {
helper.sendTrainData(interactedMessage, i.values[0]);
if (!interaction.isMessageContextMenuCommand()) {
interaction.message.edit({ components: [] });
}
interaction.client.trainingVotes.delete(voteId);
}, 10_000)
);
});
}

View File

@@ -0,0 +1,61 @@
export default {
command: /\/train/,
async execute(bot, config, msg) {
const admins = await bot.getChatAdministrators(msg.chat.id);
const isAdmin = admins.find((admin) => admin.user.id === msg.from.id);
if (!isAdmin)
return bot.sendMessage(msg.chat.id, 'You\'re not an admin.', {
message_thread_id: msg.message_thread_id,
reply_to_message_id: msg.message_id
});
if (msg.reply_to_message.message_id === msg.message_thread_id)
return bot.sendMessage(msg.chat.id, 'Please reply to a message!', {
message_thread_id: msg.message_thread_id,
reply_to_message_id: msg.message_id
});
const options = [];
let arrI = 0;
let i = 0;
for (const { label } of config.responses) {
if (arrI === 0 && i === 0) {
options.push([
{
text: label,
callback_data: `label_${label.toLowerCase()}`
}
]);
i++;
} else if (i === 2) {
options.push([
{
text: label,
callback_data: `label_${label.toLowerCase()}`
}
]);
i = 0;
arrI++;
} else {
options[arrI].push({
text: label,
callback_data: `label_${label.toLowerCase()}`
});
i++;
}
}
bot.sendMessage(
msg.chat.id,
'Please select the corresponding label to train the bot.',
{
message_thread_id: msg.message_thread_id,
reply_to_message_id: msg.reply_to_message.message_id,
reply_markup: {
inline_keyboard: options
}
}
);
}
};

View File

@@ -0,0 +1,26 @@
{
"server": {
"port": 3000,
"host": "192.168.1.6"
},
"responses": [
{
"label": "revanced_download",
"threshold": 0.85,
"reply": {
"title": "How to download ReVanced?",
"desc": "You don't."
}
}
],
"ocrResponses": [
{
"regex": "is not installed",
"reply": {
"title": "Why can't I download videos",
"desc": "Because you didn't install the app."
}
}
]
}

View File

@@ -0,0 +1,25 @@
{
"server": {
"port": 3000,
"host": "127.0.0.1"
},
"responses": [
{
"label": "revanced_download",
"threshold": 0.85,
"reply": {
"title": "How to download ReVanced?",
"desc": "You don't."
}
}
],
"ocrResponses": [
{
"regex": "is not installed",
"reply": {
"title": "Why can't I download videos",
"desc": "Because you didn't install the app."
}
}
]
}

View File

@@ -0,0 +1,26 @@
export default {
name: 'callback_query',
once: false,
async execute(bot, helper, cb) {
const admins = await bot.getChatAdministrators(cb.message.chat.id);
const isAdmin = admins.find((admin) => admin.user.id === cb.from.id);
if (!isAdmin)
return bot.sendMessage(cb.message.chat.id, 'You\'re not an admin.', {
message_thread_id: cb.message.message_thread_id,
reply_to_message_id: cb.message.message_id
});
helper.sendTrainData(
cb.message.reply_to_message.text.toLowerCase(),
cb.data.replace('label_', '').toUpperCase()
);
bot.sendMessage(cb.message.chat.id, 'Sent training data to server.', {
message_thread_id: cb.message.message_thread_id,
reply_to_message_id: cb.message.message_id
});
bot.deleteMessage(cb.message.chat.id, cb.message.message_id);
}
};

View File

@@ -0,0 +1,15 @@
export default {
name: 'message',
once: false,
async execute(bot, helper, msg) {
if (msg.photo) {
const fileLink = await bot.getFileLink(msg.photo.at(-1).file_id);
helper.scanImage(fileLink, `${msg.chat.id}/${msg.message_thread_id}/${msg.message_id}`)
}
if (!msg.text) return;
helper.scanText(
msg.text.toLowerCase(),
`${msg.chat.id}/${msg.message_thread_id}/${msg.message_id}`
);
}
};

View File

@@ -0,0 +1,29 @@
export default {
name: 'aiResponse',
once: false,
async execute(bot, config, aiRes) {
if (!aiRes.response) return;
if (!aiRes.response[0]) return;
const ids = aiRes.id.split('/');
const intent = aiRes.response.reduce((a, b) =>
a.confidence > b.confidence ? a : b
);
const response = config.responses.find((res) => res.label === intent.name);
if (!response) return;
if (response.threshold > intent.confidence) return;
if (!response.reply) return;
// Because for some reason the markdown parser in TG is a pain in the ass,
// there won't be markdown support for now.
bot.sendMessage(
ids[0],
`## ${response.reply.title}\n\n${response.reply.desc}\n\n_Confidence: ${intent.confidence}_\n\nThis bot is currently being tested in production. Ignore it, if it's wrong.`,
{
message_thread_id: ids[1],
reply_to_message_id: ids[2]
}
);
return;
}
};

View File

@@ -0,0 +1,24 @@
export default {
name: 'ocrResponse',
once: false,
async execute(bot, config, ocrRes) {
const ids = ocrRes.id.split('/');
for (const ocrReply of config.ocrResponses) {
if (ocrRes.ocrText.match(ocrReply.regex)) {
// Because for some reason the markdown parser in TG is a pain in the ass,
// there won't be markdown support for now.
bot.sendMessage(
ids[0],
`## ${ocrReply.reply.title}\n\n${ocrReply.reply.desc}\n\nThis bot is currently being tested in production. Ignore it, if it's wrong.`,
{
message_thread_id: ids[1],
reply_to_message_id: ids[2]
}
);
break;
}
}
return;
}
};

View File

@@ -0,0 +1,66 @@
import TelegramBot from 'node-telegram-bot-api';
import { readFileSync, readdirSync } from 'node:fs';
// Fix __dirname not being defined in ES modules. (https://stackoverflow.com/a/64383997)
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
import HelperClient from '@revanced-helper/helper-client';
import config from './config.json' assert { type: 'json' };
const helper = new HelperClient(config);
helper.connect();
const bot = new TelegramBot(process.env.TELEGRAM_TOKEN, { polling: true });
const commandsPath = join(__dirname, 'commands');
const commandFiles = readdirSync(commandsPath).filter((file) =>
file.endsWith('.js')
);
for (const file of commandFiles) {
const filePath = join(commandsPath, file);
const command = (await import(`file://${filePath}`)).default;
if ('command' in command && 'execute' in command) {
bot.onText(command.command, (...args) =>
command.execute(bot, config, ...args)
);
} else {
console.log(
`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`
);
}
}
const tgEventsPath = join(__dirname, 'events');
const tgEventFiles = readdirSync(tgEventsPath).filter((file) =>
file.endsWith('.js')
);
for (const file of tgEventFiles) {
const filePath = join(tgEventsPath, file);
const event = (await import(`file://${filePath}`)).default;
if (event.once) {
bot.once(event.name, (...args) => event.execute(bot, helper, ...args));
} else {
bot.on(event.name, (...args) => event.execute(bot, helper, ...args));
}
}
// The ReVanced Helper events.
const helperEventsPath = join(__dirname, 'helperEvents');
const helperEventFiles = readdirSync(helperEventsPath).filter((file) =>
file.endsWith('.js')
);
for (const file of helperEventFiles) {
const filePath = join(helperEventsPath, file);
const event = (await import(`file://${filePath}`)).default;
if (event.once) {
helper.once(event.name, (...args) => event.execute(bot, config, ...args));
} else {
helper.on(event.name, (...args) => event.execute(bot, config, ...args));
}
}

2302
apps/bot-telegram/src/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,17 @@
{
"name": "bot-telegram",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "Reis Can",
"license": "GPL-3.0-or-later",
"dependencies": {
"@revanced-helper/helper-client": "file:../../../packages/client",
"node-telegram-bot-api": "^0.61.0"
}
}

View File

@@ -0,0 +1,64 @@
# Server Protocol
The server uses TCP for connection and BSON for messages, so you need to serialize and deserialize the messages.
## AI
Sending the server this JSON (BSON) will send you back the AI predictions.
```json
{
"op": 1,
"id": "String",
"text": "How do i download ReVanced?"
}
```
And the server would return something like this:
```json
{
"op": 2,
"id": "String",
"response": [
{
"confidence": 0.99,
"id": "String",
"name": "revanced_download"
}
]
```
### Training the AI
To train the AI, send the server a JSON (BSON) like this:
```json
{
"op": 3,
"label": "revanced_download",
"text": "how to download revanced"
}
```
## OCR
Sending the server this JSON (BSON) will send you back the read text.
```json
{
"op": 5,
"id": "String",
"url": "https://cdn.discordapp.com/attachments/1033338556493606963/1033338557231796224/Screenshot_20221022-121318.jpg"
}
```
And the server would return something like this:
```json
{
"op": 6,
"id": "String",
"ocrText": "..."
}
```

View File

@@ -0,0 +1,5 @@
import runAI from './runAI.js';
import runOCR from './runOCR.js';
import trainAI from './trainAI.js';
export { runAI, runOCR, trainAI };

View File

@@ -0,0 +1,24 @@
import { serialize } from 'bson';
export default async function runAI(client, data) {
const witAIReq = await fetch(
`https://api.wit.ai/message?v=20230215&q=${encodeURI(data.text)}`,
{
headers: {
authorization: `Bearer ${process.env.WIT_AI_TOKEN}`
}
}
);
const response = await witAIReq.json();
client.write(
serialize({
op: 2,
id: data.id,
response: response.intents
})
);
return;
}

View File

@@ -0,0 +1,61 @@
import { createWorker } from 'tesseract.js';
import { serialize } from 'bson';
import EventEmitter from 'node:events';
const worker = await createWorker();
await worker.loadLanguage('eng');
await worker.initialize('eng');
async function recognize({ client, data }) {
const { data: { text } } = await worker.recognize(data.url);
client.write(
serialize({
op: 6,
id: data.id,
ocrText: text
})
);
}
class Queue extends EventEmitter {
constructor() {
super();
this.isRunning = false;
this.items = []
}
push(item) {
this.items.push(item);
this.emit('item', item)
}
shift() {
return this.items.shift();
}
}
const queue = new Queue();
queue.on('item', async ({ client, data }) => {
if (!queue.isRunning) {
queue.isRunning = true;
await recognize(queue.items.shift());
queue.isRunning = false;
queue.emit('finished');
}
});
queue.on('finished', async () => {
if (queue.items.length !== 0) {
queue.isRunning = true;
await recognize(queue.items.shift());
queue.isRunning = false;
queue.emit('finished');
}
});
export default async function runOCR(client, data) {
queue.push({ client, data });
}

View File

@@ -0,0 +1,17 @@
export default async function trainAI(data) {
fetch('https://api.wit.ai/utterances', {
headers: {
authorization: `Bearer ${process.env.WIT_AI_TOKEN}`
},
body: JSON.stringify([
{
text: data.text,
intent: data.label,
entities: [],
traits: []
}
]),
method: 'POST'
});
return;
}

30
apps/server/src/index.js Normal file
View File

@@ -0,0 +1,30 @@
import { createServer } from 'node:net';
import { deserialize } from 'bson';
import { runAI, runOCR, trainAI } from './events/index.js';
const server = createServer(async (client) => {
client.on('data', async (data) => {
const eventData = deserialize(data, {
allowObjectSmallerThanBufferSize: true
});
switch (eventData.op) {
case 1: {
runAI(client, eventData);
break;
}
case 3: {
trainAI(eventData);
break;
}
case 5: {
await runOCR(client, eventData);
break;
}
}
});
});
server.listen(process.env.PORT || 3000);

228
apps/server/src/package-lock.json generated Normal file
View File

@@ -0,0 +1,228 @@
{
"name": "server",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "server",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"bson": "^5.3.0",
"tesseract.js": "^4.1.0"
}
},
"node_modules/bmp-js": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
"integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw=="
},
"node_modules/bson": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/bson/-/bson-5.3.0.tgz",
"integrity": "sha512-ukmCZMneMlaC5ebPHXIkP8YJzNl5DC41N5MAIvKDqLggdao342t4McltoJBQfQya/nHBWAcSsYRqlXPoQkTJag==",
"engines": {
"node": ">=14.20.1"
}
},
"node_modules/idb-keyval": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
"integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
},
"node_modules/is-electron": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.2.tgz",
"integrity": "sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg=="
},
"node_modules/is-url": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
"integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
},
"node_modules/node-fetch": {
"version": "2.6.11",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
"integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/opencollective-postinstall": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
"integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
"bin": {
"opencollective-postinstall": "index.js"
}
},
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"node_modules/tesseract.js": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/tesseract.js/-/tesseract.js-4.1.0.tgz",
"integrity": "sha512-sCfWJtei6Ykc7uLiWs5H4IKDAhwsMauEVDwUiSkEpzMo4kH+7n8QDBPPNRtGJoZ4NJBf1WSlcbU+Puf64GjOfw==",
"hasInstallScript": true,
"dependencies": {
"bmp-js": "^0.1.0",
"idb-keyval": "^6.2.0",
"is-electron": "^2.2.2",
"is-url": "^1.2.4",
"node-fetch": "^2.6.9",
"opencollective-postinstall": "^2.0.3",
"regenerator-runtime": "^0.13.3",
"tesseract.js-core": "^4.0.4",
"wasm-feature-detect": "^1.2.11",
"zlibjs": "^0.3.1"
}
},
"node_modules/tesseract.js-core": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-4.0.4.tgz",
"integrity": "sha512-MJ+vtktjAaT0681uPl6TDUPhbRbpD/S9emko5rtorgHRZpQo7R3BG7h+3pVHgn1KjfNf1bvnx4B7KxEK8YKqpg=="
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/wasm-feature-detect": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.5.1.tgz",
"integrity": "sha512-GHr23qmuehNXHY4902/hJ6EV5sUANIJC3R/yMfQ7hWDg3nfhlcJfnIL96R2ohpIwa62araN6aN4bLzzzq5GXkg=="
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/zlibjs": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz",
"integrity": "sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==",
"engines": {
"node": "*"
}
}
},
"dependencies": {
"bmp-js": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
"integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw=="
},
"bson": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/bson/-/bson-5.3.0.tgz",
"integrity": "sha512-ukmCZMneMlaC5ebPHXIkP8YJzNl5DC41N5MAIvKDqLggdao342t4McltoJBQfQya/nHBWAcSsYRqlXPoQkTJag=="
},
"idb-keyval": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
"integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
},
"is-electron": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.2.tgz",
"integrity": "sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg=="
},
"is-url": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
"integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
},
"node-fetch": {
"version": "2.6.11",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
"integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
"requires": {
"whatwg-url": "^5.0.0"
}
},
"opencollective-postinstall": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
"integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q=="
},
"regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"tesseract.js": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/tesseract.js/-/tesseract.js-4.1.0.tgz",
"integrity": "sha512-sCfWJtei6Ykc7uLiWs5H4IKDAhwsMauEVDwUiSkEpzMo4kH+7n8QDBPPNRtGJoZ4NJBf1WSlcbU+Puf64GjOfw==",
"requires": {
"bmp-js": "^0.1.0",
"idb-keyval": "^6.2.0",
"is-electron": "^2.2.2",
"is-url": "^1.2.4",
"node-fetch": "^2.6.9",
"opencollective-postinstall": "^2.0.3",
"regenerator-runtime": "^0.13.3",
"tesseract.js-core": "^4.0.4",
"wasm-feature-detect": "^1.2.11",
"zlibjs": "^0.3.1"
}
},
"tesseract.js-core": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-4.0.4.tgz",
"integrity": "sha512-MJ+vtktjAaT0681uPl6TDUPhbRbpD/S9emko5rtorgHRZpQo7R3BG7h+3pVHgn1KjfNf1bvnx4B7KxEK8YKqpg=="
},
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"wasm-feature-detect": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.5.1.tgz",
"integrity": "sha512-GHr23qmuehNXHY4902/hJ6EV5sUANIJC3R/yMfQ7hWDg3nfhlcJfnIL96R2ohpIwa62araN6aN4bLzzzq5GXkg=="
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"zlibjs": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz",
"integrity": "sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w=="
}
}
}

View File

@@ -0,0 +1,14 @@
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"keywords": [],
"author": "Reis Can",
"license": "GPL-3.0-or-later",
"dependencies": {
"bson": "^5.3.0",
"tesseract.js": "^4.1.0"
}
}