Réécriture complète 4.0
Build and Push Docker Image / build-and-push (push) Failing after 6m16s

This commit is contained in:
Zachary Guénot
2025-06-09 16:29:12 +02:00
parent f2c6388da6
commit ddd617317c
133 changed files with 8092 additions and 4332 deletions
+5 -6
View File
@@ -1,8 +1,7 @@
import { Events } from 'discord.js'
import { Events } from "discord.js"
import { logConsoleError } from "@/utils/console"
export default {
name: Events.Error,
execute(error: Error) {
console.error(error)
}
export const name = Events.Error
export function execute(error: Error) {
logConsoleError('discordjs', 'error', { message: error.message }, error)
}
+12 -14
View File
@@ -1,14 +1,12 @@
import { Events, Guild } from 'discord.js'
import dbGuildInit from '../../utils/dbGuildInit'
export default {
name: Events.GuildCreate,
async execute(guild: Guild) {
console.log(`Joined "${guild.name}" with ${guild.memberCount} members`)
let guildProfile = await dbGuildInit(guild)
if (!guildProfile) return console.log(`An error occured while initializing database data for "${guild.name}" !`)
console.log(`Database data for new guild "${guildProfile.guildName}" successfully initialized !`)
}
}
import { Events, Guild } from "discord.js"
import dbGuildInit from "@/utils/dbGuildInit"
import { logConsole } from "@/utils/console"
export const name = Events.GuildCreate
export async function execute(guild: Guild) {
logConsole('discordjs', 'guild_create', { name: guild.name, count: guild.memberCount.toString() })
const guildProfile = await dbGuildInit(guild)
logConsole('mongoose', 'guild_create', { name: guildProfile.guildName })
}
+42 -44
View File
@@ -1,44 +1,42 @@
import { Events, GuildMember, EmbedBuilder, TextChannel } from 'discord.js'
export default {
name: Events.GuildMemberAdd,
async execute(member: GuildMember) {
if (member.guild.id === '1086577543651524699') { // Salon posé tamisé
let guild = member.guild
guild.members.fetch().then(() => {
let i = 0
guild.members.cache.forEach(async member => { if (!member.user.bot) i++ })
let channel = guild.channels.cache.get('1091140609139560508')
if (!channel) return
channel.setName('Changement...')
channel.setName(`${i} Gens Posés`)
}).catch(console.error)
} else if (member.guild.id === '796327643783626782') { // Jujul Community
let guild = member.guild
let channel = guild.channels.cache.get('837248593609097237') as TextChannel
if (!channel) return console.log(`\u001b[1;31m Aucun channel trouvé avec l'id "837248593609097237" !`)
if (!guild.members.me) return console.log(`\u001b[1;31m Je ne suis pas sur le serveur !`)
let embed = new EmbedBuilder()
.setColor(guild.members.me.displayHexColor)
.setTitle(`Salut ${member.user.username} !`)
.setDescription(`
Bienvenue sur le serveur de **Jujul** !
Nous sommes actuellement ${guild.memberCount} membres !\n
N'hésite pas à aller lire le <#797471924367786004> et à aller te présenter dans <#837138238417141791> !\n
Si tu as des questions,
n'hésite pas à les poser dans le <#837110617315344444> !\n
Bon séjour parmi nous !
`)
.setThumbnail(member.user.avatarURL())
.setTimestamp(new Date())
await channel.send({ embeds: [embed] })
}
}
}
import { Events, EmbedBuilder, ChannelType } from "discord.js"
import type { GuildMember } from "discord.js"
import { t } from "@/utils/i18n"
import { logConsole } from "@/utils/console"
export const name = Events.GuildMemberAdd
export async function execute(member: GuildMember) {
if (member.guild.id === "1086577543651524699") {
// Salon posé tamisé
const guild = member.guild
guild.members.fetch().then(async () => {
let i = 0
guild.members.cache.forEach(member => { if (!member.user.bot) i++ })
const channel = guild.channels.cache.get("1091140609139560508")
if (!channel) return
await channel.setName("Changement...")
await channel.setName(`${i} Gens Posés`)
}).catch(console.error)
} else if (member.guild.id === "796327643783626782") {
// Jujul Community
const guild = member.guild
if (!guild.members.me) return
const channel = guild.channels.cache.get("837248593609097237")
if (!channel || (channel.type !== ChannelType.GuildText && channel.type !== ChannelType.GuildAnnouncement)) {
logConsole('discordjs', 'guild_member_add', { channelId: '837248593609097237' })
return
}
const embed = new EmbedBuilder()
.setColor(guild.members.me.displayHexColor)
.setTitle(t(guild.preferredLocale, "welcome.title", { username: member.user.username }))
.setDescription(t(guild.preferredLocale, "welcome.description", { memberCount: guild.memberCount.toString() }))
.setThumbnail(member.user.avatarURL())
.setTimestamp(new Date())
return channel.send({ embeds: [embed] })
}
}
+22 -21
View File
@@ -1,21 +1,22 @@
import { Events, GuildMember } from 'discord.js'
export default {
name: Events.GuildMemberRemove,
async execute(member: GuildMember) {
if (member.guild.id === '1086577543651524699') { // Salon posé tamisé
let guild = member.guild
guild.members.fetch().then(() => {
let i = 0
guild.members.cache.forEach(async member => { if (!member.user.bot) i++ })
let channel = guild.channels.cache.get('1091140609139560508')
if (!channel) return
channel.setName('Changement...')
channel.setName(`${i} Gens Posés`)
}).catch(console.error)
}
}
}
import { Events } from "discord.js"
import type { GuildMember } from "discord.js"
import { t } from "@/utils/i18n"
export const name = Events.GuildMemberRemove
export function execute(member: GuildMember) {
if (member.guild.id === "1086577543651524699") {
// Salon posé tamisé
const guild = member.guild
guild.members.fetch().then(async () => {
let i = 0
guild.members.cache.forEach(member => { if (!member.user.bot) i++ })
const channel = guild.channels.cache.get("1091140609139560508")
if (!channel) return
await channel.setName(t(guild.preferredLocale, "salonpostam.update.loading"))
await channel.setName(t(guild.preferredLocale, "salonpostam.update.members_updated", { count: i.toString() }))
}).catch(console.error)
}
}
+37 -35
View File
@@ -1,35 +1,37 @@
import { Events, GuildMember, EmbedBuilder, TextChannel } from 'discord.js'
export default {
name: Events.GuildMemberUpdate,
async execute(oldMember: GuildMember, newMember: GuildMember) {
if (newMember.guild.id === '796327643783626782') { // Jujul Community
let guild = newMember.guild
let channel = guild.channels.cache.get('924353449930412153') as TextChannel
if (!channel) return console.log(`\u001b[1;31m Aucun channel trouvé avec l'id "924353449930412153" !`)
let boostRole = guild.roles.premiumSubscriberRole
if (!boostRole) return console.log(`\u001b[1;31m Aucun rôle de boost trouvé !`)
const hadRole = oldMember.roles.cache.find(role => role.id === boostRole.id)
const hasRole = newMember.roles.cache.find(role => role.id === boostRole.id)
if (!hadRole && hasRole) {
if (!guild.members.me) return console.log(`\u001b[1;31m Je ne suis pas sur le serveur !`)
let embed = new EmbedBuilder()
.setColor(guild.members.me.displayHexColor)
.setTitle(`Nouveau boost de ${newMember.user.username} !`)
.setDescription(`
Merci à toi pour ce boost.\n
Grâce à toi, on a atteint ${guild.premiumSubscriptionCount} boosts !
`)
.setThumbnail(newMember.user.avatarURL())
.setTimestamp(new Date())
await channel.send({ embeds: [embed] })
}
}
}
}
import { Events, EmbedBuilder, ChannelType } from "discord.js"
import type { GuildMember } from "discord.js"
import { t } from "@/utils/i18n"
import { logConsole } from "@/utils/console"
export const name = Events.GuildMemberUpdate
export async function execute(oldMember: GuildMember, newMember: GuildMember) {
if (newMember.guild.id === "796327643783626782") {
// Jujul Community
const guild = newMember.guild
const channel = await guild.channels.fetch("924353449930412153")
if (!channel || (channel.type !== ChannelType.GuildText && channel.type !== ChannelType.GuildAnnouncement)) {
logConsole('discordjs', 'boost.no_channel', { channelId: "924353449930412153" })
return
}
const boostRole = guild.roles.premiumSubscriberRole
if (!boostRole) { logConsole('discordjs', 'boost.no_boost_role'); return }
const hadRole = oldMember.roles.cache.find(role => role.id === boostRole.id)
const hasRole = newMember.roles.cache.find(role => role.id === boostRole.id)
if (!hadRole && hasRole) {
if (!guild.members.me) { logConsole('discordjs', 'boost.not_in_guild'); return }
const embed = new EmbedBuilder()
.setColor(guild.members.me.displayHexColor)
.setTitle(t(guild.preferredLocale, "boost.new_boost_title", { username: newMember.user.username }))
.setDescription(t(guild.preferredLocale, "boost.new_boost_description", { count: guild.premiumSubscriptionCount?.toString() ?? "0" }))
.setThumbnail(newMember.user.avatarURL())
.setTimestamp(new Date())
return channel.send({ embeds: [embed] })
}
}
}
+18 -18
View File
@@ -1,18 +1,18 @@
import { Events, Guild } from 'discord.js'
import dbGuildInit from '../../utils/dbGuildInit'
import dbGuild from '../../schemas/guild'
export default {
name: Events.GuildUpdate,
async execute(oldGuild: Guild, newGuild: Guild) {
console.log(`Guild ${oldGuild.name} updated`)
let guildProfile = await dbGuild.findOne({ guildId: newGuild.id })
if (!guildProfile) guildProfile = await dbGuildInit(newGuild)
else {
guildProfile.guildName = newGuild.name
guildProfile.guildIcon = newGuild.iconURL() ?? 'None'
await guildProfile.save().catch(console.error)
}
}
}
import { Events } from "discord.js"
import type { Guild } from "discord.js"
import dbGuildInit from "@/utils/dbGuildInit"
import dbGuild from "@/schemas/guild"
import { logConsole } from "@/utils/console"
export const name = Events.GuildUpdate
export async function execute(oldGuild: Guild, newGuild: Guild) {
logConsole('discordjs', 'guild_update', { name: oldGuild.name })
let guildProfile = await dbGuild.findOne({ guildId: newGuild.id })
if (!guildProfile) guildProfile = await dbGuildInit(newGuild)
else {
guildProfile.guildName = newGuild.name
guildProfile.guildIcon = newGuild.iconURL() ?? "None"
await guildProfile.save().catch(console.error)
}
}
+21
View File
@@ -0,0 +1,21 @@
import * as error from "./error"
import * as guildCreate from "./guildCreate"
import * as guildMemberAdd from "./guildMemberAdd"
import * as guildMemberRemove from "./guildMemberRemove"
import * as guildMemberUpdate from "./guildMemberUpdate"
import * as guildUpdate from "./guildUpdate"
import * as interactionCreate from "./interactionCreate"
import * as ready from "./ready"
import type { Event } from "@/types"
export default [
error,
guildCreate,
guildMemberAdd,
guildMemberRemove,
guildMemberUpdate,
guildUpdate,
interactionCreate,
ready
] as Event[]
+49 -45
View File
@@ -1,45 +1,49 @@
import { Events, Interaction, ChatInputCommandInteraction, AutocompleteInteraction, ButtonInteraction } from 'discord.js'
import { playerButtons, playerEdit } from '../../utils/player'
export default {
name: Events.InteractionCreate,
async execute(interaction: Interaction) {
//if (!interaction.isAutocomplete() && !interaction.isChatInputCommand() && !interaction.isButton()) return console.error(`Interaction ${interaction.commandName} is not a command.`)
if (interaction.isChatInputCommand()) {
interaction = interaction as ChatInputCommandInteraction
let chatInputCommand = interaction.client.commands.get(interaction.commandName)
if (!chatInputCommand) return console.error(`No chat input command matching ${interaction.commandName} was found.`)
console.log(`Command '${interaction.commandName}' launched by ${interaction.user.tag}`)
try { await chatInputCommand.execute(interaction) }
catch (error) { console.error(`Error executing ${interaction.commandName}:`, error) }
}
else if (interaction.isAutocomplete()) {
interaction = interaction as AutocompleteInteraction
let autoCompleteRun = interaction.client.commands.get(interaction.commandName)
if (!autoCompleteRun) return console.error(`No autoCompleteRun matching ${interaction.commandName} was found.`)
console.log(`AutoCompleteRun '${interaction.commandName}' launched by ${interaction.user.tag}`)
try { await autoCompleteRun.autocompleteRun(interaction) }
catch (error) { console.error(`Error autocompleting ${interaction.commandName}:`, error) }
}
else if (interaction.isButton()) {
interaction = interaction as ButtonInteraction
let button = interaction.client.buttons.get(interaction.customId)
if (!button) return console.error(`No button id matching ${interaction.customId} was found.`)
console.log(`Button '${interaction.customId}' clicked by ${interaction.user.tag}`)
if (playerButtons.includes(interaction.customId)) { await playerEdit(interaction) }
try { await button.execute(interaction) }
catch (error) { console.error(`Error clicking ${interaction.customId}:`, error) }
}
}
}
import { Events } from "discord.js"
import type { Interaction } from "discord.js"
import commands from "@/commands"
import buttons, { buttonFolders } from "@/buttons"
import selectMenus from "@/selectmenus"
import { playerEdit } from "@/utils/player"
import { logConsole, logConsoleError } from "@/utils/console"
export const name = Events.InteractionCreate
export async function execute(interaction: Interaction) {
if (interaction.isChatInputCommand()) {
const chatInputCommand = commands.find(cmd => cmd.data.name == interaction.commandName)
if (!chatInputCommand) { logConsole('discordjs', 'interaction_create.command_not_found', { command: interaction.commandName }); return }
logConsole('discordjs', 'interaction_create.command_launched', { command: interaction.commandName, user: interaction.user.tag })
try { await chatInputCommand.execute(interaction) }
catch (error) { logConsoleError('discordjs', 'interaction_create.command_error', { command: interaction.commandName }, error as Error) }
}
else if (interaction.isAutocomplete()) {
const autocompleteRun = commands.find(cmd => cmd.data.name == interaction.commandName)
if (!autocompleteRun?.autocompleteRun) { logConsole('discordjs', 'interaction_create.autocomplete_not_found', { command: interaction.commandName }); return }
logConsole('discordjs', 'interaction_create.autocomplete_launched', { command: interaction.commandName, user: interaction.user.tag })
try { await autocompleteRun.autocompleteRun(interaction) }
catch (error) { logConsoleError('discordjs', 'interaction_create.autocomplete_error', { command: interaction.commandName }, error as Error) }
}
else if (interaction.isButton()) {
const button = buttons.find(btn => btn.id === interaction.customId)
if (!button) { logConsole('discordjs', 'interaction_create.button_not_found', { id: interaction.customId }); return }
logConsole('discordjs', 'interaction_create.button_clicked', { id: interaction.customId, user: interaction.user.tag })
try { await button.execute(interaction) }
catch (error) { logConsoleError('discordjs', 'interaction_create.button_error', { id: interaction.customId }, error as Error) }
if (buttonFolders.find(folder => folder.name === "player" ? folder.commands.some(cmd => cmd.id === interaction.customId) : false)) await playerEdit(interaction)
}
else if (interaction.isAnySelectMenu()) {
const selectMenu = selectMenus.find(menu => menu.id === interaction.customId)
if (!selectMenu) { logConsole('discordjs', 'interaction_create.selectmenu_not_found', { id: interaction.customId }); return }
logConsole('discordjs', 'interaction_create.selectmenu_used', { id: interaction.customId, user: interaction.user.tag })
try { await selectMenu.execute(interaction) }
catch (error) { logConsoleError('discordjs', 'interaction_create.selectmenu_error', { id: interaction.customId }, error as Error) }
}
}
+139 -117
View File
@@ -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)
}
}
-61
View File
@@ -1,61 +0,0 @@
//import { Events, VoiceState } from 'discord.js'
import { Events } from 'discord.js'
export default {
name: Events.VoiceStateUpdate,
async execute() {
//async execute(oldState: VoiceState, newState: VoiceState) {
/*
let oldMute = oldState.serverMute
let newMute = newState.serverMute
let oldDeaf = oldState.serverDeaf
let newDeaf = newState.serverDeaf
let oldChannel = oldState.channelId
let newChannel = newState.channelId
console.log(oldChannel)
console.log(newChannel)
let guild = newState.guild
let member = newState.member
let channel = guild.channels.cache.get('1076215868863819848')
let angels = guild.members.cache.get('223831938346123275')
if (oldChannel !== newChannel) {
let executor = await logMoveOrKick('channel_id')
//if (!executor) channel.send(`Impossible de savoir qui a déplacé <@${member.id}> !`)
//else if (member.id === executor.id) channel.send(`<@${member.id}> s'est déplacé lui-même le con...`)
//else {
// channel.send(`<@${member.id}> a été mis en sourdine par <@${executor.id}> !`)
//}
} else if (!oldMute && newMute) {
let executor = await logMuteOrDeaf('mute')
if (!executor) channel.send(`Impossible de savoir qui a muté <@${member.id}> !`)
else if (member.id === executor.id) channel.send(`<@${member.id}> s'est muté lui-même le con...`)
else {
channel.send(`<@${member.id}> a été muté par <@${executor.id}> !`)
}
} else if (!oldDeaf && newDeaf) {
let executor = await logMuteOrDeaf('deaf')
if (!executor) channel.send(`Impossible de savoir qui a mis en sourdine <@${member.id}> !`)
else if (member.id === executor.id) channel.send(`<@${member.id}> s'est mis en sourdine lui-même le con...`)
else {
channel.send(`<@${member.id}> a été mis en sourdine par <@${executor.id}> !`)
}
}
async function logMoveOrKick() {
let auditLogs = await guild.fetchAuditLogs({ limit: 1, type: AuditLogEvent.MemberMove })
console.log(auditLogs.entries.find(entry => { return entry }))
let log = await auditLogs.entries.find(entry => { return entry.extra.channel.id === newChannel })
console.log(log)
if (!log) return undefined
let executor = await guild.members.cache.get(log.executor.id)
return executor
}
async function logMuteOrDeaf(type) {
let auditLogs = await guild.fetchAuditLogs({ limit: 1, type: AuditLogEvent.MemberUpdate })
let log = await auditLogs.entries.find(entry => { return entry.target.id === member.id && entry.changes[0].key === type && entry.changes[0].new === true })
if (!log) return undefined
let executor = await guild.members.cache.get(log.executor.id)
return executor
}
*/
}
}
+5 -7
View File
@@ -1,8 +1,6 @@
import chalk from 'chalk'
import { logConsole } from "@/utils/console"
export default {
name: 'connected',
async execute() {
console.log(chalk.green('[Mongoose] Connected to MongoDB !'))
}
}
export const name = "connected"
export function execute() {
logConsole('mongoose', 'connected')
}
+5 -7
View File
@@ -1,8 +1,6 @@
import chalk from 'chalk'
import { logConsole } from "@/utils/console"
export default {
name: 'connecting',
async execute() {
console.log(chalk.green('[Mongoose] Connecting to MongoDB...'))
}
}
export const name = "connecting"
export function execute() {
logConsole('mongoose', 'connecting')
}
+5 -7
View File
@@ -1,8 +1,6 @@
import chalk from 'chalk'
import { logConsole } from "@/utils/console"
export default {
name: 'disconnected',
async execute() {
console.log(chalk.green('[Mongoose] Disconnected from MongoDB !'))
}
}
export const name = "disconnected"
export function execute() {
logConsole('mongoose', 'disconnected')
}
+5 -7
View File
@@ -1,8 +1,6 @@
import chalk from 'chalk'
import { logConsoleError } from "@/utils/console"
export default {
name: 'error',
async execute(error: Error) {
console.log(chalk.red('[Mongoose] An error occured with the database conenction :\n' + error))
}
}
export const name = "error"
export function execute(error: Error) {
logConsoleError('mongoose', 'error', { message: error.message }, error)
}
+13
View File
@@ -0,0 +1,13 @@
import * as connected from "./connected"
import * as connecting from "./connecting"
import * as disconnected from "./disconnected"
import * as error from "./error"
import type { Event } from "@/types"
export default [
connected,
connecting,
disconnected,
error
] as Event[]
+11 -10
View File
@@ -1,10 +1,11 @@
import { GuildQueue, Track } from 'discord-player'
import { PlayerMetadata } from '../../utils/player'
export default {
name: 'audioTrackAdd',
async execute(queue: GuildQueue<PlayerMetadata>, track: Track) {
// Emitted when the player adds a single song to its queue
queue.metadata.channel.send(`Musique **${track.title}** de **${track.author}** ajoutée à la file d'attente !`)
}
}
import type { GuildQueue, Track } from "discord-player"
import type { PlayerMetadata } from "@/types/player"
import { t } from "@/utils/i18n"
export const name = "audioTrackAdd"
export async function execute(queue: GuildQueue<PlayerMetadata>, track: Track) {
// Emitted when the player adds a single song to its queue
if (!queue.metadata.channel) return
if ("send" in queue.metadata.channel) return queue.metadata.channel.send({ content: t(queue.guild.preferredLocale, "player.track_added", { title: track.title }) })
}
+10 -10
View File
@@ -1,10 +1,10 @@
import { GuildQueue, Track } from 'discord-player'
import { PlayerMetadata } from '../../utils/player'
export default {
name: 'audioTracksAdd',
async execute(queue: GuildQueue<PlayerMetadata>, track: Array<Track>) {
// Emitted when the player adds multiple songs to its queue
queue.metadata.channel.send(`Ajout de ${track.length} musiques à la file d'attente !`)
}
}
import type { GuildQueue, Track } from "discord-player"
import type { PlayerMetadata } from "@/types/player"
import { t } from "@/utils/i18n"
export const name = "audioTracksAdd"
export async function execute(queue: GuildQueue<PlayerMetadata>, track: Track[]) {
// Emitted when the player adds multiple songs to its queue
if (!queue.metadata.channel) return
if ("send" in queue.metadata.channel) return queue.metadata.channel.send({ content: t(queue.guild.preferredLocale, "player.track_added_playlist", { count: track.length.toString() }) })
}
+9 -10
View File
@@ -1,10 +1,9 @@
import { GuildQueue } from 'discord-player'
export default {
name: 'debug',
async execute(queue: GuildQueue, message: string) {
// Emitted when the player queue sends debug info
// Useful for seeing what state the current queue is at
console.log(`Player debug event: ${message}`)
}
}
import type { GuildQueue } from "discord-player"
import { logConsoleDev } from "@/utils/console"
export const name = "debug"
export function execute(queue: GuildQueue, message: string) {
// Emitted when the player queue sends debug info
// Useful for seeing what state the current queue is at
logConsoleDev('discord_player', 'debug', { message })
}
+13 -24
View File
@@ -1,24 +1,13 @@
import { GuildQueue } from 'discord-player'
import { PlayerMetadata } from '../../utils/player'
import dbGuild from '../../schemas/guild'
export default {
name: 'disconnect',
async execute(queue: GuildQueue<PlayerMetadata>) {
// Emitted when the bot leaves the voice channel
queue.metadata.channel.send("J'ai quitté le vocal !")
let guildProfile = await dbGuild.findOne({ guildId: queue.guild.id })
if (!guildProfile) return console.log(`Database data for **${queue.guild.name}** does not exist !`)
let dbData = guildProfile.get('guildPlayer.replay')
dbData['textChannelId'] = ''
dbData['voiceChannelId'] = ''
dbData['trackUrl'] = ''
dbData['progress'] = ''
guildProfile.set('guildPlayer.replay', dbData)
guildProfile.markModified('guildPlayer.replay')
return await guildProfile.save().catch(console.error)
}
}
import type { GuildQueue } from "discord-player"
import type { PlayerMetadata } from "@/types/player"
import { stopProgressSaving } from "@/utils/player"
import { t } from "@/utils/i18n"
export const name = "disconnect"
export async function execute(queue: GuildQueue<PlayerMetadata>) {
// Emitted when the bot leaves the voice channel
await stopProgressSaving(queue.guild.id, queue.player.client.user?.id ?? "")
if (!queue.metadata.channel) return
if ("send" in queue.metadata.channel) return queue.metadata.channel.send({ content: t(queue.guild.preferredLocale, "player.disconnect") })
}
+14 -11
View File
@@ -1,11 +1,14 @@
import { GuildQueue } from 'discord-player'
import { PlayerMetadata } from '../../utils/player'
export default {
name: 'emptyChannel',
async execute(queue: GuildQueue<PlayerMetadata>) {
// Emitted when the voice channel has been empty for the set threshold
// Bot will automatically leave the voice channel with this event
queue.metadata.channel.send(`Je quitte le vocal car il est vide depuis trop longtemps.`)
}
}
import type { GuildQueue } from "discord-player"
import type { PlayerMetadata } from "@/types/player"
import { stopProgressSaving } from "@/utils/player"
import { t } from "@/utils/i18n"
export const name = "emptyChannel"
export async function execute(queue: GuildQueue<PlayerMetadata>) {
// Emitted when the voice channel has been empty for the set threshold
// Bot will automatically leave the voice channel with this event
await stopProgressSaving(queue.guild.id, queue.player.client.user?.id ?? "")
if (!queue.metadata.channel) return
if ("send" in queue.metadata.channel) return queue.metadata.channel.send({ content: t(queue.guild.preferredLocale, "player.leaving_empty_channel") })
}
+13 -10
View File
@@ -1,10 +1,13 @@
import { GuildQueue } from 'discord-player'
import { PlayerMetadata } from '../../utils/player'
export default {
name: 'emptyQueue',
async execute(queue: GuildQueue<PlayerMetadata>) {
// Emitted when the player queue has finished
queue.metadata.channel.send("File d'attente vide !")
}
}
import type { GuildQueue } from "discord-player"
import type { PlayerMetadata } from "@/types/player"
import { stopProgressSaving } from "@/utils/player"
import { t } from "@/utils/i18n"
export const name = "emptyQueue"
export async function execute(queue: GuildQueue<PlayerMetadata>) {
// Emitted when the player queue has finished
await stopProgressSaving(queue.guild.id, queue.player.client.user?.id ?? "")
if (!queue.metadata.channel) return
if ("send" in queue.metadata.channel) return queue.metadata.channel.send({ content: t(queue.guild.preferredLocale, "player.queue_empty") })
}
+8 -10
View File
@@ -1,10 +1,8 @@
import { GuildQueue } from 'discord-player'
export default {
name: 'error',
async execute(queue: GuildQueue, error: Error) {
// Emitted when the player queue encounters error
console.log(`General player error event: ${error.message}`)
console.error(error)
}
}
import type { GuildQueue } from "discord-player"
import { logConsoleError } from "@/utils/console"
export const name = "error"
export function execute(queue: GuildQueue, error: Error) {
// Emitted when the player queue encounters error
logConsoleError('discord_player', 'error', { message: error.message }, error)
}
+25
View File
@@ -0,0 +1,25 @@
import * as audioTrackAdd from "./audioTrackAdd"
import * as audioTracksAdd from "./audioTracksAdd"
import * as debug from "./debug"
import * as disconnect from "./disconnect"
import * as emptyChannel from "./emptyChannel"
import * as emptyQueue from "./emptyQueue"
import * as error from "./error"
import * as playerError from "./playerError"
import * as playerSkip from "./playerSkip"
import * as playerStart from "./playerStart"
import type { Event } from "@/types"
export default [
audioTrackAdd,
audioTracksAdd,
debug,
disconnect,
emptyChannel,
emptyQueue,
error,
playerError,
playerSkip,
playerStart
] as Event[]
+8 -10
View File
@@ -1,10 +1,8 @@
import { GuildQueue } from 'discord-player'
export default {
name: 'playerError',
async execute(queue: GuildQueue, error: Error) {
// Emitted when the audio player errors while streaming audio track
console.log(`\u001b[1;31m Player error event: ${error.message}`)
console.error(error)
}
}
import type { GuildQueue } from "discord-player"
import { logConsoleError } from "@/utils/console"
export const name = "playerError"
export function execute(queue: GuildQueue, error: Error) {
// Emitted when the audio player errors while streaming audio track
logConsoleError('discord_player', 'player_error', { message: error.message }, error)
}
+12 -10
View File
@@ -1,10 +1,12 @@
import { GuildQueue, Track } from 'discord-player'
import { PlayerMetadata } from '../../utils/player'
export default {
name: 'playerSkip',
async execute(queue: GuildQueue<PlayerMetadata>, track: Track) {
// Emitted when the audio player fails to load the stream for a song
queue.metadata.channel.send(`Musique **${track.title}** de **${track.author}** passée !`)
}
}
import type { GuildQueue, Track } from "discord-player"
import type { PlayerMetadata } from "@/types/player"
import { t } from "@/utils/i18n"
export const name = "playerSkip"
export async function execute(queue: GuildQueue<PlayerMetadata>, track: Track) {
// Emitted when the audio player fails to load the stream for a song
if (!queue.metadata.channel) return
if ("send" in queue.metadata.channel) return queue.metadata.channel.send({
content: t(queue.guild.preferredLocale, "player.track_skipped", { title: track.title, author: track.author })
})
}
+10 -22
View File
@@ -1,22 +1,10 @@
import { GuildQueue, Track } from 'discord-player'
import { PlayerMetadata } from '../../utils/player'
import dbGuild from '../../schemas/guild'
export default {
name: 'playerStart',
async execute(queue: GuildQueue<PlayerMetadata>, track: Track) {
// Emitted when the player starts to play a song
queue.metadata.channel.send(`Lecture de **${track.title}** de **${track.author}** !`)
let guildProfile = await dbGuild.findOne({ guildId: queue.guild.id })
if (!guildProfile) return console.log(`Database data for **${queue.guild.name}** does not exist !`)
let dbData = guildProfile.get('guildPlayer.replay')
dbData['trackUrl'] = track.url
dbData['progress'] = '0'
guildProfile.set('guildPlayer.replay', dbData)
guildProfile.markModified('guildPlayer.replay')
return await guildProfile.save().catch(console.error)
}
}
import type { GuildQueue, Track } from "discord-player"
import type { PlayerMetadata } from "@/types/player"
import { t } from "@/utils/i18n"
export const name = "playerStart"
export async function execute(queue: GuildQueue<PlayerMetadata>, track: Track) {
// Emitted when the player starts to play a song
if (!queue.metadata.channel) return
if ("send" in queue.metadata.channel) await queue.metadata.channel.send({ content: t(queue.guild.preferredLocale, "player.now_playing", { title: track.title, author: track.author }) })
}