mirror of
https://github.com/ReVanced/revanced-bots.git
synced 2026-01-18 00:33:59 +00:00
Compare commits
10 Commits
@revanced/
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfa08397d4 | ||
|
|
9626c4d9ba | ||
|
|
5f74f2dcf8 | ||
|
|
77626c9aed | ||
|
|
2c8740e489 | ||
|
|
6fe15301a2 | ||
|
|
6885e18976 | ||
|
|
42038e6b38 | ||
|
|
51c0252b44 | ||
|
|
399c201f8c |
@@ -1,3 +1,31 @@
|
|||||||
|
## @revanced/discord-bot [1.5.3](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.5.2...@revanced/discord-bot@1.5.3) (2026-01-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bots/discord:** more logging during apply role preset on member join ([77626c9](https://github.com/revanced/revanced-bots/commit/77626c9aeddceb25c2f0d418bf764efc66669baf))
|
||||||
|
|
||||||
|
## @revanced/discord-bot [1.5.2](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.5.1...@revanced/discord-bot@1.5.2) (2025-09-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bots/discord:** correct `respondToReply` logic ([6fe1530](https://github.com/revanced/revanced-bots/commit/6fe15301a21fdc196fded8d6fb13236a7bb826f5))
|
||||||
|
|
||||||
|
## @revanced/discord-bot [1.5.1](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.5.0...@revanced/discord-bot@1.5.1) (2025-09-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bots/discord:** only fetch reference when it exists when `respondToReply` is set ([42038e6](https://github.com/revanced/revanced-bots/commit/42038e6b38983fefe79481359bad300dcb5e83b4))
|
||||||
|
|
||||||
|
# @revanced/discord-bot [1.5.0](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.4.1...@revanced/discord-bot@1.5.0) (2025-09-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **bots/discord:** add additional options for `respondToReply` ([399c201](https://github.com/revanced/revanced-bots/commit/399c201f8c3e9e116050b49c2ffccdd79b02f39b))
|
||||||
|
|
||||||
## @revanced/discord-bot [1.4.1](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.4.0...@revanced/discord-bot@1.4.1) (2025-09-13)
|
## @revanced/discord-bot [1.4.1](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.4.0...@revanced/discord-bot@1.4.1) (2025-09-13)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
humanCorrections: {
|
humanCorrections: {
|
||||||
|
falsePositiveLabel: 'false_positive',
|
||||||
allow: {
|
allow: {
|
||||||
members: {
|
members: {
|
||||||
permissions: 8n,
|
permissions: 8n,
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export type Config = {
|
|||||||
blacklist?: Filter
|
blacklist?: Filter
|
||||||
}
|
}
|
||||||
humanCorrections: {
|
humanCorrections: {
|
||||||
|
falsePositiveLabel: string
|
||||||
allow?: {
|
allow?: {
|
||||||
users?: string[]
|
users?: string[]
|
||||||
members?: {
|
members?: {
|
||||||
@@ -71,8 +72,8 @@ export type ConfigMessageScanResponse = {
|
|||||||
image?: Array<RegExp>
|
image?: Array<RegExp>
|
||||||
}
|
}
|
||||||
filterOverride?: NonNullable<Config['messageScan']>['filter']
|
filterOverride?: NonNullable<Config['messageScan']>['filter']
|
||||||
response: ConfigMessageScanResponseMessage
|
response: ConfigMessageScanResponseMessage | null
|
||||||
respondToReply?: boolean
|
respondToReply?: boolean | 'only_regex' | 'only_labeled'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ConfigMessageScanResponseLabelConfig = {
|
export type ConfigMessageScanResponseLabelConfig = {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "@revanced/discord-bot",
|
"name": "@revanced/discord-bot",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.4.1",
|
"version": "1.5.3",
|
||||||
"description": "🤖 Discord bot assisting ReVanced",
|
"description": "🤖 Discord bot assisting ReVanced",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const msRcConfig = config.messageScan?.humanCorrections?.allow
|
|||||||
|
|
||||||
export default new Command({
|
export default new Command({
|
||||||
name: 'train',
|
name: 'train',
|
||||||
description: 'Train a specific message to a specific label',
|
description: 'Train a specific message or text to a specific label',
|
||||||
type: Command.Type.ChatGuild,
|
type: Command.Type.ChatGuild,
|
||||||
requirements: {
|
requirements: {
|
||||||
users: msRcConfig?.users,
|
users: msRcConfig?.users,
|
||||||
@@ -26,9 +26,9 @@ export default new Command({
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
description: 'The label to train the message as (leave empty for out of scope)',
|
description: 'The label to train the message as',
|
||||||
type: Command.OptionType.String,
|
type: Command.OptionType.String,
|
||||||
required: false,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
allowMessageCommand: true,
|
allowMessageCommand: true,
|
||||||
@@ -49,7 +49,7 @@ export default new Command({
|
|||||||
'This command can only be used in or on text channels',
|
'This command can only be used in or on text channels',
|
||||||
)
|
)
|
||||||
|
|
||||||
if (label && !labels.includes(label))
|
if (!labels.includes(label))
|
||||||
throw new CommandError(
|
throw new CommandError(
|
||||||
CommandErrorType.InvalidArgument,
|
CommandErrorType.InvalidArgument,
|
||||||
`The provided label is invalid.\nValid labels are:${labels.map(l => `\n- \`${l}\``).join('')}`,
|
`The provided label is invalid.\nValid labels are:${labels.map(l => `\n- \`${l}\``).join('')}`,
|
||||||
@@ -60,14 +60,14 @@ export default new Command({
|
|||||||
)
|
)
|
||||||
if (!refMsg) throw new CommandError(CommandErrorType.InvalidArgument, 'The provided message does not exist.')
|
if (!refMsg) throw new CommandError(CommandErrorType.InvalidArgument, 'The provided message does not exist.')
|
||||||
|
|
||||||
logger.debug(`User ${context.executor.id} is training message ${refMsg?.id} as ${label ?? 'out of scope'}`)
|
logger.debug(`User ${context.executor.id} is training message ${refMsg?.id} as ${label}`)
|
||||||
|
|
||||||
await context.api.client.trainMessage(refMsg.content, label)
|
await context.api.client.trainMessage(refMsg.content, label)
|
||||||
await trigger.reply({
|
await trigger.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
createSuccessEmbed(
|
createSuccessEmbed(
|
||||||
'Message trained',
|
'Message trained',
|
||||||
`The provided message has been trained as ${label ? `\`${label}\`` : 'out of scope'}. Thank you for your contribution!`,
|
`The provided message has been trained as \`${label}\`. Thank you for your contribution!`,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
flags: MessageFlags.Ephemeral,
|
flags: MessageFlags.Ephemeral,
|
||||||
|
|||||||
@@ -37,10 +37,7 @@ export default new Command({
|
|||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
custom_id: `tr_${trigger.targetMessage.channelId}_${trigger.targetId}`,
|
custom_id: `tr_${trigger.targetMessage.channelId}_${trigger.targetId}`,
|
||||||
options: [
|
options: labels.map(label => ({ label, value: label })),
|
||||||
...labels.map(label => ({ label, value: label })),
|
|
||||||
{ label: 'Out of scope', value: OutOfScopeLabel, emoji: { name: '❌' } },
|
|
||||||
],
|
|
||||||
type: ComponentType.StringSelect,
|
type: ComponentType.StringSelect,
|
||||||
} satisfies APIStringSelectComponent,
|
} satisfies APIStringSelectComponent,
|
||||||
],
|
],
|
||||||
@@ -51,5 +48,3 @@ export default new Command({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export const OutOfScopeLabel = '<out of scope>'
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { and, eq, gt } from 'drizzle-orm'
|
|||||||
import { appliedPresets } from '$/database/schemas'
|
import { appliedPresets } from '$/database/schemas'
|
||||||
import { on, withContext } from '$/utils/discord/events'
|
import { on, withContext } from '$/utils/discord/events'
|
||||||
import { applyRolesUsingPreset } from '$/utils/discord/rolePresets'
|
import { applyRolesUsingPreset } from '$/utils/discord/rolePresets'
|
||||||
|
import { logger } from '$/context'
|
||||||
|
|
||||||
withContext(on, 'guildMemberAdd', async ({ database }, member) => {
|
withContext(on, 'guildMemberAdd', async ({ database }, member) => {
|
||||||
const applieds = await database.query.appliedPresets.findMany({
|
const applieds = await database.query.appliedPresets.findMany({
|
||||||
@@ -12,5 +13,12 @@ withContext(on, 'guildMemberAdd', async ({ database }, member) => {
|
|||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (!applieds.length) return
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
`Re-applying role presets for member ${member.id} in guild ${member.guild.id}:`,
|
||||||
|
applieds.map(x => x.preset),
|
||||||
|
)
|
||||||
|
|
||||||
for (const { preset } of applieds) await applyRolesUsingPreset(preset, member)
|
for (const { preset } of applieds) await applyRolesUsingPreset(preset, member)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ withContext(on, 'interactionCreate', async (context, interaction) => {
|
|||||||
|
|
||||||
const editMessage = (content: string, description?: string) =>
|
const editMessage = (content: string, description?: string) =>
|
||||||
editInteractionMessage(interaction, msg.url, content, description)
|
editInteractionMessage(interaction, msg.url, content, description)
|
||||||
const handleCorrection = (label?: string) =>
|
const handleCorrection = (label: string) =>
|
||||||
handleUserResponseCorrection(context, response, msg, interaction.user, label)
|
handleUserResponseCorrection(context, response, msg, label, interaction.user)
|
||||||
|
|
||||||
if (response.correctedById)
|
if (response.correctedById)
|
||||||
return await editMessage(
|
return await editMessage(
|
||||||
@@ -82,7 +82,7 @@ withContext(on, 'interactionCreate', async (context, interaction) => {
|
|||||||
await editMessage('Canceled', 'You canceled this interaction. 😞')
|
await editMessage('Canceled', 'You canceled this interaction. 😞')
|
||||||
break
|
break
|
||||||
case 'delete':
|
case 'delete':
|
||||||
await handleCorrection()
|
await handleCorrection(msConfig.humanCorrections.falsePositiveLabel)
|
||||||
await editMessage(
|
await editMessage(
|
||||||
'Marked as false positive',
|
'Marked as false positive',
|
||||||
'The response has been deleted and marked as a false positive. Thank you for your feedback. 🎉',
|
'The response has been deleted and marked as a false positive. Thank you for your feedback. 🎉',
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { MessageFlags, type TextBasedChannel } from 'discord.js'
|
import { MessageFlags, type TextBasedChannel } from 'discord.js'
|
||||||
import { OutOfScopeLabel } from '$/commands/support/train/context-menu'
|
|
||||||
import { createErrorEmbed, createStackTraceEmbed, createSuccessEmbed } from '$utils/discord/embeds'
|
import { createErrorEmbed, createStackTraceEmbed, createSuccessEmbed } from '$utils/discord/embeds'
|
||||||
import { on, withContext } from '$utils/discord/events'
|
import { on, withContext } from '$utils/discord/events'
|
||||||
|
|
||||||
@@ -31,11 +30,8 @@ withContext(on, 'interactionCreate', async (context, interaction) => {
|
|||||||
flags: MessageFlags.Ephemeral,
|
flags: MessageFlags.Ephemeral,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const selectedLabel = interaction.values[0]
|
const selectedLabel = interaction.values[0]!
|
||||||
await context.api.client.trainMessage(
|
await context.api.client.trainMessage(msg.content, selectedLabel)
|
||||||
msg.content,
|
|
||||||
selectedLabel === OutOfScopeLabel ? undefined : selectedLabel,
|
|
||||||
)
|
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
createSuccessEmbed(
|
createSuccessEmbed(
|
||||||
|
|||||||
@@ -33,7 +33,13 @@ withContext(on, 'messageCreate', async (context, msg) => {
|
|||||||
if (response) {
|
if (response) {
|
||||||
logger.debug('Response found')
|
logger.debug('Response found')
|
||||||
|
|
||||||
const toReply = respondToReply ? (msg.reference?.messageId ? await msg.fetchReference() : msg) : msg
|
const toReply =
|
||||||
|
msg.reference?.messageId &&
|
||||||
|
(respondToReply === true ||
|
||||||
|
(label === undefined ? respondToReply === 'only_regex' : respondToReply === 'only_labeled'))
|
||||||
|
? await msg.fetchReference()
|
||||||
|
: msg
|
||||||
|
|
||||||
const reply = await toReply.reply({
|
const reply = await toReply.reply({
|
||||||
...response,
|
...response,
|
||||||
embeds: response.embeds?.map(createMessageScanResponseEmbed),
|
embeds: response.embeds?.map(createMessageScanResponseEmbed),
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ withContext(on, 'messageReactionAdd', async (context, rct, user) => {
|
|||||||
|
|
||||||
logger.debug(`User ${user.id} is trying to correct the response ${rct.message.id}`)
|
logger.debug(`User ${user.id} is trying to correct the response ${rct.message.id}`)
|
||||||
|
|
||||||
const handleCorrection = (label?: string) =>
|
const handleCorrection = (label: string) =>
|
||||||
handleUserResponseCorrection(context, response, reactionMessage, user, label)
|
handleUserResponseCorrection(context, response, reactionMessage, label, user)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (reaction.emoji.name === Reactions.train) {
|
if (reaction.emoji.name === Reactions.train) {
|
||||||
@@ -106,7 +106,7 @@ withContext(on, 'messageReactionAdd', async (context, rct, user) => {
|
|||||||
.setCustomId(`${componentPrefix}_cancel`),
|
.setCustomId(`${componentPrefix}_cancel`),
|
||||||
new ButtonBuilder()
|
new ButtonBuilder()
|
||||||
.setEmoji(Reactions.delete)
|
.setEmoji(Reactions.delete)
|
||||||
.setLabel('Delete (mark as out of scope)')
|
.setLabel('Delete (mark as false positive)')
|
||||||
.setStyle(ButtonStyle.Danger)
|
.setStyle(ButtonStyle.Danger)
|
||||||
.setCustomId(`${componentPrefix}_delete`),
|
.setCustomId(`${componentPrefix}_delete`),
|
||||||
),
|
),
|
||||||
@@ -117,8 +117,8 @@ withContext(on, 'messageReactionAdd', async (context, rct, user) => {
|
|||||||
components: rows,
|
components: rows,
|
||||||
})
|
})
|
||||||
} else if (reaction.emoji.name === Reactions.delete) {
|
} else if (reaction.emoji.name === Reactions.delete) {
|
||||||
await handleCorrection()
|
await handleCorrection(msConfig.humanCorrections.falsePositiveLabel)
|
||||||
await user.send({ content: 'The response has been deleted and marked as out of scope.' })
|
await user.send({ content: 'The response has been deleted and marked as a false positive.' })
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('Failed to correct response:', e)
|
logger.error('Failed to correct response:', e)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const getResponseFromText = async (
|
|||||||
type ResponseConfig = Awaited<ReturnType<typeof getResponseFromText>>
|
type ResponseConfig = Awaited<ReturnType<typeof getResponseFromText>>
|
||||||
let responseConfig: Omit<ResponseConfig, 'triggers'> & { triggers?: ResponseConfig['triggers'] } = {
|
let responseConfig: Omit<ResponseConfig, 'triggers'> & { triggers?: ResponseConfig['triggers'] } = {
|
||||||
triggers: undefined,
|
triggers: undefined,
|
||||||
response: null!,
|
response: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstLabelIndexes: number[] = []
|
const firstLabelIndexes: number[] = []
|
||||||
@@ -143,22 +143,15 @@ export const handleUserResponseCorrection = async (
|
|||||||
{ api, database: db, config: { messageScan: msConfig }, logger }: typeof import('$/context'),
|
{ api, database: db, config: { messageScan: msConfig }, logger }: typeof import('$/context'),
|
||||||
response: Response,
|
response: Response,
|
||||||
reply: Message,
|
reply: Message,
|
||||||
|
label: string,
|
||||||
user: User | PartialUser,
|
user: User | PartialUser,
|
||||||
label?: string,
|
|
||||||
) => {
|
) => {
|
||||||
if (!label) {
|
|
||||||
await Promise.all([reply.delete(), api.client.trainMessage(response.content, label)]).finally(() =>
|
|
||||||
logger.debug(`User ${user.id} trained message ${response.replyId} as out of scope`),
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const correctLabelResponse = msConfig!.responses!.find(r =>
|
const correctLabelResponse = msConfig!.responses!.find(r =>
|
||||||
r.triggers.text!.some(t => 'label' in t && t.label === label),
|
r.triggers.text!.some(t => 'label' in t && t.label === label),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!correctLabelResponse) throw new Error('Cannot find label config for the selected label')
|
if (!correctLabelResponse) throw new Error('Cannot find label config for the selected label')
|
||||||
|
if (!correctLabelResponse.response) return void (await reply.delete())
|
||||||
|
|
||||||
if (response.label !== label) {
|
if (response.label !== label) {
|
||||||
db.update(responses)
|
db.update(responses)
|
||||||
@@ -175,12 +168,12 @@ export const handleUserResponseCorrection = async (
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all([
|
await api.client.trainMessage(response.content, label)
|
||||||
api.client.trainMessage(response.content, label),
|
logger.debug(`User ${user.id} trained message ${response.replyId} as ${label} (positive)`)
|
||||||
reply.edit({
|
|
||||||
|
await reply.edit({
|
||||||
components: [],
|
components: [],
|
||||||
}),
|
})
|
||||||
]).finally(() => logger.debug(`User ${user.id} trained message ${response.replyId} as ${label}`))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createMessageScanResponseComponents = (reply: Message<true>) => [
|
export const createMessageScanResponseComponents = (reply: Message<true>) => [
|
||||||
|
|||||||
Reference in New Issue
Block a user