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

This commit is contained in:
2025-06-09 16:29:12 +02:00
parent f2c6388da6
commit ddd617317c
133 changed files with 8092 additions and 4332 deletions

View File

@@ -0,0 +1,19 @@
import { MessageFlags, ChannelType, ActionRowBuilder, ChannelSelectMenuBuilder } from "discord.js"
import type { ButtonInteraction } from "discord.js"
import { t } from "@/utils/i18n"
export const id = "twitch_channel"
export async function execute(interaction: ButtonInteraction) {
const channelSelect = new ChannelSelectMenuBuilder()
.setCustomId("twitch_channel")
.setPlaceholder(t(interaction.locale, "twitch.select_notification_channel_placeholder"))
.addChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement)
const row = new ActionRowBuilder<ChannelSelectMenuBuilder>().addComponents(channelSelect)
return interaction.reply({
content: t(interaction.locale, "twitch.select_notification_channel"),
components: [row],
flags: MessageFlags.Ephemeral
})
}

View File

@@ -0,0 +1,28 @@
import { MessageFlags } from "discord.js"
import type { ButtonInteraction } from "discord.js"
import { generateTwitchEmbed } from "@/utils/twitch"
import type { GuildTwitch } from "@/types/schemas"
import dbGuild from "@/schemas/guild"
import { t } from "@/utils/i18n"
export const id = "twitch_disable"
export async function execute(interaction: ButtonInteraction) {
const guildProfile = await dbGuild.findOne({ guildId: interaction.guild?.id })
if (!guildProfile) return interaction.reply({ content: t(interaction.locale, "common.database_not_found"), flags: MessageFlags.Ephemeral })
const dbData = guildProfile.get("guildTwitch") as GuildTwitch
dbData.enabled = false
dbData.botId = ""
guildProfile.set("guildTwitch", dbData)
guildProfile.markModified("guildTwitch")
await guildProfile.save().catch(console.error)
// Utiliser la fonction utilitaire pour générer l'embed et les composants mis à jour
const { embed, components } = generateTwitchEmbed(dbData, interaction.client, interaction.guild?.id ?? "", interaction.locale)
return interaction.update({
embeds: [embed],
components: components
})
}

View File

@@ -0,0 +1,28 @@
import { MessageFlags } from "discord.js"
import type { ButtonInteraction } from "discord.js"
import { generateTwitchEmbed } from "@/utils/twitch"
import type { GuildTwitch } from "@/types/schemas"
import dbGuild from "@/schemas/guild"
import { t } from "@/utils/i18n"
export const id = "twitch_enable"
export async function execute(interaction: ButtonInteraction) {
const guildProfile = await dbGuild.findOne({ guildId: interaction.guild?.id })
if (!guildProfile) return interaction.reply({ content: t(interaction.locale, "common.database_not_found"), flags: MessageFlags.Ephemeral })
const dbData = guildProfile.get("guildTwitch") as GuildTwitch
dbData.enabled = true
dbData.botId = interaction.client.user.id
guildProfile.set("guildTwitch", dbData)
guildProfile.markModified("guildTwitch")
await guildProfile.save().catch(console.error)
// Utiliser la fonction utilitaire pour générer l'embed et les composants mis à jour
const { embed, components } = generateTwitchEmbed(dbData, interaction.client, interaction.guild?.id ?? "", interaction.locale)
return interaction.update({
embeds: [embed],
components: components
})
}

View File

@@ -0,0 +1,17 @@
import * as twitch_disable from "./disable"
import * as twitch_enable from "./enable"
import * as twitch_set_channel from "./channel"
import * as twitch_list_streamers from "./streamer_list"
import * as twitch_add_streamer from "./streamer_add"
import * as twitch_remove_streamer from "./streamer_remove"
import type { Button } from "@/types"
export default [
twitch_disable,
twitch_enable,
twitch_set_channel,
twitch_list_streamers,
twitch_add_streamer,
twitch_remove_streamer
] as Button[]

View File

@@ -0,0 +1,20 @@
import { MessageFlags } from "discord.js"
import type { ButtonInteraction } from "discord.js"
import type { GuildTwitch } from "@/types/schemas"
import dbGuild from "@/schemas/guild"
import { t } from "@/utils/i18n"
export const id = "twitch_streamer_add"
export async function execute(interaction: ButtonInteraction) {
const guildProfile = await dbGuild.findOne({ guildId: interaction.guild?.id })
if (!guildProfile) return interaction.reply({ content: t(interaction.locale, "common.database_not_found"), flags: MessageFlags.Ephemeral })
const dbData = guildProfile.get("guildTwitch") as GuildTwitch
if (!dbData.enabled) return interaction.reply({ content: t(interaction.locale, "twitch.module_disabled"), flags: MessageFlags.Ephemeral })
if (!dbData.channelId) return interaction.reply({ content: t(interaction.locale, "twitch.configure_channel_first"), flags: MessageFlags.Ephemeral })
return interaction.reply({
content: t(interaction.locale, "twitch.add_streamer_command"),
flags: MessageFlags.Ephemeral
})
}

View File

@@ -0,0 +1,51 @@
import { MessageFlags, EmbedBuilder } from "discord.js"
import type { ButtonInteraction } from "discord.js"
import type { GuildTwitch } from "@/types/schemas"
import dbGuild from "@/schemas/guild"
import { twitchClient } from "@/utils/twitch"
import { t } from "@/utils/i18n"
import { logConsole } from "@/utils/console"
export const id = "twitch_streamer_list"
export async function execute(interaction: ButtonInteraction) {
const guildProfile = await dbGuild.findOne({ guildId: interaction.guild?.id })
if (!guildProfile) return interaction.reply({ content: t(interaction.locale, "common.database_not_found"), flags: MessageFlags.Ephemeral })
const dbData = guildProfile.get("guildTwitch") as GuildTwitch
if (!dbData.enabled) return interaction.reply({ content: t(interaction.locale, "twitch.module_disabled"), flags: MessageFlags.Ephemeral })
if (!dbData.streamers.length) {
const embed = new EmbedBuilder()
.setTitle(t(interaction.locale, "twitch.list.title"))
.setDescription(t(interaction.locale, "twitch.list.empty_description"))
.setColor(0x808080)
.setTimestamp()
return interaction.reply({ embeds: [embed], flags: MessageFlags.Ephemeral })
}
const streamers = [] as string[]
await Promise.all(dbData.streamers.map(async (streamer, index) => {
try {
const user = await twitchClient.users.getUserById(streamer.twitchUserId)
if (user) {
const discordUser = streamer.discordUserId ? `<@${streamer.discordUserId}>` : t(interaction.locale, "twitch.list.discord_not_associated")
streamers.push(`**${index + 1}.** ${user.displayName}\n└ Discord: ${discordUser}\n└ ID: \`${streamer.twitchUserId}\``)
} else {
streamers.push(`**${index + 1}.** ${t(interaction.locale, "twitch.list.user_not_found")}\n└ ID: \`${streamer.twitchUserId}\``)
}
} catch (error) {
logConsole('twitch', 'user_fetch_error_buttons', { id: streamer.twitchUserId })
console.error(error)
streamers.push(`**${index + 1}.** ${t(interaction.locale, "twitch.list.fetch_error")}\n└ ID: \`${streamer.twitchUserId}\``)
}
}))
const embed = new EmbedBuilder()
.setTitle(t(interaction.locale, "twitch.list.title"))
.setDescription(streamers.join("\n\n"))
.setColor(0x9146FF)
.setFooter({ text: t(interaction.locale, "twitch.list.footer", { count: streamers.length.toString() }) })
.setTimestamp()
return interaction.reply({ embeds: [embed], flags: MessageFlags.Ephemeral })
}

View File

@@ -0,0 +1,46 @@
import { MessageFlags, ActionRowBuilder, StringSelectMenuBuilder } from "discord.js"
import type { ButtonInteraction } from "discord.js"
import { twitchClient } from "@/utils/twitch"
import type { GuildTwitch } from "@/types/schemas"
import dbGuild from "@/schemas/guild"
import { t } from "@/utils/i18n"
import { logConsole } from "@/utils/console"
export const id = "twitch_streamer_remove"
export async function execute(interaction: ButtonInteraction) {
const guildProfile = await dbGuild.findOne({ guildId: interaction.guild?.id })
if (!guildProfile) return interaction.reply({ content: t(interaction.locale, "common.database_not_found"), flags: MessageFlags.Ephemeral })
const dbData = guildProfile.get("guildTwitch") as GuildTwitch
if (!dbData.enabled) return interaction.reply({ content: t(interaction.locale, "twitch.module_disabled"), flags: MessageFlags.Ephemeral })
if (!dbData.streamers.length) return interaction.reply({ content: t(interaction.locale, "twitch.no_streamers_list"), flags: MessageFlags.Ephemeral })
// Créer la liste des streamers dans un menu de sélection
const options = await Promise.all(dbData.streamers.map(async (streamer) => {
try {
const user = await twitchClient.users.getUserById(streamer.twitchUserId)
return {
label: user ? user.displayName : `ID: ${streamer.twitchUserId}`,
value: streamer.twitchUserId,
description: user ? `@${user.name}` : t(interaction.locale, "twitch.user_not_found")
}
} catch (error) {
logConsole('twitch', 'user_fetch_error_buttons', { id: streamer.twitchUserId })
console.error(error)
return {
label: `ID: ${streamer.twitchUserId}`,
value: streamer.twitchUserId,
description: t(interaction.locale, "twitch.fetch_error")
}
}
}))
const selectMenu = new StringSelectMenuBuilder()
.setCustomId("twitch_streamer_remove")
.setPlaceholder(t(interaction.locale, "twitch.select_streamer_to_remove"))
.addOptions(options.slice(0, 25)) // Discord limite à 25 options
const row = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(selectMenu)
return interaction.reply({ content: t(interaction.locale, "twitch.select_streamer_prompt"), components: [row], flags: MessageFlags.Ephemeral })
}