mirror of
https://github.com/ReVanced/revanced-bots.git
synced 2026-01-11 13:56:15 +00:00
docs(bots/discord): add docs
This commit is contained in:
@@ -66,7 +66,13 @@ export type ConfigMessageScanResponse = {
|
||||
}
|
||||
|
||||
export type ConfigMessageScanResponseLabelConfig = {
|
||||
/**
|
||||
* Label name
|
||||
*/
|
||||
label: string
|
||||
/**
|
||||
* Confidence threshold
|
||||
*/
|
||||
threshold: number
|
||||
}
|
||||
|
||||
|
||||
124
bots/discord/docs/1_configuration.md
Normal file
124
bots/discord/docs/1_configuration.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# ⚙️ Configuration
|
||||
|
||||
This is the default configuration (provided in [config.ts](../config.ts)):
|
||||
|
||||
```ts
|
||||
export default {
|
||||
owners: ["USER_ID_HERE"],
|
||||
allowedGuilds: ["GUILD_ID_HERE"],
|
||||
messageScan: {
|
||||
channels: ["CHANNEL_ID_HERE"],
|
||||
roles: ["ROLE_ID_HERE"],
|
||||
users: ["USER_ID_HERE"],
|
||||
whitelist: false,
|
||||
humanCorrections: {
|
||||
falsePositiveLabel: "false_positive",
|
||||
allowUsers: ["USER_ID_HERE"],
|
||||
memberRequirements: {
|
||||
permissions: 8n,
|
||||
roles: ["ROLE_ID_HERE"],
|
||||
},
|
||||
},
|
||||
allowedAttachmentMimeTypes: ["image/jpeg", "image/png", "image/webp"],
|
||||
responses: [
|
||||
{
|
||||
triggers: [/^regexp?$/, { label: "label", threshold: 0.85 }],
|
||||
response: {
|
||||
title: "Embed title",
|
||||
description: "Embed description",
|
||||
fields: [
|
||||
{
|
||||
name: "Field name",
|
||||
value: "Field value",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
logLevel: "log",
|
||||
api: {
|
||||
websocketUrl: "ws://127.0.0.1:3000",
|
||||
},
|
||||
} as Config;
|
||||
```
|
||||
|
||||
This may look very overwhelming but configurating it is pretty easy.
|
||||
|
||||
---
|
||||
|
||||
### `config.owners`
|
||||
|
||||
User IDs of the owners of the bot. They'll be able to execute specific commands that others can't and take control of the bot.
|
||||
|
||||
### `config.allowedGuilds`
|
||||
|
||||
Servers the bot is allowed to be and register commands in. The bot will leave servers that are not in this list automatically once detected.
|
||||
|
||||
### `config.logLevel`
|
||||
|
||||
The level of logs to print to console. If the level is more important or equally important to set level, it will be forwarded to the console.
|
||||
|
||||
The possible levels (sorted by their importance descendingly) are:
|
||||
|
||||
- `none`
|
||||
- `fatal`
|
||||
- `error`
|
||||
- `warn`
|
||||
- `info`
|
||||
- `log`
|
||||
- `debug`
|
||||
|
||||
### `config.api.websocketUrl`
|
||||
|
||||
The WebSocket URL to connect to (including port).
|
||||
|
||||
### `config.messageScan`
|
||||
|
||||
Message scan configuration.
|
||||
|
||||
##### `config.messageScan.roles` & `config.messageScan.users` & `config.messageScan.channels`
|
||||
|
||||
Roles, users, and channels which will be affected by the blacklist/whitelist rule.
|
||||
|
||||
##### `config.messageScan.whitelist`
|
||||
|
||||
Whether to use whitelist (`true`) or blacklist (`false`) mode.
|
||||
|
||||
- Blacklist mode **will refuse** to scan messages of any roles or users who **are** in the list above.
|
||||
- Whitelist mode **will refuse** to scan messages of any roles or users who **aren't** in the list above.
|
||||
|
||||
##### `config.messageScan.responses`
|
||||
|
||||
An array containing response configurations. A response can be triggered by multiple ways[^1], which can be specified in the `response.triggers` field.
|
||||
The `response` field contains the embed data that the bot should send. If it is set to `null`, the bot will not send a response or delete the current response if editing.
|
||||
|
||||
```ts
|
||||
{
|
||||
triggers: [
|
||||
/cool regex/i,
|
||||
{
|
||||
label: 'some_label',
|
||||
threshold: 0.8,
|
||||
},
|
||||
],
|
||||
response: {
|
||||
title: 'Embed title',
|
||||
description: 'Embed description',
|
||||
fields: [
|
||||
{
|
||||
name: 'Field name',
|
||||
value: 'Field value',
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[^1]: Possible triggers are regular expressions or [label configurations](../config.example.ts#68).
|
||||
|
||||
## ⏭️ What's next
|
||||
|
||||
The next page will tell you how to run and bundle the bot.
|
||||
|
||||
Continue: [🏃🏻♂️ Running the bot](./2_running.md)
|
||||
24
bots/discord/docs/2_running.md
Normal file
24
bots/discord/docs/2_running.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# 🏃🏻♂️ Running the bot
|
||||
|
||||
There are two methods to run the bot. Choose one that suits best for the situation.
|
||||
|
||||
## 👷🏻 Development mode (recommended)
|
||||
|
||||
There will be no compilation step, and Bun will automatically watch changes and restart the bot for you.
|
||||
|
||||
You can quickly start the bot by running:
|
||||
|
||||
```sh
|
||||
bun dev
|
||||
```
|
||||
|
||||
## 📦 Building
|
||||
|
||||
There's unfortunately no way to build/bundle the bot yet due to how dynamic imports currently work, though we have a few ideas that may work.
|
||||
As a workaround, you can zip up the whole project, unzip, and run it in development mode using Bun.
|
||||
|
||||
## ⏭️ What's next
|
||||
|
||||
The next page will tell you how to add commands and listen to events to the bot.
|
||||
|
||||
Continue: [✨ Adding commands and listening to events](./3_commands_and_events.md)
|
||||
110
bots/discord/docs/3_commands_and_events.md
Normal file
110
bots/discord/docs/3_commands_and_events.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# ✨ Adding commands and listening to events
|
||||
|
||||
Adding commands and listening to new events is easy once you learn the project's structure.
|
||||
|
||||
## 🗄️ Project structure
|
||||
|
||||
In the source directory, you'll find multiple other directories:
|
||||
|
||||
- [Commands](#💬-commands) are located in `src/commands`
|
||||
- [Events](#🚩-events) are located in `src/events`
|
||||
- [Utility functions](../src/utils) are located in `src/utils`
|
||||
|
||||
You'll also find multiple files:
|
||||
|
||||
- [`index.ts`](../src/index.ts) is the entry of the bot
|
||||
- [`context.ts`](../src/context.ts) is the context object that will be referenced in multiple places
|
||||
|
||||
## 💬 Commands
|
||||
|
||||
> [!IMPORTANT]
|
||||
> You are currently developing with the temporary system which isn't very great in terms of development experience.
|
||||
> A new system will be made and pushed soon and all commands will be migrated to it.
|
||||
|
||||
If you feel the need to categorize commands into directories, you absolutely can, as the system does not restrict subdirectories.
|
||||
|
||||
You can start developing commands with this template:
|
||||
|
||||
```ts
|
||||
// src/commands/my-command.ts
|
||||
|
||||
import { SlashCommandBuilder } from "discord.js";
|
||||
import type { Command } from ".";
|
||||
|
||||
export default {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("my-command")
|
||||
.setDescription("My cool command")
|
||||
// Allowing this command to be used in DMs
|
||||
.setDMPermission(true)
|
||||
// DO NOT forget this line!
|
||||
.toJSON(),
|
||||
|
||||
// Member requirements, will only apply to
|
||||
memberRequirements: {
|
||||
// Match mode, can be `all` or `any` (`all` by default)
|
||||
// - All mode means all of the following conditions have to match
|
||||
// - Any mode means one of the following conditions have to match
|
||||
mode: "all",
|
||||
// This will always match in Any mode, which means the member must have one of these roles to pass
|
||||
roles: ["955220417969262612", "973886585294704640"],
|
||||
// Permissions required to execute this command
|
||||
// -1n means bot owners only (default for security reasons)
|
||||
permissions: -1n,
|
||||
},
|
||||
|
||||
// Whether this command should be able to be executed by only bot owners
|
||||
// (true by default)
|
||||
ownerOnly: false,
|
||||
|
||||
// Whether to register this command globally
|
||||
// This is turned off by default for security reasons
|
||||
global: true,
|
||||
|
||||
// What to do when this command executes
|
||||
async execute(_context, interaction) {
|
||||
await interaction.reply({
|
||||
content: "Hello!",
|
||||
});
|
||||
},
|
||||
} satisfies Command;
|
||||
```
|
||||
|
||||
## 🚩 Events
|
||||
|
||||
Events are a bit different. We have 2 different event systems for both Discord API and our own bot API. This means the [`src/events`](../src/events) directory will have 2 separate directories inside. They are specific to the respective API, but the utility functions make the experience with both of them very similar.
|
||||
|
||||
To start adding events, you can use this template:
|
||||
|
||||
```ts
|
||||
// For Discord events (remove functions you do not use)
|
||||
import { on, once } from '$utils/discord/events'
|
||||
|
||||
// You will have auto-complete and types for all of them, don't worry!
|
||||
// WARNING: The first argument is the `context` object for Discord events
|
||||
// This is intended by design because Discord events usually always use it.
|
||||
on('eventName', async (context, arg1, arg2, ...) => {
|
||||
// Do something in here when the event is triggered
|
||||
})
|
||||
```
|
||||
|
||||
```ts
|
||||
// For "Helper" events (remove functions you do not use)
|
||||
import { on, once } from '$utils/api/events'
|
||||
|
||||
// You will have auto-complete and types for all of them, don't worry!
|
||||
on('eventName', async (arg1, arg2, ...) => {
|
||||
// Do something in here when the event is triggered
|
||||
})
|
||||
```
|
||||
|
||||
API events are stored in [`src/events/api`](../src/events/api), and Discord events are in [`src/events/discord`](../src/events/discord).
|
||||
|
||||
> [!NOTE]
|
||||
> If you need multiple event listeners for the same exact event, you can put them in a directory with the event name and rename the listeners to what they handle specifically. You can see how we do it in [`src/events/discord/interactionCreate`](../src/events/discord/interactionCreate).
|
||||
|
||||
## ⏭️ What's next
|
||||
|
||||
The next page will tell you how to create and interact with a database.
|
||||
|
||||
Continue: [🫙 Storing data](./4_databases.md)
|
||||
88
bots/discord/docs/4_databases.md
Normal file
88
bots/discord/docs/4_databases.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# 🫙 Storing data
|
||||
|
||||
We use SQLite to store every piece of persistent data. By using Bun, we get access to the `bun:sqlite` module which allows us to easily do SQLite operations.
|
||||
|
||||
## 🪄 Creating a database
|
||||
|
||||
You can easily create a database by initializing the `BasicDatabase` class:
|
||||
|
||||
```ts
|
||||
interface MyDatabase {
|
||||
field: string
|
||||
key: string
|
||||
}
|
||||
|
||||
const db = new BasicDatabase<MyDatabase>(
|
||||
// File path
|
||||
'database_file.db',
|
||||
// Database schema, in SQL
|
||||
`field TEXT NOT NULL, key TEXT PRIMARY KEY NOT NULL`,
|
||||
// Custom table name (optional, defaults to 'data'),
|
||||
'data'
|
||||
)
|
||||
```
|
||||
|
||||
## 📝 Writing data
|
||||
|
||||
Initializing `MyDatabase` will immediately create/open the `database_file.db` file. To write data, you can use the `insert` or `update` method:
|
||||
|
||||
```ts
|
||||
const key = 'my key'
|
||||
const field = 'some data'
|
||||
|
||||
// Order is according to the schema
|
||||
// db.insert(...columns)
|
||||
db.insert(field, key)
|
||||
|
||||
const field2 = 'some other data'
|
||||
|
||||
// db.update(data, filter)
|
||||
db.update({
|
||||
field: field2
|
||||
}, `key = ${key}`)
|
||||
```
|
||||
|
||||
You can also delete a row:
|
||||
|
||||
```ts
|
||||
db.delete(`key = ${key}`)
|
||||
|
||||
console.log(db.select(`key = ${key}`)) // null
|
||||
```
|
||||
|
||||
## 👀 Reading data
|
||||
|
||||
To get data using a filter, you can use the `select` method:
|
||||
|
||||
```ts
|
||||
// We insert it back
|
||||
db.insert(field, key)
|
||||
|
||||
const data = db.select('*', `key = ${key}`)
|
||||
console.log(data) // { key: 'my key', field: 'some other data' }
|
||||
|
||||
const { key: someKey } = db.select('key', `field = '${field2}'`)
|
||||
console.log(someKey) // 'my key'
|
||||
```
|
||||
|
||||
|
||||
If the existing abstractions aren't enough, you can also use the `run`, `prepare`, or `query` method:
|
||||
|
||||
```ts
|
||||
// Enable WAL
|
||||
db.run('PRAGMA journal_mode=WAL')
|
||||
|
||||
const selectFromKey = db.prepare('SELECT * FROM data WHERE key = $key')
|
||||
|
||||
console.log(
|
||||
selectFromKey.get({
|
||||
$key: key
|
||||
})
|
||||
) // { key: 'my key', field: 'some other data' }
|
||||
|
||||
console.log(
|
||||
selectFromKey.get({
|
||||
$key: 'non existent key'
|
||||
})
|
||||
) // null
|
||||
```
|
||||
17
bots/discord/docs/README.md
Normal file
17
bots/discord/docs/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# 🤖 ReVanced Discord Bot
|
||||
|
||||
This documentation explains how to start developing, and how to configure the bot.
|
||||
|
||||
## 📖 Table of contents
|
||||
|
||||
0. [🏗️ Set up the development environment (if you haven't already)](../../../docs/0_development_environment.md)
|
||||
1. [⚙️ Configuration](./1_configuration.md)
|
||||
2. [🏃🏻♂️ Running the server](./2_running.md)
|
||||
3. [🗣️ Command and events](./3_commands_and_events.md)
|
||||
4. [🫙 Storing data](./4_databases.md)
|
||||
|
||||
## ⏭️ Start here
|
||||
|
||||
The next page will tell you how to configure the bot.
|
||||
|
||||
Continue: [⚙️ Configuration](./1_configuration.md)
|
||||
Reference in New Issue
Block a user