Ajout RSS + Tentative fix lecture de musique HS
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
.dockerignore
|
||||
.git
|
||||
.gitignore
|
||||
.vscode
|
||||
Dockerfile
|
||||
node_modules
|
||||
README.md
|
||||
.git
|
||||
.vscode
|
||||
node_modules
|
||||
public/cracks
|
||||
.dockerignore
|
||||
.gitignore
|
||||
Dockerfile
|
||||
README.md
|
||||
tsconfig.json
|
||||
.ncurc.json
|
||||
.env
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
node_modules/
|
||||
public/cracks/
|
||||
dist/
|
||||
.env*
|
||||
dist/
|
||||
node_modules/
|
||||
public/cracks/
|
||||
.env*
|
||||
.ncurc.json
|
||||
55
Dockerfile
55
Dockerfile
@@ -1,28 +1,29 @@
|
||||
FROM node:alpine as base
|
||||
|
||||
ENV NODE_ENV=production
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY ["package.json", "package-lock.json*", "./"]
|
||||
RUN apk add --no-cache ffmpeg python3 make g++
|
||||
RUN npm install --production --verbose && mv node_modules ../
|
||||
|
||||
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
|
||||
FROM node:lts-alpine as base
|
||||
|
||||
ENV NODE_ENV=production
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY ["package.json", "package-lock.json*", "./"]
|
||||
RUN apk add --no-cache ffmpeg python3 make g++
|
||||
RUN npm install -g ts-node
|
||||
RUN npm install --production --verbose && mv node_modules ../
|
||||
|
||||
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"]
|
||||
8344
package-lock.json
generated
8344
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
83
package.json
83
package.json
@@ -1,41 +1,42 @@
|
||||
{
|
||||
"name": "bot_tamiseur",
|
||||
"description": "Listen to music and use fun commands with your friends!",
|
||||
"version": "2.0.0",
|
||||
"author": {
|
||||
"name": "Zachary Guénot"
|
||||
},
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"format": "prettier --write .",
|
||||
"start": "node src/index.ts",
|
||||
"dev": "nodemon -e ts src/index.ts",
|
||||
"build": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@discord-player/equalizer": "^0.2.3",
|
||||
"@discord-player/extractor": "^4.4.6",
|
||||
"@discordjs/opus": "^0.9.0",
|
||||
"@discordjs/voice": "^0.16.1",
|
||||
"axios": "^1.6.5",
|
||||
"bufferutil": "^4.0.8",
|
||||
"discord-player": "^6.6.7",
|
||||
"discord.js": "^14.14.1",
|
||||
"dotenv": "^16.3.1",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"jsdom": "^23.2.0",
|
||||
"libsodium-wrappers": "^0.7.13",
|
||||
"mariadb": "^3.2.3",
|
||||
"parse-torrent": "^9.1.5",
|
||||
"require-all": "^3.0.0",
|
||||
"sqlite3": "^5.1.7",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "bot_tamiseur",
|
||||
"description": "Listen to music and use fun commands with your friends!",
|
||||
"version": "2.1.0",
|
||||
"author": {
|
||||
"name": "Zachary Guénot"
|
||||
},
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"format": "prettier --write .",
|
||||
"start": "ts-node src/index.ts",
|
||||
"dev": "nodemon -e ts src/index.ts",
|
||||
"build": "ncc build src/index.ts -o dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@discord-player/equalizer": "^0.2.3",
|
||||
"@discord-player/extractor": "^4.4.6",
|
||||
"@discordjs/opus": "^0.9.0",
|
||||
"@discordjs/voice": "^0.16.1",
|
||||
"@types/parse-torrent": "^5.8.7",
|
||||
"axios": "^1.6.7",
|
||||
"bufferutil": "^4.0.8",
|
||||
"discord-player": "^6.6.7",
|
||||
"discord.js": "^14.14.1",
|
||||
"dotenv": "^16.4.5",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"jsdom": "^24.0.0",
|
||||
"libsodium-wrappers": "^0.7.13",
|
||||
"mariadb": "^3.2.3",
|
||||
"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.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.57.0",
|
||||
"nodemon": "^3.1.0",
|
||||
"prettier": "^3.2.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,91 +1,91 @@
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction, AutocompleteInteraction, GuildMember } from 'discord.js'
|
||||
import { useMainPlayer, useQueue, QueryType } from 'discord-player'
|
||||
import writeEnv from '../../utils/writeEnv'
|
||||
|
||||
export interface TrackSearchResult { name: string, value: string }
|
||||
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('play')
|
||||
.setDescription('Jouer une musique.')
|
||||
.addStringOption(option => option.setName('recherche').setDescription('Titre de la musique à chercher').setRequired(true).setAutocomplete(true)),
|
||||
async autocompleteRun(interaction: AutocompleteInteraction) {
|
||||
let query = interaction.options.getString('recherche', true)
|
||||
if (!query) return interaction.respond([])
|
||||
|
||||
let player = useMainPlayer()
|
||||
|
||||
const resultsYouTube = await player.search(query, { searchEngine: QueryType.YOUTUBE })
|
||||
const resultsSpotify = await player.search(query, { searchEngine: QueryType.SPOTIFY_SEARCH })
|
||||
|
||||
const tracksYouTube = resultsYouTube.tracks.slice(0, 5).map((t) => ({
|
||||
name: `YouTube: ${`${t.title} - ${t.author} (${t.duration})`.length > 75 ? `${`${t.title} - ${t.author}`.substring(0, 75)}... (${t.duration})` : `${t.title} - ${t.author} (${t.duration})`}`,
|
||||
value: t.url
|
||||
}))
|
||||
const tracksSpotify = resultsSpotify.tracks.slice(0, 5).map((t) => ({
|
||||
name: `Spotify: ${`${t.title} - ${t.author} (${t.duration})`.length > 75 ? `${`${t.title} - ${t.author}`.substring(0, 75)}... (${t.duration})` : `${t.title} - ${t.author} (${t.duration})`}`,
|
||||
value: t.url
|
||||
}))
|
||||
|
||||
const tracks: TrackSearchResult[] = []
|
||||
tracksYouTube.forEach((t) => tracks.push({ name: t.name, value: t.value }))
|
||||
tracksSpotify.forEach((t) => tracks.push({ name: t.name, value: t.value }))
|
||||
|
||||
return interaction.respond(tracks)
|
||||
},
|
||||
async execute(interaction: ChatInputCommandInteraction) {
|
||||
let member = interaction.member as GuildMember
|
||||
let voiceChannel = member.voice.channel
|
||||
if (!voiceChannel) return await interaction.reply({ content: 'T\'es pas dans un vocal, idiot !', ephemeral: true })
|
||||
|
||||
let botChannel = interaction.guild?.members.me?.voice.channel
|
||||
if (botChannel && voiceChannel.id !== botChannel.id) return await interaction.reply({ content: 'T\'es pas dans mon vocal !', ephemeral: true })
|
||||
|
||||
await interaction.deferReply()
|
||||
|
||||
let query = interaction.options.getString('recherche', true)
|
||||
let player = useMainPlayer()
|
||||
let queue = useQueue(interaction.guild?.id ?? '')
|
||||
|
||||
if (!queue) {
|
||||
if (interaction.guild) queue = player.nodes.create(interaction.guild, {
|
||||
metadata: {
|
||||
channel: interaction.channel,
|
||||
client: interaction.guild.members.me,
|
||||
requestedBy: interaction.user
|
||||
},
|
||||
selfDeaf: true,
|
||||
volume: 20,
|
||||
leaveOnEmpty: true,
|
||||
leaveOnEmptyCooldown: 30000,
|
||||
leaveOnEnd: true,
|
||||
leaveOnEndCooldown: 300000
|
||||
})
|
||||
else return
|
||||
}
|
||||
try { if (!queue.connection) await queue.connect(voiceChannel) }
|
||||
catch (error: 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 })
|
||||
if (!result.hasTracks()) return interaction.followUp(`Aucune musique trouvée pour **${query}** !`)
|
||||
let track = result.tracks[0]
|
||||
console.log(track.duration)
|
||||
console.log(track.durationMS)
|
||||
|
||||
let entry = queue.tasksQueue.acquire()
|
||||
await entry.getTask()
|
||||
queue.addTrack(track)
|
||||
|
||||
try {
|
||||
if (!queue.isPlaying()) await queue.node.play()
|
||||
let track_source = track.source === 'youtube' ? 'Youtube' : track.source === 'spotify' ? 'Spotify' : 'Inconnu'
|
||||
return interaction.followUp(`Chargement de la musique **${track.title}** de **${track.author}** sur **${track_source}**...`)
|
||||
} catch (error: any) { console.error(error); return interaction.followUp(`Y'a eu un problème, <@223831938346123275> ! (${error.message})`) }
|
||||
finally { queue.tasksQueue.release() }
|
||||
}
|
||||
import { SlashCommandBuilder, ChatInputCommandInteraction, AutocompleteInteraction, GuildMember } from 'discord.js'
|
||||
import { useMainPlayer, useQueue, QueryType } from 'discord-player'
|
||||
import writeEnv from '../../utils/writeEnv'
|
||||
|
||||
export interface TrackSearchResult { name: string, value: string }
|
||||
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('play')
|
||||
.setDescription('Jouer une musique.')
|
||||
.addStringOption(option => option.setName('recherche').setDescription('Titre de la musique à chercher').setRequired(true).setAutocomplete(true)),
|
||||
async autocompleteRun(interaction: AutocompleteInteraction) {
|
||||
let query = interaction.options.getString('recherche', true)
|
||||
if (!query) return interaction.respond([])
|
||||
|
||||
let player = useMainPlayer()
|
||||
|
||||
const resultsYouTube = await player.search(query, { searchEngine: QueryType.YOUTUBE })
|
||||
const resultsSpotify = await player.search(query, { searchEngine: QueryType.SPOTIFY_SEARCH })
|
||||
|
||||
const tracksYouTube = resultsYouTube.tracks.slice(0, 5).map((t) => ({
|
||||
name: `YouTube: ${`${t.title} - ${t.author} (${t.duration})`.length > 75 ? `${`${t.title} - ${t.author}`.substring(0, 75)}... (${t.duration})` : `${t.title} - ${t.author} (${t.duration})`}`,
|
||||
value: t.url
|
||||
}))
|
||||
const tracksSpotify = resultsSpotify.tracks.slice(0, 5).map((t) => ({
|
||||
name: `Spotify: ${`${t.title} - ${t.author} (${t.duration})`.length > 75 ? `${`${t.title} - ${t.author}`.substring(0, 75)}... (${t.duration})` : `${t.title} - ${t.author} (${t.duration})`}`,
|
||||
value: t.url
|
||||
}))
|
||||
|
||||
const tracks: TrackSearchResult[] = []
|
||||
tracksYouTube.forEach((t) => tracks.push({ name: t.name, value: t.value }))
|
||||
tracksSpotify.forEach((t) => tracks.push({ name: t.name, value: t.value }))
|
||||
|
||||
return interaction.respond(tracks)
|
||||
},
|
||||
async execute(interaction: ChatInputCommandInteraction) {
|
||||
let member = interaction.member as GuildMember
|
||||
let voiceChannel = member.voice.channel
|
||||
if (!voiceChannel) return await interaction.reply({ content: 'T\'es pas dans un vocal, idiot !', ephemeral: true })
|
||||
|
||||
let botChannel = interaction.guild?.members.me?.voice.channel
|
||||
if (botChannel && voiceChannel.id !== botChannel.id) return await interaction.reply({ content: 'T\'es pas dans mon vocal !', ephemeral: true })
|
||||
|
||||
await interaction.deferReply()
|
||||
|
||||
let query = interaction.options.getString('recherche', true)
|
||||
let player = useMainPlayer()
|
||||
let queue = useQueue(interaction.guild?.id ?? '')
|
||||
|
||||
if (!queue) {
|
||||
if (interaction.guild) queue = player.nodes.create(interaction.guild, {
|
||||
metadata: {
|
||||
channel: interaction.channel,
|
||||
client: interaction.guild.members.me,
|
||||
requestedBy: interaction.user
|
||||
},
|
||||
selfDeaf: true,
|
||||
volume: 20,
|
||||
leaveOnEmpty: true,
|
||||
leaveOnEmptyCooldown: 30000,
|
||||
leaveOnEnd: true,
|
||||
leaveOnEndCooldown: 300000
|
||||
})
|
||||
else return
|
||||
}
|
||||
try { if (!queue.connection) await queue.connect(voiceChannel) }
|
||||
catch (error: 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 })
|
||||
if (!result.hasTracks()) return interaction.followUp(`Aucune musique trouvée pour **${query}** !`)
|
||||
let track = result.tracks[0]
|
||||
console.log(track.duration)
|
||||
console.log(track.durationMS)
|
||||
|
||||
let entry = queue.tasksQueue.acquire()
|
||||
await entry.getTask()
|
||||
queue.addTrack(track)
|
||||
|
||||
try {
|
||||
if (!queue.isPlaying()) await queue.node.play()
|
||||
let track_source = track.source === 'youtube' ? 'Youtube' : track.source === 'spotify' ? 'Spotify' : 'Inconnu'
|
||||
return interaction.followUp(`Chargement de la musique **${track.title}** de **${track.author}** sur **${track_source}**...`)
|
||||
} catch (error: any) { console.error(error); return interaction.followUp(`Y'a eu un problème, <@223831938346123275> ! (${error.message})`) }
|
||||
finally { queue.tasksQueue.release() }
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,39 @@
|
||||
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)
|
||||
}
|
||||
import { Events, Client, ActivityType } from 'discord.js'
|
||||
import { useMainPlayer } from 'discord-player'
|
||||
import replay from '../utilsPlayer/replay'
|
||||
import disco from '../utilsPlayer/disco'
|
||||
import rss from '../utils/rss'
|
||||
import 'dotenv/config'
|
||||
|
||||
declare module "discord.js" {
|
||||
export interface Client {
|
||||
disco: { interval: NodeJS.Timeout },
|
||||
rss: { 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)
|
||||
|
||||
client.rss = { interval: {} as NodeJS.Timeout }
|
||||
client.rss.interval = setInterval(async () => {
|
||||
let state = await rss(client)
|
||||
if (state === 'clear') clearInterval(client.rss.interval)
|
||||
}, 30000)
|
||||
rss(client)
|
||||
}
|
||||
}
|
||||
177
src/index.ts
177
src/index.ts
@@ -1,89 +1,90 @@
|
||||
// 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
|
||||
// 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 commands = [] as Command[]
|
||||
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); commands.push(commandData) }
|
||||
} 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: 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()
|
||||
105
src/utils/rss.ts
Normal file
105
src/utils/rss.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { Client, TextChannel } from 'discord.js'
|
||||
import Parser from 'rss-parser'
|
||||
import 'dotenv/config'
|
||||
|
||||
export default async (client: Client) => {
|
||||
try {
|
||||
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'
|
||||
}
|
||||
let channel = client.channels.cache.get(process.env.DISCORD_RSSCHANNEL_ID as string) as TextChannel
|
||||
if (!channel) {
|
||||
clearInterval(client.disco.interval)
|
||||
console.log(`Aucun channel trouvé avec l'id \`${process.env.DISCORD_RSSCHANNEL_ID}\`, veuillez utiliser la commande \`/setchannel\` !`)
|
||||
return 'clear'
|
||||
}
|
||||
let feeds = [
|
||||
{
|
||||
name: 'Nautiljon - Actualités',
|
||||
url: 'https://www.nautiljon.com/actualite/rss.php'
|
||||
},
|
||||
{
|
||||
name: 'Nautiljon - Les Brèves',
|
||||
url: 'https://www.nautiljon.com/breves/rss.php'
|
||||
},
|
||||
{
|
||||
name: 'YGG - Application',
|
||||
url: 'https://www3.yggtorrent.qa/rss?action=generate&type=cat&id=2144&passkey='
|
||||
},
|
||||
{
|
||||
name: 'YGG - Audio',
|
||||
url: 'https://www3.yggtorrent.qa/rss?action=generate&type=cat&id=2139&passkey='
|
||||
},
|
||||
{
|
||||
name: 'YGG - eBook',
|
||||
url: 'https://www3.yggtorrent.qa/rss?action=generate&type=cat&id=2140&passkey='
|
||||
},
|
||||
{
|
||||
name: 'YGG - Emulation',
|
||||
url: 'https://www3.yggtorrent.qa/rss?action=generate&type=cat&id=2141&passkey='
|
||||
},
|
||||
{
|
||||
name: 'YGG - Flim/Vidéo',
|
||||
url: 'https://www3.yggtorrent.qa/rss?action=generate&type=cat&id=2145&passkey='
|
||||
},
|
||||
{
|
||||
name: 'YGG - GPS',
|
||||
url: 'https://www3.yggtorrent.qa/rss?action=generate&type=cat&id=2143&passkey='
|
||||
},
|
||||
{
|
||||
name: 'YGG - Imprimante 3D',
|
||||
url: 'https://www3.yggtorrent.qa/rss?action=generate&type=cat&id=2200&passkey='
|
||||
},
|
||||
{
|
||||
name: 'YGG - Jeu Vidéo',
|
||||
url: 'https://www3.yggtorrent.qa/rss?action=generate&type=cat&id=2142&passkey='
|
||||
},
|
||||
{
|
||||
name: 'YGG - Nulled',
|
||||
url: 'https://www3.yggtorrent.qa/rss?action=generate&type=cat&id=2300&passkey='
|
||||
},
|
||||
{
|
||||
name: 'YGG - XXX',
|
||||
url: 'https://www3.yggtorrent.qa/rss?action=generate&type=cat&id=2188&passkey='
|
||||
}
|
||||
]
|
||||
|
||||
feeds.forEach((feed, i) => { setTimeout(async () => {
|
||||
let parser = new Parser()
|
||||
let url = feed.url
|
||||
if (feed.name.includes('YGG')) url += process.env.YGG_PASSKEY
|
||||
let feedData = await parser.parseURL(url)
|
||||
|
||||
let thread = await channel.threads.cache.find(thread => thread.name === feed.name)
|
||||
if (!thread) {
|
||||
thread = await channel.threads.create({
|
||||
name: feed.name,
|
||||
autoArchiveDuration: 60,
|
||||
reason: 'Création du fil RSS'
|
||||
})
|
||||
await thread.send({ content: 'Fil RSS créé !'})
|
||||
await thread.send({ content: `Visionnage de **${feedData.title}** sur ${feedData.link}...` })
|
||||
|
||||
if (feed.name.includes('YGG')) {
|
||||
let lastItem = feedData.items[0]
|
||||
await thread.send({ content: `**${lastItem.title}**\n${lastItem.link}` })
|
||||
}
|
||||
else feedData.items.forEach(async (item, i) => { setTimeout(async () => {
|
||||
await thread?.send({ content: `**${item.title}**\n${item.link}` })
|
||||
}, i * 1000) })
|
||||
}
|
||||
|
||||
let lastItem = feedData.items[0]
|
||||
let messages = await thread.messages.fetch({ limit: 1 })
|
||||
|
||||
let lastMessage = messages.first()
|
||||
if (!lastMessage) return console.log('No last message found for ' + feed.name)
|
||||
|
||||
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)
|
||||
}, i * 1000) })
|
||||
} catch (error: any) { console.error(error); return 'clear' }
|
||||
}
|
||||
@@ -1,40 +1,42 @@
|
||||
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] })
|
||||
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) => {
|
||||
try {
|
||||
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_DISCOCHANNEL_ID as string) as TextChannel
|
||||
if (!channel) {
|
||||
clearInterval(client.disco.interval)
|
||||
console.log(`Aucun channel trouvé avec l'id \`${process.env.DISCORD_DISCOCHANNEL_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] })
|
||||
} catch (error: any) { console.error(error); return 'clear' }
|
||||
}
|
||||
@@ -1,42 +1,42 @@
|
||||
import { Client, TextChannel, VoiceChannel } from 'discord.js'
|
||||
import { useMainPlayer } from 'discord-player'
|
||||
|
||||
export default async (client: Client) => {
|
||||
let textChannel = client.channels.cache.get(process.env.DISCORD_MUSIC_TEXTCHANNEL_ID as string) as TextChannel
|
||||
if (!textChannel) return console.log(`Aucun channel trouvé avec l'id \`${process.env.DISCORD_MUSIC_TEXTCHANNEL_ID}\`, veuillez utiliser la commande \`/setchannel\` !`)
|
||||
let voiceChannel = client.channels.cache.get(process.env.DISCORD_MUSIC_VOICECHANNEL_ID as string) as VoiceChannel
|
||||
if (!voiceChannel) return console.log(`Aucun channel trouvé avec l'id \`${process.env.DISCORD_MUSIC_VOICECHANNEL_ID}\`, 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); await textChannel.send(`Y'a eu un problème, <@223831938346123275> ! (${error.message})`) }
|
||||
|
||||
let result = await player.search(process.env.DISCORD_MUSIC_CURRENT_TRACK as string, { requestedBy: client.user || undefined })
|
||||
if (!result.hasTracks()) await textChannel.send(`Aucune musique trouvée pour **${process.env.DISCORD_MUSIC_CURRENT_TRACK}** !`)
|
||||
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(process.env.DISCORD_MUSIC_CURRENT_PROGRESS))
|
||||
await textChannel.send(`Relancement de la musique suite à mon redémarrage...`)
|
||||
} catch (error: any) { console.error(error); await textChannel.send(`Y'a eu un problème, <@223831938346123275> ! (${error.message})`) }
|
||||
finally { queue.tasksQueue.release() }
|
||||
import { Client, TextChannel, VoiceChannel } from 'discord.js'
|
||||
import { useMainPlayer } from 'discord-player'
|
||||
|
||||
export default async (client: Client) => {
|
||||
let textChannel = client.channels.cache.get(process.env.DISCORD_MUSIC_TEXTCHANNEL_ID as string) as TextChannel
|
||||
if (!textChannel) return console.log(`Aucun channel trouvé avec l'id \`${process.env.DISCORD_MUSIC_TEXTCHANNEL_ID}\`, veuillez utiliser la commande \`/setchannel\` !`)
|
||||
let voiceChannel = client.channels.cache.get(process.env.DISCORD_MUSIC_VOICECHANNEL_ID as string) as VoiceChannel
|
||||
if (!voiceChannel) return console.log(`Aucun channel trouvé avec l'id \`${process.env.DISCORD_MUSIC_VOICECHANNEL_ID}\`, 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); await textChannel.send(`Y'a eu un problème, <@223831938346123275> ! (${error.message})`) }
|
||||
|
||||
let result = await player.search(process.env.DISCORD_MUSIC_CURRENT_TRACK as string, { requestedBy: client.user || undefined })
|
||||
if (!result.hasTracks()) await textChannel.send(`Aucune musique trouvée pour **${process.env.DISCORD_MUSIC_CURRENT_TRACK}** !`)
|
||||
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(process.env.DISCORD_MUSIC_CURRENT_PROGRESS) / 1000)
|
||||
await textChannel.send(`Relancement de la musique suite à mon redémarrage...`)
|
||||
} catch (error: any) { console.error(error); await textChannel.send(`Y'a eu un problème, <@223831938346123275> ! (${error.message})`) }
|
||||
finally { queue.tasksQueue.release() }
|
||||
}
|
||||
@@ -11,5 +11,6 @@
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
},
|
||||
"include": ["./src/**/*"]
|
||||
}
|
||||
"include": ["./src/**/*"],
|
||||
"exclude": ["./src/utilsAMP/**/*", "./src/utilsCrack/**/*"]
|
||||
}
|
||||
Reference in New Issue
Block a user