Compare commits

..

3 Commits

Author SHA1 Message Date
semantic-release-bot
8168f79ac6 chore(release): 1.0.0-dev.8 [skip ci]
# @revanced/discord-bot [1.0.0-dev.8](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.7...@revanced/discord-bot@1.0.0-dev.8) (2024-07-28)

### Bug Fixes

* **bots/discord:** cross-device link build errors ([38c0699](38c06997b4))

### Features

* **bots/discord:** blacklist and whitelist for filters ([cdb6001](cdb6001955))
2024-07-28 14:15:40 +00:00
PalmDevs
38c06997b4 fix(bots/discord): cross-device link build errors 2024-07-28 21:14:07 +07:00
PalmDevs
cdb6001955 feat(bots/discord): blacklist and whitelist for filters 2024-07-28 20:43:25 +07:00
11 changed files with 72 additions and 44 deletions

View File

@@ -1,3 +1,15 @@
# @revanced/discord-bot [1.0.0-dev.8](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.7...@revanced/discord-bot@1.0.0-dev.8) (2024-07-28)
### Bug Fixes
* **bots/discord:** cross-device link build errors ([38c0699](https://github.com/revanced/revanced-helper/commit/38c06997b4d0f7bb3f1e62618a5e3f088c522e30))
### Features
* **bots/discord:** blacklist and whitelist for filters ([cdb6001](https://github.com/revanced/revanced-helper/commit/cdb600195520dba33110c40841629259e317055e))
# @revanced/discord-bot [1.0.0-dev.7](https://github.com/revanced/revanced-helper/compare/@revanced/discord-bot@1.0.0-dev.6...@revanced/discord-bot@1.0.0-dev.7) (2024-07-25)

View File

@@ -37,11 +37,19 @@ export default {
checkExpiredEvery: 3600,
},
messageScan: {
scanBots: false,
scanOutsideGuilds: false,
filter: {
channels: ['CHANNEL_ID_HERE'],
roles: ['ROLE_ID_HERE'],
users: ['USER_ID_HERE'],
whitelist: false,
whitelist: {
channels: ['CHANNEL_ID_HERE'],
roles: ['ROLE_ID_HERE'],
users: ['USER_ID_HERE'],
},
blacklist: {
channels: ['CHANNEL_ID_HERE'],
roles: ['ROLE_ID_HERE'],
users: ['USER_ID_HERE'],
},
},
humanCorrections: {
falsePositiveLabel: 'false_positive',
@@ -55,6 +63,18 @@ export default {
allowedAttachmentMimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
responses: [
{
filterOverride: {
whitelist: {
channels: ['CHANNEL_ID_HERE'],
roles: ['ROLE_ID_HERE'],
users: ['USER_ID_HERE'],
},
blacklist: {
channels: ['CHANNEL_ID_HERE'],
roles: ['ROLE_ID_HERE'],
users: ['USER_ID_HERE'],
},
},
triggers: {
text: [/^regexp?$/, { label: 'label', threshold: 0.85 }],
},

View File

@@ -20,12 +20,12 @@ export type Config = {
guilds: Record<string, Record<string, RolePresetConfig>>
}
messageScan?: {
scanBots?: boolean
scanOutsideGuilds?: boolean
allowedAttachmentMimeTypes: string[]
filter: {
roles?: string[]
users?: string[]
channels?: string[]
whitelist: boolean
filter?: {
whitelist?: Filter
blacklist?: Filter
}
humanCorrections: {
falsePositiveLabel: string
@@ -73,4 +73,10 @@ export type ConfigMessageScanResponseLabelConfig = {
threshold: number
}
export type Filter = {
roles?: string[]
users?: string[]
channels?: string[]
}
export type ConfigMessageScanResponseMessage = BaseMessageOptions

View File

@@ -2,7 +2,7 @@
"name": "@revanced/discord-bot",
"type": "module",
"private": true,
"version": "1.0.0-dev.7",
"version": "1.0.0-dev.8",
"description": "🤖 Discord bot assisting ReVanced",
"main": "src/index.ts",
"scripts": {

View File

@@ -17,7 +17,8 @@ await Bun.build({
})
logger.info('Copying config...')
await cp('config.js', 'dist/config.js')
await cp('./config.js', './dist/config.js')
logger.info('Copying database schema...')
await rename('.drizzle', 'dist/.drizzle')
await cp('./.drizzle', './dist/.drizzle', { recursive: true })
await rm('./.drizzle', { recursive: true })

View File

@@ -3,7 +3,7 @@ import { existsSync, readFileSync, readdirSync } from 'fs'
import { join } from 'path'
import { Client as APIClient } from '@revanced/bot-api'
import { createLogger } from '@revanced/bot-shared'
import { ActivityType, Client as DiscordClient, Partials } from 'discord.js'
import { Client as DiscordClient, Partials } from 'discord.js'
import { drizzle } from 'drizzle-orm/bun-sqlite'
// Export config first, as commands require them
@@ -27,7 +27,7 @@ export const api = {
},
},
}),
isStopping: false,
intentionallyDisconnecting: false,
disconnectCount: 0,
}
@@ -80,14 +80,6 @@ export const discord = {
repliedUser: true,
},
partials: [Partials.Message, Partials.Reaction],
presence: {
activities: [
{
type: ActivityType.Watching,
name: 'cat videos',
},
],
},
}),
commands: Object.fromEntries(Object.values<Command>(commands).map(cmd => [cmd.data.name, cmd])) as Record<
string,

View File

@@ -2,7 +2,7 @@ import { on, withContext } from '$utils/api/events'
import { DisconnectReason, HumanizedDisconnectReason } from '@revanced/bot-shared'
withContext(on, 'disconnect', ({ api, config, logger }, reason, msg) => {
if (reason === DisconnectReason.PlannedDisconnect && api.isStopping) return
if (reason === DisconnectReason.PlannedDisconnect && api.intentionallyDisconnecting) return
const ws = api.client.ws
if (!ws.disconnected) ws.disconnect()

View File

@@ -1,6 +1,6 @@
import { MessageScanLabeledResponseReactions } from '$/constants'
import { responses } from '$/database/schemas'
import { getResponseFromText, shouldScanMessage } from '$/utils/discord/messageScan'
import { getResponseFromText, messageMatchesFilter } from '$/utils/discord/messageScan'
import { createMessageScanResponseEmbed } from '$utils/discord/embeds'
import { on, withContext } from '$utils/discord/events'
@@ -13,8 +13,11 @@ withContext(on, 'messageCreate', async (context, msg) => {
} = context
if (!config || !config.responses) return
if (msg.author.bot && !config.scanBots)
if (!msg.inGuild() && !config.scanOutsideGuilds) return
if (msg.inGuild() && msg.member?.partial) await msg.member.fetch()
const filteredResponses = config.responses.filter(x => shouldScanMessage(msg, x.filterOverride ?? config.filter))
const filteredResponses = config.responses.filter(x => messageMatchesFilter(msg, x.filterOverride ?? config.filter))
if (!filteredResponses.length) return
if (msg.content.length) {

View File

@@ -33,7 +33,7 @@ withContext(on, 'messageReactionAdd', async (context, rct, user) => {
if (reactionMessage.author.id !== reaction.client.user!.id) return
if (!PossibleReactions.includes(reaction.emoji.name!)) return
if (!isAdmin(reactionMessage.member || reactionMessage.author, config.admin)) {
if (!isAdmin(reactionMessage.member || reactionMessage.author)) {
// User is in guild, and config has member requirements
if (
reactionMessage.inGuild() &&

View File

@@ -113,24 +113,18 @@ export const getResponseFromText = async (
return responseConfig
}
export const shouldScanMessage = (
export const messageMatchesFilter = (
message: Message,
filter: NonNullable<Config['messageScan']>['filter'],
): message is Message<true> => {
if (message.author.bot) return false
if (!message.guild) return false
) => {
if (!filter) return true
const filters = [
filter.users?.includes(message.author.id),
message.member?.roles.cache.some(x => filter.roles?.includes(x.id)),
filter.channels?.includes(message.channel.id),
]
const memberRoles = new Set(message.member?.roles.cache.keys())
const blFilter = filter.blacklist
if (filter.whitelist && filters.every(x => !x)) return false
if (!filter.whitelist && filters.some(x => x)) return false
return true
// If matches blacklist, will return false
// Any other case, will return true
return !(blFilter && (blFilter.channels?.includes(message.channelId) || blFilter.roles?.some(role => memberRoles.has(role)) || blFilter.users?.includes(message.author.id)))
}
export const handleUserResponseCorrection = async (

View File

@@ -1,11 +1,11 @@
import { GuildMember, type User } from 'discord.js'
import type { Config } from 'config.schema'
import config from '../../../config'
export const isAdmin = (userOrMember: User | GuildMember, adminConfig: Config['admin']) => {
return adminConfig?.users?.includes(userOrMember.id) || (userOrMember instanceof GuildMember && isMemberAdmin(userOrMember, adminConfig))
export const isAdmin = (userOrMember: User | GuildMember) => {
return config.admin?.users?.includes(userOrMember.id) || (userOrMember instanceof GuildMember && isMemberAdmin(userOrMember))
}
export const isMemberAdmin = (member: GuildMember, adminConfig: Config['admin']) => {
export const isMemberAdmin = (member: GuildMember) => {
const roles = new Set(member.roles.cache.keys())
return Boolean(adminConfig?.roles?.[member.guild.id]?.some(role => roles.has(role)))
return Boolean(config?.admin?.roles?.[member.guild.id]?.some(role => roles.has(role)))
}