import { Events, ActivityType, ChannelType } from "discord.js" import type { Client } from "discord.js" import { useMainPlayer } from "discord-player" import { SpotifyExtractor } from "@discord-player/extractor" import { YoutubeiExtractor } from "discord-player-youtubei" import { connect } from "mongoose" import type { Document } from "mongoose" import { playerDisco, playerReplay } from "@/utils/player" import { twitchClient, listener, onlineSub, offlineSub, startStreamWatching } from "@/utils/twitch" import { logConsole, logConsoleError } from "@/utils/console" import type { GuildPlayer, Disco, GuildTwitch, GuildFbx } from "@/types/schemas" import * as Freebox from "@/utils/freebox" import dbGuildInit from "@/utils/dbGuildInit" import dbGuild from "@/schemas/guild" export const name = Events.ClientReady export const once = true export async function execute(client: Client) { logConsole('discordjs', 'ready', { tag: client.user?.tag ?? "unknown" }) client.user?.setActivity("some bangers...", { type: ActivityType.Listening }) const player = useMainPlayer() await player.extractors.register(SpotifyExtractor, {}).then(() => { logConsole('discord_player', 'extractor_loaded', { extractor: 'Spotify' }) }).catch(console.error) await player.extractors.register(YoutubeiExtractor, {}).then(() => { logConsole('discord_player', 'extractor_loaded', { extractor: 'Youtube' }) }).catch(console.error) if (process.env.NODE_ENV === "development") console.log(player.scanDeps()) const mongo_url = `mongodb://${process.env.MONGOOSE_USER}:${process.env.MONGOOSE_PASSWORD}@${process.env.MONGOOSE_HOST}/${process.env.MONGOOSE_DATABASE}` await connect(mongo_url).catch(console.error) if (process.env.NODE_ENV === "development") await twitchClient.eventSub.deleteAllSubscriptions() const streamerIds: string[] = [] await Promise.all(client.guilds.cache.map(async guild => { let guildProfile = await dbGuild.findOne({ guildId: guild.id }) guildProfile ??= await dbGuildInit(guild) const dbDataPlayer = guildProfile.get("guildPlayer") as GuildPlayer const botInstance = dbDataPlayer.instances?.find(instance => instance.botId === client.user?.id) if (botInstance?.replay.trackUrl) await playerReplay(client, dbDataPlayer) client.disco = { interval: {} as NodeJS.Timeout } // eslint-disable-next-line @typescript-eslint/no-misused-promises client.disco.interval = setInterval(async () => { const guildProfile = await dbGuild.findOne({ guildId: guild.id }) const dbDataDisco = guildProfile?.get("guildPlayer.disco") as Disco if (dbDataDisco.enabled) { const state = await playerDisco(client, guild, dbDataDisco) if (state === "clear") clearInterval(client.disco.interval) } }, 3000) // Gestion du timer LCD Freebox const dbDataFbx = guildProfile.get("guildFbx") as GuildFbx if (dbDataFbx.enabled && dbDataFbx.lcd) { if (dbDataFbx.lcd.enabled && dbDataFbx.lcd.botId === client.user?.id) { logConsole('freebox', 'lcd_timer_restored', { guild: guild.name }) Freebox.Timer.schedule(client, guild.id, dbDataFbx) } } const dbDataTwitch = guildProfile.get("guildTwitch") as GuildTwitch if (!dbDataTwitch.enabled) return if (!dbDataTwitch.streamers.length) { logConsole('twitch', 'ready.no_streamers_configured', { guild: guild.name }); return } await Promise.all(dbDataTwitch.streamers.map(async streamer => { if (streamerIds.includes(streamer.twitchUserId)) return streamerIds.push(streamer.twitchUserId) const user = await twitchClient.users.getUserById(streamer.twitchUserId) if (!user) { logConsole('twitch', 'ready.user_not_found', { guild: guild.name, userId: streamer.twitchUserId }); return } const userSubs = await twitchClient.eventSub.getSubscriptionsForUser(streamer.twitchUserId) if (!userSubs.data.find(sub => sub.transportMethod === "webhook" && sub.type === "stream.online")) { // eslint-disable-next-line @typescript-eslint/no-misused-promises listener.onStreamOnline(streamer.twitchUserId, onlineSub) logConsole('twitch', 'listener_registered', { type: 'stream.online', name: user.name, id: streamer.twitchUserId }) } if (!userSubs.data.find(sub => sub.transportMethod === "webhook" && sub.type === "stream.offline")) { // eslint-disable-next-line @typescript-eslint/no-misused-promises listener.onStreamOffline(streamer.twitchUserId, offlineSub) logConsole('twitch', 'listener_registered', { type: 'stream.offline', name: user.name, id: streamer.twitchUserId }) } logConsole('twitch', 'user_operational', { name: user.name, id: streamer.twitchUserId }) const stream = await user.getStream() if (stream && streamer.messageId) { logConsole('twitch', 'ready.stream_restoration', { guild: guild.name, userName: user.name, userId: streamer.twitchUserId }) // Vérifier que le message existe encore if (!dbDataTwitch.channelId) return const channel = await guild.channels.fetch(dbDataTwitch.channelId) if (channel && (channel.type === ChannelType.GuildText || channel.type === ChannelType.GuildAnnouncement)) { try { await channel.messages.fetch(streamer.messageId) startStreamWatching(guild.id, streamer.twitchUserId, user.name, streamer.messageId) logConsole('twitch', 'ready.monitoring_restored', { guild: guild.name, userName: user.name }) } catch (error) { logConsoleError('twitch', 'ready.message_not_found', { guild: guild.name, userName: user.name }, error as Error) await cleanupMessageId(guildProfile, streamer.twitchUserId) } } } else if (streamer.messageId) { // Il y a un messageId mais le stream n'est plus en ligne, nettoyer logConsole('twitch', 'ready.stream_offline_cleanup', { guild: guild.name, userName: user.name }) await cleanupMessageId(guildProfile, streamer.twitchUserId) } logConsole('twitch', 'user_operational', { name: user.name, id: streamer.twitchUserId }) })) })) const subs = await twitchClient.eventSub.getSubscriptions() await Promise.all(subs.data.map(async sub => { if (streamerIds.includes(sub.condition.broadcaster_user_id as string)) return if (sub.type !== "stream.online" && sub.type !== "stream.offline") return await sub.unsubscribe().catch(console.error) logConsole('twitch', 'unsubscribed', { type: sub.type, id: sub.condition.broadcaster_user_id as string }) })) } async function cleanupMessageId(guildProfile: Document, twitchUserId: string) { try { const dbData = guildProfile.get("guildTwitch") as GuildTwitch const streamerIndex = dbData.streamers.findIndex(s => s.twitchUserId === twitchUserId) if (streamerIndex === -1) return dbData.streamers[streamerIndex].messageId = "" guildProfile.set("guildTwitch", dbData) guildProfile.markModified("guildTwitch") await guildProfile.save().catch(console.error) } catch (error) { logConsoleError('twitch', 'ready.cleanup_error', { userId: twitchUserId }, error as Error) } }