discord-player 5.3.0 → 5.3.2-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/Player.js CHANGED
@@ -32,7 +32,8 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
32
32
  ytdlOptions: {
33
33
  highWaterMark: 1 << 25
34
34
  },
35
- connectionTimeout: 20000
35
+ connectionTimeout: 20000,
36
+ smoothVolume: true
36
37
  };
37
38
  this.queues = new discord_js_1.Collection();
38
39
  this.voiceUtils = new VoiceUtils_1.VoiceUtils();
@@ -164,7 +165,7 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
164
165
  return this.queues.get(guild.id);
165
166
  const _meta = queueInitOptions.metadata;
166
167
  delete queueInitOptions["metadata"];
167
- queueInitOptions.volumeSmoothness ?? (queueInitOptions.volumeSmoothness = 0.08);
168
+ queueInitOptions.volumeSmoothness ?? (queueInitOptions.volumeSmoothness = this.options.smoothVolume ? 0.08 : 0);
168
169
  queueInitOptions.ytdlOptions ?? (queueInitOptions.ytdlOptions = this.options.ytdlOptions);
169
170
  const queue = new Queue_1.Queue(this, guild, queueInitOptions);
170
171
  queue.metadata = _meta;
@@ -174,7 +175,7 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
174
175
  /**
175
176
  * Returns the queue if available
176
177
  * @param {GuildResolvable} guild The guild id
177
- * @returns {Queue}
178
+ * @returns {Queue | undefined}
178
179
  */
179
180
  getQueue(guild) {
180
181
  guild = this.client.guilds.resolve(guild);
@@ -346,10 +347,11 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
346
347
  description: spotifyData.description ?? "",
347
348
  author: spotifyData.artists[0]?.name ?? "Unknown Artist",
348
349
  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)),
350
+ thumbnail: (spotifyData.coverArt?.sources?.[0]?.url ??
351
+ spotifyData.album?.images[0]?.url ??
352
+ (spotifyData.preview_url?.length && `https://i.scdn.co/image/${spotifyData.preview_url?.split("?cid=")[1]}`)) ||
353
+ "https://www.scdn.co/i/_global/twitter_card-default.jpg",
354
+ duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(spotifyData.duration_ms ?? spotifyData.duration ?? spotifyData.maxDuration)),
353
355
  views: 0,
354
356
  requestedBy: options.requestedBy,
355
357
  source: "spotify"
@@ -366,7 +368,7 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
366
368
  const playlist = new Playlist_1.Playlist(this, {
367
369
  title: spotifyPlaylist.name ?? spotifyPlaylist.title,
368
370
  description: spotifyPlaylist.description ?? "",
369
- thumbnail: spotifyPlaylist.images[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
371
+ thumbnail: spotifyPlaylist.coverArt?.sources?.[0]?.url ?? spotifyPlaylist.images[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
370
372
  type: spotifyPlaylist.type,
371
373
  source: "spotify",
372
374
  author: spotifyPlaylist.type !== "playlist"
@@ -86,6 +86,7 @@ class Queue {
86
86
  leaveOnEnd: true,
87
87
  leaveOnStop: true,
88
88
  leaveOnEmpty: true,
89
+ leaveOnEndCooldown: 1000,
89
90
  leaveOnEmptyCooldown: 1000,
90
91
  autoSelfDeaf: true,
91
92
  ytdlOptions: {
@@ -100,6 +101,18 @@ class Queue {
100
101
  this.onBeforeCreateStream = this.options.onBeforeCreateStream;
101
102
  this.player.emit("debug", this, `Queue initialized:\n\n${this.player.scanDeps()}`);
102
103
  }
104
+ /**
105
+ * Forces next play
106
+ * @returns {Promise<void>}
107
+ */
108
+ async forceNext() {
109
+ if (this.connection.audioResource) {
110
+ this.connection.emit("finish", this.connection.audioResource);
111
+ }
112
+ else if (this.tracks.length) {
113
+ await this.play();
114
+ }
115
+ }
103
116
  /**
104
117
  * Returns current track
105
118
  * @type {Track}
@@ -175,9 +188,7 @@ class Queue {
175
188
  this.previousTracks.push(resource.metadata);
176
189
  this.player.emit("trackEnd", this, resource.metadata);
177
190
  if (!this.tracks.length && this.repeatMode === types_1.QueueRepeatMode.OFF) {
178
- if (this.options.leaveOnEnd)
179
- this.destroy();
180
- this.player.emit("queueEnd", this);
191
+ this.emitEnd();
181
192
  }
182
193
  else if (!this.tracks.length && this.repeatMode === types_1.QueueRepeatMode.AUTOPLAY) {
183
194
  this._handleAutoplay(Util_1.Util.last(this.previousTracks));
@@ -194,6 +205,25 @@ class Queue {
194
205
  });
195
206
  return this;
196
207
  }
208
+ emitEnd() {
209
+ const timeout = setTimeout(() => {
210
+ if (!this.player.queues.has(this.guild.id))
211
+ return;
212
+ if (this.tracks.length || this.current)
213
+ return;
214
+ if (this.options.leaveOnEnd)
215
+ this.destroy();
216
+ this.player.emit("queueEnd", this);
217
+ }, this.options.leaveOnEndCooldown || 0).unref();
218
+ this._cooldownsTimeout.set(`queueEnd_${this.guild.id}`, timeout);
219
+ }
220
+ refreshEndCooldown() {
221
+ const existingTimeout = this._cooldownsTimeout.get(`queueEnd_${this.guild.id}`);
222
+ if (this.tracks.length || this.current) {
223
+ clearTimeout(existingTimeout);
224
+ this._cooldownsTimeout.delete(`queueEnd_${this.guild.id}`);
225
+ }
226
+ }
197
227
  /**
198
228
  * Destroys this queue
199
229
  * @param {boolean} [disconnect=this.options.leaveOnStop] If it should leave on destroy
@@ -234,6 +264,7 @@ class Queue {
234
264
  if (!(track instanceof Track_1.default))
235
265
  throw new PlayerError_1.PlayerError("invalid track", PlayerError_1.ErrorStatusCode.INVALID_TRACK);
236
266
  this.tracks.push(track);
267
+ this.refreshEndCooldown();
237
268
  this.player.emit("trackAdd", this, track);
238
269
  }
239
270
  /**
@@ -246,6 +277,7 @@ class Queue {
246
277
  if (!tracks.every((y) => y instanceof Track_1.default))
247
278
  throw new PlayerError_1.PlayerError("invalid track", PlayerError_1.ErrorStatusCode.INVALID_TRACK);
248
279
  this.tracks.push(...tracks);
280
+ this.refreshEndCooldown();
249
281
  this.player.emit("tracksAdd", this, tracks);
250
282
  }
251
283
  /**
@@ -450,14 +482,12 @@ class Queue {
450
482
  shuffle() {
451
483
  if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
452
484
  return;
453
- if (!this.tracks.length || this.tracks.length < 3)
485
+ if (!this.tracks.length || this.tracks.length < 2)
454
486
  return false;
455
- const currentTrack = this.tracks.shift();
456
487
  for (let i = this.tracks.length - 1; i > 0; i--) {
457
488
  const j = Math.floor(Math.random() * (i + 1));
458
489
  [this.tracks[i], this.tracks[j]] = [this.tracks[j], this.tracks[i]];
459
490
  }
460
- this.tracks.unshift(currentTrack);
461
491
  return true;
462
492
  }
463
493
  /**
@@ -632,7 +662,9 @@ class Queue {
632
662
  if (this.options.spotifyBridge && track.raw.source === "spotify" && !track.raw.engine) {
633
663
  track.raw.engine = await youtube_sr_1.default.search(`${track.author} ${track.title}`, { type: "video" })
634
664
  .then((res) => res[0].url)
635
- .catch(() => null);
665
+ .catch(() => {
666
+ /* void */
667
+ });
636
668
  spotifyResolved = true;
637
669
  }
638
670
  const url = track.raw.source === "spotify" ? track.raw.engine : track.url;
@@ -691,9 +723,7 @@ class Queue {
691
723
  if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this))
692
724
  return;
693
725
  if (!track || ![track.source, track.raw?.source].includes("youtube")) {
694
- if (this.options.leaveOnEnd)
695
- this.destroy();
696
- return void this.player.emit("queueEnd", this);
726
+ return this.emitEnd();
697
727
  }
698
728
  let info = await youtube_sr_1.default.getVideo(track.url)
699
729
  .then((x) => x.videos[0])
@@ -704,9 +734,7 @@ class Queue {
704
734
  .then((x) => x[0])
705
735
  .catch(Util_1.Util.noop);
706
736
  if (!info) {
707
- if (this.options.leaveOnEnd)
708
- this.destroy();
709
- return void this.player.emit("queueEnd", this);
737
+ return this.emitEnd();
710
738
  }
711
739
  const nextTrack = new Track_1.default(this.player, {
712
740
  title: info.title,
@@ -171,8 +171,9 @@ class StreamDispatcher extends tiny_typed_emitter_1.TypedEmitter {
171
171
  async playStream(resource = this.audioResource) {
172
172
  if (!resource)
173
173
  throw new PlayerError_1.PlayerError("Audio resource is not available!", PlayerError_1.ErrorStatusCode.NO_AUDIO_RESOURCE);
174
- if (resource.ended)
175
- return void this.emit("error", new PlayerError_1.PlayerError("Cannot play a resource that has already ended."));
174
+ if (resource.ended) {
175
+ return void this.emit("finish", resource);
176
+ }
176
177
  if (!this.audioResource)
177
178
  this.audioResource = resource;
178
179
  if (this.voiceConnection.state.status !== voice_1.VoiceConnectionStatus.Ready) {
@@ -108,7 +108,7 @@ class VolumeTransformer extends stream_1.Transform {
108
108
  this._smoothing = smoothness;
109
109
  }
110
110
  smoothingEnabled() {
111
- return Number.isFinite(this._smoothing) && this._smoothing > 0;
111
+ return typeof this._smoothing === "number" && !Number.isNaN(this._smoothing) && Number.isFinite(this._smoothing) && this._smoothing > 0;
112
112
  }
113
113
  get hasSmoothness() {
114
114
  return true;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { User, VoiceChannel, StageChannel, Collection, Snowflake, Client, GuildResolvable, Guild, GuildChannelResolvable, UserResolvable } from 'discord.js';
3
- import { Readable, Duplex } from 'stream';
3
+ import { Readable, Duplex, TransformOptions, Transform } from 'stream';
4
4
  import { TypedEmitter } from 'tiny-typed-emitter';
5
5
  import { AudioPlayerError, AudioResource, VoiceConnection, AudioPlayer, StreamType, AudioPlayerStatus } from '@discordjs/voice';
6
6
  import { downloadOptions } from 'ytdl-core';
@@ -266,9 +266,9 @@ declare class Player extends TypedEmitter<PlayerEvents> {
266
266
  /**
267
267
  * Returns the queue if available
268
268
  * @param {GuildResolvable} guild The guild id
269
- * @returns {Queue}
269
+ * @returns {Queue | undefined}
270
270
  */
271
- getQueue<T = unknown>(guild: GuildResolvable): Queue<T>;
271
+ getQueue<T = unknown>(guild: GuildResolvable): Queue<T> | undefined;
272
272
  /**
273
273
  * Deletes a queue and returns deleted queue object
274
274
  * @param {GuildResolvable} guild The guild id to remove
@@ -345,6 +345,11 @@ declare class Queue<T = unknown> {
345
345
  * @param {PlayerOptions} [options] Player options for the queue
346
346
  */
347
347
  constructor(player: Player, guild: Guild, options?: PlayerOptions);
348
+ /**
349
+ * Forces next play
350
+ * @returns {Promise<void>}
351
+ */
352
+ forceNext(): Promise<void>;
348
353
  /**
349
354
  * Returns current track
350
355
  * @type {Track}
@@ -366,6 +371,8 @@ declare class Queue<T = unknown> {
366
371
  * @returns {Promise<Queue>}
367
372
  */
368
373
  connect(channel: GuildChannelResolvable): Promise<this>;
374
+ private emitEnd;
375
+ private refreshEndCooldown;
369
376
  /**
370
377
  * Destroys this queue
371
378
  * @param {boolean} [disconnect=this.options.leaveOnStop] If it should leave on destroy
@@ -671,6 +678,7 @@ interface PlayerProgressbarOptions {
671
678
  * @property {boolean} [leaveOnStop=true] If it should leave on stop
672
679
  * @property {boolean} [leaveOnEmpty=true] If it should leave on empty
673
680
  * @property {number} [leaveOnEmptyCooldown=1000] The cooldown in ms
681
+ * @property {number} [leaveOnEndCooldown=1000] The cooldown in ms
674
682
  * @property {boolean} [autoSelfDeaf=true] If it should set the bot in deaf mode
675
683
  * @property {YTDLDownloadOptions} [ytdlOptions] The youtube download options
676
684
  * @property {number} [initialVolume=100] The initial player volume
@@ -683,6 +691,7 @@ interface PlayerProgressbarOptions {
683
691
  */
684
692
  interface PlayerOptions {
685
693
  leaveOnEnd?: boolean;
694
+ leaveOnEndCooldown?: number;
686
695
  leaveOnStop?: boolean;
687
696
  leaveOnEmpty?: boolean;
688
697
  leaveOnEmptyCooldown?: number;
@@ -995,11 +1004,13 @@ interface PlaylistJSON {
995
1004
  * @property {boolean} [autoRegisterExtractor=true] If it should automatically register `@discord-player/extractor`
996
1005
  * @property {YTDLDownloadOptions} [ytdlOptions] The options passed to `ytdl-core`
997
1006
  * @property {number} [connectionTimeout=20000] The voice connection timeout
1007
+ * @property {boolean} [smoothVolume=true] Toggle smooth volume transition
998
1008
  */
999
1009
  interface PlayerInitOptions {
1000
1010
  autoRegisterExtractor?: boolean;
1001
1011
  ytdlOptions?: downloadOptions;
1002
1012
  connectionTimeout?: number;
1013
+ smoothVolume?: boolean;
1003
1014
  }
1004
1015
 
1005
1016
  declare class AudioFilters {
@@ -1019,7 +1030,7 @@ declare class AudioFilters {
1019
1030
  * @param filter The filter name
1020
1031
  * @returns
1021
1032
  */
1022
- static create(filters?: FiltersName[]): string;
1033
+ static create<K extends FiltersName>(filters?: K[]): string;
1023
1034
  /**
1024
1035
  * Defines audio filter
1025
1036
  * @param filterName The name of the filter
@@ -1087,6 +1098,38 @@ declare class QueryResolver {
1087
1098
  static getVimeoID(query: string): string;
1088
1099
  }
1089
1100
 
1101
+ interface VolumeTransformerOptions extends TransformOptions {
1102
+ type?: "s16le" | "s16be" | "s32le" | "s32be";
1103
+ smoothness?: number;
1104
+ volume?: number;
1105
+ }
1106
+ declare class VolumeTransformer extends Transform {
1107
+ private _bits;
1108
+ private _smoothing;
1109
+ private _bytes;
1110
+ private _extremum;
1111
+ private _chunk;
1112
+ volume: number;
1113
+ private _targetVolume;
1114
+ type: "s16le" | "s32le" | "s16be" | "s32be";
1115
+ constructor(options?: VolumeTransformerOptions);
1116
+ _readInt(buffer: Buffer, index: number): number;
1117
+ _writeInt(buffer: Buffer, int: number, index: number): number;
1118
+ _applySmoothness(): void;
1119
+ _transform(chunk: Buffer, encoding: BufferEncoding, done: () => unknown): unknown;
1120
+ _destroy(err: Error, cb: (error: Error) => void): void;
1121
+ setVolume(volume: number): void;
1122
+ setVolumeDecibels(db: number): void;
1123
+ setVolumeLogarithmic(value: number): void;
1124
+ get volumeDecibels(): number;
1125
+ get volumeLogarithmic(): number;
1126
+ get smoothness(): number;
1127
+ setSmoothness(smoothness: number): void;
1128
+ smoothingEnabled(): boolean;
1129
+ get hasSmoothness(): boolean;
1130
+ static get hasSmoothing(): boolean;
1131
+ }
1132
+
1090
1133
  declare class Util {
1091
1134
  /**
1092
1135
  * Utils
@@ -1155,4 +1198,4 @@ declare function createFFmpegStream(stream: Readable | Duplex | string, options?
1155
1198
 
1156
1199
  declare const version: string;
1157
1200
 
1158
- export { AudioFilters, ErrorStatusCode, ExtractorModel, ExtractorModelData, FFMPEG_ARGS_PIPED, FFMPEG_ARGS_STRING, FFmpegStreamOptions, FiltersName, PlayOptions, Player, PlayerError, PlayerEvents, PlayerInitOptions, PlayerOptions, PlayerProgressbarOptions, PlayerSearchResult, Playlist, PlaylistInitData, PlaylistJSON, QueryResolver, QueryType, Queue, QueueFilters, QueueRepeatMode, RawTrackData, SearchOptions, StreamDispatcher, TimeData, Track, TrackJSON, TrackSource, Util, VoiceEvents, VoiceUtils, createFFmpegStream, version };
1201
+ export { AudioFilters, ErrorStatusCode, ExtractorModel, ExtractorModelData, FFMPEG_ARGS_PIPED, FFMPEG_ARGS_STRING, FFmpegStreamOptions, FiltersName, PlayOptions, Player, PlayerError, PlayerEvents, PlayerInitOptions, PlayerOptions, PlayerProgressbarOptions, PlayerSearchResult, Playlist, PlaylistInitData, PlaylistJSON, QueryResolver, QueryType, Queue, QueueFilters, QueueRepeatMode, RawTrackData, SearchOptions, StreamDispatcher, TimeData, Track, TrackJSON, TrackSource, Util, VoiceEvents, VoiceUtils, VolumeTransformer, VolumeTransformerOptions, createFFmpegStream, version };
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ var VoiceUtils_1 = require("./VoiceInterface/VoiceUtils");
25
25
  Object.defineProperty(exports, "VoiceUtils", { enumerable: true, get: function () { return VoiceUtils_1.VoiceUtils; } });
26
26
  var StreamDispatcher_1 = require("./VoiceInterface/StreamDispatcher");
27
27
  Object.defineProperty(exports, "StreamDispatcher", { enumerable: true, get: function () { return StreamDispatcher_1.StreamDispatcher; } });
28
+ tslib_1.__exportStar(require("./VoiceInterface/VolumeTransformer"), exports);
28
29
  var Util_1 = require("./utils/Util");
29
30
  Object.defineProperty(exports, "Util", { enumerable: true, get: function () { return Util_1.Util; } });
30
31
  tslib_1.__exportStar(require("./types/types"), exports);
package/dist/index.mjs CHANGED
@@ -17,5 +17,6 @@ export const StreamDispatcher = mod.StreamDispatcher;
17
17
  export const Track = mod.Track;
18
18
  export const Util = mod.Util;
19
19
  export const VoiceUtils = mod.VoiceUtils;
20
+ export const VolumeTransformer = mod.VolumeTransformer;
20
21
  export const createFFmpegStream = mod.createFFmpegStream;
21
22
  export const version = mod.version;
@@ -1,13 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const VolumeTransformer_1 = require("./VoiceInterface/VolumeTransformer");
4
- try {
5
- // eslint-disable-next-line
6
- const mod = require("prism-media");
7
- if (typeof mod.VolumeTransformer.hasSmoothing !== "boolean") {
8
- Reflect.set(mod, "VolumeTransformer", VolumeTransformer_1.VolumeTransformer);
4
+ if (!("DISABLE_DISCORD_PLAYER_SMOOTH_VOLUME" in process.env)) {
5
+ try {
6
+ // eslint-disable-next-line
7
+ const mod = require("prism-media");
8
+ if (typeof mod.VolumeTransformer.hasSmoothing !== "boolean") {
9
+ Reflect.set(mod, "VolumeTransformer", VolumeTransformer_1.VolumeTransformer);
10
+ }
11
+ }
12
+ catch {
13
+ /* do nothing */
9
14
  }
10
- }
11
- catch {
12
- /* do nothing */
13
15
  }
@@ -50,17 +50,16 @@ class AudioFilters {
50
50
  return name in this.filters;
51
51
  }
52
52
  static *[Symbol.iterator]() {
53
- for (const [k, v] of Object.entries(this)) {
54
- if (typeof this.filters[k] === "string")
55
- yield { name: k, value: v };
53
+ for (const [k, v] of Object.entries(this.filters)) {
54
+ yield { name: k, value: v };
56
55
  }
57
56
  }
58
57
  static get names() {
59
- return Object.keys(this).filter((p) => !["names", "length"].includes(p) && typeof this.filters[p] !== "function");
58
+ return Object.keys(this.filters);
60
59
  }
61
60
  // @ts-expect-error AudioFilters.length
62
61
  static get length() {
63
- return Object.keys(this).filter((p) => !["names", "length"].includes(p) && typeof this.filters[p] !== "function").length;
62
+ return this.names.length;
64
63
  }
65
64
  static toString() {
66
65
  return this.names.map((m) => this[m]).join(","); // eslint-disable-line @typescript-eslint/no-explicit-any
@@ -7,7 +7,7 @@ const types_1 = require("../types/types");
7
7
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
8
8
  // @ts-ignore
9
9
  const soundcloud_scraper_1 = require("soundcloud-scraper");
10
- // scary things below *sigh*
10
+ // #region scary things below *sigh*
11
11
  const spotifySongRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:track\/|\?uri=spotify:track:)((\w|-){22})/;
12
12
  const spotifyPlaylistRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:playlist\/|\?uri=spotify:playlist:)((\w|-){22})/;
13
13
  const spotifyAlbumRegex = /https?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:album\/|\?uri=spotify:album:)((\w|-){22})/;
@@ -15,7 +15,7 @@ const vimeoRegex = /(http|https)?:\/\/(www\.|player\.)?vimeo\.com\/(?:channels\/
15
15
  const facebookRegex = /(https?:\/\/)(www\.|m\.)?(facebook|fb).com\/.*\/videos\/.*/;
16
16
  const reverbnationRegex = /https:\/\/(www.)?reverbnation.com\/(.+)\/song\/(.+)/;
17
17
  const attachmentRegex = /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/;
18
- // scary things above *sigh*
18
+ // #endregion scary things above *sigh*
19
19
  class QueryResolver {
20
20
  /**
21
21
  * Query resolver
@@ -45,6 +45,8 @@ class Util {
45
45
  * @returns {TimeData}
46
46
  */
47
47
  static parseMS(milliseconds) {
48
+ if (isNaN(milliseconds))
49
+ milliseconds = 0;
48
50
  const round = milliseconds > 0 ? Math.floor : Math.ceil;
49
51
  return {
50
52
  days: round(milliseconds / 86400000),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discord-player",
3
- "version": "5.3.0",
3
+ "version": "5.3.2-dev.1",
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,7 +18,7 @@
18
18
  "./dist/*": "./dist/*"
19
19
  },
20
20
  "scripts": {
21
- "dev": "cd example/test && ts-node index.ts",
21
+ "dev": "cd examples/test && ts-node index.ts",
22
22
  "build": "rimraf dist && tsc && npm run build:esm",
23
23
  "build:check": "tsc --noEmit --incremental false",
24
24
  "prepublishOnly": "rollup-type-bundler -e stream",
@@ -67,12 +67,14 @@
67
67
  "dependencies": {
68
68
  "@discordjs/voice": "^0.11.0",
69
69
  "libsodium-wrappers": "^0.7.10",
70
- "soundcloud-scraper": "^5.0.3",
71
- "spotify-url-info": "^3.1.2",
72
70
  "tiny-typed-emitter": "^2.1.0",
73
- "tslib": "^2.4.0",
74
- "youtube-sr": "^4.3.0",
75
- "ytdl-core": "^4.11.0"
71
+ "tslib": "^2.4.0"
72
+ },
73
+ "peerDependencies": {
74
+ "soundcloud-scraper": "5.x",
75
+ "spotify-url-info": "3.x",
76
+ "youtube-sr": "4.x",
77
+ "ytdl-core": "4.x"
76
78
  },
77
79
  "devDependencies": {
78
80
  "@discordjs/ts-docgen": "^0.4.1",
@@ -89,8 +91,12 @@
89
91
  "opusscript": "^0.0.8",
90
92
  "prettier": "^2.7.1",
91
93
  "rimraf": "^3.0.2",
94
+ "soundcloud-scraper": "^5.0.3",
95
+ "spotify-url-info": "^3.1.7",
92
96
  "ts-node": "^10.9.1",
93
97
  "typedoc": "^0.23.10",
94
- "typescript": "^4.7.4"
98
+ "typescript": "^4.7.4",
99
+ "youtube-sr": "^4.3.4",
100
+ "ytdl-core": "^4.11.2"
95
101
  }
96
102
  }