Version 0.3.0 - Ajout des premières fonctionnalités du Player
This commit is contained in:
		
							
								
								
									
										61
									
								
								backend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										61
									
								
								backend/package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -24,9 +24,11 @@
 | 
			
		||||
        "nodemon": "^3.1.9",
 | 
			
		||||
        "pm2": "^5.4.3",
 | 
			
		||||
        "socket.io": "^4.8.1",
 | 
			
		||||
        "soundcloud.ts": "^0.6.3",
 | 
			
		||||
        "spotify-web-api-node": "^5.0.2",
 | 
			
		||||
        "uuid": "^11.1.0",
 | 
			
		||||
        "webmetrik": "^0.1.4"
 | 
			
		||||
        "webmetrik": "^0.1.4",
 | 
			
		||||
        "ytfps": "^1.2.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@derhuerst/http-basic": {
 | 
			
		||||
@@ -65,6 +67,16 @@
 | 
			
		||||
        "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": {
 | 
			
		||||
      "version": "7.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@discord-player/ffmpeg/-/ffmpeg-7.1.0.tgz",
 | 
			
		||||
@@ -1560,6 +1572,32 @@
 | 
			
		||||
      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
 | 
			
		||||
      "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": {
 | 
			
		||||
      "version": "1.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
 | 
			
		||||
@@ -5569,14 +5607,10 @@
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "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"
 | 
			
		||||
      }
 | 
			
		||||
      "version": "0.6.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/soundcloud.ts/-/soundcloud.ts-0.6.3.tgz",
 | 
			
		||||
      "integrity": "sha512-Ri5bO0jQKKACijGP1/OVbWXhHREDST2T6QUSAPWlzQjUScXVyh+7YJfN1mTnyuAA7vZjKyZ1FMlWC2hKd7jmHQ==",
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/source-map": {
 | 
			
		||||
      "version": "0.6.1",
 | 
			
		||||
@@ -6559,6 +6593,15 @@
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
 | 
			
		||||
      "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",
 | 
			
		||||
    "pm2": "^5.4.3",
 | 
			
		||||
    "socket.io": "^4.8.1",
 | 
			
		||||
    "soundcloud.ts": "^0.6.3",
 | 
			
		||||
    "spotify-web-api-node": "^5.0.2",
 | 
			
		||||
    "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 config = require("../utils/Database/Configuration")
 | 
			
		||||
const metric = require("webmetrik") 
 | 
			
		||||
const { Player } = require("../player/Player")
 | 
			
		||||
 | 
			
		||||
const dlog = new LogType("Discord")
 | 
			
		||||
 | 
			
		||||
const membersVoices = new Map()
 | 
			
		||||
const timers = new Map()
 | 
			
		||||
 | 
			
		||||
const client = new Client({
 | 
			
		||||
    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 Finder = require("../../player/Finder");
 | 
			
		||||
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) => {
 | 
			
		||||
 | 
			
		||||
@@ -11,7 +12,7 @@ const command = new Command("play", "Jouer une musique à partir d'un lien dans
 | 
			
		||||
    const url = interaction.options.get("url")
 | 
			
		||||
    const channel = interaction.member.voice.channel
 | 
			
		||||
    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)
 | 
			
		||||
    
 | 
			
		||||
        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 
 | 
			
		||||
        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.addField('**Titre : **' + song.title, "")  
 | 
			
		||||
            embed.addField('**Demandé par : **', interaction.member.user.username,)
 | 
			
		||||
            embed.addField('**Auteur : **', song.author) 
 | 
			
		||||
            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)
 | 
			
		||||
            
 | 
			
		||||
        } 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.addField('**Durée : **', song.readduration)
 | 
			
		||||
            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)
 | 
			
		||||
 | 
			
		||||
        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},
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
        }
 | 
			
		||||
        const trackInfo = await spotifyApi.getTrack(trackId);
 | 
			
		||||
 | 
			
		||||
        const trackName = trackInfo.body.name;
 | 
			
		||||
        const artistName = trackInfo.body.artists[0].name;
 | 
			
		||||
 | 
			
		||||
        return `${trackName} - ${artistName}`;
 | 
			
		||||
    } 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) {
 | 
			
		||||
    // 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 playlistId = parts[parts.indexOf('playlist') + 1].split('?')[0];
 | 
			
		||||
 | 
			
		||||
    spotifyApi.getPlaylist(playlistId)
 | 
			
		||||
    .then(function(data) {
 | 
			
		||||
        const data = await spotifyApi.getPlaylist(playlistId)
 | 
			
		||||
  
 | 
			
		||||
        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() 
 | 
			
		||||
        playlist.title = info.name;
 | 
			
		||||
        playlist.author = info.owner.display_name;
 | 
			
		||||
@@ -63,11 +113,29 @@ async function getPlaylist(url) {
 | 
			
		||||
        playlist.id = playlistId;
 | 
			
		||||
        playlist.type = "spotify";
 | 
			
		||||
       
 | 
			
		||||
        const tracks = info.tracks.items;
 | 
			
		||||
        tracks.forEach(async function(track) {
 | 
			
		||||
        for(const track of info.tracks.items) {
 | 
			
		||||
            playlist.songs.push(track.track);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            var trackName = track.track.name;
 | 
			
		||||
            var artistName = track.track.artists[0].name;
 | 
			
		||||
        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 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) {
 | 
			
		||||
@@ -82,31 +150,30 @@ async function getPlaylist(url) {
 | 
			
		||||
        
 | 
			
		||||
        } else {
 | 
			
		||||
            const song = new Song();
 | 
			
		||||
                song.title = track.track.name;
 | 
			
		||||
                song.author = track.track.artists[0].name;
 | 
			
		||||
 | 
			
		||||
            song.title = track.name;
 | 
			
		||||
            song.author = 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);
 | 
			
		||||
            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.track.duration_ms;
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
                playlist.songs.push(song);
 | 
			
		||||
            playlist.duration += track.duration_ms / 1000;
 | 
			
		||||
            playlistSongs.push(song);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // When finish do this
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        playlist.readduration = getReadableDuration(playlist.duration);
 | 
			
		||||
        return playlist;
 | 
			
		||||
        playlist.songs = playlistSongs;
 | 
			
		||||
 | 
			
		||||
    }, function(err) {
 | 
			
		||||
        clog.error('Une erreur s\'est produite lors de la récupération de la playlist');
 | 
			
		||||
        clog.error(err);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
        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 config = require('../utils/Database/Configuration');
 | 
			
		||||
const YOUTUBE_API_KEY = config.getYoutubeApiKey()
 | 
			
		||||
const { Song } = require('../player/Song');
 | 
			
		||||
const { Playlist } = require('../player/Playlist');
 | 
			
		||||
const { getReadableDuration } = require('../utils/TimeConverter');
 | 
			
		||||
const ytsr = require('@distube/ytsr');
 | 
			
		||||
const ytfps = require('ytfps');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async function 
 | 
			
		||||
getQuery(query) {
 | 
			
		||||
    // Check Query not null and a string
 | 
			
		||||
    if(query === null && typeof query !== 'string') {
 | 
			
		||||
async function getQuery(query) {
 | 
			
		||||
    if (query === null || typeof query !== 'string') {
 | 
			
		||||
        clog.error("Impossible de rechercher une vidéo YouTube, car la requête est nulle");
 | 
			
		||||
        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
 | 
			
		||||
        const videoId = data.items[0]?.id.videoId;
 | 
			
		||||
        if(videoId) videoLink = `https://www.youtube.com/watch?v=${videoId}`;
 | 
			
		||||
        if(videoLink === null) {
 | 
			
		||||
    try {
 | 
			
		||||
        const searchResults = await ytsr(query, { limit: 1 });
 | 
			
		||||
        const video = searchResults.items.find(item => item.type === 'video');
 | 
			
		||||
 | 
			
		||||
        if (!video) {
 | 
			
		||||
            clog.error("Impossible de récupérer le lien de la vidéo YouTube à partir de la requête");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        const song = await getVideo(videoLink);
 | 
			
		||||
 | 
			
		||||
        const song = await getVideo(video.url);
 | 
			
		||||
        return song;
 | 
			
		||||
       
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        clog.error('Erreur lors de la recherche YouTube: ' + error);
 | 
			
		||||
        return null;
 | 
			
		||||
@@ -37,24 +30,19 @@ getQuery(query) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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})/);
 | 
			
		||||
    if(videoId === null) {
 | 
			
		||||
    if (videoId === null) {
 | 
			
		||||
        clog.error("Impossible de récupérer l'identifiant de la vidéo YouTube à partir de l'URL");
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    // Fetch video information
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        const response = await fetch(`https://www.googleapis.com/youtube/v3/videos?part=snippet&id=${videoId[1]}&key=${YOUTUBE_API_KEY}`);
 | 
			
		||||
        const data = await response.json();
 | 
			
		||||
        const searchResults = await ytsr(videoId[1], { limit: 1 });
 | 
			
		||||
        const video = searchResults.items.find(item => item.type === 'video');
 | 
			
		||||
 | 
			
		||||
        const video = data.items[0];
 | 
			
		||||
        if(video) {
 | 
			
		||||
 | 
			
		||||
            const songReturn = new Song()
 | 
			
		||||
        if (video) {
 | 
			
		||||
            const songReturn = new Song();
 | 
			
		||||
            await songReturn.processYoutubeVideo(video);
 | 
			
		||||
           
 | 
			
		||||
            return songReturn;
 | 
			
		||||
        } else {
 | 
			
		||||
            clog.error("Impossible de récupérer la vidéo YouTube à partir de l'identifiant");
 | 
			
		||||
@@ -64,76 +52,50 @@ async function getVideo(url) {
 | 
			
		||||
        clog.error('Erreur lors de la recherche de la vidéo YouTube:' + error);
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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");
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    // * Fetch
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        // For Playlist
 | 
			
		||||
        const playlistId = url.match(/(?:youtu\.be\/|youtube\.com\/|music\.youtube.com\/)(?:playlist\?list=)?([a-zA-Z0-9_-]{34})/);
 | 
			
		||||
        if(playlistId === null) {
 | 
			
		||||
            clog.error("Impossible de récupérer l'identifiant de la vidéo YouTube à partir de l'URL");
 | 
			
		||||
        const playlistId = url.match(/(?:youtu\.be\/|youtube\.com\/|music\.youtube\.com\/)(?:playlist\?list=)?([a-zA-Z0-9_-]{34})/);
 | 
			
		||||
        if (playlistId === null) {
 | 
			
		||||
            clog.error("Impossible de récupérer l'identifiant de la playlist YouTube à partir de l'URL");
 | 
			
		||||
            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");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const playlist = new Playlist()
 | 
			
		||||
        playlist.type = "youtube"
 | 
			
		||||
        playlist.author = data.items[0].snippet.channelTitle
 | 
			
		||||
        playlist.authorId = data.items[0].snippet.channelId
 | 
			
		||||
        playlist.title = data.items[0].snippet.title
 | 
			
		||||
        playlist.thumbnail = data.items[0].snippet.thumbnails.high.url
 | 
			
		||||
        playlist.description = data.items[0].snippet.description    
 | 
			
		||||
        playlist.url = `https://www.youtube.com/playlist?list=${playlistId[1]}`
 | 
			
		||||
        playlist.id = playlistId[1]
 | 
			
		||||
        const playlist = new Playlist();
 | 
			
		||||
        playlist.type = "youtube";
 | 
			
		||||
        playlist.author = playlistInfo.author.name;
 | 
			
		||||
        playlist.authorId = playlistInfo.author.url;
 | 
			
		||||
        playlist.title = playlistInfo.title;
 | 
			
		||||
        playlist.thumbnail = playlistInfo.thumbnail_url;
 | 
			
		||||
        playlist.description = playlistInfo.description;
 | 
			
		||||
        playlist.url = `https://www.youtube.com/playlist?list=${playlistId[1]}`;
 | 
			
		||||
        playlist.id = playlistId[1];
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Get all songs from playlist
 | 
			
		||||
 | 
			
		||||
        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;    
 | 
			
		||||
        for (const video of playlistInfo.videos) {
 | 
			
		||||
            const song = new Song();
 | 
			
		||||
            await song.processYoutubeVideo(video, true);
 | 
			
		||||
            playlist.duration += song.duration;
 | 
			
		||||
            playlist.songs.push(song);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
        playlist.readduration = getReadableDuration(playlist.duration);
 | 
			
		||||
        return playlist;
 | 
			
		||||
     
 | 
			
		||||
     
 | 
			
		||||
       
 | 
			
		||||
       
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        clog.error('Erreur lors de la recherche YouTube: ' + error);
 | 
			
		||||
        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 youtube = require("../media/YoutubeInformation")
 | 
			
		||||
const spotify = require("../media/SpotifyInformation")
 | 
			
		||||
const soundcloud = require("../media/SoundcloudInformation")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async function search(query) {
 | 
			
		||||
@@ -25,16 +26,18 @@ async function search(query) {
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
    if(type == QueryType.SPOTIFY_ALBUM) {
 | 
			
		||||
 | 
			
		||||
        return await spotify.getAlbum(query)
 | 
			
		||||
    }
 | 
			
		||||
    if(type == QueryType.SPOTIFY_PLAYLIST) {
 | 
			
		||||
        return await spotify.getPlaylist(query)
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    if(type == QueryType.SOUNDCLOUD_TRACK) {
 | 
			
		||||
        return await soundcloud.getTrack(query)
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    if(type == QueryType.SOUNDCLOUD_PLAYLIST) {
 | 
			
		||||
        return await soundcloud.getPlaylist(query)
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
    // TODO: Add more providers
 | 
			
		||||
 
 | 
			
		||||
@@ -9,11 +9,11 @@ async function play(instance, song) {
 | 
			
		||||
            instance.player = createAudioPlayer()
 | 
			
		||||
            instance.generatePlayerEvents()
 | 
			
		||||
            const player = instance.player
 | 
			
		||||
            song.resource = await createAudioResource(song.url, {
 | 
			
		||||
            var resource = await createAudioResource(song.url, {
 | 
			
		||||
                    inputType: StreamType.Arbitrary
 | 
			
		||||
               }) // Remplace par ton fichier audio
 | 
			
		||||
 | 
			
		||||
            player.play(song.resource);
 | 
			
		||||
            player.play(resource);
 | 
			
		||||
            instance.connection.subscribe(player);
 | 
			
		||||
            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
 | 
			
		||||
          song.resource = createAudioResource(stream);
 | 
			
		||||
          var resource = createAudioResource(stream);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
          player.play(song.resource);
 | 
			
		||||
          player.play(resource);
 | 
			
		||||
          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) {
 | 
			
		||||
                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 youtube = require('./Method/Youtube');
 | 
			
		||||
const Activity = require('../discord/Activity');
 | 
			
		||||
const soundcloud = require('./Method/Soundcloud');
 | 
			
		||||
 | 
			
		||||
const AllPlayers = new Map()
 | 
			
		||||
 | 
			
		||||
@@ -15,6 +15,7 @@ class Player {
 | 
			
		||||
    connection;
 | 
			
		||||
    player;
 | 
			
		||||
    guildId;
 | 
			
		||||
    channelId;
 | 
			
		||||
    queue;
 | 
			
		||||
    constructor(guildId) {
 | 
			
		||||
        if(this.guildId === null) {
 | 
			
		||||
@@ -45,6 +46,8 @@ class Player {
 | 
			
		||||
            selfMute: false
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.channelId = channel.id 
 | 
			
		||||
 | 
			
		||||
        this.player = createAudioPlayer()
 | 
			
		||||
        this.generatePlayerEvents()
 | 
			
		||||
    
 | 
			
		||||
@@ -62,6 +65,8 @@ class Player {
 | 
			
		||||
 | 
			
		||||
    generatePlayerEvents() {
 | 
			
		||||
 | 
			
		||||
        const Activity = require('../discord/Activity');
 | 
			
		||||
 | 
			
		||||
        this.player.on('error', error => {
 | 
			
		||||
            plog.error(`GUILD : ${this.guildId} - Une erreur est survenue dans le player`);
 | 
			
		||||
            plog.error(error);
 | 
			
		||||
@@ -109,7 +114,9 @@ class Player {
 | 
			
		||||
       if(song.type == 'youtube') {
 | 
			
		||||
            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
 | 
			
		||||
    }
 | 
			
		||||
@@ -151,6 +158,7 @@ class Player {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async leave() {
 | 
			
		||||
        const Activity = require('../discord/Activity');
 | 
			
		||||
        if(this.checkConnection()) return
 | 
			
		||||
        if(this.queue.current != null) {
 | 
			
		||||
            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 
 | 
			
		||||
        this.connection.destroy()
 | 
			
		||||
        this.player.stop()
 | 
			
		||||
        this.player = null
 | 
			
		||||
        this.connection = null
 | 
			
		||||
        this.channelId = null
 | 
			
		||||
        Activity.idleActivity()
 | 
			
		||||
        this.queue.destroy()
 | 
			
		||||
        AllPlayers.delete(this.guildId)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,7 @@ const {LogType} = require('loguix')
 | 
			
		||||
 | 
			
		||||
const clog = new LogType("Song")
 | 
			
		||||
const MediaInformation = require('../media/MediaInformation')
 | 
			
		||||
const YoutubeDuration = require('../utils/YoutubeDuration');
 | 
			
		||||
const { getReadableDuration } = require('../utils/TimeConverter');
 | 
			
		||||
const { getReadableDuration, getSecondsDuration } = require('../utils/TimeConverter');
 | 
			
		||||
 | 
			
		||||
class Song {
 | 
			
		||||
    title = "Aucun titre";
 | 
			
		||||
@@ -15,7 +14,6 @@ class Song {
 | 
			
		||||
    duration;
 | 
			
		||||
    readduration;
 | 
			
		||||
    type;
 | 
			
		||||
    resource;
 | 
			
		||||
 | 
			
		||||
    constructor(properties) {
 | 
			
		||||
        if(properties) {
 | 
			
		||||
@@ -50,17 +48,30 @@ class Song {
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async processYoutubeVideo(video) {
 | 
			
		||||
        this.title = video.snippet.title
 | 
			
		||||
        this.author = video.snippet.channelTitle
 | 
			
		||||
        this.authorId = video.snippet.channelId
 | 
			
		||||
        this.thumbnail = video.snippet.thumbnails.standard.url
 | 
			
		||||
        this.url = `https://www.youtube.com/watch?v=${video.id}`
 | 
			
		||||
    async processYoutubeVideo(video, playlist) {
 | 
			
		||||
        if(playlist) {
 | 
			
		||||
        this.title = video.title
 | 
			
		||||
        this.author = video.author.name
 | 
			
		||||
        this.authorId = video.author.channel_url
 | 
			
		||||
        this.thumbnail = video.thumbnail_url
 | 
			
		||||
        this.url = video.url
 | 
			
		||||
        this.type = "youtube"
 | 
			
		||||
        this.id = video.id
 | 
			
		||||
 | 
			
		||||
        this.duration = await YoutubeDuration.getDurationVideo(video.id)
 | 
			
		||||
        this.duration = video.milis_length / 1000
 | 
			
		||||
        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
 | 
			
		||||
    } 
 | 
			
		||||
 
 | 
			
		||||
@@ -18,8 +18,8 @@ function getQueryType(url) {
 | 
			
		||||
    
 | 
			
		||||
    // 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.track.test(url)) return QueryType.SOUNDCLOUD_TRACK
 | 
			
		||||
   
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -29,4 +29,18 @@ function getReadableDuration(duration) {
 | 
			
		||||
    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