discord-player 5.2.1 → 5.3.0-dev.0

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
@@ -7,11 +7,11 @@ const tiny_typed_emitter_1 = require("tiny-typed-emitter");
7
7
  const Queue_1 = require("./Structures/Queue");
8
8
  const VoiceUtils_1 = require("./VoiceInterface/VoiceUtils");
9
9
  const types_1 = require("./types/types");
10
- const Track_1 = (0, tslib_1.__importDefault)(require("./Structures/Track"));
10
+ const Track_1 = tslib_1.__importDefault(require("./Structures/Track"));
11
11
  const QueryResolver_1 = require("./utils/QueryResolver");
12
- const youtube_sr_1 = (0, tslib_1.__importDefault)(require("youtube-sr"));
12
+ const youtube_sr_1 = tslib_1.__importDefault(require("youtube-sr"));
13
13
  const Util_1 = require("./utils/Util");
14
- const spotify_url_info_1 = (0, tslib_1.__importDefault)(require("spotify-url-info"));
14
+ const spotify_url_info_1 = tslib_1.__importDefault(require("spotify-url-info"));
15
15
  const PlayerError_1 = require("./Structures/PlayerError");
16
16
  const ytdl_core_1 = require("ytdl-core");
17
17
  const soundcloud_scraper_1 = require("soundcloud-scraper");
@@ -26,7 +26,6 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
26
26
  * @param {PlayerInitOptions} [options={}] The player init options
27
27
  */
28
28
  constructor(client, options = {}) {
29
- var _a;
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 (!new discord_js_1.Intents(this.client.options.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 ((_a = this.options) === null || _a === void 0 ? void 0 : _a.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,77 +68,80 @@ 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 && oldState.channelId !== newState.channelId) {
75
- if ((queue === null || queue === void 0 ? void 0 : queue.connection) && newState.member.id === newState.guild.me.id)
76
- queue.connection.channel = newState.channel;
77
- if (newState.member.id === newState.guild.me.id || (newState.member.id !== newState.guild.me.id && oldState.channelId === queue.connection.channel.id)) {
73
+ if (oldState.channelId && !newState.channelId && newState.member.id === newState.guild.members.me.id) {
74
+ try {
75
+ queue.destroy();
76
+ }
77
+ catch {
78
+ /* noop */
79
+ }
80
+ return void this.emit("botDisconnect", queue);
81
+ }
82
+ if (!oldState.channelId && newState.channelId && newState.member.id === newState.guild.members.me.id) {
83
+ if (newState.serverMute || !newState.serverMute) {
84
+ queue.setPaused(newState.serverMute);
85
+ }
86
+ else if (newState.suppress || !newState.suppress) {
87
+ if (newState.suppress)
88
+ newState.guild.members.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
89
+ queue.setPaused(newState.suppress);
90
+ }
91
+ }
92
+ if (oldState.channelId === newState.channelId && newState.member.id === newState.guild.members.me.id) {
93
+ if (oldState.serverMute !== newState.serverMute) {
94
+ queue.setPaused(newState.serverMute);
95
+ }
96
+ else if (oldState.suppress !== newState.suppress) {
97
+ if (newState.suppress)
98
+ newState.guild.members.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
99
+ queue.setPaused(newState.suppress);
100
+ }
101
+ }
102
+ if (queue.connection && !newState.channelId && oldState.channelId === queue.connection.channel.id) {
103
+ if (!Util_1.Util.isVoiceEmpty(queue.connection.channel))
104
+ return;
105
+ const timeout = setTimeout(() => {
78
106
  if (!Util_1.Util.isVoiceEmpty(queue.connection.channel))
79
107
  return;
108
+ if (!this.queues.has(queue.guild.id))
109
+ return;
110
+ if (queue.options.leaveOnEmpty)
111
+ queue.destroy(true);
112
+ this.emit("channelEmpty", queue);
113
+ }, queue.options.leaveOnEmptyCooldown || 0).unref();
114
+ queue._cooldownsTimeout.set(`empty_${oldState.guild.id}`, timeout);
115
+ }
116
+ if (queue.connection && newState.channelId && newState.channelId === queue.connection.channel.id) {
117
+ const emptyTimeout = queue._cooldownsTimeout.get(`empty_${oldState.guild.id}`);
118
+ const channelEmpty = Util_1.Util.isVoiceEmpty(queue.connection.channel);
119
+ if (!channelEmpty && emptyTimeout) {
120
+ clearTimeout(emptyTimeout);
121
+ queue._cooldownsTimeout.delete(`empty_${oldState.guild.id}`);
122
+ }
123
+ }
124
+ if (oldState.channelId && newState.channelId && oldState.channelId !== newState.channelId && newState.member.id === newState.guild.members.me.id) {
125
+ if (queue.connection && newState.member.id === newState.guild.members.me.id)
126
+ queue.connection.channel = newState.channel;
127
+ const emptyTimeout = queue._cooldownsTimeout.get(`empty_${oldState.guild.id}`);
128
+ const channelEmpty = Util_1.Util.isVoiceEmpty(queue.connection.channel);
129
+ if (!channelEmpty && emptyTimeout) {
130
+ clearTimeout(emptyTimeout);
131
+ queue._cooldownsTimeout.delete(`empty_${oldState.guild.id}`);
132
+ }
133
+ else {
80
134
  const timeout = setTimeout(() => {
81
- if (!Util_1.Util.isVoiceEmpty(queue.connection.channel))
135
+ if (queue.connection && !Util_1.Util.isVoiceEmpty(queue.connection.channel))
82
136
  return;
83
137
  if (!this.queues.has(queue.guild.id))
84
138
  return;
85
139
  if (queue.options.leaveOnEmpty)
86
- queue.destroy();
140
+ queue.destroy(true);
87
141
  this.emit("channelEmpty", queue);
88
142
  }, queue.options.leaveOnEmptyCooldown || 0).unref();
89
143
  queue._cooldownsTimeout.set(`empty_${oldState.guild.id}`, timeout);
90
144
  }
91
- if (!oldState.channelId && newState.channelId && newState.member.id === newState.guild.me.id) {
92
- if (newState.serverMute || !newState.serverMute) {
93
- queue.setPaused(newState.serverMute);
94
- }
95
- else if (newState.suppress || !newState.suppress) {
96
- if (newState.suppress)
97
- newState.guild.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
98
- queue.setPaused(newState.suppress);
99
- }
100
- }
101
- if (oldState.channelId === newState.channelId && oldState.member.id === newState.guild.me.id) {
102
- if (oldState.serverMute !== newState.serverMute) {
103
- queue.setPaused(newState.serverMute);
104
- }
105
- else if (oldState.suppress !== newState.suppress) {
106
- if (newState.suppress)
107
- newState.guild.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
108
- queue.setPaused(newState.suppress);
109
- }
110
- }
111
- if (oldState.member.id === this.client.user.id && !newState.channelId) {
112
- queue.destroy();
113
- return void this.emit("botDisconnect", queue);
114
- }
115
- if (!queue.connection || !queue.connection.channel)
116
- return;
117
- if (!oldState.channelId || newState.channelId) {
118
- const emptyTimeout = queue._cooldownsTimeout.get(`empty_${oldState.guild.id}`);
119
- const channelEmpty = Util_1.Util.isVoiceEmpty(queue.connection.channel);
120
- if (newState.channelId === queue.connection.channel.id) {
121
- if (!channelEmpty && emptyTimeout) {
122
- clearTimeout(emptyTimeout);
123
- queue._cooldownsTimeout.delete(`empty_${oldState.guild.id}`);
124
- }
125
- }
126
- }
127
- else {
128
- if (oldState.channelId === queue.connection.channel.id) {
129
- if (!Util_1.Util.isVoiceEmpty(queue.connection.channel))
130
- return;
131
- const timeout = setTimeout(() => {
132
- if (!Util_1.Util.isVoiceEmpty(queue.connection.channel))
133
- return;
134
- if (!this.queues.has(queue.guild.id))
135
- return;
136
- if (queue.options.leaveOnEmpty)
137
- queue.destroy();
138
- this.emit("channelEmpty", queue);
139
- }, queue.options.leaveOnEmptyCooldown || 0).unref();
140
- queue._cooldownsTimeout.set(`empty_${oldState.guild.id}`, timeout);
141
- }
142
- }
143
145
  }
144
146
  }
145
147
  /**
@@ -149,7 +151,6 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
149
151
  * @returns {Queue}
150
152
  */
151
153
  createQueue(guild, queueInitOptions = {}) {
152
- var _a, _b;
153
154
  guild = this.client.guilds.resolve(guild);
154
155
  if (!guild)
155
156
  throw new PlayerError_1.PlayerError("Unknown Guild", PlayerError_1.ErrorStatusCode.UNKNOWN_GUILD);
@@ -157,8 +158,8 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
157
158
  return this.queues.get(guild.id);
158
159
  const _meta = queueInitOptions.metadata;
159
160
  delete queueInitOptions["metadata"];
160
- (_a = queueInitOptions.volumeSmoothness) !== null && _a !== void 0 ? _a : (queueInitOptions.volumeSmoothness = 0.1);
161
- (_b = queueInitOptions.ytdlOptions) !== null && _b !== void 0 ? _b : (queueInitOptions.ytdlOptions = this.options.ytdlOptions);
161
+ queueInitOptions.volumeSmoothness ?? (queueInitOptions.volumeSmoothness = 0.08);
162
+ queueInitOptions.ytdlOptions ?? (queueInitOptions.ytdlOptions = this.options.ytdlOptions);
162
163
  const queue = new Queue_1.Queue(this, guild, queueInitOptions);
163
164
  queue.metadata = _meta;
164
165
  this.queues.set(guild.id, queue);
@@ -188,7 +189,7 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
188
189
  try {
189
190
  prev.destroy();
190
191
  }
191
- catch (_a) { } // eslint-disable-line no-empty
192
+ catch { } // eslint-disable-line no-empty
192
193
  this.queues.delete(guild.id);
193
194
  return prev;
194
195
  }
@@ -203,281 +204,292 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
203
204
  * @param {SearchOptions} options The search options
204
205
  * @returns {Promise<PlayerSearchResult>}
205
206
  */
206
- search(query, options) {
207
- 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;
208
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
209
- if (query instanceof Track_1.default)
210
- return { playlist: query.playlist || null, tracks: [query] };
211
- if (!options)
212
- throw new PlayerError_1.PlayerError("DiscordPlayer#search needs search options!", PlayerError_1.ErrorStatusCode.INVALID_ARG_TYPE);
213
- options.requestedBy = this.client.users.resolve(options.requestedBy);
214
- if (!("searchEngine" in options))
215
- options.searchEngine = types_1.QueryType.AUTO;
216
- if (typeof options.searchEngine === "string" && this.extractors.has(options.searchEngine)) {
217
- const extractor = this.extractors.get(options.searchEngine);
218
- if (!extractor.validate(query))
207
+ async search(query, options) {
208
+ if (query instanceof Track_1.default)
209
+ return { playlist: query.playlist || null, tracks: [query] };
210
+ if (!options)
211
+ throw new PlayerError_1.PlayerError("DiscordPlayer#search needs search options!", PlayerError_1.ErrorStatusCode.INVALID_ARG_TYPE);
212
+ options.requestedBy = this.client.users.resolve(options.requestedBy);
213
+ if (!("searchEngine" in options))
214
+ options.searchEngine = types_1.QueryType.AUTO;
215
+ if (typeof options.searchEngine === "string" && this.extractors.has(options.searchEngine)) {
216
+ const extractor = this.extractors.get(options.searchEngine);
217
+ if (!extractor.validate(query))
218
+ return { playlist: null, tracks: [] };
219
+ const data = await extractor.handle(query);
220
+ if (data && data.data.length) {
221
+ const playlist = !data.playlist
222
+ ? null
223
+ : new Playlist_1.Playlist(this, {
224
+ ...data.playlist,
225
+ tracks: []
226
+ });
227
+ const tracks = data.data.map((m) => new Track_1.default(this, {
228
+ ...m,
229
+ requestedBy: options.requestedBy,
230
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration)),
231
+ playlist: playlist
232
+ }));
233
+ if (playlist)
234
+ playlist.tracks = tracks;
235
+ return { playlist: playlist, tracks: tracks };
236
+ }
237
+ }
238
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
239
+ for (const [_, extractor] of this.extractors) {
240
+ if (options.blockExtractor)
241
+ break;
242
+ if (!extractor.validate(query))
243
+ continue;
244
+ const data = await extractor.handle(query);
245
+ if (data && data.data.length) {
246
+ const playlist = !data.playlist
247
+ ? null
248
+ : new Playlist_1.Playlist(this, {
249
+ ...data.playlist,
250
+ tracks: []
251
+ });
252
+ const tracks = data.data.map((m) => new Track_1.default(this, {
253
+ ...m,
254
+ requestedBy: options.requestedBy,
255
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration)),
256
+ playlist: playlist
257
+ }));
258
+ if (playlist)
259
+ playlist.tracks = tracks;
260
+ return { playlist: playlist, tracks: tracks };
261
+ }
262
+ }
263
+ const qt = options.searchEngine === types_1.QueryType.AUTO ? QueryResolver_1.QueryResolver.resolve(query) : options.searchEngine;
264
+ switch (qt) {
265
+ case types_1.QueryType.YOUTUBE_VIDEO: {
266
+ const info = await (0, ytdl_core_1.getInfo)(query, this.options.ytdlOptions).catch(Util_1.Util.noop);
267
+ if (!info)
219
268
  return { playlist: null, tracks: [] };
220
- const data = yield extractor.handle(query);
221
- if (data && data.data.length) {
222
- const playlist = !data.playlist
223
- ? null
224
- : new Playlist_1.Playlist(this, Object.assign(Object.assign({}, data.playlist), { tracks: [] }));
225
- 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 })));
226
- if (playlist)
227
- playlist.tracks = tracks;
228
- return { playlist: playlist, tracks: tracks };
229
- }
269
+ const track = new Track_1.default(this, {
270
+ title: info.videoDetails.title,
271
+ description: info.videoDetails.description,
272
+ author: info.videoDetails.author?.name,
273
+ url: info.videoDetails.video_url,
274
+ requestedBy: options.requestedBy,
275
+ thumbnail: Util_1.Util.last(info.videoDetails.thumbnails)?.url,
276
+ views: parseInt(info.videoDetails.viewCount.replace(/[^0-9]/g, "")) || 0,
277
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(parseInt(info.videoDetails.lengthSeconds) * 1000)),
278
+ source: "youtube",
279
+ raw: info
280
+ });
281
+ return { playlist: null, tracks: [track] };
230
282
  }
231
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
232
- for (const [_, extractor] of this.extractors) {
233
- if (options.blockExtractor)
234
- break;
235
- if (!extractor.validate(query))
236
- continue;
237
- const data = yield extractor.handle(query);
238
- if (data && data.data.length) {
239
- const playlist = !data.playlist
240
- ? null
241
- : new Playlist_1.Playlist(this, Object.assign(Object.assign({}, data.playlist), { tracks: [] }));
242
- 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 })));
243
- if (playlist)
244
- playlist.tracks = tracks;
245
- return { playlist: playlist, tracks: tracks };
246
- }
283
+ case types_1.QueryType.YOUTUBE_SEARCH: {
284
+ const videos = await youtube_sr_1.default.search(query, {
285
+ type: "video"
286
+ }).catch(Util_1.Util.noop);
287
+ if (!videos)
288
+ return { playlist: null, tracks: [] };
289
+ const tracks = videos.map((m) => {
290
+ m.source = "youtube"; // eslint-disable-line @typescript-eslint/no-explicit-any
291
+ return new Track_1.default(this, {
292
+ title: m.title,
293
+ description: m.description,
294
+ author: m.channel?.name,
295
+ url: m.url,
296
+ requestedBy: options.requestedBy,
297
+ thumbnail: m.thumbnail?.displayThumbnailURL("maxresdefault"),
298
+ views: m.views,
299
+ duration: m.durationFormatted,
300
+ source: "youtube",
301
+ raw: m
302
+ });
303
+ });
304
+ return { playlist: null, tracks };
247
305
  }
248
- const qt = options.searchEngine === types_1.QueryType.AUTO ? QueryResolver_1.QueryResolver.resolve(query) : options.searchEngine;
249
- switch (qt) {
250
- case types_1.QueryType.YOUTUBE_VIDEO: {
251
- const info = yield (0, ytdl_core_1.getInfo)(query, this.options.ytdlOptions).catch(Util_1.Util.noop);
252
- if (!info)
253
- return { playlist: null, tracks: [] };
306
+ case types_1.QueryType.SOUNDCLOUD_TRACK:
307
+ case types_1.QueryType.SOUNDCLOUD_SEARCH: {
308
+ const result = QueryResolver_1.QueryResolver.resolve(query) === types_1.QueryType.SOUNDCLOUD_TRACK ? [{ url: query }] : await soundcloud.search(query, "track").catch(() => []);
309
+ if (!result || !result.length)
310
+ return { playlist: null, tracks: [] };
311
+ const res = [];
312
+ for (const r of result) {
313
+ const trackInfo = await soundcloud.getSongInfo(r.url).catch(Util_1.Util.noop);
314
+ if (!trackInfo)
315
+ continue;
254
316
  const track = new Track_1.default(this, {
255
- title: info.videoDetails.title,
256
- description: info.videoDetails.description,
257
- author: (_a = info.videoDetails.author) === null || _a === void 0 ? void 0 : _a.name,
258
- url: info.videoDetails.video_url,
317
+ title: trackInfo.title,
318
+ url: trackInfo.url,
319
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(trackInfo.duration)),
320
+ description: trackInfo.description,
321
+ thumbnail: trackInfo.thumbnail,
322
+ views: trackInfo.playCount,
323
+ author: trackInfo.author.name,
259
324
  requestedBy: options.requestedBy,
260
- thumbnail: (_b = Util_1.Util.last(info.videoDetails.thumbnails)) === null || _b === void 0 ? void 0 : _b.url,
261
- views: parseInt(info.videoDetails.viewCount.replace(/[^0-9]/g, "")) || 0,
262
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(parseInt(info.videoDetails.lengthSeconds) * 1000)),
263
- source: "youtube",
264
- raw: info
325
+ source: "soundcloud",
326
+ engine: trackInfo
265
327
  });
266
- return { playlist: null, tracks: [track] };
328
+ res.push(track);
267
329
  }
268
- case types_1.QueryType.YOUTUBE_SEARCH: {
269
- const videos = yield youtube_sr_1.default.search(query, {
270
- type: "video"
271
- }).catch(Util_1.Util.noop);
272
- if (!videos)
273
- return { playlist: null, tracks: [] };
274
- const tracks = videos.map((m) => {
275
- var _a, _b;
276
- m.source = "youtube"; // eslint-disable-line @typescript-eslint/no-explicit-any
277
- return new Track_1.default(this, {
278
- title: m.title,
279
- description: m.description,
280
- author: (_a = m.channel) === null || _a === void 0 ? void 0 : _a.name,
281
- url: m.url,
330
+ return { playlist: null, tracks: res };
331
+ }
332
+ case types_1.QueryType.SPOTIFY_SONG: {
333
+ const spotifyData = await (0, spotify_url_info_1.default)(await Util_1.Util.getFetch())
334
+ .getData(query)
335
+ .catch(Util_1.Util.noop);
336
+ if (!spotifyData)
337
+ return { playlist: null, tracks: [] };
338
+ const spotifyTrack = new Track_1.default(this, {
339
+ title: spotifyData.name,
340
+ description: spotifyData.description ?? "",
341
+ author: spotifyData.artists[0]?.name ?? "Unknown Artist",
342
+ url: spotifyData.external_urls?.spotify ?? query,
343
+ thumbnail: spotifyData.album?.images[0]?.url ?? spotifyData.preview_url?.length
344
+ ? `https://i.scdn.co/image/${spotifyData.preview_url?.split("?cid=")[1]}`
345
+ : "https://www.scdn.co/i/_global/twitter_card-default.jpg",
346
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(spotifyData.duration_ms)),
347
+ views: 0,
348
+ requestedBy: options.requestedBy,
349
+ source: "spotify"
350
+ });
351
+ return { playlist: null, tracks: [spotifyTrack] };
352
+ }
353
+ case types_1.QueryType.SPOTIFY_PLAYLIST:
354
+ case types_1.QueryType.SPOTIFY_ALBUM: {
355
+ const spotifyPlaylist = await (0, spotify_url_info_1.default)(await Util_1.Util.getFetch())
356
+ .getData(query)
357
+ .catch(Util_1.Util.noop);
358
+ if (!spotifyPlaylist)
359
+ return { playlist: null, tracks: [] };
360
+ const playlist = new Playlist_1.Playlist(this, {
361
+ title: spotifyPlaylist.name ?? spotifyPlaylist.title,
362
+ description: spotifyPlaylist.description ?? "",
363
+ thumbnail: spotifyPlaylist.images[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
364
+ type: spotifyPlaylist.type,
365
+ source: "spotify",
366
+ author: spotifyPlaylist.type !== "playlist"
367
+ ? {
368
+ name: spotifyPlaylist.artists[0]?.name ?? "Unknown Artist",
369
+ url: spotifyPlaylist.artists[0]?.external_urls?.spotify ?? null
370
+ }
371
+ : {
372
+ name: spotifyPlaylist.owner?.display_name ?? spotifyPlaylist.owner?.id ?? "Unknown Artist",
373
+ url: spotifyPlaylist.owner?.external_urls?.spotify ?? null
374
+ },
375
+ tracks: [],
376
+ id: spotifyPlaylist.id,
377
+ url: spotifyPlaylist.external_urls?.spotify ?? query,
378
+ rawPlaylist: spotifyPlaylist
379
+ });
380
+ if (spotifyPlaylist.type !== "playlist") {
381
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
382
+ playlist.tracks = spotifyPlaylist.tracks.items.map((m) => {
383
+ const data = new Track_1.default(this, {
384
+ title: m.name ?? "",
385
+ description: m.description ?? "",
386
+ author: m.artists[0]?.name ?? "Unknown Artist",
387
+ url: m.external_urls?.spotify ?? query,
388
+ thumbnail: spotifyPlaylist.images[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
389
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration_ms)),
390
+ views: 0,
282
391
  requestedBy: options.requestedBy,
283
- thumbnail: (_b = m.thumbnail) === null || _b === void 0 ? void 0 : _b.displayThumbnailURL("maxresdefault"),
284
- views: m.views,
285
- duration: m.durationFormatted,
286
- source: "youtube",
287
- raw: m
392
+ playlist,
393
+ source: "spotify"
288
394
  });
395
+ return data;
289
396
  });
290
- return { playlist: null, tracks };
291
397
  }
292
- case types_1.QueryType.SOUNDCLOUD_TRACK:
293
- case types_1.QueryType.SOUNDCLOUD_SEARCH: {
294
- const result = QueryResolver_1.QueryResolver.resolve(query) === types_1.QueryType.SOUNDCLOUD_TRACK ? [{ url: query }] : yield soundcloud.search(query, "track").catch(() => []);
295
- if (!result || !result.length)
296
- return { playlist: null, tracks: [] };
297
- const res = [];
298
- for (const r of result) {
299
- const trackInfo = yield soundcloud.getSongInfo(r.url).catch(Util_1.Util.noop);
300
- if (!trackInfo)
301
- continue;
302
- const track = new Track_1.default(this, {
303
- title: trackInfo.title,
304
- url: trackInfo.url,
305
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(trackInfo.duration)),
306
- description: trackInfo.description,
307
- thumbnail: trackInfo.thumbnail,
308
- views: trackInfo.playCount,
309
- author: trackInfo.author.name,
398
+ else {
399
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
400
+ playlist.tracks = spotifyPlaylist.tracks.items.map((m) => {
401
+ const data = new Track_1.default(this, {
402
+ title: m.track.name ?? "",
403
+ description: m.track.description ?? "",
404
+ author: m.track.artists[0]?.name ?? "Unknown Artist",
405
+ url: m.track.external_urls?.spotify ?? query,
406
+ thumbnail: m.track.album?.images[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
407
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.track.duration_ms)),
408
+ views: 0,
310
409
  requestedBy: options.requestedBy,
311
- source: "soundcloud",
312
- engine: trackInfo
410
+ playlist,
411
+ source: "spotify"
313
412
  });
314
- res.push(track);
315
- }
316
- return { playlist: null, tracks: res };
317
- }
318
- case types_1.QueryType.SPOTIFY_SONG: {
319
- const spotifyData = yield spotify_url_info_1.default.getData(query).catch(Util_1.Util.noop);
320
- if (!spotifyData)
321
- return { playlist: null, tracks: [] };
322
- const spotifyTrack = new Track_1.default(this, {
323
- title: spotifyData.name,
324
- description: (_c = spotifyData.description) !== null && _c !== void 0 ? _c : "",
325
- author: (_e = (_d = spotifyData.artists[0]) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : "Unknown Artist",
326
- url: (_g = (_f = spotifyData.external_urls) === null || _f === void 0 ? void 0 : _f.spotify) !== null && _g !== void 0 ? _g : query,
327
- 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)
328
- ? `https://i.scdn.co/image/${(_m = spotifyData.preview_url) === null || _m === void 0 ? void 0 : _m.split("?cid=")[1]}`
329
- : "https://www.scdn.co/i/_global/twitter_card-default.jpg",
330
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(spotifyData.duration_ms)),
331
- views: 0,
332
- requestedBy: options.requestedBy,
333
- source: "spotify"
334
- });
335
- return { playlist: null, tracks: [spotifyTrack] };
336
- }
337
- case types_1.QueryType.SPOTIFY_PLAYLIST:
338
- case types_1.QueryType.SPOTIFY_ALBUM: {
339
- const spotifyPlaylist = yield spotify_url_info_1.default.getData(query).catch(Util_1.Util.noop);
340
- if (!spotifyPlaylist)
341
- return { playlist: null, tracks: [] };
342
- const playlist = new Playlist_1.Playlist(this, {
343
- title: (_o = spotifyPlaylist.name) !== null && _o !== void 0 ? _o : spotifyPlaylist.title,
344
- description: (_p = spotifyPlaylist.description) !== null && _p !== void 0 ? _p : "",
345
- 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",
346
- type: spotifyPlaylist.type,
347
- source: "spotify",
348
- author: spotifyPlaylist.type !== "playlist"
349
- ? {
350
- name: (_t = (_s = spotifyPlaylist.artists[0]) === null || _s === void 0 ? void 0 : _s.name) !== null && _t !== void 0 ? _t : "Unknown Artist",
351
- 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
352
- }
353
- : {
354
- 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",
355
- 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
356
- },
357
- tracks: [],
358
- id: spotifyPlaylist.id,
359
- url: (_5 = (_4 = spotifyPlaylist.external_urls) === null || _4 === void 0 ? void 0 : _4.spotify) !== null && _5 !== void 0 ? _5 : query,
360
- rawPlaylist: spotifyPlaylist
413
+ return data;
361
414
  });
362
- if (spotifyPlaylist.type !== "playlist") {
363
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
364
- playlist.tracks = spotifyPlaylist.tracks.items.map((m) => {
365
- var _a, _b, _c, _d, _e, _f, _g, _h;
366
- const data = new Track_1.default(this, {
367
- title: (_a = m.name) !== null && _a !== void 0 ? _a : "",
368
- description: (_b = m.description) !== null && _b !== void 0 ? _b : "",
369
- author: (_d = (_c = m.artists[0]) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : "Unknown Artist",
370
- url: (_f = (_e = m.external_urls) === null || _e === void 0 ? void 0 : _e.spotify) !== null && _f !== void 0 ? _f : query,
371
- 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",
372
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration_ms)),
373
- views: 0,
374
- requestedBy: options.requestedBy,
375
- playlist,
376
- source: "spotify"
377
- });
378
- return data;
379
- });
380
- }
381
- else {
382
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
383
- playlist.tracks = spotifyPlaylist.tracks.items.map((m) => {
384
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
385
- const data = new Track_1.default(this, {
386
- title: (_a = m.track.name) !== null && _a !== void 0 ? _a : "",
387
- description: (_b = m.track.description) !== null && _b !== void 0 ? _b : "",
388
- author: (_d = (_c = m.track.artists[0]) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : "Unknown Artist",
389
- url: (_f = (_e = m.track.external_urls) === null || _e === void 0 ? void 0 : _e.spotify) !== null && _f !== void 0 ? _f : query,
390
- 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",
391
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.track.duration_ms)),
392
- views: 0,
393
- requestedBy: options.requestedBy,
394
- playlist,
395
- source: "spotify"
396
- });
397
- return data;
398
- });
399
- }
400
- return { playlist: playlist, tracks: playlist.tracks };
401
415
  }
402
- case types_1.QueryType.SOUNDCLOUD_PLAYLIST: {
403
- const data = yield soundcloud.getPlaylist(query).catch(Util_1.Util.noop);
404
- if (!data)
405
- return { playlist: null, tracks: [] };
406
- const res = new Playlist_1.Playlist(this, {
407
- title: data.title,
408
- description: (_6 = data.description) !== null && _6 !== void 0 ? _6 : "",
409
- thumbnail: (_7 = data.thumbnail) !== null && _7 !== void 0 ? _7 : "https://soundcloud.com/pwa-icon-192.png",
410
- type: "playlist",
416
+ return { playlist: playlist, tracks: playlist.tracks };
417
+ }
418
+ case types_1.QueryType.SOUNDCLOUD_PLAYLIST: {
419
+ const data = await soundcloud.getPlaylist(query).catch(Util_1.Util.noop);
420
+ if (!data)
421
+ return { playlist: null, tracks: [] };
422
+ const res = new Playlist_1.Playlist(this, {
423
+ title: data.title,
424
+ description: data.description ?? "",
425
+ thumbnail: data.thumbnail ?? "https://soundcloud.com/pwa-icon-192.png",
426
+ type: "playlist",
427
+ source: "soundcloud",
428
+ author: {
429
+ name: data.author?.name ?? data.author?.username ?? "Unknown Artist",
430
+ url: data.author?.profile
431
+ },
432
+ tracks: [],
433
+ id: `${data.id}`,
434
+ url: data.url,
435
+ rawPlaylist: data
436
+ });
437
+ for (const song of data.tracks) {
438
+ const track = new Track_1.default(this, {
439
+ title: song.title,
440
+ description: song.description ?? "",
441
+ author: song.author?.username ?? song.author?.name ?? "Unknown Artist",
442
+ url: song.url,
443
+ thumbnail: song.thumbnail,
444
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(song.duration)),
445
+ views: song.playCount ?? 0,
446
+ requestedBy: options.requestedBy,
447
+ playlist: res,
411
448
  source: "soundcloud",
412
- author: {
413
- 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",
414
- url: (_12 = data.author) === null || _12 === void 0 ? void 0 : _12.profile
415
- },
416
- tracks: [],
417
- id: `${data.id}`,
418
- url: data.url,
419
- rawPlaylist: data
449
+ engine: song
420
450
  });
421
- for (const song of data.tracks) {
422
- const track = new Track_1.default(this, {
423
- title: song.title,
424
- description: (_13 = song.description) !== null && _13 !== void 0 ? _13 : "",
425
- 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",
426
- url: song.url,
427
- thumbnail: song.thumbnail,
428
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(song.duration)),
429
- views: (_18 = song.playCount) !== null && _18 !== void 0 ? _18 : 0,
430
- requestedBy: options.requestedBy,
431
- playlist: res,
432
- source: "soundcloud",
433
- engine: song
434
- });
435
- res.tracks.push(track);
436
- }
437
- return { playlist: res, tracks: res.tracks };
451
+ res.tracks.push(track);
438
452
  }
439
- case types_1.QueryType.YOUTUBE_PLAYLIST: {
440
- const ytpl = yield youtube_sr_1.default.getPlaylist(query).catch(Util_1.Util.noop);
441
- if (!ytpl)
442
- return { playlist: null, tracks: [] };
443
- yield ytpl.fetch().catch(Util_1.Util.noop);
444
- const playlist = new Playlist_1.Playlist(this, {
445
- title: ytpl.title,
446
- thumbnail: ytpl.thumbnail,
447
- description: "",
448
- type: "playlist",
449
- source: "youtube",
450
- author: {
451
- name: ytpl.channel.name,
452
- url: ytpl.channel.url
453
- },
454
- tracks: [],
455
- id: ytpl.id,
456
- url: ytpl.url,
457
- rawPlaylist: ytpl
458
- });
459
- playlist.tracks = ytpl.videos.map((video) => {
460
- var _a;
461
- return new Track_1.default(this, {
462
- title: video.title,
463
- description: video.description,
464
- author: (_a = video.channel) === null || _a === void 0 ? void 0 : _a.name,
465
- url: video.url,
466
- requestedBy: options.requestedBy,
467
- thumbnail: video.thumbnail.url,
468
- views: video.views,
469
- duration: video.durationFormatted,
470
- raw: video,
471
- playlist: playlist,
472
- source: "youtube"
473
- });
474
- });
475
- return { playlist: playlist, tracks: playlist.tracks };
476
- }
477
- default:
453
+ return { playlist: res, tracks: res.tracks };
454
+ }
455
+ case types_1.QueryType.YOUTUBE_PLAYLIST: {
456
+ const ytpl = await youtube_sr_1.default.getPlaylist(query).catch(Util_1.Util.noop);
457
+ if (!ytpl)
478
458
  return { playlist: null, tracks: [] };
459
+ await ytpl.fetch().catch(Util_1.Util.noop);
460
+ const playlist = new Playlist_1.Playlist(this, {
461
+ title: ytpl.title,
462
+ thumbnail: ytpl.thumbnail,
463
+ description: "",
464
+ type: "playlist",
465
+ source: "youtube",
466
+ author: {
467
+ name: ytpl.channel.name,
468
+ url: ytpl.channel.url
469
+ },
470
+ tracks: [],
471
+ id: ytpl.id,
472
+ url: ytpl.url,
473
+ rawPlaylist: ytpl
474
+ });
475
+ playlist.tracks = ytpl.videos.map((video) => new Track_1.default(this, {
476
+ title: video.title,
477
+ description: video.description,
478
+ author: video.channel?.name,
479
+ url: video.url,
480
+ requestedBy: options.requestedBy,
481
+ thumbnail: video.thumbnail.url,
482
+ views: video.views,
483
+ duration: video.durationFormatted,
484
+ raw: video,
485
+ playlist: playlist,
486
+ source: "youtube"
487
+ }));
488
+ return { playlist: playlist, tracks: playlist.tracks };
479
489
  }
480
- });
490
+ default:
491
+ return { playlist: null, tracks: [] };
492
+ }
481
493
  }
482
494
  /**
483
495
  * Registers extractor