Réécriture complète en Typescript

This commit is contained in:
Angels-dev
2024-01-14 22:53:06 +01:00
parent 6ffa521888
commit 07d54abdba
108 changed files with 2477 additions and 1943 deletions

14
.dockerignore Normal file → Executable file
View File

@@ -1,9 +1,7 @@
**/.dockerignore .dockerignore
**/.git .git
**/.gitattributes .gitignore
**/.gitignore .vscode
**/.vscode Dockerfile
**/docker-compose* node_modules
**/Dockerfile*
**/node_modules
README.md README.md

View File

@@ -1,9 +0,0 @@
{
"parserOptions": {
"ecmaVersion": "latest"
},
"env": {
"es6": true
}
}

63
.gitattributes vendored
View File

@@ -1,63 +0,0 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

6
.gitignore vendored Normal file → Executable file
View File

@@ -1,4 +1,4 @@
node_modules/ node_modules/
.env public/cracks/
cracks/ dist/
stronger_shorter.mp3 .env*

167
.npmrc
View File

@@ -1,167 +0,0 @@
;;;;
; npm projectconfig file: C:\Users\Zachary\source\repos\Discord\.npmrc
; this is a simple ini-formatted file
; lines that start with semi-colons are comments
; run `npm help 7 config` for documentation of the various options
;
; Configs like `@scope:registry` map a scope to a given registry url.
;
; Configs like `//<hostname>/:_authToken` are auth that is restricted
; to the registry host specified.
;;;;
; all available options shown below with default values
;;;;
; _auth=null
; access=null
; all=false
; allow-same-version=false
; also=null
; audit=true
; audit-level=null
; auth-type=web
; before=null
; bin-links=true
; browser=null
; ca=null
; cache=C:\Users\Zachary\AppData\Local/npm-cache
; cache-max=null
; cache-min=0
; cafile=null
; call=
; cert=null
; ci-name=null
; cidr=null
; color=true
; commit-hooks=true
; depth=null
; description=true
; dev=false
;
; diff-ignore-all-space=false
; diff-name-only=false
; diff-no-prefix=false
; diff-dst-prefix=b/
; diff-src-prefix=a/
; diff-text=false
; diff-unified=3
; dry-run=false
; editor=C:\Windows\notepad.exe
; engine-strict=false
; fetch-retries=2
; fetch-retry-factor=10
; fetch-retry-maxtimeout=60000
; fetch-retry-mintimeout=10000
; fetch-timeout=300000
; force=false
; foreground-scripts=false
; format-package-lock=true
; fund=true
; git=git
; git-tag-version=true
; global=false
; globalconfig=
; global-style=false
; heading=npm
; https-proxy=null
; if-present=false
; ignore-scripts=false
;
; include-staged=false
; include-workspace-root=false
; init-author-email=
; init-author-name=
; init-author-url=
; init-license=ISC
; init-module=~/.npm-init.js
; init-version=1.0.0
; init.author.email=
; init.author.name=
; init.author.url=
; init.license=ISC
; init.module=~/.npm-init.js
; init.version=1.0.0
; install-links=true
; install-strategy=hoisted
; json=false
; key=null
; legacy-bundling=false
; legacy-peer-deps=false
; link=false
; local-address=null
; location=user
; lockfile-version=null
; loglevel=notice
; logs-dir=null
; logs-max=10
; long=false
; maxsockets=15
; message=%s
; node-options=null
; noproxy=
; offline=false
;
; omit-lockfile-registry-resolved=false
; only=null
; optional=null
; otp=null
;
; package-lock=true
; package-lock-only=false
; pack-destination=.
; parseable=false
; prefer-offline=false
; prefer-online=false
; prefix=
; preid=
; production=null
; progress=true
; proxy=null
; read-only=false
; rebuild-bundle=true
; registry=https://registry.npmjs.org/
; replace-registry-host=npmjs
; save=true
; save-bundle=false
; save-dev=false
; save-exact=false
; save-optional=false
; save-peer=false
; save-prefix=^
; save-prod=false
; scope=
; script-shell=null
; searchexclude=
; searchlimit=20
; searchopts=
; searchstaleness=900
; shell=C:\Windows\system32\cmd.exe
; shrinkwrap=true
; sign-git-commit=false
; sign-git-tag=false
; strict-peer-deps=false
; strict-ssl=true
; tag=latest
; tag-version-prefix=v
; timing=false
; tmp=C:\Users\Zachary\AppData\Local\Temp
; umask=0
; unicode=false
; update-notifier=true
; usage=false
; user-agent=npm/{npm-version} node/{node-version} {platform} {arch} workspaces/{workspaces} {ci}
; userconfig=~/.npmrc
; version=false
; versions=false
; viewer=browser
; which=null
;
; workspaces=null
; workspaces-update=true
; yes=null
msvs_version=2022

43
.vscode/launch.json vendored Normal file → Executable file
View File

@@ -7,20 +7,43 @@
{ {
"type": "node", "type": "node",
"request": "launch", "request": "launch",
"name": "Launch", "name": "Nodemon",
"program": "${workspaceFolder}/app.js", "skipFiles": ["<node_internals>/**"],
"skipFiles": [ "runtimeExecutable": "nodemon",
"<node_internals>/**" "console": "integratedTerminal",
] "internalConsoleOptions": "neverOpen",
"restart": true
}, },
{ {
"type": "node", "type": "node",
"request": "launch", "request": "launch",
"name": "Nodemon", "name": "Nodemon Tamiseur",
"program": "${workspaceFolder}/app.js", "args": ["-r", "dotenv/config", "${workspaceFolder}/src/index.ts", "dotenv_config_path=${workspaceFolder}/.env1"],
"skipFiles": [ "skipFiles": ["<node_internals>/**"],
"<node_internals>/**" "runtimeExecutable": "nodemon",
], "console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"restart": true
},
{
"type": "node",
"request": "launch",
"name": "Nodemon Groove",
"args": ["-r", "dotenv/config", "${workspaceFolder}/src/index.ts", "dotenv_config_path=${workspaceFolder}/.env2"],
"skipFiles": ["<node_internals>/**"],
"runtimeExecutable": "nodemon",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"restart": true
},
{
"type": "node",
"request": "launch",
"name": "Nodemon Funky",
"args": ["-r", "dotenv/config", "${workspaceFolder}/src/index.ts", "dotenv_config_path=${workspaceFolder}/.env3"],
"skipFiles": ["<node_internals>/**"],
"runtimeExecutable": "nodemon", "runtimeExecutable": "nodemon",
"console": "integratedTerminal", "console": "integratedTerminal",
"internalConsoleOptions": "neverOpen", "internalConsoleOptions": "neverOpen",

3
.vscode/settings.json vendored Executable file
View File

@@ -0,0 +1,3 @@
{
"docker.commands.build": "${containerCommand} build --rm -f \"${dockerfile}\" --target tamiseur -t bot_tamiseur:tamiseur \"${context}\" && ${containerCommand} build --rm -f \"${dockerfile}\" --target funky -t bot_tamiseur:funky \"${context}\" && ${containerCommand} build --rm -f \"${dockerfile}\" --target groove -t bot_tamiseur:groove \"${context}\"",
}

28
.vscode/tasks.json vendored
View File

@@ -1,28 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "docker-build",
"label": "Build Node Image",
"platform": "node",
"dockerBuild": {
"dockerfile": "${workspaceFolder}/Dockerfile",
"context": "${workspaceFolder}",
"pull": true
}
},
{
"type": "docker-run",
"label": "Run Node Image",
"platform": "node",
"dockerRun": {
"containerName": "BotDiscord-Tamiseur",
"restart": "always",
"network": "host"
},
"dependsOn": [
"docker-build"
]
}
]
}

23
Dockerfile Normal file → Executable file
View File

@@ -1,11 +1,28 @@
FROM node:latest FROM node:alpine as base
ENV NODE_ENV=production ENV NODE_ENV=production
WORKDIR /usr/src/app WORKDIR /usr/src/app
COPY ["package.json", "package-lock.json*", "./"] COPY ["package.json", "package-lock.json*", "./"]
RUN apt-get update RUN apk add --no-cache ffmpeg python3 make g++
RUN apt-get -y install ffmpeg
RUN npm install --production --verbose && mv node_modules ../ RUN npm install --production --verbose && mv node_modules ../
COPY . . COPY . .
RUN chown -R node /usr/src/app RUN chown -R node /usr/src/app
USER node USER node
FROM base as tamiseur
RUN mv .env1 .env
RUN rm .env2 .env3
CMD ["npm", "start"] CMD ["npm", "start"]
FROM base as funky
RUN mv .env2 .env
RUN rm .env1 .env3
CMD ["npm", "start"]
FROM base as groove
RUN mv .env3 .env
RUN rm .env1 .env2
CMD ["npm", "start"]

67
app.js
View File

@@ -1,67 +0,0 @@
// PACKAGES
const { Client, Collection, GatewayIntentBits, REST, Routes } = require('discord.js')
const { YouTubeExtractor, SpotifyExtractor } = require('@discord-player/extractor')
const { Player } = require('discord-player')
const fs = require('fs')
require('dotenv').config()
// CLIENT INITIALIZATION
let intents = [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildVoiceStates]
const client = new Client({ intents })
// EVENTS HANDLING
const eventFiles = fs.readdirSync('./events').filter(file => file.endsWith('.js'))
for (file of eventFiles) {
let event = require(`./events/${file}`)
if (event.once) client.once(event.name, (...args) => { event.execute(...args) })
else client.on(event.name, (...args) => { event.execute(...args) })
}
// COMMANDS HANDLING
client.commands = new Collection()
let commands = []
const commandFolders = fs.readdirSync('./commands')
for (folder of commandFolders) {
let folderPath = `./commands/${folder}`
let commandFiles = fs.readdirSync(folderPath).filter(file => file.endsWith('.js'))
for (file of commandFiles) {
let command = require(`${folderPath}/${file}`)
if ('data' in command && 'execute' in command) { commands.push(command.data.toJSON()); client.commands.set(command.data.name, command) }
else console.log(`\u001b[1;35m [WARNING] The command at ${`${folderPath}/${file}`} is missing a required "data" or "execute" property.`)
}
}
// COMMANDS REGISTERING
const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);
(async () => {
try { await rest.put(Routes.applicationCommands(process.env.DISCORD_APP_ID), { body: commands }) }
catch (error) { console.error(error) }
})()
// BUTTONS HANDLING
client.buttons = new Collection()
const buttonFiles = fs.readdirSync('./buttons').filter(file => file.endsWith('.js'))
for (file of buttonFiles) {
let button = require(`./buttons/${file}`)
if ('id' in button && 'execute' in button) client.buttons.set(button.id, button)
else console.log(`\u001b[1;35m [WARNING] The button ${file} is missing a required "id" or "execute" property.`)
}
// PLAYER INITIALIZATION
const player = new Player(client, { autoRegisterExtractor: false })
player.extractors.register(YouTubeExtractor)
player.extractors.register(SpotifyExtractor)
// PLAYER EVENTS HANDLING
const eventPlayerFiles = fs.readdirSync('./eventsPlayer').filter(file => file.endsWith('.js'))
for (file of eventPlayerFiles) {
let event = require(`./eventsPlayer/${file}`)
if (['debug'].includes(event.name)) continue
player.events.on(event.name, (...args) => event.execute(...args))
}
// LAUNCH
client.login()

View File

@@ -1,10 +0,0 @@
const { useQueue } = require('discord-player')
module.exports = {
id: 'pause',
async execute(interaction) {
let queue = useQueue(interaction.guild.id)
await queue.node.setPaused(!queue.node.isPaused())
return interaction.followUp({ content: 'Musique mise en pause !', ephemeral: true })
}
}

View File

@@ -1,10 +0,0 @@
const { useHistory } = require('discord-player')
module.exports = {
id: 'previous',
async execute(interaction) {
let history = useHistory(interaction.guild.id)
await history.previous()
return interaction.followUp({ content: 'Musique précédente jouée !', ephemeral: true })
}
}

View File

@@ -1,10 +0,0 @@
const { useQueue } = require('discord-player')
module.exports = {
id: 'resume',
async execute(interaction) {
let queue = useQueue(interaction.guild.id)
await queue.node.setPaused(!queue.node.isPaused())
return interaction.followUp({ content: 'Musique reprise !', ephemeral: true })
}
}

View File

@@ -1,10 +0,0 @@
const { useQueue } = require('discord-player')
module.exports = {
id: 'shuffle',
async execute(interaction) {
let queue = useQueue(interaction.guild.id)
await queue.tracks.shuffle()
return interaction.followUp({ content: 'File d\'attente mélangée !', ephemeral: true })
}
}

View File

@@ -1,10 +0,0 @@
const { useQueue } = require('discord-player')
module.exports = {
id: 'skip',
async execute(interaction) {
let queue = useQueue(interaction.guild.id)
await queue.node.skip()
return interaction.followUp({ content: 'Musique passée !', ephemeral: true })
}
}

View File

@@ -1,10 +0,0 @@
const { useQueue } = require('discord-player')
module.exports = {
id: 'stop',
async execute(interaction) {
let queue = useQueue(interaction.guild.id)
await queue.delete()
return interaction.followUp({ content: 'Musique arrêtée !', ephemeral: true })
}
}

View File

@@ -1,11 +0,0 @@
const { useQueue } = require('discord-player')
module.exports = {
id: 'volume_down',
async execute(interaction) {
let queue = useQueue(interaction.guild.id)
let volume = queue.node.volume - 10
await queue.node.setVolume(volume)
return interaction.followUp({ content: `🔉 | Volume modifié à ${volume}% !`, ephemeral: true })
}
}

View File

@@ -1,11 +0,0 @@
const { useQueue } = require('discord-player')
module.exports = {
id: 'volume_up',
async execute(interaction) {
let queue = useQueue(interaction.guild.id)
let volume = queue.node.volume + 10
await queue.node.setVolume(volume)
return interaction.followUp({ content: `🔊 | Volume modifié à ${volume}% !`, ephemeral: true })
}
}

View File

@@ -1,58 +0,0 @@
const { SlashCommandBuilder, EmbedBuilder, hyperlink } = require('discord.js')
const fs = require('fs')
const appDir = require('path').dirname(require.main.filename)
require('require-all')(appDir + '/utilsCrack')
module.exports = {
data: new SlashCommandBuilder().setName('crack').setDescription('Télécharge un crack sur le site online-fix.me !')
.addStringOption(option => option.setName('jeu').setDescription('Quel jeu tu veux DL ?').setRequired(true)),
async execute(interaction) {
await interaction.deferReply()
let query = interaction.options.getString('jeu')
let games = await search(query, headers.h1)
if (!Array.isArray(games)) {
if (games.toString() == "TypeError: Cannot read properties of undefined (reading 'split')") return interaction.followUp({ content: `J'ai rien trouvé pour "${query}" !` })
else return interaction.followUp({ content: "Une erreur s'est produite ! ```" + games + "```" })
}
let game
if (games.length > 1) {
games = games.slice(0, 9)
let list = ''
for (let i = 0; i < games.length; i++) list += `\n${i + 1}. ${games[i].name} (${games[i].link})`
let message = await interaction.followUp({ content: `J'ai trouvé plusieurs jeux pour "${query}" ! ${list}` })
let emojis = ['1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣']
for (let i = 0; i < games.length; i++) await message.react(emojis[i])
// Wait for a reaction to be added by the interaction author.
const filter = (reaction, user) => {
return emojis.includes(reaction.emoji.name) && user.id === interaction.user.id
}
let collected = await message.awaitReactions({ filter, max: 1, time: 5000, errors: ['time'] })
.catch(() => { return interaction.followUp({ content: 'T\'as mis trop de temps à choisir !' }) })
console.log(collected)
if (!collected.first) return
let reaction = collected.first()
let index = emojis.indexOf(reaction.emoji.name)
game = games[index]
}
else game = games[0]
let url = await repo(game, headers.h2)
let file = await torrent(url, headers.h2)
let path = await download(url, file, headers.h2)
let link = await magnet(path)
let embed = new EmbedBuilder()
.setColor('#ffc370')
.setTitle(game.name)
.setURL(game.link)
.setDescription(`Voici ce que j'ai trouvé pour "${query}".\nTu peux aussi cliquer sur [ce lien](https://angels-dev.fr/magnet/${link}) pour pouvoir télécharger le jeu direct !`)
await interaction.followUp({ embeds: [embed], files: [path] })
//fs.unlink(path, (err) => { if (err) throw err })
}
}

View File

@@ -1,28 +0,0 @@
const { SlashCommandBuilder } = require('discord.js')
const { getVoiceConnection, joinVoiceChannel } = require('@discordjs/voice')
module.exports = {
data: new SlashCommandBuilder()
.setName('papa')
.setDescription('Si papa m\'appelle, je le rejoins !'),
async execute(interaction) {
if (interaction.user.id !== '223831938346123275') return interaction.reply({ content: 'T\'es pas mon père, dégage !' })
let botChannel = interaction.guild.members.me.voice.channel
let papaChannel = interaction.member.voice.channel
if (!papaChannel && botChannel) {
getVoiceConnection(botChannel.guild.id).destroy()
return interaction.reply({ content: 'Je quitte le vocal, papa !' })
}
else if (!botChannel || botChannel.id !== papaChannel.id) {
joinVoiceChannel({
channelId: papaChannel.id,
guildId: papaChannel.guild.id,
adapterCreator: papaChannel.guild.voiceAdapterCreator,
})
return interaction.reply({ content: 'Je rejoins ton vocal, papa !' })
}
else return interaction.reply({ content: 'Je suis déjà dans ton vocal, papa !' })
}
}

View File

@@ -1,13 +0,0 @@
const { SlashCommandBuilder } = require('discord.js')
const { useQueue } = require('discord-player')
module.exports = {
data: new SlashCommandBuilder()
.setName('pause')
.setDescription('Met en pause la musique.'),
async execute(interaction) {
let queue = useQueue(interaction.guild.id)
queue.node.setPaused(!queue.node.isPaused())
return await interaction.reply('Musique mise en pause !')
}
}

View File

@@ -1,15 +0,0 @@
const { SlashCommandBuilder } = require('discord.js')
const appDir = require('path').dirname(require.main.filename)
const generatePlayer = require(appDir + '/utilsPlayer/generate.js')
module.exports = {
data: new SlashCommandBuilder()
.setName('player')
.setDescription('Afficher une interface de contrôle de la musique.'),
async execute(interaction) {
let { embed, components } = await generatePlayer(interaction.guild)
if (!components) return await interaction.reply({ embeds: [embed] })
else return await interaction.reply({ embeds: [embed], components })
}
}

View File

@@ -1,13 +0,0 @@
const { SlashCommandBuilder } = require('discord.js')
const { useHistory } = require('discord-player')
module.exports = {
data: new SlashCommandBuilder()
.setName('previous')
.setDescription('Joue la musique précédente.'),
async execute(interaction) {
let history = useHistory(interaction.guild.id)
await history.previous()
return await interaction.reply('Musique précédente jouée !')
}
}

View File

@@ -1,13 +0,0 @@
const { SlashCommandBuilder } = require('discord.js')
const { useQueue } = require('discord-player')
module.exports = {
data: new SlashCommandBuilder()
.setName('resume')
.setDescription('Reprendre la musique.'),
async execute(interaction) {
let queue = useQueue(interaction.guild.id)
queue.node.setPaused(!queue.node.isPaused())
return await interaction.reply('Musique reprise !')
}
}

View File

@@ -1,13 +0,0 @@
const { SlashCommandBuilder } = require('discord.js')
const { useQueue } = require('discord-player')
module.exports = {
data: new SlashCommandBuilder()
.setName('shuffle')
.setDescription('Mélange la file d\'attente.'),
async execute(interaction) {
let queue = useQueue(interaction.guild.id)
queue.tracks.shuffle()
return await interaction.reply('File d\'attente mélangée !')
}
}

View File

@@ -1,13 +0,0 @@
const { SlashCommandBuilder } = require('discord.js')
const { useQueue } = require('discord-player')
module.exports = {
data: new SlashCommandBuilder()
.setName('skip')
.setDescription('Passer la musique en cours.'),
async execute(interaction) {
let queue = useQueue(interaction.guild.id)
queue.node.skip()
return await interaction.reply('Musique passée !')
}
}

View File

@@ -1,19 +0,0 @@
const { SlashCommandBuilder } = require('discord.js')
const { useQueue } = require('discord-player')
module.exports = {
data: new SlashCommandBuilder()
.setName('stop')
.setDescription('Arrêter la musique.'),
async execute(interaction) {
let queue = useQueue(interaction.guild.id)
queue.delete()
writeEnv('DISCORD_MUSIC_TEXTCHANNEL_ID', '')
writeEnv('DISCORD_MUSIC_VOICECHANNEL_ID', '')
writeEnv('DISCORD_MUSIC_CURRENT_TRACK', '')
writeEnv('DISCORD_MUSIC_CURRENT_PROGRESS', '')
return await interaction.reply('Musique arrêtée !')
}
}

View File

@@ -1,30 +0,0 @@
const { Events } = require('discord.js')
require('dotenv').config()
const appDir = require('path').dirname(require.main.filename)
const replay = require(appDir + '/utilsPlayer/replay.js')
const disco = require(appDir + '/utilsPlayer/disco.js')
//const { DataTypes } = require("sequelize")
//const sequelize = require('../utils/initSequelize.js')
module.exports = {
name: Events.ClientReady,
once: true,
async execute(client) {
console.log(`\u001b[1;35m Ready! Logged in as ${client.user.tag}`)
// Check if a music session was active before the bot was restarted
if (process.env.DISCORD_MUSIC_CURRENT_TRACK) await replay(client)
//try {
// sequelize.authenticate()
// console.log('Connection has been established successfully.')
//} catch (error) { console.error('Unable to connect to the database:', error) }
var interval = setInterval(async () => {
let state = await disco(client)
if (state === 'clear') clearInterval(interval)
}, 2000)
}
}

View File

@@ -1,7 +0,0 @@
module.exports = {
name: 'audioTracksAdd',
async execute(queue, track) {
// Emitted when the player adds multiple songs to its queue
queue.metadata.channel.send(`Ajout de ${track.length} musiques à la file d'attente !`)
}
}

View File

@@ -1,7 +0,0 @@
module.exports = {
name: 'emptyQueue',
async execute(queue, track) {
// Emitted when the player queue has finished
queue.metadata.channel.send("File d'attente vide !")
}
}

View File

@@ -1,8 +0,0 @@
module.exports = {
name: 'error',
async execute(queue, error) {
// Emitted when the player queue encounters error
console.log(`\u001b[1;31m General player error event: ${error.message}`)
console.error(error)
}
}

View File

@@ -1,7 +0,0 @@
module.exports = {
name: 'playerSkip',
async execute(queue, track) {
// Emitted when the audio player fails to load the stream for a song
queue.metadata.channel.send(`Musique **${track.title}** de **${track.author}** passée !`)
}
}

View File

@@ -1,9 +0,0 @@
module.exports = {
name: 'playerStart',
async execute(queue, track) {
// Emitted when the player starts to play a song
writeEnv('DISCORD_MUSIC_CURRENT_TRACK', track.url)
queue.metadata.channel.send(`Lecture de **${track.title}** de **${track.author}** !`)
}
}

2281
package-lock.json generated Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +1,41 @@
{ {
"name": "bot_tamiseur", "name": "bot_tamiseur",
"version": "1.0.0", "description": "Listen to music and use fun commands with your friends!",
"description": "bot_Tamiseur", "version": "2.0.0",
"main": "app.js",
"scripts": {
"format": "prettier --write .",
"start": "node app.js",
"dev": "nodemon -e js"
},
"author": { "author": {
"name": "Zachary Guénot" "name": "Zachary Guénot"
}, },
"devDependencies": { "main": "src/index.ts",
"eslint": "^8.42.0", "scripts": {
"nodemon": "^2.0.22", "format": "prettier --write .",
"prettier": "^2.8.8" "start": "node src/index.ts",
"dev": "nodemon -e ts src/index.ts",
"build": "tsc"
}, },
"eslintConfig": {},
"dependencies": { "dependencies": {
"@discord-player/equalizer": "^0.2.1", "@discord-player/equalizer": "^0.2.3",
"@discord-player/extractor": "^4.3.1", "@discord-player/extractor": "^4.4.6",
"@discordjs/opus": "^0.9.0", "@discordjs/opus": "^0.9.0",
"@discordjs/voice": "^0.16.0", "@discordjs/voice": "^0.16.1",
"axios": "^1.4.0", "axios": "^1.6.5",
"bufferutil": "^4.0.7", "bufferutil": "^4.0.8",
"discord-player": "^6.5.0", "discord-player": "^6.6.7",
"discord.js": "^14.11.0", "discord.js": "^14.14.1",
"dotenv": "^16.1.4", "dotenv": "^16.3.1",
"iconv-lite": "^0.6.3", "iconv-lite": "^0.6.3",
"libsodium-wrappers": "^0.7.11", "jsdom": "^23.2.0",
"mariadb": "^3.1.2", "libsodium-wrappers": "^0.7.13",
"opusscript": "^0.0.8", "mariadb": "^3.2.3",
"parse-torrent": "^11.0.12", "parse-torrent": "^9.1.5",
"play-dl": "^1.9.6",
"prism-media": "^1.3.5",
"require-all": "^3.0.0", "require-all": "^3.0.0",
"sequelize": "^6.32.0", "sqlite3": "^5.1.7",
"sqlite3": "^5.1.6", "utf-8-validate": "^6.0.3",
"utf-8-validate": "^6.0.3" "youtube-ext": "^1.1.16"
},
"devDependencies": {
"@types/parse-torrent": "^5.8.7",
"eslint": "^8.56.0",
"nodemon": "^3.0.2",
"prettier": "^3.2.1"
} }
} }

11
buttons/loop.js → src/buttons/loop.ts Normal file → Executable file
View File

@@ -1,9 +1,14 @@
const { useQueue } = require('discord-player') import { ButtonInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
module.exports = { module.exports = {
id: 'loop', id: 'loop',
async execute(interaction) { async execute(interaction: ButtonInteraction) {
let queue = useQueue(interaction.guild.id) let guild = interaction.guild
if (!guild) return
let queue = useQueue(guild.id)
if (!queue) return
let loop = queue.repeatMode === 0 ? 1 : queue.repeatMode === 1 ? 2 : queue.repeatMode === 2 ? 3 : 0 let loop = queue.repeatMode === 0 ? 1 : queue.repeatMode === 1 ? 2 : queue.repeatMode === 2 ? 3 : 0
await queue.setRepeatMode(loop) await queue.setRepeatMode(loop)
await interaction.followUp({ content:`Boucle ${loop === 0 ? 'désactivée' : loop === 1 ? 'en mode Titre' : loop === 2 ? 'en mode File d\'Attente' : 'en autoplay'}.`, ephemeral: true }) await interaction.followUp({ content:`Boucle ${loop === 0 ? 'désactivée' : loop === 1 ? 'en mode Titre' : loop === 2 ? 'en mode File d\'Attente' : 'en autoplay'}.`, ephemeral: true })

15
src/buttons/pause.ts Executable file
View File

@@ -0,0 +1,15 @@
import { ButtonInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
module.exports = {
id: 'pause',
async execute(interaction: ButtonInteraction) {
let guild = interaction.guild
if (!guild) return
let queue = useQueue(guild.id)
if (!queue) return
await queue.node.setPaused(!queue.node.isPaused())
return interaction.followUp({ content: 'Musique mise en pause !', ephemeral: true })
}
}

15
src/buttons/previous.ts Executable file
View File

@@ -0,0 +1,15 @@
import { ButtonInteraction } from 'discord.js'
import { useHistory } from 'discord-player'
module.exports = {
id: 'previous',
async execute(interaction: ButtonInteraction) {
let guild = interaction.guild
if (!guild) return
let history = useHistory(guild.id)
if (!history) return
await history.previous()
return interaction.followUp({ content: 'Musique précédente jouée !', ephemeral: true })
}
}

15
src/buttons/resume.ts Executable file
View File

@@ -0,0 +1,15 @@
import { ButtonInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
module.exports = {
id: 'resume',
async execute(interaction: ButtonInteraction) {
let guild = interaction.guild
if (!guild) return
let queue = useQueue(guild.id)
if (!queue) return
await queue.node.setPaused(!queue.node.isPaused())
return interaction.followUp({ content: 'Musique reprise !', ephemeral: true })
}
}

15
src/buttons/shuffle.ts Executable file
View File

@@ -0,0 +1,15 @@
import { ButtonInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
module.exports = {
id: 'shuffle',
async execute(interaction: ButtonInteraction) {
let guild = interaction.guild
if (!guild) return
let queue = useQueue(guild.id)
if (!queue) return
await queue.tracks.shuffle()
return interaction.followUp({ content: 'File d\'attente mélangée !', ephemeral: true })
}
}

15
src/buttons/skip.ts Executable file
View File

@@ -0,0 +1,15 @@
import { ButtonInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
module.exports = {
id: 'skip',
async execute(interaction: ButtonInteraction) {
let guild = interaction.guild
if (!guild) return
let queue = useQueue(guild.id)
if (!queue) return
await queue.node.skip()
return interaction.followUp({ content: 'Musique passée !', ephemeral: true })
}
}

15
src/buttons/stop.ts Executable file
View File

@@ -0,0 +1,15 @@
import { ButtonInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
module.exports = {
id: 'stop',
async execute(interaction: ButtonInteraction) {
let guild = interaction.guild
if (!guild) return
let queue = useQueue(guild.id)
if (!queue) return
await queue.delete()
return interaction.followUp({ content: 'Musique arrêtée !', ephemeral: true })
}
}

16
src/buttons/volume_down.ts Executable file
View File

@@ -0,0 +1,16 @@
import { ButtonInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
module.exports = {
id: 'volume_down',
async execute(interaction: ButtonInteraction) {
let guild = interaction.guild
if (!guild) return
let queue = useQueue(guild.id)
if (!queue) return
let volume = queue.node.volume - 10
await queue.node.setVolume(volume)
return interaction.followUp({ content: `🔉 | Volume modifié à ${volume}% !`, ephemeral: true })
}
}

16
src/buttons/volume_up.ts Executable file
View File

@@ -0,0 +1,16 @@
import { ButtonInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
module.exports = {
id: 'volume_up',
async execute(interaction: ButtonInteraction) {
let guild = interaction.guild
if (!guild) return
let queue = useQueue(guild.id)
if (!queue) return
let volume = queue.node.volume + 10
await queue.node.setVolume(volume)
return interaction.followUp({ content: `🔊 | Volume modifié à ${volume}% !`, ephemeral: true })
}
}

83
commands/global/amp.js → src/commands/global/amp.ts Normal file → Executable file
View File

@@ -1,12 +1,34 @@
const { SlashCommandBuilder, EmbedBuilder, inlineCode } = require('discord.js') import { SlashCommandBuilder, ChatInputCommandInteraction, AutocompleteInteraction, EmbedBuilder, inlineCode } from 'discord.js'
const dotenv = require('dotenv') import * as AMP from '../../utils/amp'
dotenv.config() import 'dotenv/config'
const appDir = require('path').dirname(require.main.filename) interface ListInstancesResult {
const API = require('require-all')(appDir + '/utilsAMP') status: string
data: {
result: [
Host: {
AvailableInstances: any[]
FriendlyName: string
}
]
}
}
interface InstanceFields {
name: string
value: string
inline: boolean
}
function failMsg(data) { return `La commande a échouée !\n${inlineCode(`${data.Title}: ${data.Message}`)}` } interface failData {
function errorMsg(data) { return `Y'a eu une erreur !\n${inlineCode(`${data.error_code}`)}` } Title: string
Message: string
}
interface errorData {
error_code: string
}
function failMsg(data: any) { return `La commande a échouée !\n${inlineCode(`${data.Title}: ${data.Message}`)}` }
function errorMsg(data: any) { return `Y'a eu une erreur !\n${inlineCode(`${data.error_code}`)}` }
module.exports = { module.exports = {
data: new SlashCommandBuilder().setName('amp').setDescription('Accède à mon panel de jeu AMP !') data: new SlashCommandBuilder().setName('amp').setDescription('Accède à mon panel de jeu AMP !')
@@ -25,12 +47,13 @@ module.exports = {
/*.addSubcommand(subcommand => subcommand.setName('restart').setDescription('Redémarre une instance.') /*.addSubcommand(subcommand => subcommand.setName('restart').setDescription('Redémarre une instance.')
.addStringOption(option => option.setName('name').setDescription("Nom de l'instance").setRequired(true)))*/), .addStringOption(option => option.setName('name').setDescription("Nom de l'instance").setRequired(true)))*/),
async autocompleteRun(interaction) { async autocompleteRun(interaction: AutocompleteInteraction) {
let query = interaction.options.getString('instance', true) let query = interaction.options.getString('instance', true)
// Check if the SessionID is still valid // Check if the SessionID is still valid
let sessionID = dotenv.config().parsed.AMP_SESSIONID //let sessionID = dotenv.config().parsed.AMP_SESSIONID
let session = await API.CheckSession(sessionID) let sessionID = process.env.AMP_SESSIONID as string
let session = await AMP.CheckSession(sessionID)
if (session.status === 'fail') { if (session.status === 'fail') {
if (process.env.AMP_REMEMBER_TOKEN) { if (process.env.AMP_REMEMBER_TOKEN) {
// Refresh the SessionID if the RememberMeToken is available // Refresh the SessionID if the RememberMeToken is available
@@ -40,7 +63,7 @@ module.exports = {
token: process.env.AMP_REMEMBER_TOKEN, token: process.env.AMP_REMEMBER_TOKEN,
rememberMe: true rememberMe: true
} }
let result = await API.Core.Login(details) let result = await AMP.Core.Login(details)
console.log(result) console.log(result)
if (result.status === 'success') sessionID = result.data.sessionID if (result.status === 'success') sessionID = result.data.sessionID
else if (result.status === 'fail') return interaction.respond([]) else if (result.status === 'fail') return interaction.respond([])
@@ -48,17 +71,18 @@ module.exports = {
} }
else { else {
// If no RememberMeToken is available, ask to login // If no RememberMeToken is available, ask to login
return await interaction.followUp(`Tu dois te connecter avant d'effectuer une autre commande !`) //return await interaction.followUp(`Tu dois te connecter avant d'effectuer une autre commande !`)
return await interaction.respond([])
} }
} }
else if (session.status === 'error') return interaction.respond([]) else if (session.status === 'error') return interaction.respond([])
let choices = [] let choices: any = []
let result = await API.ADSModule.GetInstances(sessionID) let result = await AMP.ADSModule.GetInstances(sessionID)
if (result.status === 'success') { if (result.status === 'success') {
let hosts = result.data.result let hosts = result.data.result as any[]
hosts.forEach(host => { hosts.forEach(host => {
let instances = host.AvailableInstances let instances = host.AvailableInstances as any[]
instances.forEach(instance => { instances.forEach(instance => {
if (instance.FriendlyName.includes(query)) choices.push({ name: `${host.FriendlyName} - ${instance.FriendlyName}`, value: instance.InstanceID }) if (instance.FriendlyName.includes(query)) choices.push({ name: `${host.FriendlyName} - ${instance.FriendlyName}`, value: instance.InstanceID })
}) })
@@ -69,7 +93,7 @@ module.exports = {
return interaction.respond(choices) return interaction.respond(choices)
}, },
async execute(interaction) { async execute(interaction: ChatInputCommandInteraction) {
// Let the user login // Let the user login
if (interaction.options.getSubcommand() == 'login') { if (interaction.options.getSubcommand() == 'login') {
// Get a SessionID and a RememberMeToken if wanted // Get a SessionID and a RememberMeToken if wanted
@@ -82,7 +106,7 @@ module.exports = {
rememberMe: interaction.options.getBoolean('remember') rememberMe: interaction.options.getBoolean('remember')
} }
let result = await API.Core.Login(details) let result = await AMP.Core.Login(details)
if (result.status === 'success') return await interaction.followUp(`Tu es connecté au panel sous **${result.data.userInfo.Username}** !`) if (result.status === 'success') return await interaction.followUp(`Tu es connecté au panel sous **${result.data.userInfo.Username}** !`)
else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data)) else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data))
else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data)) else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data))
@@ -90,8 +114,9 @@ module.exports = {
await interaction.deferReply() await interaction.deferReply()
// Check if the SessionID is still valid // Check if the SessionID is still valid
let sessionID = dotenv.config().parsed.AMP_SESSIONID //let sessionID = dotenv.config().parsed.AMP_SESSIONID
let session = await API.CheckSession(sessionID) let sessionID = process.env.AMP_SESSIONID as string
let session = await AMP.CheckSession(sessionID)
if (session.status === 'fail') { if (session.status === 'fail') {
console.log(session) console.log(session)
@@ -103,7 +128,7 @@ module.exports = {
token: process.env.AMP_REMEMBER_TOKEN, token: process.env.AMP_REMEMBER_TOKEN,
rememberMe: true rememberMe: true
} }
let result = await API.Core.Login(details) let result = await AMP.Core.Login(details)
console.log(result) console.log(result)
if (result.status === 'success') sessionID = result.data.sessionID if (result.status === 'success') sessionID = result.data.sessionID
else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data)) else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data))
@@ -118,12 +143,12 @@ module.exports = {
if (interaction.options.getSubcommandGroup() == 'instances') { if (interaction.options.getSubcommandGroup() == 'instances') {
if (interaction.options.getSubcommand() == 'list') { if (interaction.options.getSubcommand() == 'list') {
let result = await API.ADSModule.GetInstances(sessionID) let result = await AMP.ADSModule.GetInstances(sessionID) as ListInstancesResult
if (result.status === 'success') { if (result.status === 'success') {
await interaction.followUp({ content: `${result.data.result.length} hôtes trouvés !` }) await interaction.followUp({ content: `${result.data.result.length} hôtes trouvés !` })
result.data.result.forEach(async host => { result.data.result.forEach(async host => {
let fields = [] let fields = [] as InstanceFields[]
host.AvailableInstances.forEach(instance => { host.AvailableInstances.forEach(instance => {
fields.push({ fields.push({
name: instance.FriendlyName, name: instance.FriendlyName,
@@ -134,10 +159,10 @@ module.exports = {
let embed = new EmbedBuilder() let embed = new EmbedBuilder()
.setTitle(host.FriendlyName) .setTitle(host.FriendlyName)
.setDescription(`Liste des ${host.AvailableInstances.length} instances :`) .setDescription(`Liste des ${host.AvailableInstances.length} instances :`)
.setColor(interaction.guild.members.me.displayColor) .setColor(interaction.guild?.members.me?.displayColor || '#ffc370')
.setTimestamp() .setTimestamp()
.setFields(fields) .setFields(fields)
return await interaction.channel.send({ embeds: [embed] }) return await interaction.channel?.send({ embeds: [embed] })
}) })
} }
else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data)) else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data))
@@ -145,10 +170,10 @@ module.exports = {
} }
else if (interaction.options.getSubcommand() == 'manage') { else if (interaction.options.getSubcommand() == 'manage') {
let instanceID = interaction.options.getString('instance', true) let instanceID = interaction.options.getString('instance', true)
let result = await API.ADSModule.ManageInstance(sessionID, instanceID) let result = await AMP.ADSModule.ManageInstance(sessionID, instanceID)
if (result.status === 'success') { if (result.status === 'success') {
let server = await API.ADSModule.Servers(sessionID, instanceID) let server = await AMP.ADSModule.Servers(sessionID, instanceID)
console.log(server) console.log(server)
if (server.status === 'success') return await interaction.followUp(`Ok !`) if (server.status === 'success') return await interaction.followUp(`Ok !`)
@@ -160,7 +185,9 @@ module.exports = {
} }
else if (interaction.options.getSubcommand() == 'restart') { else if (interaction.options.getSubcommand() == 'restart') {
let query = interaction.options.getString('name') let query = interaction.options.getString('name')
let result = await API.ADSModule.RestartInstance(sessionID, query) if (!query) return
let result = await AMP.ADSModule.RestartInstance(sessionID, query)
if (result.status === 'success') return await interaction.followUp(`Ok !`) if (result.status === 'success') return await interaction.followUp(`Ok !`)
else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data)) else if (result.status === 'fail') return await interaction.followUp(failMsg(result.data))

58
src/commands/global/crack.ts Executable file
View File

@@ -0,0 +1,58 @@
import { SlashCommandBuilder, EmbedBuilder, ChatInputCommandInteraction, MessageReaction, User }from 'discord.js'
import * as crack from '../../utils/crack'
module.exports = {
data: new SlashCommandBuilder().setName('crack').setDescription('Télécharge un crack sur le site online-fix.me !')
.addStringOption(option => option.setName('jeu').setDescription('Quel jeu tu veux DL ?').setRequired(true)),
async execute(interaction: ChatInputCommandInteraction) {
await interaction.deferReply()
let query = interaction.options.getString('jeu')
if (!query) return
let games = await crack.search(query) as crack.Game[]
if (!Array.isArray(games)) {
//if (games.toString() == "TypeError: Cannot read properties of undefined (reading 'split')") return interaction.followUp({ content: `J'ai rien trouvé pour "${query}" !` })
//else return interaction.followUp({ content: "Une erreur s'est produite ! ```" + games + "```" })
return interaction.followUp({ content: `J'ai rien trouvé pour "${query}" !` })
}
let game = {} as crack.Game
if (games.length > 1) {
games = games.slice(0, 9)
let list = ''
for (let i = 0; i < games.length; i++) list += `\n${i + 1}. ${games[i].name} (${games[i].link})`
let message = await interaction.followUp({ content: `J'ai trouvé plusieurs jeux pour "${query}" ! ${list}` })
let emojis = ['1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣']
for (let i = 0; i < games.length; i++) await message.react(emojis[i])
// Wait for a reaction to be added by the interaction author.
const filter: any = (reaction: MessageReaction, user: User) => { if (reaction.emoji.name) return emojis.includes(reaction.emoji.name) && user.id === interaction.user.id }
await message.awaitReactions({ filter, max: 1, time: 5000, errors: ['time'] }).then(collected => {
console.log(collected)
if (!collected.first) return
let reaction = collected.first()
let index = emojis.indexOf(reaction?.emoji.name ?? '')
game = games[index]
}).catch(() => { return interaction.followUp({ content: 'T\'as mis trop de temps à choisir !' }) })
}
else game = games[0]
let url = await crack.repo(game)
if (!url) return
let file = await crack.torrent(url)
if (!file) return
let filePath = await crack.download(url, file)
if (!filePath) return
let link = await crack.magnet(filePath)
let embed = new EmbedBuilder()
.setColor('#ffc370')
.setTitle(game.name)
.setURL(game.link)
.setDescription(`Voici ce que j'ai trouvé pour "${query}".\nTu peux aussi cliquer sur [ce lien](https://angels-dev.fr/magnet/${link}) pour pouvoir télécharger le jeu direct !`)
await interaction.followUp({ embeds: [embed], files: [filePath] })
}
}

34
src/commands/global/papa.ts Executable file
View File

@@ -0,0 +1,34 @@
import { SlashCommandBuilder, ChatInputCommandInteraction, GuildMember } from 'discord.js'
import { getVoiceConnection, joinVoiceChannel } from '@discordjs/voice'
module.exports = {
data: new SlashCommandBuilder()
.setName('papa')
.setDescription('Si papa m\'appelle, je le rejoins !'),
async execute(interaction: ChatInputCommandInteraction) {
if (interaction.user.id !== '223831938346123275') return interaction.reply({ content: 'T\'es pas mon père, dégage !' })
let guild = interaction.guild
if (!guild) return interaction.reply({ content: 'Je ne peux pas rejoindre ton vocal en message privé, papa !' })
let member = interaction.member as GuildMember
let botChannel = guild.members.me?.voice.channel
let papaChannel = member.voice.channel
if (!papaChannel && botChannel) {
const voiceConnection = getVoiceConnection(guild.id);
if (voiceConnection) voiceConnection.destroy()
return interaction.reply({ content: 'Je quitte le vocal, papa !' })
}
else if (papaChannel && (!botChannel || botChannel.id !== papaChannel.id)) {
joinVoiceChannel({
channelId: papaChannel.id,
guildId: papaChannel.guild.id,
adapterCreator: papaChannel.guild.voiceAdapterCreator,
})
return interaction.reply({ content: 'Je rejoins ton vocal, papa !' })
}
else return interaction.reply({ content: 'Je suis déjà dans ton vocal, papa !' })
}
}

View File

@@ -1,21 +1,26 @@
const { SlashCommandBuilder } = require('discord.js') import { SlashCommandBuilder, ChatInputCommandInteraction, GuildMember } from 'discord.js'
const { joinVoiceChannel, createAudioPlayer, createAudioResource, AudioPlayerStatus, EndBehaviorType } = require('@discordjs/voice') import { joinVoiceChannel, createAudioPlayer, createAudioResource, AudioPlayerStatus, EndBehaviorType } from '@discordjs/voice'
const appDir = require('path').dirname(require.main.filename)
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName('parle') .setName('parle')
.setDescription('Fais moi parler par dessus quelqu\'un de chiant dans le vocal') .setDescription('Fais moi parler par dessus quelqu\'un de chiant dans le vocal')
.addUserOption(option => option.setName('user').setDescription('La personne en question').setRequired(true)), .addUserOption(option => option.setName('user').setDescription('La personne en question').setRequired(true)),
async execute(interaction) { async execute(interaction: ChatInputCommandInteraction) {
if (interaction.user.id !== '223831938346123275') return await interaction.reply({ content: 'Tu n\'as pas le droit d\'utiliser cette commande !', ephemeral: true }) if (interaction.user.id !== '223831938346123275') return await interaction.reply({ content: 'Tu n\'as pas le droit d\'utiliser cette commande !', ephemeral: true })
let user = interaction.options.getUser('user') let user = interaction.options.getUser('user')
let member = interaction.guild.members.cache.get(user.id) if (!user) return
let guild = interaction.guild
if (!guild) return
let member = guild.members.cache.get(user.id) as GuildMember
if (!member) return
let caller = interaction.member as GuildMember
if (!caller) return
if (!interaction.member.voice.channel) return await interaction.reply({ content: 'You must be in a voice channel to use this command.', ephemeral: true }) if (!caller.voice.channel) return await interaction.reply({ content: 'You must be in a voice channel to use this command.', ephemeral: true })
if (!member.voice.channel) return await interaction.reply({ content: 'The member must be in a voice channel to use this command.', ephemeral: true }) if (!member.voice.channel) return await interaction.reply({ content: 'The member must be in a voice channel to use this command.', ephemeral: true })
if (interaction.member.voice.channelId !== member.voice.channelId) return await interaction.reply({ content: 'You must be in the same voice channel than the member to use this command.', ephemeral: true }) if (caller.voice.channelId !== member.voice.channelId) return await interaction.reply({ content: 'You must be in the same voice channel than the member to use this command.', ephemeral: true })
await interaction.reply({ content: 'Je vais parler par dessus cette personne !', ephemeral: true }) await interaction.reply({ content: 'Je vais parler par dessus cette personne !', ephemeral: true })
@@ -45,26 +50,27 @@ module.exports = {
player.on(AudioPlayerStatus.Idle, () => { playing = false }) player.on(AudioPlayerStatus.Idle, () => { playing = false })
let connection = joinVoiceChannel({ let connection = joinVoiceChannel({
channelId: interaction.member.voice.channelId, channelId: caller.voice.channelId as string,
guildId: interaction.guildId, guildId: interaction.guildId as string,
adapterCreator: interaction.guild.voiceAdapterCreator, adapterCreator: guild.voiceAdapterCreator,
selfDeaf: false selfDeaf: false
}) })
connection.subscribe(player) connection.subscribe(player)
let stream = connection.receiver.subscribe(user.id, { end: { behavior: EndBehaviorType.Manual } }) let stream = connection.receiver.subscribe(user.id, { end: { behavior: EndBehaviorType.Manual } })
stream.on('data', (chunk) => { stream.on('data', (chunk) => {
if (!user) return
if (connection.receiver.speaking.users.has(user.id) && !playing) { if (connection.receiver.speaking.users.has(user.id) && !playing) {
playing = true playing = true
let resource = createAudioResource(appDir + '/parle.mp3', { inlineVolume: true }) let resource = createAudioResource('../../static/parle.mp3', { inlineVolume: true })
//let resource = createAudioResource(file.attachments.first().url, { inlineVolume: true }) //let resource = createAudioResource(file.attachments.first().url, { inlineVolume: true })
resource.volume.setVolume(0.2) if (resource.volume) resource.volume.setVolume(0.2)
player.play(resource) player.play(resource)
} }
}) })
interaction.client.on('voiceStateUpdate', (oldState, newState) => { interaction.client.on('voiceStateUpdate', (oldState, newState) => {
if (oldState.id === member.id && newState.channelId !== interaction.member.voice.channelId) { if (oldState.id === member.id && newState.channelId !== caller.voice.channelId) {
stream.destroy() stream.destroy()
connection.disconnect() connection.disconnect()
} }

View File

@@ -1,10 +1,10 @@
const { SlashCommandBuilder } = require('discord.js') import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName('ping') .setName('ping')
.setDescription('Check the latency of the bot'), .setDescription('Check the latency of the bot'),
async execute(interaction) { async execute(interaction: ChatInputCommandInteraction) {
let sent = await interaction.reply({ content: 'Pinging...', fetchReply: true }) let sent = await interaction.reply({ content: 'Pinging...', fetchReply: true })
interaction.editReply(`Websocket heartbeat: ${interaction.client.ws.ping}ms.\nRoundtrip latency: ${sent.createdTimestamp - interaction.createdTimestamp}ms`) interaction.editReply(`Websocket heartbeat: ${interaction.client.ws.ping}ms.\nRoundtrip latency: ${sent.createdTimestamp - interaction.createdTimestamp}ms`)
} }

View File

@@ -1,4 +1,4 @@
const { SlashCommandBuilder } = require('discord.js') import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
@@ -7,14 +7,18 @@ module.exports = {
.addUserOption(option => option.setName('user').setDescription('Spam').setRequired(true)) .addUserOption(option => option.setName('user').setDescription('Spam').setRequired(true))
.addStringOption(option => option.setName('string').setDescription('Spam').setRequired(true)) .addStringOption(option => option.setName('string').setDescription('Spam').setRequired(true))
.addIntegerOption(option => option.setName('integer').setDescription('Spam').setRequired(true)), .addIntegerOption(option => option.setName('integer').setDescription('Spam').setRequired(true)),
async execute(interaction) { async execute(interaction: ChatInputCommandInteraction) {
let user = interaction.options.getUser('user') let user = interaction.options.getUser('user')
let string = interaction.options.getString('string') let string = interaction.options.getString('string')
let integer = interaction.options.getInteger('integer') let integer = interaction.options.getInteger('integer')
await interaction.reply({ content: 'Spam', ephemeral: true }) await interaction.reply({ content: 'Spam', ephemeral: true })
let i = 0 let i = 0
function myLoop() { function myLoop() {
setTimeout(function () { setTimeout(function () {
if (!user) return
if (!string) return
if (!integer) return
user.send(string).catch(error => console.error(error)) user.send(string).catch(error => console.error(error))
i++ i++
if (i < integer) myLoop() if (i < integer) myLoop()

View File

@@ -1,15 +1,17 @@
const { SlashCommandBuilder } = require('discord.js') import { SlashCommandBuilder, ChatInputCommandInteraction, Guild } from 'discord.js'
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName('update') .setName('update')
.setDescription('Update the member count channel.'), .setDescription('Update the member count channel.'),
async execute(interaction) { async execute(interaction: ChatInputCommandInteraction) {
let guild = interaction.guild let guild = interaction.guild as Guild
guild.members.fetch().then(() => { guild.members.fetch().then(() => {
var i = 0 var i = 0
guild.members.cache.forEach(async member => { if (!member.user.bot) i++ }) guild.members.cache.forEach(async member => { if (!member.user.bot) i++ })
let channel = guild.channels.cache.get('1091140609139560508') let channel = guild.channels.cache.get('1091140609139560508')
if (!channel) return
channel.setName(`${i} Gens Posés`) channel.setName(`${i} Gens Posés`)
interaction.reply(`${i} Gens Posés !`) interaction.reply(`${i} Gens Posés !`)
}).catch(console.error) }).catch(console.error)

View File

@@ -1,5 +1,5 @@
const { SlashCommandBuilder } = require('discord.js') import { ChatInputCommandInteraction, SlashCommandBuilder } from 'discord.js'
const { useQueue } = require('discord-player') import { useQueue } from'discord-player'
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
@@ -10,10 +10,12 @@ module.exports = {
.setRequired(true) .setRequired(true)
.setMinValue(0) .setMinValue(0)
.setMaxValue(3)), .setMaxValue(3)),
async execute(interaction) { async execute(interaction: ChatInputCommandInteraction) {
let loop = interaction.options.getInteger('loop') let loop = interaction.options.getInteger('loop')
let queue = useQueue(interaction.guild.id) let queue = useQueue(interaction.guild?.id ?? '')
queue.setRepeatMode(loop) 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'}.`) return await interaction.reply(`Boucle ${loop === 0 ? 'désactivée' : loop === 1 ? 'en mode Titre' : loop === 2 ? 'en mode File d\'Attente' : 'en autoplay'}.`)
} }
} }

View File

@@ -1,18 +1,18 @@
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js') import { ChatInputCommandInteraction, SlashCommandBuilder, EmbedBuilder } from 'discord.js'
const { useQueue } = require('discord-player') import { useQueue } from 'discord-player'
const { lyricsExtractor } = require('@discord-player/extractor') import { lyricsExtractor } from '@discord-player/extractor'
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName('lyrics') .setName('lyrics')
.setDescription('Rechercher les paroles d\'une musique.') .setDescription('Rechercher les paroles d\'une musique.')
.addStringOption(option => option.setName('recherche').setDescription('Chercher une musique spécifique')), .addStringOption(option => option.setName('recherche').setDescription('Chercher une musique spécifique')),
async execute(interaction) { async execute(interaction: ChatInputCommandInteraction) {
await interaction.deferReply() await interaction.deferReply()
let query = interaction.options.getString('recherche', false) let query = interaction.options.getString('recherche', false)
if (!query) { if (!query) {
let queue = useQueue(interaction.guild.id) let queue = useQueue(interaction.guild?.id ?? '')
if (!queue) return interaction.followUp({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' }) if (!queue) return interaction.followUp({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' })
let track = queue.currentTrack let track = queue.currentTrack
if (!track) return interaction.followUp({ content: 'Aucune musique en cours, recherche en une plutôt !' }) if (!track) return interaction.followUp({ content: 'Aucune musique en cours, recherche en une plutôt !' })

15
src/commands/player/pause.ts Executable file
View File

@@ -0,0 +1,15 @@
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
module.exports = {
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 !')
}
}

View File

@@ -1,16 +1,19 @@
const { SlashCommandBuilder } = require('discord.js') import { SlashCommandBuilder, ChatInputCommandInteraction, AutocompleteInteraction, GuildMember } from 'discord.js'
const { useMasterPlayer, useQueue, QueryType } = require('discord-player') import { useMainPlayer, useQueue, QueryType } from 'discord-player'
import writeEnv from '../../utils/writeEnv'
export interface TrackSearchResult { name: string, value: string }
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName('play') .setName('play')
.setDescription('Jouer une musique.') .setDescription('Jouer une musique.')
.addStringOption(option => option.setName('recherche').setDescription('Titre de la musique à chercher').setRequired(true).setAutocomplete(true)), .addStringOption(option => option.setName('recherche').setDescription('Titre de la musique à chercher').setRequired(true).setAutocomplete(true)),
async autocompleteRun(interaction) { async autocompleteRun(interaction: AutocompleteInteraction) {
let query = interaction.options.getString('recherche', true) let query = interaction.options.getString('recherche', true)
if (!query) return interaction.respond([]) if (!query) return interaction.respond([])
let player = useMasterPlayer() let player = useMainPlayer()
const resultsYouTube = await player.search(query, { searchEngine: QueryType.YOUTUBE }) const resultsYouTube = await player.search(query, { searchEngine: QueryType.YOUTUBE })
const resultsSpotify = await player.search(query, { searchEngine: QueryType.SPOTIFY_SEARCH }) const resultsSpotify = await player.search(query, { searchEngine: QueryType.SPOTIFY_SEARCH })
@@ -24,27 +27,28 @@ module.exports = {
value: t.url value: t.url
})) }))
const tracks = [] const tracks: TrackSearchResult[] = []
tracksYouTube.forEach((t) => tracks.push({ name: t.name, value: t.value })); tracksYouTube.forEach((t) => tracks.push({ name: t.name, value: t.value }))
tracksSpotify.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) return interaction.respond(tracks)
}, },
async execute(interaction) { async execute(interaction: ChatInputCommandInteraction) {
let voiceChannel = interaction.member.voice.channel let member = interaction.member as GuildMember
if (!voiceChannel) return await interaction.reply({ content: "T'es pas dans un vocal, idiot !", ephemeral: true }) 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 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 }) if (botChannel && voiceChannel.id !== botChannel.id) return await interaction.reply({ content: 'T\'es pas dans mon vocal !', ephemeral: true })
await interaction.deferReply() await interaction.deferReply()
let query = interaction.options.getString('recherche', true) let query = interaction.options.getString('recherche', true)
let player = useMasterPlayer() let player = useMainPlayer()
let queue = useQueue(interaction.guild.id) let queue = useQueue(interaction.guild?.id ?? '')
if (!queue) { if (!queue) {
queue = player.nodes.create(interaction.guild, { if (interaction.guild) queue = player.nodes.create(interaction.guild, {
metadata: { metadata: {
channel: interaction.channel, channel: interaction.channel,
client: interaction.guild.members.me, client: interaction.guild.members.me,
@@ -53,32 +57,35 @@ module.exports = {
selfDeaf: true, selfDeaf: true,
volume: 20, volume: 20,
leaveOnEmpty: true, leaveOnEmpty: true,
leaveOnEmptyCooldown: 300000, leaveOnEmptyCooldown: 30000,
leaveOnEnd: true, leaveOnEnd: true,
leaveOnEndCooldown: 300000, leaveOnEndCooldown: 300000
skipOnNoStream: true
}) })
else return
} }
try { if (!queue.connection) await queue.connect(voiceChannel) } try { if (!queue.connection) await queue.connect(voiceChannel) }
catch (error) { console.error(error); return interaction.followUp(`Y'a eu un problème, <@223831938346123275> ! (${error.message})`) } catch (error: any) { console.error(error); return interaction.followUp(`Y'a eu un problème, <@223831938346123275> ! (${error.message})`) }
// Write the values in the .env file to recover the player if the bot restarts
writeEnv('DISCORD_MUSIC_TEXTCHANNEL_ID', interaction.channel?.id ?? '')
writeEnv('DISCORD_MUSIC_VOICECHANNEL_ID', voiceChannel.id)
// Search the song
let result = await player.search(query, { requestedBy: interaction.user }) let result = await player.search(query, { requestedBy: interaction.user })
if (!result.hasTracks()) return interaction.followUp(`Aucune musique trouvée pour **${query}** !`) if (!result.hasTracks()) return interaction.followUp(`Aucune musique trouvée pour **${query}** !`)
let track = result.tracks[0] let track = result.tracks[0]
console.log(track.duration)
console.log(track.durationMS)
let entry = queue.tasksQueue.acquire() let entry = queue.tasksQueue.acquire()
await entry.getTask() await entry.getTask()
queue.addTrack(track) queue.addTrack(track)
// Write the values in the .env file to recover the player if the bot restarts
writeEnv('DISCORD_MUSIC_TEXTCHANNEL_ID', interaction.channel.id)
writeEnv('DISCORD_MUSIC_VOICECHANNEL_ID', voiceChannel.id)
try { try {
if (!queue.isPlaying()) await queue.node.play() if (!queue.isPlaying()) await queue.node.play()
let track_source = track.source === 'youtube' ? 'Youtube' : track.source === 'spotify' ? 'Spotify' : 'Inconnu' 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}**...`) return interaction.followUp(`Chargement de la musique **${track.title}** de **${track.author}** sur **${track_source}**...`)
} catch (error) { console.error(error); return interaction.followUp(`Y'a eu un problème, <@223831938346123275> ! (${error.message})`) } } catch (error: any) { console.error(error); return interaction.followUp(`Y'a eu un problème, <@223831938346123275> ! (${error.message})`) }
finally { queue.tasksQueue.release() } finally { queue.tasksQueue.release() }
} }
} }

15
src/commands/player/previous.ts Executable file
View File

@@ -0,0 +1,15 @@
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'
import { useHistory } from 'discord-player'
module.exports = {
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 !')
}
}

15
src/commands/player/resume.ts Executable file
View File

@@ -0,0 +1,15 @@
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
module.exports = {
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 !')
}
}

15
src/commands/player/shuffle.ts Executable file
View File

@@ -0,0 +1,15 @@
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
module.exports = {
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 !')
}
}

15
src/commands/player/skip.ts Executable file
View File

@@ -0,0 +1,15 @@
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
module.exports = {
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 !')
}
}

21
src/commands/player/stop.ts Executable file
View File

@@ -0,0 +1,21 @@
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'
import { useQueue } from 'discord-player'
import writeEnv from '../../utils/writeEnv'
module.exports = {
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()
writeEnv('DISCORD_MUSIC_TEXTCHANNEL_ID', '')
writeEnv('DISCORD_MUSIC_VOICECHANNEL_ID', '')
writeEnv('DISCORD_MUSIC_CURRENT_TRACK', '')
writeEnv('DISCORD_MUSIC_CURRENT_PROGRESS', '')
return await interaction.reply('Musique arrêtée !')
}
}

View File

@@ -1,5 +1,5 @@
const { SlashCommandBuilder } = require('discord.js') import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'
const { useQueue } = require('discord-player') import { useQueue } from 'discord-player'
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
@@ -10,10 +10,12 @@ module.exports = {
.setRequired(true) .setRequired(true)
.setMinValue(1) .setMinValue(1)
.setMaxValue(100)), .setMaxValue(100)),
async execute(interaction) { async execute(interaction: ChatInputCommandInteraction) {
let volume = interaction.options.getInteger('volume') let volume = interaction.options.getInteger('volume')
let queue = useQueue(interaction.guild.id) let queue = useQueue(interaction.guild?.id ?? '')
queue.node.setVolume(volume) 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}% !`) return await interaction.reply(`Volume modifié à ${volume}% !`)
} }
} }

4
events/error.js → src/events/error.ts Normal file → Executable file
View File

@@ -1,8 +1,8 @@
const { Events } = require('discord.js') import { Events } from 'discord.js'
module.exports = { module.exports = {
name: Events.Error, name: Events.Error,
execute(error) { execute(error: any) {
console.error(error) console.error(error)
} }
} }

View File

@@ -1,13 +1,15 @@
const { Events } = require('discord.js') import { Events, GuildMember } from 'discord.js'
module.exports = { module.exports = {
name: Events.GuildMemberAdd, name: Events.GuildMemberAdd,
async execute(member) { async execute(member: GuildMember) {
if (member.guild.id !== '1086577543651524699') return if (member.guild.id !== '1086577543651524699') return
member.guild.members.fetch().then(() => { member.guild.members.fetch().then(() => {
var i = 0 var i = 0
member.guild.members.cache.forEach(async member => { if (!member.user.bot) i++ }) member.guild.members.cache.forEach(async member => { if (!member.user.bot) i++ })
let channel = member.guild.channels.cache.get('1091140609139560508') let channel = member.guild.channels.cache.get('1091140609139560508')
if (!channel) return
console.log(channel.name) console.log(channel.name)
console.log(`${i} Gens Posés`) console.log(`${i} Gens Posés`)
channel.setName('Changement...') channel.setName('Changement...')

View File

@@ -1,13 +1,15 @@
const { Events } = require('discord.js') import { Events, GuildMember } from 'discord.js'
module.exports = { module.exports = {
name: Events.GuildMemberRemove, name: Events.GuildMemberRemove,
async execute(member) { async execute(member: GuildMember) {
if (member.guild.id !== '1086577543651524699') return if (member.guild.id !== '1086577543651524699') return
member.guild.members.fetch().then(() => { member.guild.members.fetch().then(() => {
var i = 0 var i = 0
member.guild.members.cache.forEach(async member => { if (!member.user.bot) i++ }) member.guild.members.cache.forEach(async member => { if (!member.user.bot) i++ })
let channel = member.guild.channels.cache.get('1091140609139560508') let channel = member.guild.channels.cache.get('1091140609139560508')
if (!channel) return
console.log(channel.name) console.log(channel.name)
console.log(`${i} Gens Posés`) console.log(`${i} Gens Posés`)
channel.setName('Changement...') channel.setName('Changement...')

View File

@@ -1,37 +1,38 @@
const { Events } = require('discord.js') import { Events, Interaction, ChatInputCommandInteraction, AutocompleteInteraction, ButtonInteraction } from 'discord.js'
import editPlayer from '../utilsPlayer/edit'
const appDir = require('path').dirname(require.main.filename) import playerButtons from '../utilsPlayer/buttons'
const editPlayer = require(appDir + '/utilsPlayer/edit.js')
const playerButtons = require(appDir + '/utilsPlayer/buttons.js')
module.exports = { module.exports = {
name: Events.InteractionCreate, name: Events.InteractionCreate,
async execute(interaction) { async execute(interaction: Interaction) {
//if (!interaction.isAutocomplete() && !interaction.isChatInputCommand() && !interaction.isButton()) return console.error(`Interaction ${interaction.commandName} is not a command.`) //if (!interaction.isAutocomplete() && !interaction.isChatInputCommand() && !interaction.isButton()) return console.error(`Interaction ${interaction.commandName} is not a command.`)
if (interaction.isChatInputCommand()) { if (interaction.isChatInputCommand()) {
let command = interaction.client.commands.get(interaction.commandName) interaction = interaction as ChatInputCommandInteraction
if (!command) return console.error(`No command matching ${interaction.commandName} was found.`) let chatInputCommand = interaction.client.commands.get(interaction.commandName)
if (!chatInputCommand) return console.error(`No chat input command matching ${interaction.commandName} was found.`)
console.log(`\u001b[1;33m Command '${interaction.commandName}' launched by ${interaction.user.tag}`) console.log(`Command '${interaction.commandName}' launched by ${interaction.user.tag}`)
try { await command.execute(interaction) } try { await chatInputCommand.execute(interaction) }
catch (error) { console.error(`Error executing ${interaction.commandName}:`, error) } catch (error) { console.error(`Error executing ${interaction.commandName}:`, error) }
} }
else if (interaction.isAutocomplete()) { else if (interaction.isAutocomplete()) {
interaction = interaction as AutocompleteInteraction
let autoCompleteRun = interaction.client.commands.get(interaction.commandName) let autoCompleteRun = interaction.client.commands.get(interaction.commandName)
if (!autoCompleteRun) return console.error(`No autoCompleteRun matching ${interaction.commandName} was found.`) if (!autoCompleteRun) return console.error(`No autoCompleteRun matching ${interaction.commandName} was found.`)
console.log(`\u001b[1;33m AutoCompleteRun '${interaction.commandName}' launched by ${interaction.user.tag}`) console.log(`AutoCompleteRun '${interaction.commandName}' launched by ${interaction.user.tag}`)
try { await autoCompleteRun.autocompleteRun(interaction) } try { await autoCompleteRun.autocompleteRun(interaction) }
catch (error) { console.error(`Error autocompleting ${interaction.commandName}:`, error) } catch (error) { console.error(`Error autocompleting ${interaction.commandName}:`, error) }
} }
else if (interaction.isButton()) { else if (interaction.isButton()) {
interaction = interaction as ButtonInteraction
let button = interaction.client.buttons.get(interaction.customId) let button = interaction.client.buttons.get(interaction.customId)
if (!button) return console.error(`No button id matching ${interaction.customId} was found.`) if (!button) return console.error(`No button id matching ${interaction.customId} was found.`)
console.log(`\u001b[1;33m Button '${interaction.customId}' clicked by ${interaction.user.tag}`) console.log(`Button '${interaction.customId}' clicked by ${interaction.user.tag}`)
if (playerButtons.includes(interaction.customId)) { await editPlayer(interaction) } if (playerButtons.includes(interaction.customId)) { await editPlayer(interaction) }

30
src/events/ready.ts Executable file
View File

@@ -0,0 +1,30 @@
import { Events, Client, ActivityType } from 'discord.js'
import { useMainPlayer } from 'discord-player'
import replay from '../utilsPlayer/replay'
import disco from '../utilsPlayer/disco'
import 'dotenv/config'
declare module "discord.js" {
export interface Client {
disco: { interval: NodeJS.Timeout }
}
}
module.exports = {
name: Events.ClientReady,
once: true,
async execute(client: Client) {
console.log(`Ready! Logged in as ${client.user?.tag ?? 'unknown'}`)
client.user?.setActivity('some bangers...', { type: ActivityType.Listening })
await useMainPlayer().extractors.loadDefault(ext => ext === 'YouTubeExtractor' || ext === 'SpotifyExtractor').then(() => console.log('YouTube and Spotify extractors loaded.')).catch(console.error)
if (process.env.DISCORD_MUSIC_CURRENT_TRACK) await replay(client)
client.disco = { interval: {} as NodeJS.Timeout }
client.disco.interval = setInterval(async () => {
let state = await disco(client)
if (state === 'clear') clearInterval(client.disco.interval)
}, 2000)
}
}

View File

@@ -1,8 +1,8 @@
const { Events, AuditLogEvent } = require('discord.js') import { Events, VoiceState } from 'discord.js'
module.exports = { module.exports = {
name: Events.VoiceStateUpdate, name: Events.VoiceStateUpdate,
async execute(oldState, newState) { async execute(oldState: VoiceState, newState: VoiceState) {
/* /*
let oldMute = oldState.serverMute let oldMute = oldState.serverMute
let newMute = newState.serverMute let newMute = newState.serverMute

View File

@@ -1,6 +1,9 @@
module.exports = { import { GuildQueue, Track } from 'discord-player'
import { PlayerMetadata } from '../utilsPlayer/metadata'
export default {
name: 'audioTrackAdd', name: 'audioTrackAdd',
async execute(queue, track) { async execute(queue: GuildQueue<PlayerMetadata>, track: Track) {
// Emitted when the player adds a single song to its queue // Emitted when the player adds a single song to its queue
queue.metadata.channel.send(`Musique **${track.title}** de **${track.author}** ajoutée à la file d'attente !`) queue.metadata.channel.send(`Musique **${track.title}** de **${track.author}** ajoutée à la file d'attente !`)
} }

View File

@@ -0,0 +1,10 @@
import { GuildQueue, Track } from 'discord-player'
import { PlayerMetadata } from '../utilsPlayer/metadata'
export default {
name: 'audioTracksAdd',
async execute(queue: GuildQueue<PlayerMetadata>, track: Array<Track>) {
// Emitted when the player adds multiple songs to its queue
queue.metadata.channel.send(`Ajout de ${track.length} musiques à la file d'attente !`)
}
}

6
eventsPlayer/debug.js → src/eventsPlayer/debug.ts Normal file → Executable file
View File

@@ -1,6 +1,8 @@
module.exports = { import { GuildQueue } from 'discord-player'
export default {
name: 'debug', name: 'debug',
async execute (queue, message) { async execute(queue: GuildQueue, message: string) {
// Emitted when the player queue sends debug info // Emitted when the player queue sends debug info
// Useful for seeing what state the current queue is at // Useful for seeing what state the current queue is at
console.log(`Player debug event: ${message}`) console.log(`Player debug event: ${message}`)

View File

@@ -1,6 +1,10 @@
module.exports = { import { GuildQueue, Track } from 'discord-player'
import { PlayerMetadata } from '../utilsPlayer/metadata'
import writeEnv from '../utils/writeEnv'
export default {
name: 'disconnect', name: 'disconnect',
async execute(queue, track) { async execute(queue: GuildQueue<PlayerMetadata>, track: Track) {
// Emitted when the bot leaves the voice channel // Emitted when the bot leaves the voice channel
queue.metadata.channel.send("J'ai quitté le vocal !") queue.metadata.channel.send("J'ai quitté le vocal !")

View File

@@ -1,6 +1,9 @@
module.exports = { import { GuildQueue, Track } from 'discord-player'
import { PlayerMetadata } from '../utilsPlayer/metadata'
export default {
name: 'emptyChannel', name: 'emptyChannel',
async execute(queue, track) { async execute(queue: GuildQueue<PlayerMetadata>, track: Track) {
// Emitted when the voice channel has been empty for the set threshold // Emitted when the voice channel has been empty for the set threshold
// Bot will automatically leave the voice channel with this event // Bot will automatically leave the voice channel with this event
queue.metadata.channel.send(`Je quitte le vocal car il est vide depuis trop longtemps.`) queue.metadata.channel.send(`Je quitte le vocal car il est vide depuis trop longtemps.`)

10
src/eventsPlayer/emptyQueue.ts Executable file
View File

@@ -0,0 +1,10 @@
import { GuildQueue, Track } from 'discord-player'
import { PlayerMetadata } from '../utilsPlayer/metadata'
export default {
name: 'emptyQueue',
async execute(queue: GuildQueue<PlayerMetadata>) {
// Emitted when the player queue has finished
queue.metadata.channel.send("File d'attente vide !")
}
}

10
src/eventsPlayer/error.ts Executable file
View File

@@ -0,0 +1,10 @@
import { GuildQueue } from 'discord-player'
export default {
name: 'error',
async execute(queue: GuildQueue, error: Error) {
// Emitted when the player queue encounters error
console.log(`General player error event: ${error.message}`)
console.error(error)
}
}

View File

@@ -1,6 +1,8 @@
module.exports = { import { GuildQueue } from 'discord-player'
export default {
name: 'playerError', name: 'playerError',
async execute(queue, error) { async execute(queue: GuildQueue, error: Error) {
// Emitted when the audio player errors while streaming audio track // Emitted when the audio player errors while streaming audio track
console.log(`\u001b[1;31m Player error event: ${error.message}`) console.log(`\u001b[1;31m Player error event: ${error.message}`)
console.error(error) console.error(error)

10
src/eventsPlayer/playerSkip.ts Executable file
View File

@@ -0,0 +1,10 @@
import { GuildQueue, Track } from 'discord-player'
import { PlayerMetadata } from '../utilsPlayer/metadata'
export default {
name: 'playerSkip',
async execute(queue: GuildQueue<PlayerMetadata>, track: Track) {
// Emitted when the audio player fails to load the stream for a song
queue.metadata.channel.send(`Musique **${track.title}** de **${track.author}** passée !`)
}
}

13
src/eventsPlayer/playerStart.ts Executable file
View File

@@ -0,0 +1,13 @@
import { GuildQueue, Track } from 'discord-player'
import { PlayerMetadata } from '../utilsPlayer/metadata'
import writeEnv from '../utils/writeEnv'
export default {
name: 'playerStart',
async execute(queue: GuildQueue<PlayerMetadata>, track: Track) {
// Emitted when the player starts to play a song
queue.metadata.channel.send(`Lecture de **${track.title}** de **${track.author}** !`)
writeEnv(`DISCORD_MUSIC_CURRENT_TRACK`, track.url)
}
}

89
src/index.ts Executable file
View File

@@ -0,0 +1,89 @@
// PACKAGES
import { Client, Collection, GatewayIntentBits, REST, Routes, ChatInputCommandInteraction, AutocompleteInteraction, ButtonInteraction } from 'discord.js'
import { Player } from 'discord-player'
import path from 'path'
import fs from 'fs'
import 'dotenv/config'
export interface Command {
name: string,
description: string,
data: any,
autocompleteRun: (interaction: AutocompleteInteraction) => any,
execute: (interaction: ChatInputCommandInteraction) => any
}
export interface Button {
name: string,
description: string,
id: string,
execute: (interaction: ButtonInteraction) => any
}
declare module 'discord.js' {
export interface Client {
commands: Collection<unknown, Command>
buttons: Collection<unknown, Button>
}
}
// CLIENT INITIALIZATION
let intents = [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildVoiceStates]
const client = new Client({ intents })
// EVENTS HANDLING
const eventFiles = fs.readdirSync(path.join(__dirname, './events')).filter(file => file.endsWith('.ts'))
eventFiles.forEach(file => {
let event = require(path.join(__dirname, './events', file))
if (event.once) client.once(event.name, (...args) => { event.execute(...args) })
else client.on(event.name, (...args) => { event.execute(...args) })
})
// COMMANDS HANDLING
client.commands = new Collection()
const commandFolders = fs.readdirSync(path.join(__dirname, './commands'))
commandFolders.forEach(folder => {
let folderPath = path.join(__dirname, './commands', folder)
let commandFiles = fs.readdirSync(folderPath).filter(file => file.endsWith('.ts'))
commandFiles.forEach(file => {
let command = require(path.join(folderPath, file))
if ('data' in command && 'execute' in command) {
const commandData = command.data.toJSON()
if (commandData) client.commands.set(commandData.name, command)
} else console.log(`[WARNING] The command at ${`${folderPath}/${file}`} is missing a required "data" or "execute" property.`)
})
})
// COMMANDS REGISTERING
const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN as string)
async () => {
try { await rest.put(Routes.applicationCommands(process.env.DISCORD_APP_ID as string), { body: client.commands }) }
catch (error) { console.error(error) }
}
// BUTTONS HANDLING
client.buttons = new Collection()
const buttonFiles = fs.readdirSync(path.join(__dirname, './buttons')).filter(file => file.endsWith('.ts'))
buttonFiles.forEach(file => {
let button = require(path.join(__dirname, './buttons', file))
if ('id' in button && 'execute' in button) client.buttons.set(button.id, button)
else console.log(`[WARNING] The button ${file} is missing a required "id" or "execute" property.`)
})
// PLAYER INITIALIZATION
const player = new Player(client)
// PLAYER EVENTS HANDLING
const eventPlayerFiles = fs.readdirSync(path.join(__dirname, './eventsPlayer')).filter(file => file.endsWith('.ts'))
eventPlayerFiles.forEach(async file => {
let event = await import(path.join(__dirname, './eventsPlayer', file))
if (event.default.name === 'debug') return
player.events.on(event.default.name, (...args: any[]) => event.default.execute(...args))
})
// LAUNCH
client.login()

0
parle.mp3 → src/static/parle.mp3 Normal file → Executable file
View File

95
src/utils/amp.ts Normal file
View File

@@ -0,0 +1,95 @@
import axios from 'axios'
import writeEnv from './writeEnv'
export const ADSModule = {
async GetInstances(SESSIONID: string) {
return await axios.post(`${process.env.AMP_HOST}/API/ADSModule/GetInstances`, {
SESSIONID
}).then(response => {
if (!response.data.result) return { status: 'fail', data: response.data }
return { status: 'success', data: response.data }
}).catch(error => {
console.error(error)
return { status: 'error', data: error }
})
},
async ManageInstance(SESSIONID: string, InstanceId: string) {
return await axios.post(`${process.env.AMP_HOST}/API/ADSModule/ManageInstance`, {
SESSIONID,
InstanceId
}).then(response => {
console.log(response.data)
if (!response.data.result) return { status: 'fail', data: response.data }
return { status: 'success', data: response.data }
}).catch(error => {
console.error(error)
return { status: 'error', data: error }
})
},
async RestartInstance(SESSIONID: string, InstanceName: string) {
return await axios.post(`${process.env.AMP_HOST}/API/ADSModule/RestartInstance`, {
SESSIONID,
InstanceName
}).then(response => {
console.log(response.data)
//if (!response.data.success) return { status: 'fail', data: response.data }
return { status: 'success', data: response.data }
}).catch(error => {
console.error(error)
return { status: 'error', data: error }
})
},
async Servers(SESSIONID: string, InstanceId: string) {
return await axios.get(`${process.env.AMP_HOST}/API/ADSModule/Servers`, {
data: {
SESSIONID,
InstanceId
}
}).then(response => {
console.log(response)
console.log(response.data)
if (!response.data.result) return { status: 'fail', data: response.data }
return { status: 'success', data: response.data }
}).catch(error => {
console.error(error)
return { status: 'error', data: error }
})
}
}
export const Core = {
async Login(details: any) {
return await axios.post(`${process.env.AMP_HOST}/API/Core/Login`,
details
).then(response => {
if (!response.data.success) return { status: 'fail', data: response.data }
writeEnv('AMP_USERNAME', response.data.userInfo.Username)
writeEnv('AMP_SESSIONID', response.data.sessionID)
writeEnv('AMP_REMEMBER_TOKEN', response.data.rememberMeToken)
return { status: 'success', data: response.data }
}).catch(error => {
console.error(error)
return { status: 'error', data: error }
})
}
}
export async function CheckSession(SESSIONID: string) {
return await axios.post(`${process.env.AMP_HOST}/API/ADSModule/GetInstances`, {
SESSIONID
}).then(response => {
if (!response.data.result) return { status: 'fail', data: response.data }
return { status: 'success', data: response.data }
}).catch(error => {
console.error(error)
return { status: 'error', data: error }
})
}

98
src/utils/crack.ts Normal file
View File

@@ -0,0 +1,98 @@
import parseTorrent, { toMagnetURI } from 'parse-torrent'
import iconv from 'iconv-lite'
import axios from 'axios'
import path from 'path'
import fs from 'fs'
export declare class Game {
name: string
link: string
}
const headers = {
h1: {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"x-requested-with": "XMLHttpRequest"
},
h2: {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7",
"cache-control": "no-cache",
"pragma": "no-cache",
"sec-ch-ua": "\"Not=A?Brand\";v=\"8\", \"Chromium\";v=\"110\", \"Opera GX\";v=\"96\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"cookie": "online_fix_auth=gAAAAABkKM0s9WNLe_V6euTnJD7UQjppVty9B7OOyHBYOyVcbcejj8F6KveBcLxlf3mlx_vE7JEFPHlrpj-Aq6BFJyKPGzxds_wpcPV2MdXPyDGQLsz4mAvt3qgTgGg25MapWo_fSIOMiAAsF4Gv_uh4kUOiR_jgbHCZWJGPgpNQwU2HFFyvahYR6MzR7nYE9-fCmrev3obkRbro43vIVTTX4UyJMRHadrsY5Q-722TzinCZVmAuJfc=; dle_password=89465c26673e0199e5272e4730772c35; _ym_uid=1670534560361937997; _ym_d=1680394955; _ym_isad=2; dle_user_id=2619796; PHPSESSID=3v8sd281sr0n1n9f1p66q25sa2",
"Referer": "https://online-fix.me/",
"Referrer-Policy": "strict-origin-when-cross-origin"
}
}
export async function search(query: string) {
let body = await fetch("https://online-fix.me/engine/ajax/search.php", { headers: headers.h1, body: `query=${query}`, method: "POST" })
.then(response => response.arrayBuffer())
.then(arrayBuffer => { return iconv.decode(Buffer.from(arrayBuffer), 'win1251') })
.catch(console.error)
try {
if (!body) return
let matches = body.split('</div>')[1].split('<span class="seperator fastfullsearch">')[0].split('</a>')
let games = [] as Game[]
matches.pop()
matches.forEach(async match => {
let name = match.split('"><span class="searchheading">')[1].split('</span>')[0].slice(0, -8)
let link = match.split('<a href="')[1].split('"><span class="searchheading">')[0]
games.push({ name, link })
})
return games
} catch (error) { return error }
}
export async function repo(game: Game) {
let body = await fetch(game.link, { headers: headers.h2, body: null, method: "GET" })
.then(response => response.arrayBuffer())
.then(arrayBuffer => { return iconv.decode(Buffer.from(arrayBuffer), 'win1251') })
.catch(console.error)
try {
if (!body) return
let name = body.split('https://uploads.online-fix.me:2053/torrents/')[1].split('"')[0]
let url = `https://uploads.online-fix.me:2053/torrents/${name}`
return url
} catch (error) { console.error(error) }
}
export async function torrent(url: string) {
let response = await fetch(url, { headers: headers.h2, body: null, method: "GET" }).catch(console.error)
try {
if (!response) return
let body = await response.text()
let file = body.split('<a href="')[2].split('">')[0]
return file
} catch (error) { console.error(error) }
}
export async function download(url: string, file: string) {
let filePath = path.join(__dirname, '../../public/cracks/', file)
let writer = fs.createWriteStream(filePath)
try {
await axios({ url: url + file, method: 'GET', responseType: 'stream', headers: headers.h2 }).then(response => {
return new Promise((resolve, reject) => {
response.data.pipe(writer)
let error = null as unknown as Error
writer.on('error', err => { error = err; writer.close(); reject(err) })
writer.on('close', () => { if (!error) resolve(true) })
})
}).catch(console.error)
return filePath
} catch (error) { console.error(error) }
}
export async function magnet(filePath: string) {
let torrentData = parseTorrent(fs.readFileSync(filePath))
let uri = toMagnetURI(torrentData)
return uri
}

5
utils/getUptime.js → src/utils/getUptime.ts Normal file → Executable file
View File

@@ -1,4 +1,7 @@
module.exports = function (uptime) { import { Client } from 'discord.js'
export default function (uptime: Client["uptime"]) {
if (!uptime) return '0J, 0H, 0M et 0S'
let days = Math.floor(uptime / 86400000) let days = Math.floor(uptime / 86400000)
let hours = Math.floor(uptime / 3600000) % 24 let hours = Math.floor(uptime / 3600000) % 24
let minutes = Math.floor(uptime / 60000) % 60 let minutes = Math.floor(uptime / 60000) % 60

4
utils/writeEnv.js → src/utils/writeEnv.ts Normal file → Executable file
View File

@@ -1,6 +1,6 @@
const fs = require('fs') import fs from 'fs'
module.exports = writeEnv = ((variable, value) => { export default ((variable: string, value: string) => {
let parsedFile = fs.readFileSync('./.env', 'utf8') let parsedFile = fs.readFileSync('./.env', 'utf8')
parsedFile = parsedFile.replace(new RegExp(`${variable} = .*`, 'g'), `${variable} = ${value}`) parsedFile = parsedFile.replace(new RegExp(`${variable} = .*`, 'g'), `${variable} = ${value}`)
fs.writeFileSync('./.env', parsedFile) fs.writeFileSync('./.env', parsedFile)

View File

View File

0
utilsAMP/Core/Login.js → src/utilsAMP/Core/Login.ts Normal file → Executable file
View File

0
utilsCrack/download.js → src/utilsCrack/download.ts Normal file → Executable file
View File

0
utilsCrack/headers.js → src/utilsCrack/headers.ts Normal file → Executable file
View File

0
utilsCrack/magnet.js → src/utilsCrack/magnet.ts Normal file → Executable file
View File

0
utilsCrack/repo.js → src/utilsCrack/repo.ts Normal file → Executable file
View File

0
utilsCrack/search.js → src/utilsCrack/search.ts Normal file → Executable file
View File

0
utilsCrack/torrent.js → src/utilsCrack/torrent.ts Normal file → Executable file
View File

1
src/utilsPlayer/buttons.ts Executable file
View File

@@ -0,0 +1 @@
export default ['loop', 'pause', 'previous', 'resume', 'shuffle', 'skip', 'stop', 'volume_down', 'volume_up']

40
src/utilsPlayer/disco.ts Executable file
View File

@@ -0,0 +1,40 @@
import { Client, TextChannel } from 'discord.js'
import { useQueue } from 'discord-player'
import getUptime from '../utils/getUptime'
import writeEnv from '../utils/writeEnv'
import generate from './generate'
export default async (client: Client) => {
let guild = client.guilds.cache.get(process.env.DISCORD_GUILD_ID as string)
if (!guild) {
clearInterval(client.disco.interval)
console.log(`Aucun serveur trouvé avec l'id \`${process.env.DISCORD_GUILD_ID}\`, veuillez utiliser la commande \`/setchannel\` !`)
return 'clear'
}
// Keep track of the music progress if the bot reboots
let queue = useQueue(guild.id)
if (queue) if (queue.isPlaying()) writeEnv('DISCORD_MUSIC_CURRENT_PROGRESS', queue.node.playbackTime.toString())
let channel = client.channels.cache.get(process.env.DISCORD_PLAYERCHANNEL_ID as string) as TextChannel
if (!channel) {
clearInterval(client.disco.interval)
console.log(`Aucun channel trouvé avec l'id \`${process.env.DISCORD_PLAYERCHANNEL_ID}\`, veuillez utiliser la commande \`/setchannel\` !`)
return 'clear'
}
let { embed, components } = await generate(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)}` })
let messages = await channel.messages.fetch()
messages.forEach(msg => { if (msg.member) if (!msg.author.bot && !msg.member.roles.cache.has(process.env.DISCORD_ROLE_ID as string)) msg.delete() })
let botMessage = messages.find(msg => client.user && msg.author.id === client.user.id)
if (botMessage) {
if (!components && botMessage.components.length > 0) {
await botMessage.delete()
return channel.send({ embeds: [embed] })
} else if (components) return botMessage.edit({ embeds: [embed], components })
} else return channel.send({ embeds: [embed] })
}

13
src/utilsPlayer/edit.ts Executable file
View File

@@ -0,0 +1,13 @@
import { ButtonInteraction } from 'discord.js'
import generatePlayer from './generate'
export default async (interaction: ButtonInteraction) => {
let guild = interaction.guild
if (!guild) return await interaction.reply({ content: 'Cette commande n\'est pas disponible en message privé.', ephemeral: true })
let { components } = await generatePlayer(guild)
if (!components) return
components.forEach((actionRow) => actionRow.components.forEach((button) => button.setDisabled(true)))
await interaction.update({ components })
}

21
utilsPlayer/generate.js → src/utilsPlayer/generate.ts Normal file → Executable file
View File

@@ -1,7 +1,7 @@
const { EmbedBuilder, ButtonBuilder, ActionRowBuilder } = require('discord.js') import { EmbedBuilder, ButtonBuilder, ActionRowBuilder, Guild } from 'discord.js'
const { useQueue } = require('discord-player') import { useQueue } from 'discord-player'
module.exports = async (guild) => { export default async (guild: Guild) => {
let embed = new EmbedBuilder().setColor('#ffc370') let embed = new EmbedBuilder().setColor('#ffc370')
let queue = useQueue(guild.id) let queue = useQueue(guild.id)
@@ -24,15 +24,14 @@ module.exports = async (guild) => {
{ name: 'Durée', value: track.duration, inline: true }, { name: 'Durée', value: track.duration, inline: true },
{ name: 'Source', value: track.source === 'youtube' ? 'Youtube' : track.source === 'spotify' ? 'Spotify' : 'Inconnu', inline: true }, { name: 'Source', value: track.source === 'youtube' ? 'Youtube' : track.source === 'spotify' ? 'Spotify' : 'Inconnu', inline: true },
{ name: 'Volume', value: `${queue.node.volume}%`, inline: true }, { name: 'Volume', value: `${queue.node.volume}%`, inline: true },
{ name: queue.node.isPaused() ? 'Progression (en pause)' : 'Progression', value: queue.node.createProgressBar() }, { name: queue.node.isPaused() ? 'Progression (en pause)' : 'Progression', value: queue.node.createProgressBar() || 'Aucune' },
{ name: 'Loop', value: queue.repeatMode ? queue.repeatMode === 2 ? "File d'Attente" : "Titre" : "Off", inline: true }, { name: 'Loop', value: queue.repeatMode === 3 ? 'Autoplay' : queue.repeatMode === 2 ? 'File d\'Attente' : queue.repeatMode === 1 ? 'Titre' : 'Off', inline: true }
{ name: 'Autoplay', value: queue.autoplay ? "On" : "Off", inline: true }
) )
.setDescription(`**Musique suivante :** ${queue.tracks.data[0] ? queue.tracks.data[0].title : 'Aucune'}`) .setDescription(`**Musique suivante :** ${queue.tracks.data[0] ? queue.tracks.data[0].title : 'Aucune'}`)
.setFooter({ text: `Demandé par ${track.requestedBy.tag}` }) .setFooter({ text: `Demandé par ${track.requestedBy ? track.requestedBy.tag : 'Inconnu'}` })
let components = [ let components = [
new ActionRowBuilder().addComponents( new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder() new ButtonBuilder()
.setLabel(queue.node.isPaused() ? '▶️' : '⏸️') .setLabel(queue.node.isPaused() ? '▶️' : '⏸️')
.setStyle(2) .setStyle(2)
@@ -57,7 +56,7 @@ module.exports = async (guild) => {
.setCustomId('volume_up') .setCustomId('volume_up')
.setDisabled(queue.node.volume === 100) .setDisabled(queue.node.volume === 100)
), ),
new ActionRowBuilder().addComponents( new ActionRowBuilder<ButtonBuilder>().addComponents(
new ButtonBuilder() new ButtonBuilder()
.setLabel('🔀') .setLabel('🔀')
.setStyle(2) .setStyle(2)
@@ -70,7 +69,7 @@ module.exports = async (guild) => {
.setLabel('⏮️') .setLabel('⏮️')
.setStyle(2) .setStyle(2)
.setCustomId('previous') .setCustomId('previous')
.setDisabled(queue.previousTracks ? !queue.previousTracks[0] : true) .setDisabled(queue.history.previousTrack ? false : true)
) )
] ]
return ({ embed, components }) return ({ embed, components })

Some files were not shown because too many files have changed in this diff Show More