backend-0.2.0 => main #1
61
backend/package-lock.json
generated
61
backend/package-lock.json
generated
@@ -24,9 +24,11 @@
|
|||||||
"nodemon": "^3.1.9",
|
"nodemon": "^3.1.9",
|
||||||
"pm2": "^5.4.3",
|
"pm2": "^5.4.3",
|
||||||
"socket.io": "^4.8.1",
|
"socket.io": "^4.8.1",
|
||||||
|
"soundcloud.ts": "^0.6.3",
|
||||||
"spotify-web-api-node": "^5.0.2",
|
"spotify-web-api-node": "^5.0.2",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
"webmetrik": "^0.1.4"
|
"webmetrik": "^0.1.4",
|
||||||
|
"ytfps": "^1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@derhuerst/http-basic": {
|
"node_modules/@derhuerst/http-basic": {
|
||||||
@@ -65,6 +67,16 @@
|
|||||||
"spotify-url-info": "^3.2.6"
|
"spotify-url-info": "^3.2.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@discord-player/extractor/node_modules/soundcloud.ts": {
|
||||||
|
"version": "0.5.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/soundcloud.ts/-/soundcloud.ts-0.5.5.tgz",
|
||||||
|
"integrity": "sha512-bygjhC1w/w26Nk0Y+4D4cWSEJ1TdxLaE6+w4pCazFzPF+J4mzuB62ggWmFa7BiwnirzNf9lgPbjzrQYGege4Ew==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"undici": "^6.17.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@discord-player/ffmpeg": {
|
"node_modules/@discord-player/ffmpeg": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@discord-player/ffmpeg/-/ffmpeg-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@discord-player/ffmpeg/-/ffmpeg-7.1.0.tgz",
|
||||||
@@ -1560,6 +1572,32 @@
|
|||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.1.tgz",
|
||||||
|
"integrity": "sha512-NN+fvwH/kV01dYUQ3PTOZns4LWtWhOFCAhQ/pHb88WQ1hNe5V/dvFwc4VJcDL11LT9xSX0QtsR8sWUuyOuOq7g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.6",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/axios/node_modules/form-data": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@@ -5569,14 +5607,10 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/soundcloud.ts": {
|
"node_modules/soundcloud.ts": {
|
||||||
"version": "0.5.5",
|
"version": "0.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/soundcloud.ts/-/soundcloud.ts-0.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/soundcloud.ts/-/soundcloud.ts-0.6.3.tgz",
|
||||||
"integrity": "sha512-bygjhC1w/w26Nk0Y+4D4cWSEJ1TdxLaE6+w4pCazFzPF+J4mzuB62ggWmFa7BiwnirzNf9lgPbjzrQYGege4Ew==",
|
"integrity": "sha512-Ri5bO0jQKKACijGP1/OVbWXhHREDST2T6QUSAPWlzQjUScXVyh+7YJfN1mTnyuAA7vZjKyZ1FMlWC2hKd7jmHQ==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
|
||||||
"undici": "^6.17.0"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
@@ -6559,6 +6593,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/ytfps": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ytfps/-/ytfps-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-DLcW0opwT0zO+4C5YqcCgPiOIzAtge6q6q3nDW0gCBy4kPufEdyxmjd1O9GUV4WeAFxfA2XNhZLmaohrGKV1WA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.7.2"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -33,8 +33,10 @@
|
|||||||
"nodemon": "^3.1.9",
|
"nodemon": "^3.1.9",
|
||||||
"pm2": "^5.4.3",
|
"pm2": "^5.4.3",
|
||||||
"socket.io": "^4.8.1",
|
"socket.io": "^4.8.1",
|
||||||
|
"soundcloud.ts": "^0.6.3",
|
||||||
"spotify-web-api-node": "^5.0.2",
|
"spotify-web-api-node": "^5.0.2",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
"webmetrik": "^0.1.4"
|
"webmetrik": "^0.1.4",
|
||||||
|
"ytfps": "^1.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,9 +5,13 @@ const { __glob } = require("../utils/GlobalVars")
|
|||||||
const { LogType } = require("loguix")
|
const { LogType } = require("loguix")
|
||||||
const config = require("../utils/Database/Configuration")
|
const config = require("../utils/Database/Configuration")
|
||||||
const metric = require("webmetrik")
|
const metric = require("webmetrik")
|
||||||
|
const { Player } = require("../player/Player")
|
||||||
|
|
||||||
const dlog = new LogType("Discord")
|
const dlog = new LogType("Discord")
|
||||||
|
|
||||||
|
const membersVoices = new Map()
|
||||||
|
const timers = new Map()
|
||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
intents:[GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMembers],
|
intents:[GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMembers],
|
||||||
})
|
})
|
||||||
@@ -68,7 +72,42 @@ function init() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: Implement the disconnect event for the bot
|
client.on("voiceStateUpdate", (oldMember, newMember) => {
|
||||||
|
membersVoices.set(newMember.id, {
|
||||||
|
guildId: newMember.guild.id,
|
||||||
|
channelId: newMember.channelId,
|
||||||
|
})
|
||||||
|
|
||||||
|
const player = new Player(newMember.guild.id)
|
||||||
|
|
||||||
|
if(player.connection && player.channelId) {
|
||||||
|
client.channels.fetch(player.channelId).then(channel => {
|
||||||
|
|
||||||
|
if(channel.members.size <= 1) {
|
||||||
|
|
||||||
|
// If the player is alone in the channel, we will destroy it in 10 minutes
|
||||||
|
// 10 minutes = 600000 ms
|
||||||
|
// 10 second = 10000 ms
|
||||||
|
timers.set(newMember.guild.id, setTimeout(() => {
|
||||||
|
const getPlayer = new Player(newMember.guild.id)
|
||||||
|
if(getPlayer.connection && player.channelId) {
|
||||||
|
getPlayer.leave()
|
||||||
|
dlog.log("[Automatic Task] Guild Id :" + newMember.guild.id + " - Player supprimé : " + channel.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 10000))
|
||||||
|
dlog.log("[Automatic Task] Guild Id :" + newMember.guild.id + " - Player supprimé dans 10 minutess : " + channel.name)
|
||||||
|
} else {
|
||||||
|
dlog.log("[Automatic Task] Guild Id :" + newMember.guild.id + " - Player n'est pas seul dans le channel : " + channel.name)
|
||||||
|
clearTimeout(timers.get(newMember.guild.id))
|
||||||
|
timers.delete(newMember.guild.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -3,6 +3,7 @@ const { Embed, EmbedError } = require("../Embed");
|
|||||||
const { Player } = require("../../player/Player");
|
const { Player } = require("../../player/Player");
|
||||||
const Finder = require("../../player/Finder");
|
const Finder = require("../../player/Finder");
|
||||||
const { Playlist } = require("../../player/Playlist");
|
const { Playlist } = require("../../player/Playlist");
|
||||||
|
const spotify = require("../../media/SpotifyInformation");
|
||||||
|
|
||||||
const command = new Command("play", "Jouer une musique à partir d'un lien dans un salon vocal", async (client, interaction) => {
|
const command = new Command("play", "Jouer une musique à partir d'un lien dans un salon vocal", async (client, interaction) => {
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ const command = new Command("play", "Jouer une musique à partir d'un lien dans
|
|||||||
const url = interaction.options.get("url")
|
const url = interaction.options.get("url")
|
||||||
const channel = interaction.member.voice.channel
|
const channel = interaction.member.voice.channel
|
||||||
const now = interaction.options.getBoolean("now") || false
|
const now = interaction.options.getBoolean("now") || false
|
||||||
await Finder.search(url.value).then((song) => {
|
await Finder.search(url.value).then(async (song) => {
|
||||||
if(!song) return new EmbedError("Impossible de trouver la musique à partir du lien donné ou des mots clés donnés").send(interaction)
|
if(!song) return new EmbedError("Impossible de trouver la musique à partir du lien donné ou des mots clés donnés").send(interaction)
|
||||||
|
|
||||||
const player = new Player(channel.guildId)
|
const player = new Player(channel.guildId)
|
||||||
@@ -23,34 +24,22 @@ const command = new Command("play", "Jouer une musique à partir d'un lien dans
|
|||||||
// Check if song is playlist
|
// Check if song is playlist
|
||||||
if(song instanceof Playlist) {
|
if(song instanceof Playlist) {
|
||||||
|
|
||||||
if(now) {
|
|
||||||
player.readPlaylist(song, true)
|
|
||||||
embed.setTitle('**Lecture immédiate**')
|
|
||||||
} else {
|
|
||||||
player.readPlaylist(song)
|
|
||||||
embed.setTitle('**Ajout à la liste de lecture**')
|
|
||||||
}
|
|
||||||
embed.setDescription('**Playlist : **' + song.songs.length + ' musiques')
|
embed.setDescription('**Playlist : **' + song.songs.length + ' musiques')
|
||||||
embed.addField('**Titre : **' + song.title, "")
|
embed.addField('**Titre : **' + song.title, "")
|
||||||
embed.addField('**Demandé par : **', interaction.member.user.username,)
|
embed.addField('**Demandé par : **', interaction.member.user.username,)
|
||||||
embed.addField('**Auteur : **', song.author)
|
embed.addField('**Auteur : **', song.author)
|
||||||
embed.addField('**Durée : **', song.readduration)
|
embed.addField('**Provient de : **', song.type.replace(/^\w/, (c) => c.toUpperCase()))
|
||||||
|
if(!song.type == "spotify") {
|
||||||
|
embed.addField('**Durée : **', song.readduration)
|
||||||
|
}
|
||||||
|
embed.addField('**Lien : **', song.url)
|
||||||
|
embed.addField(":warning: La récupération des musiques peut prendre du temps", "Veuillez patienter ... et éviter de lancer d'autres commandes")
|
||||||
|
|
||||||
|
|
||||||
embed.setThumbnail(song.thumbnail)
|
embed.setThumbnail(song.thumbnail)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if(now) {
|
|
||||||
|
|
||||||
player.play(song)
|
|
||||||
embed.setTitle('**Lecture immédiate**')
|
|
||||||
|
|
||||||
} else {
|
|
||||||
player.add(song)
|
|
||||||
embed.setTitle('**Ajout à liste de lecture**')
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
embed.setDescription('**Titre : **' + song.title)
|
embed.setDescription('**Titre : **' + song.title)
|
||||||
embed.addField('**Durée : **', song.readduration)
|
embed.addField('**Durée : **', song.readduration)
|
||||||
embed.addField("**Artiste : **",song.author)
|
embed.addField("**Artiste : **",song.author)
|
||||||
@@ -60,9 +49,42 @@ const command = new Command("play", "Jouer une musique à partir d'un lien dans
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(now) {
|
||||||
|
embed.setTitle("Lecture immédiate")
|
||||||
|
} else {
|
||||||
|
embed.setTitle("Ajoutée à la file d'attente")
|
||||||
|
}
|
||||||
|
|
||||||
embed.send(interaction)
|
embed.send(interaction)
|
||||||
|
|
||||||
|
if(song instanceof Playlist) {
|
||||||
|
if(song.type == "spotify") {
|
||||||
|
song = await spotify.getTracks(song)
|
||||||
|
}
|
||||||
|
if(now) {
|
||||||
|
player.readPlaylist(song, true)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
player.readPlaylist(song)
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
|
||||||
|
if(now) {
|
||||||
|
|
||||||
|
player.play(song)
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
player.add(song)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
}, [{type: "STRING", name: "url", description: "Recherche / Lien audio (Youtube / Soundclound / Spotify)", required: true},
|
}, [{type: "STRING", name: "url", description: "Recherche / Lien audio (Youtube / Soundclound / Spotify)", required: true},
|
||||||
|
@@ -0,0 +1,85 @@
|
|||||||
|
const {LogType} = require('loguix');
|
||||||
|
const clog = new LogType("SoundcloudInformation");
|
||||||
|
const {Song} = require('../player/Song');
|
||||||
|
const {Playlist} = require('../player/Playlist');
|
||||||
|
const {Soundcloud} = require('soundcloud.ts')
|
||||||
|
const {getReadableDuration} = require('../utils/TimeConverter');
|
||||||
|
|
||||||
|
const soundcloud = new Soundcloud();
|
||||||
|
|
||||||
|
async function getTrack(url) {
|
||||||
|
try {
|
||||||
|
const info = await soundcloud.tracks.get(url)
|
||||||
|
|
||||||
|
if(!info) {
|
||||||
|
clog.error("Impossible de récupérer les informations de la piste Soundcloud à partir de l'URL");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const song = new Song();
|
||||||
|
song.title = info.title;
|
||||||
|
song.author = info.user.username;
|
||||||
|
song.url = info.permalink_url;
|
||||||
|
song.thumbnail = info.artwork_url;
|
||||||
|
song.id = info.id;
|
||||||
|
song.duration = info.duration / 1000;
|
||||||
|
song.readduration = getReadableDuration(info.duration / 1000);
|
||||||
|
song.type = "soundcloud";
|
||||||
|
|
||||||
|
return song;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
clog.error('Erreur lors de la recherche Soundcloud (Track): ' + error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPlaylist(url) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
const info = await soundcloud.playlists.get(url)
|
||||||
|
|
||||||
|
if(!info) {
|
||||||
|
clog.error("Impossible de récupérer les informations de la playlist Soundcloud à partir de l'URL");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const playlist = new Playlist();
|
||||||
|
|
||||||
|
playlist.title = info.title;
|
||||||
|
playlist.author = info.user.username;
|
||||||
|
playlist.url = info.permalink_url;
|
||||||
|
playlist.thumbnail = info.artwork_url;
|
||||||
|
playlist.id = info.id;
|
||||||
|
playlist.duration = 0;
|
||||||
|
playlist.songs = [];
|
||||||
|
playlist.type = "soundcloud";
|
||||||
|
|
||||||
|
for(const track of info.tracks) {
|
||||||
|
const song = new Song();
|
||||||
|
song.title = track.title;
|
||||||
|
song.author = track.user.username;
|
||||||
|
song.url = track.permalink_url;
|
||||||
|
song.thumbnail = track.artwork_url;
|
||||||
|
song.id = track.id;
|
||||||
|
song.duration = track.duration / 1000;
|
||||||
|
song.readduration = getReadableDuration(track.duration / 1000);
|
||||||
|
song.type = "soundcloud";
|
||||||
|
|
||||||
|
playlist.duration += track.duration / 1000;
|
||||||
|
playlist.songs.push(song);
|
||||||
|
}
|
||||||
|
|
||||||
|
playlist.readduration = getReadableDuration(playlist.duration);
|
||||||
|
|
||||||
|
return playlist;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
clog.error('Erreur lors de la recherche Soundcloud (Playlist): ' + error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {getTrack, getPlaylist}
|
@@ -27,33 +27,83 @@ async function getSong(url) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const trackInfo = await spotifyApi.getTrack(trackId);
|
const trackInfo = await spotifyApi.getTrack(trackId);
|
||||||
|
|
||||||
const trackName = trackInfo.body.name;
|
const trackName = trackInfo.body.name;
|
||||||
const artistName = trackInfo.body.artists[0].name;
|
const artistName = trackInfo.body.artists[0].name;
|
||||||
|
|
||||||
return `${trackName} - ${artistName}`;
|
return `${trackName} - ${artistName}`;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erreur lors de la récupération des données :', error);
|
|
||||||
|
|
||||||
|
clog.error("Impossible de récupérer les informations de la piste Spotify à partir de l'URL");
|
||||||
|
clog.error(error);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAlbum(albumId) {
|
async function getAlbum(url) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
|
||||||
|
const creditdata = await spotifyApi.clientCredentialsGrant();
|
||||||
|
spotifyApi.setAccessToken(creditdata.body['access_token']);
|
||||||
|
|
||||||
|
const parts = url.split('/');
|
||||||
|
const albumId = parts[parts.indexOf('album') + 1].split('?')[0];
|
||||||
|
|
||||||
|
const data = await spotifyApi.getAlbum(albumId);
|
||||||
|
const info = data.body;
|
||||||
|
|
||||||
|
if(!info) {
|
||||||
|
clog.error("Impossible de récupérer les informations de l'album Spotify à partir de l'URL");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
clog.log("Informations de l'album récupérées : " + info.name);
|
||||||
|
|
||||||
|
const playlist = new Playlist()
|
||||||
|
playlist.title = info.name;
|
||||||
|
playlist.author = info.artists[0].name;
|
||||||
|
playlist.authorId = info.artists[0].id;
|
||||||
|
playlist.thumbnail = info.images[0].url;
|
||||||
|
playlist.url = info.external_urls.spotify;
|
||||||
|
playlist.id = albumId;
|
||||||
|
playlist.type = "spotify";
|
||||||
|
playlist.songs = info.tracks.items;
|
||||||
|
|
||||||
|
return playlist;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
clog.error("Impossible de récupérer les informations de l'album Spotify à partir de l'URL");
|
||||||
|
clog.error(error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getPlaylist(url) {
|
async function getPlaylist(url) {
|
||||||
// Get the playlist and return a Playlist Object
|
// Get the playlist and return a Playlist Object
|
||||||
const data = await spotifyApi.clientCredentialsGrant();
|
|
||||||
spotifyApi.setAccessToken(data.body['access_token']);
|
try {
|
||||||
|
const creditdata = await spotifyApi.clientCredentialsGrant();
|
||||||
|
spotifyApi.setAccessToken(creditdata.body['access_token']);
|
||||||
|
|
||||||
const parts = url.split('/');
|
const parts = url.split('/');
|
||||||
const playlistId = parts[parts.indexOf('playlist') + 1].split('?')[0];
|
const playlistId = parts[parts.indexOf('playlist') + 1].split('?')[0];
|
||||||
|
|
||||||
spotifyApi.getPlaylist(playlistId)
|
const data = await spotifyApi.getPlaylist(playlistId)
|
||||||
.then(function(data) {
|
|
||||||
const info = data.body;
|
const info = data.body;
|
||||||
|
|
||||||
|
if(!info) {
|
||||||
|
clog.error("Impossible de récupérer les informations de la playlist Spotify à partir de l'URL");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
clog.log("Informations de la playlist récupérées : " + info.name);
|
||||||
|
|
||||||
const playlist = new Playlist()
|
const playlist = new Playlist()
|
||||||
playlist.title = info.name;
|
playlist.title = info.name;
|
||||||
playlist.author = info.owner.display_name;
|
playlist.author = info.owner.display_name;
|
||||||
@@ -63,50 +113,67 @@ async function getPlaylist(url) {
|
|||||||
playlist.id = playlistId;
|
playlist.id = playlistId;
|
||||||
playlist.type = "spotify";
|
playlist.type = "spotify";
|
||||||
|
|
||||||
const tracks = info.tracks.items;
|
for(const track of info.tracks.items) {
|
||||||
tracks.forEach(async function(track) {
|
playlist.songs.push(track.track);
|
||||||
|
}
|
||||||
|
|
||||||
var trackName = track.track.name;
|
|
||||||
var artistName = track.track.artists[0].name;
|
|
||||||
var queryForYoutube = `${trackName} - ${artistName}`;
|
|
||||||
|
|
||||||
var urlYoutubeFounded = await youtube.getQuery(queryForYoutube).then(function(songFind) {
|
|
||||||
if(!songFind) return null;
|
|
||||||
return songFind.url;
|
|
||||||
});
|
|
||||||
|
|
||||||
clog.log("URL de la vidéo YouTube trouvée : " + urlYoutubeFounded);
|
|
||||||
|
|
||||||
if(!urlYoutubeFounded) {
|
|
||||||
clog.error("Impossible de récupérer l'URL de la vidéo YouTube à partir de la requête " + queryForYoutube);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
const song = new Song();
|
|
||||||
song.title = track.track.name;
|
|
||||||
song.author = track.track.artists[0].name;
|
|
||||||
song.url = urlYoutubeFounded;
|
|
||||||
song.thumbnail = track.track.album.images[0].url;
|
|
||||||
song.id = track.track.id;
|
|
||||||
song.duration = track.track.duration_ms / 1000;
|
|
||||||
song.readduration = getReadableDuration(track.track.duration_ms);
|
|
||||||
|
|
||||||
playlist.duration += track.track.duration_ms;
|
|
||||||
|
|
||||||
|
|
||||||
playlist.songs.push(song);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
playlist.readduration = getReadableDuration(playlist.duration);
|
|
||||||
return playlist;
|
return playlist;
|
||||||
|
|
||||||
}, function(err) {
|
} catch (error) {
|
||||||
clog.error('Une erreur s\'est produite lors de la récupération de la playlist');
|
|
||||||
clog.error(err);
|
clog.error("Impossible de récupérer les informations de l'album Spotify à partir de l'URL");
|
||||||
});
|
clog.error(error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getTracks(playlist) {
|
||||||
|
|
||||||
|
const tracks = playlist.songs
|
||||||
|
playlistSongs = [];
|
||||||
|
for(const track of tracks) {
|
||||||
|
|
||||||
|
var trackName = track.name;
|
||||||
|
var artistName = track.artists[0].name;
|
||||||
|
var queryForYoutube = `${trackName} - ${artistName}`;
|
||||||
|
|
||||||
|
var urlYoutubeFounded = await youtube.getQuery(queryForYoutube).then(function(songFind) {
|
||||||
|
if(!songFind) return null;
|
||||||
|
return songFind.url;
|
||||||
|
});
|
||||||
|
|
||||||
|
clog.log("URL de la vidéo YouTube trouvée : " + urlYoutubeFounded);
|
||||||
|
|
||||||
|
if(!urlYoutubeFounded) {
|
||||||
|
clog.error("Impossible de récupérer l'URL de la vidéo YouTube à partir de la requête " + queryForYoutube);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const song = new Song();
|
||||||
|
|
||||||
|
song.title = track.name;
|
||||||
|
song.author = track.artists[0].name;
|
||||||
|
song.url = urlYoutubeFounded;
|
||||||
|
song.thumbnail = playlist.thumbnail;
|
||||||
|
song.id = track.id;
|
||||||
|
song.duration = track.duration_ms / 1000;
|
||||||
|
song.readduration = getReadableDuration(track.duration_ms / 1000);
|
||||||
|
song.type = "youtube";
|
||||||
|
|
||||||
|
playlist.duration += track.duration_ms / 1000;
|
||||||
|
playlistSongs.push(song);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When finish do this
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
playlist.readduration = getReadableDuration(playlist.duration);
|
||||||
|
playlist.songs = playlistSongs;
|
||||||
|
|
||||||
|
|
||||||
|
return playlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = {getSong, getAlbum, getPlaylist}
|
module.exports = {getSong, getAlbum, getPlaylist, getTracks}
|
@@ -1,35 +1,28 @@
|
|||||||
const {LogType} = require('loguix');
|
const { LogType } = require('loguix');
|
||||||
const clog = new LogType("YoutubeInformation");
|
const clog = new LogType("YoutubeInformation");
|
||||||
const config = require('../utils/Database/Configuration');
|
|
||||||
const YOUTUBE_API_KEY = config.getYoutubeApiKey()
|
|
||||||
const { Song } = require('../player/Song');
|
const { Song } = require('../player/Song');
|
||||||
const { Playlist } = require('../player/Playlist');
|
const { Playlist } = require('../player/Playlist');
|
||||||
const { getReadableDuration } = require('../utils/TimeConverter');
|
const { getReadableDuration } = require('../utils/TimeConverter');
|
||||||
|
const ytsr = require('@distube/ytsr');
|
||||||
|
const ytfps = require('ytfps');
|
||||||
|
|
||||||
|
async function getQuery(query) {
|
||||||
async function
|
if (query === null || typeof query !== 'string') {
|
||||||
getQuery(query) {
|
|
||||||
// Check Query not null and a string
|
|
||||||
if(query === null && typeof query !== 'string') {
|
|
||||||
clog.error("Impossible de rechercher une vidéo YouTube, car la requête est nulle");
|
clog.error("Impossible de rechercher une vidéo YouTube, car la requête est nulle");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// * Fetch
|
|
||||||
try {
|
|
||||||
const response = await fetch(`https://www.googleapis.com/youtube/v3/search?part=snippet&type=video&q=${encodeURIComponent(query)}&key=${YOUTUBE_API_KEY}`);
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
var videoLink = null
|
try {
|
||||||
const videoId = data.items[0]?.id.videoId;
|
const searchResults = await ytsr(query, { limit: 1 });
|
||||||
if(videoId) videoLink = `https://www.youtube.com/watch?v=${videoId}`;
|
const video = searchResults.items.find(item => item.type === 'video');
|
||||||
if(videoLink === null) {
|
|
||||||
|
if (!video) {
|
||||||
clog.error("Impossible de récupérer le lien de la vidéo YouTube à partir de la requête");
|
clog.error("Impossible de récupérer le lien de la vidéo YouTube à partir de la requête");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const song = await getVideo(videoLink);
|
|
||||||
|
|
||||||
|
const song = await getVideo(video.url);
|
||||||
return song;
|
return song;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clog.error('Erreur lors de la recherche YouTube: ' + error);
|
clog.error('Erreur lors de la recherche YouTube: ' + error);
|
||||||
return null;
|
return null;
|
||||||
@@ -37,103 +30,72 @@ getQuery(query) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getVideo(url) {
|
async function getVideo(url) {
|
||||||
// Extract video ID from URL if it exists and is valid (11 characters) and if not return "NOT_VALID"
|
|
||||||
// Extract id from youtu.be youtube.com and music.youtube.com
|
|
||||||
const videoId = url.match(/(?:youtu\.be\/|youtube\.com\/|music\.youtube\.com\/)(?:watch\?v=)?([a-zA-Z0-9_-]{11})/);
|
const videoId = url.match(/(?:youtu\.be\/|youtube\.com\/|music\.youtube\.com\/)(?:watch\?v=)?([a-zA-Z0-9_-]{11})/);
|
||||||
if(videoId === null) {
|
if (videoId === null) {
|
||||||
clog.error("Impossible de récupérer l'identifiant de la vidéo YouTube à partir de l'URL");
|
clog.error("Impossible de récupérer l'identifiant de la vidéo YouTube à partir de l'URL");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// Fetch video information
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`https://www.googleapis.com/youtube/v3/videos?part=snippet&id=${videoId[1]}&key=${YOUTUBE_API_KEY}`);
|
const searchResults = await ytsr(videoId[1], { limit: 1 });
|
||||||
const data = await response.json();
|
const video = searchResults.items.find(item => item.type === 'video');
|
||||||
|
|
||||||
const video = data.items[0];
|
if (video) {
|
||||||
if(video) {
|
const songReturn = new Song();
|
||||||
|
|
||||||
const songReturn = new Song()
|
|
||||||
await songReturn.processYoutubeVideo(video);
|
await songReturn.processYoutubeVideo(video);
|
||||||
|
|
||||||
return songReturn;
|
return songReturn;
|
||||||
} else {
|
} else {
|
||||||
clog.error("Impossible de récupérer la vidéo YouTube à partir de l'identifiant");
|
clog.error("Impossible de récupérer la vidéo YouTube à partir de l'identifiant");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clog.error('Erreur lors de la recherche de la vidéo YouTube:' + error);
|
clog.error('Erreur lors de la recherche de la vidéo YouTube:' + error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getPlaylist(url) {
|
async function getPlaylist(url) {
|
||||||
// Check Query not null and a string
|
if (url === null || typeof url !== 'string') {
|
||||||
if(url === null && typeof url !== 'string') {
|
|
||||||
clog.error("Impossible de rechercher une playlist YouTube, car la requête est nulle");
|
clog.error("Impossible de rechercher une playlist YouTube, car la requête est nulle");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// * Fetch
|
|
||||||
try {
|
try {
|
||||||
// For Playlist
|
const playlistId = url.match(/(?:youtu\.be\/|youtube\.com\/|music\.youtube\.com\/)(?:playlist\?list=)?([a-zA-Z0-9_-]{34})/);
|
||||||
const playlistId = url.match(/(?:youtu\.be\/|youtube\.com\/|music\.youtube.com\/)(?:playlist\?list=)?([a-zA-Z0-9_-]{34})/);
|
if (playlistId === null) {
|
||||||
if(playlistId === null) {
|
clog.error("Impossible de récupérer l'identifiant de la playlist YouTube à partir de l'URL");
|
||||||
clog.error("Impossible de récupérer l'identifiant de la vidéo YouTube à partir de l'URL");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const response = await fetch(`https://www.googleapis.com/youtube/v3/search?part=snippet&type=playlist&q=${encodeURIComponent(playlistId[1])}&key=${YOUTUBE_API_KEY}`);
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if(data.items.length === 0) {
|
const playlistInfo = await ytfps(playlistId[1]);
|
||||||
|
|
||||||
|
if (!playlistInfo) {
|
||||||
clog.error("Impossible de récupérer la playlist YouTube à partir de l'identifiant");
|
clog.error("Impossible de récupérer la playlist YouTube à partir de l'identifiant");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const playlist = new Playlist()
|
const playlist = new Playlist();
|
||||||
playlist.type = "youtube"
|
playlist.type = "youtube";
|
||||||
playlist.author = data.items[0].snippet.channelTitle
|
playlist.author = playlistInfo.author.name;
|
||||||
playlist.authorId = data.items[0].snippet.channelId
|
playlist.authorId = playlistInfo.author.url;
|
||||||
playlist.title = data.items[0].snippet.title
|
playlist.title = playlistInfo.title;
|
||||||
playlist.thumbnail = data.items[0].snippet.thumbnails.high.url
|
playlist.thumbnail = playlistInfo.thumbnail_url;
|
||||||
playlist.description = data.items[0].snippet.description
|
playlist.description = playlistInfo.description;
|
||||||
playlist.url = `https://www.youtube.com/playlist?list=${playlistId[1]}`
|
playlist.url = `https://www.youtube.com/playlist?list=${playlistId[1]}`;
|
||||||
playlist.id = playlistId[1]
|
playlist.id = playlistId[1];
|
||||||
|
|
||||||
|
for (const video of playlistInfo.videos) {
|
||||||
|
const song = new Song();
|
||||||
|
await song.processYoutubeVideo(video, true);
|
||||||
// Get all songs from playlist
|
playlist.duration += song.duration;
|
||||||
|
playlist.songs.push(song);
|
||||||
const responsePlaylist = await fetch(`https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=${playlistId[1]}&key=${YOUTUBE_API_KEY}&maxResults=100`);
|
|
||||||
const dataPlaylist = await responsePlaylist.json();
|
|
||||||
|
|
||||||
if(dataPlaylist.items.length === 0) {
|
|
||||||
clog.error("Impossible de récupérer les vidéos de la playlist YouTube à partir de l'identifiant ou la playlist est vide");
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
playlist.readduration = getReadableDuration(playlist.duration);
|
||||||
for (const video of dataPlaylist.items) {
|
|
||||||
const song = new Song()
|
|
||||||
video.id = video.snippet.resourceId.videoId
|
|
||||||
await song.processYoutubeVideo(video)
|
|
||||||
//? Add seconds to playlist duration
|
|
||||||
playlist.duration += song.duration
|
|
||||||
playlist.songs.push(song)
|
|
||||||
}
|
|
||||||
playlist.readduration = getReadableDuration(playlist.duration)
|
|
||||||
return playlist;
|
return playlist;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clog.error('Erreur lors de la recherche YouTube: ' + error);
|
clog.error('Erreur lors de la recherche YouTube: ' + error);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {getQuery, getVideo, getPlaylist}
|
module.exports = { getQuery, getVideo, getPlaylist };
|
||||||
|
@@ -3,6 +3,7 @@ const { QueryType } = require('../utils/QueryType');
|
|||||||
const { Links } = require('../utils/Links');
|
const { Links } = require('../utils/Links');
|
||||||
const youtube = require("../media/YoutubeInformation")
|
const youtube = require("../media/YoutubeInformation")
|
||||||
const spotify = require("../media/SpotifyInformation")
|
const spotify = require("../media/SpotifyInformation")
|
||||||
|
const soundcloud = require("../media/SoundcloudInformation")
|
||||||
|
|
||||||
|
|
||||||
async function search(query) {
|
async function search(query) {
|
||||||
@@ -25,16 +26,18 @@ async function search(query) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
if(type == QueryType.SPOTIFY_ALBUM) {
|
if(type == QueryType.SPOTIFY_ALBUM) {
|
||||||
|
return await spotify.getAlbum(query)
|
||||||
}
|
}
|
||||||
if(type == QueryType.SPOTIFY_PLAYLIST) {
|
if(type == QueryType.SPOTIFY_PLAYLIST) {
|
||||||
return await spotify.getPlaylist(query)
|
return await spotify.getPlaylist(query)
|
||||||
|
|
||||||
}
|
}
|
||||||
if(type == QueryType.SOUNDCLOUD_TRACK) {
|
if(type == QueryType.SOUNDCLOUD_TRACK) {
|
||||||
|
return await soundcloud.getTrack(query)
|
||||||
|
|
||||||
}
|
}
|
||||||
if(type == QueryType.SOUNDCLOUD_PLAYLIST) {
|
if(type == QueryType.SOUNDCLOUD_PLAYLIST) {
|
||||||
|
return await soundcloud.getPlaylist(query)
|
||||||
|
|
||||||
}
|
}
|
||||||
// TODO: Add more providers
|
// TODO: Add more providers
|
||||||
|
@@ -9,11 +9,11 @@ async function play(instance, song) {
|
|||||||
instance.player = createAudioPlayer()
|
instance.player = createAudioPlayer()
|
||||||
instance.generatePlayerEvents()
|
instance.generatePlayerEvents()
|
||||||
const player = instance.player
|
const player = instance.player
|
||||||
song.resource = await createAudioResource(song.url, {
|
var resource = await createAudioResource(song.url, {
|
||||||
inputType: StreamType.Arbitrary
|
inputType: StreamType.Arbitrary
|
||||||
}) // Remplace par ton fichier audio
|
}) // Remplace par ton fichier audio
|
||||||
|
|
||||||
player.play(song.resource);
|
player.play(resource);
|
||||||
instance.connection.subscribe(player);
|
instance.connection.subscribe(player);
|
||||||
clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Media): ${song.title} - id : ${song.id}`)
|
clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Media): ${song.title} - id : ${song.id}`)
|
||||||
|
|
||||||
|
31
backend/src/player/Method/Soundcloud.js
Normal file
31
backend/src/player/Method/Soundcloud.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
const {createAudioResource, VoiceConnectionStatus, createAudioPlayer, StreamType} = require('@discordjs/voice');
|
||||||
|
const {LogType} = require('loguix')
|
||||||
|
const clog = new LogType("Soundcloud")
|
||||||
|
const plog = require("loguix").getInstance("Player")
|
||||||
|
const {Soundcloud} = require('soundcloud.ts')
|
||||||
|
|
||||||
|
const soundcloud = new Soundcloud();
|
||||||
|
|
||||||
|
async function play(instance, song) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
instance.player = createAudioPlayer()
|
||||||
|
instance.generatePlayerEvents()
|
||||||
|
const player = instance.player
|
||||||
|
|
||||||
|
const stream = await soundcloud.util.streamTrack(song.url)
|
||||||
|
var resource = await createAudioResource(stream)
|
||||||
|
|
||||||
|
player.play(resource);
|
||||||
|
instance.connection.subscribe(player);
|
||||||
|
clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Soundcloud): ${song.title} - id : ${song.id}`)
|
||||||
|
|
||||||
|
} catch(e) {
|
||||||
|
clog.error("Erreur lors de la lecture de la musique : " + song.title)
|
||||||
|
clog.error(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {play}
|
@@ -20,13 +20,13 @@ async function play(instance, song) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add compressor to the audio resource
|
// Add compressor to the audio resource
|
||||||
song.resource = createAudioResource(stream);
|
var resource = createAudioResource(stream);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
player.play(song.resource);
|
player.play(resource);
|
||||||
instance.connection.subscribe(player);
|
instance.connection.subscribe(player);
|
||||||
clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Media): ${song.title} - id : ${song.id}`)
|
clog.log(`GUILD : ${instance.guildId} - Lecture de la musique (Youtube): ${song.title} - id : ${song.id}`)
|
||||||
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
clog.error("Erreur lors de la lecture de la musique : " + song.title)
|
clog.error("Erreur lors de la lecture de la musique : " + song.title)
|
||||||
|
@@ -7,7 +7,7 @@ const clog = new LogType("Signal")
|
|||||||
|
|
||||||
const media = require('./Method/Media');
|
const media = require('./Method/Media');
|
||||||
const youtube = require('./Method/Youtube');
|
const youtube = require('./Method/Youtube');
|
||||||
const Activity = require('../discord/Activity');
|
const soundcloud = require('./Method/Soundcloud');
|
||||||
|
|
||||||
const AllPlayers = new Map()
|
const AllPlayers = new Map()
|
||||||
|
|
||||||
@@ -15,6 +15,7 @@ class Player {
|
|||||||
connection;
|
connection;
|
||||||
player;
|
player;
|
||||||
guildId;
|
guildId;
|
||||||
|
channelId;
|
||||||
queue;
|
queue;
|
||||||
constructor(guildId) {
|
constructor(guildId) {
|
||||||
if(this.guildId === null) {
|
if(this.guildId === null) {
|
||||||
@@ -45,6 +46,8 @@ class Player {
|
|||||||
selfMute: false
|
selfMute: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.channelId = channel.id
|
||||||
|
|
||||||
this.player = createAudioPlayer()
|
this.player = createAudioPlayer()
|
||||||
this.generatePlayerEvents()
|
this.generatePlayerEvents()
|
||||||
|
|
||||||
@@ -62,6 +65,8 @@ class Player {
|
|||||||
|
|
||||||
generatePlayerEvents() {
|
generatePlayerEvents() {
|
||||||
|
|
||||||
|
const Activity = require('../discord/Activity');
|
||||||
|
|
||||||
this.player.on('error', error => {
|
this.player.on('error', error => {
|
||||||
plog.error(`GUILD : ${this.guildId} - Une erreur est survenue dans le player`);
|
plog.error(`GUILD : ${this.guildId} - Une erreur est survenue dans le player`);
|
||||||
plog.error(error);
|
plog.error(error);
|
||||||
@@ -109,7 +114,9 @@ class Player {
|
|||||||
if(song.type == 'youtube') {
|
if(song.type == 'youtube') {
|
||||||
youtube.play(this, song)
|
youtube.play(this, song)
|
||||||
}
|
}
|
||||||
|
if(song.type == "soundcloud") {
|
||||||
|
soundcloud.play(this, song)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Créer une méthode pour les autres types de médias
|
// TODO: Créer une méthode pour les autres types de médias
|
||||||
}
|
}
|
||||||
@@ -151,6 +158,7 @@ class Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async leave() {
|
async leave() {
|
||||||
|
const Activity = require('../discord/Activity');
|
||||||
if(this.checkConnection()) return
|
if(this.checkConnection()) return
|
||||||
if(this.queue.current != null) {
|
if(this.queue.current != null) {
|
||||||
this.queue.addPreviousSong(this.queue.current)
|
this.queue.addPreviousSong(this.queue.current)
|
||||||
@@ -158,6 +166,9 @@ class Player {
|
|||||||
// Détruit la connection et le player et l'enlève de la liste des
|
// Détruit la connection et le player et l'enlève de la liste des
|
||||||
this.connection.destroy()
|
this.connection.destroy()
|
||||||
this.player.stop()
|
this.player.stop()
|
||||||
|
this.player = null
|
||||||
|
this.connection = null
|
||||||
|
this.channelId = null
|
||||||
Activity.idleActivity()
|
Activity.idleActivity()
|
||||||
this.queue.destroy()
|
this.queue.destroy()
|
||||||
AllPlayers.delete(this.guildId)
|
AllPlayers.delete(this.guildId)
|
||||||
|
@@ -2,8 +2,7 @@ const {LogType} = require('loguix')
|
|||||||
|
|
||||||
const clog = new LogType("Song")
|
const clog = new LogType("Song")
|
||||||
const MediaInformation = require('../media/MediaInformation')
|
const MediaInformation = require('../media/MediaInformation')
|
||||||
const YoutubeDuration = require('../utils/YoutubeDuration');
|
const { getReadableDuration, getSecondsDuration } = require('../utils/TimeConverter');
|
||||||
const { getReadableDuration } = require('../utils/TimeConverter');
|
|
||||||
|
|
||||||
class Song {
|
class Song {
|
||||||
title = "Aucun titre";
|
title = "Aucun titre";
|
||||||
@@ -15,7 +14,6 @@ class Song {
|
|||||||
duration;
|
duration;
|
||||||
readduration;
|
readduration;
|
||||||
type;
|
type;
|
||||||
resource;
|
|
||||||
|
|
||||||
constructor(properties) {
|
constructor(properties) {
|
||||||
if(properties) {
|
if(properties) {
|
||||||
@@ -50,17 +48,30 @@ class Song {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async processYoutubeVideo(video) {
|
async processYoutubeVideo(video, playlist) {
|
||||||
this.title = video.snippet.title
|
if(playlist) {
|
||||||
this.author = video.snippet.channelTitle
|
this.title = video.title
|
||||||
this.authorId = video.snippet.channelId
|
this.author = video.author.name
|
||||||
this.thumbnail = video.snippet.thumbnails.standard.url
|
this.authorId = video.author.channel_url
|
||||||
this.url = `https://www.youtube.com/watch?v=${video.id}`
|
this.thumbnail = video.thumbnail_url
|
||||||
|
this.url = video.url
|
||||||
this.type = "youtube"
|
this.type = "youtube"
|
||||||
this.id = video.id
|
this.id = video.id
|
||||||
|
|
||||||
this.duration = await YoutubeDuration.getDurationVideo(video.id)
|
this.duration = video.milis_length / 1000
|
||||||
this.readduration = getReadableDuration(this.duration)
|
this.readduration = getReadableDuration(this.duration)
|
||||||
|
} else {
|
||||||
|
this.title = video.name
|
||||||
|
this.author = video.author.name
|
||||||
|
this.authorId = video.author.url
|
||||||
|
this.thumbnail = video.thumbnail
|
||||||
|
this.url = video.url
|
||||||
|
this.type = "youtube"
|
||||||
|
this.id = video.id
|
||||||
|
|
||||||
|
this.duration = getSecondsDuration(video.duration)
|
||||||
|
this.readduration = getReadableDuration(this.duration)
|
||||||
|
}
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
@@ -18,8 +18,8 @@ function getQueryType(url) {
|
|||||||
|
|
||||||
// Check if it's a Soundcloud link
|
// Check if it's a Soundcloud link
|
||||||
|
|
||||||
if(Links.regex.soundcloud.track.test(url)) return QueryType.SOUNDCLOUD_TRACK
|
|
||||||
if(Links.regex.soundcloud.playlist.test(url)) return QueryType.SOUNDCLOUD_PLAYLIST
|
if(Links.regex.soundcloud.playlist.test(url)) return QueryType.SOUNDCLOUD_PLAYLIST
|
||||||
|
if(Links.regex.soundcloud.track.test(url)) return QueryType.SOUNDCLOUD_TRACK
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -29,4 +29,18 @@ function getReadableDuration(duration) {
|
|||||||
return max
|
return max
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {getReadableDuration}
|
function getSecondsDuration(duration) {
|
||||||
|
// Duration is in format hh:mm:ss and can be just m:ss or mm:ss
|
||||||
|
var durationArray = duration.split(":");
|
||||||
|
var seconds = 0;
|
||||||
|
if(durationArray.length == 3) {
|
||||||
|
seconds = parseInt(durationArray[0]) * 3600 + parseInt(durationArray[1]) * 60 + parseInt(durationArray[2]);
|
||||||
|
} else if(durationArray.length == 2) {
|
||||||
|
seconds = parseInt(durationArray[0]) * 60 + parseInt(durationArray[1]);
|
||||||
|
} else {
|
||||||
|
seconds = parseInt(durationArray[0]);
|
||||||
|
}
|
||||||
|
return seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {getReadableDuration, getSecondsDuration}
|
@@ -1,45 +0,0 @@
|
|||||||
const config = require('../utils/Database/Configuration');
|
|
||||||
const YOUTUBE_API_KEY = config.getYoutubeApiKey()
|
|
||||||
|
|
||||||
async function getDurationVideo(videoId) {
|
|
||||||
const clog = require("loguix").getInstance("YoutubeInformation");
|
|
||||||
// Check videoId if valid
|
|
||||||
if(videoId === null && typeof videoId !== 'string') {
|
|
||||||
clog.error("Impossible de récupérer la durée de la vidéo YouTube, car l'identifiant est nul ou n'est pas une chaîne de caractères");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch video information
|
|
||||||
try {
|
|
||||||
const response = await fetch(`https://www.googleapis.com/youtube/v3/videos?part=contentDetails&id=${videoId}&key=${YOUTUBE_API_KEY}`);
|
|
||||||
const data = await response.json();
|
|
||||||
const video = data.items[0];
|
|
||||||
if(video) {
|
|
||||||
|
|
||||||
if(video.contentDetails.duration == "P0D") return "LIVE";
|
|
||||||
const duration = video.contentDetails.duration;
|
|
||||||
//Convert ISO 8601 duration to seconds
|
|
||||||
return parseDuration(duration);
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
clog.error("Impossible de récupérer la durée de la vidéo YouTube à partir de l'identifiant");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
clog.error('Erreur lors de la recherche de la durée de la vidéo YouTube:', error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseDuration(duration) {
|
|
||||||
const match = duration.match(/PT(\d+H)?(\d+M)?(\d+S)?/);
|
|
||||||
const hours = parseInt(match[1]) || 0;
|
|
||||||
const minutes = parseInt(match[2]) || 0;
|
|
||||||
const seconds = parseInt(match[3]) || 0;
|
|
||||||
return hours * 3600 + minutes * 60 + seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {getDurationVideo}
|
|
Reference in New Issue
Block a user