discord-player 5.4.0 → 5.4.1-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 DELETED
@@ -1,623 +0,0 @@
1
- "use strict";
2
- var _Player_lastLatency;
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.Player = void 0;
5
- const tslib_1 = require("tslib");
6
- const discord_js_1 = require("discord.js");
7
- const tiny_typed_emitter_1 = require("tiny-typed-emitter");
8
- const Queue_1 = require("./Structures/Queue");
9
- const VoiceUtils_1 = require("./VoiceInterface/VoiceUtils");
10
- const types_1 = require("./types/types");
11
- const Track_1 = tslib_1.__importDefault(require("./Structures/Track"));
12
- const QueryResolver_1 = require("./utils/QueryResolver");
13
- const youtube_sr_1 = tslib_1.__importDefault(require("youtube-sr"));
14
- const Util_1 = require("./utils/Util");
15
- const spotify_url_info_1 = tslib_1.__importDefault(require("spotify-url-info"));
16
- const PlayerError_1 = require("./Structures/PlayerError");
17
- const ytdl_core_1 = require("ytdl-core");
18
- const soundcloud_scraper_1 = require("soundcloud-scraper");
19
- const Playlist_1 = require("./Structures/Playlist");
20
- const ExtractorModel_1 = require("./Structures/ExtractorModel");
21
- const voice_1 = require("@discordjs/voice");
22
- const soundcloud = new soundcloud_scraper_1.Client();
23
- class Player extends tiny_typed_emitter_1.TypedEmitter {
24
- /**
25
- * Creates new Discord Player
26
- * @param {Client} client The Discord Client
27
- * @param {PlayerInitOptions} [options] The player init options
28
- */
29
- constructor(client, options = {}) {
30
- super();
31
- this.options = {
32
- autoRegisterExtractor: true,
33
- ytdlOptions: {
34
- highWaterMark: 1 << 25
35
- },
36
- connectionTimeout: 20000,
37
- smoothVolume: true,
38
- lagMonitor: 30000
39
- };
40
- this.queues = new discord_js_1.Collection();
41
- this.voiceUtils = new VoiceUtils_1.VoiceUtils();
42
- this.extractors = new discord_js_1.Collection();
43
- this.requiredEvents = ["error", "connectionError"];
44
- _Player_lastLatency.set(this, -1);
45
- /**
46
- * The discord.js client
47
- * @type {Client}
48
- */
49
- this.client = client;
50
- if (this.client?.options?.intents && !new discord_js_1.IntentsBitField(this.client?.options?.intents).has(discord_js_1.IntentsBitField.Flags.GuildVoiceStates)) {
51
- throw new PlayerError_1.PlayerError('client is missing "GuildVoiceStates" intent');
52
- }
53
- /**
54
- * The extractors collection
55
- * @type {ExtractorModel}
56
- */
57
- this.options = Object.assign(this.options, options);
58
- this.client.on("voiceStateUpdate", this._handleVoiceState.bind(this));
59
- if (this.options?.autoRegisterExtractor) {
60
- let nv; // eslint-disable-line @typescript-eslint/no-explicit-any
61
- if ((nv = Util_1.Util.require("@discord-player/extractor"))) {
62
- ["Attachment", "Facebook", "Reverbnation", "Vimeo"].forEach((ext) => void this.use(ext, nv[ext]));
63
- }
64
- }
65
- if (typeof this.options.lagMonitor === "number" && this.options.lagMonitor > 0) {
66
- setInterval(() => {
67
- const start = performance.now();
68
- setTimeout(() => {
69
- tslib_1.__classPrivateFieldSet(this, _Player_lastLatency, performance.now() - start, "f");
70
- }, 0).unref();
71
- }, this.options.lagMonitor).unref();
72
- }
73
- }
74
- /**
75
- * Event loop lag
76
- * @type {number}
77
- */
78
- get eventLoopLag() {
79
- return tslib_1.__classPrivateFieldGet(this, _Player_lastLatency, "f");
80
- }
81
- /**
82
- * Generates statistics
83
- */
84
- generateStatistics() {
85
- return this.queues.map((m) => m.generateStatistics());
86
- }
87
- /**
88
- * Handles voice state update
89
- * @param {VoiceState} oldState The old voice state
90
- * @param {VoiceState} newState The new voice state
91
- * @returns {void}
92
- * @private
93
- */
94
- _handleVoiceState(oldState, newState) {
95
- const queue = this.getQueue(oldState.guild.id);
96
- if (!queue || !queue.connection)
97
- return;
98
- this.emit("voiceStateUpdate", queue, oldState, newState);
99
- if (oldState.channelId && !newState.channelId && newState.member.id === newState.guild.members.me.id) {
100
- try {
101
- queue.destroy();
102
- }
103
- catch {
104
- /* noop */
105
- }
106
- return void this.emit("botDisconnect", queue);
107
- }
108
- if (!oldState.channelId && newState.channelId && newState.member.id === newState.guild.members.me.id) {
109
- if (oldState.serverMute !== newState.serverMute) {
110
- // state.serverMute can be null
111
- queue.setPaused(!!newState.serverMute);
112
- }
113
- else if (oldState.suppress !== newState.suppress) {
114
- // state.suppress can be null
115
- queue.setPaused(!!newState.suppress);
116
- if (newState.suppress) {
117
- newState.guild.members.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
118
- }
119
- }
120
- }
121
- if (!newState.channelId && oldState.channelId === queue.connection.channel.id) {
122
- if (!Util_1.Util.isVoiceEmpty(queue.connection.channel))
123
- return;
124
- const timeout = setTimeout(() => {
125
- if (!Util_1.Util.isVoiceEmpty(queue.connection.channel))
126
- return;
127
- if (!this.queues.has(queue.guild.id))
128
- return;
129
- if (queue.options.leaveOnEmpty)
130
- queue.destroy(true);
131
- this.emit("channelEmpty", queue);
132
- }, queue.options.leaveOnEmptyCooldown || 0).unref();
133
- queue._cooldownsTimeout.set(`empty_${oldState.guild.id}`, timeout);
134
- }
135
- if (newState.channelId && newState.channelId === queue.connection.channel.id) {
136
- const emptyTimeout = queue._cooldownsTimeout.get(`empty_${oldState.guild.id}`);
137
- const channelEmpty = Util_1.Util.isVoiceEmpty(queue.connection.channel);
138
- if (!channelEmpty && emptyTimeout) {
139
- clearTimeout(emptyTimeout);
140
- queue._cooldownsTimeout.delete(`empty_${oldState.guild.id}`);
141
- }
142
- }
143
- if (oldState.channelId && newState.channelId && oldState.channelId !== newState.channelId) {
144
- if (newState.member.id === newState.guild.members.me.id) {
145
- if (queue.connection && newState.member.id === newState.guild.members.me.id)
146
- queue.connection.channel = newState.channel;
147
- const emptyTimeout = queue._cooldownsTimeout.get(`empty_${oldState.guild.id}`);
148
- const channelEmpty = Util_1.Util.isVoiceEmpty(queue.connection.channel);
149
- if (!channelEmpty && emptyTimeout) {
150
- clearTimeout(emptyTimeout);
151
- queue._cooldownsTimeout.delete(`empty_${oldState.guild.id}`);
152
- }
153
- else {
154
- const timeout = setTimeout(() => {
155
- if (queue.connection && !Util_1.Util.isVoiceEmpty(queue.connection.channel))
156
- return;
157
- if (!this.queues.has(queue.guild.id))
158
- return;
159
- if (queue.options.leaveOnEmpty)
160
- queue.destroy(true);
161
- this.emit("channelEmpty", queue);
162
- }, queue.options.leaveOnEmptyCooldown || 0).unref();
163
- queue._cooldownsTimeout.set(`empty_${oldState.guild.id}`, timeout);
164
- }
165
- }
166
- else {
167
- if (newState.channelId !== queue.connection.channel.id) {
168
- if (!Util_1.Util.isVoiceEmpty(queue.connection.channel))
169
- return;
170
- if (queue._cooldownsTimeout.has(`empty_${oldState.guild.id}`))
171
- return;
172
- const timeout = setTimeout(() => {
173
- if (!Util_1.Util.isVoiceEmpty(queue.connection.channel))
174
- return;
175
- if (!this.queues.has(queue.guild.id))
176
- return;
177
- if (queue.options.leaveOnEmpty)
178
- queue.destroy(true);
179
- this.emit("channelEmpty", queue);
180
- }, queue.options.leaveOnEmptyCooldown || 0).unref();
181
- queue._cooldownsTimeout.set(`empty_${oldState.guild.id}`, timeout);
182
- }
183
- else {
184
- const emptyTimeout = queue._cooldownsTimeout.get(`empty_${oldState.guild.id}`);
185
- const channelEmpty = Util_1.Util.isVoiceEmpty(queue.connection.channel);
186
- if (!channelEmpty && emptyTimeout) {
187
- clearTimeout(emptyTimeout);
188
- queue._cooldownsTimeout.delete(`empty_${oldState.guild.id}`);
189
- }
190
- }
191
- }
192
- }
193
- }
194
- /**
195
- * Creates a queue for a guild if not available, else returns existing queue
196
- * @param {GuildResolvable} guild The guild
197
- * @param {PlayerOptions} queueInitOptions Queue init options
198
- * @returns {Queue}
199
- */
200
- createQueue(guild, queueInitOptions = {}) {
201
- guild = this.client.guilds.resolve(guild);
202
- if (!guild)
203
- throw new PlayerError_1.PlayerError("Unknown Guild", PlayerError_1.ErrorStatusCode.UNKNOWN_GUILD);
204
- if (this.queues.has(guild.id))
205
- return this.queues.get(guild.id);
206
- const _meta = queueInitOptions.metadata;
207
- delete queueInitOptions["metadata"];
208
- queueInitOptions.volumeSmoothness ?? (queueInitOptions.volumeSmoothness = this.options.smoothVolume ? 0.08 : 0);
209
- queueInitOptions.ytdlOptions ?? (queueInitOptions.ytdlOptions = this.options.ytdlOptions);
210
- const queue = new Queue_1.Queue(this, guild, queueInitOptions);
211
- queue.metadata = _meta;
212
- this.queues.set(guild.id, queue);
213
- return queue;
214
- }
215
- /**
216
- * Returns the queue if available
217
- * @param {GuildResolvable} guild The guild id
218
- * @returns {Queue | undefined}
219
- */
220
- getQueue(guild) {
221
- guild = this.client.guilds.resolve(guild);
222
- if (!guild)
223
- throw new PlayerError_1.PlayerError("Unknown Guild", PlayerError_1.ErrorStatusCode.UNKNOWN_GUILD);
224
- return this.queues.get(guild.id);
225
- }
226
- /**
227
- * Deletes a queue and returns deleted queue object
228
- * @param {GuildResolvable} guild The guild id to remove
229
- * @returns {Queue}
230
- */
231
- deleteQueue(guild) {
232
- guild = this.client.guilds.resolve(guild);
233
- if (!guild)
234
- throw new PlayerError_1.PlayerError("Unknown Guild", PlayerError_1.ErrorStatusCode.UNKNOWN_GUILD);
235
- const prev = this.getQueue(guild);
236
- try {
237
- prev.destroy();
238
- }
239
- catch { } // eslint-disable-line no-empty
240
- this.queues.delete(guild.id);
241
- return prev;
242
- }
243
- /**
244
- * @typedef {object} PlayerSearchResult
245
- * @property {Playlist} [playlist] The playlist (if any)
246
- * @property {Track[]} tracks The tracks
247
- */
248
- /**
249
- * Search tracks
250
- * @param {string|Track} query The search query
251
- * @param {SearchOptions} options The search options
252
- * @returns {Promise<PlayerSearchResult>}
253
- */
254
- async search(query, options) {
255
- if (query instanceof Track_1.default)
256
- return { playlist: query.playlist || null, tracks: [query] };
257
- if (!options)
258
- throw new PlayerError_1.PlayerError("DiscordPlayer#search needs search options!", PlayerError_1.ErrorStatusCode.INVALID_ARG_TYPE);
259
- options.requestedBy = this.client.users.resolve(options.requestedBy);
260
- if (!("searchEngine" in options))
261
- options.searchEngine = types_1.QueryType.AUTO;
262
- if (typeof options.searchEngine === "string" && this.extractors.has(options.searchEngine)) {
263
- const extractor = this.extractors.get(options.searchEngine);
264
- if (!extractor.validate(query))
265
- return { playlist: null, tracks: [] };
266
- const data = await extractor.handle(query);
267
- if (data && data.data.length) {
268
- const playlist = !data.playlist
269
- ? null
270
- : new Playlist_1.Playlist(this, {
271
- ...data.playlist,
272
- tracks: []
273
- });
274
- const tracks = data.data.map((m) => new Track_1.default(this, {
275
- ...m,
276
- requestedBy: options.requestedBy,
277
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration)),
278
- playlist: playlist
279
- }));
280
- if (playlist)
281
- playlist.tracks = tracks;
282
- return { playlist: playlist, tracks: tracks };
283
- }
284
- }
285
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
286
- for (const [_, extractor] of this.extractors) {
287
- if (options.blockExtractor)
288
- break;
289
- if (!extractor.validate(query))
290
- continue;
291
- const data = await extractor.handle(query);
292
- if (data && data.data.length) {
293
- const playlist = !data.playlist
294
- ? null
295
- : new Playlist_1.Playlist(this, {
296
- ...data.playlist,
297
- tracks: []
298
- });
299
- const tracks = data.data.map((m) => new Track_1.default(this, {
300
- ...m,
301
- requestedBy: options.requestedBy,
302
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration)),
303
- playlist: playlist
304
- }));
305
- if (playlist)
306
- playlist.tracks = tracks;
307
- return { playlist: playlist, tracks: tracks };
308
- }
309
- }
310
- const qt = options.searchEngine === types_1.QueryType.AUTO ? QueryResolver_1.QueryResolver.resolve(query) : options.searchEngine;
311
- switch (qt) {
312
- case types_1.QueryType.YOUTUBE_VIDEO: {
313
- const info = await (0, ytdl_core_1.getInfo)(query, this.options.ytdlOptions).catch(Util_1.Util.noop);
314
- if (!info)
315
- return { playlist: null, tracks: [] };
316
- const track = new Track_1.default(this, {
317
- title: info.videoDetails.title,
318
- description: info.videoDetails.description,
319
- author: info.videoDetails.author?.name,
320
- url: info.videoDetails.video_url,
321
- requestedBy: options.requestedBy,
322
- thumbnail: Util_1.Util.last(info.videoDetails.thumbnails)?.url,
323
- views: parseInt(info.videoDetails.viewCount.replace(/[^0-9]/g, "")) || 0,
324
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(parseInt(info.videoDetails.lengthSeconds) * 1000)),
325
- source: "youtube",
326
- raw: info
327
- });
328
- return { playlist: null, tracks: [track] };
329
- }
330
- case types_1.QueryType.YOUTUBE_SEARCH: {
331
- const videos = await youtube_sr_1.default.search(query, {
332
- type: "video"
333
- }).catch(Util_1.Util.noop);
334
- if (!videos)
335
- return { playlist: null, tracks: [] };
336
- const tracks = videos.map((m) => {
337
- m.source = "youtube"; // eslint-disable-line @typescript-eslint/no-explicit-any
338
- return new Track_1.default(this, {
339
- title: m.title,
340
- description: m.description,
341
- author: m.channel?.name,
342
- url: m.url,
343
- requestedBy: options.requestedBy,
344
- thumbnail: m.thumbnail?.displayThumbnailURL("maxresdefault"),
345
- views: m.views,
346
- duration: m.durationFormatted,
347
- source: "youtube",
348
- raw: m
349
- });
350
- });
351
- return { playlist: null, tracks };
352
- }
353
- case types_1.QueryType.SOUNDCLOUD_TRACK:
354
- case types_1.QueryType.SOUNDCLOUD_SEARCH: {
355
- const result = QueryResolver_1.QueryResolver.resolve(query) === types_1.QueryType.SOUNDCLOUD_TRACK ? [{ url: query }] : await soundcloud.search(query, "track").catch(() => []);
356
- if (!result || !result.length)
357
- return { playlist: null, tracks: [] };
358
- const res = [];
359
- for (const r of result) {
360
- const trackInfo = await soundcloud.getSongInfo(r.url).catch(Util_1.Util.noop);
361
- if (!trackInfo)
362
- continue;
363
- const track = new Track_1.default(this, {
364
- title: trackInfo.title,
365
- url: trackInfo.url,
366
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(trackInfo.duration)),
367
- description: trackInfo.description,
368
- thumbnail: trackInfo.thumbnail,
369
- views: trackInfo.playCount,
370
- author: trackInfo.author.name,
371
- requestedBy: options.requestedBy,
372
- source: "soundcloud",
373
- engine: trackInfo
374
- });
375
- res.push(track);
376
- }
377
- return { playlist: null, tracks: res };
378
- }
379
- case types_1.QueryType.SPOTIFY_SONG: {
380
- const spotifyData = await (0, spotify_url_info_1.default)(await Util_1.Util.getFetch())
381
- .getData(query)
382
- .catch(Util_1.Util.noop);
383
- if (!spotifyData)
384
- return { playlist: null, tracks: [] };
385
- const spotifyTrack = new Track_1.default(this, {
386
- title: spotifyData.name,
387
- description: spotifyData.description ?? "",
388
- author: spotifyData.artists[0]?.name ?? "Unknown Artist",
389
- url: spotifyData.external_urls?.spotify ?? query,
390
- thumbnail: (spotifyData.coverArt?.sources?.[0]?.url ??
391
- spotifyData.album?.images[0]?.url ??
392
- (spotifyData.preview_url?.length && `https://i.scdn.co/image/${spotifyData.preview_url?.split("?cid=")[1]}`)) ||
393
- "https://www.scdn.co/i/_global/twitter_card-default.jpg",
394
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(spotifyData.duration_ms ?? spotifyData.duration ?? spotifyData.maxDuration)),
395
- views: 0,
396
- requestedBy: options.requestedBy,
397
- source: "spotify"
398
- });
399
- return { playlist: null, tracks: [spotifyTrack] };
400
- }
401
- case types_1.QueryType.SPOTIFY_PLAYLIST:
402
- case types_1.QueryType.SPOTIFY_ALBUM: {
403
- const spotifyPlaylist = await (0, spotify_url_info_1.default)(await Util_1.Util.getFetch())
404
- .getData(query)
405
- .catch(Util_1.Util.noop);
406
- if (!spotifyPlaylist)
407
- return { playlist: null, tracks: [] };
408
- const playlist = new Playlist_1.Playlist(this, {
409
- title: spotifyPlaylist.name ?? spotifyPlaylist.title,
410
- description: spotifyPlaylist.description ?? "",
411
- thumbnail: spotifyPlaylist.coverArt?.sources?.[0]?.url ?? spotifyPlaylist.images[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
412
- type: spotifyPlaylist.type,
413
- source: "spotify",
414
- author: spotifyPlaylist.type !== "playlist"
415
- ? {
416
- name: spotifyPlaylist.artists[0]?.name ?? "Unknown Artist",
417
- url: spotifyPlaylist.artists[0]?.external_urls?.spotify ?? null
418
- }
419
- : {
420
- name: spotifyPlaylist.owner?.display_name ?? spotifyPlaylist.owner?.id ?? "Unknown Artist",
421
- url: spotifyPlaylist.owner?.external_urls?.spotify ?? null
422
- },
423
- tracks: [],
424
- id: spotifyPlaylist.id,
425
- url: spotifyPlaylist.external_urls?.spotify ?? query,
426
- rawPlaylist: spotifyPlaylist
427
- });
428
- if (spotifyPlaylist.type !== "playlist") {
429
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
430
- playlist.tracks = spotifyPlaylist.tracks.items.map((m) => {
431
- const data = new Track_1.default(this, {
432
- title: m.name ?? "",
433
- description: m.description ?? "",
434
- author: m.artists[0]?.name ?? "Unknown Artist",
435
- url: m.external_urls?.spotify ?? query,
436
- thumbnail: spotifyPlaylist.images[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
437
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration_ms)),
438
- views: 0,
439
- requestedBy: options.requestedBy,
440
- playlist,
441
- source: "spotify"
442
- });
443
- return data;
444
- });
445
- }
446
- else {
447
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
448
- playlist.tracks = spotifyPlaylist.trackList.map((m) => {
449
- const data = new Track_1.default(this, {
450
- title: m.title ?? "",
451
- description: m.description ?? "",
452
- author: m.subtitle ?? "Unknown Artist",
453
- url: m.external_urls?.spotify ?? query,
454
- thumbnail: m.album?.images?.[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
455
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.duration)),
456
- views: 0,
457
- requestedBy: options.requestedBy,
458
- playlist,
459
- source: "spotify"
460
- });
461
- return data;
462
- });
463
- }
464
- return { playlist: playlist, tracks: playlist.tracks };
465
- }
466
- case types_1.QueryType.SOUNDCLOUD_PLAYLIST: {
467
- const data = await soundcloud.getPlaylist(query).catch(Util_1.Util.noop);
468
- if (!data)
469
- return { playlist: null, tracks: [] };
470
- const res = new Playlist_1.Playlist(this, {
471
- title: data.title,
472
- description: data.description ?? "",
473
- thumbnail: data.thumbnail ?? "https://soundcloud.com/pwa-icon-192.png",
474
- type: "playlist",
475
- source: "soundcloud",
476
- author: {
477
- name: data.author?.name ?? data.author?.username ?? "Unknown Artist",
478
- url: data.author?.profile
479
- },
480
- tracks: [],
481
- id: `${data.id}`,
482
- url: data.url,
483
- rawPlaylist: data
484
- });
485
- for (const song of data.tracks) {
486
- const track = new Track_1.default(this, {
487
- title: song.title,
488
- description: song.description ?? "",
489
- author: song.author?.username ?? song.author?.name ?? "Unknown Artist",
490
- url: song.url,
491
- thumbnail: song.thumbnail,
492
- duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(song.duration)),
493
- views: song.playCount ?? 0,
494
- requestedBy: options.requestedBy,
495
- playlist: res,
496
- source: "soundcloud",
497
- engine: song
498
- });
499
- res.tracks.push(track);
500
- }
501
- return { playlist: res, tracks: res.tracks };
502
- }
503
- case types_1.QueryType.YOUTUBE_PLAYLIST: {
504
- const ytpl = await youtube_sr_1.default.getPlaylist(query).catch(Util_1.Util.noop);
505
- if (!ytpl)
506
- return { playlist: null, tracks: [] };
507
- await ytpl.fetch().catch(Util_1.Util.noop);
508
- const playlist = new Playlist_1.Playlist(this, {
509
- title: ytpl.title,
510
- thumbnail: ytpl.thumbnail,
511
- description: "",
512
- type: "playlist",
513
- source: "youtube",
514
- author: {
515
- name: ytpl.channel.name,
516
- url: ytpl.channel.url
517
- },
518
- tracks: [],
519
- id: ytpl.id,
520
- url: ytpl.url,
521
- rawPlaylist: ytpl
522
- });
523
- playlist.tracks = ytpl.videos.map((video) => new Track_1.default(this, {
524
- title: video.title,
525
- description: video.description,
526
- author: video.channel?.name,
527
- url: video.url,
528
- requestedBy: options.requestedBy,
529
- thumbnail: video.thumbnail.url,
530
- views: video.views,
531
- duration: video.durationFormatted,
532
- raw: video,
533
- playlist: playlist,
534
- source: "youtube"
535
- }));
536
- return { playlist: playlist, tracks: playlist.tracks };
537
- }
538
- default:
539
- return { playlist: null, tracks: [] };
540
- }
541
- }
542
- /**
543
- * Registers extractor
544
- * @param {string} extractorName The extractor name
545
- * @param {ExtractorModel|any} extractor The extractor object
546
- * @param {boolean} [force=false] Overwrite existing extractor with this name (if available)
547
- * @returns {ExtractorModel}
548
- */
549
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
550
- use(extractorName, extractor, force = false) {
551
- if (!extractorName)
552
- throw new PlayerError_1.PlayerError("Cannot use unknown extractor!", PlayerError_1.ErrorStatusCode.UNKNOWN_EXTRACTOR);
553
- if (this.extractors.has(extractorName) && !force)
554
- return this.extractors.get(extractorName);
555
- if (extractor instanceof ExtractorModel_1.ExtractorModel) {
556
- this.extractors.set(extractorName, extractor);
557
- return extractor;
558
- }
559
- for (const method of ["validate", "getInfo"]) {
560
- if (typeof extractor[method] !== "function")
561
- throw new PlayerError_1.PlayerError("Invalid extractor data!", PlayerError_1.ErrorStatusCode.INVALID_EXTRACTOR);
562
- }
563
- const model = new ExtractorModel_1.ExtractorModel(extractorName, extractor);
564
- this.extractors.set(model.name, model);
565
- return model;
566
- }
567
- /**
568
- * Removes registered extractor
569
- * @param {string} extractorName The extractor name
570
- * @returns {ExtractorModel}
571
- */
572
- unuse(extractorName) {
573
- if (!this.extractors.has(extractorName))
574
- throw new PlayerError_1.PlayerError(`Cannot find extractor "${extractorName}"`, PlayerError_1.ErrorStatusCode.UNKNOWN_EXTRACTOR);
575
- const prev = this.extractors.get(extractorName);
576
- this.extractors.delete(extractorName);
577
- return prev;
578
- }
579
- /**
580
- * Generates a report of the dependencies used by the `@discordjs/voice` module. Useful for debugging.
581
- * @returns {string}
582
- */
583
- scanDeps() {
584
- const line = "-".repeat(50);
585
- const depsReport = (0, voice_1.generateDependencyReport)();
586
- const extractorReport = this.extractors
587
- .map((m) => {
588
- return `${m.name} :: ${m.version || "0.1.0"}`;
589
- })
590
- .join("\n");
591
- return `${depsReport}\n${line}\nLoaded Extractors:\n${extractorReport || "None"}`;
592
- }
593
- emit(eventName, ...args) {
594
- if (this.requiredEvents.includes(eventName) && !super.eventNames().includes(eventName)) {
595
- // eslint-disable-next-line no-console
596
- console.error(...args);
597
- process.emitWarning(`[DiscordPlayerWarning] Unhandled "${eventName}" event! Events ${this.requiredEvents.map((m) => `"${m}"`).join(", ")} must have event listeners!`);
598
- return false;
599
- }
600
- else {
601
- return super.emit(eventName, ...args);
602
- }
603
- }
604
- /**
605
- * Resolves queue
606
- * @param {GuildResolvable|Queue} queueLike Queue like object
607
- * @returns {Queue}
608
- */
609
- resolveQueue(queueLike) {
610
- return this.getQueue(queueLike instanceof Queue_1.Queue ? queueLike.guild : queueLike);
611
- }
612
- *[(_Player_lastLatency = new WeakMap(), Symbol.iterator)]() {
613
- yield* Array.from(this.queues.values());
614
- }
615
- /**
616
- * Creates `Playlist` instance
617
- * @param data The data to initialize a playlist
618
- */
619
- createPlaylist(data) {
620
- return new Playlist_1.Playlist(this, data);
621
- }
622
- }
623
- exports.Player = Player;
@@ -1,65 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ExtractorModel = void 0;
4
- class ExtractorModel {
5
- /**
6
- * Model for raw Discord Player extractors
7
- * @param {string} extractorName Name of the extractor
8
- * @param {object} data Extractor object
9
- */
10
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
- constructor(extractorName, data) {
12
- /**
13
- * The extractor name
14
- * @type {string}
15
- */
16
- this.name = extractorName;
17
- /**
18
- * The raw model
19
- * @name ExtractorModel#_raw
20
- * @type {any}
21
- * @private
22
- */
23
- Object.defineProperty(this, "_raw", { value: data, configurable: false, writable: false, enumerable: false });
24
- }
25
- /**
26
- * Method to handle requests from `Player.play()`
27
- * @param {string} query Query to handle
28
- * @returns {Promise<ExtractorModelData>}
29
- */
30
- async handle(query) {
31
- const data = await this._raw.getInfo(query);
32
- if (!data)
33
- return null;
34
- return {
35
- playlist: data.playlist ?? null,
36
- data: data.info?.map((m) => ({
37
- title: m.title,
38
- duration: m.duration,
39
- thumbnail: m.thumbnail,
40
- engine: m.engine,
41
- views: m.views,
42
- author: m.author,
43
- description: m.description,
44
- url: m.url,
45
- source: m.source || "arbitrary"
46
- })) ?? []
47
- };
48
- }
49
- /**
50
- * Method used by Discord Player to validate query with this extractor
51
- * @param {string} query The query to validate
52
- * @returns {boolean}
53
- */
54
- validate(query) {
55
- return Boolean(this._raw.validate(query));
56
- }
57
- /**
58
- * The extractor version
59
- * @type {string}
60
- */
61
- get version() {
62
- return this._raw.version ?? "0.0.0";
63
- }
64
- }
65
- exports.ExtractorModel = ExtractorModel;