jellyfin-discord-bot/server/structures/client.ts

121 lines
5.1 KiB
TypeScript
Raw Normal View History

import { ApplicationCommandDataResolvable, Client, ClientOptions, Collection, GatewayIntentBits, Guild, IntentsBitField, Snowflake, TextChannel } from "discord.js";
2023-04-15 22:06:35 +02:00
import { CommandType } from "../types/commandTypes";
import fs from 'fs'
import { config } from "../configuration";
2023-04-16 02:03:39 +02:00
import { logger } from "../logger";
2023-05-04 23:38:51 +02:00
import { JellyfinHandler } from "../jellyfin/handler";
2023-04-15 22:06:35 +02:00
2023-04-15 22:06:35 +02:00
export class ExtendedClient extends Client {
private eventFilePath = `${__dirname}/../events`
private commandFilePath = `${__dirname}/../commands`
2023-04-16 02:03:39 +02:00
private jellyfin: JellyfinHandler
2023-04-15 22:06:35 +02:00
public commands: Collection<string, CommandType> = new Collection()
private announcementChannels: Collection<string, TextChannel> = new Collection //guildId to TextChannel
2023-04-16 02:03:39 +02:00
public constructor(jf: JellyfinHandler) {
2023-04-15 22:06:35 +02:00
const intents: IntentsBitField = new IntentsBitField()
intents.add(IntentsBitField.Flags.GuildMembers, IntentsBitField.Flags.MessageContent, IntentsBitField.Flags.Guilds, IntentsBitField.Flags.DirectMessages, IntentsBitField.Flags.GuildScheduledEvents, IntentsBitField.Flags.GuildVoiceStates)
2023-04-15 22:06:35 +02:00
const options: ClientOptions = { intents }
super(options)
2023-04-16 02:03:39 +02:00
this.jellyfin = jf
2023-04-15 22:06:35 +02:00
}
2023-04-16 02:03:39 +02:00
public async start() {
2023-04-15 22:06:35 +02:00
if (process.env.NODE_ENV === 'test') return
2023-05-04 23:38:51 +02:00
const promises: Promise<any>[] = []
2023-04-15 22:06:35 +02:00
promises.push(this.registerSlashCommands())
promises.push(this.registerEventCallback())
Promise.all(promises).then(() => {
2023-04-16 02:03:39 +02:00
this.login(config.bot.token)
2023-04-15 22:06:35 +02:00
})
2023-04-16 02:03:39 +02:00
logger.info(`Connected with ${await this.jellyfin.ServerName()}`)
2023-04-15 22:06:35 +02:00
}
private async importFile(filepath: string): Promise<any> {
2023-05-04 23:38:51 +02:00
logger.debug(`Importing ${filepath}`)
2023-04-15 22:06:35 +02:00
const imported = await import(filepath)
2023-05-04 23:38:51 +02:00
logger.debug(`Imported ${JSON.stringify(imported)}`)
2023-04-15 22:06:35 +02:00
return imported.default ?? imported
}
public async registerCommands(cmds: ApplicationCommandDataResolvable[], guildIds: Collection<Snowflake, Guild>) {
if (guildIds) {
guildIds.forEach(guild => {
this.guilds.cache.get(guild.id)?.commands.set(cmds)
2023-05-04 23:38:51 +02:00
logger.info(`Registering commands to ${guild.name}|${guild.id}`)
2023-04-15 22:06:35 +02:00
})
} else {
this.application?.commands.set(cmds)
2023-05-04 23:38:51 +02:00
logger.info(`Registering global commands`)
2023-04-15 22:06:35 +02:00
}
return
}
public async registerSlashCommands(): Promise<void> {
try {
const slashCommands: ApplicationCommandDataResolvable[] = []
const commandFiles = fs.readdirSync(this.commandFilePath).filter(file => file.endsWith('.ts') || file.endsWith('.js'))
for (const commandFile of commandFiles) {
const filePath = `${this.commandFilePath}/${commandFile}`
const command = await this.importFile(filePath)
2023-05-04 23:38:51 +02:00
logger.debug(JSON.stringify(command))
2023-04-15 22:06:35 +02:00
if (!command.name) return
this.commands.set(command.name, command)
slashCommands.push(command)
}
this.on("ready", (client: Client) => {
2023-05-04 23:38:51 +02:00
//logger.info(`Ready processing ${JSON.stringify(client)}`)
logger.info(`SlashCommands: ${JSON.stringify(slashCommands)}`)
2023-04-15 22:06:35 +02:00
const guilds = client.guilds.cache
2023-04-15 22:06:35 +02:00
this.registerCommands(slashCommands, guilds)
this.cacheUsers(guilds)
this.cacheAnnouncementServer(guilds)
2023-04-15 22:06:35 +02:00
})
} catch (error) {
2023-05-04 23:38:51 +02:00
logger.info(`Error refreshing slash commands: ${error}`)
2023-04-15 22:06:35 +02:00
}
}
private async cacheAnnouncementServer(guilds: Collection<Snowflake, Guild>) {
for (const guild of guilds.values()) {
const channels: TextChannel[] = <TextChannel[]>(await guild.channels.fetch())
?.filter(channel => channel!.id === config.bot.announcement_channel_id)
.map((value, _) => value)
if (!channels || channels.length != 1) {
logger.error(`Could not find announcement channel for guild ${guild.name} with guildId ${guild.id}. Found ${channels}`)
continue
}
logger.info(`Fetched announcement channel: ${JSON.stringify(channels[0])}`)
this.announcementChannels.set(guild.id, channels[0])
}
}
public getAnnouncementChannelForGuild(guildId: string): TextChannel {
return this.announcementChannels.get(guildId)! //we set the channel by ourselves only if we find one, I think this is sage (mark my words)
}
2023-04-15 22:06:35 +02:00
public async cacheUsers(guilds: Collection<Snowflake, Guild>) {
2023-04-16 02:03:39 +02:00
guilds.forEach((guild: Guild, id: Snowflake) => {
2023-05-04 23:38:51 +02:00
logger.info(`Fetching members for ${guild.name}|${id}`)
2023-04-15 22:06:35 +02:00
guild.members.fetch()
2023-05-04 23:38:51 +02:00
logger.info(`Fetched: ${guild.memberCount} members`)
2023-04-15 22:06:35 +02:00
})
}
public async registerEventCallback() {
try {
const eventFiles = fs.readdirSync(this.eventFilePath).filter(file => file.endsWith('.ts') || file.endsWith('.js'));
for (const file of eventFiles) {
const filePath = `${this.eventFilePath}/${file}`
const event = await this.importFile(filePath)
if (event.once) {
2023-05-04 23:38:51 +02:00
logger.info(`Registering once ${file}`)
2023-04-15 22:06:35 +02:00
this.once(event.name, (...args: any[]) => event.execute(...args))
}
else {
2023-05-04 23:38:51 +02:00
logger.info(`Registering on ${file}`)
2023-04-15 22:06:35 +02:00
this.on(event.name, (...args: any[]) => event.execute(...args))
}
}
2023-05-04 23:38:51 +02:00
logger.info(`Registered event names ${this.eventNames()}`)
2023-04-15 22:06:35 +02:00
} catch (error) {
2023-05-04 23:38:51 +02:00
logger.error(error)
2023-04-15 22:06:35 +02:00
}
}
}