Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

poru

Package Overview
Dependencies
Maintainers
1
Versions
48
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

poru - npm Package Compare versions

Comparing version 3.0.2 to 3.1.0

SECURITY.md

26

index.js

@@ -1,16 +0,12 @@

module.exports = {
Node: require("./src/Node"),
Player: require("./src/Player"),
Poru: require("./src/Poru"),
Spotify : require("./src/platform/Spotify"),
Deezer : require("./src/platform/Deezer"),
AppleMusic : require("./src/platform/AppleMusic"),
Queue : require("./src/guild/Queue"),
Filter : require("./src/guild/Filter"),
Track: require("./src/guild/Track"),
PoruTrack : require("./src/guild/PoruTrack")
}
Node: require("./src/Node"),
Player: require("./src/Player"),
Poru: require("./src/Poru"),
Spotify: require("./src/platform/Spotify"),
Deezer: require("./src/platform/Deezer"),
AppleMusic: require("./src/platform/AppleMusic"),
Queue: require("./src/guild/Queue"),
Filter: require("./src/guild/Filter"),
Track: require("./src/guild/Track"),
PoruTrack: require("./src/guild/PoruTrack"),
};
{
"name": "poru",
"version": "3.0.2",
"description": "A stable and powefull lavalink client with so many features",
"version": "3.1.0",
"description": "A stable and powerfull lavalink client around node.js",
"main": "index.js",

@@ -24,4 +24,4 @@ "scripts": {

"engines": {
"node": ">=16.9.0"
},
"node": ">=16.9.0"
},
"keywords": [

@@ -35,2 +35,3 @@ "music",

"soundcloud",
"deezer",
"discordjs",

@@ -37,0 +38,0 @@ "eris"

@@ -53,4 +53,4 @@ <p align="center">

```javascript
const { Client, GatewayIntentBits } = require('discord.js');
const { Poru } = require('poru');
const { Client, GatewayIntentBits } = require("discord.js");
const { Poru } = require("poru");
const nodes = [

@@ -61,22 +61,22 @@ {

port: 8080,
password: "iloveyou3000"
}
]
password: "iloveyou3000",
},
];
const PoruOptions = {
reconnectTime: 0,
resumeKey: 'MyPlayers',
resumeKey: "MyPlayers",
resumeTimeout: 60,
defaultPlatform: "ytsearch"
}
defaultPlatform: "ytsearch",
};
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.MessageContent
]
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.MessageContent,
],
});
client.poru = new Poru(client, nodes, PoruOptions)
client.poru = new Poru(client, nodes, PoruOptions);
client.poru.on('trackStart', (player, track) => {
client.poru.on("trackStart", (player, track) => {
const channel = client.channels.cache.get(player.textChannel);

@@ -86,13 +86,16 @@ return channel.send(`Now playing \`${track.title}\``);

client.on('ready', () => {
console.log('Ready!');
client.on("ready", () => {
console.log("Ready!");
client.poru.init(client);
});
client.on('interactionCreate', async (interaction) => {
client.on("interactionCreate", async (interaction) => {
if (!interaction.isChatInputCommand()) return;
if (!interaction.member.voice.channel) return interaction.reply({ content: `Please connect with voice channel `, ephemeral: true });
if (!interaction.member.voice.channel)
return interaction.reply({
content: `Please connect with voice channel `,
ephemeral: true,
});
const track = interaction.options.getString('track');
const track = interaction.options.getString("track");

@@ -102,8 +105,8 @@ const res = await client.poru.resolve(track);

if (res.loadType === "LOAD_FAILED") {
return interaction.reply('Failed to load track.');
return interaction.reply("Failed to load track.");
} else if (res.loadType === "NO_MATCHES") {
return interaction.reply('No source found!');
return interaction.reply("No source found!");
}
//create connection with discord voice channnel
//create connection with discord voice channnel
const player = client.poru.createConnection({

@@ -113,7 +116,6 @@ guildId: interaction.guild.id,

textChannel: interaction.channel.id,
selfDeaf: true
selfDeaf: true,
});
if (res.loadType === 'PLAYLIST_LOADED') {
if (res.loadType === "PLAYLIST_LOADED") {
for (const track of res.tracks) {

@@ -124,3 +126,5 @@ track.info.requester = interaction.user;

interaction.reply(`${res.playlistInfo.name} has been loaded with ${res.tracks.length}`);
interaction.reply(
`${res.playlistInfo.name} has been loaded with ${res.tracks.length}`
);
} else {

@@ -136,3 +140,3 @@ const track = res.tracks[0];

client.login('TOKEN');
client.login("TOKEN");
```

@@ -139,0 +143,0 @@

module.exports = {
clientName: "Poru",
autoResume : true,
version :"2.0",
OPCodes: {
CONFIGURE_RESUMING : 'configureResuming',
DESTROY : 'destroy',
FILTERS : 'filters',
EVENT : 'event',
PAUSE : 'pause',
PLAY : 'play',
PLAYER_UPDATE : 'playerUpdate',
SEEK : 'seek',
STATS : 'stats',
STOP : 'stop',
VOICE_UPDATE : 'voiceUpdate',
VOLUME : 'volume'
}
}
clientName: "Poru",
autoResume: true,
version: "2.0",
OPCodes: {
CONFIGURE_RESUMING: "configureResuming",
DESTROY: "destroy",
FILTERS: "filters",
EVENT: "event",
PAUSE: "pause",
PLAY: "play",
PLAYER_UPDATE: "playerUpdate",
SEEK: "seek",
STATS: "stats",
STOP: "stop",
VOICE_UPDATE: "voiceUpdate",
VOLUME: "volume",
},
};
class Filters {
constructor(player, options = {}) {
this._8d = options._8d || null;
this.bassboost = options.bassboost || null;
this.player = player;
this.node = player.node;
this.equalizer = options.equalizer || [];
this.karaoke = options.karaoke || null;
this.timescale = options.timescale || null;
this.tremolo = options.tremolo || null;
this.vibrato = options.vibrato || null;
this.rotation = options.rotation || null;
this.distortion = options.distortion || null;
this.channelMix = options.channelMix || null;
this.lowPass = options.lowPass || null;
}
constructor(player,options = {}) {
this._8d =options._8d|| null;
this.bassboost = options.bassboost || null;
this.player = player;
this.node = player.node
this.equalizer = options.equalizer || [];
this.karaoke = options.karaoke || null;
this.timescale = options.timescale || null;
this.tremolo = options.tremolo || null;
this.vibrato = options.vibrato || null;
this.rotation = options.rotation || null;
this.distortion = options.distortion || null;
this.channelMix = options.channelMix || null;
this.lowPass = options.lowPass || null;
}
setEqualizer(band, gain) {
this.band = band || this.band;
this.gain = gain || this.gain;
this.equalizer = [
{
band: this.band,
gain: this.gain,
},
{
band: this.band,
gain: this.gain,
},
{
band: this.band,
gain: this.gain,
},
{
band: this.band,
gain: this.gain,
},
{
band: this.band,
gain: this.gain,
},
{
band: this.band,
gain: this.gain,
},
];
this.updateFilters();
return this;
}
setKaraoke(karaoke) {
this.karaoke = karaoke || null;
this.updateFilters();
return this;
}
setTimescale(timescale) {
this.timescale = timescale || null;
this.updateFilters();
return this;
}
setTremolo(tremolo) {
this.tremolo = tremolo || null;
this.updateFilters();
return this;
}
setEqualizer(band,gain){
this.band = band || this.band;
this.gain = gain || this.gain;
this.equalizer = [
{
band: this.band,
gain: this.gain,
},
{
band: this.band,
gain: this.gain,
},
{
band: this.band,
gain: this.gain,
},
{
band: this.band,
gain: this.gain,
},
{
band: this.band,
gain: this.gain,
},
{
band: this.band,
gain: this.gain,
},
]
this.updateFilters();
return this;
}
setKaraoke(karaoke) {
this.karaoke = karaoke|| null;
this.updateFilters();
return this;
}
setTimescale(timescale) {
this.timescale = timescale || null;
this.updateFilters();
return this;
}
setTremolo(tremolo) {
this.tremolo = tremolo || null;
this.updateFilters();
return this;
}
setVibrato(vibrato) {
this.vibrato = vibrato || null;
this.updateFilters();
return this;
}
setVibrato(vibrato){
this.vibrato = vibrato || null;
this.updateFilters();
return this;
}
setRotation(rotation) {
this.rotation = rotation || null;
this.updateFilters();
return this;
}
setDistortion(distortion) {
this.distortion = distortion || null;
this.updateFilters();
return this;
}
setRotation(rotation) {
this.rotation = rotation || null;
this.updateFilters();
return this;
}
setDistortion(distortion) {
this.distortion = distortion || null;
this.updateFilters();
return this;
}
setChannelMix(mix) {
this.channelMix = mix || null;
this.updateFilters();
return this;
}
setChannelMix(mix) {
this.channelMix = mix || null;
this.updateFilters();
return this;
}
setLowPass(pass) {
this.lowPass = pass || null;
this.updateFilters();
return this;
}
setLowPass(pass) {
this.lowPass = pass || null;
this.updateFilters();
return this;
setFilters(options) {
this.player.filters = new Filters(this.player, options);
this.updateFilters();
return this;
}
clearFilters() {
this.player.filters = new Filters(this.player);
this.player.node.send({
op: "filters",
guildId: this.player.guildId,
});
return this;
}
setNightcore(val) {
if (!this.player) return;
this.setTimescale(val ? { rate: 1.5 } : null);
this.nightcore = val;
if (val) {
this.doubleTime = false;
this.vaporwave = false;
}
return val;
}
setFilters(options) {
this.player.filters = new Filters(this.player,options);
this.updateFilters();
return this;
setSlowmode(val) {
if (!this.player) return;
this.slowmode = val;
if (val) {
}
this.setFilters(
val
? {
timescale: {
speed: 0.5,
pitch: 1.0,
rate: 0.8,
},
}
: this.clearFilters()
);
}
clearFilters() {
this.player.filters = new Filters(this.player);
this.player.node.send({
op: "filters",
guildId: this.player.guildId
});
return this;
setVaporwave(val) {
if (!this.player) return;
this.vaporwave = val;
if (val) {
this.doubleTime = false;
this.nightcore = false;
}
setNightcore(val) {
if (!this.player) return;
this.setTimescale(val ? { rate: 1.5 } : null);
this.nightcore = val;
if (val) {
this.doubleTime = false;
this.vaporwave = false;
}
return val;
}
this.setTimescale(val ? { pitch: 0.5 } : null);
}
setSlowmode(val) {
if (!this.player) return;
this.slowmode = val;
if (val) {
}
this.setFilters(
val
? {
timescale: {
speed: 0.5,
pitch: 1.0,
rate: 0.8,
},
}
: this.clearFilters()
);
}
set8D(val) {
if (!this.player) return;
this._8d = val;
this.setRotation(val ? { rotationHz: 0.2 } : null);
}
setVaporwave(val) {
if (!this.player) return;
this.vaporwave = val;
if (val) {
this.doubleTime = false;
this.nightcore = false;
}
this.setTimescale(val ? { pitch: 0.5 } : null);
}
set8D(val) {
if (!this.player) return;
this._8d = val;
this.setRotation(val ? { rotationHz: 0.2 } : null);
}
setBassboost(val) {
if (!this.player) return;
this.bassboost = !!val;
this.bassboost = val / 100;
this.setEqualizer(1, 0.9);
}
setBassboost(val) {
if (!this.player) return;
this.bassboost = !!val;
this.bassboost = val / 100;
this.setEqualizer(1,0.90);
}
updateFilters(){
const {equalizer, karaoke, timescale, tremolo, vibrato, rotation, distortion, channelMix, lowPass } = this;
this.node.send({
op:"filters",
guildId: this.player.guildId,
equalizer,
karaoke,
timescale,
tremolo,
vibrato,
rotation,
distortion,
channelMix,
lowPass
});
}
updateFilters() {
const {
equalizer,
karaoke,
timescale,
tremolo,
vibrato,
rotation,
distortion,
channelMix,
lowPass,
} = this;
this.node.send({
op: "filters",
guildId: this.player.guildId,
equalizer,
karaoke,
timescale,
tremolo,
vibrato,
rotation,
distortion,
channelMix,
lowPass,
});
}
}
module.exports = Filters;

@@ -1,5 +0,5 @@

const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
class PoruTrack {
constructor(data) {
this.track = data.track
this.track = data.track;
this.info = {

@@ -14,13 +14,15 @@ identifier: null,

uri: data.info.uri,
image: data.info.image || null
}
image: data.info.image || null,
};
}
async resolve(manager) {
const query = [this.info.author, this.info.title]
.filter((x) => !!x)
.join(" - ");
const query = [this.info.author, this.info.title].filter((x) => !!x).join(' - ');
const result = await manager.resolve(query,manager.options.defaultPlatform || "ytsearch");
const result = await manager.resolve(
query,
manager.options.defaultPlatform || "ytsearch"
);
if (!result || !result.tracks.length) return;

@@ -32,10 +34,14 @@

(track) =>
author.some((name) => new RegExp(`^${escapeRegExp(name)}$`, 'i').test(track.info.author)) ||
new RegExp(`^${escapeRegExp(this.info.title)}$`, 'i').test(track.info.title),
author.some((name) =>
new RegExp(`^${escapeRegExp(name)}$`, "i").test(track.info.author)
) ||
new RegExp(`^${escapeRegExp(this.info.title)}$`, "i").test(
track.info.title
)
);
if (officialAudio) {
this.info.identifier = officialAudio.info.identifier
this.info.identifier = officialAudio.info.identifier;
this.track = officialAudio.track;
this.info.length = officialAudio.info.length
return this
this.info.length = officialAudio.info.length;
return this;
}

@@ -47,15 +53,15 @@ }

track.info.length >= (this.info.length ? this.length : 0) - 2000 &&
track.info.length <= (this.info.length ? this.length : 0) + 2000,
track.info.length <= (this.info.length ? this.length : 0) + 2000
);
if (sameDuration) {
this.info.identifier = sameDuration.info.identifier
this.info.identifier = sameDuration.info.identifier;
this.track = sameDuration.track;
this.info.length = sameDuration.length
return this
this.info.length = sameDuration.length;
return this;
}
}
this.info.identifier = result.tracks[0].info.identifier
this.info.identifier = result.tracks[0].info.identifier;
this.track = result.tracks[0].track;
this.info.length = result.tracks[0].info.length
return this
this.info.length = result.tracks[0].info.length;
return this;
}

@@ -62,0 +68,0 @@ }

@@ -1,37 +0,35 @@

class Queue extends Array{
constructor() {
super(...arguments);
}
get size() {
return this.length
}
first() {
return this ? this[0] : 0;
}
class Queue extends Array {
constructor() {
super(...arguments);
}
add(track) {
this.push(track);
return this;
}
remove(index) {
return this.splice(index, 1)[0];
}
clear() {
return this.splice(0);
}
shuffle() {
for (let i = this.length - 1; i > 0; i -= 1) {
const j = Math.floor(Math.random() * (i + 1));
[this[i], this[j]] = [this[j], this[i]];
}
}
get size() {
return this.length;
}
first() {
return this ? this[0] : 0;
}
add(track) {
this.push(track);
return this;
}
remove(index) {
return this.splice(index, 1)[0];
}
clear() {
return this.splice(0);
}
shuffle() {
for (let i = this.length - 1; i > 0; i -= 1) {
const j = Math.floor(Math.random() * (i + 1));
[this[i], this[j]] = [this[j], this[i]];
}
}
}
module.exports = Queue;
const Track = require("./Track");
class Response {
constructor(data) {
this.tracks = data.tracks.map((track) => new Track(track));
this.loadType = data.loadType;
this.playlistInfo = data.playlistInfo;
}
constructor(data) {
this.tracks = data.tracks.map((track) => new Track(track));
this.loadType = data.loadType;
this.playlistInfo = data.playlistInfo;
}
module.exports =Response
}
module.exports = Response;

@@ -1,5 +0,5 @@

const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
class Track {
constructor(data) {
this.track = data.track
this.track = data.track;
this.info = {

@@ -14,13 +14,17 @@ identifier: data.info.identifier,

uri: data.info.uri,
image: `https://i.ytimg.com/vi/${data.info.identifier}/maxresdefault.jpg` || null
}
image:
`https://i.ytimg.com/vi/${data.info.identifier}/maxresdefault.jpg` ||
null,
};
}
async resolve(manager) {
const query = [this.info.author, this.info.title]
.filter((x) => !!x)
.join(" - ");
const query = [this.info.author, this.info.title].filter((x) => !!x).join(' - ');
const result = await manager.resolve(query,manager.options.defaultPlatform || "ytsearch");
const result = await manager.resolve(
query,
manager.options.defaultPlatform || "ytsearch"
);
if (!result || !result.tracks.length) return;

@@ -32,10 +36,14 @@

(track) =>
author.some((name) => new RegExp(`^${escapeRegExp(name)}$`, 'i').test(track.info.author)) ||
new RegExp(`^${escapeRegExp(this.info.title)}$`, 'i').test(track.info.title),
author.some((name) =>
new RegExp(`^${escapeRegExp(name)}$`, "i").test(track.info.author)
) ||
new RegExp(`^${escapeRegExp(this.info.title)}$`, "i").test(
track.info.title
)
);
if (officialAudio) {
this.info.identifier = officialAudio.info.identifier
this.image =`https://i.ytimg.com/vi/${this.info.identifier}/maxresdefault.jpg`
this.info.identifier = officialAudio.info.identifier;
this.image = `https://i.ytimg.com/vi/${this.info.identifier}/maxresdefault.jpg`;
this.track = officialAudio.track;
return this
return this;
}

@@ -47,15 +55,15 @@ }

track.info.length >= (this.info.length ? this.length : 0) - 2000 &&
track.info.length <= (this.info.length ? this.length : 0) + 2000,
track.info.length <= (this.info.length ? this.length : 0) + 2000
);
if (sameDuration) {
this.info.identifier = sameDuration.info.identifier
this.image =`https://i.ytimg.com/vi/${this.info.identifier}/maxresdefault.jpg`
this.info.identifier = sameDuration.info.identifier;
this.image = `https://i.ytimg.com/vi/${this.info.identifier}/maxresdefault.jpg`;
this.track = sameDuration.track;
return this
return this;
}
}
this.info.identifier = result.tracks[0].info.identifier
this.image =`https://i.ytimg.com/vi/${this.info.identifier}/maxresdefault.jpg`
this.info.identifier = result.tracks[0].info.identifier;
this.image = `https://i.ytimg.com/vi/${this.info.identifier}/maxresdefault.jpg`;
this.track = result.tracks[0].track;
return this
return this;
}

@@ -62,0 +70,0 @@ }

const WebSocket = require("ws");
const config = require("./config")
const config = require("./config");
class Node {
constructor(manager,options,node) {
this.manager = manager
this.name= options.name || null;
this.host = options.host || "localhost"
this.port = options.port || 2333
this.password = options.password ||"youshallnotpass"
this.secure = options.secure || false;
this.url = `${this.secure ? 'wss' : 'ws'}://${this.host}:${this.port}/`;
this.ws = null;
this.reconnectTime = node.reconnectTime || 5000;
this.resumeKey = node.resumeKey || null;
this.resumeTimeout = node.resumeTimeout || 60;
this.reconnectAttempt;
this.reconnects = 0;
this.isConnected = false;
this.destroyed = null;
this.stats = {
players: 0,
playingPlayers: 0,
uptime: 0,
memory: {
free: 0,
used: 0,
allocated: 0,
reservable: 0,
},
cpu: {
cores: 0,
systemLoad: 0,
lavalinkLoad: 0,
},
};
constructor(manager, options, node) {
this.manager = manager;
this.name = options.name || null;
this.host = options.host || "localhost";
this.port = options.port || 2333;
this.password = options.password || "youshallnotpass";
this.secure = options.secure || false;
this.url = `${this.secure ? "wss" : "ws"}://${this.host}:${this.port}/`;
this.ws = null;
this.reconnectTime = node.reconnectTime || 5000;
this.resumeKey = node.resumeKey || null;
this.resumeTimeout = node.resumeTimeout || 60;
this.reconnectAttempt;
this.reconnects = 0;
this.isConnected = false;
this.destroyed = null;
this.stats = {
players: 0,
playingPlayers: 0,
uptime: 0,
memory: {
free: 0,
used: 0,
allocated: 0,
reservable: 0,
},
cpu: {
cores: 0,
systemLoad: 0,
lavalinkLoad: 0,
},
};
}
connect() {
if (this.ws) this.ws.close();
const headers = {
Authorization: this.password,
"Num-Shards": this.manager.shards || 1,
"User-Id": this.manager.user,
"Client-Name": config.clientName,
};
if (this.resumeKey) headers["Resume-Key"] = this.resumeKey;
this.ws = new WebSocket(this.url, { headers });
this.ws.on("open", this.#open.bind(this));
this.ws.on("error", this.#error.bind(this));
this.ws.on("message", this.#message.bind(this));
this.ws.on("close", this.#close.bind(this));
}
}
disconnect() {
if (!this.isConnected) return;
connect() {
if (this.ws) this.ws.close();
const headers = {
Authorization: this.password,
"Num-Shards": this.manager.shards || 1,
"User-Id": this.manager.user,
"Client-Name": config.clientName
};
if (this.resumeKey) headers["Resume-Key"] = this.resumeKey;
this.ws = new WebSocket(this.url, { headers });
this.ws.on("open",this.#open.bind(this));
this.ws.on("error", this.#error.bind(this));
this.ws.on("message", this.#message.bind(this));
this.ws.on("close", this.#close.bind(this));
this.ws?.removeAllListeners();
this.ws?.close();
this.ws = null;
this.isConnected = false;
}
#open() {
if (this.reconnectAttempt) {
clearTimeout(this.reconnectAttempt);
delete this.reconnectAttempt;
}
disconnect(){
if(!this.isConnected) return;
this.ws?.removeAllListeners();
this.ws?.close();
this.ws = null;
this.isConnected = false;
if (this.resumeKey) {
this.send({
op: "configureResuming",
key: this.resumeKey.toString(),
timeout: this.resumeTimeout,
});
this.manager.emit(
"debug",
this.name,
`[Web Socket] Resuming configured on Lavalink`
);
}
this.manager.emit("nodeConnect", this);
this.isConnected = true;
this.manager.emit(
"debug",
this.name,
`[Web Socket] Connection ready ${this.url}`
);
#open(){
if (this.reconnectAttempt) {
clearTimeout(this.reconnectAttempt);
delete this.reconnectAttempt;
}
if (this.resumeKey){
this.send({
op: "configureResuming",
key: (this.resumeKey).toString(),
timeout: this.resumeTimeout
});
this.manager.emit("debug",this.name,`[Web Socket] Resuming configured on Lavalink`)
if (config.autoResume) {
for (const player of this.manager.players.values()) {
if (player.node === this) {
player.restart();
}
this.manager.emit("nodeConnect", this);
this.isConnected = true;
this.manager.emit('debug', this.name, `[Web Socket] Connection ready ${this.url}`);
if(config.autoResume){
for (const player of this.manager.players.values()) {
if (player.node === this) {
player.restart();
}
}
}
}
}
}
#message(payload) {
#message(payload) {
const packet = JSON.parse(payload);
if (!packet.op) return;
const packet = JSON.parse(payload);
if(!packet.op) return;
if (packet.op && packet.op === "stats") {
this.stats = { ...packet };
}
const player = this.manager.players.get(packet.guildId);
if (packet.guildId && player) player.emit(packet.op, packet);
packet.node = this;
this.manager.emit("debug",this.name,`[Web Socket] Lavalink Node Update : ${packet.op} `)
this.manager.emit("raw", packet);
if (packet.op && packet.op === "stats") {
this.stats = { ...packet };
}
const player = this.manager.players.get(packet.guildId);
if (packet.guildId && player) player.emit(packet.op, packet);
packet.node = this;
this.manager.emit(
"debug",
this.name,
`[Web Socket] Lavalink Node Update : ${packet.op} `
);
this.manager.emit("raw", packet);
}
#close(event) {
this.disconnect();
this.manager.emit("nodeDisconnect",this,event);
this.manager.emit("debug",this.name,`[Web Socket] Connection with Lavalink closed with Error code : ${event||"Unknown code"}`)
if (event !== 1000){
}
#close(event) {
this.disconnect();
this.manager.emit("nodeDisconnect", this, event);
this.manager.emit(
"debug",
this.name,
`[Web Socket] Connection with Lavalink closed with Error code : ${
event || "Unknown code"
}`
);
if (event !== 1000) {
}
}
#error(event) {
if (!event) return "Unknown event";
#error(event) {
if (!event) return "Unknown event";
this.manager.emit(
"debug",
this.name,
`[Web Socket] Connection for Lavalink node has error code: ${event.code}`
);
this.manager.emit("nodeError", this, event);
return this.reconnect();
}
this.manager.emit("debug",this.name,`[Web Socket] Connection for Lavalink node has error code: ${event.code}`)
this.manager.emit("nodeError", this, event);
return this.reconnect();
}
destroy() {
if (!this.isConnected) return;
destroy(){
if(!this.isConnected) return;
const players = this.manager.players.filter((p) => p.node == this);
if (players.size) players.forEach((p) => p.destroy());
this.ws.close(1000, "destroy");
this.ws.removeAllListeners();
this.ws = null;
this.reconnect = 1;
this.destroyed = true;
this.manager.nodes.delete(this.host);
this.manager.emit("nodeDestroy", this);
}
const players = this.manager.players.filter(p => p.node == this);
if (players.size) players.forEach(p => p.destroy());
this.ws.close(1000, "destroy");
this.ws.removeAllListeners();
this.ws = null;
this.reconnect = 1;
this.destroyed = true;
this.manager.nodes.delete(this.host)
this.manager.emit("nodeDestroy", this);
reconnect() {
this.reconnectAttempt = setTimeout(() => {
this.isConnected = false;
this.ws.removeAllListeners();
this.ws = null;
this.manager.emit("nodeReconnect", this);
this.connect();
}, this.reconnectTime);
}
send(payload) {
const data = JSON.stringify(payload);
this.ws.send(data, (error) => {
if (error) return error;
return null;
});
this.manager.emit("raw", data, this.name);
}
get penalties() {
let penalties = 0;
if (!this.isConnected) return penalties;
penalties += this.stats.players;
penalties += Math.round(
Math.pow(1.05, 100 * this.stats.cpu.systemLoad) * 10 - 10
);
if (this.stats.frameStats) {
penalties += this.stats.frameStats.deficit;
penalties += this.stats.frameStats.nulled * 2;
}
reconnect() {
this.reconnectAttempt = setTimeout(() => {
this.isConnected = false;
this.ws.removeAllListeners();
this.ws = null;
this.manager.emit("nodeReconnect", this);
this.connect();
}, this.reconnectTime);
}
send(payload) {
const data = JSON.stringify(payload);
this.ws.send(data, (error) => {
if (error) return error;
return null;
});
this.manager.emit("raw", data, this.name)
}
get penalties(){
let penalties = 0;
if (!this.isConnected) return penalties;
penalties += this.stats.players;
penalties += Math.round(Math.pow(1.05, 100 * this.stats.cpu.systemLoad) * 10 - 10);
if (this.stats.frameStats) {
penalties += this.stats.frameStats.deficit;
penalties += this.stats.frameStats.nulled * 2;
}
return penalties;
}
return penalties;
}
}
module.exports = Node;

@@ -1,4 +0,5 @@

const {fetch} = require("undici")
const PoruTrack = require("../guild/PoruTrack")
let baseURL = /(?:https:\/\/music\.apple\.com\/)(?:.+)?(artist|album|music-video|playlist)\/([\w\-\.]+(\/)+[\w\-\.]+|[^&]+)\/([\w\-\.]+(\/)+[\w\-\.]+|[^&]+)/;
const { fetch } = require("undici");
const PoruTrack = require("../guild/PoruTrack");
let baseURL =
/(?:https:\/\/music\.apple\.com\/)(?:.+)?(artist|album|music-video|playlist)\/([\w\-\.]+(\/)+[\w\-\.]+|[^&]+)\/([\w\-\.]+(\/)+[\w\-\.]+|[^&]+)/;

@@ -15,6 +16,5 @@ class AppleMusic {

imageWeight: options.imageWeight || 500,
}
this.url = `https://amp-api.music.apple.com/v1/catalog/${this.options.searchMarket}`
};
this.url = `https://amp-api.music.apple.com/v1/catalog/${this.options.searchMarket}`;
this.token = null;
}

@@ -26,14 +26,15 @@

async requestToken() {
try {
let req = await fetch('https://music.apple.com/us/browse');
let req = await fetch("https://music.apple.com/us/browse");
let json = await req.text();
let config = /<meta name="desktop-music-app\/config\/environment" content="(.*?)">/.exec(json);
let config =
/<meta name="desktop-music-app\/config\/environment" content="(.*?)">/.exec(
json
);
let key = config = JSON.parse(decodeURIComponent(config[1]));
let { token } = key?.MEDIA_API
let key = (config = JSON.parse(decodeURIComponent(config[1])));
let { token } = key?.MEDIA_API;
if (!token) throw new Error("No acess key found for apple music")
if (!token) throw new Error("No acess key found for apple music");

@@ -48,3 +49,2 @@ this.token = `Bearer ${token}`;

async requestData(param) {

@@ -56,5 +56,5 @@ if (!this.token) await this.requestToken();

Authorization: `${this.token}`,
origin: 'https://music.apple.com'
}
})
origin: "https://music.apple.com",
},
});

@@ -66,8 +66,4 @@ let body = await req.json();

async resolve(url) {
let [, type, id] = await baseURL.exec(url)
let [, type, id] = await baseURL.exec(url);

@@ -91,19 +87,15 @@ switch (type) {

try {
let tracks = await this.requestData(`/search?types=songs&term=${query}`);
let tracks = await this.requestData(`/search?types=songs&term=${query}`)
let track = await this.buildUnresolved(tracks.results.songs.data[0]);
let track = await this.buildUnresolved(tracks.results.songs.data[0])
return this.buildResponse('TRACK_LOADED', [track]);
return this.buildResponse("TRACK_LOADED", [track]);
} catch (e) {
return this.buildResponse(
'LOAD_FAILED',
"LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);
}
}

@@ -113,19 +105,24 @@

try {
let query = new URL(url).pathname.split('/');
let query = new URL(url).pathname.split("/");
let id = query.pop();
let playlist = await this.requestData(`/playlists/${id}`)
let name = playlist.data[0].attributes.name
let playlist = await this.requestData(`/playlists/${id}`);
let name = playlist.data[0].attributes.name;
const limitedTracks = this.options.playlistLimit
? playlist.data[0].relationships.tracks.data.slice(0, this.options.playlistLimit * 100)
? playlist.data[0].relationships.tracks.data.slice(
0,
this.options.playlistLimit * 100
)
: playlist.data[0].relationships.tracks.data;
let tracks = await Promise.all(limitedTracks.map(x => this.buildUnresolved(x)))
return this.buildResponse('PLAYLIST_LOADED', tracks, name);
let tracks = await Promise.all(
limitedTracks.map((x) => this.buildUnresolved(x))
);
return this.buildResponse("PLAYLIST_LOADED", tracks, name);
} catch (e) {
return this.buildResponse(
'LOAD_FAILED',
"LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);

@@ -135,28 +132,27 @@ }

async fetchAlbum(url) {
try {
let query = new URL(url).pathname.split('/');
let query = new URL(url).pathname.split("/");
let id = query.pop();
let album = await this.requestData(`/albums/${id}`)
let album = await this.requestData(`/albums/${id}`);
const limitedTracks = this.options.albumLimit
? album.data[0].relationships.tracks.data.slice(0, this.options.albumLimit * 100)
? album.data[0].relationships.tracks.data.slice(
0,
this.options.albumLimit * 100
)
: album.data[0].relationships.tracks.data;
let name = album.data[0].attributes.name
let tracks = await Promise.all(limitedTracks.map(x => this.buildUnresolved(x)));
return this.buildResponse('PLAYLIST_LOADED', tracks, name);
let name = album.data[0].attributes.name;
let tracks = await Promise.all(
limitedTracks.map((x) => this.buildUnresolved(x))
);
return this.buildResponse("PLAYLIST_LOADED", tracks, name);
} catch (e) {
return this.buildResponse(
'LOAD_FAILED',
"LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);
}

@@ -166,42 +162,42 @@ }

async fetchArtist(url) {
try {
let query = new URL(url).pathname.split('/');
let query = new URL(url).pathname.split("/");
let id = query.pop();
let artist = await this.requestData(`/attists/${id}`)
let name = artistdata[0].attributes.name
let artist = await this.requestData(`/attists/${id}`);
let name = artist.data[0].attributes.name;
const limitedTracks = this.options.artistLimit
? artist.data[0].relationships.tracks.data.slice(0, this.options.artist * 100)
? artist.data[0].relationships.tracks.data.slice(
0,
this.options.artist * 100
)
: artist.data[0].relationships.tracks.data;
let tracks = await Promise.all(limitedTracks.map(x => this.buildUnresolved(x)));
return this.buildResponse('PLAYLIST_LOADED', tracks, name);
let tracks = await Promise.all(
limitedTracks.map((x) => this.buildUnresolved(x))
);
return this.buildResponse("PLAYLIST_LOADED", tracks, name);
} catch (e) {
return this.buildResponse(
'LOAD_FAILED',
"LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);
}
}
async buildUnresolved(track) {
if (!track) throw new ReferenceError('The Apple track object was not provided');
if (!track)
throw new ReferenceError("The Apple track object was not provided");
return new PoruTrack({
track: '',
track: "",
info: {
sourceName: 'Apple Music',
sourceName: "Apple Music",
identifier: track.id,
isSeekable: true,
author: track.attributes.artistName ? track.attributes.artistName : 'Unknown',
author: track.attributes.artistName
? track.attributes.artistName
: "Unknown",
length: track.attributes.durationInMillis,

@@ -211,3 +207,5 @@ isStream: false,

uri: track.attributes.url,
image: track.attributes.artwork.url.replace("{w}", this.options.imageWeight).replace("{h}", this.options.imageHeight)
image: track.attributes.artwork.url
.replace("{w}", this.options.imageWeight)
.replace("{h}", this.options.imageHeight),
},

@@ -218,3 +216,5 @@ });

compareValue(value) {
return typeof value !== 'undefined' ? value !== null : typeof value !== 'undefined';
return typeof value !== "undefined"
? value !== null
: typeof value !== "undefined";
}

@@ -229,30 +229,8 @@

},
exceptionMsg ? { exception: { message: exceptionMsg, severity: 'COMMON' } } : {},
exceptionMsg
? { exception: { message: exceptionMsg, severity: "COMMON" } }
: {}
);
}
}
module.exports = AppleMusic
const apple = new AppleMusic("",{apple:{}})
apple.resolve("https://music.apple.com/us/playlist/bollywood-hits/pl.d60caf02fcce4d7e9788fe01243b7c2c")
module.exports = AppleMusic;

@@ -1,22 +0,19 @@

const {fetch} = require("undici")
const { fetch } = require("undici");
let REGEX = /^(?:https?:\/\/|)?(?:www\.)?deezer\.com\/(?:\w{2}\/)?(track|album|playlist|artist)\/(\d+)/
let REGEX =
/^(?:https?:\/\/|)?(?:www\.)?deezer\.com\/(?:\w{2}\/)?(track|album|playlist|artist)\/(\d+)/;
const PoruTrack = require("../guild/PoruTrack")
const PoruTrack = require("../guild/PoruTrack");
class Deezer {
constructor(manager, options) {
this.manager = manager;
this.baseURL = 'https://api.deezer.com';
this.baseURL = "https://api.deezer.com";
this.options = {
playlistLimit: options.playlistLimit || null,
albumLimit: options.albumLimit || null,
artistLimit: options.artistLimit || null
}
artistLimit: options.artistLimit || null,
};
}
check(url) {

@@ -27,4 +24,3 @@ return REGEX.test(url);

async requestData(endpoint) {
const req = await fetch(`${this.baseURL}/${endpoint}`, {
});
const req = await fetch(`${this.baseURL}/${endpoint}`, {});
const data = await req.json();

@@ -34,26 +30,20 @@ return data;

async resolve(url) {
const [, type, id] = REGEX.exec(url) ?? [];
switch (type) {
case 'playlist': {
case "playlist": {
return this.fetchPlaylist(id);
}
case 'track': {
case "track": {
return this.fetchTrack(id);
}
case 'album': {
case "album": {
return this.fetchAlbum(id);
}
case 'artist': {
case "artist": {
return this.fetchArtist(id);
}
}
}
async fetchPlaylist(id) {

@@ -64,15 +54,19 @@ try {

const limitedTracks = this.options.playlistLimit
? playlist.track.data.slice(0, this.options.playlistLimit * 100)
: playlist.track.data;
? playlist.tracks.data.slice(0, this.options.playlistLimit * 100)
: playlist.tracks.data;
const unresolvedPlaylistTracks = await Promise.all(limitedTracks.map(x => this.buildUnresolved(x)));
return this.buildResponse('PLAYLIST_LOADED', unresolvedPlaylistTracks, playlist.name);
const unresolvedPlaylistTracks = await Promise.all(
limitedTracks.map((x) => this.buildUnresolved(x))
);
return this.buildResponse(
"PLAYLIST_LOADED",
unresolvedPlaylistTracks,
playlist.title
);
} catch (e) {
return this.buildResponse(
'LOAD_FAILED',
"LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);

@@ -90,15 +84,18 @@ }

const unresolvedAlbumTracks = await Promise.all(
limitedTracks.map((x) => this.buildUnresolved(x))
);
const unresolvedAlbumTracks = await Promise.all(limitedTracks.map(x => this.buildUnresolved(x)));
return this.buildResponse('PLAYLIST_LOADED', unresolvedAlbumTracks, album.name);
return this.buildResponse(
"PLAYLIST_LOADED",
unresolvedAlbumTracks,
album.name
);
} catch (e) {
return this.buildResponse(
'LOAD_FAILED',
"LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);
}

@@ -108,17 +105,14 @@ }

async fetchTrack(id) {
try {
const track = await this.requestData(`/track/${id}`)
const track = await this.requestData(`/track/${id}`);
const unresolvedTrack = await Promise.all(this.buildUnresolved(track));
return this.buildResponse('TRACK_LOADED', [unresolvedTrack]);
return this.buildResponse("TRACK_LOADED", [unresolvedTrack]);
} catch (e) {
return this.buildResponse(
'LOAD_FAILED',
"LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);
}

@@ -128,6 +122,5 @@ }

async fetchArtist(id) {
try {
const artist = await this.requestData(`/artist/${id}/top`);
await this.fetchArtistTracks(artist)
await this.fetchArtistTracks(artist);

@@ -138,17 +131,18 @@ const limitedTracks = this.options.artistLimit

const unresolvedArtistTracks = await Promise.all(limitedTracks.map(x => this.buildUnresolved(x)
));
const unresolvedArtistTracks = await Promise.all(
limitedTracks.map((x) => this.buildUnresolved(x))
);
return this.buildResponse('PLAYLIST_LOADED', unresolvedArtistTracks, artist.name);
return this.buildResponse(
"PLAYLIST_LOADED",
unresolvedArtistTracks,
artist.name
);
} catch (e) {
return this.buildResponse(
'LOAD_FAILED',
"LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);
}

@@ -162,4 +156,4 @@ }

if (!nextPage) break;
const req = await fetch(nextPage)
const json = await req.json()
const req = await fetch(nextPage);
const json = await req.json();

@@ -177,30 +171,28 @@ deezerArtist.data.push(...json.data);

try {
if (this.check(query)) return this.resolve(query)
let tracks = await this.requestData(`/search?q="${query}"`)
if (this.check(query)) return this.resolve(query);
let tracks = await this.requestData(`/search?q="${query}"`);
const unresolvedTrack = await this.buildUnresolved(tracks.data[0]);
return this.buildResponse('TRACK_LOADED', [unresolvedTrack]);
return this.buildResponse("TRACK_LOADED", [unresolvedTrack]);
} catch (e) {
return this.buildResponse(
'LOAD_FAILED',
"LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);
}
}
async buildUnresolved(track) {
if (!track) throw new ReferenceError('The Deezer track object was not provided');
if (!track)
throw new ReferenceError("The Deezer track object was not provided");
return new PoruTrack({
track: '',
track: "",
info: {
sourceName: 'deezer',
sourceName: "deezer",
identifier: track.id,
isSeekable: true,
author: track.artist ? track.artist.name : 'Unknown',
author: track.artist ? track.artist.name : "Unknown",
length: track.duration,

@@ -210,3 +202,3 @@ isStream: false,

uri: track.link,
image: track.album.cover_medium
image: track.album.cover_medium,
},

@@ -216,5 +208,6 @@ });

compareValue(value) {
return typeof value !== 'undefined' ? value !== null : typeof value !== 'undefined';
return typeof value !== "undefined"
? value !== null
: typeof value !== "undefined";
}

@@ -229,16 +222,9 @@

},
exceptionMsg ? { exception: { message: exceptionMsg, severity: 'COMMON' } } : {},
exceptionMsg
? { exception: { message: exceptionMsg, severity: "COMMON" } }
: {}
);
}
}
module.exports = Deezer;
let deezer = new Deezer("", { deezer: { playlistLimit: 10 } })
deezer.resolve("https://www.deezer.com/en/playlist/4404579662")

@@ -1,7 +0,7 @@

const {fetch} = require("undici")
const { fetch } = require("undici");
let spotifyPattern =
/^(?:https:\/\/open\.spotify\.com\/(?:user\/[A-Za-z0-9]+\/)?|spotify:)(album|playlist|track|artist)(?:[/:])([A-Za-z0-9]+).*$/;
/^(?:https:\/\/open\.spotify\.com\/(?:user\/[A-Za-z0-9]+\/)?|spotify:)(album|playlist|track|artist)(?:[/:])([A-Za-z0-9]+).*$/;
const PoruTrack = require("../guild/PoruTrack")
const PoruTrack = require("../guild/PoruTrack");

@@ -11,11 +11,12 @@ class Spotify {

this.manager = manager;
this.baseURL = 'https://api.spotify.com/v1';
this.options ={
playlistLimit : manager.options.playlistLimit,
albumLimit : manager.options.albumLimit,
artistLimit : manager.options.artistLimit,
searchMarket : manager.options.searchMarket
}
this.authorization = Buffer.from(`${this.options.clientID}:${this.options.clientSecret}`).toString('base64');
this.baseURL = "https://api.spotify.com/v1";
this.options = {
playlistLimit: manager.options.playlistLimit,
albumLimit: manager.options.albumLimit,
artistLimit: manager.options.artistLimit,
searchMarket: manager.options.searchMarket,
};
this.authorization = Buffer.from(
`${this.options.clientID}:${this.options.clientSecret}`
).toString("base64");
this.interval = 0;

@@ -25,28 +26,28 @@ }

check(url) {
return spotifyPattern.test(url);
}
async requestToken() {
try {
const data = await fetch(
"https://open.spotify.com/get_access_token?reason=transport&productType=embed",
{
headers: {
"User-Agent":
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36",
},
}
);
async requestToken() {
try{
const data = await fetch('https://open.spotify.com/get_access_token?reason=transport&productType=embed', {
headers: {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36'
const body = await data.json();
this.token = `Bearer ${body.accessToken}`;
this.interval = body.accessTokenExpirationTimestampMs * 1000;
} catch (e) {
if (e.status === 400) {
throw new Error("Invalid Spotify client.");
}
})
const body = await data.json();
this.token = `Bearer ${body.accessToken}`;
this.interval = body.accessTokenExpirationTimestampMs * 1000;
} catch (e) {
if (e.status === 400) {
throw new Error('Invalid Spotify client.');
}
}
}
/*
/*
async requestToken() {

@@ -83,5 +84,8 @@

const req = await fetch(`${this.baseURL}${/^\//.test(endpoint) ? endpoint : `/${endpoint}`}`, {
headers: { Authorization: this.token },
});
const req = await fetch(
`${this.baseURL}${/^\//.test(endpoint) ? endpoint : `/${endpoint}`}`,
{
headers: { Authorization: this.token },
}
);
const data = await req.json();

@@ -92,19 +96,18 @@ return data;

async resolve(url) {
if (!this.token) await this.requestToken();
if (!this.token) await this.requestToken();
const [, type, id] = spotifyPattern.exec(url) ?? [];
switch (type) {
case 'playlist': {
case "playlist": {
return this.fetchPlaylist(id);
}
case 'track': {
case "track": {
return this.fetchTrack(id);
}
case 'album': {
case "album": {
return this.fetchAlbum(id);
}
case 'artist': {
case "artist": {
return this.fetchArtist(id);
}
}

@@ -122,11 +125,17 @@ }

const unresolvedPlaylistTracks = await Promise.all(limitedTracks.map(x => this.buildUnresolved(x.track)));
const unresolvedPlaylistTracks = await Promise.all(
limitedTracks.map((x) => this.buildUnresolved(x.track))
);
return this.buildResponse('PLAYLIST_LOADED', unresolvedPlaylistTracks, playlist.name);
return this.buildResponse(
"PLAYLIST_LOADED",
unresolvedPlaylistTracks,
playlist.name
);
} catch (e) {
return this.buildResponse(
e.status === 404 ? 'NO_MATCHES' : 'LOAD_FAILED',
e.status === 404 ? "NO_MATCHES" : "LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);

@@ -140,12 +149,20 @@ }

const limitedTracks = this.options.albumLimit ? album.tracks.items.slice(0, this.options.albumLimit * 100) : album.tracks.items;
const limitedTracks = this.options.albumLimit
? album.tracks.items.slice(0, this.options.albumLimit * 100)
: album.tracks.items;
const unresolvedPlaylistTracks = await Promise.all(limitedTracks.map(x => this.buildUnresolved(x)));
return this.buildResponse('PLAYLIST_LOADED', unresolvedPlaylistTracks, album.name);
const unresolvedPlaylistTracks = await Promise.all(
limitedTracks.map((x) => this.buildUnresolved(x))
);
return this.buildResponse(
"PLAYLIST_LOADED",
unresolvedPlaylistTracks,
album.name
);
} catch (e) {
return this.buildResponse(
e.body?.error.message === 'invalid id' ? 'NO_MATCHES' : 'LOAD_FAILED',
e.body?.error.message === "invalid id" ? "NO_MATCHES" : "LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);

@@ -159,15 +176,25 @@ }

const data = await this.requestData(`/artists/${id}/top-tracks?market=${this.searchMarket ?? 'US'}`);
const data = await this.requestData(
`/artists/${id}/top-tracks?market=${this.searchMarket ?? "US"}`
);
const limitedTracks = this.options.artistLimit ? data.tracks.slice(0, this.options.artistLimit * 100) : data.tracks;
const limitedTracks = this.options.artistLimit
? data.tracks.slice(0, this.options.artistLimit * 100)
: data.tracks;
const unresolvedPlaylistTracks = await Promise.all(limitedTracks.map(x => this.buildUnresolved(x)));
const unresolvedPlaylistTracks = await Promise.all(
limitedTracks.map((x) => this.buildUnresolved(x))
);
return this.buildResponse('PLAYLIST_LOADED', unresolvedPlaylistTracks, artist.name);
return this.buildResponse(
"PLAYLIST_LOADED",
unresolvedPlaylistTracks,
artist.name
);
} catch (e) {
return this.buildResponse(
e.body?.error.message === 'invalid id' ? 'NO_MATCHES' : 'LOAD_FAILED',
e.body?.error.message === "invalid id" ? "NO_MATCHES" : "LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);

@@ -181,9 +208,9 @@ }

const unresolvedTrack = await this.buildUnresolved(data);
return this.buildResponse('TRACK_LOADED', [unresolvedTrack]);
return this.buildResponse("TRACK_LOADED", [unresolvedTrack]);
} catch (e) {
return this.buildResponse(
e.body?.error.message === 'invalid id' ? 'NO_MATCHES' : 'LOAD_FAILED',
e.body?.error.message === "invalid id" ? "NO_MATCHES" : "LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);

@@ -198,3 +225,5 @@ }

const data = await this.requestData(
`/search/?q="${query}"&type=artist,album,track&market=${this.options.searchMarket ?? 'US'}`,
`/search/?q="${query}"&type=artist,album,track&market=${
this.options.searchMarket ?? "US"
}`
);

@@ -204,9 +233,9 @@

return this.buildResponse('TRACK_LOADED', [unresolvedTrack]);
return this.buildResponse("TRACK_LOADED", [unresolvedTrack]);
} catch (e) {
return this.buildResponse(
e.body?.error.message === 'invalid id' ? 'NO_MATCHES' : 'LOAD_FAILED',
e.body?.error.message === "invalid id" ? "NO_MATCHES" : "LOAD_FAILED",
[],
undefined,
e.body?.error.message ?? e.message,
e.body?.error.message ?? e.message
);

@@ -234,11 +263,12 @@ }

async buildUnresolved(track) {
if (!track) throw new ReferenceError('The Spotify track object was not provided');
if (!track)
throw new ReferenceError("The Spotify track object was not provided");
return new PoruTrack({
track: '',
track: "",
info: {
sourceName: 'spotify',
sourceName: "spotify",
identifier: track.id,
isSeekable: true,
author: track.artists[0] ? track.artists[0].name : 'Unknown',
author: track.artists[0] ? track.artists[0].name : "Unknown",
length: track.duration_ms,

@@ -254,3 +284,5 @@ isStream: false,

async fetchMetaData(track) {
const fetch = await this.manager.resolve(`${track.info.title} ${track.info.author}`);
const fetch = await this.manager.resolve(
`${track.info.title} ${track.info.author}`
);
return fetch.tracks[0];

@@ -269,3 +301,5 @@ }

compareValue(value) {
return typeof value !== 'undefined' ? value !== null : typeof value !== 'undefined';
return typeof value !== "undefined"
? value !== null
: typeof value !== "undefined";
}

@@ -280,3 +314,5 @@

},
exceptionMsg ? { exception: { message: exceptionMsg, severity: 'COMMON' } } : {},
exceptionMsg
? { exception: { message: exceptionMsg, severity: "COMMON" } }
: {}
);

@@ -283,0 +319,0 @@ }

const { EventEmitter } = require("events");
const Queue = require("./guild/Queue");
const Filters = require("./guild/Filter")
const Filters = require("./guild/Filter");
class Player extends EventEmitter {
constructor(manager, node, options) {
super();
constructor(manager, node, options) {
super();
this.manager = manager;
this.manager = manager;
this.queue = new Queue();
this.queue = new Queue();
this.node = node;
this.node = node;
this.options = options;
this.options = options;
this.filters = new Filters(this, this.node)
this.filters = new Filters(this, this.node);
this.guildId = options.guildId;
this.guildId = options.guildId;
this.voiceChannel = options.voiceChannel.id || options.voiceChannel;
this.voiceChannel = options.voiceChannel.id || options.voiceChannel;
this.textChannel = options.textChannel || null;
this.textChannel = options.textChannel || null;
this.shardId = options.shardId || 1;
this.shardId = options.shardId || 1;
this.isConnected = false;
this.isConnected = false;
this.isPlaying = false;
this.isPlaying = false;
this.isPaused = false;
this.isPaused = false;
this.trackRepeat = false;
this.trackRepeat = false;
this.queueRepeat = false;
this.queueRepeat = false;
this.loop = 0;
this.loop = 0;
this.position = 0;
this.position = 0;
this.volume = 100;
this.volume = 100;
this.currentTrack = {};
this.currentTrack = {};
this.previousTrack = null;
this.previousTrack = null;
this.voiceUpdateState = null;
this.voiceUpdateState = null;
this.on("event", (data) => this.lavalinkEvent(data).bind(this)());
this.on("playerUpdate", (packet) => {
(this.isConnected = packet.state.connected),
(this.position = packet.state.position);
this.manager.emit("playerUpdate", this, packet);
});
}
this.on("event", (data) => (this.lavalinkEvent(data).bind(this))());
this.on("playerUpdate", (packet) => {
this.isConnected = packet.state.connected,
this.position = packet.state.position
this.manager.emit("playerUpdate", this, packet);
});
async play(options = {}) {
if (!this.queue.length) {
return null;
}
async play(options = {}) {
this.currentTrack = this.queue.shift();
if (!this.queue.length) {
return null;
}
this.currentTrack = this.queue.shift()
if (!this.currentTrack.track) {
this.currentTrack = await this.currentTrack.resolve(this.manager);
}
this.isPlaying = true;
this.node.send({
op: "play",
guildId: this.guildId,
track: this.currentTrack.track,
noReplace: options.noReplace || true,
});
this.position = 0;
return this;
if (!this.currentTrack.track) {
this.currentTrack = await this.currentTrack.resolve(this.manager);
}
this.isPlaying = true;
this.node.send({
op: "play",
guildId: this.guildId,
track: this.currentTrack.track,
noReplace: options.noReplace || true,
});
this.position = 0;
return this;
}
stop() {
stop() {
this.position = 0;
this.isConnected = false;
this.isPlaying = false;
this.node.send({
op: "stop",
guildId: this.guildId,
});
return this;
}
this.position = 0;
this.isConnected = false
this.isPlaying = false;
this.node.send({
op: "stop",
guildId: this.guildId
});
return this;
}
pause(pause = true) {
if (typeof pause !== "boolean")
throw new RangeError("Pause function must be pass with boolean value.");
pause(pause = true) {
if (typeof pause !== "boolean") throw new RangeError("Pause function must be pass with boolean value.");
this.node.send({
op: "pause",
guildId: this.guildId,
pause,
});
this.isPlaying = !pause;
this.isPaused = pause;
this.node.send({
op: "pause",
guildId: this.guildId,
pause,
});
this.isPlaying = !pause;
this.isPaused = pause;
return this;
}
return this;
}
async seekTo(position) {
if (Number.isNaN(position))
throw new RangeError("[Poru Error] Position must be a number.");
this.position = position;
this.node.send({
op: "seek",
guildId: this.guildId,
position,
});
return this;
}
async seekTo(position) {
if (Number.isNaN(position)) throw new RangeError("[Poru Error] Position must be a number.");
this.position = position;
this.node.send({
op: "seek",
guildId: this.guildId,
position,
});
return this;
}
setVolume(volume) {
if (Number.isNaN(volume))
throw new RangeError("Volume level must be a number.");
this.volume = volume;
this.node.send({
op: "volume",
guildId: this.guildId,
volume: this.volume,
});
return this;
}
setVolume(volume) {
if (Number.isNaN(volume)) throw new RangeError("Volume level must be a number.");
this.volume = volume;
this.node.send({
op: "volume",
guildId: this.guildId,
volume: this.volume,
});
return this;
TrackRepeat() {
this.loop = 1;
this.trackRepeat = true;
this.queueRepeat = false;
return this;
}
}
QueueRepeat() {
this.loop = 2;
this.queueRepeat = true;
this.trackRepeat = false;
return this;
}
TrackRepeat() {
this.loop = 1;
this.trackRepeat = true;
this.queueRepeat = false;
return this;
}
DisableRepeat() {
this.loop = 0;
this.trackRepeat = false;
this.queueRepeat = false;
return this;
}
setTextChannel(channel) {
if (typeof channel !== "string")
throw new RangeError("Channel must be a string.");
this.textChannel = channel;
return this;
}
QueueRepeat() {
this.loop = 2;
this.queueRepeat = true;
this.trackRepeat = false;
return this;
}
setVoiceChannel(channel) {
if (typeof channel !== "string")
throw new RangeError("Channel must be a string.");
this.voiceChannel = channel;
return this;
}
DisableRepeat() {
this.loop = 0;
this.trackRepeat = false;
this.queueRepeat = false;
return this;
}
connect(options) {
let { guildId, voiceChannel, deaf, mute } = options;
this.send(
{
guild_id: guildId,
channel_id: voiceChannel,
self_deaf: deaf || true,
self_mute: mute || false,
},
true
);
this.isConnected = true;
}
setTextChannel(channel) {
if (typeof channel !== "string") throw new RangeError("Channel must be a string.");
this.textChannel = channel;
return this;
updateSession(data) {
if (data) {
this.voiceUpdateState = data;
this.node.send({
op: "voiceUpdate",
guildId: this.guildId,
...data,
});
}
return this;
}
setVoiceChannel(channel) {
if (typeof channel !== "string") throw new RangeError("Channel must be a string.");
this.voiceChannel = channel;
return this;
}
reconnect() {
if (this.voiceChannel === null) return null;
this.send({
guild_id: this.guildId,
channel_id: this.voiceChannel,
self_mute: false,
self_deaf: false,
});
connect(options) {
return this;
}
let { guildId, voiceChannel, deaf, mute } = options;
this.send({ guild_id: guildId, channel_id: voiceChannel, self_deaf: deaf || true, self_mute: mute || false }, true);
this.isConnected = true;
disconnect() {
if (this.voiceChannel === null) return null;
this.pause(true);
this.isConnected = false;
this.send({
guild_id: this.guildId,
channel_id: null,
self_mute: false,
self_deaf: false,
});
this.voiceChannel = null;
return this;
}
}
destroy() {
this.disconnect();
this.node.send({
op: "destroy",
guildId: this.guildId,
});
this.manager.emit("playerDestroy", this);
this.manager.players.delete(this.guildId);
}
updateSession(data) {
if (data) {
this.voiceUpdateState = data;
this.node.send({
op: "voiceUpdate",
guildId: this.guildId,
...data,
});
}
return this;
restart() {
this.filters.updateFilters();
if (this.currentTrack) {
this.isPlaying = true;
this.node.send({
op: "play",
startTime: this.position,
noReplace: true,
guildId: this.guildId,
track: this.currentTrack.track,
pause: this.isPaused,
});
}
}
reconnect() {
if (this.voiceChannel === null) return null;
this.send({
guild_id: this.guildId,
channel_id: this.voiceChannel,
self_mute: false,
self_deaf: false,
})
return this;
}
async autoplay(option = false) {
if (!option) return false;
try {
let data = `https://www.youtube.com/watch?v=${
this.previousTrack.info.identifier || this.currentTrack.info.identifier
}&list=RD${
this.previousTrack.info.identifier || this.currentTrack.info.identifier
}`;
disconnect() {
if (this.voiceChannel === null) return null;
this.pause(true);
this.isConnected = false;
this.send({
guild_id: this.guildId,
channel_id: null,
self_mute: false,
self_deaf: false,
});
this.voiceChannel = null;
return this;
}
let response = await this.manager.resolve(
data,
this.manager.options.defaultPlatform || "ytsearch"
);
destroy() {
this.disconnect();
this.node.send({
op: "destroy",
guildId: this.guildId,
});
this.manager.emit("playerDestroy", this);
this.manager.players.delete(this.guildId);
}
if (
!response ||
!response.tracks ||
["LOAD_FAILED", "NO_MATCHES"].includes(response.loadType)
)
return this.stop();
restart() {
this.filters.updateFilters();
if (this.currentTrack) {
let track =
response.tracks[
Math.floor(Math.random() * Math.floor(response.tracks.length))
];
this.isPlaying = true;
this.node.send({
op: "play",
startTime: this.position,
noReplace: true,
guildId: this.guildId,
track: this.currentTrack.track,
pause: this.isPaused
});
this.queue.push(track);
this.play();
}
return this;
} catch (e) {
console.log(`[Poru Autoplay] error : ${e}`);
return this.stop();
}
}
async autoplay(toggle = false) {
send(data) {
this.manager.sendData({ op: 4, d: data });
}
if (!toggle) return null;
try {
if (!this.previousTrack) return this.stop();
let data = `https://www.youtube.com/watch?v=${this.previousTrack.info.identifier}&list=RD${this.previousTrack.info.identifier}`;
lavalinkEvent(data) {
const events = {
TrackStartEvent() {
this.isPlaying = true;
this.isPaused = false;
this.manager.emit("trackStart", this, this.currentTrack, data);
},
// eslint-disable-next-line consistent-return
TrackEndEvent() {
this.previousTrack = this.currentTrack;
let response = await this.manager.resolve(data,this.manager.options.defaultPlatform || "ytsearch");
if (this.currentTrack && this.loop === 1) {
this.queue.unshift(this.previousTrack);
this.manager.emit("trackEnd", this, this.currentTrack, data);
return this.play();
} else if (this.currentTrack && this.loop === 2) {
this.queue.push(this.previousTrack);
this.manager.emit("trackEnd", this, this.currentTrack, data);
if (!response || !response.tracks || ["LOAD_FAILED", "NO_MATCHES"].includes(response.loadType)) return this.stop();
return this.play();
}
let track = response.tracks[Math.floor(Math.random() * Math.floor(response.tracks.length))];
this.queue.push(track);
this.play();
return this;
} catch (e) {
console.log(`[Poru Autoplay] error : ${e}`)
return this.stop();
if (this.queue.length === 0) {
return this.manager.emit("queueEnd", this, this.track, data);
} else if (this.queue.length > 0) {
this.manager.emit("trackEnd", this, this.currentTrack, data);
return this.play();
}
}
send(data) {
this.manager.sendData({ op: 4, d: data });
}
lavalinkEvent(data) {
const events = {
TrackStartEvent() {
this.isPlaying = true;
this.isPaused = false;
this.manager.emit("trackStart", this, this.currentTrack, data);
},
// eslint-disable-next-line consistent-return
TrackEndEvent() {
this.previousTrack = this.currentTrack;
if (this.currentTrack && this.loop === 1) {
this.queue.unshift(this.previousTrack)
this.manager.emit("trackEnd", this, this.currentTrack, data)
return this.play();
} else if (this.currentTrack && this.loop === 2) {
this.queue.push(this.previousTrack)
this.manager.emit("trackEnd", this, this.currentTrack, data)
return this.play();
}
if (this.queue.length === 0) {
this.manager.emit("queueEnd",this, this.track, data);
return this.destroy();
} else if (this.queue.length > 0) {
this.manager.emit("trackEnd", this, this.currentTrack, data)
return this.play();
}
this.manager.emit("queueEnd", this, this.currentTrack, data);
this.destroy();
},
TrackStuckEvent() {
this.manager.emit("trackError", this,this.currentTrack, data);
this.stop();
},
TrackExceptionEvent() {
this.manager.emit("trackError", this, this.track, data);
this.stop();
},
WebSocketClosedEvent() {
if ([4015, 4009].includes(data.code)) {
this.send({
guild_id: data.guildId,
channel_id: this.voiceChannel.id || this.voiceChannel,
self_mute: this.options.mute || false,
self_deaf: this.options.deaf || false,
});
}
this.manager.emit("socketClosed", this, data);
},
default() {
throw new Error(`An unknown event: ${data}`);
},
};
return events[data.type] || events.default;
}
this.manager.emit("queueEnd", this, this.currentTrack, data);
this.destroy();
},
TrackStuckEvent() {
this.manager.emit("trackError", this, this.currentTrack, data);
this.stop();
},
TrackExceptionEvent() {
this.manager.emit("trackError", this, this.track, data);
this.stop();
},
WebSocketClosedEvent() {
if ([4015, 4009].includes(data.code)) {
this.send({
guild_id: data.guildId,
channel_id: this.voiceChannel.id || this.voiceChannel,
self_mute: this.options.mute || false,
self_deaf: this.options.deaf || false,
});
}
this.manager.emit("socketClosed", this, data);
},
default() {
throw new Error(`An unknown event: ${data}`);
},
};
return events[data.type] || events.default;
}
}
module.exports = Player;
const { EventEmitter } = require("events");
const { fetch } = require("undici")
const config = require("./config")
const { fetch } = require("undici");
const config = require("./config");
const Player = require("./Player");
const Node = require("./Node");
const Response = require("./guild/Response");
const Spotify = require("./platform/Spotify")
const AppleMusic = require("./platform/AppleMusic")
const Deezer = require("./platform/Deezer")
const Spotify = require("./platform/Spotify");
const AppleMusic = require("./platform/AppleMusic");
const Deezer = require("./platform/Deezer");
class Poru extends EventEmitter {
constructor(client, nodes, options = {}) {
super();
if (!client) throw new Error("[Poru Error] You didn't provide a valid client");
if (!nodes) throw new Error("[Poru Error] You didn't provide a lavalink node");
constructor(client, nodes, options = {}) {
super();
if (!client)
throw new Error("[Poru Error] You didn't provide a valid client");
if (!nodes)
throw new Error("[Poru Error] You didn't provide a lavalink node");
this.client = client;
this._nodes = nodes;
this.nodes = new Map();
this.players = new Map();
this.voiceStates = new Map();
this.voiceServers = new Map();
this.isReady = false;
this.user = null;
this.options = options
this.shards = options.shards || 1;
this.sendData = null;
this.version = config.version
this.spotify = new Spotify(this, this.options);
this.apple = new AppleMusic(this, this.options)
this.apple.requestToken();
this.deezer = new Deezer(this, this.options)
this.client = client;
this._nodes = nodes;
this.nodes = new Map();
this.players = new Map();
this.voiceStates = new Map();
this.voiceServers = new Map();
this.isReady = false;
this.user = null;
this.options = options;
this.shards = options.shards || 1;
this.sendData = null;
this.version = config.version;
this.spotify = new Spotify(this, this.options);
this.apple = new AppleMusic(this, this.options);
this.apple.requestToken();
this.deezer = new Deezer(this, this.options);
}
}
init(client) {
if (this.isReady) return this;
this.user = client.user.id;
this.sendData = (data) => {
const guild = client.guilds.cache.get(data.d.guild_id);
if (guild) guild.shard.send(data);
};
init(client) {
client.on("raw", async (packet) => {
await this.packetUpdate(packet);
});
if (this.isReady) return this;
this._nodes.forEach((node) => this.addNode(node));
}
this.user = client.user.id;
this.sendData = (data) => {
const guild = client.guilds.cache.get(data.d.guild_id);
if (guild) guild.shard.send(data);
}
client.on("raw", async packet => {
await this.packetUpdate(packet);
})
this._nodes.forEach((node) => this.addNode(node));
//create a node and connect it with lavalink
addNode(options) {
const node = new Node(this, options, this.options);
if (options.name) {
this.nodes.set(options.name || options.host, node);
node.connect();
return node;
}
this.nodes.set(options.host, node);
node.connect();
return node;
}
//remove node and destroy web socket connection
removeNode(identifier) {
if (!identifier)
throw new Error(
`[Poru Error] Provide identifier as a parameter of removeNode`
);
const node = this.nodes.get(identifier);
if (!node) return;
node.destroy();
this.nodes.delete(identifier);
}
get leastUsedNodes() {
return [...this.nodes.values()]
.filter((node) => node.isConnected)
.sort((a, b) => {
const aLoad = a.stats.cpu
? (a.stats.cpu.systemLoad / a.stats.cpu.cores) * 100
: 0;
const bLoad = b.stats.cpu
? (b.stats.cpu.systemLoad / b.stats.cpu.cores) * 100
: 0;
return aLoad - bLoad;
});
}
getNode(identifier = "best") {
if (!this.nodes.size) throw new Error(`No nodes avaliable currently`);
if (identifier === "best") return this.leastUsedNodes();
//create a node and connect it with lavalink
addNode(options) {
const node = new Node(this, options, this.options);
if (options.name) {
this.nodes.set(options.name || options.host, node);
node.connect();
return node;
}
this.nodes.set(options.host, node);
node.connect();
return node;
}
const node = this.nodes.get(indetifier);
if (!node) throw new Error("The node identifier you provided is not found");
if (!node.isConnected) node.connect();
return node;
}
//remove node and destroy web socket connection
removeNode(identifier) {
if (!identifier) throw new Error(`[Poru Error] Provide identifier as a parameter of removeNode`)
const node = this.nodes.get(identifier);
if (!node) return;
node.destroy();
this.nodes.delete(identifier)
}
createConnection(options) {
this.checkConnection(options);
const player = this.players.get(options.guildId);
if (player) return player;
get leastUsedNodes() {
return [...this.nodes.values()]
.filter((node) => node.isConnected)
.sort((a, b) => {
const aLoad = a.stats.cpu ? (a.stats.cpu.systemLoad / a.stats.cpu.cores) * 100 : 0;
const bLoad = b.stats.cpu ? (b.stats.cpu.systemLoad / b.stats.cpu.cores) * 100 : 0;
return aLoad - bLoad;
});
}
if (this.leastUsedNodes.length === 0)
throw new Error("[Poru Error] No nodes are avaliable");
const node = this.nodes.get(
this.leastUsedNodes[0].name || this.leastUsedNodes[0].host
);
if (!node) throw new Error("[Poru Error] No nodes are avalible");
return this.#createPlayer(node, options);
}
getNode(identifier = "best") {
if (!this.nodes.size) throw new Error(`No nodes avaliable currently`)
if (identifier === "best") return this.leastUsedNodes();
removeConnection(guildId) {
this.players.get(guildId)?.destroy();
}
const node = this.nodes.get(indetifier);
if (!node) throw new Error('The node identifier you provided is not found');
if (!node.isConnected) node.connect();
return node;
}
checkConnection(options) {
let { guildId, voiceChannel, textChannel, shardId } = options;
if (!guildId)
throw new Error(`[Poru Connection] you have to Provide guildId`);
if (!voiceChannel)
throw new Error(`[Poru Connection] you have to Provide voiceChannel`);
if (!textChannel)
throw new Error(`[Poru Connection] you have to Provide texteChannel`);
// if(shardId == null) throw new Error(`[Poru Connection] You must have to Provide shardId`);
if (typeof guildId !== "string")
throw new Error(`[Poru Connection] guildId must be provided as a string`);
if (typeof voiceChannel !== "string")
throw new Error(
`[Poru Connection] voiceChannel must be provided as a string`
);
if (typeof textChannel !== "string")
throw new Error(
`[Poru Connection] textChannel must be provided as a string`
);
// if(typeof shardId !=="number") throw new Error(`[Poru Connection] shardId must be provided as a number`);
}
createConnection(options) {
this.checkConnection(options)
const player = this.players.get(options.guildId);
if (player) return player;
#createPlayer(node, options) {
if (this.players.has(options.guildId))
return this.players.get(options.guildId);
if (this.leastUsedNodes.length === 0) throw new Error("[Poru Error] No nodes are avaliable");
const node = this.nodes.get(this.leastUsedNodes[0].name || this.leastUsedNodes[0].host);
if (!node) throw new Error("[Poru Error] No nodes are avalible");
const player = new Player(this, node, options);
this.players.set(options.guildId, player);
player.connect(options);
return player;
}
return this.#createPlayer(node, options);
setServersUpdate(data) {
let guild = data.guild_id;
this.voiceServers.set(guild, data);
const server = this.voiceServers.get(guild);
const state = this.voiceStates.get(guild);
if (!server) return false;
const player = this.players.get(guild);
if (!player) return false;
player.updateSession({
sessionId: state ? state.session_id : player.voiceUpdateState.sessionId,
event: server,
});
return true;
}
}
setStateUpdate(data) {
if (data.user_id !== this.user) return;
if (data.channel_id) {
const guild = data.guild_id;
removeConnection(guildId) {
this.players.get(guildId)?.destroy();
}
this.voiceStates.set(data.guild_id, data);
const server = this.voiceServers.get(guild);
const state = this.voiceStates.get(guild);
if (!server) return false;
const player = this.players.get(guild);
if (!player) return false;
player.updateSession({
sessionId: state ? state.session_id : player.voiceUpdateState.sessionId,
event: server,
});
checkConnection(options) {
let { guildId, voiceChannel, textChannel, shardId } = options;
if (!guildId) throw new Error(`[Poru Connection] you have to Provide guildId`)
if (!voiceChannel) throw new Error(`[Poru Connection] you have to Provide voiceChannel`)
if (!textChannel) throw new Error(`[Poru Connection] you have to Provide texteChannel`);
// if(shardId == null) throw new Error(`[Poru Connection] You must have to Provide shardId`);
if (typeof guildId !== "string") throw new Error(`[Poru Connection] guildId must be provided as a string`);
if (typeof voiceChannel !== "string") throw new Error(`[Poru Connection] voiceChannel must be provided as a string`);
if (typeof textChannel !== "string") throw new Error(`[Poru Connection] textChannel must be provided as a string`);
// if(typeof shardId !=="number") throw new Error(`[Poru Connection] shardId must be provided as a number`);
return true;
}
this.voiceServers.delete(data.guild_id);
this.voiceStates.delete(data.guild_id);
}
packetUpdate(packet) {
if (!["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(packet.t))
return;
const player = this.players.get(packet.d.guild_id);
if (!player) return;
#createPlayer(node, options) {
if (this.players.has(options.guildId)) return this.players.get(options.guildId);
const player = new Player(this, node, options);
this.players.set(options.guildId, player);
player.connect(options)
return player;
if (packet.t === "VOICE_SERVER_UPDATE") {
this.setServersUpdate(packet.d);
}
setServersUpdate(data) {
let guild = data.guild_id
this.voiceServers.set(guild, data);
const server = this.voiceServers.get(guild);
const state = this.voiceStates.get(guild);
if (!server) return false;
const player = this.players.get(guild);
if (!player) return false;
player.updateSession({
sessionId: state ? state.session_id : player.voiceUpdateState.sessionId,
event: server,
});
return true;
if (packet.t === "VOICE_STATE_UPDATE") {
this.setStateUpdate(packet.d);
}
}
setStateUpdate(data) {
if (data.user_id !== this.user) return;
if (data.channel_id) {
const guild = data.guild_id;
async resolve(query, source) {
const node = this.leastUsedNodes[0];
if (!node) throw new Error("No nodes are available.");
const regex = /^https?:\/\//;
this.voiceStates.set(data.guild_id, data);
const server = this.voiceServers.get(guild);
const state = this.voiceStates.get(guild);
if (!server) return false;
const player = this.players.get(guild);
if (!player) return false;
player.updateSession({
sessionId: state ? state.session_id : player.voiceUpdateState.sessionId,
event: server,
});
return true;
}
this.voiceServers.delete(data.guild_id);
this.voiceStates.delete(data.guild_id);
if (regex.test(query)) {
return this.fetchURL(node, query, source);
} else {
return this.fetchTrack(node, query, source);
}
}
packetUpdate(packet) {
if (!['VOICE_STATE_UPDATE', 'VOICE_SERVER_UPDATE'].includes(packet.t)) return;
const player = this.players.get(packet.d.guild_id);
if (!player) return;
if (packet.t === "VOICE_SERVER_UPDATE") {
this.setServersUpdate(packet.d);
}
if (packet.t === "VOICE_STATE_UPDATE") {
this.setStateUpdate(packet.d);
}
async fetchURL(node, track, source) {
if (this.spotify.check(track)) {
return await this.spotify.resolve(track);
} else if (this.apple.check(track)) {
return await this.apple.resolve(track);
} else if (this.deezer.check(track)) {
return await this.deezer.resolve(track);
} else {
const result = await this.#fetch(
node,
"loadtracks",
`identifier=${encodeURIComponent(track)}`
);
if (!result) throw new Error("[Poru Error] No tracks found.");
return new Response(result);
}
}
async resolve(query, source) {
const node = this.leastUsedNodes[0];
if (!node) throw new Error("No nodes are available.");
const regex = /^https?:\/\//;
if (regex.test(query)) {
return this.fetchURL(node, query, source)
} else {
return this.fetchTrack(node, query, source)
}
async fetchTrack(node, query, source) {
switch (source) {
case "spotify": {
return this.spotify.fetch(query);
}
case "applemusic": {
return this.apple.fetch(query);
}
case "deezer": {
return this.deezer.fetch(query);
}
default: {
let track = `${source || "ytsearch"}:${query}`;
const result = await this.#fetch(
node,
"loadtracks",
`identifier=${encodeURIComponent(track)}`
);
if (!result) throw new Error("[Poru Error] No tracks found.");
return new Response(result);
}
}
}
async fetchURL(node, track, source) {
async decodeTrack(track) {
const node = this.leastUsedNodes[0];
if (!node) throw new Error("No nodes are available.");
const result = await this.#fetch(node, "decodetrack", `track=${track}`);
if (result.status === 500) return null;
return result;
}
if (this.spotify.check(track)) {
return await this.spotify.resolve(track);
} else if (this.apple.check(track)) {
return await this.apple.resolve(track);
} else if (this.deezer.check(track)) {
return await this.deezer.resolve(track);
} else {
const result = await this.#fetch(node, "loadtracks", `identifier=${encodeURIComponent(track)}`);
if (!result) throw new Error("[Poru Error] No tracks found.");
return new Response(result);
}
}
#fetch(node, endpoint, param) {
return fetch(
`http${node.secure ? "s" : ""}://${node.host}:${
node.port
}/${endpoint}?${param}`,
{
headers: {
Authorization: node.password,
},
}
)
.then((r) => r.json())
.catch((e) => {
throw new Error(
`[Poru Error] Failed to fetch from the lavalink.\n error: ${e}`
);
});
}
async fetchTrack(node, query, source) {
switch (source) {
case "spotify": {
return this.spotify.fetch(query)
}
case "applemusic": {
return this.apple.fetch(query)
}
case "deezer": {
return this.deezer.fetch(query);
}
default:
{
let track = `${source || "ytsearch"}:${query}`;
const result = await this.#fetch(node, "loadtracks", `identifier=${encodeURIComponent(track)}`);
if (!result) throw new Error("[Poru Error] No tracks found.");
return new Response(result);
}
}
}
async decodeTrack(track) {
const node = this.leastUsedNodes[0];
if (!node) throw new Error("No nodes are available.");
const result = await this.#fetch(node, "decodetrack", `track=${track}`);
if (result.status === 500) return null;
return result;
}
#fetch(node, endpoint, param) {
return fetch(`http${node.secure ? "s" : ""}://${node.host}:${node.port}/${endpoint}?${param}`, {
headers: {
Authorization: node.password,
},
})
.then((r) => r.json())
.catch((e) => {
throw new Error(`[Poru Error] Failed to fetch from the lavalink.\n error: ${e}`);
});
}
get(guildId) {
return this.players.get(guildId);
}
get(guildId) {
return this.players.get(guildId);
}
}
module.exports = Poru
module.exports = Poru;

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc