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