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:
198
src/commands/global/twitch.ts
Normal file
198
src/commands/global/twitch.ts
Normal file
@@ -0,0 +1,198 @@
|
||||
import { SlashCommandBuilder, ChannelType, MessageFlags, PermissionFlagsBits } from "discord.js"
|
||||
import type { ChatInputCommandInteraction, AutocompleteInteraction, ApplicationCommandOptionChoiceData } from "discord.js"
|
||||
import chalk from "chalk"
|
||||
import { twitchClient, listener, onlineSub, offlineSub, generateTwitchEmbed } from "@/utils/twitch"
|
||||
import type { GuildTwitch } from "@/types/schemas"
|
||||
import dbGuild from "@/schemas/guild"
|
||||
import { t } from "@/utils/i18n"
|
||||
|
||||
export const data = new SlashCommandBuilder()
|
||||
.setName("twitch")
|
||||
.setDescription("Manage streamers notifications")
|
||||
.setDescriptionLocalizations({ fr: "Gérer les notifications des streameurs" })
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild)
|
||||
.addSubcommand(subcommand => subcommand
|
||||
.setName("status")
|
||||
.setDescription("Display Twitch module status")
|
||||
.setNameLocalizations({ fr: "statut" })
|
||||
.setDescriptionLocalizations({ fr: "Afficher le statut du module Twitch" })
|
||||
)
|
||||
.addSubcommand(subcommand => subcommand
|
||||
.setName("channel")
|
||||
.setDescription("Set the channel to send notifications")
|
||||
.setNameLocalizations({ fr: "canal" })
|
||||
.setDescriptionLocalizations({ fr: "Définir le canal pour envoyer les notifications" })
|
||||
.addChannelOption(option => option
|
||||
.setName("channel")
|
||||
.setDescription("The channel to send notifications")
|
||||
.setNameLocalizations({ fr: "canal" })
|
||||
.setDescriptionLocalizations({ fr: "Le canal pour envoyer les notifications" })
|
||||
.setRequired(true)
|
||||
)
|
||||
)
|
||||
.addSubcommandGroup(subcommandgroup => subcommandgroup
|
||||
.setName("streamer")
|
||||
.setDescription("Manage streamers")
|
||||
.setNameLocalizations({ fr: "streameur" })
|
||||
.setDescriptionLocalizations({ fr: "Gérer les streameurs" })
|
||||
.addSubcommand(subcommand => subcommand
|
||||
.setName("list")
|
||||
.setDescription("List all streamers")
|
||||
.setNameLocalizations({ fr: "liste" })
|
||||
.setDescriptionLocalizations({ fr: "Lister tous les streameurs" })
|
||||
)
|
||||
.addSubcommand(subcommand => subcommand
|
||||
.setName("add")
|
||||
.setDescription("Add a streamer")
|
||||
.setNameLocalizations({ fr: "ajouter" })
|
||||
.setDescriptionLocalizations({ fr: "Ajouter un streameur" })
|
||||
.addStringOption(option => option
|
||||
.setName("username")
|
||||
.setDescription("The username of the streamer to add")
|
||||
.setNameLocalizations({ fr: "nom_utilisateur" })
|
||||
.setDescriptionLocalizations({ fr: "Le nom d'utilisateur du streameur à ajouter" })
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)
|
||||
)
|
||||
.addUserOption(option => option
|
||||
.setName("member")
|
||||
.setDescription("The member on the guild to mention")
|
||||
.setNameLocalizations({ fr: "membre" })
|
||||
.setDescriptionLocalizations({ fr: "Le membre sur le serveur à mentionner" })
|
||||
.setRequired(false)
|
||||
)
|
||||
)
|
||||
.addSubcommand(subcommand => subcommand
|
||||
.setName("remove")
|
||||
.setDescription("Remove a streamer")
|
||||
.setNameLocalizations({ fr: "supprimer" })
|
||||
.setDescriptionLocalizations({ fr: "Supprimer un streameur" })
|
||||
.addStringOption(option => option
|
||||
.setName("username")
|
||||
.setDescription("The username of the streamer to remove")
|
||||
.setNameLocalizations({ fr: "nom_utilisateur" })
|
||||
.setDescriptionLocalizations({ fr: "Le nom d'utilisateur du streameur à supprimer" })
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
export async function execute(interaction: ChatInputCommandInteraction) {
|
||||
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
|
||||
|
||||
const subcommandGroup = interaction.options.getSubcommandGroup(false)
|
||||
const subcommand = interaction.options.getSubcommand(true)
|
||||
if (subcommand == "status") {
|
||||
// Utiliser la fonction utilitaire pour générer l'embed et les composants
|
||||
const { embed, components } = generateTwitchEmbed(dbData, interaction.client, interaction.guild?.id ?? "", interaction.locale)
|
||||
|
||||
return interaction.reply({ embeds: [embed], components: components, flags: MessageFlags.Ephemeral })
|
||||
}
|
||||
|
||||
if (!dbData.enabled) return interaction.reply({ content: t(interaction.locale, "twitch.module_disabled_activate"), flags: MessageFlags.Ephemeral })
|
||||
|
||||
if (subcommand == "channel") {
|
||||
const channel = interaction.options.getChannel("channel", true)
|
||||
if (channel.type !== ChannelType.GuildText && channel.type !== ChannelType.GuildAnnouncement)
|
||||
return interaction.reply({ content: t(interaction.locale, "common.invalid_text_channel"), flags: MessageFlags.Ephemeral })
|
||||
|
||||
dbData.channelId = channel.id
|
||||
guildProfile.set("guildTwitch", dbData)
|
||||
guildProfile.markModified("guildTwitch")
|
||||
await guildProfile.save().catch(console.error)
|
||||
|
||||
return interaction.reply({ content: t(interaction.locale, "twitch.notifications_channel_set", { channel: channel.name ?? channel.id }), flags: MessageFlags.Ephemeral })
|
||||
}
|
||||
else if (subcommandGroup == "streamer") {
|
||||
if (!dbData.channelId) return interaction.reply({ content: t(interaction.locale, "twitch.configure_channel_first"), flags: MessageFlags.Ephemeral })
|
||||
|
||||
if (subcommand == "list") {
|
||||
if (!dbData.streamers.length) return interaction.reply({ content: t(interaction.locale, "twitch.no_streamers_list"), flags: MessageFlags.Ephemeral })
|
||||
|
||||
const streamers = [] as string[]
|
||||
await Promise.all(dbData.streamers.map(async streamer => {
|
||||
try {
|
||||
const user = await twitchClient.users.getUserById(streamer.twitchUserId)
|
||||
if (user) streamers.push(`- ${user.displayName} (${streamer.twitchUserId})`)
|
||||
else streamers.push(`- ${t(interaction.locale, "twitch.user_not_found_id", { id: streamer.twitchUserId })}`)
|
||||
} catch (error) {
|
||||
console.log(chalk.magenta(`[Twitch] Error fetching user for ID ${streamer.twitchUserId}`))
|
||||
console.error(error)
|
||||
}
|
||||
}))
|
||||
const streamerList = streamers.length > 0 ? streamers.join("\n") : t(interaction.locale, "twitch.no_streamers")
|
||||
|
||||
return interaction.reply({ content: `${t(interaction.locale, "twitch.list.title")}:\n${streamerList}`, flags: MessageFlags.Ephemeral })
|
||||
}
|
||||
else if (subcommand == "add") {
|
||||
const username = interaction.options.getString("username", true)
|
||||
const member = interaction.options.getUser("member", false)
|
||||
|
||||
const user = await twitchClient.users.getUserByName(username)
|
||||
if (!user) return interaction.reply({ content: t(interaction.locale, "twitch.streamer_not_found", { username }), flags: MessageFlags.Ephemeral })
|
||||
|
||||
if (dbData.streamers.some(s => s.twitchUserId === user.id)) return interaction.reply({ content: t(interaction.locale, "twitch.streamer_already_added", { username }), flags: MessageFlags.Ephemeral })
|
||||
dbData.streamers.push({ twitchUserId: user.id, discordUserId: member?.id ?? "", messageId: "" })
|
||||
|
||||
guildProfile.set("guildTwitch", dbData)
|
||||
guildProfile.markModified("guildTwitch")
|
||||
await guildProfile.save().catch(console.error)
|
||||
|
||||
const userSubs = await twitchClient.eventSub.getSubscriptionsForUser(user.id)
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
if (!userSubs.data.find(sub => sub.transportMethod === "webhook" && sub.type === "stream.online")) listener.onStreamOnline(user.id, onlineSub)
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
if (!userSubs.data.find(sub => sub.transportMethod === "webhook" && sub.type === "stream.offline")) listener.onStreamOffline(user.id, offlineSub)
|
||||
|
||||
return interaction.reply({ content: t(interaction.locale, "twitch.streamer_added", { username, id: user.id }), flags: MessageFlags.Ephemeral })
|
||||
}
|
||||
else if (subcommand == "remove") {
|
||||
const username = interaction.options.getString("username", true)
|
||||
|
||||
const user = await twitchClient.users.getUserByName(username)
|
||||
if (!user) return interaction.reply({ content: t(interaction.locale, "twitch.streamer_not_found", { username }), flags: MessageFlags.Ephemeral })
|
||||
|
||||
const streamerIndex = dbData.streamers.findIndex(s => s.twitchUserId === user.id)
|
||||
if (streamerIndex === -1)return interaction.reply({ content: t(interaction.locale, "twitch.streamer_not_in_list", { username }), flags: MessageFlags.Ephemeral })
|
||||
|
||||
dbData.streamers.splice(streamerIndex, 1)
|
||||
guildProfile.set("guildTwitch", dbData)
|
||||
guildProfile.markModified("guildTwitch")
|
||||
await guildProfile.save().catch(console.error)
|
||||
|
||||
if (!await dbGuild.exists({ "guildTwitch.streamers.twitchUserId": user.id })) {
|
||||
const userSubs = await twitchClient.eventSub.getSubscriptionsForUser(user.id)
|
||||
await Promise.all(userSubs.data.map(async sub => { if (sub.transportMethod === "webhook" && (sub.type === "stream.online" || sub.type === "stream.offline")) await sub.unsubscribe() }))
|
||||
console.log(chalk.magenta(`[Twitch] Listener removed for ${user.displayName} (ID ${user.id})`))
|
||||
}
|
||||
|
||||
return interaction.reply({ content: t(interaction.locale, "twitch.streamer_removed", { username }), flags: MessageFlags.Ephemeral })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function autocompleteRun(interaction: AutocompleteInteraction) {
|
||||
const query = interaction.options.getString("username", true)
|
||||
if (!query || query.length < 3) return interaction.respond([])
|
||||
|
||||
const guildProfile = await dbGuild.findOne({ guildId: interaction.guild?.id })
|
||||
if (!guildProfile) return interaction.respond([])
|
||||
|
||||
const dbData = guildProfile.get("guildTwitch") as GuildTwitch
|
||||
if (!dbData.enabled) return interaction.respond([])
|
||||
|
||||
const choices: ApplicationCommandOptionChoiceData[] = []
|
||||
const searchResult = await twitchClient.search.searchChannels(query)
|
||||
if (searchResult.data.length === 0) return interaction.respond([])
|
||||
|
||||
searchResult.data.forEach(streamerResult => {
|
||||
if (dbData.streamers.some(s => s.twitchUserId === streamerResult.id)) return
|
||||
choices.push({ name: streamerResult.displayName, value: streamerResult.name })
|
||||
})
|
||||
|
||||
return interaction.respond(choices)
|
||||
}
|
||||
Reference in New Issue
Block a user