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:
		
							
								
								
									
										60
									
								
								src/commands/player/disco.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/commands/player/disco.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| import { SlashCommandBuilder, PermissionFlagsBits, MessageFlags, ChannelType } from "discord.js" | ||||
| import type { ChatInputCommandInteraction } from "discord.js" | ||||
| import { generateDiscoEmbed } from "@/utils/player" | ||||
| import type { Disco } from "@/types/schemas" | ||||
| import dbGuild from "@/schemas/guild" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("disco") | ||||
| 	.setDescription("Manage the Disco module") | ||||
| 	.setDescriptionLocalizations({ fr: "Gérer le module Disco" }) | ||||
| 	.setDefaultMemberPermissions(PermissionFlagsBits.ManageGuild) | ||||
| 	.addSubcommand(subcommand => subcommand | ||||
| 		.setName("status") | ||||
| 		.setDescription("Display Disco mode status") | ||||
| 		.setNameLocalizations({ fr: "statut" }) | ||||
| 		.setDescriptionLocalizations({ fr: "Afficher le statut du mode Disco" }) | ||||
| 	) | ||||
| 	.addSubcommand(subcommand => subcommand | ||||
| 		.setName("channel") | ||||
| 		.setDescription("Configure the channel for Disco effects") | ||||
| 		.setNameLocalizations({ fr: "canal" }) | ||||
| 		.setDescriptionLocalizations({ fr: "Configurer le canal pour les effets Disco" }) | ||||
| 		.addChannelOption(option => option | ||||
| 			.setName("channel") | ||||
| 			.setDescription("The channel where to apply Disco effects") | ||||
| 			.setNameLocalizations({ fr: "canal" }) | ||||
| 			.setDescriptionLocalizations({ fr: "Le canal où appliquer les effets Disco" }) | ||||
| 			.setRequired(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("guildPlayer.disco") as Disco | ||||
|  | ||||
| 	const subcommand = interaction.options.getSubcommand(true) | ||||
| 	if (subcommand === "status") { | ||||
| 		const { embed, components } = generateDiscoEmbed(dbData, interaction.client, interaction.guild?.id ?? "", interaction.locale) | ||||
|  | ||||
| 		return interaction.reply({ embeds: [embed], components: components, flags: MessageFlags.Ephemeral }) | ||||
| 	} | ||||
| 	else 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_channel_type"), | ||||
| 			flags: MessageFlags.Ephemeral | ||||
| 		}) | ||||
|  | ||||
| 		dbData.channelId = channel.id | ||||
|  | ||||
| 		guildProfile.set("guildPlayer.disco", dbData) | ||||
| 		guildProfile.markModified("guildPlayer.disco") | ||||
| 		await guildProfile.save().catch(console.error) | ||||
|  | ||||
| 		return interaction.reply({ content: t(interaction.locale, "player.disco.channel_configured_success", { channel: channel.name ?? "Inconnu" }), flags: MessageFlags.Ephemeral }) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										31
									
								
								src/commands/player/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/commands/player/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| import * as disco from "./disco" | ||||
| import * as loop from "./loop" | ||||
| import * as lyrics from "./lyrics" | ||||
| import * as panel from "./panel" | ||||
| import * as pause from "./pause" | ||||
| import * as play from "./play" | ||||
| import * as previous from "./previous" | ||||
| import * as queue from "./queue" | ||||
| import * as resume from "./resume" | ||||
| import * as shuffle from "./shuffle" | ||||
| import * as skip from "./skip" | ||||
| import * as stop from "./stop" | ||||
| import * as volume from "./volume" | ||||
|  | ||||
| import type { Command } from "@/types" | ||||
|  | ||||
| export default [ | ||||
| 	disco, | ||||
| 	loop, | ||||
| 	lyrics, | ||||
| 	panel, | ||||
| 	pause, | ||||
| 	play, | ||||
| 	previous, | ||||
| 	queue, | ||||
| 	resume, | ||||
| 	shuffle, | ||||
| 	skip, | ||||
| 	stop, | ||||
| 	volume | ||||
| ] as Command[] | ||||
| @@ -1,21 +1,29 @@ | ||||
| import { ChatInputCommandInteraction, SlashCommandBuilder } from 'discord.js' | ||||
| import { useQueue } from'discord-player' | ||||
|  | ||||
| export default { | ||||
| 	data: new SlashCommandBuilder() | ||||
| 		.setName('loop') | ||||
| 		.setDescription('Boucler la musique en cours de lecture.') | ||||
| 		.addIntegerOption(option => option.setName('loop') | ||||
| 			.setDescription('Mode de boucle (0 = Off, 1 = Titre, 2 = File d\'Attente; 3 = Autoplay)') | ||||
| 			.setRequired(true) | ||||
| 			.setMinValue(0) | ||||
| 			.setMaxValue(3)), | ||||
| 	async execute(interaction: ChatInputCommandInteraction) { | ||||
| 		let loop = interaction.options.getInteger('loop') | ||||
| 		let queue = useQueue(interaction.guild?.id ?? '') | ||||
| 		if (!queue) return interaction.followUp({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' }) | ||||
| 		 | ||||
| 		queue.setRepeatMode(loop as number) | ||||
| 		return await interaction.reply(`Boucle ${loop === 0 ? 'désactivée' : loop === 1 ? 'en mode Titre' : loop === 2 ? 'en mode File d\'Attente' : 'en autoplay'}.`) | ||||
| 	} | ||||
| } | ||||
| import { SlashCommandBuilder } from "discord.js" | ||||
| import type { ChatInputCommandInteraction } from "discord.js" | ||||
| import { useQueue } from "discord-player" | ||||
| import type { QueueRepeatMode } from "discord-player" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("loop") | ||||
| 	.setDescription("Loop the current music") | ||||
| 	.setNameLocalizations({ fr: "boucle" }) | ||||
| 	.setDescriptionLocalizations({ fr: "Boucler la musique en cours de lecture" }) | ||||
| 	.addIntegerOption(option => option | ||||
| 		.setName("mode") | ||||
| 		.setDescription("Loop mode (0 = Off | 1 = Track | 2 = Queue | 3 = Autoplay)") | ||||
| 		.setDescriptionLocalizations({ fr: "Mode de boucle (0 = Arrêt | 1 = Titre | 2 = File d'Attente | 3 = Autoplay)" }) | ||||
| 		.setRequired(true) | ||||
| 		.setMinValue(0) | ||||
| 		.setMaxValue(3) | ||||
| 	) | ||||
|  | ||||
| export async function execute(interaction: ChatInputCommandInteraction) { | ||||
| 	const mode = interaction.options.getInteger("mode", true) | ||||
| 	const queue = useQueue(interaction.guild?.id ?? "") | ||||
| 	if (!queue) return interaction.followUp({ content: t(interaction.locale, "player.no_queue") }) | ||||
|  | ||||
| 	queue.setRepeatMode(mode as QueueRepeatMode) | ||||
|  | ||||
| 	return interaction.reply(t(interaction.locale, mode === 0 ? "player.loop_off" : mode === 1 ? "player.loop_track" : mode === 2 ? "player.loop_queue" : "player.loop_autoplay")) | ||||
| } | ||||
|   | ||||
| @@ -1,45 +1,61 @@ | ||||
| import { ChatInputCommandInteraction, SlashCommandBuilder, EmbedBuilder } from 'discord.js' | ||||
| import { useQueue } from 'discord-player' | ||||
| import { lyricsExtractor } from '@discord-player/extractor' | ||||
|  | ||||
| export default { | ||||
| 	data: new SlashCommandBuilder() | ||||
| 		.setName('lyrics') | ||||
| 		.setDescription('Rechercher les paroles d\'une musique.') | ||||
| 		.addStringOption(option => option.setName('recherche').setDescription('Chercher une musique spécifique')), | ||||
| 	async execute(interaction: ChatInputCommandInteraction) { | ||||
| 		await interaction.deferReply() | ||||
|  | ||||
| 		let query = interaction.options.getString('recherche', false) | ||||
| 		if (!query) { | ||||
| 			let queue = useQueue(interaction.guild?.id ?? '') | ||||
| 			if (!queue) return interaction.followUp({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' }) | ||||
| 			let track = queue.currentTrack | ||||
| 			if (!track) return interaction.followUp({ content: 'Aucune musique en cours, recherche en une plutôt !' }) | ||||
| 			 | ||||
| 			if (track.raw.source === 'spotify') query = `${track.author} ${track.title}` | ||||
| 			else query = track.title | ||||
| 		} | ||||
|  | ||||
| 		let lyricsFinder = lyricsExtractor() | ||||
|  | ||||
| 		let lyrics = await lyricsFinder.search(query).catch(() => null) | ||||
| 		if (!lyrics) return interaction.followUp({ content: 'Pas de paroles trouvées !' }) | ||||
|  | ||||
| 		let trimmedLyrics = lyrics.lyrics.substring(0, 1997) | ||||
|  | ||||
| 		let embed = new EmbedBuilder() | ||||
| 			.setColor('#ffc370') | ||||
| 			.setTitle(lyrics.title) | ||||
| 			.setURL(lyrics.url) | ||||
| 			.setThumbnail(lyrics.thumbnail) | ||||
| 			.setAuthor({ | ||||
| 				name: lyrics.artist.name, | ||||
| 				iconURL: lyrics.artist.image, | ||||
| 				url: lyrics.artist.url | ||||
| 			}) | ||||
| 			.setDescription(trimmedLyrics.length === 1997 ? `${trimmedLyrics}...` : trimmedLyrics) | ||||
|  | ||||
| 		return interaction.followUp({ embeds: [embed] }) | ||||
| 	} | ||||
| } | ||||
| import { SlashCommandBuilder, EmbedBuilder, MessageFlags } from "discord.js" | ||||
| import type { ChatInputCommandInteraction } from "discord.js" | ||||
| import { useQueue, useMainPlayer } from "discord-player" | ||||
| import type { LrcSearchResult } from "discord-player" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("lyrics") | ||||
| 	.setDescription("Search for song lyrics") | ||||
| 	.setNameLocalizations({ fr: "paroles" }) | ||||
| 	.setDescriptionLocalizations({ fr: "Rechercher les paroles d'une musique" }) | ||||
| 	.addStringOption(option => option | ||||
| 		.setName("search") | ||||
| 		.setDescription("Search for a specific song") | ||||
| 		.setNameLocalizations({ fr: "recherche" }) | ||||
| 		.setDescriptionLocalizations({ fr: "Chercher une musique spécifique" }) | ||||
| 	) | ||||
|  | ||||
| export async function execute(interaction: ChatInputCommandInteraction) { | ||||
| 	await interaction.deferReply() | ||||
|  | ||||
| 	const player = useMainPlayer() | ||||
| 	const embed = new EmbedBuilder().setColor("#ffff64").setFooter({ text: "Powered by Genius" }) | ||||
| 	let lyrics = [] as LrcSearchResult[] | ||||
|  | ||||
| 	const query = interaction.options.getString("search", false) | ||||
| 	if (!query) { | ||||
| 		const queue = useQueue(interaction.guild?.id ?? "") | ||||
| 		if (!queue) return interaction.followUp({ content: t(interaction.locale, "player.no_queue"), flags: MessageFlags.Ephemeral }) | ||||
|  | ||||
| 		const track = queue.currentTrack | ||||
| 		if (!track) return interaction.followUp({ content: t(interaction.locale, "player.no_current_track"), flags: MessageFlags.Ephemeral }) | ||||
|  | ||||
| 		lyrics = await player.lyrics.search({ trackName: track.title, artistName: track.author }) | ||||
|  | ||||
| 		if (!lyrics.length) return interaction.followUp({ content: t(interaction.locale, "player.no_lyrics_found"), flags: MessageFlags.Ephemeral }) | ||||
| 		const trimmedLyrics = lyrics[0].plainLyrics.substring(0, 1997) | ||||
|  | ||||
| 		embed | ||||
| 			.setTitle(track.title) | ||||
| 			.setURL(track.url) | ||||
| 			.setDescription(trimmedLyrics.length === 1997 ? `${trimmedLyrics}...` : trimmedLyrics) | ||||
| 			.setThumbnail(track.thumbnail) | ||||
| 			.setAuthor({ name: track.author, url: `https://genius.com/search?q=${track.author.replace(/ /g, "-")}` }) | ||||
| 	} | ||||
| 	else { | ||||
| 		lyrics = await player.lyrics.search({ q: query }) | ||||
|  | ||||
| 		if (!lyrics.length) return interaction.followUp({ content: t(interaction.locale, "player.no_lyrics_found"), flags: MessageFlags.Ephemeral }) | ||||
| 		const trimmedLyrics = lyrics[0].plainLyrics.substring(0, 1997) | ||||
|  | ||||
| 		embed | ||||
| 			.setTitle(lyrics[0].name) | ||||
| 			.setURL(`https://genius.com/search?q=${query.replace(/ /g, "%20")}`) | ||||
| 			.setDescription(trimmedLyrics.length === 1997 ? `${trimmedLyrics}...` : trimmedLyrics) | ||||
| 			.setThumbnail("https://play-lh.googleusercontent.com/e6-dZlTM-gJ2sFxFFs3X15O84HEv6jc9PQGgHtVTn7FP6lUXeEAkDl9v4RfVOwbSuQ") | ||||
| 			.setAuthor({ name: lyrics[0].artistName, url: `https://genius.com/search?q=${lyrics[0].artistName.replace(/ /g, "-")}` }) | ||||
| 	} | ||||
|  | ||||
| 	return interaction.followUp({ embeds: [embed] }) | ||||
| } | ||||
|   | ||||
| @@ -1,25 +1,26 @@ | ||||
| import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js' | ||||
| import { playerGenerate } from '../../utils/player' | ||||
| import getUptime from '../../utils/getUptime' | ||||
| import { useQueue } from 'discord-player' | ||||
|  | ||||
| export default { | ||||
| 	data: new SlashCommandBuilder() | ||||
| 		.setName('panel') | ||||
| 		.setDescription('Générer les infos de la lecture en cours.'), | ||||
| 	async execute(interaction: ChatInputCommandInteraction) { | ||||
| 		let queue = useQueue(interaction.guild?.id ?? '') | ||||
| 		if (!queue) return interaction.followUp({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' }) | ||||
| 		 | ||||
| 		let guild = interaction.guild | ||||
| 		if (!guild) return await interaction.reply({ content: 'Cette commande n\'est pas disponible en message privé.', ephemeral: true }) | ||||
|  | ||||
| 		let client = guild.client | ||||
| 		 | ||||
| 		let { embed, components } = await playerGenerate(guild) | ||||
| 		if (components && embed.data.footer) embed.setFooter({ text: `Uptime: ${getUptime(client.uptime)} \n ${embed.data.footer.text}` }) | ||||
| 		else embed.setFooter({ text: `Uptime: ${getUptime(client.uptime)}` }) | ||||
|  | ||||
| 		return interaction.reply({ embeds: [embed] }) | ||||
| 	} | ||||
| } | ||||
| import { SlashCommandBuilder, MessageFlags } from "discord.js" | ||||
| import type { ChatInputCommandInteraction } from "discord.js" | ||||
| import { useQueue } from "discord-player" | ||||
| import { generatePlayerEmbed } from "@/utils/player" | ||||
| import uptime from "@/utils/uptime" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("panel") | ||||
| 	.setDescription("Generate current playback info") | ||||
| 	.setNameLocalizations({ fr: "panneau" }) | ||||
| 	.setDescriptionLocalizations({ fr: "Générer les infos de la lecture en cours" }) | ||||
|  | ||||
| export async function execute(interaction: ChatInputCommandInteraction) { | ||||
| 	const queue = useQueue(interaction.guild?.id ?? "") | ||||
| 	if (!queue) return interaction.followUp({ content: t(interaction.locale, "player.no_queue"), flags: MessageFlags.Ephemeral }) | ||||
|  | ||||
| 	const guild = interaction.guild | ||||
| 	if (!guild) return interaction.reply({ content: t(interaction.locale, "common.private_message_not_available"), flags: MessageFlags.Ephemeral }) | ||||
|  | ||||
| 	const { embed, components } = generatePlayerEmbed(guild, interaction.locale) | ||||
| 	if (components && embed.data.footer) embed.setFooter({ text: `${t(interaction.locale, "player.uptime")}: ${uptime(guild.client.uptime)} \n ${embed.data.footer.text}` }) | ||||
| 	else embed.setFooter({ text: `${t(interaction.locale, "player.uptime")}: ${uptime(guild.client.uptime)}` }) | ||||
|  | ||||
| 	return interaction.reply({ embeds: [embed] }) | ||||
| } | ||||
|   | ||||
| @@ -1,15 +1,17 @@ | ||||
| import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js' | ||||
| import { useQueue } from 'discord-player' | ||||
|  | ||||
| export default { | ||||
| 	data: new SlashCommandBuilder() | ||||
| 		.setName('pause') | ||||
| 		.setDescription('Met en pause la musique.'), | ||||
| 	async execute(interaction: ChatInputCommandInteraction) { | ||||
| 		let queue = useQueue(interaction.guild?.id ?? '') | ||||
| 		if (!queue) return interaction.followUp({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' }) | ||||
| 		 | ||||
| 		queue.node.setPaused(!queue.node.isPaused()) | ||||
| 		return await interaction.reply('Musique mise en pause !') | ||||
| 	} | ||||
| import { SlashCommandBuilder, MessageFlags } from "discord.js" | ||||
| import type { ChatInputCommandInteraction } from "discord.js" | ||||
| import { useQueue } from "discord-player" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("pause") | ||||
| 	.setDescription("Pause the music") | ||||
| 	.setDescriptionLocalizations({ fr: "Met en pause la musique" }) | ||||
|  | ||||
| export const execute = async (interaction: ChatInputCommandInteraction) => { | ||||
| 	const queue = useQueue(interaction.guild?.id ?? "") | ||||
| 	if (!queue) return interaction.followUp({ content: t(interaction.locale, "player.no_queue_search_instead"), flags: MessageFlags.Ephemeral }) | ||||
|  | ||||
| 	queue.node.setPaused(!queue.node.isPaused()) | ||||
| 	return interaction.reply(t(interaction.locale, "player.paused")) | ||||
| } | ||||
| @@ -1,96 +1,123 @@ | ||||
| import { SlashCommandBuilder, ChatInputCommandInteraction, AutocompleteInteraction, GuildMember } from 'discord.js' | ||||
| import { useMainPlayer, useQueue, QueryType } from 'discord-player' | ||||
| import dbGuild from '../../schemas/guild' | ||||
|  | ||||
| interface TrackSearchResult { name: string, value: string } | ||||
|  | ||||
| export default { | ||||
| 	data: new SlashCommandBuilder() | ||||
| 		.setName('play') | ||||
| 		.setDescription('Jouer une musique.') | ||||
| 		.addStringOption(option => option.setName('recherche').setDescription('Titre de la musique à chercher').setRequired(true).setAutocomplete(true)), | ||||
| 	async autocompleteRun(interaction: AutocompleteInteraction) { | ||||
| 		let query = interaction.options.getString('recherche', true) | ||||
| 		if (!query) return interaction.respond([]) | ||||
|  | ||||
| 		let player = useMainPlayer() | ||||
|  | ||||
| 		const resultsYouTube = await player.search(query, { searchEngine: QueryType.YOUTUBE }) | ||||
| 		const resultsSpotify = await player.search(query, { searchEngine: QueryType.SPOTIFY_SEARCH }) | ||||
|  | ||||
| 		const tracksYouTube = resultsYouTube.tracks.slice(0, 5).map((t) => ({ | ||||
| 			name: `YouTube: ${`${t.title} - ${t.author} (${t.duration})`.length > 75 ? `${`${t.title} - ${t.author}`.substring(0, 75)}... (${t.duration})` : `${t.title} - ${t.author} (${t.duration})`}`, | ||||
| 			value: t.url | ||||
|         })) | ||||
| 		const tracksSpotify = resultsSpotify.tracks.slice(0, 5).map((t) => ({ | ||||
| 			name: `Spotify: ${`${t.title} - ${t.author} (${t.duration})`.length > 75 ? `${`${t.title} - ${t.author}`.substring(0, 75)}... (${t.duration})` : `${t.title} - ${t.author} (${t.duration})`}`, | ||||
| 			value: t.url | ||||
| 		})) | ||||
|  | ||||
| 		const tracks: TrackSearchResult[] = [] | ||||
| 		tracksYouTube.forEach((t) => tracks.push({ name: t.name, value: t.value })) | ||||
| 		tracksSpotify.forEach((t) => tracks.push({ name: t.name, value: t.value })) | ||||
|  | ||||
| 		return interaction.respond(tracks) | ||||
| 	}, | ||||
| 	async execute(interaction: ChatInputCommandInteraction) { | ||||
| 		let member = interaction.member as GuildMember | ||||
| 		let voiceChannel = member.voice.channel | ||||
| 		if (!voiceChannel) return await interaction.reply({ content: 'T\'es pas dans un vocal, idiot !', ephemeral: true }) | ||||
|  | ||||
| 		let botChannel = interaction.guild?.members.me?.voice.channel | ||||
| 		if (botChannel && voiceChannel.id !== botChannel.id) return await interaction.reply({ content: 'T\'es pas dans mon vocal !', ephemeral: true }) | ||||
|   | ||||
| 		await interaction.deferReply() | ||||
| 		 | ||||
| 		let query = interaction.options.getString('recherche', true) | ||||
| 		let player = useMainPlayer() | ||||
| 		let queue = useQueue(interaction.guild?.id ?? '') | ||||
|  | ||||
| 		if (!queue) { | ||||
| 			if (interaction.guild) queue = player.nodes.create(interaction.guild, { | ||||
| 				metadata: { | ||||
| 					channel: interaction.channel, | ||||
| 					client: interaction.guild.members.me, | ||||
| 					requestedBy: interaction.user | ||||
| 				}, | ||||
| 				selfDeaf: true, | ||||
| 				volume: 20, | ||||
| 				leaveOnEmpty: true, | ||||
| 				leaveOnEmptyCooldown: 30000, | ||||
| 				leaveOnEnd: true, | ||||
| 				leaveOnEndCooldown: 300000 | ||||
| 			}) | ||||
| 			else return | ||||
| 		} | ||||
| 		try { if (!queue.connection) await queue.connect(voiceChannel) } | ||||
| 		catch (error: unknown) { console.error(error) } | ||||
|  | ||||
|  | ||||
| 		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'] = interaction.channel?.id | ||||
| 		dbData['voiceChannelId'] = voiceChannel.id | ||||
|  | ||||
| 		guildProfile.set('guildPlayer.replay', dbData) | ||||
| 		await guildProfile.save().catch(console.error) | ||||
|  | ||||
|  | ||||
| 		let result = await player.search(query, { requestedBy: interaction.user }) | ||||
| 		if (!result.hasTracks()) return interaction.followUp(`Aucune musique trouvée pour **${query}** !`) | ||||
| 		let track = result.tracks[0] | ||||
|  | ||||
| 		let entry = queue.tasksQueue.acquire() | ||||
| 		await entry.getTask() | ||||
| 		queue.addTrack(track) | ||||
|  | ||||
| 		try { | ||||
| 			if (!queue.isPlaying()) await queue.node.play() | ||||
| 			let track_source = track.source === 'youtube' ? 'Youtube' : track.source === 'spotify' ? 'Spotify' : 'Inconnu' | ||||
| 			return interaction.followUp(`Chargement de la musique **${track.title}** de **${track.author}** sur **${track_source}**...`) | ||||
| 		} catch (error: unknown) { console.error(error) } | ||||
| 		finally { queue.tasksQueue.release() } | ||||
| 	} | ||||
| } | ||||
| import { SlashCommandBuilder, MessageFlags } from "discord.js" | ||||
| import type { ChatInputCommandInteraction, AutocompleteInteraction, GuildMember } from "discord.js" | ||||
| import { useMainPlayer, useQueue } from "discord-player" | ||||
| import { SpotifyExtractor } from "@discord-player/extractor" | ||||
| import { YoutubeiExtractor } from "discord-player-youtubei" | ||||
| import { startProgressSaving } from "@/utils/player" | ||||
| import type { TrackSearchResult } from "@/types/player" | ||||
| import type { GuildPlayer } from "@/types/schemas" | ||||
| import dbGuild from "@/schemas/guild" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("play") | ||||
| 	.setDescription("Play a song") | ||||
| 	.setNameLocalizations({ fr: "jouer" }) | ||||
| 	.setDescriptionLocalizations({ fr: "Jouer une musique" }) | ||||
| 	.addStringOption(option => option | ||||
| 		.setName("search") | ||||
| 		.setDescription("Music title to search for") | ||||
| 		.setNameLocalizations({ fr: "recherche" }) | ||||
| 		.setDescriptionLocalizations({ fr: "Titre de la musique à chercher" }) | ||||
| 		.setRequired(true) | ||||
| 		.setAutocomplete(true) | ||||
| 	) | ||||
|  | ||||
| export async function execute(interaction: ChatInputCommandInteraction) { | ||||
| 	const member = interaction.member as GuildMember | ||||
| 	const voiceChannel = member.voice.channel | ||||
| 	if (!voiceChannel) return interaction.reply({ content: t(interaction.locale, "player.not_in_voice"), flags: MessageFlags.Ephemeral }) | ||||
|  | ||||
| 	const botChannel = interaction.guild?.members.me?.voice.channel | ||||
| 	if (botChannel && voiceChannel.id !== botChannel.id) return interaction.reply({ content: t(interaction.locale, "player.not_in_same_voice"), flags: MessageFlags.Ephemeral }) | ||||
|  | ||||
| 	await interaction.deferReply() | ||||
|  | ||||
| 	const query = interaction.options.getString("search", true) | ||||
| 	const player = useMainPlayer() | ||||
| 	let queue = useQueue(interaction.guild?.id ?? "") | ||||
|  | ||||
| 	if (!queue) { | ||||
| 		if (interaction.guild) queue = player.nodes.create(interaction.guild, { | ||||
| 			metadata: { | ||||
| 				channel: interaction.channel, | ||||
| 				client: interaction.guild.members.me, | ||||
| 				requestedBy: interaction.user | ||||
| 			}, | ||||
| 			selfDeaf: true, | ||||
| 			volume: 20, | ||||
| 			leaveOnEmpty: true, | ||||
| 			leaveOnEmptyCooldown: 30000, | ||||
| 			leaveOnEnd: true, | ||||
| 			leaveOnEndCooldown: 300000 | ||||
| 		}) | ||||
| 		else return | ||||
| 	} | ||||
|  | ||||
| 	try { if (!queue.connection) await queue.connect(voiceChannel) } | ||||
| 	catch (error) { console.error(error) } | ||||
|  | ||||
| 	const guildProfile = await dbGuild.findOne({ guildId: queue.guild.id }) | ||||
| 	if (!guildProfile) return interaction.reply({ content: t(interaction.locale, "common.database_not_found"), flags: MessageFlags.Ephemeral }) | ||||
|  | ||||
| 	const botId = interaction.client.user.id | ||||
| 	const dbData = guildProfile.get("guildPlayer") as GuildPlayer | ||||
| 	dbData.instances ??= [] | ||||
|  | ||||
| 	const instanceIndex = dbData.instances.findIndex(instance => instance.botId === botId) | ||||
| 	const instance = { botId, replay: { | ||||
| 		textChannelId: interaction.channel?.id ?? "", | ||||
| 		voiceChannelId: voiceChannel.id, | ||||
| 		trackUrl: "", | ||||
| 		progress: 0 | ||||
| 	} } | ||||
|  | ||||
| 	if (instanceIndex === -1) dbData.instances.push(instance) | ||||
| 	else dbData.instances[instanceIndex] = instance | ||||
|  | ||||
| 	guildProfile.set("guildPlayer", dbData) | ||||
| 	guildProfile.markModified("guildPlayer") | ||||
| 	await guildProfile.save().catch(console.error) | ||||
|  | ||||
| 	const result = await player.search(query, { requestedBy: interaction.user }) | ||||
| 	if (!result.hasTracks()) return interaction.followUp({ content: t(interaction.locale, "player.no_track_found", { query }), flags: MessageFlags.Ephemeral }) | ||||
| 	const track = result.tracks[0] | ||||
|  | ||||
| 	const entry = queue.tasksQueue.acquire() | ||||
| 	await entry.getTask() | ||||
| 	queue.addTrack(track) | ||||
|  | ||||
| 	try { | ||||
| 		if (!queue.isPlaying()) await queue.node.play() | ||||
| 		startProgressSaving(queue.guild.id, botId) | ||||
| 		const track_source = track.source === "spotify" ? t(interaction.locale, "player.sources.spotify") : track.source === "youtube" ? t(interaction.locale, "player.sources.youtube") : t(interaction.locale, "player.sources.unknown") | ||||
| 		return await interaction.followUp(t(interaction.locale, "player.loading_track", { title: track.title, author: track.author, source: track_source })) | ||||
| 	} | ||||
| 	catch (error) { console.error(error) } | ||||
| 	finally { queue.tasksQueue.release() } | ||||
| } | ||||
|  | ||||
| export async function autocompleteRun(interaction: AutocompleteInteraction) { | ||||
| 	const query = interaction.options.getString("search", true) | ||||
| 	if (!query) return interaction.respond([]) | ||||
|  | ||||
| 	const player = useMainPlayer() | ||||
|  | ||||
| 	const resultsSpotify = await player.search(query, { searchEngine: `ext:${SpotifyExtractor.identifier}` }) | ||||
| 	const resultsYouTube = await player.search(query, { searchEngine: `ext:${YoutubeiExtractor.identifier}` }) | ||||
|  | ||||
| 	const tracksSpotify = resultsSpotify.tracks.slice(0, 5).map(t => ({ | ||||
| 		name: `Spotify: ${`${t.title} - ${t.author} (${t.duration})`.length > 75 ? `${`${t.title} - ${t.author}`.substring(0, 75)}... (${t.duration})` : `${t.title} - ${t.author} (${t.duration})`}`, | ||||
| 		value: t.url | ||||
| 	})) | ||||
| 	const tracksYouTube = resultsYouTube.tracks.slice(0, 5).map(t => ({ | ||||
| 		name: `YouTube: ${`${t.title} - ${t.author} (${t.duration})`.length > 75 ? `${`${t.title} - ${t.author}`.substring(0, 75)}... (${t.duration})` : `${t.title} - ${t.author} (${t.duration})`}`, | ||||
| 		value: t.url | ||||
| 	})) | ||||
|  | ||||
| 	const tracks: TrackSearchResult[] = [] | ||||
| 	tracksSpotify.forEach((t) => tracks.push({ name: t.name, value: t.value })) | ||||
| 	tracksYouTube.forEach((t) => tracks.push({ name: t.name, value: t.value })) | ||||
|  | ||||
| 	return interaction.respond(tracks) | ||||
| } | ||||
|   | ||||
| @@ -1,15 +1,18 @@ | ||||
| import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js' | ||||
| import { useHistory } from 'discord-player' | ||||
|  | ||||
| export default { | ||||
| 	data: new SlashCommandBuilder() | ||||
| 		.setName('previous') | ||||
| 		.setDescription('Joue la musique précédente.'), | ||||
| 	async execute(interaction: ChatInputCommandInteraction) { | ||||
| 		let history = useHistory(interaction.guild?.id ?? '') | ||||
| 		if (!history) return await interaction.reply('Il n\'y a pas d\'historique de musique !') | ||||
|  | ||||
| 		await history.previous() | ||||
| 		return await interaction.reply('Musique précédente jouée !') | ||||
| 	} | ||||
| } | ||||
| import { SlashCommandBuilder, MessageFlags } from "discord.js" | ||||
| import type { ChatInputCommandInteraction } from "discord.js" | ||||
| import { useHistory } from "discord-player" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("previous") | ||||
| 	.setDescription("Play the previous song") | ||||
| 	.setNameLocalizations({ fr: "precedent" }) | ||||
| 	.setDescriptionLocalizations({ fr: "Joue la musique précédente" }) | ||||
|  | ||||
| export async function execute(interaction: ChatInputCommandInteraction) { | ||||
| 	const history = useHistory(interaction.guild?.id ?? "") | ||||
| 	if (!history) return interaction.reply({ content: t(interaction.locale, "player.no_session"), flags: MessageFlags.Ephemeral }) | ||||
|  | ||||
| 	await history.previous() | ||||
| 	return interaction.reply({ content: t(interaction.locale, "player.previous_played"), flags: MessageFlags.Ephemeral }) | ||||
| } | ||||
|   | ||||
| @@ -1,19 +1,22 @@ | ||||
| import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js' | ||||
| import { useQueue } from 'discord-player' | ||||
|  | ||||
| export default { | ||||
| 	data: new SlashCommandBuilder() | ||||
| 		.setName('queue') | ||||
| 		.setDescription("Récupérer la file d'attente."), | ||||
| 	async execute(interaction: ChatInputCommandInteraction) { | ||||
| 		let queue = useQueue(interaction.guild?.id ?? '') | ||||
| 		if (!queue) return interaction.reply({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' }) | ||||
| 		if (!queue.currentTrack) return interaction.reply({ content: 'Aucune musique en cours de lecture.' }) | ||||
| 	 | ||||
| 		let track = `[${queue.currentTrack.title}](${queue.currentTrack.url})` | ||||
| 		let tracks = queue.tracks.map((track, index) => { return `${index + 1}. [${track.title}](${track.url})` }) | ||||
| 		if (tracks.length === 0) return interaction.reply({ content: `Lecture en cours : ${track} \nAucune musique dans la file d'attente.` }) | ||||
|  | ||||
| 		return interaction.reply({ content: `Lecture en cours : ${track} \nFile d'attente actuelle : \n${tracks.join('\n')}` }) | ||||
| 	} | ||||
| } | ||||
| import { SlashCommandBuilder, MessageFlags } from "discord.js" | ||||
| import type { ChatInputCommandInteraction } from "discord.js" | ||||
| import { useQueue } from "discord-player" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("queue") | ||||
| 	.setDescription("Get the queue") | ||||
| 	.setNameLocalizations({ fr: "file" }) | ||||
| 	.setDescriptionLocalizations({ fr: "Récupérer la file d'attente." }) | ||||
|  | ||||
| export async function execute(interaction: ChatInputCommandInteraction) { | ||||
| 	const queue = useQueue(interaction.guild?.id ?? "") | ||||
| 	if (!queue) return interaction.reply({ content: t(interaction.locale, "player.no_queue_search_instead"), flags: MessageFlags.Ephemeral}) | ||||
| 	if (!queue.currentTrack) return interaction.reply({ content: t(interaction.locale, "player.no_track_playing"), flags: MessageFlags.Ephemeral}) | ||||
|  | ||||
| 	const track = `[${queue.currentTrack.title}](${queue.currentTrack.url})` | ||||
| 	const tracks = queue.tracks.map((track, index) => { return `${index + 1}. [${track.title}](${track.url})` }) | ||||
| 	if (tracks.length === 0) return interaction.reply({ content: t(interaction.locale, "player.now_playing_no_queue", { track }) }) | ||||
|  | ||||
| 	return interaction.reply({ content: t(interaction.locale, "player.now_playing_with_queue", { track, tracks: tracks.join("\n") }) }) | ||||
| } | ||||
|   | ||||
| @@ -1,15 +1,18 @@ | ||||
| import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js' | ||||
| import { useQueue } from 'discord-player' | ||||
|  | ||||
| export default { | ||||
| 	data: new SlashCommandBuilder() | ||||
| 		.setName('resume') | ||||
| 		.setDescription('Reprendre la musique.'), | ||||
| 	async execute(interaction: ChatInputCommandInteraction) { | ||||
| 		let queue = useQueue(interaction.guild?.id ?? '') | ||||
| 		if (!queue) return interaction.followUp({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' }) | ||||
| 		 | ||||
| 		queue.node.setPaused(!queue.node.isPaused()) | ||||
| 		return await interaction.reply('Musique reprise !') | ||||
| 	} | ||||
| } | ||||
| import { SlashCommandBuilder, MessageFlags } from "discord.js" | ||||
| import type { ChatInputCommandInteraction } from "discord.js" | ||||
| import { useQueue } from "discord-player" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("resume") | ||||
| 	.setDescription("Resume the music") | ||||
| 	.setNameLocalizations({ fr: "reprendre" }) | ||||
| 	.setDescriptionLocalizations({ fr: "Reprendre la musique" }) | ||||
|  | ||||
| export async function execute(interaction: ChatInputCommandInteraction) { | ||||
| 	const queue = useQueue(interaction.guild?.id ?? "") | ||||
| 	if (!queue) return interaction.followUp({ content: t(interaction.locale, "player.no_queue_search_instead"), flags: MessageFlags.Ephemeral}) | ||||
|  | ||||
| 	queue.node.setPaused(!queue.node.isPaused()) | ||||
| 	return interaction.reply(t(interaction.locale, "player.resumed")) | ||||
| } | ||||
|   | ||||
| @@ -1,15 +1,18 @@ | ||||
| import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js' | ||||
| import { useQueue } from 'discord-player' | ||||
|  | ||||
| export default { | ||||
| 	data: new SlashCommandBuilder() | ||||
| 		.setName('shuffle') | ||||
| 		.setDescription('Mélange la file d\'attente.'), | ||||
| 	async execute(interaction: ChatInputCommandInteraction) { | ||||
| 		let queue = useQueue(interaction.guild?.id ?? '') | ||||
| 		if (!queue) return interaction.followUp({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' }) | ||||
| 		 | ||||
| 		queue.tracks.shuffle() | ||||
| 		return await interaction.reply('File d\'attente mélangée !') | ||||
| 	} | ||||
| } | ||||
| import { SlashCommandBuilder, MessageFlags } from "discord.js" | ||||
| import type { ChatInputCommandInteraction } from "discord.js" | ||||
| import { useQueue } from "discord-player" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("shuffle") | ||||
| 	.setDescription("Shuffle the queue") | ||||
| 	.setNameLocalizations({ fr: "melanger" }) | ||||
| 	.setDescriptionLocalizations({ fr: "Mélange la file d'attente" }) | ||||
|  | ||||
| export async function execute(interaction: ChatInputCommandInteraction) { | ||||
| 	const queue = useQueue(interaction.guild?.id ?? "") | ||||
| 	if (!queue) return interaction.followUp({ content: t(interaction.locale, "player.no_queue_search_instead"), flags: MessageFlags.Ephemeral}) | ||||
|  | ||||
| 	queue.tracks.shuffle() | ||||
| 	return interaction.reply(t(interaction.locale, "player.shuffled")) | ||||
| } | ||||
|   | ||||
| @@ -1,15 +1,18 @@ | ||||
| import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js' | ||||
| import { useQueue } from 'discord-player' | ||||
|  | ||||
| export default { | ||||
| 	data: new SlashCommandBuilder() | ||||
| 		.setName('skip') | ||||
| 		.setDescription('Passer la musique en cours.'), | ||||
| 	async execute(interaction: ChatInputCommandInteraction) { | ||||
| 		let queue = useQueue(interaction.guild?.id ?? '') | ||||
| 		if (!queue) return interaction.followUp({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' }) | ||||
| 		 | ||||
| 		queue.node.skip() | ||||
| 		return await interaction.reply('Musique passée !') | ||||
| 	} | ||||
| } | ||||
| import { SlashCommandBuilder, MessageFlags } from "discord.js" | ||||
| import type { ChatInputCommandInteraction } from "discord.js" | ||||
| import { useQueue } from "discord-player" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("skip") | ||||
| 	.setDescription("Skip the current song") | ||||
| 	.setNameLocalizations({ fr: "passer" }) | ||||
| 	.setDescriptionLocalizations({ fr: "Passer la musique en cours" }) | ||||
|  | ||||
| export async function execute(interaction: ChatInputCommandInteraction) { | ||||
| 	const queue = useQueue(interaction.guild?.id ?? "") | ||||
| 	if (!queue) return interaction.followUp({ content: t(interaction.locale, "player.no_queue_search_instead"), flags: MessageFlags.Ephemeral}) | ||||
|  | ||||
| 	queue.node.skip() | ||||
| 	return interaction.reply(t(interaction.locale, "player.skipped")) | ||||
| } | ||||
|   | ||||
| @@ -1,15 +1,21 @@ | ||||
| import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js' | ||||
| import { useQueue } from 'discord-player' | ||||
|  | ||||
| export default { | ||||
| 	data: new SlashCommandBuilder() | ||||
| 		.setName('stop') | ||||
| 		.setDescription('Arrêter la musique.'), | ||||
| 	async execute(interaction: ChatInputCommandInteraction) { | ||||
| 		let queue = useQueue(interaction.guild?.id ?? '') | ||||
| 		if (!queue) return interaction.followUp({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' }) | ||||
|  | ||||
| 		queue.delete() | ||||
| 		return await interaction.reply('Musique arrêtée !') | ||||
| 	} | ||||
| } | ||||
| import { SlashCommandBuilder, MessageFlags } from "discord.js" | ||||
| import type { ChatInputCommandInteraction } from "discord.js" | ||||
| import { useQueue } from "discord-player" | ||||
| import { stopProgressSaving } from "@/utils/player" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("stop") | ||||
| 	.setDescription("Stop the music") | ||||
| 	.setNameLocalizations({ fr: "arreter" }) | ||||
| 	.setDescriptionLocalizations({ fr: "Arrêter la musique" }) | ||||
|  | ||||
| export async function execute(interaction: ChatInputCommandInteraction) { | ||||
| 	await stopProgressSaving(interaction.guild?.id ?? "", interaction.client.user.id) | ||||
|  | ||||
| 	const queue = useQueue(interaction.guild?.id ?? "") | ||||
| 	if (!queue) return interaction.followUp({ content: t(interaction.locale, "player.no_queue_search_instead"), flags: MessageFlags.Ephemeral}) | ||||
|  | ||||
| 	queue.delete() | ||||
| 	return interaction.reply(t(interaction.locale, "player.stopped")) | ||||
| } | ||||
|   | ||||
| @@ -1,21 +1,26 @@ | ||||
| import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js' | ||||
| import { useQueue } from 'discord-player' | ||||
|  | ||||
| export default { | ||||
| 	data: new SlashCommandBuilder() | ||||
| 		.setName('volume') | ||||
| 		.setDescription('Modifie le volume de la musique.') | ||||
| 		.addIntegerOption(option => option.setName('volume') | ||||
| 			.setDescription('Le volume à mettre (%)') | ||||
| 			.setRequired(true) | ||||
| 			.setMinValue(1) | ||||
| 			.setMaxValue(100)), | ||||
| 	async execute(interaction: ChatInputCommandInteraction) { | ||||
| 		let volume = interaction.options.getInteger('volume') | ||||
| 		let queue = useQueue(interaction.guild?.id ?? '') | ||||
| 		if (!queue) return interaction.followUp({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' }) | ||||
| 		 | ||||
| 		queue.node.setVolume(volume as number) | ||||
| 		return await interaction.reply(`Volume modifié à ${volume}% !`) | ||||
| 	} | ||||
| } | ||||
| import { SlashCommandBuilder, MessageFlags } from "discord.js" | ||||
| import type { ChatInputCommandInteraction } from "discord.js" | ||||
| import { useQueue } from "discord-player" | ||||
| import { t } from "@/utils/i18n" | ||||
|  | ||||
| export const data = new SlashCommandBuilder() | ||||
| 	.setName("volume") | ||||
| 	.setDescription("Change the music volume") | ||||
| 	.setDescriptionLocalizations({ fr: "Modifie le volume de la musique" }) | ||||
| 	.addIntegerOption(option => option | ||||
| 		.setName("volume") | ||||
| 		.setDescription("The volume to set (%)") | ||||
| 		.setDescriptionLocalizations({ fr: "Le volume à mettre (%)" }) | ||||
| 		.setRequired(true) | ||||
| 		.setMinValue(0) | ||||
| 		.setMaxValue(100) | ||||
| 	) | ||||
|  | ||||
| export async function execute(interaction: ChatInputCommandInteraction) { | ||||
| 	const volume = interaction.options.getInteger("volume", true) | ||||
| 	const queue = useQueue(interaction.guild?.id ?? "") | ||||
| 	if (!queue) return interaction.followUp({ content: t(interaction.locale, "player.no_queue_search_instead"), flags: MessageFlags.Ephemeral}) | ||||
|  | ||||
| 	queue.node.setVolume(volume) | ||||
| 	return interaction.reply(t(interaction.locale, "player.volume_changed", { volume: volume.toString() })) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user