Compare commits

..

1 commit

Author SHA1 Message Date
f334deacc4
[chore] vscode rule
All checks were successful
ci/woodpecker/push/publish Pipeline was successful
2024-06-10 21:35:28 +02:00
20 changed files with 484 additions and 494 deletions

View file

@ -1,23 +0,0 @@
name: Lint and Format Check
on:
pull_request:
types: [opened, synchronize, reopened]
branches:
- main
- dev
jobs:
lint-and-format:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install dependencies
run: npm install
- name: Run lint
run: npm run lint
- name: Run format check
run: npm run format-check

View file

@ -1,36 +1,15 @@
name: Publish latest version steps:
publish:
on: image: woodpeckerci/plugin-docker-buildx:2
push: settings:
branches: [main] labels:
platform: linux/amd64
jobs: repo: git.mylloon.fr/${CI_REPO,,}
build: auto_tag: true
container: registry: git.mylloon.fr
image: ghcr.io/catthehacker/ubuntu:act-latest username: ${CI_REPO_OWNER}
steps: password:
- name: Checkout from_secret: cb_token
uses: actions/checkout@v4 when:
event: push
- name: Set up Docker Buildx branch: main
uses: docker/setup-buildx-action@v3
- name: Sanitize metadata
id: meta
uses: docker/metadata-action@v5
with:
tags: latest
images: git.mylloon.fr/${{ github.repository }}
- name: Login to Registry
uses: docker/login-action@v3
with:
registry: ${{ github.server_url }}
username: ${{ github.actor }}
password: ${{ secrets.TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}

View file

@ -1,4 +1,4 @@
# 🌱 Botanique ![status-badge](https://git.mylloon.fr/ConfrerieDuKassoulait/Botanique/badges/workflows/publish.yml/badge.svg) # 🌱 Botanique [![status-badge](https://ci.mylloon.fr/api/badges/ConfrerieDuKassoulait/Botanique/status.svg)](https://ci.mylloon.fr/ConfrerieDuKassoulait/Botanique)
[**Ajoute le bot à ton serveur**](https://discord.com/api/oauth2/authorize?client_id=965598852407230494&permissions=8&scope=bot%20applications.commands) [**Ajoute le bot à ton serveur**](https://discord.com/api/oauth2/authorize?client_id=965598852407230494&permissions=8&scope=bot%20applications.commands)

717
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -17,21 +17,21 @@
"author": "La confrérie du Kassoulait", "author": "La confrérie du Kassoulait",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"dependencies": { "dependencies": {
"@discord-player/extractor": "^4.5.1", "@discord-player/extractor": "^4.4.7",
"@discordjs/rest": "^2.4.0", "@discordjs/rest": "^2.3.0",
"@distube/ytdl-core": "^4.13.4",
"@types/sqlite3": "^3.1.11", "@types/sqlite3": "^3.1.11",
"@types/uuid": "^10.0.0", "@types/uuid": "^9.0.8",
"discord-player": "^6.7.1", "discord-player": "^6.6.10",
"discord-player-youtubei": "^1.3.1", "discord.js": "^14.15.3",
"discord.js": "^14.16.1",
"mediaplex": "^0.0.9", "mediaplex": "^0.0.9",
"sqlite3": "^5.1.7", "sqlite3": "^5.1.7",
"typescript": "^5.5.4", "typescript": "^5.4.5",
"uuid": "^10.0.0" "uuid": "^10.0.0"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "~8.4.0", "@typescript-eslint/eslint-plugin": "~7.13.0",
"@typescript-eslint/parser": "~8.4.0", "@typescript-eslint/parser": "~7.13.0",
"dotenv": "~16.4.5", "dotenv": "~16.4.5",
"prettier-eslint": "~16.3.0", "prettier-eslint": "~16.3.0",
"ts-node-dev": "~2.0.0" "ts-node-dev": "~2.0.0"

View file

@ -1,11 +1,6 @@
import { readdir } from "fs/promises"; import { readdir } from "fs/promises";
import { removeExtension } from "../utils/misc"; import { removeExtension } from "../utils/misc";
import { import { ChatInputCommandInteraction, Client, MessageComponentInteraction } from "discord.js";
ChatInputCommandInteraction,
Client,
Message,
MessageComponentInteraction,
} from "discord.js";
import { getLocale } from "../utils/locales"; import { getLocale } from "../utils/locales";
export default async (client: Client) => { export default async (client: Client) => {
@ -42,14 +37,12 @@ export default async (client: Client) => {
* @param client Client * @param client Client
* @param interaction Chat interaction * @param interaction Chat interaction
* @param id Button ID * @param id Button ID
* @param message Message holding the buttons
* @param deferUpdate defer update in case update take time * @param deferUpdate defer update in case update take time
*/ */
export const collect = ( export const collect = (
client: Client, client: Client,
interaction: ChatInputCommandInteraction | MessageComponentInteraction, interaction: ChatInputCommandInteraction | MessageComponentInteraction,
id: string, id: string,
message: Message,
deferUpdate = false, deferUpdate = false,
) => { ) => {
const loc = getLocale(client, interaction.locale); const loc = getLocale(client, interaction.locale);
@ -63,7 +56,7 @@ export const collect = (
} }
const filter = (i: MessageComponentInteraction) => i.customId === id; const filter = (i: MessageComponentInteraction) => i.customId === id;
const collector = message.createMessageComponentCollector({ const collector = interaction.channel?.createMessageComponentCollector({
filter, filter,
max: 1, max: 1,
}); });

View file

@ -59,8 +59,8 @@ export default {
); );
// Buttons interactions // Buttons interactions
collect(client, interaction, idPrec, interaction.message); collect(client, interaction, idPrec);
collect(client, interaction, idNext, interaction.message); collect(client, interaction, idNext);
return { return {
embeds: [list], embeds: [list],

View file

@ -59,8 +59,8 @@ export default {
); );
// Buttons interactions // Buttons interactions
collect(client, interaction, idPrec, interaction.message); collect(client, interaction, idPrec);
collect(client, interaction, idNext, interaction.message); collect(client, interaction, idNext);
return { return {
embeds: [list], embeds: [list],

View file

@ -59,8 +59,8 @@ export default {
); );
// Buttons interactions // Buttons interactions
collect(client, interaction, idPrec, interaction.message); collect(client, interaction, idPrec);
collect(client, interaction, idNext, interaction.message); collect(client, interaction, idNext);
} else { } else {
// In case queue doesn't exists // In case queue doesn't exists
embed.setDescription(loc.get("c_queue2")); embed.setDescription(loc.get("c_queue2"));

View file

@ -59,8 +59,8 @@ export default {
); );
// Buttons interactions // Buttons interactions
collect(client, interaction, idPrec, interaction.message); collect(client, interaction, idPrec);
collect(client, interaction, idNext, interaction.message); collect(client, interaction, idNext);
} else { } else {
// In case queue doesn't exists // In case queue doesn't exists
embed.setDescription(loc.get("c_queue2")); embed.setDescription(loc.get("c_queue2"));

View file

@ -230,18 +230,15 @@ export default {
.setStyle(ButtonStyle.Primary), .setStyle(ButtonStyle.Primary),
); );
const message = await interaction.reply({ // Buttons interactions
collect(client, interaction, idPrec);
collect(client, interaction, idNext);
return await interaction.reply({
ephemeral: true, ephemeral: true,
embeds: [list], embeds: [list],
components: [row], components: [row],
fetchReply: true,
}); });
// Buttons interactions
collect(client, interaction, idPrec, message);
collect(client, interaction, idNext, message);
return;
} }
// Delete a reminder // Delete a reminder
case loc_default?.get(`c_${filename}_sub3_name`)?.toLowerCase() ?? "": { case loc_default?.get(`c_${filename}_sub3_name`)?.toLowerCase() ?? "": {

View file

@ -1,6 +1,6 @@
import { SlashCommandBuilder } from "@discordjs/builders"; import { SlashCommandBuilder } from "@discordjs/builders";
import { Player, useMainPlayer, useQueue } from "discord-player"; import { Player, useMainPlayer, useQueue } from "discord-player";
import { ChannelType, 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";
@ -56,15 +56,6 @@ export default {
.setDescriptionLocalizations(getLocalizations(client, `c_${filename}_opt1_desc`)), .setDescriptionLocalizations(getLocalizations(client, `c_${filename}_opt1_desc`)),
), ),
) )
// Synced
.addSubcommand((subcommand) =>
subcommand
.setName(loc_default.get(`c_${filename}_sub3_name`)?.toLowerCase() ?? "")
.setDescription(loc_default.get(`c_${filename}_sub3_desc`) ?? "")
.setNameLocalizations(getLocalizations(client, `c_${filename}_sub3_name`, true))
.setDescriptionLocalizations(getLocalizations(client, `c_${filename}_sub3_desc`)),
)
); );
}, },
@ -82,7 +73,6 @@ export default {
await interaction.deferReply(); await interaction.deferReply();
const player = useMainPlayer() as Player; const player = useMainPlayer() as Player;
const queue = useQueue(interaction.guildId ?? "");
if (request) { if (request) {
if ( if (
interaction.options.getSubcommand() == interaction.options.getSubcommand() ==
@ -98,7 +88,9 @@ export default {
} catch { } catch {
return await interaction.followUp(`❌ | ${loc.get("c_lyrics2")} \`${request}\``); return await interaction.followUp(`❌ | ${loc.get("c_lyrics2")} \`${request}\``);
} }
} else if (queue) { } else {
const queue = useQueue(interaction.guildId ?? "");
if (queue) {
const track = queue.history.currentTrack; const track = queue.history.currentTrack;
if (track) { if (track) {
try { try {
@ -110,48 +102,9 @@ export default {
} }
} }
} }
if (
interaction.options.getSubcommand() ==
loc_default?.get(`c_${filename}_sub3_name`)?.toLowerCase() ??
""
) {
if (queue === null) {
return await interaction.followUp(`❌ | ${loc.get("c_lyrics1")}`);
} }
if (data === null || !data[0] || !data[0].syncedLyrics) { if (data && data.length > 0) {
return await interaction.followUp(
`❌ | ${loc.get("c_lyrics3")} \`${queue.currentTrack?.cleanTitle}\``,
);
}
// Load lyrics
const syncedLyrics = queue.syncedLyrics(data[0]);
syncedLyrics?.onChange(async (lyrics) => {
const content = `[${data[0].trackName}]: ${lyrics}`;
if (interaction.channel?.type === ChannelType.GroupDM) {
await interaction.followUp({
content,
});
} else {
await interaction.channel?.send({
content,
});
}
});
// Live update
syncedLyrics.subscribe();
return await interaction.followUp({
content: `🎤 | ${loc.get("c_lyrics4")}`,
ephemeral: true,
});
}
if (data && data.length > 0 && data[0].plainLyrics !== null) {
const title = data[0]; const title = data[0];
const limit_desc = 4096; const limit_desc = 4096;
const nb_embed = Math.ceil(title.plainLyrics.length / limit_desc); const nb_embed = Math.ceil(title.plainLyrics.length / limit_desc);

View file

@ -181,7 +181,6 @@ export default {
delay, delay,
player.search(query, { player.search(query, {
requestedBy: interaction.user, requestedBy: interaction.user,
searchEngine: "spotifySearch",
}), }),
]) ])
.then((res) => { .then((res) => {

View file

@ -96,6 +96,7 @@ export default {
const queue = useQueue(interaction.guildId ?? ""); const queue = useQueue(interaction.guildId ?? "");
const embed = new EmbedBuilder(); const embed = new EmbedBuilder();
const rows = [];
if (queue) { if (queue) {
const subcommand = interaction.options.getSubcommand(); const subcommand = interaction.options.getSubcommand();
@ -109,7 +110,6 @@ export default {
embedListQueue(client, embed, queue, page, interaction.locale); embedListQueue(client, embed, queue, page, interaction.locale);
const rows = [];
const idPrec = "queueList-prec_" + uuidv4(); const idPrec = "queueList-prec_" + uuidv4();
const idNext = "queueList-next_" + uuidv4(); const idNext = "queueList-next_" + uuidv4();
rows.push( rows.push(
@ -128,17 +128,11 @@ export default {
), ),
); );
const message = await interaction.reply({
embeds: [embed],
components: rows,
fetchReply: true,
});
// Buttons interactions // Buttons interactions
collect(client, interaction, idPrec, message); collect(client, interaction, idPrec);
collect(client, interaction, idNext, message); collect(client, interaction, idNext);
return; break;
} }
// Shuffle Queue // Shuffle Queue
@ -172,6 +166,6 @@ export default {
embed.setDescription(loc.get("c_queue2")); embed.setDescription(loc.get("c_queue2"));
} }
return await interaction.reply({ embeds: [embed] }); return await interaction.reply({ embeds: [embed], components: rows });
}, },
}; };

View file

@ -1,11 +1,4 @@
import { import { Client, EmbedBuilder, GuildMember, Message, TextBasedChannel } from "discord.js";
ChannelType,
Client,
EmbedBuilder,
GuildMember,
Message,
TextBasedChannel,
} from "discord.js";
import { getLocale } from "../../utils/locales"; import { getLocale } from "../../utils/locales";
import { isImage, userWithNickname } from "../../utils/misc"; import { isImage, userWithNickname } from "../../utils/misc";
import { showDate } from "../../utils/time"; import { showDate } from "../../utils/time";
@ -171,8 +164,7 @@ export default async (message: Message, client: Client) => {
if ( if (
!message.content.replace(new RegExp(regex, "g"), "").trim() && !message.content.replace(new RegExp(regex, "g"), "").trim() &&
messages.length === urls.length && messages.length === urls.length &&
!message.mentions.repliedUser && !message.mentions.repliedUser
message.channel.type !== ChannelType.GroupDM
) { ) {
message.delete(); message.delete();
return message.channel.send({ embeds: [embed] }); return message.channel.send({ embeds: [embed] });

View file

@ -1,6 +1,6 @@
import { EmbedBuilder } from "@discordjs/builders"; import { EmbedBuilder } from "@discordjs/builders";
import { GuildQueue, Track } from "discord-player"; import { GuildQueue, Track } from "discord-player";
import { ChannelType, 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";
@ -19,8 +19,5 @@ export default (queue: GuildQueue<Metadata>, track: Track, client: Client) => {
} via ${track.source.capitalize()}`, } via ${track.source.capitalize()}`,
iconURL: emojiPng("🎶"), iconURL: emojiPng("🎶"),
}); });
if (queue.metadata.channel?.type !== ChannelType.GroupDM) {
queue.metadata?.channel?.send({ embeds: [embed] }); queue.metadata?.channel?.send({ embeds: [embed] });
}
}; };

View file

@ -134,14 +134,10 @@
"c_lyrics_name": "lyrics", "c_lyrics_name": "lyrics",
"c_lyrics_desc": "Displays the lyrics of a song", "c_lyrics_desc": "Displays the lyrics of a song",
"c_lyrics_sub3_name": "synced",
"c_lyrics_sub3_desc": "Synchronized lyrics search (updates in live)",
"c_lyrics_opt1_name": "song", "c_lyrics_opt1_name": "song",
"c_lyrics_opt1_desc": "Wanted song", "c_lyrics_opt1_desc": "Wanted song",
"c_lyrics1": "The bot is not playing anything at the moment and no songs are specified.", "c_lyrics1": "The bot is not playing anything at the moment and no songs are specified.",
"c_lyrics2": "Unable to find the lyrics for", "c_lyrics2": "Unable to find the lyrics for",
"c_lyrics3": "Impossible to find synchronized lyrics for",
"c_lyrics4": "It's karaoke time!",
"c_repeat_name": "repeat", "c_repeat_name": "repeat",
"c_repeat_desc": "Command for the type of music repetition", "c_repeat_desc": "Command for the type of music repetition",

View file

@ -141,14 +141,10 @@
"c_lyrics_sub1_desc": "Recherche de paroles", "c_lyrics_sub1_desc": "Recherche de paroles",
"c_lyrics_sub2_name": "romanized", "c_lyrics_sub2_name": "romanized",
"c_lyrics_sub2_desc": "Recherche de paroles romanisée (ex: hangul -> latin)", "c_lyrics_sub2_desc": "Recherche de paroles romanisée (ex: hangul -> latin)",
"c_lyrics_sub3_name": "synced",
"c_lyrics_sub3_desc": "Recherche de paroles synchronisée (se met à jour avec la chanson en direct)",
"c_lyrics_opt1_name": "chanson", "c_lyrics_opt1_name": "chanson",
"c_lyrics_opt1_desc": "Chanson recherchée", "c_lyrics_opt1_desc": "Chanson recherchée",
"c_lyrics1": "Le bot ne joue rien en ce moment et aucune chanson n'est renseignée.", "c_lyrics1": "Le bot ne joue rien en ce moment et aucune chanson n'est renseignée.",
"c_lyrics2": "Impossible de trouver les paroles pour", "c_lyrics2": "Impossible de trouver les paroles pour",
"c_lyrics3": "Impossible de trouver les paroles synchronisées pour",
"c_lyrics4": "C'est parti !",
"c_repeat_name": "repeat", "c_repeat_name": "repeat",
"c_repeat_desc": "Commande relative à la répétition des musiques", "c_repeat_desc": "Commande relative à la répétition des musiques",

View file

@ -4,7 +4,6 @@ import { readFileSync } from "fs";
import { Database } from "sqlite3"; import { Database } from "sqlite3";
import "../modules/client"; import "../modules/client";
import { loadLocales } from "./locales"; import { loadLocales } from "./locales";
import { YoutubeiExtractor } from "discord-player-youtubei";
/** Creation of the client and definition of its properties. */ /** Creation of the client and definition of its properties. */
export default async () => { export default async () => {
@ -45,8 +44,7 @@ export default async () => {
quality: "highestaudio", quality: "highestaudio",
}, },
}); });
await player.extractors.loadDefault((ext) => ext !== "YouTubeExtractor"); await player.extractors.loadDefault();
await player.extractors.register(YoutubeiExtractor, {});
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,4 +1,4 @@
import { ChannelType, Client, Colors, EmbedBuilder, User } from "discord.js"; import { Client, Colors, EmbedBuilder, User } from "discord.js";
import { getLocale } from "./locales"; import { getLocale } from "./locales";
import { cleanCodeBlock } from "./misc"; import { cleanCodeBlock } from "./misc";
import { showDate, strToSeconds, timeDeltaToString } from "./time"; import { showDate, strToSeconds, timeDeltaToString } from "./time";
@ -169,7 +169,7 @@ export const sendReminder = (client: Client, info: infoReminder, option: OptionR
} else { } else {
// Channel // Channel
client.channels.fetch(info.channelId ?? "").then((channel) => { client.channels.fetch(info.channelId ?? "").then((channel) => {
if (channel?.isTextBased() && channel.type !== ChannelType.GroupDM) { if (channel?.isTextBased()) {
let content = `<@${info.userId}>`; let content = `<@${info.userId}>`;
embed.setFooter({ embed.setFooter({
text: `${loc.get("c_reminder17")} ${timeDeltaToString(info.createdAt)}`, text: `${loc.get("c_reminder17")} ${timeDeltaToString(info.createdAt)}`,