poru 1.1.8 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.gitpod.yml ADDED
@@ -0,0 +1,8 @@
1
+ # This configuration file was automatically generated by Gitpod.
2
+ # Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file)
3
+ # and commit this file to your remote git repository to share the goodness with others.
4
+
5
+ tasks:
6
+ - init: npm install
7
+
8
+
package/README.md CHANGED
@@ -3,16 +3,15 @@
3
3
  </p>
4
4
  <p align="center">
5
5
 
6
- [![Discord](https://img.shields.io/discord/567705326774779944?style=flat-square)](https://discord.gg/Zmmc47Nrh8)
6
+ [![Discord](https://img.shields.io/discord/567705326774779944?style=flat-square)](https://discord.gg/Zmmc47Nrh8)
7
7
  [![npm](https://img.shields.io/npm/v/poru?style=flat-square)](https://www.npmjs.com/package/poru)
8
8
  ![Github Stars](https://img.shields.io/github/stars/parasop/poru?style=flat-square)
9
9
  ![GitHub issues](https://img.shields.io/github/issues-raw/parasop/poru?style=flat-square)
10
- ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/poru?style=flat-square)
10
+ ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/poru?style=flat-square)
11
11
  ![NPM](https://img.shields.io/npm/l/poru?style=flat-square)
12
12
 
13
13
  </p>
14
14
 
15
-
16
15
  <p align="center">
17
16
  <a href="https://nodei.co/npm/poru/"><img src="https://nodei.co/npm/poru.png?downloads=true&downloadRank=true&stars=true"></a>
18
17
  </p>
@@ -25,6 +24,7 @@
25
24
  - [Example](https://github.com/parasop/poru-example)
26
25
 
27
26
  # Installation
27
+
28
28
  ```
29
29
  // Using npm
30
30
  npm install poru
@@ -34,6 +34,7 @@ yarn add poru
34
34
  ```
35
35
 
36
36
  # About
37
+
37
38
  To use you need a configured [Lavalink](https://github.com/Frederikam/Lavalink) instance.
38
39
 
39
40
  - Stable client
@@ -43,15 +44,16 @@ To use you need a configured [Lavalink](https://github.com/Frederikam/Lavalink)
43
44
  - Easy to setup
44
45
 
45
46
  ## Implementation
46
- [Poru Music](https://github.com/parasop/poru-example) **Example bot as guide for beginning.**
47
47
 
48
+ [Poru Music](https://github.com/parasop/poru-example) **Example bot as guide for beginning.**
48
49
 
49
50
  ## Example usage basic bot
51
+
50
52
  ```javascript
51
53
  // main file
52
54
  // Require both libraries
53
- const { Client } = require("discord.js");
54
- const { Poru } = require("poru");
55
+ const { Client } = require('discord.js');
56
+ const { Poru } = require('poru');
55
57
 
56
58
  // Initiate both main classes
57
59
  const client = new Client();
@@ -59,40 +61,49 @@ const client = new Client();
59
61
  // Define some options for the node
60
62
  const nodes = [
61
63
  {
62
- host: "localhost",
63
- password: "youshallnotpass",
64
+ host: 'localhost',
65
+ password: 'youshallnotpass',
64
66
  port: 2333,
65
- secure:false
66
- }
67
+ secure: false,
68
+ },
67
69
  ];
68
70
 
71
+ // Define if you want to integrate spotify
72
+ const spotifyOptions = {
73
+ clientID: 'Your Client ID', // You'll find this on https://developers.spotify.com/dashboard/
74
+ clientSecret: 'Your Client Secret', // You'll find this on https://developers.spotify.com/dashboard/
75
+ playlistLimit: 10, // The amount of pages to load when a playlist is searched with each page having 50 tracks.
76
+ albumLimit: 5, // The amount of pages to load when a album is searched with each page having 50 tracks.
77
+ artistLimit: 5, // The amount of pages to load when a artist is searched with each page having 50 tracks.
78
+ searchMarket: 'IN', // The market from where the query should be searched from. Mainly this should contain your country.
79
+ };
80
+
69
81
  // Assign Manager to the client variable
70
- client.poru = new Poru(client,nodes);
82
+ client.poru = new Poru(client, nodes);
71
83
 
72
84
  // Emitted whenever a node connects
73
- client.poru.on("nodeConnect", node => {
74
- console.log(`Node "${node.name}" connected.`)
75
- })
85
+ client.poru.on('nodeConnect', node => {
86
+ console.log(`Node "${node.name}" connected.`);
87
+ });
76
88
 
77
89
  // Emitted whenever a node encountered an error
78
- client.poru.on("nodeError", (node, error) => {
79
- console.log(`Node "${node.name}" encountered an error`)
80
- })
90
+ client.poru.on('nodeError', (node, error) => {
91
+ console.log(`Node "${node.name}" encountered an error`);
92
+ });
81
93
 
82
94
  // Listen for when the client becomes ready
83
- client.once("ready", () => {
95
+ client.once('ready', () => {
84
96
  client.poru.init(client);
85
97
  console.log(`Logged in as ${client.user.tag}`);
86
98
  });
87
99
 
100
+ // this event used to make connections upto date with lavalink
101
+ client.on('raw', async d => await client.poru.packetUpdate(d));
88
102
 
89
103
  // Finally login at the END of your code
90
- client.login("your bot token here");
91
-
92
-
104
+ client.login('your bot token here');
93
105
  ```
94
106
 
95
-
96
107
  ```javascript
97
108
  // creating player
98
109
  const player = await client.poru.createConnection({
@@ -100,12 +111,13 @@ const player = await client.poru.createConnection({
100
111
  voiceChannel: message.member.voice.channel.id,
101
112
  textChannel: message.channel,
102
113
  selfDeaf: true,
103
- selfMute: false,
104
- })
105
- // Getting tracks
106
- const resolve = await client.poru.resolve('Ignite',"yt");
114
+ selfMute: false,
115
+ });
116
+ // Getting tracks
117
+ const resolve = await client.poru.resolve('Ignite', 'yt');
107
118
  ```
108
119
 
109
120
  ## Need Help?
110
- Feel free to join our [discord server](https://discord.gg/Zmmc47Nrh8), Give us suggestions and advice about errors and new features.
121
+
122
+ Feel free to join our [discord server](https://discord.gg/Zmmc47Nrh8), Give us suggestions and advice about errors and new features.
111
123
  with ❤️ by [Paras](https://github.com/parasop) .
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poru",
3
- "version": "1.1.8",
3
+ "version": "1.2.1",
4
4
  "description": "A stable and powefull lavalink client with so many features",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -17,10 +17,19 @@
17
17
  },
18
18
  "homepage": "https://github.com/parasop/poru#readme",
19
19
  "dependencies": {
20
- "node-fetch": "^3.2.6",
21
- "ws": "^8.8.0",
22
- "axios": "^0.27.2",
23
- "cheerio": "^1.0.0-rc.12"
24
-
25
- }
20
+ "cheerio": "^1.0.0-rc.12",
21
+ "undici": "^5.6.0",
22
+ "ws": "^8.8.0"
23
+ },
24
+ "keywords": [
25
+ "music",
26
+ "lavalink",
27
+ "poru",
28
+ "bot",
29
+ "spotify",
30
+ "apple-music",
31
+ "soundcloud",
32
+ "discordjs",
33
+ "eris"
34
+ ]
26
35
  }
package/src/Node.js CHANGED
@@ -1,16 +1,15 @@
1
1
  const WebSocket = require("ws");
2
- const config = require("./config.json")
2
+ const config = require("./config")
3
3
 
4
4
  class Node {
5
5
  constructor(manager,options,node) {
6
-
7
6
  this.manager = manager
8
7
  this.name= options.name || null;
9
8
  this.host = options.host || "localhost"
10
9
  this.port = options.port || 2333
11
- this.url = `${options.secure ? 'wss' : 'ws'}://${options.host}:${options.port}`;
12
10
  this.password = options.password ||"youshallnotpass"
13
11
  this.secure = options.secure || false;
12
+ this.url = `${this.secure ? 'wss' : 'ws'}://${this.host}:${this.port}/`;
14
13
  this.ws = null;
15
14
  this.reconnectTime = node.reconnectTime || 5000;
16
15
  this.resumeKey = node.resumeKey || null;
@@ -37,132 +36,130 @@ class Node {
37
36
  };
38
37
 
39
38
 
40
- }
41
-
42
- connect() {
43
- if (this.ws) this.ws.close();
44
- const headers = {
45
- Authorization: this.password,
46
- "Num-Shards": this.manager.shards || 1,
47
- "User-Id": this.manager.user,
48
- "Client-Name": config.client
49
- };
50
- if (this.resumeKey) headers["Resume-Key"] = this.resumeKey;
51
- this.ws = new WebSocket(`ws${this.secure ? "s" : ""}:${this.host}:${this.port}/`, { headers });
52
- this.ws.on("open",this.#open.bind(this));
53
- this.ws.on("error", this.#error.bind(this));
54
- this.ws.on("message", this.#message.bind(this));
55
- this.ws.on("close", this.#close.bind(this));
56
- }
57
-
58
-
59
- #open(){
60
- if (this.reconnectAttempt) {
61
- clearTimeout(this.reconnectAttempt);
62
- delete this.reconnectAttempt;
63
- }
64
-
65
- if (this.resumeKey){
66
- this.send({
67
- op: "configureResuming",
68
- key: (this.resumeKey).toString(),
69
- timeout: this.resumeTimeout
70
- });
71
- this.manager.emit("debug",this.name,`[Web Socket] Resuming configured on Lavalink`)
72
- }
73
-
74
- this.manager.emit("nodeConnect", this);
75
- this.isConnected = true;
76
- this.manager.emit('debug', this.name, `[Web Socket] Connection ready ${this.url}`);
77
-
78
- }
79
-
80
- #message(payload) {
81
- if (Array.isArray(payload)) payload = Buffer.concat(payload);
82
- else if (payload instanceof ArrayBuffer) payload = Buffer.from(payload);
39
+ }
83
40
 
84
- const packet = JSON.parse(payload);
85
- if (packet.op && packet.op === "stats") {
86
- this.stats = { ...packet };
87
- delete this.stats.op;
41
+ connect() {
42
+ if (this.ws) this.ws.close();
43
+ const headers = {
44
+ Authorization: this.password,
45
+ "Num-Shards": this.manager.shards || 1,
46
+ "User-Id": this.manager.user,
47
+ "Client-Name": config.clientName
48
+ };
49
+ if (this.resumeKey) headers["Resume-Key"] = this.resumeKey;
50
+ this.ws = new WebSocket(this.url, { headers });
51
+ this.ws.on("open",this.#open.bind(this));
52
+ this.ws.on("error", this.#error.bind(this));
53
+ this.ws.on("message", this.#message.bind(this));
54
+ this.ws.on("close", this.#close.bind(this));
88
55
  }
89
- const player = this.manager.players.get(packet.guildId);
90
- if (packet.guildId && player) player.emit(packet.op, packet);
91
56
 
92
- packet.node = this;
93
- this.manager.emit("debug",this.name,`[Web Socket] Lavalink Node Update : ${packet.op} `)
94
- this.manager.emit("raw", packet);
95
- }
96
57
 
97
- #close(event) {
98
- this.manager.emit("nodeDisconnect", event, this);
99
- this.manager.emit("debug",this.name,`[Web Socket] Connection with Lavalink closed with Error code : ${event||"Unkwon code"}`)
100
- if (event !== 1000){
58
+ #open(){
59
+ if (this.reconnectAttempt) {
60
+ clearTimeout(this.reconnectAttempt);
61
+ delete this.reconnectAttempt;
62
+ }
63
+
64
+ if (this.resumeKey){
65
+ this.send({
66
+ op: "configureResuming",
67
+ key: (this.resumeKey).toString(),
68
+ timeout: this.resumeTimeout
69
+ });
70
+ this.manager.emit("debug",this.name,`[Web Socket] Resuming configured on Lavalink`)
71
+ }
72
+
73
+ this.manager.emit("nodeConnect", this);
74
+ this.isConnected = true;
75
+ this.manager.emit('debug', this.name, `[Web Socket] Connection ready ${this.url}`);
101
76
 
102
- return this.reconnect();
103
77
  }
104
- }
105
78
 
79
+ #message(payload) {
80
+ if (Array.isArray(payload)) payload = Buffer.concat(payload);
81
+ else if (payload instanceof ArrayBuffer) payload = Buffer.from(payload);
106
82
 
107
- #error(event) {
108
- if (!event) return "Unknown event";
83
+ const packet = JSON.parse(payload);
84
+ if(!packet.op) return;
85
+
86
+ if (packet.op && packet.op === "stats") {
87
+ this.stats = { ...packet };
88
+ delete this.stats.op;
89
+ }
90
+ const player = this.manager.players.get(packet.guildId);
91
+ if (packet.guildId && player) player.emit(packet.op, packet);
92
+
93
+ packet.node = this;
94
+ this.manager.emit("debug",this.name,`[Web Socket] Lavalink Node Update : ${packet.op} `)
95
+ this.manager.emit("raw", packet);
96
+ }
109
97
 
110
- this.manager.emit("debug",this.name,`[Web Socket] Connection for Lavalink node has error code: ${event.code}`)
111
- this.manager.emit("nodeError", this, event);
112
- return this.reconnect();
113
- }
98
+ #close(event) {
99
+ this.manager.emit("nodeDisconnect", event, this);
100
+ this.manager.emit("debug",this.name,`[Web Socket] Connection with Lavalink closed with Error code : ${event||"Unknown code"}`)
101
+ if (event !== 1000){
102
+
103
+ return this.reconnect();
104
+ }
105
+ }
114
106
 
115
- destroy(){
116
- if(!this.isConnected) return;
117
107
 
118
- const players = this.manager.players.filter(p => p.node == this);
119
- if (players.size) players.forEach(p => p.destroy());
120
- this.ws.close(1000, "destroy");
121
- this.ws.removeAllListeners();
122
- this.ws = null;
123
- this.reconnect = 1;
124
- this.destroyed = true;
125
- this.manager.nodes.delete(this.host)
126
- this.manager.emit("nodeDestroy", this);
108
+ #error(event) {
109
+ if (!event) return "Unknown event";
127
110
 
111
+ this.manager.emit("debug",this.name,`[Web Socket] Connection for Lavalink node has error code: ${event.code}`)
112
+ this.manager.emit("nodeError", this, event);
113
+ return this.reconnect();
114
+ }
128
115
 
129
- }
116
+ destroy(){
117
+ if(!this.isConnected) return;
130
118
 
131
- reconnect() {
132
- this.reconnectAttempt = setTimeout(() => {
133
- this.isConnected = false;
119
+ const players = this.manager.players.filter(p => p.node == this);
120
+ if (players.size) players.forEach(p => p.destroy());
121
+ this.ws.close(1000, "destroy");
134
122
  this.ws.removeAllListeners();
135
123
  this.ws = null;
136
- this.manager.emit("nodeReconnect", this);
137
- this.connect();
138
- }, this.reconnectTime);
139
- }
140
-
141
- send(payload) {
142
- this.ws.send(JSON.stringify(payload), (error) => {
143
- if (error) return error;
144
- return null;
145
- });
146
- }
124
+ this.reconnect = 1;
125
+ this.destroyed = true;
126
+ this.manager.nodes.delete(this.host)
127
+ this.manager.emit("nodeDestroy", this);
147
128
 
148
129
 
149
-
150
- get penalties(){
151
- let penalties = 0;
152
- if (!this.isConnected) return penalties;
153
- penalties += this.stats.players;
154
- penalties += Math.round(Math.pow(1.05, 100 * this.stats.cpu.systemLoad) * 10 - 10);
155
- if (this.stats.frameStats) {
156
- penalties += this.stats.frameStats.deficit;
157
- penalties += this.stats.frameStats.nulled * 2;
158
130
  }
159
- return penalties;
160
- }
161
131
 
132
+ reconnect() {
133
+ this.reconnectAttempt = setTimeout(() => {
134
+ this.isConnected = false;
135
+ this.ws.removeAllListeners();
136
+ this.ws = null;
137
+ this.manager.emit("nodeReconnect", this);
138
+ this.connect();
139
+ }, this.reconnectTime);
140
+ }
162
141
 
163
- }
164
-
142
+ send(payload) {
143
+ const data = JSON.stringify(payload);
144
+ this.ws.send(data, (error) => {
145
+ if (error) return error;
146
+ return null;
147
+ });
148
+ this.manager.emit("raw", data, this.name)
149
+ }
165
150
 
151
+ get penalties(){
152
+ let penalties = 0;
153
+ if (!this.isConnected) return penalties;
154
+ penalties += this.stats.players;
155
+ penalties += Math.round(Math.pow(1.05, 100 * this.stats.cpu.systemLoad) * 10 - 10);
156
+ if (this.stats.frameStats) {
157
+ penalties += this.stats.frameStats.deficit;
158
+ penalties += this.stats.frameStats.nulled * 2;
159
+ }
160
+ return penalties;
161
+ }
162
+ }
166
163
 
167
- module.exports = Node;
164
+ module.exports = Node;
168
165
 
package/src/Player.js CHANGED
@@ -50,6 +50,7 @@ class Player extends EventEmitter {
50
50
  this.manager.emit("playerUpdate", this, packet);
51
51
  });
52
52
  }
53
+
53
54
  async play() {
54
55
 
55
56
  if (!this.queue.length) {
@@ -72,7 +73,7 @@ class Player extends EventEmitter {
72
73
  }
73
74
 
74
75
 
75
- stop() {
76
+ stop() {
76
77
 
77
78
  this.position = 0;
78
79
  this.isConnectd = false
@@ -182,9 +183,6 @@ class Player extends EventEmitter {
182
183
  return this;
183
184
  }
184
185
 
185
-
186
-
187
-
188
186
  async disconnect() {
189
187
  if (this.voiceChannel === null) return null;
190
188
  this.pause(true);
@@ -221,7 +219,7 @@ class Player extends EventEmitter {
221
219
 
222
220
  let response = await this.manager.resolve(data);
223
221
 
224
- if (!response || !response.tracks || ["LOAD_FAILED", "NO_MATCHES"].includes(response.type)) return this.stop();
222
+ if (!response || !response.tracks || ["LOAD_FAILED", "NO_MATCHES"].includes(response.loadType)) return this.stop();
225
223
 
226
224
  let track = response.tracks[Math.floor(Math.random() * Math.floor(response.tracks.length))];
227
225
 
@@ -306,7 +304,6 @@ class Player extends EventEmitter {
306
304
  return events[data.type] || events.default;
307
305
  }
308
306
 
309
-
310
307
  }
311
308
 
312
309
  module.exports = Player;
package/src/Poru.js CHANGED
@@ -1,14 +1,11 @@
1
1
  const { EventEmitter } = require("events");
2
- const fetch = (...args) => import('node-fetch').then(({
3
- default: fetch
4
- }) => fetch(...args));
2
+ const { fetch } = require('undici');
5
3
  const Player = require("./Player");
6
4
  const Node = require("./Node");
7
5
  const Response = require("./guild/Response");
8
- const config = require("./config.json")
9
6
  const Spotify = require("./platform/Spotify")
10
7
  const Apple = require("./platform/Apple")
11
-
8
+ const Deezer = require("./platform/Deezer")
12
9
  class Poru extends EventEmitter {
13
10
  constructor(client, nodes, options = {}) {
14
11
  super();
@@ -76,27 +73,33 @@ class Poru extends EventEmitter {
76
73
  const guild = client.guilds.cache.get(data.d.guild_id);
77
74
  if (guild) guild.shard.send(data);
78
75
  }
76
+
79
77
  client.on("raw", async packet => {
80
- await this.#packetUpdate(packet);
78
+ await this.packetUpdate(packet);
81
79
  })
82
-
80
+
83
81
  this._nodes.forEach((node) => this.addNode(node));
84
82
 
85
83
 
86
- if (this.options.spotify && this.options.spotify.clientID && this.options.spotify.clientSecret) {
87
- this.spotify = new Spotify(this, {
88
- clientID: this.options.clientID,
89
- clientSecret: this.options.clientSecret
90
- })
84
+ if (this.options.spotify && this.options.spotify.clientID && this.options.spotify.clientSecret) {
85
+ this.spotify = new Spotify(this, this.options)
86
+ }
87
+ if (this.options.apple) {
88
+ if (!this.options.apple.playlistLimit) {
89
+ throw new Error("[Poru Apple Music] playlistLimit must be provided")
90
+ }
91
+ this.apple = new Apple(this, this.options)
92
+ }
93
+ if (this.options.dezzer) {
94
+ if (!this.options.dezzer.playlistLimit) {
95
+ throw new Error("[Poru Deezer Music] playlistLimit must be provided")
96
+
97
+ }
98
+ this.deezer = new Deezer(this, this.options)
99
+
91
100
  }
92
- if(this.options.apple){
93
- if(!this.options.apple.playlistLimit){
94
- throw new Error("[Poru Apple Music] playlistLimit must be provided")
95
- }
96
- this.apple = new Apple(this,this.options)
97
- }
98
101
  console.log(`Thanks for using Poru`)
99
- }
102
+ }
100
103
 
101
104
 
102
105
  setServersUpdate(data) {
@@ -139,7 +142,7 @@ if(this.options.apple){
139
142
  this.voiceStates.delete(data.guild_id);
140
143
  }
141
144
 
142
- #packetUpdate(packet) {
145
+ packetUpdate(packet) {
143
146
  if (!['VOICE_STATE_UPDATE', 'VOICE_SERVER_UPDATE'].includes(packet.t)) return;
144
147
  const player = this.players.get(packet.d.guild_id);
145
148
  if (!player) return;
@@ -184,22 +187,23 @@ if(this.options.apple){
184
187
 
185
188
 
186
189
  async resolve(track, source) {
187
-
190
+
188
191
  const node = this.leastUsedNodes[0];
189
192
  if (!node) throw new Error("No nodes are available.");
190
- if(this.spotify && this.spotify.check(track)){
191
- return await this.spotify.resolve(track);
192
- }
193
-
194
- if(this.apple && this.apple.check(track)){
193
+ if (this.spotify && this.spotify.check(track)) {
194
+ return await this.spotify.resolve(track);
195
+ }else if (this.apple && this.apple.check(track)) {
195
196
  return await this.apple.resolve(track);
196
- }
197
-
197
+ }else if (this.deezer && this.deezer.check(track)) {
198
+ return await this.deezer.resolve(track);
199
+ }
200
+
201
+
198
202
 
199
203
  const regex = /^https?:\/\//;
200
204
  if (!regex.test(track)) {
201
205
  // eslint-disable-next-line no-param-reassign
202
- track = `${source || "yt"}search:${track}`;
206
+ track = `${source || "ytsearch"}:${track}`;
203
207
  }
204
208
  const result = await this.#fetch(node, "loadtracks", `identifier=${encodeURIComponent(track)}`);
205
209
 
package/src/config.js ADDED
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ clientName: "Poru"
3
+ }
@@ -0,0 +1,61 @@
1
+ const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2
+ class DeezerTrack {
3
+ constructor(data) {
4
+ this.track = data.track
5
+ this.info = {
6
+ identifier: null,
7
+ isSeekable: data.info.isSeekable,
8
+ author: data.info.author,
9
+ length: data.info.length,
10
+ isStream: data.info.isStream,
11
+ sourceName: data.info.sourceName,
12
+ title: data.info.title,
13
+ uri: data.info.uri,
14
+ image: data.image || null
15
+
16
+ }
17
+ }
18
+
19
+ async resolve(manager) {
20
+
21
+ const query = [this.info.author, this.info.title].filter((x) => !!x).join(' - ');
22
+
23
+
24
+ const result = await manager.resolve(query);
25
+ if (!result || !result.tracks.length) return;
26
+
27
+ if (this.info.author) {
28
+ const author = [this.info.author, `${this.info.author} - Topic`];
29
+ const officialAudio = result.tracks.find(
30
+ (track) =>
31
+ author.some((name) => new RegExp(`^${escapeRegExp(name)}$`, 'i').test(track.info.author)) ||
32
+ new RegExp(`^${escapeRegExp(this.info.title)}$`, 'i').test(track.info.title),
33
+ );
34
+ if (officialAudio) {
35
+ this.info.identifier = officialAudio.info.identifier
36
+ this.track = officialAudio.track;
37
+ this.length = officialAudio.info.length
38
+ return this
39
+ }
40
+ }
41
+ if (this.info.length) {
42
+ const sameDuration = result.tracks.find(
43
+ (track) =>
44
+ track.info.length >= (this.info.length ? this.length : 0) - 2000 &&
45
+ track.info.length <= (this.info.length ? this.length : 0) + 2000,
46
+ );
47
+ if (sameDuration) {
48
+ this.info.identifier = sameDuration.info.identifier
49
+ this.track = sameDuration.track;
50
+ this.length = officialAudio.info.length
51
+ return this
52
+ }
53
+ }
54
+ this.info.identifier = result.tracks[0].info.identifier
55
+ this.track = result.tracks[0].track;
56
+ this.length = officialAudio.info.length
57
+ return this
58
+ }
59
+ }
60
+
61
+ module.exports = DeezerTrack;