discord-player 5.2.3-dev → 5.3.0-dev.2

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/dist/Player.js CHANGED
@@ -23,10 +23,9 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
23
23
  /**
24
24
  * Creates new Discord Player
25
25
  * @param {Client} client The Discord Client
26
- * @param {PlayerInitOptions} [options={}] The player init options
26
+ * @param {PlayerInitOptions} [options] The player init options
27
27
  */
28
28
  constructor(client, options = {}) {
29
- var _a, _b, _c, _d, _e;
30
29
  super();
31
30
  this.options = {
32
31
  autoRegisterExtractor: true,
@@ -44,8 +43,8 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
44
43
  * @type {Client}
45
44
  */
46
45
  this.client = client;
47
- if (((_b = (_a = this.client) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.intents) && !new discord_js_1.Intents((_d = (_c = this.client) === null || _c === void 0 ? void 0 : _c.options) === null || _d === void 0 ? void 0 : _d.intents).has(discord_js_1.Intents.FLAGS.GUILD_VOICE_STATES)) {
48
- throw new PlayerError_1.PlayerError('client is missing "GUILD_VOICE_STATES" intent');
46
+ if (this.client?.options?.intents && !new discord_js_1.IntentsBitField(this.client?.options?.intents).has(discord_js_1.IntentsBitField.Flags.GuildVoiceStates)) {
47
+ throw new PlayerError_1.PlayerError('client is missing "GuildVoiceStates" intent');
49
48
  }
50
49
  /**
51
50
  * The extractors collection
@@ -53,7 +52,7 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
53
52
  */
54
53
  this.options = Object.assign(this.options, options);
55
54
  this.client.on("voiceStateUpdate", this._handleVoiceState.bind(this));
56
- if ((_e = this.options) === null || _e === void 0 ? void 0 : _e.autoRegisterExtractor) {
55
+ if (this.options?.autoRegisterExtractor) {
57
56
  let nv; // eslint-disable-line @typescript-eslint/no-explicit-any
58
57
  if ((nv = Util_1.Util.require("@discord-player/extractor"))) {
59
58
  ["Attachment", "Facebook", "Reverbnation", "Vimeo"].forEach((ext) => void this.use(ext, nv[ext]));
@@ -69,35 +68,41 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
69
68
  */
70
69
  _handleVoiceState(oldState, newState) {
71
70
  const queue = this.getQueue(oldState.guild.id);
72
- if (!queue)
71
+ if (!queue || !queue.connection)
73
72
  return;
74
- if (oldState.channelId && !newState.channelId && newState.member.id === newState.guild.me.id) {
73
+ if (oldState.channelId && !newState.channelId && newState.member.id === newState.guild.members.me.id) {
75
74
  try {
76
75
  queue.destroy();
77
76
  }
78
- catch (_a) {
77
+ catch {
79
78
  /* noop */
80
79
  }
81
80
  return void this.emit("botDisconnect", queue);
82
81
  }
83
- if (!oldState.channelId && newState.channelId && newState.member.id === newState.guild.me.id) {
84
- if (newState.serverMute || !newState.serverMute) {
85
- queue.setPaused(newState.serverMute);
82
+ if (!oldState.channelId && newState.channelId && newState.member.id === newState.guild.members.me.id) {
83
+ if (!oldState.serverMute && newState.serverMute) {
84
+ // state.serverMute can be null
85
+ queue.setPaused(!!newState.serverMute);
86
86
  }
87
- else if (newState.suppress || !newState.suppress) {
88
- if (newState.suppress)
89
- newState.guild.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
90
- queue.setPaused(newState.suppress);
87
+ else if (!oldState.suppress && newState.suppress) {
88
+ // state.suppress can be null
89
+ queue.setPaused(!!newState.suppress);
90
+ if (newState.suppress) {
91
+ newState.guild.members.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
92
+ }
91
93
  }
92
94
  }
93
- if (oldState.channelId === newState.channelId && newState.member.id === newState.guild.me.id) {
94
- if (oldState.serverMute !== newState.serverMute) {
95
- queue.setPaused(newState.serverMute);
95
+ if (oldState.channelId === newState.channelId && newState.member.id === newState.guild.members.me.id) {
96
+ if (!oldState.serverMute && newState.serverMute) {
97
+ // state.serverMute can be null
98
+ queue.setPaused(!!newState.serverMute);
96
99
  }
97
- else if (oldState.suppress !== newState.suppress) {
98
- if (newState.suppress)
99
- newState.guild.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
100
- queue.setPaused(newState.suppress);
100
+ else if (!oldState.suppress && newState.suppress) {
101
+ // state.suppress can be null
102
+ queue.setPaused(!!newState.suppress);
103
+ if (newState.suppress) {
104
+ newState.guild.members.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
105
+ }
101
106
  }
102
107
  }
103
108
  if (queue.connection && !newState.channelId && oldState.channelId === queue.connection.channel.id) {
@@ -109,7 +114,7 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
109
114
  if (!this.queues.has(queue.guild.id))
110
115
  return;
111
116
  if (queue.options.leaveOnEmpty)
112
- queue.destroy();
117
+ queue.destroy(true);
113
118
  this.emit("channelEmpty", queue);
114
119
  }, queue.options.leaveOnEmptyCooldown || 0).unref();
115
120
  queue._cooldownsTimeout.set(`empty_${oldState.guild.id}`, timeout);
@@ -122,8 +127,8 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
122
127
  queue._cooldownsTimeout.delete(`empty_${oldState.guild.id}`);
123
128
  }
124
129
  }
125
- if (oldState.channelId && newState.channelId && oldState.channelId !== newState.channelId && newState.member.id === newState.guild.me.id) {
126
- if (queue.connection && newState.member.id === newState.guild.me.id)
130
+ if (oldState.channelId && newState.channelId && oldState.channelId !== newState.channelId && newState.member.id === newState.guild.members.me.id) {
131
+ if (queue.connection && newState.member.id === newState.guild.members.me.id)
127
132
  queue.connection.channel = newState.channel;
128
133
  const emptyTimeout = queue._cooldownsTimeout.get(`empty_${oldState.guild.id}`);
129
134
  const channelEmpty = Util_1.Util.isVoiceEmpty(queue.connection.channel);
@@ -138,7 +143,7 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
138
143
  if (!this.queues.has(queue.guild.id))
139
144
  return;
140
145
  if (queue.options.leaveOnEmpty)
141
- queue.destroy();
146
+ queue.destroy(true);
142
147
  this.emit("channelEmpty", queue);
143
148
  }, queue.options.leaveOnEmptyCooldown || 0).unref();
144
149
  queue._cooldownsTimeout.set(`empty_${oldState.guild.id}`, timeout);
@@ -152,7 +157,6 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
152
157
  * @returns {Queue}
153
158
  */
154
159
  createQueue(guild, queueInitOptions = {}) {
155
- var _a, _b;
156
160
  guild = this.client.guilds.resolve(guild);
157
161
  if (!guild)
158
162
  throw new PlayerError_1.PlayerError("Unknown Guild", PlayerError_1.ErrorStatusCode.UNKNOWN_GUILD);
@@ -160,8 +164,8 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
160
164
  return this.queues.get(guild.id);
161
165
  const _meta = queueInitOptions.metadata;
162
166
  delete queueInitOptions["metadata"];
163
- (_a = queueInitOptions.volumeSmoothness) !== null && _a !== void 0 ? _a : (queueInitOptions.volumeSmoothness = 0.08);
164
- (_b = queueInitOptions.ytdlOptions) !== null && _b !== void 0 ? _b : (queueInitOptions.ytdlOptions = this.options.ytdlOptions);
167
+ queueInitOptions.volumeSmoothness ?? (queueInitOptions.volumeSmoothness = 0.08);
168
+ queueInitOptions.ytdlOptions ?? (queueInitOptions.ytdlOptions = this.options.ytdlOptions);
165
169
  const queue = new Queue_1.Queue(this, guild, queueInitOptions);
166
170
  queue.metadata = _meta;
167
171
  this.queues.set(guild.id, queue);
@@ -191,7 +195,7 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
191
195
  try {
192
196
  prev.destroy();
193
197
  }
194
- catch (_a) { } // eslint-disable-line no-empty
198
+ catch { } // eslint-disable-line no-empty
195
199
  this.queues.delete(guild.id);
196
200
  return prev;
197
201
  }
@@ -206,281 +210,292 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
206
210
  * @param {SearchOptions} options The search options
207
211
  * @returns {Promise<PlayerSearchResult>}
208
212
  */
209
- search(query, options) {
210
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18;
211
- return tslib_1.__awaiter(this, void 0, void 0, function* () {
212
- if (query instanceof Track_1.default)
213
- return { playlist: query.playlist || null, tracks: [query] };
214
- if (!options)
215
- throw new PlayerError_1.PlayerError("DiscordPlayer#search needs search options!", PlayerError_1.ErrorStatusCode.INVALID_ARG_TYPE);
216
- options.requestedBy = this.client.users.resolve(options.requestedBy);
217
- if (!("searchEngine" in options))
218
- options.searchEngine = types_1.QueryType.AUTO;
219
- if (typeof options.searchEngine === "string" && this.extractors.has(options.searchEngine)) {
220
- const extractor = this.extractors.get(options.searchEngine);
221
- if (!extractor.validate(query))
213
+ async search(query, options) {
214
+ if (query instanceof Track_1.default)
215
+ return { playlist: query.playlist || null, tracks: [query] };
216
+ if (!options)
217
+ throw new PlayerError_1.PlayerError("DiscordPlayer#search needs search options!", PlayerError_1.ErrorStatusCode.INVALID_ARG_TYPE);
218
+ options.requestedBy = this.client.users.resolve(options.requestedBy);
219
+ if (!("searchEngine" in options))
220
+ options.searchEngine = types_1.QueryType.AUTO;
221
+ if (typeof options.searchEngine === "string" && this.extractors.has(options.searchEngine)) {
222
+ const extractor = this.extractors.get(options.searchEngine);
223
+ if (!extractor.validate(query))
224
+ return { playlist: null, tracks: [] };
225
+ const data = await extractor.handle(query);
226
+ if (data && data.data.length) {
227
+ const playlist = !data.playlist
228
+ ? null
229
+ : new Playlist_1.Playlist(this, {
230
+ ...data.playlist,
231
+ tracks: []
232
+ });
233
+ const tracks = data.data.map((m) => new Track_1.default(this, {
234
+ ...m,
235
+ requestedBy: options.requestedBy,
236
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration)),
237
+ playlist: playlist
238
+ }));
239
+ if (playlist)
240
+ playlist.tracks = tracks;
241
+ return { playlist: playlist, tracks: tracks };
242
+ }
243
+ }
244
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
245
+ for (const [_, extractor] of this.extractors) {
246
+ if (options.blockExtractor)
247
+ break;
248
+ if (!extractor.validate(query))
249
+ continue;
250
+ const data = await extractor.handle(query);
251
+ if (data && data.data.length) {
252
+ const playlist = !data.playlist
253
+ ? null
254
+ : new Playlist_1.Playlist(this, {
255
+ ...data.playlist,
256
+ tracks: []
257
+ });
258
+ const tracks = data.data.map((m) => new Track_1.default(this, {
259
+ ...m,
260
+ requestedBy: options.requestedBy,
261
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration)),
262
+ playlist: playlist
263
+ }));
264
+ if (playlist)
265
+ playlist.tracks = tracks;
266
+ return { playlist: playlist, tracks: tracks };
267
+ }
268
+ }
269
+ const qt = options.searchEngine === types_1.QueryType.AUTO ? QueryResolver_1.QueryResolver.resolve(query) : options.searchEngine;
270
+ switch (qt) {
271
+ case types_1.QueryType.YOUTUBE_VIDEO: {
272
+ const info = await (0, ytdl_core_1.getInfo)(query, this.options.ytdlOptions).catch(Util_1.Util.noop);
273
+ if (!info)
222
274
  return { playlist: null, tracks: [] };
223
- const data = yield extractor.handle(query);
224
- if (data && data.data.length) {
225
- const playlist = !data.playlist
226
- ? null
227
- : new Playlist_1.Playlist(this, Object.assign(Object.assign({}, data.playlist), { tracks: [] }));
228
- const tracks = data.data.map((m) => new Track_1.default(this, Object.assign(Object.assign({}, m), { requestedBy: options.requestedBy, duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration)), playlist: playlist })));
229
- if (playlist)
230
- playlist.tracks = tracks;
231
- return { playlist: playlist, tracks: tracks };
232
- }
275
+ const track = new Track_1.default(this, {
276
+ title: info.videoDetails.title,
277
+ description: info.videoDetails.description,
278
+ author: info.videoDetails.author?.name,
279
+ url: info.videoDetails.video_url,
280
+ requestedBy: options.requestedBy,
281
+ thumbnail: Util_1.Util.last(info.videoDetails.thumbnails)?.url,
282
+ views: parseInt(info.videoDetails.viewCount.replace(/[^0-9]/g, "")) || 0,
283
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(parseInt(info.videoDetails.lengthSeconds) * 1000)),
284
+ source: "youtube",
285
+ raw: info
286
+ });
287
+ return { playlist: null, tracks: [track] };
233
288
  }
234
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
235
- for (const [_, extractor] of this.extractors) {
236
- if (options.blockExtractor)
237
- break;
238
- if (!extractor.validate(query))
239
- continue;
240
- const data = yield extractor.handle(query);
241
- if (data && data.data.length) {
242
- const playlist = !data.playlist
243
- ? null
244
- : new Playlist_1.Playlist(this, Object.assign(Object.assign({}, data.playlist), { tracks: [] }));
245
- const tracks = data.data.map((m) => new Track_1.default(this, Object.assign(Object.assign({}, m), { requestedBy: options.requestedBy, duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration)), playlist: playlist })));
246
- if (playlist)
247
- playlist.tracks = tracks;
248
- return { playlist: playlist, tracks: tracks };
249
- }
289
+ case types_1.QueryType.YOUTUBE_SEARCH: {
290
+ const videos = await youtube_sr_1.default.search(query, {
291
+ type: "video"
292
+ }).catch(Util_1.Util.noop);
293
+ if (!videos)
294
+ return { playlist: null, tracks: [] };
295
+ const tracks = videos.map((m) => {
296
+ m.source = "youtube"; // eslint-disable-line @typescript-eslint/no-explicit-any
297
+ return new Track_1.default(this, {
298
+ title: m.title,
299
+ description: m.description,
300
+ author: m.channel?.name,
301
+ url: m.url,
302
+ requestedBy: options.requestedBy,
303
+ thumbnail: m.thumbnail?.displayThumbnailURL("maxresdefault"),
304
+ views: m.views,
305
+ duration: m.durationFormatted,
306
+ source: "youtube",
307
+ raw: m
308
+ });
309
+ });
310
+ return { playlist: null, tracks };
250
311
  }
251
- const qt = options.searchEngine === types_1.QueryType.AUTO ? QueryResolver_1.QueryResolver.resolve(query) : options.searchEngine;
252
- switch (qt) {
253
- case types_1.QueryType.YOUTUBE_VIDEO: {
254
- const info = yield (0, ytdl_core_1.getInfo)(query, this.options.ytdlOptions).catch(Util_1.Util.noop);
255
- if (!info)
256
- return { playlist: null, tracks: [] };
312
+ case types_1.QueryType.SOUNDCLOUD_TRACK:
313
+ case types_1.QueryType.SOUNDCLOUD_SEARCH: {
314
+ const result = QueryResolver_1.QueryResolver.resolve(query) === types_1.QueryType.SOUNDCLOUD_TRACK ? [{ url: query }] : await soundcloud.search(query, "track").catch(() => []);
315
+ if (!result || !result.length)
316
+ return { playlist: null, tracks: [] };
317
+ const res = [];
318
+ for (const r of result) {
319
+ const trackInfo = await soundcloud.getSongInfo(r.url).catch(Util_1.Util.noop);
320
+ if (!trackInfo)
321
+ continue;
257
322
  const track = new Track_1.default(this, {
258
- title: info.videoDetails.title,
259
- description: info.videoDetails.description,
260
- author: (_a = info.videoDetails.author) === null || _a === void 0 ? void 0 : _a.name,
261
- url: info.videoDetails.video_url,
323
+ title: trackInfo.title,
324
+ url: trackInfo.url,
325
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(trackInfo.duration)),
326
+ description: trackInfo.description,
327
+ thumbnail: trackInfo.thumbnail,
328
+ views: trackInfo.playCount,
329
+ author: trackInfo.author.name,
262
330
  requestedBy: options.requestedBy,
263
- thumbnail: (_b = Util_1.Util.last(info.videoDetails.thumbnails)) === null || _b === void 0 ? void 0 : _b.url,
264
- views: parseInt(info.videoDetails.viewCount.replace(/[^0-9]/g, "")) || 0,
265
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(parseInt(info.videoDetails.lengthSeconds) * 1000)),
266
- source: "youtube",
267
- raw: info
331
+ source: "soundcloud",
332
+ engine: trackInfo
268
333
  });
269
- return { playlist: null, tracks: [track] };
334
+ res.push(track);
270
335
  }
271
- case types_1.QueryType.YOUTUBE_SEARCH: {
272
- const videos = yield youtube_sr_1.default.search(query, {
273
- type: "video"
274
- }).catch(Util_1.Util.noop);
275
- if (!videos)
276
- return { playlist: null, tracks: [] };
277
- const tracks = videos.map((m) => {
278
- var _a, _b;
279
- m.source = "youtube"; // eslint-disable-line @typescript-eslint/no-explicit-any
280
- return new Track_1.default(this, {
281
- title: m.title,
282
- description: m.description,
283
- author: (_a = m.channel) === null || _a === void 0 ? void 0 : _a.name,
284
- url: m.url,
336
+ return { playlist: null, tracks: res };
337
+ }
338
+ case types_1.QueryType.SPOTIFY_SONG: {
339
+ const spotifyData = await (0, spotify_url_info_1.default)(await Util_1.Util.getFetch())
340
+ .getData(query)
341
+ .catch(Util_1.Util.noop);
342
+ if (!spotifyData)
343
+ return { playlist: null, tracks: [] };
344
+ const spotifyTrack = new Track_1.default(this, {
345
+ title: spotifyData.name,
346
+ description: spotifyData.description ?? "",
347
+ author: spotifyData.artists[0]?.name ?? "Unknown Artist",
348
+ url: spotifyData.external_urls?.spotify ?? query,
349
+ thumbnail: spotifyData.album?.images[0]?.url ?? spotifyData.preview_url?.length
350
+ ? `https://i.scdn.co/image/${spotifyData.preview_url?.split("?cid=")[1]}`
351
+ : "https://www.scdn.co/i/_global/twitter_card-default.jpg",
352
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(spotifyData.duration_ms)),
353
+ views: 0,
354
+ requestedBy: options.requestedBy,
355
+ source: "spotify"
356
+ });
357
+ return { playlist: null, tracks: [spotifyTrack] };
358
+ }
359
+ case types_1.QueryType.SPOTIFY_PLAYLIST:
360
+ case types_1.QueryType.SPOTIFY_ALBUM: {
361
+ const spotifyPlaylist = await (0, spotify_url_info_1.default)(await Util_1.Util.getFetch())
362
+ .getData(query)
363
+ .catch(Util_1.Util.noop);
364
+ if (!spotifyPlaylist)
365
+ return { playlist: null, tracks: [] };
366
+ const playlist = new Playlist_1.Playlist(this, {
367
+ title: spotifyPlaylist.name ?? spotifyPlaylist.title,
368
+ description: spotifyPlaylist.description ?? "",
369
+ thumbnail: spotifyPlaylist.images[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
370
+ type: spotifyPlaylist.type,
371
+ source: "spotify",
372
+ author: spotifyPlaylist.type !== "playlist"
373
+ ? {
374
+ name: spotifyPlaylist.artists[0]?.name ?? "Unknown Artist",
375
+ url: spotifyPlaylist.artists[0]?.external_urls?.spotify ?? null
376
+ }
377
+ : {
378
+ name: spotifyPlaylist.owner?.display_name ?? spotifyPlaylist.owner?.id ?? "Unknown Artist",
379
+ url: spotifyPlaylist.owner?.external_urls?.spotify ?? null
380
+ },
381
+ tracks: [],
382
+ id: spotifyPlaylist.id,
383
+ url: spotifyPlaylist.external_urls?.spotify ?? query,
384
+ rawPlaylist: spotifyPlaylist
385
+ });
386
+ if (spotifyPlaylist.type !== "playlist") {
387
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
388
+ playlist.tracks = spotifyPlaylist.tracks.items.map((m) => {
389
+ const data = new Track_1.default(this, {
390
+ title: m.name ?? "",
391
+ description: m.description ?? "",
392
+ author: m.artists[0]?.name ?? "Unknown Artist",
393
+ url: m.external_urls?.spotify ?? query,
394
+ thumbnail: spotifyPlaylist.images[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
395
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration_ms)),
396
+ views: 0,
285
397
  requestedBy: options.requestedBy,
286
- thumbnail: (_b = m.thumbnail) === null || _b === void 0 ? void 0 : _b.displayThumbnailURL("maxresdefault"),
287
- views: m.views,
288
- duration: m.durationFormatted,
289
- source: "youtube",
290
- raw: m
398
+ playlist,
399
+ source: "spotify"
291
400
  });
401
+ return data;
292
402
  });
293
- return { playlist: null, tracks };
294
403
  }
295
- case types_1.QueryType.SOUNDCLOUD_TRACK:
296
- case types_1.QueryType.SOUNDCLOUD_SEARCH: {
297
- const result = QueryResolver_1.QueryResolver.resolve(query) === types_1.QueryType.SOUNDCLOUD_TRACK ? [{ url: query }] : yield soundcloud.search(query, "track").catch(() => []);
298
- if (!result || !result.length)
299
- return { playlist: null, tracks: [] };
300
- const res = [];
301
- for (const r of result) {
302
- const trackInfo = yield soundcloud.getSongInfo(r.url).catch(Util_1.Util.noop);
303
- if (!trackInfo)
304
- continue;
305
- const track = new Track_1.default(this, {
306
- title: trackInfo.title,
307
- url: trackInfo.url,
308
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(trackInfo.duration)),
309
- description: trackInfo.description,
310
- thumbnail: trackInfo.thumbnail,
311
- views: trackInfo.playCount,
312
- author: trackInfo.author.name,
404
+ else {
405
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
406
+ playlist.tracks = spotifyPlaylist.tracks.items.map((m) => {
407
+ const data = new Track_1.default(this, {
408
+ title: m.track.name ?? "",
409
+ description: m.track.description ?? "",
410
+ author: m.track.artists?.[0]?.name ?? "Unknown Artist",
411
+ url: m.track.external_urls?.spotify ?? query,
412
+ thumbnail: m.track.album?.images?.[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
413
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.track.duration_ms)),
414
+ views: 0,
313
415
  requestedBy: options.requestedBy,
314
- source: "soundcloud",
315
- engine: trackInfo
416
+ playlist,
417
+ source: "spotify"
316
418
  });
317
- res.push(track);
318
- }
319
- return { playlist: null, tracks: res };
320
- }
321
- case types_1.QueryType.SPOTIFY_SONG: {
322
- const spotifyData = yield spotify_url_info_1.default.getData(query).catch(Util_1.Util.noop);
323
- if (!spotifyData)
324
- return { playlist: null, tracks: [] };
325
- const spotifyTrack = new Track_1.default(this, {
326
- title: spotifyData.name,
327
- description: (_c = spotifyData.description) !== null && _c !== void 0 ? _c : "",
328
- author: (_e = (_d = spotifyData.artists[0]) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : "Unknown Artist",
329
- url: (_g = (_f = spotifyData.external_urls) === null || _f === void 0 ? void 0 : _f.spotify) !== null && _g !== void 0 ? _g : query,
330
- thumbnail: ((_k = (_j = (_h = spotifyData.album) === null || _h === void 0 ? void 0 : _h.images[0]) === null || _j === void 0 ? void 0 : _j.url) !== null && _k !== void 0 ? _k : (_l = spotifyData.preview_url) === null || _l === void 0 ? void 0 : _l.length)
331
- ? `https://i.scdn.co/image/${(_m = spotifyData.preview_url) === null || _m === void 0 ? void 0 : _m.split("?cid=")[1]}`
332
- : "https://www.scdn.co/i/_global/twitter_card-default.jpg",
333
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(spotifyData.duration_ms)),
334
- views: 0,
335
- requestedBy: options.requestedBy,
336
- source: "spotify"
419
+ return data;
337
420
  });
338
- return { playlist: null, tracks: [spotifyTrack] };
339
421
  }
340
- case types_1.QueryType.SPOTIFY_PLAYLIST:
341
- case types_1.QueryType.SPOTIFY_ALBUM: {
342
- const spotifyPlaylist = yield spotify_url_info_1.default.getData(query).catch(Util_1.Util.noop);
343
- if (!spotifyPlaylist)
344
- return { playlist: null, tracks: [] };
345
- const playlist = new Playlist_1.Playlist(this, {
346
- title: (_o = spotifyPlaylist.name) !== null && _o !== void 0 ? _o : spotifyPlaylist.title,
347
- description: (_p = spotifyPlaylist.description) !== null && _p !== void 0 ? _p : "",
348
- thumbnail: (_r = (_q = spotifyPlaylist.images[0]) === null || _q === void 0 ? void 0 : _q.url) !== null && _r !== void 0 ? _r : "https://www.scdn.co/i/_global/twitter_card-default.jpg",
349
- type: spotifyPlaylist.type,
350
- source: "spotify",
351
- author: spotifyPlaylist.type !== "playlist"
352
- ? {
353
- name: (_t = (_s = spotifyPlaylist.artists[0]) === null || _s === void 0 ? void 0 : _s.name) !== null && _t !== void 0 ? _t : "Unknown Artist",
354
- url: (_w = (_v = (_u = spotifyPlaylist.artists[0]) === null || _u === void 0 ? void 0 : _u.external_urls) === null || _v === void 0 ? void 0 : _v.spotify) !== null && _w !== void 0 ? _w : null
355
- }
356
- : {
357
- name: (_0 = (_y = (_x = spotifyPlaylist.owner) === null || _x === void 0 ? void 0 : _x.display_name) !== null && _y !== void 0 ? _y : (_z = spotifyPlaylist.owner) === null || _z === void 0 ? void 0 : _z.id) !== null && _0 !== void 0 ? _0 : "Unknown Artist",
358
- url: (_3 = (_2 = (_1 = spotifyPlaylist.owner) === null || _1 === void 0 ? void 0 : _1.external_urls) === null || _2 === void 0 ? void 0 : _2.spotify) !== null && _3 !== void 0 ? _3 : null
359
- },
360
- tracks: [],
361
- id: spotifyPlaylist.id,
362
- url: (_5 = (_4 = spotifyPlaylist.external_urls) === null || _4 === void 0 ? void 0 : _4.spotify) !== null && _5 !== void 0 ? _5 : query,
363
- rawPlaylist: spotifyPlaylist
364
- });
365
- if (spotifyPlaylist.type !== "playlist") {
366
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
367
- playlist.tracks = spotifyPlaylist.tracks.items.map((m) => {
368
- var _a, _b, _c, _d, _e, _f, _g, _h;
369
- const data = new Track_1.default(this, {
370
- title: (_a = m.name) !== null && _a !== void 0 ? _a : "",
371
- description: (_b = m.description) !== null && _b !== void 0 ? _b : "",
372
- author: (_d = (_c = m.artists[0]) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : "Unknown Artist",
373
- url: (_f = (_e = m.external_urls) === null || _e === void 0 ? void 0 : _e.spotify) !== null && _f !== void 0 ? _f : query,
374
- thumbnail: (_h = (_g = spotifyPlaylist.images[0]) === null || _g === void 0 ? void 0 : _g.url) !== null && _h !== void 0 ? _h : "https://www.scdn.co/i/_global/twitter_card-default.jpg",
375
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration_ms)),
376
- views: 0,
377
- requestedBy: options.requestedBy,
378
- playlist,
379
- source: "spotify"
380
- });
381
- return data;
382
- });
383
- }
384
- else {
385
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
386
- playlist.tracks = spotifyPlaylist.tracks.items.map((m) => {
387
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
388
- const data = new Track_1.default(this, {
389
- title: (_a = m.track.name) !== null && _a !== void 0 ? _a : "",
390
- description: (_b = m.track.description) !== null && _b !== void 0 ? _b : "",
391
- author: (_d = (_c = m.track.artists[0]) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : "Unknown Artist",
392
- url: (_f = (_e = m.track.external_urls) === null || _e === void 0 ? void 0 : _e.spotify) !== null && _f !== void 0 ? _f : query,
393
- thumbnail: (_j = (_h = (_g = m.track.album) === null || _g === void 0 ? void 0 : _g.images[0]) === null || _h === void 0 ? void 0 : _h.url) !== null && _j !== void 0 ? _j : "https://www.scdn.co/i/_global/twitter_card-default.jpg",
394
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.track.duration_ms)),
395
- views: 0,
396
- requestedBy: options.requestedBy,
397
- playlist,
398
- source: "spotify"
399
- });
400
- return data;
401
- });
402
- }
403
- return { playlist: playlist, tracks: playlist.tracks };
404
- }
405
- case types_1.QueryType.SOUNDCLOUD_PLAYLIST: {
406
- const data = yield soundcloud.getPlaylist(query).catch(Util_1.Util.noop);
407
- if (!data)
408
- return { playlist: null, tracks: [] };
409
- const res = new Playlist_1.Playlist(this, {
410
- title: data.title,
411
- description: (_6 = data.description) !== null && _6 !== void 0 ? _6 : "",
412
- thumbnail: (_7 = data.thumbnail) !== null && _7 !== void 0 ? _7 : "https://soundcloud.com/pwa-icon-192.png",
413
- type: "playlist",
422
+ return { playlist: playlist, tracks: playlist.tracks };
423
+ }
424
+ case types_1.QueryType.SOUNDCLOUD_PLAYLIST: {
425
+ const data = await soundcloud.getPlaylist(query).catch(Util_1.Util.noop);
426
+ if (!data)
427
+ return { playlist: null, tracks: [] };
428
+ const res = new Playlist_1.Playlist(this, {
429
+ title: data.title,
430
+ description: data.description ?? "",
431
+ thumbnail: data.thumbnail ?? "https://soundcloud.com/pwa-icon-192.png",
432
+ type: "playlist",
433
+ source: "soundcloud",
434
+ author: {
435
+ name: data.author?.name ?? data.author?.username ?? "Unknown Artist",
436
+ url: data.author?.profile
437
+ },
438
+ tracks: [],
439
+ id: `${data.id}`,
440
+ url: data.url,
441
+ rawPlaylist: data
442
+ });
443
+ for (const song of data.tracks) {
444
+ const track = new Track_1.default(this, {
445
+ title: song.title,
446
+ description: song.description ?? "",
447
+ author: song.author?.username ?? song.author?.name ?? "Unknown Artist",
448
+ url: song.url,
449
+ thumbnail: song.thumbnail,
450
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(song.duration)),
451
+ views: song.playCount ?? 0,
452
+ requestedBy: options.requestedBy,
453
+ playlist: res,
414
454
  source: "soundcloud",
415
- author: {
416
- name: (_11 = (_9 = (_8 = data.author) === null || _8 === void 0 ? void 0 : _8.name) !== null && _9 !== void 0 ? _9 : (_10 = data.author) === null || _10 === void 0 ? void 0 : _10.username) !== null && _11 !== void 0 ? _11 : "Unknown Artist",
417
- url: (_12 = data.author) === null || _12 === void 0 ? void 0 : _12.profile
418
- },
419
- tracks: [],
420
- id: `${data.id}`,
421
- url: data.url,
422
- rawPlaylist: data
455
+ engine: song
423
456
  });
424
- for (const song of data.tracks) {
425
- const track = new Track_1.default(this, {
426
- title: song.title,
427
- description: (_13 = song.description) !== null && _13 !== void 0 ? _13 : "",
428
- author: (_17 = (_15 = (_14 = song.author) === null || _14 === void 0 ? void 0 : _14.username) !== null && _15 !== void 0 ? _15 : (_16 = song.author) === null || _16 === void 0 ? void 0 : _16.name) !== null && _17 !== void 0 ? _17 : "Unknown Artist",
429
- url: song.url,
430
- thumbnail: song.thumbnail,
431
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(song.duration)),
432
- views: (_18 = song.playCount) !== null && _18 !== void 0 ? _18 : 0,
433
- requestedBy: options.requestedBy,
434
- playlist: res,
435
- source: "soundcloud",
436
- engine: song
437
- });
438
- res.tracks.push(track);
439
- }
440
- return { playlist: res, tracks: res.tracks };
457
+ res.tracks.push(track);
441
458
  }
442
- case types_1.QueryType.YOUTUBE_PLAYLIST: {
443
- const ytpl = yield youtube_sr_1.default.getPlaylist(query).catch(Util_1.Util.noop);
444
- if (!ytpl)
445
- return { playlist: null, tracks: [] };
446
- yield ytpl.fetch().catch(Util_1.Util.noop);
447
- const playlist = new Playlist_1.Playlist(this, {
448
- title: ytpl.title,
449
- thumbnail: ytpl.thumbnail,
450
- description: "",
451
- type: "playlist",
452
- source: "youtube",
453
- author: {
454
- name: ytpl.channel.name,
455
- url: ytpl.channel.url
456
- },
457
- tracks: [],
458
- id: ytpl.id,
459
- url: ytpl.url,
460
- rawPlaylist: ytpl
461
- });
462
- playlist.tracks = ytpl.videos.map((video) => {
463
- var _a;
464
- return new Track_1.default(this, {
465
- title: video.title,
466
- description: video.description,
467
- author: (_a = video.channel) === null || _a === void 0 ? void 0 : _a.name,
468
- url: video.url,
469
- requestedBy: options.requestedBy,
470
- thumbnail: video.thumbnail.url,
471
- views: video.views,
472
- duration: video.durationFormatted,
473
- raw: video,
474
- playlist: playlist,
475
- source: "youtube"
476
- });
477
- });
478
- return { playlist: playlist, tracks: playlist.tracks };
479
- }
480
- default:
459
+ return { playlist: res, tracks: res.tracks };
460
+ }
461
+ case types_1.QueryType.YOUTUBE_PLAYLIST: {
462
+ const ytpl = await youtube_sr_1.default.getPlaylist(query).catch(Util_1.Util.noop);
463
+ if (!ytpl)
481
464
  return { playlist: null, tracks: [] };
465
+ await ytpl.fetch().catch(Util_1.Util.noop);
466
+ const playlist = new Playlist_1.Playlist(this, {
467
+ title: ytpl.title,
468
+ thumbnail: ytpl.thumbnail,
469
+ description: "",
470
+ type: "playlist",
471
+ source: "youtube",
472
+ author: {
473
+ name: ytpl.channel.name,
474
+ url: ytpl.channel.url
475
+ },
476
+ tracks: [],
477
+ id: ytpl.id,
478
+ url: ytpl.url,
479
+ rawPlaylist: ytpl
480
+ });
481
+ playlist.tracks = ytpl.videos.map((video) => new Track_1.default(this, {
482
+ title: video.title,
483
+ description: video.description,
484
+ author: video.channel?.name,
485
+ url: video.url,
486
+ requestedBy: options.requestedBy,
487
+ thumbnail: video.thumbnail.url,
488
+ views: video.views,
489
+ duration: video.durationFormatted,
490
+ raw: video,
491
+ playlist: playlist,
492
+ source: "youtube"
493
+ }));
494
+ return { playlist: playlist, tracks: playlist.tracks };
482
495
  }
483
- });
496
+ default:
497
+ return { playlist: null, tracks: [] };
498
+ }
484
499
  }
485
500
  /**
486
501
  * Registers extractor
@@ -555,5 +570,12 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
555
570
  *[Symbol.iterator]() {
556
571
  yield* Array.from(this.queues.values());
557
572
  }
573
+ /**
574
+ * Creates `Playlist` instance
575
+ * @param data The data to initialize a playlist
576
+ */
577
+ createPlaylist(data) {
578
+ return new Playlist_1.Playlist(this, data);
579
+ }
558
580
  }
559
581
  exports.Player = Player;