Version 3.0 sortie, fusion avec JujulBot
This commit is contained in:
16
Dockerfile
16
Dockerfile
@@ -1,4 +1,4 @@
|
||||
FROM node:lts-alpine as base
|
||||
FROM node:lts-alpine
|
||||
|
||||
ENV NODE_ENV=production
|
||||
WORKDIR /usr/src/app
|
||||
@@ -12,18 +12,4 @@ COPY . .
|
||||
RUN chown -R node /usr/src/app
|
||||
USER node
|
||||
|
||||
|
||||
FROM base as tamiseur
|
||||
RUN mv .env1 .env
|
||||
RUN rm .env2 .env3
|
||||
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"]
|
||||
23
eslint.config.mjs
Normal file
23
eslint.config.mjs
Normal file
@@ -0,0 +1,23 @@
|
||||
import typescriptEslint from "@typescript-eslint/eslint-plugin"
|
||||
import tsParser from "@typescript-eslint/parser"
|
||||
import { FlatCompat } from "@eslint/eslintrc"
|
||||
import { fileURLToPath } from "node:url"
|
||||
import path from "node:path"
|
||||
import js from "@eslint/js"
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
recommendedConfig: js.configs.recommended,
|
||||
allConfig: js.configs.all
|
||||
})
|
||||
|
||||
export default [
|
||||
...compat.extends("eslint:recommended", "plugin:@typescript-eslint/recommended"),
|
||||
{
|
||||
plugins: { "@typescript-eslint": typescriptEslint },
|
||||
languageOptions: { parser: tsParser },
|
||||
rules: { "prefer-const": "off" }
|
||||
}
|
||||
]
|
||||
2312
package-lock.json
generated
Executable file → Normal file
2312
package-lock.json
generated
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
47
package.json
47
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "bot_tamiseur",
|
||||
"description": "Listen to music and use fun commands with your friends!",
|
||||
"version": "2.3.1",
|
||||
"version": "3.0.0",
|
||||
"author": {
|
||||
"name": "Zachary Guénot"
|
||||
},
|
||||
@@ -10,36 +10,49 @@
|
||||
"format": "prettier --write .",
|
||||
"start": "ts-node src/index.ts",
|
||||
"dev": "nodemon -e ts src/index.ts",
|
||||
"build": "ncc build src/index.ts -o dist"
|
||||
"build": "tsc && terser ./dist -o ./dist",
|
||||
"lint": "eslint src/**/*.ts"
|
||||
},
|
||||
"//": [
|
||||
"Garder chalk à la version 4.1.2 pour éviter un bug ESM avec la version >=5.0.0"
|
||||
],
|
||||
"dependencies": {
|
||||
"@discord-player/equalizer": "^0.2.3",
|
||||
"@discord-player/extractor": "^4.4.7",
|
||||
"@discordjs/opus": "^0.9.0",
|
||||
"@discord-player/extractor": "^4.5.0",
|
||||
"@discordjs/voice": "^0.17.0",
|
||||
"@types/parse-torrent": "^5.8.7",
|
||||
"axios": "^1.6.8",
|
||||
"axios": "^1.7.3",
|
||||
"bufferutil": "^4.0.8",
|
||||
"chalk": "^4.1.2",
|
||||
"discord-player": "^6.6.8",
|
||||
"discord.js": "^14.15.2",
|
||||
"discord-player": "^6.7.1",
|
||||
"discord-player-youtubei": "^1.2.4",
|
||||
"discord.js": "^14.15.3",
|
||||
"dotenv": "^16.4.5",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"jsdom": "^24.0.0",
|
||||
"libsodium-wrappers": "^0.7.13",
|
||||
"mariadb": "^3.3.0",
|
||||
"mongoose": "^8.3.5",
|
||||
"jsdom": "^24.1.1",
|
||||
"libsodium-wrappers": "^0.7.14",
|
||||
"mariadb": "^3.3.1",
|
||||
"mediaplex": "^0.0.9",
|
||||
"mongoose": "^8.5.2",
|
||||
"parse-torrent": "^9.1.5",
|
||||
"play-dl": "^1.9.7",
|
||||
"require-all": "^3.0.0",
|
||||
"rss-parser": "^3.13.0",
|
||||
"sqlite3": "^5.1.7",
|
||||
"utf-8-validate": "^6.0.4"
|
||||
"ts-node": "^10.9.2",
|
||||
"utf-8-validate": "^6.0.4",
|
||||
"websocket": "^1.0.35"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@swc/core": "^1.5.7",
|
||||
"eslint": "^9.2.0",
|
||||
"nodemon": "^3.1.0",
|
||||
"prettier": "^3.2.5"
|
||||
"@eslint/eslintrc": "^3.1.0",
|
||||
"@eslint/js": "^9.8.0",
|
||||
"@swc/core": "^1.7.6",
|
||||
"@types/node": "^22.1.0",
|
||||
"@types/websocket": "^1.0.10",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.1",
|
||||
"@typescript-eslint/parser": "^8.0.1",
|
||||
"eslint": "^9.8.0",
|
||||
"nodemon": "^3.1.4",
|
||||
"prettier": "^3.3.3",
|
||||
"terser": "^5.31.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,45 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction, AutocompleteInteraction, EmbedBuilder, inlineCode } from 'discord.js'
|
||||
import * as AMP from '../../utils/amp'
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction, AutocompleteInteraction, ApplicationCommandOptionChoiceData, EmbedBuilder, inlineCode, PermissionFlagsBits } from 'discord.js'
|
||||
import dbGuild from '../../schemas/guild'
|
||||
import * as AMP from '../../utils/amp'
|
||||
|
||||
interface ListInstancesResult {
|
||||
status: string
|
||||
data: [
|
||||
Host: {
|
||||
AvailableInstances: any[]
|
||||
FriendlyName: string
|
||||
}
|
||||
]
|
||||
}
|
||||
interface InstanceFields {
|
||||
name: string
|
||||
value: string
|
||||
inline: boolean
|
||||
}
|
||||
|
||||
interface failData {
|
||||
Title: string
|
||||
Message: string
|
||||
interface InstanceResult {
|
||||
status: string
|
||||
data: [
|
||||
Host
|
||||
]
|
||||
}
|
||||
interface errorData {
|
||||
error_code: string
|
||||
interface Host {
|
||||
AvailableInstances: Instance[]
|
||||
FriendlyName: string
|
||||
}
|
||||
interface Instance {
|
||||
InstanceID: string
|
||||
FriendlyName: string
|
||||
Running: boolean
|
||||
Module: string
|
||||
Port: number
|
||||
}
|
||||
interface FailMsgData {
|
||||
Title: string
|
||||
Message: string
|
||||
}
|
||||
interface ErrorMsgData {
|
||||
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}`)}` }
|
||||
function failMsg(data: FailMsgData) { return `La commande a échouée !\n${inlineCode(`${data.Title}: ${data.Message}`)}` }
|
||||
function errorMsg(data: ErrorMsgData) { return `Y'a eu une erreur !\n${inlineCode(`${data.error_code}`)}` }
|
||||
|
||||
export default {
|
||||
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 !')
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
|
||||
.addSubcommand(subcommand => subcommand.setName('login').setDescription("Connectez-vous avant d'effectuer une autre commande !")
|
||||
.addStringOption(option => option.setName('username').setDescription("Nom d'Utilisateur").setRequired(true))
|
||||
.addStringOption(option => option.setName('password').setDescription('Mot de Passe').setRequired(true))
|
||||
@@ -71,12 +81,12 @@ export default {
|
||||
}
|
||||
else if (session.status === 'error') return interaction.respond([])
|
||||
|
||||
let choices: any = []
|
||||
let choices: ApplicationCommandOptionChoiceData[] = []
|
||||
let result = await AMP.ADSModule.GetInstances(host, sessionID)
|
||||
if (result.status === 'success') {
|
||||
let hosts = result.data.result as any[]
|
||||
let hosts = result.data.result as Host[]
|
||||
hosts.forEach(host => {
|
||||
let instances = host.AvailableInstances as any[]
|
||||
let instances = host.AvailableInstances as Instance[]
|
||||
instances.forEach(instance => {
|
||||
if (instance.FriendlyName.includes(query)) choices.push({ name: `${host.FriendlyName} - ${instance.FriendlyName}`, value: instance.InstanceID })
|
||||
})
|
||||
@@ -105,10 +115,10 @@ export default {
|
||||
await interaction.deferReply({ ephemeral: true })
|
||||
|
||||
let details = {
|
||||
username: interaction.options.getString('username'),
|
||||
password: interaction.options.getString('password'),
|
||||
token: interaction.options.getString('otp') || '',
|
||||
rememberMe: interaction.options.getBoolean('remember')
|
||||
username: interaction.options.getString('username') || '',
|
||||
password: interaction.options.getString('password') || '',
|
||||
rememberMe: interaction.options.getBoolean('remember') || '',
|
||||
token: interaction.options.getString('otp') || ''
|
||||
}
|
||||
|
||||
let result = await AMP.Core.Login(host, details)
|
||||
@@ -146,13 +156,13 @@ export default {
|
||||
|
||||
if (interaction.options.getSubcommandGroup() == 'instances') {
|
||||
if (interaction.options.getSubcommand() == 'list') {
|
||||
let result = await AMP.ADSModule.GetInstances(host, sessionID) as ListInstancesResult
|
||||
let result = await AMP.ADSModule.GetInstances(host, sessionID) as InstanceResult
|
||||
|
||||
if (result.status === 'success') {
|
||||
await interaction.followUp({ content: `${result.data.length} hôte(s) trouvé(s) !` })
|
||||
result.data.forEach(async host => {
|
||||
let fields = [] as InstanceFields[]
|
||||
host.AvailableInstances.forEach(instance => {
|
||||
host.AvailableInstances.forEach((instance: Instance) => {
|
||||
fields.push({
|
||||
name: instance.FriendlyName,
|
||||
value: `**Running:** ${instance.Running}\n**Port:** ${instance.Port}\n**Module:** ${instance.Module}`,
|
||||
@@ -168,8 +178,8 @@ export default {
|
||||
return await interaction.channel?.send({ embeds: [embed] })
|
||||
})
|
||||
}
|
||||
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 === 'fail') return await interaction.followUp(failMsg(result.data as unknown as FailMsgData))
|
||||
else if (result.status === 'error') return await interaction.followUp(errorMsg(result.data as unknown as ErrorMsgData))
|
||||
}
|
||||
else if (interaction.options.getSubcommand() == 'manage') {
|
||||
let instanceID = interaction.options.getString('instance', true)
|
||||
|
||||
37
src/commands/global/boost.ts
Normal file
37
src/commands/global/boost.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { SlashCommandBuilder, EmbedBuilder, ChatInputCommandInteraction, TextChannel, PermissionFlagsBits } from 'discord.js'
|
||||
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('boost')
|
||||
.setDescription('Tester le boost du serveur !')
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator),
|
||||
async execute(interaction: ChatInputCommandInteraction) {
|
||||
if (interaction.guild?.id !== '796327643783626782') return interaction.reply({ content: 'Non !' })// Jujul Community
|
||||
let member = interaction.member
|
||||
if (!member) return console.log(`\u001b[1;31m Aucun membre trouvé !`)
|
||||
|
||||
let guild = interaction.guild
|
||||
if (!guild) return console.log(`\u001b[1;31m Aucun serveur trouvé !`)
|
||||
|
||||
let channel = guild.channels.cache.get('924353449930412153') as TextChannel
|
||||
if (!channel) return console.log(`\u001b[1;31m Aucun channel trouvé avec l'id "924353449930412153" !`)
|
||||
|
||||
let boostRole = guild.roles.premiumSubscriberRole
|
||||
if (!boostRole) return console.log(`\u001b[1;31m Aucun rôle de boost trouvé !`)
|
||||
|
||||
if (!guild.members.me) return console.log(`\u001b[1;31m Je ne suis pas sur le serveur !`)
|
||||
|
||||
let embed = new EmbedBuilder()
|
||||
.setColor(guild.members.me.displayHexColor)
|
||||
.setTitle(`Nouveau boost de ${member.user.username} !`)
|
||||
.setDescription(`
|
||||
Merci à toi pour ce boost.\n
|
||||
Grâce à toi, on a atteint ${guild.premiumSubscriptionCount} boosts !
|
||||
`)
|
||||
.setThumbnail(member.user.avatar)
|
||||
.setTimestamp(new Date())
|
||||
|
||||
await channel.send({ embeds: [embed] })
|
||||
await interaction.reply({ content: 'Va voir dans <#924353449930412153> !' })
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction, EmbedBuilder, APIEmbedField } from 'discord.js'
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction, EmbedBuilder, APIEmbedField, PermissionFlagsBits } from 'discord.js'
|
||||
|
||||
import dbGuildInit from '../../utils/dbGuildInit'
|
||||
import dbGuild from '../../schemas/guild'
|
||||
@@ -23,6 +23,7 @@ export default {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('database')
|
||||
.setDescription('Communicate with the database')
|
||||
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
|
||||
.addSubcommand(subcommand => subcommand.setName('info').setDescription('Returns information about the current guild'))
|
||||
.addSubcommand(subcommand => subcommand.setName('init').setDescription('Force initialize an entry for the current guild in the database'))
|
||||
.addSubcommand(subcommand => subcommand.setName('edit').setDescription('Modify parameters for the current guild')
|
||||
@@ -44,7 +45,9 @@ export default {
|
||||
.setDescription(`Guild **${guildProfile.guildName}** (ID: ${guildProfile.guildId})`)
|
||||
.setThumbnail(guildProfile.guildIcon as string)
|
||||
.setTimestamp()
|
||||
.addFields(fields as APIEmbedField[])
|
||||
//.addFields(fields as APIEmbedField[])
|
||||
// Limit the number of fields to 25
|
||||
.addFields(fields.slice(0, 25) as APIEmbedField[])
|
||||
return await interaction.reply({ embeds: [embed] })
|
||||
|
||||
} else if (interaction.options.getSubcommand() === 'init') {
|
||||
|
||||
25
src/commands/player/panel.ts
Executable file
25
src/commands/player/panel.ts
Executable file
@@ -0,0 +1,25 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'
|
||||
import { playerGenerate } from '../../utils/player'
|
||||
import getUptime from '../../utils/getUptime'
|
||||
import { useQueue } from 'discord-player'
|
||||
|
||||
export default {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('panel')
|
||||
.setDescription('Générer les infos de la lecture en cours.'),
|
||||
async execute(interaction: ChatInputCommandInteraction) {
|
||||
let queue = useQueue(interaction.guild?.id ?? '')
|
||||
if (!queue) return interaction.followUp({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' })
|
||||
|
||||
let guild = interaction.guild
|
||||
if (!guild) return await interaction.reply({ content: 'Cette commande n\'est pas disponible en message privé.', ephemeral: true })
|
||||
|
||||
let client = guild.client
|
||||
|
||||
let { embed, components } = await playerGenerate(guild)
|
||||
if (components && embed.data.footer) embed.setFooter({ text: `Uptime: ${getUptime(client.uptime)} \n ${embed.data.footer.text}` })
|
||||
else embed.setFooter({ text: `Uptime: ${getUptime(client.uptime)}` })
|
||||
|
||||
return interaction.reply({ embeds: [embed] })
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction, AutocompleteInteraction, GuildMember } from 'discord.js'
|
||||
import { useMainPlayer, useQueue, QueryType } from 'discord-player'
|
||||
|
||||
import dbGuild from '../../schemas/guild'
|
||||
|
||||
export interface TrackSearchResult { name: string, value: string }
|
||||
interface TrackSearchResult { name: string, value: string }
|
||||
|
||||
export default {
|
||||
data: new SlashCommandBuilder()
|
||||
|
||||
19
src/commands/player/queue.ts
Executable file
19
src/commands/player/queue.ts
Executable file
@@ -0,0 +1,19 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction } from 'discord.js'
|
||||
import { useQueue } from 'discord-player'
|
||||
|
||||
export default {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('queue')
|
||||
.setDescription("Récupérer la file d'attente."),
|
||||
async execute(interaction: ChatInputCommandInteraction) {
|
||||
let queue = useQueue(interaction.guild?.id ?? '')
|
||||
if (!queue) return interaction.reply({ content: 'Aucune file d\'attente en cours, recherche une musique plutôt !' })
|
||||
if (!queue.currentTrack) return interaction.reply({ content: 'Aucune musique en cours de lecture.' })
|
||||
|
||||
let track = `[${queue.currentTrack.title}](${queue.currentTrack.url})`
|
||||
let tracks = queue.tracks.map((track, index) => { return `${index + 1}. [${track.title}](${track.url})` })
|
||||
if (tracks.length === 0) return interaction.reply({ content: `Lecture en cours : ${track} \nAucune musique dans la file d'attente.` })
|
||||
|
||||
return interaction.reply({ content: `Lecture en cours : ${track} \nFile d'attente actuelle : \n${tracks.join('\n')}` })
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,19 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction, EmbedBuilder, Message, inlineCode } from 'discord.js'
|
||||
import https from 'https'
|
||||
import * as Freebox from '../../utils/freebox'
|
||||
import dbGuild from '../../schemas/guild'
|
||||
import crypto from 'crypto'
|
||||
import https from 'https'
|
||||
//import path from 'path'
|
||||
//import fs from 'fs'
|
||||
|
||||
import * as Freebox from '../../utils/freebox'
|
||||
import dbGuild from '../../schemas/guild'
|
||||
interface ReturnMsgData {
|
||||
status: string
|
||||
error_code?: string
|
||||
Title?: string
|
||||
Message?: string
|
||||
}
|
||||
|
||||
|
||||
function returnMsg(result: any) {
|
||||
function returnMsg(result: ReturnMsgData) {
|
||||
if (result.status === 'fail') return `La commande a échouée !\n${inlineCode(`${result.Title}: ${result.Message}`)}`
|
||||
if (result.status === 'error') return `Y'a eu une erreur !\n${inlineCode(`${result.error_code}`)}`
|
||||
}
|
||||
@@ -4,11 +4,11 @@ import dbGuildInit from '../../utils/dbGuildInit'
|
||||
export default {
|
||||
name: Events.GuildCreate,
|
||||
async execute(guild: Guild) {
|
||||
console.log(`Joined ${guild.name} with ${guild.memberCount} members`)
|
||||
console.log(`Joined "${guild.name}" with ${guild.memberCount} members`)
|
||||
|
||||
let guildProfile = await dbGuildInit(guild)
|
||||
if (!guildProfile) return console.log(`An error occured while initializing database data for **${guild.name}** !`)
|
||||
if (!guildProfile) return console.log(`An error occured while initializing database data for "${guild.name}" !`)
|
||||
|
||||
console.log(`Database data for new guild **${guildProfile.guildName}** successfully initialized !`)
|
||||
console.log(`Database data for new guild "${guildProfile.guildName}" successfully initialized !`)
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,44 @@
|
||||
import { Events, GuildMember } from 'discord.js'
|
||||
import { Events, GuildMember, EmbedBuilder, TextChannel } from 'discord.js'
|
||||
|
||||
export default {
|
||||
name: Events.GuildMemberAdd,
|
||||
async execute(member: GuildMember) {
|
||||
if (member.guild.id !== '1086577543651524699') return
|
||||
member.guild.members.fetch().then(() => {
|
||||
var i = 0
|
||||
member.guild.members.cache.forEach(async member => { if (!member.user.bot) i++ })
|
||||
let channel = member.guild.channels.cache.get('1091140609139560508')
|
||||
if (!channel) return
|
||||
if (member.guild.id === '1086577543651524699') { // Salon posé tamisé
|
||||
let guild = member.guild
|
||||
|
||||
console.log(channel.name)
|
||||
console.log(`${i} Gens Posés`)
|
||||
channel.setName('Changement...')
|
||||
channel.setName(`${i} Gens Posés`)
|
||||
}).catch(console.error)
|
||||
guild.members.fetch().then(() => {
|
||||
var i = 0
|
||||
guild.members.cache.forEach(async member => { if (!member.user.bot) i++ })
|
||||
|
||||
let channel = guild.channels.cache.get('1091140609139560508')
|
||||
if (!channel) return
|
||||
|
||||
channel.setName('Changement...')
|
||||
channel.setName(`${i} Gens Posés`)
|
||||
}).catch(console.error)
|
||||
} else if (member.guild.id === '796327643783626782') { // Jujul Community
|
||||
let guild = member.guild
|
||||
|
||||
let channel = guild.channels.cache.get('837248593609097237') as TextChannel
|
||||
if (!channel) return console.log(`\u001b[1;31m Aucun channel trouvé avec l'id "837248593609097237" !`)
|
||||
|
||||
if (!guild.members.me) return console.log(`\u001b[1;31m Je ne suis pas sur le serveur !`)
|
||||
|
||||
let embed = new EmbedBuilder()
|
||||
.setColor(guild.members.me.displayHexColor)
|
||||
.setTitle(`Salut ${member.user.username} !`)
|
||||
.setDescription(`
|
||||
Bienvenue sur le serveur de **Jujul** !
|
||||
Nous sommes actuellement ${guild.memberCount} membres !\n
|
||||
N'hésite pas à aller lire le <#797471924367786004> et à aller te présenter dans <#837138238417141791> !\n
|
||||
Si tu as des questions,
|
||||
n'hésite pas à les poser dans le <#837110617315344444> !\n
|
||||
Bon séjour parmi nous !
|
||||
`)
|
||||
.setThumbnail(member.user.avatarURL())
|
||||
.setTimestamp(new Date())
|
||||
|
||||
await channel.send({ embeds: [embed] })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,19 @@ import { Events, GuildMember } from 'discord.js'
|
||||
export default {
|
||||
name: Events.GuildMemberRemove,
|
||||
async execute(member: GuildMember) {
|
||||
if (member.guild.id !== '1086577543651524699') return
|
||||
member.guild.members.fetch().then(() => {
|
||||
var i = 0
|
||||
member.guild.members.cache.forEach(async member => { if (!member.user.bot) i++ })
|
||||
let channel = member.guild.channels.cache.get('1091140609139560508')
|
||||
if (!channel) return
|
||||
if (member.guild.id === '1086577543651524699') { // Salon posé tamisé
|
||||
let guild = member.guild
|
||||
|
||||
console.log(channel.name)
|
||||
console.log(`${i} Gens Posés`)
|
||||
channel.setName('Changement...')
|
||||
channel.setName(`${i} Gens Posés`)
|
||||
}).catch(console.error)
|
||||
guild.members.fetch().then(() => {
|
||||
var i = 0
|
||||
guild.members.cache.forEach(async member => { if (!member.user.bot) i++ })
|
||||
|
||||
let channel = guild.channels.cache.get('1091140609139560508')
|
||||
if (!channel) return
|
||||
|
||||
channel.setName('Changement...')
|
||||
channel.setName(`${i} Gens Posés`)
|
||||
}).catch(console.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
35
src/events/client/guildMemberUpdate.ts
Normal file
35
src/events/client/guildMemberUpdate.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Events, GuildMember, EmbedBuilder, TextChannel } from 'discord.js'
|
||||
|
||||
export default {
|
||||
name: Events.GuildMemberUpdate,
|
||||
async execute(oldMember: GuildMember, newMember: GuildMember) {
|
||||
if (newMember.guild.id === '796327643783626782') { // Jujul Community
|
||||
let guild = newMember.guild
|
||||
|
||||
let channel = guild.channels.cache.get('924353449930412153') as TextChannel
|
||||
if (!channel) return console.log(`\u001b[1;31m Aucun channel trouvé avec l'id "924353449930412153" !`)
|
||||
|
||||
let boostRole = guild.roles.premiumSubscriberRole
|
||||
if (!boostRole) return console.log(`\u001b[1;31m Aucun rôle de boost trouvé !`)
|
||||
|
||||
const hadRole = oldMember.roles.cache.find(role => role.id === boostRole.id)
|
||||
const hasRole = newMember.roles.cache.find(role => role.id === boostRole.id)
|
||||
|
||||
if (!hadRole && hasRole) {
|
||||
if (!guild.members.me) return console.log(`\u001b[1;31m Je ne suis pas sur le serveur !`)
|
||||
|
||||
let embed = new EmbedBuilder()
|
||||
.setColor(guild.members.me.displayHexColor)
|
||||
.setTitle(`Nouveau boost de ${newMember.user.username} !`)
|
||||
.setDescription(`
|
||||
Merci à toi pour ce boost.\n
|
||||
Grâce à toi, on a atteint ${guild.premiumSubscriptionCount} boosts !
|
||||
`)
|
||||
.setThumbnail(newMember.user.avatarURL())
|
||||
.setTimestamp(new Date())
|
||||
|
||||
await channel.send({ embeds: [embed] })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,8 @@ export default {
|
||||
console.log(`Guild ${oldGuild.name} updated`)
|
||||
|
||||
let guildProfile = await dbGuild.findOne({ guildId: newGuild.id })
|
||||
if (!guildProfile) {
|
||||
guildProfile = await dbGuildInit(newGuild)
|
||||
} else {
|
||||
if (!guildProfile) guildProfile = await dbGuildInit(newGuild)
|
||||
else {
|
||||
guildProfile.guildName = newGuild.name
|
||||
guildProfile.guildIcon = newGuild.iconURL() ?? 'None'
|
||||
await guildProfile.save().catch(console.error)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Events, Interaction, ChatInputCommandInteraction, AutocompleteInteraction, ButtonInteraction } from 'discord.js'
|
||||
import playerButtons from '../../utilsPlayer/buttons'
|
||||
import editPlayer from '../../utilsPlayer/edit'
|
||||
import { playerButtons, playerEdit } from '../../utils/player'
|
||||
|
||||
export default {
|
||||
name: Events.InteractionCreate,
|
||||
@@ -37,7 +36,7 @@ export default {
|
||||
|
||||
console.log(`Button '${interaction.customId}' clicked by ${interaction.user.tag}`)
|
||||
|
||||
if (playerButtons.includes(interaction.customId)) { await editPlayer(interaction) }
|
||||
if (playerButtons.includes(interaction.customId)) { await playerEdit(interaction) }
|
||||
|
||||
try { await button.execute(interaction) }
|
||||
catch (error) { console.error(`Error clicking ${interaction.customId}:`, error) }
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { Events, Client, ActivityType } from 'discord.js'
|
||||
import { YoutubeiExtractor } from "discord-player-youtubei"
|
||||
import { useMainPlayer } from 'discord-player'
|
||||
import { connect } from 'mongoose'
|
||||
import WebSocket from 'websocket'
|
||||
import chalk from 'chalk'
|
||||
import 'dotenv/config'
|
||||
|
||||
import dbGuildInit from '../../utils/dbGuildInit'
|
||||
import dbGuild from '../../schemas/guild'
|
||||
import replay from '../../utilsPlayer/replay'
|
||||
import disco from '../../utilsPlayer/disco'
|
||||
import { playerDisco, playerReplay } from '../../utils/player'
|
||||
import * as Twitch from '../../utils/twitch'
|
||||
import rss from '../../utils/rss'
|
||||
|
||||
|
||||
export default {
|
||||
name: Events.ClientReady,
|
||||
once: true,
|
||||
@@ -18,7 +19,8 @@ export default {
|
||||
console.log(chalk.blue(`[DiscordJS] Connected to Discord ! 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(chalk.blue('[Discord-Player] YouTube and Spotify extractors loaded.'))).catch(console.error)
|
||||
await useMainPlayer().extractors.loadDefault(ext => ext === 'SpotifyExtractor').then(() => console.log(chalk.blue('[Discord-Player] Spotify extractor loaded.'))).catch(console.error)
|
||||
await useMainPlayer().extractors.register(YoutubeiExtractor, {}).then(() => console.log(chalk.blue('[Discord-Player] Youtube extractor loaded.'))).catch(console.error)
|
||||
|
||||
let mongo_url = `mongodb://${process.env.MONGOOSE_USER}:${process.env.MONGOOSE_PASSWORD}@${process.env.MONGOOSE_HOST}/${process.env.MONGOOSE_DATABASE}`
|
||||
await connect(mongo_url).catch(console.error)
|
||||
@@ -29,14 +31,14 @@ export default {
|
||||
let guildProfile = await dbGuild.findOne({ guildId: guild.id })
|
||||
|
||||
if (!guildProfile) guildProfile = await dbGuildInit(guild)
|
||||
if (guildProfile.guildPlayer?.replay?.enabled && guildProfile.guildPlayer?.replay?.textChannelId) await replay(client, guildProfile)
|
||||
if (guildProfile.guildPlayer?.replay?.enabled && guildProfile.guildPlayer?.replay?.textChannelId) await playerReplay(client, guildProfile)
|
||||
|
||||
client.disco = { interval: {} as NodeJS.Timeout }
|
||||
client.disco.interval = setInterval(async () => {
|
||||
let guildProfile = await dbGuild.findOne({ guildId: guild.id })
|
||||
|
||||
if (guildProfile?.guildPlayer?.disco?.enabled) {
|
||||
let state = await disco(client, guildProfile)
|
||||
let state = await playerDisco(client, guildProfile)
|
||||
if (state === 'clear') clearInterval(client.disco.interval)
|
||||
}
|
||||
}, 3000)
|
||||
@@ -50,6 +52,64 @@ export default {
|
||||
if (state === 'clear') clearInterval(client.rss.interval)
|
||||
}
|
||||
}, 30000)
|
||||
|
||||
// TWITCH EVENTSUB
|
||||
let dbData = guildProfile.get('guildTwitch')
|
||||
if (!dbData?.enabled) return console.log(chalk.magenta(`[Twitch] Module is disabled for "${guild?.name}", please activate with \`/database edit guildTwitch.enabled True\` !`))
|
||||
|
||||
let client_id = process.env.TWITCH_APP_ID as string
|
||||
if (!client_id) return console.log(chalk.magenta('[Twitch] App ID is not defined !'))
|
||||
|
||||
let client_secret = process.env.TWITCH_APP_SECRET as string
|
||||
if (!client_secret) return console.log(chalk.magenta('[Twitch] App Secret is not defined !'))
|
||||
|
||||
let twitch = new WebSocket.client().on('connect', async connection => {
|
||||
console.log(chalk.magenta('[Twitch] EventSub WebSocket Connected !'))
|
||||
|
||||
connection.on('message', async message => { if (message.type === 'utf8') { try {
|
||||
let data = JSON.parse(message.utf8Data)
|
||||
let channel_access_token = guildProfile.get('guildTwitch')?.channelAccessToken as string
|
||||
|
||||
// Check when Twitch asks to login
|
||||
if (data.metadata.message_type === 'session_welcome') {
|
||||
|
||||
// Check if the channel access token is still valid before connecting
|
||||
channel_access_token = await Twitch.checkChannel(client_id, client_secret, channel_access_token, guild) as string
|
||||
if (!channel_access_token) return console.log(chalk.magenta("[Twitch] Can't refresh channel access token !"))
|
||||
|
||||
// Get broadcaster user id and reward id
|
||||
let broadcaster_user_id = await Twitch.getUserInfo(client_id, channel_access_token, 'id') as string
|
||||
|
||||
let topics: { [key: string]: { version: string; condition: { broadcaster_user_id: string } } } = {
|
||||
'stream.online': { version: '1', condition: { broadcaster_user_id } },
|
||||
'stream.offline': { version: '1', condition: { broadcaster_user_id } }
|
||||
}
|
||||
|
||||
// Subscribe to all events required
|
||||
for (let type in topics) {
|
||||
console.log(chalk.magenta(`[Twitch] Creating ${type}...`))
|
||||
let { version, condition } = topics[type]
|
||||
|
||||
let status = await Twitch.subscribeToEvents(client_id, channel_access_token, data.payload.session.id, type, version, condition)
|
||||
if (!status) return console.error(chalk.magenta(`[Twitch] Failed to create ${type}`))
|
||||
else if (status.error) return console.log(chalk.magenta('[Twitch] Erreur de connexion EventSub, veuillez vous reconnecter !'))
|
||||
else console.log(chalk.magenta(`[Twitch] Successfully created ${type}`))
|
||||
}
|
||||
}
|
||||
|
||||
// Handle notification messages
|
||||
else if (data.metadata.message_type === 'notification') Twitch.notification(client_id, channel_access_token, data, guild)
|
||||
|
||||
} catch (error) { console.error(chalk.magenta('[Twitch] ' + error)) } } })
|
||||
.on('error', error => console.error(chalk.magenta('[Twitch] ' + error)))
|
||||
.on('close', () => {
|
||||
console.log(chalk.magenta('[Twitch] EventSub Connection Closed !'))
|
||||
twitch.connect('wss://eventsub.wss.twitch.tv/ws')
|
||||
})
|
||||
}).on('connectFailed', error => console.error(chalk.magenta('[Twitch] ' + error)))
|
||||
|
||||
// LAUNCH TWITCH EVENTSUB
|
||||
twitch.connect('wss://eventsub.wss.twitch.tv/ws')
|
||||
})
|
||||
}
|
||||
}
|
||||
26
src/index.ts
26
src/index.ts
@@ -1,28 +1,29 @@
|
||||
// PACKAGES
|
||||
import { Client, Collection, GatewayIntentBits, REST, Routes, ChatInputCommandInteraction, AutocompleteInteraction, ButtonInteraction } from 'discord.js'
|
||||
import { Player } from 'discord-player'
|
||||
import { connection } from 'mongoose'
|
||||
import { connection, Connection } from 'mongoose'
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import 'dotenv/config'
|
||||
|
||||
import pjson from '../package.json'
|
||||
console.log('Running on version', pjson.version)
|
||||
|
||||
export interface Command {
|
||||
// CUSTOM TYPES
|
||||
interface CConnection extends Connection {
|
||||
once: (event: string, listener: (...args: any[]) => void) => void
|
||||
on: (event: string, listener: (...args: any[]) => void) => void
|
||||
}
|
||||
interface Command {
|
||||
name: string
|
||||
description: string
|
||||
data: any
|
||||
autocompleteRun: (interaction: AutocompleteInteraction) => any
|
||||
execute: (interaction: ChatInputCommandInteraction) => any
|
||||
}
|
||||
export interface Button {
|
||||
interface Button {
|
||||
name: string
|
||||
description: string
|
||||
id: string
|
||||
execute: (interaction: ButtonInteraction) => any
|
||||
}
|
||||
|
||||
declare module 'discord.js' {
|
||||
export interface Client {
|
||||
commands: Collection<unknown, Command>
|
||||
@@ -69,6 +70,8 @@ let commandsTotal = 0
|
||||
|
||||
let commandFolders = fs.readdirSync(path.join(__dirname, './commands'))
|
||||
commandFolders.forEach(folder => {
|
||||
if (folder === 'salonpostam' && process.env.DISCORD_APP_ID === '660961595006124052') return
|
||||
|
||||
let folderPath = path.join(__dirname, './commands', folder)
|
||||
let commandFiles = fs.readdirSync(folderPath).filter(file => file.endsWith('.ts'))
|
||||
commandsTotal += commandFiles.length
|
||||
@@ -83,6 +86,7 @@ commandFolders.forEach(folder => {
|
||||
commandsParsed++
|
||||
|
||||
if (commandsParsed === commandsTotal) {
|
||||
console.log(`[INFO] ${commandsParsed} commands parsed.`)
|
||||
// COMMANDS REGISTRATION
|
||||
const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN as string);
|
||||
(async () => {
|
||||
@@ -107,8 +111,8 @@ let eventClientFiles = fs.readdirSync(path.join(__dirname, './events/client')).f
|
||||
eventClientFiles.forEach(async file => {
|
||||
let event = await import(path.join(__dirname, './events/client', file))
|
||||
event = event.default
|
||||
if (event.once) client.once(event.name, (...args) => { event.execute(...args) })
|
||||
else client.on(event.name, (...args) => { event.execute(...args) })
|
||||
if (event.once) client.once(event.name, (...args: any[]) => { event.execute(...args) })
|
||||
else client.on(event.name, (...args: any[]) => { event.execute(...args) })
|
||||
})
|
||||
|
||||
// PLAYER EVENTS HANDLING
|
||||
@@ -125,8 +129,8 @@ let eventsMongo = fs.readdirSync(path.join(__dirname, './events/mongo')).filter(
|
||||
eventsMongo.forEach(async file => {
|
||||
let event = await import(path.join(__dirname, './events/mongo', file))
|
||||
event = event.default
|
||||
if (event.once) connection.once(event.name, (...args) => { event.execute(...args, client) })
|
||||
else connection.on(event.name, (...args) => { event.execute(...args, client) })
|
||||
if (event.once) (connection as CConnection).once(event.name, (...args: any[]) => { event.execute(...args, client) })
|
||||
else (connection as CConnection).on(event.name, (...args: any[]) => { event.execute(...args, client) })
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -41,6 +41,15 @@ const guildSchema = new Schema({
|
||||
appToken: { type: String, required: false },
|
||||
sessionToken: { type: String, required: false },
|
||||
password_salt: { type: String, required: false }
|
||||
},
|
||||
guildTwitch: {
|
||||
enabled: { type: Boolean, required: true },
|
||||
channelName: { type: String, required: false },
|
||||
channelAccessToken: { type: String, required: false },
|
||||
channelRefreshToken: { type: String, required: false },
|
||||
liveChannelId: { type: String, required: false },
|
||||
liveMessageId: { type: String, required: false },
|
||||
liveBroadcasterId: { type: String, required: false }
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import axios from 'axios'
|
||||
|
||||
export interface LoginDetails {
|
||||
username: string
|
||||
password: string
|
||||
remember?: boolean
|
||||
otp?: string
|
||||
}
|
||||
|
||||
export const ADSModule = {
|
||||
async GetInstances(host: string, SESSIONID: string) {
|
||||
return await axios.post(host + '/API/ADSModule/GetInstances', {
|
||||
@@ -56,7 +63,7 @@ export const ADSModule = {
|
||||
}
|
||||
|
||||
export const Core = {
|
||||
async Login(host: string, details: any) {
|
||||
async Login(host: string, details: LoginDetails) {
|
||||
return await axios.post(host + '/API/Core/Login',
|
||||
details
|
||||
).then(response => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import axios from 'axios'
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
|
||||
export declare class Game {
|
||||
interface Game {
|
||||
name: string
|
||||
link: string
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ export default async (guild: Guild) => {
|
||||
},
|
||||
guildRss: { enabled: false, feeds: [] },
|
||||
guildAmp: { enabled: false },
|
||||
guildFbx: { enabled: false }
|
||||
guildFbx: { enabled: false },
|
||||
guildTwitch: { enabled: false }
|
||||
})
|
||||
await guildProfile.save().catch(console.error)
|
||||
return guildProfile
|
||||
|
||||
@@ -20,7 +20,7 @@ export const Core = {
|
||||
return { status: 'error', data: error }
|
||||
})
|
||||
},
|
||||
async Init(host: string, version: Number, httpsAgent: https.Agent, app: App, trackId: String) {
|
||||
async Init(host: string, version: number, httpsAgent: https.Agent, app: App, trackId: string) {
|
||||
let request
|
||||
|
||||
if (trackId) request = axios.get(host + `/api/v${version}/login/authorize/` + trackId, { httpsAgent })
|
||||
@@ -37,7 +37,7 @@ export const Core = {
|
||||
}
|
||||
|
||||
export const Login = {
|
||||
async Challenge(host: string, version: Number, httpsAgent: https.Agent) {
|
||||
async Challenge(host: string, version: number, httpsAgent: https.Agent) {
|
||||
let request = axios.get(host + `/api/v${version}/login/`, { httpsAgent })
|
||||
|
||||
return await request.then(response => {
|
||||
@@ -49,7 +49,7 @@ export const Login = {
|
||||
return { status: 'error', data: error }
|
||||
})
|
||||
},
|
||||
async Session(host: string, version: Number, httpsAgent: https.Agent, app_id: string, password: string) {
|
||||
async Session(host: string, version: number, httpsAgent: https.Agent, app_id: string, password: string) {
|
||||
let request = axios.post(host + `/api/v${version}/login/session/`, { app_id, password }, { httpsAgent })
|
||||
|
||||
return await request.then(response => {
|
||||
@@ -64,7 +64,7 @@ export const Login = {
|
||||
}
|
||||
|
||||
export const Get = {
|
||||
async Connection(host: string, version: Number, httpsAgent: https.Agent, sessionToken: string) {
|
||||
async Connection(host: string, version: number, httpsAgent: https.Agent, sessionToken: string) {
|
||||
let request = axios.get(host + `/api/v${version}/connection/`, { httpsAgent, headers: { 'X-Fbx-App-Auth': sessionToken } })
|
||||
|
||||
return await request.then(response => {
|
||||
|
||||
206
src/utils/player.ts
Normal file
206
src/utils/player.ts
Normal file
@@ -0,0 +1,206 @@
|
||||
import { Client, TextChannel, CommandInteraction, Guild, GuildChannel, TextBasedChannel, VoiceChannel, EmbedBuilder, ButtonBuilder, ActionRowBuilder, ButtonInteraction } from 'discord.js'
|
||||
import { useMainPlayer, useQueue } from 'discord-player'
|
||||
import { Document } from 'mongoose'
|
||||
import getUptime from './getUptime'
|
||||
|
||||
type ChannelInferrable = {
|
||||
channel: TextBasedChannel | VoiceChannel
|
||||
guild?: Guild
|
||||
}
|
||||
|
||||
export class PlayerMetadata {
|
||||
public constructor(public data: ChannelInferrable) {
|
||||
if (data.channel.isDMBased()) { throw new Error('PlayerMetadata cannot be created from a DM') }
|
||||
if (!data.channel) { throw new Error('PlayerMetadata can only be created from a channel') }
|
||||
}
|
||||
public get channel() { return this.data.channel! }
|
||||
public get guild() { return this.data.guild || (this.data.channel as GuildChannel).guild }
|
||||
|
||||
public static create(data: ChannelInferrable | CommandInteraction) {
|
||||
if (data instanceof CommandInteraction) {
|
||||
if (!data.inGuild()) { throw new Error('PlayerMetadata cannot be created from a DM') }
|
||||
|
||||
return new PlayerMetadata({ channel: data.channel!, guild: data.guild! })
|
||||
}
|
||||
return new PlayerMetadata(data);
|
||||
}
|
||||
}
|
||||
|
||||
export const bots = ['1065047326860783636', '1119343522059927684', '1119344050412204032', '1210714000321548329', '660961595006124052']
|
||||
export const playerButtons = ['loop', 'pause', 'previous', 'resume', 'shuffle', 'skip', 'stop', 'volume_down', 'volume_up']
|
||||
|
||||
export async function playerDisco (client: Client, guildProfile: Document) {
|
||||
try {
|
||||
let guild = client.guilds.cache.get(guildProfile.get('guildId'))
|
||||
if (!guild) {
|
||||
clearInterval(client.disco.interval)
|
||||
return 'clear'
|
||||
}
|
||||
|
||||
let dbData = guildProfile.get('guildPlayer.disco')
|
||||
let queue = useQueue(guild.id)
|
||||
if (queue) if (queue.isPlaying()) {
|
||||
dbData['progress'] = queue.node.playbackTime.toString()
|
||||
|
||||
guildProfile.set('guildPlayer.disco', dbData)
|
||||
guildProfile.markModified('guildPlayer.disco')
|
||||
await guildProfile.save().catch(console.error)
|
||||
}
|
||||
|
||||
let channel = client.channels.cache.get(dbData.channelId) as TextChannel
|
||||
if (!channel) {
|
||||
console.log(`Aucun channel trouvé avec l'id \`${dbData.channelId}\`, veuillez utiliser la commande \`/database edit 'value': guildPlayer.disco.channelId\` !`)
|
||||
clearInterval(client.disco.interval)
|
||||
return 'clear'
|
||||
}
|
||||
|
||||
let { embed, components } = await playerGenerate(guild)
|
||||
if (components && embed.data.footer) embed.setFooter({ text: `Uptime: ${getUptime(client.uptime)} \n ${embed.data.footer.text}` })
|
||||
else embed.setFooter({ text: `Uptime: ${getUptime(client.uptime)}` })
|
||||
|
||||
let messages = await channel.messages.fetch()
|
||||
messages.forEach(msg => { if (!bots.includes(msg.author.id)) 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 botMessage.edit({ embeds: [embed] })
|
||||
|
||||
} else return channel.send({ embeds: [embed] })
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return 'clear'
|
||||
}
|
||||
}
|
||||
|
||||
export async function playerEdit (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 playerGenerate(guild)
|
||||
if (!components) return
|
||||
|
||||
components.forEach((actionRow) => actionRow.components.forEach((button) => button.setDisabled(true)))
|
||||
await interaction.update({ components })
|
||||
}
|
||||
|
||||
export async function playerGenerate (guild: Guild) {
|
||||
let embed = new EmbedBuilder().setColor('#ffc370')
|
||||
|
||||
let queue = useQueue(guild.id)
|
||||
if (!queue) {
|
||||
embed.setTitle('Aucune session d\'écoute en cours !')
|
||||
return ({ embed, components: null })
|
||||
}
|
||||
|
||||
let track = queue.currentTrack
|
||||
if (!track) {
|
||||
embed.setTitle('Aucune musique en cours de lecture !')
|
||||
return ({ embed, components: null })
|
||||
}
|
||||
|
||||
embed.setTitle(track.title)
|
||||
.setAuthor({ name: track.author })
|
||||
.setURL(track.url)
|
||||
.setImage(track.thumbnail)
|
||||
.addFields(
|
||||
{ name: 'Durée', value: track.duration, 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: queue.node.isPaused() ? 'Progression (en pause)' : 'Progression', value: queue.node.createProgressBar() || 'Aucune' },
|
||||
{ name: 'Loop', value: queue.repeatMode === 3 ? 'Autoplay' : queue.repeatMode === 2 ? 'File d\'Attente' : queue.repeatMode === 1 ? 'Titre' : 'Off', inline: true }
|
||||
)
|
||||
.setDescription(`**Musique suivante :** ${queue.tracks.data[0] ? queue.tracks.data[0].title : 'Aucune'}`)
|
||||
.setFooter({ text: `Demandé par ${track.requestedBy ? track.requestedBy.tag : 'Inconnu'}` })
|
||||
|
||||
let components = [
|
||||
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel(queue.node.isPaused() ? '▶️' : '⏸️')
|
||||
.setStyle(2)
|
||||
.setCustomId(queue.node.isPaused() ? 'resume' : 'pause'),
|
||||
new ButtonBuilder()
|
||||
.setLabel('⏹️')
|
||||
.setStyle(2)
|
||||
.setCustomId('stop'),
|
||||
new ButtonBuilder()
|
||||
.setLabel('⏭️')
|
||||
.setStyle(2)
|
||||
.setCustomId('skip')
|
||||
.setDisabled(queue.tracks.data.length !== 0),
|
||||
new ButtonBuilder()
|
||||
.setLabel('🔉')
|
||||
.setStyle(2)
|
||||
.setCustomId('volume_down')
|
||||
.setDisabled(queue.node.volume === 0),
|
||||
new ButtonBuilder()
|
||||
.setLabel('🔊')
|
||||
.setStyle(2)
|
||||
.setCustomId('volume_up')
|
||||
.setDisabled(queue.node.volume === 100)
|
||||
),
|
||||
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel('🔀')
|
||||
.setStyle(2)
|
||||
.setCustomId('shuffle'),
|
||||
new ButtonBuilder()
|
||||
.setLabel('🔁')
|
||||
.setStyle(2)
|
||||
.setCustomId('loop'),
|
||||
new ButtonBuilder()
|
||||
.setLabel('⏮️')
|
||||
.setStyle(2)
|
||||
.setCustomId('previous')
|
||||
.setDisabled(queue.history.previousTrack ? false : true)
|
||||
)
|
||||
]
|
||||
return ({ embed, components })
|
||||
}
|
||||
|
||||
export async function playerReplay (client: Client, guildProfile: Document) {
|
||||
let dbData = guildProfile.get('guildPlayer.replay')
|
||||
|
||||
let textChannel = client.channels.cache.get(dbData.textChannelId) as TextChannel
|
||||
if (!textChannel) return console.log(`Aucun channel trouvé avec l'id \`${dbData.textChannelId}\`, veuillez utiliser la commande \`/setchannel\` !`)
|
||||
let voiceChannel = client.channels.cache.get(dbData.voiceChannelId) as VoiceChannel
|
||||
if (!voiceChannel) return console.log(`Aucun channel trouvé avec l'id \`${dbData.voiceChannelId}\`, veuillez utiliser la commande \`/setchannel\` !`)
|
||||
|
||||
let player = useMainPlayer()
|
||||
let queue = player.nodes.create(textChannel.guild, {
|
||||
metadata: {
|
||||
channel: textChannel,
|
||||
client: textChannel.guild.members.me,
|
||||
requestedBy: client.user
|
||||
},
|
||||
selfDeaf: true,
|
||||
volume: 20,
|
||||
leaveOnEmpty: true,
|
||||
leaveOnEmptyCooldown: 30000,
|
||||
leaveOnEnd: true,
|
||||
leaveOnEndCooldown: 300000
|
||||
})
|
||||
|
||||
try { if (!queue.connection) await queue.connect(voiceChannel) }
|
||||
catch (error) { console.error(error) }
|
||||
|
||||
let result = await player.search(dbData.trackUrl as string, { requestedBy: client.user || undefined })
|
||||
if (!result.hasTracks()) await textChannel.send(`Aucune musique trouvée pour **${dbData.trackUrl}** !`)
|
||||
let track = result.tracks[0]
|
||||
|
||||
let entry = queue.tasksQueue.acquire()
|
||||
await entry.getTask()
|
||||
queue.addTrack(track)
|
||||
|
||||
try {
|
||||
await queue.node.play()
|
||||
await queue.node.seek(Number(dbData.progress) / 1000)
|
||||
await textChannel.send(`Relancement de la musique suite à mon redémarrage...`)
|
||||
} catch (error) { console.error(error) }
|
||||
finally { queue.tasksQueue.release() }
|
||||
}
|
||||
@@ -88,7 +88,7 @@ export default async (client: Client, guildProfile: Document) => {
|
||||
]
|
||||
|
||||
if (!dbData.feeds) dbData.feeds = feeds
|
||||
dbData.feeds.forEach((feed: Feed, i: Number) => { setTimeout(async () => {
|
||||
dbData.feeds.forEach((feed: Feed, i: number) => { setTimeout(async () => {
|
||||
let parser = new Parser()
|
||||
if (feed.token) feed.url += feed.token
|
||||
let feedData = await parser.parseURL(feed.url)
|
||||
@@ -119,5 +119,5 @@ export default async (client: Client, guildProfile: Document) => {
|
||||
if (lastMessage.content !== `**${lastItem.title}**\n${lastItem.link}`) await thread.send({ content: `**${lastItem.title}**\n${lastItem.link}` })
|
||||
//else console.log('No new item found for ' + feed.name)
|
||||
}, Number(i) * 1000) })
|
||||
} catch (error: any) { console.error(error); return 'clear' }
|
||||
} catch (error) { console.error(error); return 'clear' }
|
||||
}
|
||||
173
src/utils/twitch.ts
Normal file
173
src/utils/twitch.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
import { Guild, TextChannel, EmbedBuilder } from 'discord.js'
|
||||
import axios, { AxiosHeaderValue } from 'axios'
|
||||
import dbGuild from '../schemas/guild'
|
||||
|
||||
interface NotificationData {
|
||||
metadata: {
|
||||
message_type: string
|
||||
}
|
||||
payload: {
|
||||
subscription: {
|
||||
type: string
|
||||
}
|
||||
event: {
|
||||
broadcaster_user_name: string
|
||||
broadcaster_user_login: string
|
||||
}
|
||||
session: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Condition {
|
||||
broadcaster_user_id: string
|
||||
}
|
||||
|
||||
export async function checkChannel (client_id: string, client_secret: string, channel_access_token: string, guild: Guild) {
|
||||
let guildProfile = await dbGuild.findOne({ guildId: guild?.id })
|
||||
if (!guildProfile) return console.log(`Database data for ${guild?.name} does not exist, please initialize with \`/database init\` !`)
|
||||
|
||||
let dbData = guildProfile.get('guildTwitch')
|
||||
if (!dbData?.enabled) return console.log(`Twitch module is disabled for "${guild?.name}", please activate with \`/database edit guildTwitch.enabled True\` !`)
|
||||
|
||||
if (!await validateToken(channel_access_token)) {
|
||||
let channel_refresh_token = dbData.channelRefreshToken
|
||||
if (!channel_refresh_token) return console.log('No refresh token found in database !')
|
||||
|
||||
let GetAccessFromRefresh = await refreshToken(client_id, client_secret, channel_refresh_token)
|
||||
if (!GetAccessFromRefresh) return false;
|
||||
|
||||
[channel_access_token, channel_refresh_token] = [dbData.channelAccessToken, dbData.channelRefreshToken] = GetAccessFromRefresh
|
||||
|
||||
guildProfile.set('guildTwitch', dbData)
|
||||
guildProfile.markModified('guildTwitch')
|
||||
await guildProfile.save().catch(console.error)
|
||||
}
|
||||
return channel_access_token
|
||||
}
|
||||
|
||||
export async function validateToken (access_token: string) {
|
||||
return await axios.get('https://id.twitch.tv/oauth2/validate', {
|
||||
headers: {
|
||||
'Authorization': `OAuth ${access_token}`,
|
||||
}
|
||||
}).then(() => {
|
||||
return true
|
||||
}).catch(error => { console.error(error.response.data) })
|
||||
}
|
||||
|
||||
export async function refreshToken (client_id: string, client_secret: string, refresh_token: string) {
|
||||
return await axios.post('https://id.twitch.tv/oauth2/token', {
|
||||
client_id,
|
||||
client_secret,
|
||||
refresh_token,
|
||||
grant_type: 'refresh_token'
|
||||
}).then(response => {
|
||||
if (response.data.token_type === 'bearer') return [response.data.access_token, response.data.refresh_token]
|
||||
}).catch(error => { console.error(error.response.data) })
|
||||
}
|
||||
|
||||
export async function getStreams (client_id: string, access_token: string, user_login: string) {
|
||||
return await axios.get(`https://api.twitch.tv/helix/streams?user_login=${user_login}`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${access_token}`,
|
||||
'Client-Id': client_id as AxiosHeaderValue
|
||||
}
|
||||
}).then(response => {
|
||||
return response.data.data[0]
|
||||
}).catch(error => { console.error(error.response) })
|
||||
}
|
||||
|
||||
export async function getUserInfo (client_id: string, access_token: string, type: string) {
|
||||
return await axios.get('https://api.twitch.tv/helix/users', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${access_token}`,
|
||||
'Client-Id': client_id as AxiosHeaderValue
|
||||
}
|
||||
}).then(response => {
|
||||
if (type === 'login') return response.data.data[0].login
|
||||
if (type === 'id') return response.data.data[0].id
|
||||
if (type === 'profile_image_url') return response.data.data[0].profile_image_url
|
||||
}).catch(error => { console.error(error.response.data) })
|
||||
}
|
||||
|
||||
export async function notification (client_id: string, channel_access_token: string, data: NotificationData, guild: Guild) {
|
||||
let { subscription, event } = data.payload
|
||||
|
||||
let guildProfile = await dbGuild.findOne({ guildId: guild?.id })
|
||||
if (!guildProfile) return console.log(`Database data for ${guild?.name} does not exist, please initialize with \`/database init\` !`)
|
||||
|
||||
let dbData = guildProfile.get('guildTwitch')
|
||||
if (!dbData?.enabled) return console.log(`Twitch module is disabled for "${guild?.name}", please activate with \`/database edit guildTwitch.enabled True\` !`)
|
||||
|
||||
let liveChannelId = dbData.liveChannelId
|
||||
if (!liveChannelId) return console.log('No live channel id found in database !')
|
||||
|
||||
let liveChannel = guild.channels.cache.get(liveChannelId) as TextChannel
|
||||
if (!liveChannel) return console.log(`\u001b[1;35m Can't find channel with id ${liveChannelId}`)
|
||||
|
||||
if (subscription.type === 'stream.online') {
|
||||
console.log(`\u001b[1;35m Stream from ${event.broadcaster_user_name} is now online, sending Discord message...`)
|
||||
|
||||
let stream_data = await getStreams(client_id, channel_access_token, event.broadcaster_user_login)
|
||||
let user_profile_image_url = await getUserInfo(client_id, channel_access_token, 'profile_image_url')
|
||||
|
||||
let embed = new EmbedBuilder()
|
||||
.setColor('#6441a5')
|
||||
.setTitle(stream_data.title)
|
||||
.setURL(`https://twitch.tv/laytho_`)
|
||||
.setAuthor({ name: `${event.broadcaster_user_login.toUpperCase()} EST ACTUELLEMENT EN LIVE !`, iconURL: user_profile_image_url })
|
||||
.setDescription(`Joue à ${stream_data.game_name} avec ${stream_data.viewer_count} viewers`)
|
||||
.setImage(stream_data.thumbnail_url.replace('{width}', '1920').replace('{height}', '1080'))
|
||||
.setTimestamp()
|
||||
let message = await liveChannel.send({ content: `Hey @everyone ! <@${dbData.liveBroadcasterId}> démarre son live sur **Twitch** !`, embeds: [embed] })
|
||||
|
||||
dbData.liveMessageId = message.id
|
||||
guildProfile.set('guildTwitch', dbData)
|
||||
guildProfile.markModified('guildTwitch')
|
||||
await guildProfile.save().catch(console.error)
|
||||
}
|
||||
else if (subscription.type === 'stream.offline') {
|
||||
console.log(`\u001b[1;35m Stream from laytho_ is now offline, editing Discord message...`)
|
||||
|
||||
let message = liveChannel.messages.cache.find(message => message.id === dbData.liveMessageId)
|
||||
if (!message) return console.log(`\u001b[1;35m Can't find message with id ${dbData.liveMessageId}`)
|
||||
if (!message.embeds[0]) return console.log(`\u001b[1;35m Can't find embed in message with id ${dbData.liveMessageId}`)
|
||||
|
||||
let duration = new Date().getTime() - new Date(message.embeds[0].data.timestamp ?? 0).getTime()
|
||||
let seconds = Math.floor(duration / 1000)
|
||||
let minutes = Math.floor(seconds / 60)
|
||||
let hours = Math.floor(minutes / 60)
|
||||
let duration_string = `${hours ? hours + 'H' : ''} ${minutes % 60 ? minutes % 60 + 'M' : ''} ${seconds % 60 ? seconds % 60 + 'S' : ''}`
|
||||
|
||||
let user_profile_image_url = await getUserInfo(client_id, channel_access_token, 'profile_image_url')
|
||||
|
||||
let embed = new EmbedBuilder()
|
||||
.setColor('#6441a5')
|
||||
.setAuthor({ name: `C'EST FINI, LE LIVE A DURÉ ${duration_string} !`, iconURL: user_profile_image_url })
|
||||
.setTimestamp()
|
||||
|
||||
message.edit({ content: `Re @everyone ! <@${dbData.liveBroadcasterId}> a terminé son live sur **Twitch** !`, embeds: [embed] })
|
||||
}
|
||||
}
|
||||
|
||||
export async function subscribeToEvents (client_id: string, access_token: string, session_id: string, type: string, version: string, condition: Condition) {
|
||||
return await axios.post('https://api.twitch.tv/helix/eventsub/subscriptions', {
|
||||
type,
|
||||
version,
|
||||
condition,
|
||||
transport: {
|
||||
method: 'websocket',
|
||||
session_id
|
||||
}
|
||||
}, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${access_token}`,
|
||||
'Client-Id': client_id,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}).then(response => {
|
||||
return response.data.data[0].status
|
||||
}).catch(error => { return error.response.data })
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
const axios = require('axios')
|
||||
|
||||
module.exports = (async (SESSIONID) => {
|
||||
return await axios.post(`${process.env.AMP_HOST}/API/${__filename.split('utilsAMP/')[1].split('.js')[0]}`, {
|
||||
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 }
|
||||
})
|
||||
})
|
||||
@@ -1,16 +0,0 @@
|
||||
const axios = require('axios')
|
||||
|
||||
module.exports = (async (SESSIONID, InstanceId) => {
|
||||
return await axios.post(`${process.env.AMP_HOST}/API/${__filename.split('utilsAMP/')[1].split('.js')[0]}`, {
|
||||
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 }
|
||||
})
|
||||
})
|
||||
@@ -1,16 +0,0 @@
|
||||
const axios = require('axios')
|
||||
|
||||
module.exports = (async (SESSIONID, InstanceName) => {
|
||||
return await axios.post(`${process.env.AMP_HOST}/API/${__filename.split('utilsAMP/')[1].split('.js')[0]}`, {
|
||||
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 }
|
||||
})
|
||||
})
|
||||
@@ -1,17 +0,0 @@
|
||||
const axios = require('axios')
|
||||
|
||||
module.exports = (async (SESSIONID, InstanceId) => {
|
||||
return await axios.get(`${process.env.AMP_HOST}/API/${__filename.split('utilsAMP/')[1].split('.js')[0]}`, {
|
||||
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 }
|
||||
})
|
||||
})
|
||||
@@ -1,13 +0,0 @@
|
||||
const axios = require('axios')
|
||||
|
||||
module.exports = (async (SESSIONID) => {
|
||||
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 }
|
||||
})
|
||||
})
|
||||
@@ -1,21 +0,0 @@
|
||||
const axios = require('axios')
|
||||
|
||||
const appDir = require('path').dirname(require.main.filename)
|
||||
const writeEnv = require(appDir + '/utils/writeEnv')
|
||||
|
||||
module.exports = (async (details) => {
|
||||
return await axios.post(`${process.env.AMP_HOST}/API/${__filename.split('utilsAMP/')[1].split('.js')[0]}`,
|
||||
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 }
|
||||
})
|
||||
})
|
||||
@@ -1,18 +0,0 @@
|
||||
const axios = require('axios')
|
||||
const fs = require('fs')
|
||||
|
||||
module.exports = download = (async (url, file, headers) => {
|
||||
let path = `./cracks/${file}`
|
||||
let writer = fs.createWriteStream(path)
|
||||
try {
|
||||
await axios({ url: url + file, method: 'GET', responseType: 'stream', headers }).then(response => {
|
||||
return new Promise((resolve, reject) => {
|
||||
response.data.pipe(writer)
|
||||
let error = null
|
||||
writer.on('error', err => { error = err; writer.close(); reject(err) })
|
||||
writer.on('close', () => { if (!error) resolve(true) })
|
||||
})
|
||||
}).catch(console.error)
|
||||
return path
|
||||
} catch (error) { console.error(error) }
|
||||
})
|
||||
@@ -1,23 +0,0 @@
|
||||
const h1 = {
|
||||
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
"x-requested-with": "XMLHttpRequest"
|
||||
}
|
||||
const 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"
|
||||
}
|
||||
|
||||
module.exports = headers = { h1, h2 }
|
||||
@@ -1,12 +0,0 @@
|
||||
const fs = require('fs')
|
||||
|
||||
module.exports = magnet = (async path => {
|
||||
const parseTorrent = await import('parse-torrent')
|
||||
const parse = parseTorrent.default
|
||||
const magnetURI = parseTorrent.toMagnetURI
|
||||
|
||||
let data = await parse(fs.readFileSync(path))
|
||||
let uri = await magnetURI({ infoHash: data.infoHash })
|
||||
|
||||
return uri
|
||||
})
|
||||
@@ -1,13 +0,0 @@
|
||||
const iconv = require('iconv-lite')
|
||||
|
||||
module.exports = repo = (async (game, headers) => {
|
||||
let body = await fetch(game.link, { headers, body: null, method: "GET" })
|
||||
.then(response => response.arrayBuffer())
|
||||
.then(arrayBuffer => { return iconv.decode(Buffer.from(arrayBuffer), 'win1251') })
|
||||
.catch(console.error)
|
||||
try {
|
||||
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) }
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
const iconv = require('iconv-lite')
|
||||
|
||||
module.exports = search = (async (query, headers) => {
|
||||
let body = await fetch("https://online-fix.me/engine/ajax/search.php", { headers, body: `query=${query}`, method: "POST" })
|
||||
.then(response => response.arrayBuffer())
|
||||
.then(arrayBuffer => { return iconv.decode(Buffer.from(arrayBuffer), 'win1251') })
|
||||
.catch(console.error)
|
||||
try {
|
||||
let matches = body.split('</div>')[1].split('<span class="seperator fastfullsearch">')[0].split('</a>')
|
||||
let games = []
|
||||
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 }
|
||||
})
|
||||
@@ -1,8 +0,0 @@
|
||||
module.exports = torrent = (async (url, headers) => {
|
||||
let response = await fetch(url, { headers, body: null, method: "GET" }).catch(console.error)
|
||||
try {
|
||||
let body = await response.text()
|
||||
let file = body.split('<a href="')[2].split('">')[0]
|
||||
return file
|
||||
} catch (error) { console.error(error) }
|
||||
})
|
||||
@@ -1 +0,0 @@
|
||||
export default ['1065047326860783636', '1119343522059927684', '1119344050412204032', '1210714000321548329']
|
||||
@@ -1 +0,0 @@
|
||||
export default ['loop', 'pause', 'previous', 'resume', 'shuffle', 'skip', 'stop', 'volume_down', 'volume_up']
|
||||
@@ -1,55 +0,0 @@
|
||||
import { Client, TextChannel } from 'discord.js'
|
||||
import { useQueue } from 'discord-player'
|
||||
import { Document } from 'mongoose'
|
||||
import getUptime from '../utils/getUptime'
|
||||
import generate from './generate'
|
||||
import bots from './bots'
|
||||
|
||||
export default async (client: Client, guildProfile: Document) => {
|
||||
try {
|
||||
let guild = client.guilds.cache.get(guildProfile.get('guildId'))
|
||||
if (!guild) {
|
||||
clearInterval(client.disco.interval)
|
||||
return 'clear'
|
||||
}
|
||||
|
||||
let dbData = guildProfile.get('guildPlayer.disco')
|
||||
let queue = useQueue(guild.id)
|
||||
if (queue) if (queue.isPlaying()) {
|
||||
dbData['progress'] = queue.node.playbackTime.toString()
|
||||
|
||||
guildProfile.set('guildPlayer.disco', dbData)
|
||||
guildProfile.markModified('guildPlayer.disco')
|
||||
await guildProfile.save().catch(console.error)
|
||||
}
|
||||
|
||||
let channel = client.channels.cache.get(dbData.channelId) as TextChannel
|
||||
if (!channel) {
|
||||
console.log(`Aucun channel trouvé avec l'id \`${dbData.channelId}\`, veuillez utiliser la commande \`/database edit 'value': guildPlayer.disco.channelId\` !`)
|
||||
clearInterval(client.disco.interval)
|
||||
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 (!bots.includes(msg.author.id)) 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 botMessage.edit({ embeds: [embed] })
|
||||
|
||||
} else return channel.send({ embeds: [embed] })
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
return 'clear'
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
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 })
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
import { EmbedBuilder, ButtonBuilder, ActionRowBuilder, Guild } from 'discord.js'
|
||||
import { useQueue } from 'discord-player'
|
||||
|
||||
export default async (guild: Guild) => {
|
||||
let embed = new EmbedBuilder().setColor('#ffc370')
|
||||
|
||||
let queue = useQueue(guild.id)
|
||||
if (!queue) {
|
||||
embed.setTitle('Aucune session d\'écoute en cours !')
|
||||
return ({ embed, components: null })
|
||||
}
|
||||
|
||||
let track = queue.currentTrack
|
||||
if (!track) {
|
||||
embed.setTitle('Aucune musique en cours de lecture !')
|
||||
return ({ embed, components: null })
|
||||
}
|
||||
|
||||
embed.setTitle(track.title)
|
||||
.setAuthor({ name: track.author })
|
||||
.setURL(track.url)
|
||||
.setImage(track.thumbnail)
|
||||
.addFields(
|
||||
{ name: 'Durée', value: track.duration, 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: queue.node.isPaused() ? 'Progression (en pause)' : 'Progression', value: queue.node.createProgressBar() || 'Aucune' },
|
||||
{ name: 'Loop', value: queue.repeatMode === 3 ? 'Autoplay' : queue.repeatMode === 2 ? 'File d\'Attente' : queue.repeatMode === 1 ? 'Titre' : 'Off', inline: true }
|
||||
)
|
||||
.setDescription(`**Musique suivante :** ${queue.tracks.data[0] ? queue.tracks.data[0].title : 'Aucune'}`)
|
||||
.setFooter({ text: `Demandé par ${track.requestedBy ? track.requestedBy.tag : 'Inconnu'}` })
|
||||
|
||||
let components = [
|
||||
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel(queue.node.isPaused() ? '▶️' : '⏸️')
|
||||
.setStyle(2)
|
||||
.setCustomId(queue.node.isPaused() ? 'resume' : 'pause'),
|
||||
new ButtonBuilder()
|
||||
.setLabel('⏹️')
|
||||
.setStyle(2)
|
||||
.setCustomId('stop'),
|
||||
new ButtonBuilder()
|
||||
.setLabel('⏭️')
|
||||
.setStyle(2)
|
||||
.setCustomId('skip')
|
||||
.setDisabled(queue.tracks.data.length !== 0),
|
||||
new ButtonBuilder()
|
||||
.setLabel('🔉')
|
||||
.setStyle(2)
|
||||
.setCustomId('volume_down')
|
||||
.setDisabled(queue.node.volume === 0),
|
||||
new ButtonBuilder()
|
||||
.setLabel('🔊')
|
||||
.setStyle(2)
|
||||
.setCustomId('volume_up')
|
||||
.setDisabled(queue.node.volume === 100)
|
||||
),
|
||||
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel('🔀')
|
||||
.setStyle(2)
|
||||
.setCustomId('shuffle'),
|
||||
new ButtonBuilder()
|
||||
.setLabel('🔁')
|
||||
.setStyle(2)
|
||||
.setCustomId('loop'),
|
||||
new ButtonBuilder()
|
||||
.setLabel('⏮️')
|
||||
.setStyle(2)
|
||||
.setCustomId('previous')
|
||||
.setDisabled(queue.history.previousTrack ? false : true)
|
||||
)
|
||||
]
|
||||
return ({ embed, components })
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import { CommandInteraction, Guild, GuildChannel, TextBasedChannel, VoiceChannel } from 'discord.js'
|
||||
|
||||
type ChannelInferrable = {
|
||||
channel: TextBasedChannel | VoiceChannel
|
||||
guild?: Guild
|
||||
}
|
||||
|
||||
export class PlayerMetadata {
|
||||
public constructor(public data: ChannelInferrable) {
|
||||
if (data.channel.isDMBased()) { throw new Error('PlayerMetadata cannot be created from a DM') }
|
||||
if (!data.channel) { throw new Error('PlayerMetadata can only be created from a channel') }
|
||||
}
|
||||
public get channel() { return this.data.channel! }
|
||||
public get guild() { return this.data.guild || (this.data.channel as GuildChannel).guild }
|
||||
|
||||
public static create(data: ChannelInferrable | CommandInteraction) {
|
||||
if (data instanceof CommandInteraction) {
|
||||
if (!data.inGuild()) { throw new Error('PlayerMetadata cannot be created from a DM') }
|
||||
|
||||
return new PlayerMetadata({ channel: data.channel!, guild: data.guild! })
|
||||
}
|
||||
return new PlayerMetadata(data);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { Client, TextChannel, VoiceChannel } from 'discord.js'
|
||||
import { useMainPlayer } from 'discord-player'
|
||||
import { Document } from 'mongoose'
|
||||
|
||||
export default async (client: Client, guildProfile: Document) => {
|
||||
let dbData = guildProfile.get('guildPlayer.replay')
|
||||
|
||||
let textChannel = client.channels.cache.get(dbData.textChannelId) as TextChannel
|
||||
if (!textChannel) return console.log(`Aucun channel trouvé avec l'id \`${dbData.textChannelId}\`, veuillez utiliser la commande \`/setchannel\` !`)
|
||||
let voiceChannel = client.channels.cache.get(dbData.voiceChannelId) as VoiceChannel
|
||||
if (!voiceChannel) return console.log(`Aucun channel trouvé avec l'id \`${dbData.voiceChannelId}\`, veuillez utiliser la commande \`/setchannel\` !`)
|
||||
|
||||
let player = useMainPlayer()
|
||||
let queue = player.nodes.create(textChannel.guild, {
|
||||
metadata: {
|
||||
channel: textChannel,
|
||||
client: textChannel.guild.members.me,
|
||||
requestedBy: client.user
|
||||
},
|
||||
selfDeaf: true,
|
||||
volume: 20,
|
||||
leaveOnEmpty: true,
|
||||
leaveOnEmptyCooldown: 30000,
|
||||
leaveOnEnd: true,
|
||||
leaveOnEndCooldown: 300000
|
||||
})
|
||||
|
||||
try { if (!queue.connection) await queue.connect(voiceChannel) }
|
||||
catch (error: any) { console.error(error) }
|
||||
|
||||
let result = await player.search(dbData.trackUrl as string, { requestedBy: client.user || undefined })
|
||||
if (!result.hasTracks()) await textChannel.send(`Aucune musique trouvée pour **${dbData.trackUrl}** !`)
|
||||
let track = result.tracks[0]
|
||||
|
||||
let entry = queue.tasksQueue.acquire()
|
||||
await entry.getTask()
|
||||
queue.addTrack(track)
|
||||
|
||||
try {
|
||||
await queue.node.play()
|
||||
await queue.node.seek(Number(dbData.progress) / 1000)
|
||||
await textChannel.send(`Relancement de la musique suite à mon redémarrage...`)
|
||||
} catch (error: any) { console.error(error) }
|
||||
finally { queue.tasksQueue.release() }
|
||||
}
|
||||
Reference in New Issue
Block a user