Réécriture complète 4.0
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 6m16s
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 6m16s
This commit is contained in:
@@ -1,117 +1,139 @@
|
||||
import { Events, Client, ActivityType } from 'discord.js'
|
||||
import { SpotifyExtractor } from '@discord-player/extractor'
|
||||
import { YoutubeiExtractor } from 'discord-player-youtubei'
|
||||
import { useMainPlayer } from 'discord-player'
|
||||
import { connect } from 'mongoose'
|
||||
import WebSocket from 'websocket'
|
||||
import chalk from 'chalk'
|
||||
import 'dotenv/config'
|
||||
|
||||
import dbGuildInit from '../../utils/dbGuildInit'
|
||||
import dbGuild from '../../schemas/guild'
|
||||
import { playerDisco, playerReplay } from '../../utils/player'
|
||||
import * as Twitch from '../../utils/twitch'
|
||||
import rss from '../../utils/rss'
|
||||
|
||||
export default {
|
||||
name: Events.ClientReady,
|
||||
once: true,
|
||||
async execute(client: Client) {
|
||||
console.log(chalk.blue(`[DiscordJS] Connected to Discord ! Logged in as ${client.user?.tag ?? 'unknown'}`))
|
||||
client.user?.setActivity('some bangers...', { type: ActivityType.Listening })
|
||||
|
||||
await useMainPlayer().extractors.register(SpotifyExtractor, {}).then(() => console.log(chalk.blue('[Discord-Player] Spotify extractor loaded.'))).catch(console.error)
|
||||
await useMainPlayer().extractors.register(YoutubeiExtractor, {}).then(() => console.log(chalk.blue('[Discord-Player] Youtube extractor loaded.'))).catch(console.error)
|
||||
|
||||
let 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)
|
||||
|
||||
|
||||
let guilds = client.guilds.cache
|
||||
guilds.forEach(async guild => {
|
||||
let guildProfile = await dbGuild.findOne({ guildId: guild.id })
|
||||
|
||||
if (!guildProfile) guildProfile = await dbGuildInit(guild)
|
||||
if (guildProfile.guildPlayer?.replay?.enabled && guildProfile.guildPlayer?.replay?.textChannelId) await playerReplay(client, guildProfile)
|
||||
|
||||
client.disco = { interval: {} as NodeJS.Timeout }
|
||||
client.disco.interval = setInterval(async () => {
|
||||
let guildProfile = await dbGuild.findOne({ guildId: guild.id })
|
||||
|
||||
if (guildProfile?.guildPlayer?.disco?.enabled) {
|
||||
let state = await playerDisco(client, guildProfile)
|
||||
if (state === 'clear') clearInterval(client.disco.interval)
|
||||
}
|
||||
}, 3000)
|
||||
|
||||
client.rss = { interval: {} as NodeJS.Timeout }
|
||||
client.rss.interval = setInterval(async () => {
|
||||
let guildProfile = await dbGuild.findOne({ guildId: guild.id })
|
||||
|
||||
if (guildProfile?.guildRss?.enabled) {
|
||||
let state = await rss(client, guildProfile)
|
||||
if (state === 'clear') clearInterval(client.rss.interval)
|
||||
}
|
||||
}, 30000)
|
||||
|
||||
// TWITCH EVENTSUB
|
||||
if (process.env['TWITCH_RUNNING_' + guild.id]) return console.log(chalk.magenta(`[Twitch] {${guild.name}} Already running...`))
|
||||
console.log(chalk.magenta(`[Twitch] {${guild.name}} Not running, starting...`))
|
||||
process.env['TWITCH_RUNNING_' + guild.id] = 'true'
|
||||
|
||||
let client_id = process.env.TWITCH_APP_ID as string
|
||||
let client_secret = process.env.TWITCH_APP_SECRET as string
|
||||
if (!client_id || !client_secret) return console.log(chalk.magenta(`[Twitch] {${guild.name}} App ID or Secret is not defined !`))
|
||||
|
||||
let dbData = guildProfile.get('guildTwitch')
|
||||
if (!dbData?.enabled) return console.log(chalk.magenta(`[Twitch] {${guild.name}} Module is disabled, please activate with \`/database edit guildTwitch.enabled True\` !`))
|
||||
|
||||
let twitch = new WebSocket.client().on('connect', async connection => {
|
||||
console.log(chalk.magenta(`[Twitch] {${guild.name}} EventSub WebSocket Connected !`))
|
||||
|
||||
connection.on('message', async message => { if (message.type === 'utf8') { try {
|
||||
let data = JSON.parse(message.utf8Data)
|
||||
let channel_access_token = guildProfile.get('guildTwitch')?.channelAccessToken as string
|
||||
|
||||
// Check when Twitch asks to login
|
||||
if (data.metadata.message_type === 'session_welcome') {
|
||||
|
||||
// Check if the channel access token is still valid before connecting
|
||||
channel_access_token = await Twitch.checkChannel(client_id, client_secret, channel_access_token, guild) as string
|
||||
if (!channel_access_token) return console.log(chalk.magenta(`[Twitch] {${guild.name}} Can't refresh channel access token !`))
|
||||
|
||||
// Get broadcaster user id and reward id
|
||||
let broadcaster_user_id = await Twitch.getUserInfo(client_id, channel_access_token, 'id') as string
|
||||
|
||||
let topics: { [key: string]: { version: string; condition: { broadcaster_user_id: string } } } = {
|
||||
'stream.online': { version: '1', condition: { broadcaster_user_id } },
|
||||
'stream.offline': { version: '1', condition: { broadcaster_user_id } }
|
||||
}
|
||||
|
||||
// Subscribe to all events required
|
||||
for (let type in topics) {
|
||||
console.log(chalk.magenta(`[Twitch] {${guild.name}} Creating ${type}...`))
|
||||
let { version, condition } = topics[type]
|
||||
|
||||
let status = await Twitch.subscribeToEvents(client_id, channel_access_token, data.payload.session.id, type, version, condition)
|
||||
if (!status) return console.error(chalk.magenta(`[Twitch] {${guild.name}} Failed to create ${type}`))
|
||||
else if (status.error) return console.log(chalk.magenta(`[Twitch] {${guild.name}} Erreur de connexion EventSub, veuillez vous reconnecter !`))
|
||||
else console.log(chalk.magenta(`[Twitch] {${guild.name}} Successfully created ${type}`))
|
||||
}
|
||||
}
|
||||
|
||||
// Handle notification messages
|
||||
else if (data.metadata.message_type === 'notification') Twitch.notification(client_id, client_secret, channel_access_token, data, guild)
|
||||
|
||||
} catch (error) { console.error(chalk.magenta(`[Twitch] {${guild.name}} ` + error)) } } })
|
||||
.on('error', error => console.error(chalk.magenta(`[Twitch] {${guild.name}} ` + error)))
|
||||
.on('close', () => {
|
||||
console.log(chalk.magenta(`[Twitch] {${guild.name}} EventSub Connection Closed !`))
|
||||
twitch.connect('wss://eventsub.wss.twitch.tv/ws')
|
||||
})
|
||||
}).on('connectFailed', error => console.error(chalk.magenta(`[Twitch] {${guild.name}} ` + error)))
|
||||
|
||||
twitch.connect('wss://eventsub.wss.twitch.tv/ws')
|
||||
})
|
||||
}
|
||||
}
|
||||
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 } 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 })
|
||||
|
||||
await useMainPlayer().extractors.register(SpotifyExtractor, {}).then(() => { logConsole('discord_player', 'extractor_loaded', { extractor: 'Spotify' }) }).catch(console.error)
|
||||
await useMainPlayer().extractors.register(YoutubeiExtractor, {}).then(() => { logConsole('discord_player', 'extractor_loaded', { extractor: 'Youtube' }) }).catch(console.error)
|
||||
|
||||
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) {
|
||||
logConsole('twitch', 'ready.message_not_found', { guild: guild.name, userName: user.name })
|
||||
console.error(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 (error) {
|
||||
logConsole('twitch', 'ready.cleanup_error', { userId: twitchUserId })
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user