update to discord-player-v6 #76

Merged
Anri merged 30 commits from feat/music-v6 into main 2023-03-11 20:36:25 +01:00
27 changed files with 368 additions and 3237 deletions

View file

@ -7,6 +7,7 @@ pipeline:
auto_tag: true auto_tag: true
registry: git.mylloon.fr registry: git.mylloon.fr
username: ${CI_REPO_OWNER} username: ${CI_REPO_OWNER}
dockerfile: Docker/Dockerfile.debian
password: password:
from_secret: cb_token from_secret: cb_token
when: when:

3
.gitignore vendored
View file

@ -12,3 +12,6 @@ dist/
# Databse # Databse
*.sqlite3 *.sqlite3
# Debug file
src/events/player/debug.ts

View file

@ -5,9 +5,9 @@ Lisez attentivement si vous êtes un nouveau contributeur.
Ce guide n'est pas fixe et est mis à jour régulièrement. Si vous Ce guide n'est pas fixe et est mis à jour régulièrement. Si vous
trouvez un problème quelconque, n'hésitez pas à le signaler par le biais trouvez un problème quelconque, n'hésitez pas à le signaler par le biais
d'un [ticket](https://git.kennel.ml/ConfrerieDuKassoulait/Botanique/issues) ou d'un [ticket](https://git.mylloon.fr/ConfrerieDuKassoulait/Botanique/issues) ou
à le corriger directement en soumettant à le corriger directement en soumettant
une [Pull Request](https://git.kennel.ml/ConfrerieDuKassoulait/Botanique/pulls). une [Pull Request](https://git.mylloon.fr/ConfrerieDuKassoulait/Botanique/pulls).
## Sommaire <!-- omit in toc --> ## Sommaire <!-- omit in toc -->
@ -18,6 +18,7 @@ une [Pull Request](https://git.kennel.ml/ConfrerieDuKassoulait/Botanique/pulls).
- [Projet](#projet) - [Projet](#projet)
- [Ajouter une commande](#ajouter-une-commande) - [Ajouter une commande](#ajouter-une-commande)
- [Ajouter un évènement](#ajouter-un-évènement) - [Ajouter un évènement](#ajouter-un-évènement)
- [Player](#player)
- [Modèles](#modèles) - [Modèles](#modèles)
- [Boutons](#boutons) - [Boutons](#boutons)
- [Modifier du code](#modifier-du-code) - [Modifier du code](#modifier-du-code)
@ -157,6 +158,9 @@ Vous devez aussi ajouter **obligatoirement** :
- `"c_COMMANDE_desc": "DESCRIPTION"` au fichier de langue, avec `COMMANDE` - `"c_COMMANDE_desc": "DESCRIPTION"` au fichier de langue, avec `COMMANDE`
le nom de la commande et `DESCRIPTION` la description de votre commande. le nom de la commande et `DESCRIPTION` la description de votre commande.
> Note: Il est possible d'ajouter de l'autocomplétion via
> un 4ème élément : `autocomplete`.
## Ajouter un évènement ## Ajouter un évènement
Pour ajouter le support d'un évènement au bot, créez un fichier Pour ajouter le support d'un évènement au bot, créez un fichier
@ -174,6 +178,23 @@ De préférence, merci de mettre un lien en commentaire vers la documentation
de discord.js de l'évènement de discord.js de l'évènement
([exemple ici pour l'évènement `ready`](./src/events/client/ready.ts#L3)) ([exemple ici pour l'évènement `ready`](./src/events/client/ready.ts#L3))
### Player
Les évènement du player ont la même logique les autres, mais sont placés
dans le dossier [`player`](./src/events/player/).
> Pour débogguer le player, il est possible d'ajouter un évènement `debug`, en
> voici un exemple :
>
> ```ts
> import { GuildQueue } from "discord-player";
>
> /** https://discord-player.js.org/docs/types/discord-player/GuildQueueEvents */
> export default (_: GuildQueue, message: string) => {
> console.info(message);
> };
> ```
## Modèles ## Modèles
Les modèles sont gérés [en dehors séparément du reste](./src/modals/). Les modèles sont gérés [en dehors séparément du reste](./src/modals/).
@ -194,11 +215,11 @@ Quand vous modifiez quelque chose, pensez à mettre-à-jour les langues. Si vous
ne savez pas traduire dans une langue, ne vous forcez pas, supprimer simplement ne savez pas traduire dans une langue, ne vous forcez pas, supprimer simplement
la traduction. la traduction.
- [Créez un fork](https://git.kennel.ml/repo/fork/76) et poussez - [Créez un fork](https://git.mylloon.fr/repo/fork/76) et poussez
vos modifications dans ce dernier. vos modifications dans ce dernier.
Pour commencer, vous pouvez jeté un oeil aux Pour commencer, vous pouvez jeté un oeil aux
[tickets facilement résolvable](https://git.kennel.ml/ConfrerieDuKassoulait/Botanique/issues?state=open&labels=82). [tickets facilement résolvable](https://git.mylloon.fr/ConfrerieDuKassoulait/Botanique/issues?state=open&labels=82).
- De préférences, les fonctions, méthodes et variables seront écrites - De préférences, les fonctions, méthodes et variables seront écrites
en anglais, ainsi que les commits afin que chacun puisse contribuer. en anglais, ainsi que les commits afin que chacun puisse contribuer.
@ -219,7 +240,7 @@ Pour commencer, vous pouvez jeté un oeil aux
fonctionneront avec `npm run main`, ainsi que dans l'image Docker. fonctionneront avec `npm run main`, ainsi que dans l'image Docker.
4. Lorsque vous vous sentez confiant dans vos modifications, ouvrez 4. Lorsque vous vous sentez confiant dans vos modifications, ouvrez
une [Pull Request](https://git.kennel.ml/ConfrerieDuKassoulait/Botanique/pulls) une [Pull Request](https://git.mylloon.fr/ConfrerieDuKassoulait/Botanique/pulls)
afin que votre code puisse être revu et fusionné. Vous pouvez suivre cette afin que votre code puisse être revu et fusionné. Vous pouvez suivre cette
[condition de nommage](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716#example), [condition de nommage](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716#example),
ça aide à s'y retrouver plus rapidement. ça aide à s'y retrouver plus rapidement.
@ -237,7 +258,7 @@ Pour commencer, vous pouvez jeté un oeil aux
- On ne push jamais directement sur la branche `main`. - On ne push jamais directement sur la branche `main`.
- Quand on merge des modifications vers `main`, on fait un _squash_, - Quand on merge des modifications vers `main`, on fait un _squash_,
l'historique des modifications reste disponible dans l'historique des modifications reste disponible dans
[le graph](https://git.kennel.ml/ConfrerieDuKassoulait/Botanique/graph). [le graph](https://git.mylloon.fr/ConfrerieDuKassoulait/Botanique/graph).
- De préférences, suivre les indications de - De préférences, suivre les indications de
[ce post](https://gist.github.com/revett/88ee5abf5a9a097b4c88) (c'est un peu la [ce post](https://gist.github.com/revett/88ee5abf5a9a097b4c88) (c'est un peu la
même que dans le `4.` de [la partie précédente](#soumettre-ses-modifications)). même que dans le `4.` de [la partie précédente](#soumettre-ses-modifications)).

View file

@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM node:19.4.0-alpine3.16 FROM node:19.7.0-alpine3.17
ENV DOCKERIZED=1 ENV DOCKERIZED=1
RUN mkdir /config RUN mkdir /config
@ -12,10 +12,10 @@ WORKDIR /app
COPY --chown=node:node . . COPY --chown=node:node . .
RUN npm ci --only=production --legacy-peer-deps RUN npm ci --only=production
RUN npx tsc RUN npx tsc
RUN rm -r src/ tsconfig.json RUN rm -r src/ tsconfig.json
RUN npm uninstall typescript @types/sqlite3 --legacy-peer-deps RUN npm uninstall typescript @types/sqlite3
CMD ["dumb-init", "node", "./dist/index.js"] CMD ["dumb-init", "node", "./dist/index.js"]

22
Docker/Dockerfile.debian Normal file
View file

@ -0,0 +1,22 @@
# syntax=docker/dockerfile:1
FROM node:19.7.0-bullseye-slim
ENV DOCKERIZED=1
RUN mkdir /config
RUN chown node:node /config
RUN apt-get update
RUN apt-get install -y dumb-init
ENV NODE_ENV=production
WORKDIR /app
COPY --chown=node:node . .
RUN npm ci --only=production
RUN npx tsc
RUN rm -r src/ tsconfig.json
RUN npm uninstall typescript @types/sqlite3
CMD ["dumb-init", "node", "./dist/index.js"]

View file

@ -13,7 +13,7 @@
> Installer les dépendances du bot > Installer les dépendances du bot
```bash ```bash
npm install --legacy-peer-deps npm install
``` ```
> Lancer le bot > Lancer le bot

3371
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,28 +11,29 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git@git.kennel.ml:ConfrerieDuKassoulait/Botanique.git" "url": "git@git.mylloon.fr:ConfrerieDuKassoulait/Botanique.git"
}, },
"author": "La confrérie du Kassoulait", "author": "La confrérie du Kassoulait",
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"dependencies": { "dependencies": {
"@discord-player/extractor": "^4.0.0", "@discord-player/extractor": "^4.1.1",
"@discordjs/opus": "^0.9.0", "@discordjs/opus": "^0.9.0",
"@discordjs/rest": "^1.5.0", "@discordjs/rest": "^1.5.0",
"@types/sqlite3": "^3.1.8", "@types/sqlite3": "^3.1.8",
"@types/uuid": "^9.0.0", "@types/uuid": "^9.0.0",
"discord-api-types": "^0.37.32", "discord-player": "^6.1.0",
"discord-player": "^5.4.1-dev.0",
"discord.js": "^14.7.1", "discord.js": "^14.7.1",
"ffmpeg-static": "^5.1.0", "ffmpeg-static": "^5.1.0",
"genius-lyrics": "^4.4.3", "genius-lyrics": "^4.4.3",
"node-fetch": "^2.6.9", "node-fetch": "^2.6.9",
"play-dl": "^1.9.6", "play-dl": "^1.9.6",
"prism-media": "^1.3.4",
"sqlite3": "^5.1.4", "sqlite3": "^5.1.4",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"uuid": "^9.0.0" "uuid": "^9.0.0"
}, },
"overrides": {
"discord-api-types": "0.37.34"
},
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/eslint-plugin": "^5.30.7",
"@typescript-eslint/parser": "^5.30.7", "@typescript-eslint/parser": "^5.30.7",

View file

@ -1,3 +1,4 @@
import { useQueue } from "discord-player";
import { import {
ActionRowBuilder, ActionRowBuilder,
ButtonBuilder, ButtonBuilder,
@ -30,7 +31,7 @@ export default {
} }
// Get queue // Get queue
const queue = client.player.queues.get(interaction.guildId ?? ""); const queue = useQueue(interaction.guildId ?? "");
const embed = new EmbedBuilder(); const embed = new EmbedBuilder();
const rows = []; const rows = [];

View file

@ -1,3 +1,4 @@
import { useQueue } from "discord-player";
import { import {
ActionRowBuilder, ActionRowBuilder,
ButtonBuilder, ButtonBuilder,
@ -30,7 +31,7 @@ export default {
} }
// Get queue // Get queue
const queue = client.player.queues.get(interaction.guildId ?? ""); const queue = useQueue(interaction.guildId ?? "");
const embed = new EmbedBuilder(); const embed = new EmbedBuilder();
const rows = []; const rows = [];

View file

@ -1,4 +1,5 @@
import { SlashCommandBuilder } from "@discordjs/builders"; import { SlashCommandBuilder } from "@discordjs/builders";
import { Player, useMasterPlayer, useQueue } from "discord-player";
import { ChatInputCommandInteraction, Client, EmbedBuilder } from "discord.js"; import { ChatInputCommandInteraction, Client, EmbedBuilder } from "discord.js";
import { getLocale, getLocalizations } from "../../utils/locales"; import { getLocale, getLocalizations } from "../../utils/locales";
import { getFilename } from "../../utils/misc"; import { getFilename } from "../../utils/misc";
@ -44,19 +45,20 @@ export default {
let data = null; let data = null;
await interaction.deferReply(); await interaction.deferReply();
const player = useMasterPlayer() as Player;
if (request) { if (request) {
try { try {
data = await client.player.lyrics.search(request); data = await player.lyrics.search(request);
} catch { } catch {
return await interaction.followUp(`❌ | ${loc.get("c_lyrics2")} \`${request}\``); return await interaction.followUp(`❌ | ${loc.get("c_lyrics2")} \`${request}\``);
} }
} else { } else {
const queue = client.player.queues.get(interaction.guildId ?? ""); const queue = useQueue(interaction.guildId ?? "");
if (queue) { if (queue) {
const title = queue.current?.title; const title = queue.history.currentTrack?.title;
if (title) { if (title) {
try { try {
data = await client.player.lyrics.search(title + " " + queue.current.author); data = await player.lyrics.search(title + " " + queue.history.currentTrack?.author);
} catch { } catch {
return await interaction.followUp(`❌ | ${loc.get("c_lyrics2")} \`${title}\``); return await interaction.followUp(`❌ | ${loc.get("c_lyrics2")} \`${title}\``);
} }

View file

@ -1,4 +1,5 @@
import { SlashCommandBuilder } from "@discordjs/builders"; import { SlashCommandBuilder } from "@discordjs/builders";
import { useQueue } from "discord-player";
import { ChatInputCommandInteraction, Client, EmbedBuilder } from "discord.js"; import { ChatInputCommandInteraction, Client, EmbedBuilder } from "discord.js";
import { getLocale, getLocalizations } from "../../utils/locales"; import { getLocale, getLocalizations } from "../../utils/locales";
import { getFilename } from "../../utils/misc"; import { getFilename } from "../../utils/misc";
@ -22,17 +23,17 @@ export default {
interaction: async (interaction: ChatInputCommandInteraction, client: Client) => { interaction: async (interaction: ChatInputCommandInteraction, client: Client) => {
const loc = getLocale(client, interaction.locale); const loc = getLocale(client, interaction.locale);
const queue = client.player.queues.get(interaction.guildId ?? ""); const queue = useQueue(interaction.guildId ?? "");
if (queue) { if (queue) {
const embed = new EmbedBuilder(); const embed = new EmbedBuilder();
if (queue.paused) { if (queue.node.isPaused()) {
queue.resume(); queue.node.resume();
embed.setDescription(loc.get("c_pause1")); embed.setDescription(loc.get("c_pause1"));
return await interaction.reply({ embeds: [embed] }); return await interaction.reply({ embeds: [embed] });
} else { } else {
queue.pause(); queue.node.pause();
embed.setDescription(loc.get("c_pause2")); embed.setDescription(loc.get("c_pause2"));
return await interaction.reply({ embeds: [embed] }); return await interaction.reply({ embeds: [embed] });

View file

@ -1,5 +1,6 @@
import { SlashCommandBuilder } from "@discordjs/builders"; import { SlashCommandBuilder } from "@discordjs/builders";
import { import {
AutocompleteInteraction,
ChatInputCommandInteraction, ChatInputCommandInteraction,
Client, Client,
EmbedBuilder, EmbedBuilder,
@ -9,6 +10,7 @@ import {
import { Metadata } from "../../utils/metadata"; import { Metadata } from "../../utils/metadata";
import { getLocale, getLocalizations } from "../../utils/locales"; import { getLocale, getLocalizations } from "../../utils/locales";
import { getFilename } from "../../utils/misc"; import { getFilename } from "../../utils/misc";
import { Player, useMasterPlayer, useQueue } from "discord-player";
export default { export default {
scope: () => [], scope: () => [],
@ -34,6 +36,7 @@ export default {
.setDescription(loc_default.get(`c_${filename}_opt1_desc`) ?? "") .setDescription(loc_default.get(`c_${filename}_opt1_desc`) ?? "")
.setNameLocalizations(getLocalizations(client, `c_${filename}_opt1_name`, true)) .setNameLocalizations(getLocalizations(client, `c_${filename}_opt1_name`, true))
.setDescriptionLocalizations(getLocalizations(client, `c_${filename}_opt1_desc`)) .setDescriptionLocalizations(getLocalizations(client, `c_${filename}_opt1_desc`))
.setAutocomplete(true)
) )
); );
}, },
@ -68,17 +71,18 @@ export default {
loc_default?.get(`c_${filename}_opt1_name`) as string loc_default?.get(`c_${filename}_opt1_name`) as string
); );
const player = useMasterPlayer() as Player;
if (!query) { if (!query) {
// Now playing // Now playing
const queue = client.player.queues.get(interaction.guildId ?? ""); const queue = useQueue(interaction.guildId ?? "");
if (queue) { if (queue) {
const track = queue.nowPlaying(); const track = queue.history.currentTrack;
if (track) { if (track) {
const embed = new EmbedBuilder() const embed = new EmbedBuilder()
.setDescription( .setDescription(
`${queue.createProgressBar()}\n\n${loc.get("c_play8")} ${track.requestedBy}` `${queue.node.createProgressBar()}\n\n${loc.get("c_play8")} ${track.requestedBy}`
) )
.setTitle(track.title + " • " + track.author) .setTitle(track.title + " • " + track.author)
.setURL(track.url) .setURL(track.url)
@ -93,7 +97,7 @@ export default {
return await interaction.reply({ embeds: [embed] }); return await interaction.reply({ embeds: [embed] });
} }
const queue = client.player.createQueue(interaction.guild as GuildResolvable, { const queue = player.nodes.create(interaction.guild as GuildResolvable, {
metadata: { metadata: {
channel: interaction.channel, channel: interaction.channel,
} as Metadata, } as Metadata,
@ -103,7 +107,7 @@ export default {
try { try {
if (!queue.connection) await queue.connect(member.voice.channel as VoiceBasedChannel); if (!queue.connection) await queue.connect(member.voice.channel as VoiceBasedChannel);
} catch { } catch {
queue.destroy(); queue.delete();
return await interaction.reply({ return await interaction.reply({
content: `❌ | ${loc.get("c_play3")}`, content: `❌ | ${loc.get("c_play3")}`,
ephemeral: true, ephemeral: true,
@ -111,35 +115,57 @@ export default {
} }
await interaction.deferReply(); await interaction.deferReply();
const result = await client.player const result = await player
.search(query, { .search(query, {
requestedBy: interaction.user, requestedBy: interaction.user,
}) })
.then((x) => x); .then((x) => x);
if (!result.tracks[0]) { if (result.isEmpty()) {
const embed = new EmbedBuilder().setDescription(`❌ | \`${query}\` ${loc.get("c_play4")}.`); const embed = new EmbedBuilder().setDescription(`❌ | \`${query}\` ${loc.get("c_play4")}.`);
return await interaction.followUp({ embeds: [embed] }); return await interaction.followUp({ embeds: [embed] });
} }
let title; let title;
if (result.playlist) { if (result.playlist) {
queue.addTracks(result.playlist.tracks); queue.addTrack(result.playlist.tracks);
title = result.playlist.title; title = result.playlist.title;
} else { } else {
// TODO: Ask user which result to choose
const track = result.tracks[0]; const track = result.tracks[0];
queue.addTrack(track); queue.addTrack(track);
title = track.title; title = track.title;
} }
if (!queue.playing) { if (!queue.node.isPlaying()) {
queue.play(); queue.node.play();
} }
// TODO: When added to an existing queue (size of queue > 0):
// - Add position in queue
// - Add estimated time until playing
return await interaction.followUp({ return await interaction.followUp({
content: `⏱️ | \`${title}\` ${loc.get("c_play5")}.`, content: `⏱️ | \`${title}\` ${loc.get("c_play5")}.`,
}); });
}, },
autocomplete: async (interaction: AutocompleteInteraction) => {
const loc_default = interaction.client.locales.get(interaction.client.config.default_lang);
const filename = getFilename(__filename);
const player = useMasterPlayer() as Player;
const query = interaction.options.getString(
loc_default?.get(`c_${filename}_opt1_name`) as string,
true
);
const results = await player.search(query);
// Returns a list of songs with their title
return interaction.respond(
results.tracks.slice(0, 10).map((t) => ({
name: t.title,
value: t.url,
}))
);
},
}; };

View file

@ -1,4 +1,5 @@
import { SlashCommandBuilder } from "@discordjs/builders"; import { SlashCommandBuilder } from "@discordjs/builders";
import { useQueue } from "discord-player";
import { import {
ActionRowBuilder, ActionRowBuilder,
ButtonBuilder, ButtonBuilder,
@ -92,7 +93,7 @@ export default {
const filename = getFilename(__filename); const filename = getFilename(__filename);
const loc = getLocale(client, interaction.locale); const loc = getLocale(client, interaction.locale);
const queue = client.player.queues.get(interaction.guildId ?? ""); const queue = useQueue(interaction.guildId ?? "");
const embed = new EmbedBuilder(); const embed = new EmbedBuilder();
const rows = []; const rows = [];
@ -136,7 +137,7 @@ export default {
// Shuffle Queue // Shuffle Queue
case loc_default?.get(`c_${filename}_sub2_name`)?.toLowerCase() ?? "": { case loc_default?.get(`c_${filename}_sub2_name`)?.toLowerCase() ?? "": {
queue.shuffle(); queue.tracks.shuffle();
embed.setDescription(loc.get("c_queue3")); embed.setDescription(loc.get("c_queue3"));
break; break;
@ -148,7 +149,7 @@ export default {
loc_default?.get(`c_${filename}_sub3_opt1_name`) as string loc_default?.get(`c_${filename}_sub3_opt1_name`) as string
) as number; ) as number;
const track = queue.remove(id - 1); const track = queue.removeTrack(id - 1);
if (track) { if (track) {
embed.setDescription( embed.setDescription(

View file

@ -1,5 +1,5 @@
import { SlashCommandBuilder } from "@discordjs/builders"; import { SlashCommandBuilder } from "@discordjs/builders";
import { QueueRepeatMode } from "discord-player"; import { QueueRepeatMode, useQueue } from "discord-player";
import { ChatInputCommandInteraction, Client } from "discord.js"; import { ChatInputCommandInteraction, Client } from "discord.js";
import { getLocale, getLocalizations } from "../../utils/locales"; import { getLocale, getLocalizations } from "../../utils/locales";
import { getFilename } from "../../utils/misc"; import { getFilename } from "../../utils/misc";
@ -64,7 +64,7 @@ export default {
const filename = getFilename(__filename); const filename = getFilename(__filename);
const loc = getLocale(client, interaction.locale); const loc = getLocale(client, interaction.locale);
const queue = client.player.queues.get(interaction.guildId ?? ""); const queue = useQueue(interaction.guildId ?? "");
if (queue) { if (queue) {
const subcommand = interaction.options.getSubcommand(); const subcommand = interaction.options.getSubcommand();
@ -91,7 +91,7 @@ export default {
case loc_default?.get(`c_${filename}_sub2_name`)?.toLowerCase() ?? "": { case loc_default?.get(`c_${filename}_sub2_name`)?.toLowerCase() ?? "": {
queue.setRepeatMode(QueueRepeatMode.TRACK); queue.setRepeatMode(QueueRepeatMode.TRACK);
return interaction.reply( return interaction.reply(
`${loc.get("c_repeat5")} ${queue.nowPlaying()?.title} ${loc.get("c_repeat6")}.` `${loc.get("c_repeat5")} ${queue.history.currentTrack?.title} ${loc.get("c_repeat6")}.`
); );
} }
} }

View file

@ -1,4 +1,5 @@
import { SlashCommandBuilder } from "@discordjs/builders"; import { SlashCommandBuilder } from "@discordjs/builders";
import { useQueue } from "discord-player";
import { ChatInputCommandInteraction, Client } from "discord.js"; import { ChatInputCommandInteraction, Client } from "discord.js";
import { getLocale, getLocalizations } from "../../utils/locales"; import { getLocale, getLocalizations } from "../../utils/locales";
import { getFilename } from "../../utils/misc"; import { getFilename } from "../../utils/misc";
@ -36,17 +37,17 @@ export default {
const filename = getFilename(__filename); const filename = getFilename(__filename);
const loc = getLocale(client, interaction.locale); const loc = getLocale(client, interaction.locale);
const queue = client.player.queues.get(interaction.guildId ?? ""); const queue = useQueue(interaction.guildId ?? "");
const id = interaction.options.getNumber(loc_default?.get(`c_${filename}_opt1_name`) as string); const id = interaction.options.getNumber(loc_default?.get(`c_${filename}_opt1_name`) as string);
if (queue) { if (queue) {
let msg; let msg;
if (id) { if (id) {
queue.skipTo(id - 1); queue.node.skipTo(id - 1);
msg = loc.get("c_skip3") + " #" + id + "..."; msg = loc.get("c_skip3") + " #" + id + "...";
} else { } else {
queue.skip(); queue.node.skip();
msg = loc.get("c_skip1") + "..."; msg = loc.get("c_skip1") + "...";
} }

View file

@ -3,6 +3,7 @@ import { ChatInputCommandInteraction, Client, GuildResolvable } from "discord.js
import { Metadata } from "../../utils/metadata"; import { Metadata } from "../../utils/metadata";
import { getLocale, getLocalizations } from "../../utils/locales"; import { getLocale, getLocalizations } from "../../utils/locales";
import { getFilename } from "../../utils/misc"; import { getFilename } from "../../utils/misc";
import { Player, useMasterPlayer } from "discord-player";
export default { export default {
scope: () => [], scope: () => [],
@ -24,17 +25,18 @@ export default {
interaction: async (interaction: ChatInputCommandInteraction, client: Client) => { interaction: async (interaction: ChatInputCommandInteraction, client: Client) => {
const loc = getLocale(client, interaction.locale); const loc = getLocale(client, interaction.locale);
const queue = client.player.createQueue(interaction.guild as GuildResolvable, { const player = useMasterPlayer() as Player;
const queue = player.nodes.create(interaction.guild as GuildResolvable, {
metadata: { metadata: {
channel: interaction.channel, channel: interaction.channel,
} as Metadata, } as Metadata,
}); });
if (!(queue.connection || queue.playing)) { if (!(queue.connection || queue.node.isPlaying())) {
return interaction.reply(`❌ | ${loc.get("c_stop1")}`); return interaction.reply(`❌ | ${loc.get("c_stop1")}`);
} }
queue.destroy(); queue.delete();
interaction.reply(loc.get("c_stop2")); interaction.reply(loc.get("c_stop2"));
}, },

View file

@ -29,6 +29,19 @@ export default (interaction: Interaction, client: Client) => {
return modal.interaction(interaction, client); return modal.interaction(interaction, client);
} }
case InteractionType.ApplicationCommandAutocomplete: {
const command = client.commands.list.get(interaction.commandName);
if (!command) {
return console.error(loc.get("e_interacreate_no_command"));
}
if (command.autocomplete) {
return command.autocomplete(interaction);
}
return console.error(loc.get("e_interacreate_no_autocomplete"));
}
default: default:
break; break;
} }

View file

@ -1,4 +1,4 @@
import { PlayerEvents } from "discord-player"; import { Player, PlayerEvents, useMasterPlayer } from "discord-player";
import { Client } from "discord.js"; import { Client } from "discord.js";
import { readdir } from "fs/promises"; import { readdir } from "fs/promises";
@ -29,14 +29,15 @@ export default async (client: Client) => {
const event_type = event_type_ext.join("."); const event_type = event_type_ext.join(".");
if (event_category == "player") { if (event_category == "player") {
const player = useMasterPlayer() as Player;
if (once) { if (once) {
// eslint-disable-next-line // eslint-disable-next-line
return client.player.once(event_type as keyof PlayerEvents, (...args: any[]) => { return player.events.once(event_type as keyof PlayerEvents, (...args: any[]) => {
execute(...args, client); execute(...args, client);
}); });
} }
// eslint-disable-next-line // eslint-disable-next-line
return client.player.on(event_type as keyof PlayerEvents, (...args: any[]) => { return player.events.on(event_type as keyof PlayerEvents, (...args: any[]) => {
execute(...args, client); execute(...args, client);
}); });
} }

View file

@ -1,7 +1,7 @@
import { Queue } from "discord-player"; import { GuildQueue } from "discord-player";
import { Metadata } from "../../utils/metadata"; import { Metadata } from "../../utils/metadata";
/** https://discord-player.js.org/docs/main/master/typedef/PlayerEvents */ /** https://discord-player.js.org/docs/main/master/typedef/PlayerEvents */
export default (_: Queue<Metadata>, error: Error) => { export default (_: GuildQueue<Metadata>, error: Error) => {
console.error(error); console.error(error);
}; };

View file

@ -1,7 +1,7 @@
import { Queue } from "discord-player"; import { GuildQueue } from "discord-player";
import { Metadata } from "../../utils/metadata"; import { Metadata } from "../../utils/metadata";
/** https://discord-player.js.org/docs/main/master/typedef/PlayerEvents */ /** https://discord-player.js.org/docs/main/master/typedef/PlayerEvents */
export default (_: Queue<Metadata>, error: Error) => { export default (_: GuildQueue<Metadata>, error: Error) => {
console.error(error); console.error(error);
}; };

View file

@ -1,11 +1,11 @@
import { EmbedBuilder } from "@discordjs/builders"; import { EmbedBuilder } from "@discordjs/builders";
import { Queue, Track } from "discord-player"; import { GuildQueue, Track } from "discord-player";
import { Client } from "discord.js"; import { Client } from "discord.js";
import { Metadata } from "../../utils/metadata"; import { Metadata } from "../../utils/metadata";
import { emojiPng } from "../../utils/misc"; import { emojiPng } from "../../utils/misc";
/** https://discord-player.js.org/docs/main/master/typedef/PlayerEvents */ /** https://discord-player.js.org/docs/types/discord-player/GuildQueueEvents */
export default (queue: Queue<Metadata>, track: Track, client: Client) => { export default (queue: GuildQueue<Metadata>, track: Track, client: Client) => {
const loc_default = client.locales.get(client.config.default_lang); const loc_default = client.locales.get(client.config.default_lang);
const embed = new EmbedBuilder() const embed = new EmbedBuilder()

View file

@ -21,7 +21,7 @@ const run = async () => {
const client_name = "Client"; const client_name = "Client";
await loadClient() await loadClient()
.then(async (client) => { .then(async (client) => {
// Events Discord.JS // Events Discord.JS and Player
const events_name = "Events"; const events_name = "Events";
await loadEvents(client) await loadEvents(client)
.then(() => console.log(logStart(events_name, true))) .then(() => console.log(logStart(events_name, true)))

View file

@ -2,6 +2,7 @@
"e_interacreate_no_command": "Désolé, la commande n'existe plus...", "e_interacreate_no_command": "Désolé, la commande n'existe plus...",
"e_interacreate_no_modal": "Désolé, le modèle n'existe plus...", "e_interacreate_no_modal": "Désolé, le modèle n'existe plus...",
"e_interacreate_no_button": "Désolé, le bouton n'existe plus...", "e_interacreate_no_button": "Désolé, le bouton n'existe plus...",
"e_interacreate_no_autocomplete": "Désolé, pas d'autocomplétion existe pour cette commande...",
"c_ping_name": "Ping", "c_ping_name": "Ping",
"c_ping_desc": "Pong!", "c_ping_desc": "Pong!",

View file

@ -1,7 +1,6 @@
import { Collection } from "discord.js"; import { Collection } from "discord.js";
import { SlashCommandBuilder } from "@discordjs/builders"; import { SlashCommandBuilder } from "@discordjs/builders";
import { Database } from "sqlite3"; import { Database } from "sqlite3";
import { Player } from "discord-player";
export {}; export {};
@ -80,11 +79,11 @@ declare module "discord.js" {
data: SlashCommandBuilder; data: SlashCommandBuilder;
/** How the command interact */ /** How the command interact */
interaction: (interaction: CommandInteraction, client: Client) => unknown; interaction: (interaction: CommandInteraction, client: Client) => unknown;
/** Autocomplete logic */
autocomplete: undefined | ((interaction: AutocompleteInteraction) => unknown);
} }
>; >;
}; };
/** Music player */
player: Player;
/** Store all the localizations */ /** Store all the localizations */
locales: Map<string, Map<string, string>>; locales: Map<string, Map<string, string>>;
db: Database; db: Database;

View file

@ -38,13 +38,14 @@ export default async () => {
list: new Collection(), list: new Collection(),
}; };
client.player = new Player(client, { const player = Player.singleton(client, {
ytdlOptions: { ytdlOptions: {
filter: "audioonly", filter: "audioonly",
quality: "highestaudio",
}, },
}); });
client.player.lyrics = lyricsExtractor(); player.lyrics = lyricsExtractor();
console.log("Translations progression :"); console.log("Translations progression :");
client.locales = await loadLocales(client.config.default_lang); client.locales = await loadLocales(client.config.default_lang);

View file

@ -1,20 +1,20 @@
import { EmbedBuilder } from "@discordjs/builders"; import { EmbedBuilder } from "@discordjs/builders";
import { Queue, QueueRepeatMode, Track } from "discord-player"; import { GuildQueue, QueueRepeatMode, Track } from "discord-player";
import { Client } from "discord.js"; import { Client } from "discord.js";
import { getLocale } from "./locales"; import { getLocale } from "./locales";
export const embedListQueue = ( export const embedListQueue = (
client: Client, client: Client,
embed: EmbedBuilder, embed: EmbedBuilder,
queue: Queue, queue: GuildQueue,
page: number, page: number,
local: string local: string
) => { ) => {
const loc = getLocale(client, local); const loc = getLocale(client, local);
const tracks = queue.tracks.slice(); const tracks = queue.tracks.toArray();
// Add the current song at the top of the list // Add the current song at the top of the list
tracks.unshift(queue.current as Track); tracks.unshift(queue.history.currentTrack as Track);
// Limit of discord is 25 // Limit of discord is 25
const limit_fields = 25; const limit_fields = 25;