discord-player 5.3.0-dev.0 → 5.3.0-dev.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/Player.js CHANGED
@@ -23,7 +23,7 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
23
23
  /**
24
24
  * Creates new Discord Player
25
25
  * @param {Client} client The Discord Client
26
- * @param {PlayerInitOptions} [options={}] The player init options
26
+ * @param {PlayerInitOptions} [options] The player init options
27
27
  */
28
28
  constructor(client, options = {}) {
29
29
  super();
@@ -80,23 +80,29 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
80
80
  return void this.emit("botDisconnect", queue);
81
81
  }
82
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);
83
+ if (!oldState.serverMute && newState.serverMute) {
84
+ // state.serverMute can be null
85
+ queue.setPaused(!!newState.serverMute);
85
86
  }
86
- else if (newState.suppress || !newState.suppress) {
87
- if (newState.suppress)
87
+ else if (!oldState.suppress && newState.suppress) {
88
+ // state.suppress can be null
89
+ queue.setPaused(!!newState.suppress);
90
+ if (newState.suppress) {
88
91
  newState.guild.members.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
89
- queue.setPaused(newState.suppress);
92
+ }
90
93
  }
91
94
  }
92
95
  if (oldState.channelId === newState.channelId && newState.member.id === newState.guild.members.me.id) {
93
- if (oldState.serverMute !== newState.serverMute) {
94
- queue.setPaused(newState.serverMute);
96
+ if (!oldState.serverMute && newState.serverMute) {
97
+ // state.serverMute can be null
98
+ queue.setPaused(!!newState.serverMute);
95
99
  }
96
- else if (oldState.suppress !== newState.suppress) {
97
- if (newState.suppress)
100
+ else if (!oldState.suppress && newState.suppress) {
101
+ // state.suppress can be null
102
+ queue.setPaused(!!newState.suppress);
103
+ if (newState.suppress) {
98
104
  newState.guild.members.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop);
99
- queue.setPaused(newState.suppress);
105
+ }
100
106
  }
101
107
  }
102
108
  if (queue.connection && !newState.channelId && oldState.channelId === queue.connection.channel.id) {
@@ -401,9 +407,9 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
401
407
  const data = new Track_1.default(this, {
402
408
  title: m.track.name ?? "",
403
409
  description: m.track.description ?? "",
404
- author: m.track.artists[0]?.name ?? "Unknown Artist",
410
+ author: m.track.artists?.[0]?.name ?? "Unknown Artist",
405
411
  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",
412
+ thumbnail: m.track.album?.images?.[0]?.url ?? "https://www.scdn.co/i/_global/twitter_card-default.jpg",
407
413
  duration: Util_1.Util.buildTimeCode(Util_1.Util.parseMS(m.track.duration_ms)),
408
414
  views: 0,
409
415
  requestedBy: options.requestedBy,
@@ -564,5 +570,12 @@ class Player extends tiny_typed_emitter_1.TypedEmitter {
564
570
  *[Symbol.iterator]() {
565
571
  yield* Array.from(this.queues.values());
566
572
  }
573
+ /**
574
+ * Creates `Playlist` instance
575
+ * @param data The data to initialize a playlist
576
+ */
577
+ createPlaylist(data) {
578
+ return new Playlist_1.Playlist(this, data);
579
+ }
567
580
  }
568
581
  exports.Player = Player;
@@ -6,18 +6,19 @@ const tslib_1 = require("tslib");
6
6
  const discord_js_1 = require("discord.js");
7
7
  const Track_1 = tslib_1.__importDefault(require("./Track"));
8
8
  const types_1 = require("../types/types");
9
- const discord_ytdl_core_1 = tslib_1.__importDefault(require("discord-ytdl-core"));
9
+ const ytdl_core_1 = tslib_1.__importDefault(require("ytdl-core"));
10
10
  const voice_1 = require("@discordjs/voice");
11
11
  const Util_1 = require("../utils/Util");
12
12
  const youtube_sr_1 = tslib_1.__importDefault(require("youtube-sr"));
13
13
  const AudioFilters_1 = tslib_1.__importDefault(require("../utils/AudioFilters"));
14
14
  const PlayerError_1 = require("./PlayerError");
15
+ const FFmpegStream_1 = require("../utils/FFmpegStream");
15
16
  class Queue {
16
17
  /**
17
18
  * Queue constructor
18
19
  * @param {Player} player The player that instantiated this queue
19
20
  * @param {Guild} guild The guild that instantiated this queue
20
- * @param {PlayerOptions} [options={}] Player options for the queue
21
+ * @param {PlayerOptions} [options] Player options for the queue
21
22
  */
22
23
  constructor(player, guild, options = {}) {
23
24
  _Queue_instances.add(this);
@@ -191,9 +192,6 @@ class Queue {
191
192
  return;
192
193
  }
193
194
  });
194
- await this.player.voiceUtils.enterReady(this.connection.voiceConnection, {
195
- maxTime: this.player.options.connectionTimeout || 30000
196
- });
197
195
  return this;
198
196
  }
199
197
  /**
@@ -609,7 +607,7 @@ class Queue {
609
607
  /**
610
608
  * Play stream in a voice/stage channel
611
609
  * @param {Track} [src] The track to play (if empty, uses first track from the queue)
612
- * @param {PlayOptions} [options={}] The options
610
+ * @param {PlayOptions} [options] The options
613
611
  * @returns {Promise<void>}
614
612
  */
615
613
  async play(src, options = {}) {
@@ -628,66 +626,43 @@ class Queue {
628
626
  this.previousTracks.push(track);
629
627
  }
630
628
  let stream = null;
631
- const customDownloader = typeof this.onBeforeCreateStream === "function";
629
+ const hasCustomDownloader = typeof this.onBeforeCreateStream === "function";
632
630
  if (["youtube", "spotify"].includes(track.raw.source)) {
633
631
  let spotifyResolved = false;
634
632
  if (this.options.spotifyBridge && track.raw.source === "spotify" && !track.raw.engine) {
635
633
  track.raw.engine = await youtube_sr_1.default.search(`${track.author} ${track.title}`, { type: "video" })
636
- .then((x) => x[0].url)
634
+ .then((res) => res[0].url)
637
635
  .catch(() => null);
638
636
  spotifyResolved = true;
639
637
  }
640
- const link = track.raw.source === "spotify" ? track.raw.engine : track.url;
641
- if (!link)
638
+ const url = track.raw.source === "spotify" ? track.raw.engine : track.url;
639
+ if (!url)
642
640
  return void this.play(this.tracks.shift(), { immediate: true });
643
- if (customDownloader) {
644
- stream = (await this.onBeforeCreateStream(track, spotifyResolved ? "youtube" : track.raw.source, this)) ?? null;
645
- if (stream)
646
- stream = discord_ytdl_core_1.default
647
- .arbitraryStream(stream, {
648
- opusEncoded: false,
649
- fmt: "s16le",
650
- encoderArgs: options.encoderArgs ?? this._activeFilters.length ? ["-af", AudioFilters_1.default.create(this._activeFilters)] : [],
651
- seek: options.seek ? options.seek / 1000 : 0
652
- })
653
- .on("error", (err) => {
654
- return err.message.toLowerCase().includes("premature close") ? null : this.player.emit("error", this, err);
655
- });
641
+ if (hasCustomDownloader) {
642
+ stream = (await this.onBeforeCreateStream(track, spotifyResolved ? "youtube" : track.raw.source, this)) || null;
656
643
  }
657
- else {
658
- stream = (0, discord_ytdl_core_1.default)(link, {
659
- ...this.options.ytdlOptions,
660
- // discord-ytdl-core
661
- opusEncoded: false,
662
- fmt: "s16le",
663
- encoderArgs: options.encoderArgs ?? this._activeFilters.length ? ["-af", AudioFilters_1.default.create(this._activeFilters)] : [],
664
- seek: options.seek ? options.seek / 1000 : 0
665
- }).on("error", (err) => {
666
- return err.message.toLowerCase().includes("premature close") ? null : this.player.emit("error", this, err);
667
- });
644
+ if (!stream) {
645
+ stream = (0, ytdl_core_1.default)(url, this.options.ytdlOptions);
668
646
  }
669
647
  }
670
648
  else {
671
- const tryArb = (customDownloader && (await this.onBeforeCreateStream(track, track.raw.source || track.raw.engine, this))) || null;
672
- const arbitrarySource = tryArb
673
- ? tryArb
674
- : track.raw.source === "soundcloud"
649
+ const arbitraryStream = (hasCustomDownloader && (await this.onBeforeCreateStream(track, track.raw.source || track.raw.engine, this))) || null;
650
+ stream =
651
+ arbitraryStream || track.raw.source === "soundcloud"
675
652
  ? await track.raw.engine.downloadProgressive()
676
653
  : typeof track.raw.engine === "function"
677
- ? await track.raw.engine()
654
+ ? await track.raw.engine
678
655
  : track.raw.engine;
679
- stream = discord_ytdl_core_1.default
680
- .arbitraryStream(arbitrarySource, {
681
- opusEncoded: false,
682
- fmt: "s16le",
683
- encoderArgs: options.encoderArgs ?? this._activeFilters.length ? ["-af", AudioFilters_1.default.create(this._activeFilters)] : [],
684
- seek: options.seek ? options.seek / 1000 : 0
685
- })
686
- .on("error", (err) => {
687
- return err.message.toLowerCase().includes("premature close") ? null : this.player.emit("error", this, err);
688
- });
689
656
  }
690
- const resource = this.connection.createStream(stream, {
657
+ const ffmpegStream = (0, FFmpegStream_1.createFFmpegStream)(stream, {
658
+ encoderArgs: options.encoderArgs || this._activeFilters.length ? ["-af", AudioFilters_1.default.create(this._activeFilters)] : [],
659
+ seek: options.seek ? options.seek / 1000 : 0,
660
+ fmt: "s16le"
661
+ }).on("error", (err) => {
662
+ if (!`${err}`.toLowerCase().includes("premature close"))
663
+ this.player.emit("error", this, err);
664
+ });
665
+ const resource = this.connection.createStream(ffmpegStream, {
691
666
  type: voice_1.StreamType.Raw,
692
667
  data: track,
693
668
  disableVolume: Boolean(this.options.disableVolume)
@@ -697,7 +672,7 @@ class Queue {
697
672
  this._filtersUpdate = options.filtersUpdate;
698
673
  const volumeTransformer = resource.volume;
699
674
  if (volumeTransformer && typeof this.options.initialVolume === "number")
700
- Reflect.set(volumeTransformer, "volume", Math.pow(this.options.initialVolume, 1.660964));
675
+ Reflect.set(volumeTransformer, "volume", Math.pow(this.options.initialVolume / 100, 1.660964));
701
676
  if (volumeTransformer?.hasSmoothness && typeof this.options.volumeSmoothness === "number") {
702
677
  if (typeof volumeTransformer.setSmoothness === "function")
703
678
  volumeTransformer.setSmoothness(this.options.volumeSmoothness || 0);
@@ -720,9 +695,14 @@ class Queue {
720
695
  this.destroy();
721
696
  return void this.player.emit("queueEnd", this);
722
697
  }
723
- const info = await youtube_sr_1.default.getVideo(track.url)
698
+ let info = await youtube_sr_1.default.getVideo(track.url)
724
699
  .then((x) => x.videos[0])
725
700
  .catch(Util_1.Util.noop);
701
+ // fallback
702
+ if (!info)
703
+ info = await youtube_sr_1.default.search(track.author)
704
+ .then((x) => x[0])
705
+ .catch(Util_1.Util.noop);
726
706
  if (!info) {
727
707
  if (this.options.leaveOnEnd)
728
708
  this.destroy();
@@ -106,7 +106,7 @@ class StreamDispatcher extends tiny_typed_emitter_1.TypedEmitter {
106
106
  /**
107
107
  * Creates stream
108
108
  * @param {Readable|Duplex|string} src The stream source
109
- * @param {object} [ops={}] Options
109
+ * @param {object} [ops] Options
110
110
  * @returns {AudioResource}
111
111
  */
112
112
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -19,7 +19,7 @@ class VoiceUtils {
19
19
  /**
20
20
  * Joins a voice channel, creating basic stream dispatch manager
21
21
  * @param {StageChannel|VoiceChannel} channel The voice channel
22
- * @param {object} [options={}] Join options
22
+ * @param {object} [options] Join options
23
23
  * @returns {Promise<StreamDispatcher>}
24
24
  */
25
25
  async connect(channel, options) {
@@ -31,7 +31,7 @@ class VoiceUtils {
31
31
  /**
32
32
  * Joins a voice channel
33
33
  * @param {StageChannel|VoiceChannel} [channel] The voice/stage channel to join
34
- * @param {object} [options={}] Join options
34
+ * @param {object} [options] Join options
35
35
  * @returns {VoiceConnection}
36
36
  */
37
37
  async join(channel, options) {
@@ -43,16 +43,6 @@ class VoiceUtils {
43
43
  });
44
44
  return conn;
45
45
  }
46
- async enterReady(conn, options = {}) {
47
- try {
48
- conn = await (0, voice_1.entersState)(conn, voice_1.VoiceConnectionStatus.Ready, options?.maxTime ?? 20000);
49
- return conn;
50
- }
51
- catch (err) {
52
- conn.destroy();
53
- throw err;
54
- }
55
- }
56
46
  /**
57
47
  * Disconnects voice connection
58
48
  * @param {VoiceConnection} connection The voice connection
package/dist/index.d.ts CHANGED
@@ -4,7 +4,6 @@ import { Readable, Duplex } 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';
7
- import * as undici from 'undici';
8
7
 
9
8
  declare class Playlist {
10
9
  readonly player: Player;
@@ -107,7 +106,7 @@ declare class StreamDispatcher extends TypedEmitter<VoiceEvents> {
107
106
  /**
108
107
  * Creates stream
109
108
  * @param {Readable|Duplex|string} src The stream source
110
- * @param {object} [ops={}] Options
109
+ * @param {object} [ops] Options
111
110
  * @returns {AudioResource}
112
111
  */
113
112
  createStream(src: Readable | Duplex | string, ops?: {
@@ -175,7 +174,7 @@ declare class VoiceUtils {
175
174
  /**
176
175
  * Joins a voice channel, creating basic stream dispatch manager
177
176
  * @param {StageChannel|VoiceChannel} channel The voice channel
178
- * @param {object} [options={}] Join options
177
+ * @param {object} [options] Join options
179
178
  * @returns {Promise<StreamDispatcher>}
180
179
  */
181
180
  connect(channel: VoiceChannel | StageChannel, options?: {
@@ -185,16 +184,13 @@ declare class VoiceUtils {
185
184
  /**
186
185
  * Joins a voice channel
187
186
  * @param {StageChannel|VoiceChannel} [channel] The voice/stage channel to join
188
- * @param {object} [options={}] Join options
187
+ * @param {object} [options] Join options
189
188
  * @returns {VoiceConnection}
190
189
  */
191
190
  join(channel: VoiceChannel | StageChannel, options?: {
192
191
  deaf?: boolean;
193
192
  maxTime?: number;
194
193
  }): Promise<VoiceConnection>;
195
- enterReady(conn: VoiceConnection, options?: {
196
- maxTime?: number;
197
- }): Promise<VoiceConnection>;
198
194
  /**
199
195
  * Disconnects voice connection
200
196
  * @param {VoiceConnection} connection The voice connection
@@ -247,7 +243,7 @@ declare class Player extends TypedEmitter<PlayerEvents> {
247
243
  /**
248
244
  * Creates new Discord Player
249
245
  * @param {Client} client The Discord Client
250
- * @param {PlayerInitOptions} [options={}] The player init options
246
+ * @param {PlayerInitOptions} [options] The player init options
251
247
  */
252
248
  constructor(client: Client, options?: PlayerInitOptions);
253
249
  /**
@@ -318,6 +314,11 @@ declare class Player extends TypedEmitter<PlayerEvents> {
318
314
  */
319
315
  resolveQueue<T>(queueLike: GuildResolvable | Queue): Queue<T>;
320
316
  [Symbol.iterator](): Generator<Queue<unknown>, void, undefined>;
317
+ /**
318
+ * Creates `Playlist` instance
319
+ * @param data The data to initialize a playlist
320
+ */
321
+ createPlaylist(data: PlaylistInitData): Playlist;
321
322
  }
322
323
 
323
324
  declare class Queue<T = unknown> {
@@ -341,7 +342,7 @@ declare class Queue<T = unknown> {
341
342
  * Queue constructor
342
343
  * @param {Player} player The player that instantiated this queue
343
344
  * @param {Guild} guild The guild that instantiated this queue
344
- * @param {PlayerOptions} [options={}] Player options for the queue
345
+ * @param {PlayerOptions} [options] Player options for the queue
345
346
  */
346
347
  constructor(player: Player, guild: Guild, options?: PlayerOptions);
347
348
  /**
@@ -523,7 +524,7 @@ declare class Queue<T = unknown> {
523
524
  /**
524
525
  * Play stream in a voice/stage channel
525
526
  * @param {Track} [src] The track to play (if empty, uses first track from the queue)
526
- * @param {PlayOptions} [options={}] The options
527
+ * @param {PlayOptions} [options] The options
527
528
  * @returns {Promise<void>}
528
529
  */
529
530
  play(src?: Track, options?: PlayOptions): Promise<void>;
@@ -671,12 +672,12 @@ interface PlayerProgressbarOptions {
671
672
  * @property {boolean} [leaveOnEmpty=true] If it should leave on empty
672
673
  * @property {number} [leaveOnEmptyCooldown=1000] The cooldown in ms
673
674
  * @property {boolean} [autoSelfDeaf=true] If it should set the bot in deaf mode
674
- * @property {YTDLDownloadOptions} [ytdlOptions={}] The youtube download options
675
+ * @property {YTDLDownloadOptions} [ytdlOptions] The youtube download options
675
676
  * @property {number} [initialVolume=100] The initial player volume
676
677
  * @property {number} [bufferingTimeout=3000] Buffering timeout for the stream
677
678
  * @property {boolean} [spotifyBridge=true] If player should bridge spotify source to youtube
678
679
  * @property {boolean} [disableVolume=false] If player should disable inline volume
679
- * @property {boolean} [volumeSmoothness=0] The volume transition smoothness between volume changes (lower the value to get better result)
680
+ * @property {number} [volumeSmoothness=0] The volume transition smoothness between volume changes (lower the value to get better result)
680
681
  * Setting this or leaving this empty will disable this effect. Example: `volumeSmoothness: 0.1`
681
682
  * @property {Function} [onBeforeCreateStream] Runs before creating stream
682
683
  */
@@ -992,7 +993,7 @@ interface PlaylistJSON {
992
993
  /**
993
994
  * @typedef {object} PlayerInitOptions
994
995
  * @property {boolean} [autoRegisterExtractor=true] If it should automatically register `@discord-player/extractor`
995
- * @property {YTDLDownloadOptions} [ytdlOptions={}] The options passed to `ytdl-core`
996
+ * @property {YTDLDownloadOptions} [ytdlOptions] The options passed to `ytdl-core`
996
997
  * @property {number} [connectionTimeout=20000] The voice connection timeout
997
998
  */
998
999
  interface PlayerInitOptions {
@@ -1001,91 +1002,39 @@ interface PlayerInitOptions {
1001
1002
  connectionTimeout?: number;
1002
1003
  }
1003
1004
 
1004
- /**
1005
- * The available audio filters
1006
- * @typedef {object} AudioFilters
1007
- * @property {string} bassboost_low The bassboost filter (+15dB)
1008
- * @property {string} bassboost The bassboost filter (+20dB)
1009
- * @property {string} bassboost_high The bassboost filter (+30dB)
1010
- * @property {string} 8D The 8D filter
1011
- * @property {string} vaporwave The vaporwave filter
1012
- * @property {string} nightcore The nightcore filter
1013
- * @property {string} phaser The phaser filter
1014
- * @property {string} tremolo The tremolo filter
1015
- * @property {string} vibrato The vibrato filter
1016
- * @property {string} reverse The reverse filter
1017
- * @property {string} treble The treble filter
1018
- * @property {string} normalizer The normalizer filter (dynamic audio normalizer based)
1019
- * @property {string} normalizer2 The normalizer filter (audio compressor based)
1020
- * @property {string} surrounding The surrounding filter
1021
- * @property {string} pulsator The pulsator filter
1022
- * @property {string} subboost The subboost filter
1023
- * @property {string} karaoke The kakaoke filter
1024
- * @property {string} flanger The flanger filter
1025
- * @property {string} gate The gate filter
1026
- * @property {string} haas The haas filter
1027
- * @property {string} mcompand The mcompand filter
1028
- * @property {string} mono The mono filter
1029
- * @property {string} mstlr The mstlr filter
1030
- * @property {string} mstrr The mstrr filter
1031
- * @property {string} compressor The compressor filter
1032
- * @property {string} expander The expander filter
1033
- * @property {string} softlimiter The softlimiter filter
1034
- * @property {string} chorus The chorus filter
1035
- * @property {string} chorus2d The chorus2d filter
1036
- * @property {string} chorus3d The chorus3d filter
1037
- * @property {string} fadein The fadein filter
1038
- * @property {string} dim The dim filter
1039
- * @property {string} earrape The earrape filter
1040
- */
1041
- declare const FilterList: {
1042
- bassboost_low: string;
1043
- bassboost: string;
1044
- bassboost_high: string;
1045
- "8D": string;
1046
- vaporwave: string;
1047
- nightcore: string;
1048
- phaser: string;
1049
- tremolo: string;
1050
- vibrato: string;
1051
- reverse: string;
1052
- treble: string;
1053
- normalizer: string;
1054
- normalizer2: string;
1055
- surrounding: string;
1056
- pulsator: string;
1057
- subboost: string;
1058
- karaoke: string;
1059
- flanger: string;
1060
- gate: string;
1061
- haas: string;
1062
- mcompand: string;
1063
- mono: string;
1064
- mstlr: string;
1065
- mstrr: string;
1066
- compressor: string;
1067
- expander: string;
1068
- softlimiter: string;
1069
- chorus: string;
1070
- chorus2d: string;
1071
- chorus3d: string;
1072
- fadein: string;
1073
- dim: string;
1074
- earrape: string;
1075
- [Symbol.iterator](): IterableIterator<{
1005
+ declare class AudioFilters {
1006
+ constructor();
1007
+ static get filters(): Record<FiltersName, string>;
1008
+ static get<K extends FiltersName>(name: K): Record<keyof QueueFilters, string>[K];
1009
+ static has<K extends FiltersName>(name: K): boolean;
1010
+ static [Symbol.iterator](): IterableIterator<{
1076
1011
  name: FiltersName;
1077
1012
  value: string;
1078
1013
  }>;
1079
- readonly names: (keyof QueueFilters)[];
1080
- readonly length: number;
1081
- toString(): string;
1082
- create(filter?: FiltersName[]): string;
1083
- define(filterName: string, value: string): void;
1084
- defineBulk(filterArray: {
1014
+ static get names(): (keyof QueueFilters)[];
1015
+ static get length(): number;
1016
+ static toString(): string;
1017
+ /**
1018
+ * Create ffmpeg args from the specified filters name
1019
+ * @param filter The filter name
1020
+ * @returns
1021
+ */
1022
+ static create(filters?: FiltersName[]): string;
1023
+ /**
1024
+ * Defines audio filter
1025
+ * @param filterName The name of the filter
1026
+ * @param value The ffmpeg args
1027
+ */
1028
+ static define(filterName: string, value: string): void;
1029
+ /**
1030
+ * Defines multiple audio filters
1031
+ * @param filtersArray Array of filters containing the filter name and ffmpeg args
1032
+ */
1033
+ static defineBulk(filtersArray: {
1085
1034
  name: string;
1086
1035
  value: string;
1087
1036
  }[]): void;
1088
- };
1037
+ }
1089
1038
 
1090
1039
  declare enum ErrorStatusCode {
1091
1040
  STREAM_ERROR = "StreamError",
@@ -1186,9 +1135,24 @@ declare class Util {
1186
1135
  */
1187
1136
  static wait(time: number): Promise<unknown>;
1188
1137
  static noop(): void;
1189
- static getFetch(): Promise<typeof fetch | typeof undici.default>;
1138
+ static getFetch(): Promise<any>;
1190
1139
  }
1191
1140
 
1141
+ interface FFmpegStreamOptions {
1142
+ fmt?: string;
1143
+ encoderArgs?: string[];
1144
+ seek?: number;
1145
+ skip?: boolean;
1146
+ }
1147
+ declare function FFMPEG_ARGS_STRING(stream: string, fmt?: string): string[];
1148
+ declare function FFMPEG_ARGS_PIPED(fmt?: string): string[];
1149
+ /**
1150
+ * Creates FFmpeg stream
1151
+ * @param stream The source stream
1152
+ * @param options FFmpeg stream options
1153
+ */
1154
+ declare function createFFmpegStream(stream: Readable | Duplex | string, options?: FFmpegStreamOptions): Readable | Duplex;
1155
+
1192
1156
  declare const version: string;
1193
1157
 
1194
- export { FilterList as AudioFilters, ErrorStatusCode, ExtractorModel, ExtractorModelData, 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, version };
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 };
package/dist/index.js CHANGED
@@ -28,5 +28,6 @@ Object.defineProperty(exports, "StreamDispatcher", { enumerable: true, get: func
28
28
  var Util_1 = require("./utils/Util");
29
29
  Object.defineProperty(exports, "Util", { enumerable: true, get: function () { return Util_1.Util; } });
30
30
  tslib_1.__exportStar(require("./types/types"), exports);
31
+ tslib_1.__exportStar(require("./utils/FFmpegStream"), exports);
31
32
  // eslint-disable-next-line @typescript-eslint/no-var-requires
32
33
  exports.version = require(`${__dirname}/../package.json`).version;
package/dist/index.mjs CHANGED
@@ -4,6 +4,8 @@ export default mod;
4
4
  export const AudioFilters = mod.AudioFilters;
5
5
  export const ErrorStatusCode = mod.ErrorStatusCode;
6
6
  export const ExtractorModel = mod.ExtractorModel;
7
+ export const FFMPEG_ARGS_PIPED = mod.FFMPEG_ARGS_PIPED;
8
+ export const FFMPEG_ARGS_STRING = mod.FFMPEG_ARGS_STRING;
7
9
  export const Player = mod.Player;
8
10
  export const PlayerError = mod.PlayerError;
9
11
  export const Playlist = mod.Playlist;
@@ -15,4 +17,5 @@ export const StreamDispatcher = mod.StreamDispatcher;
15
17
  export const Track = mod.Track;
16
18
  export const Util = mod.Util;
17
19
  export const VoiceUtils = mod.VoiceUtils;
20
+ export const createFFmpegStream = mod.createFFmpegStream;
18
21
  export const version = mod.version;
@@ -2,108 +2,97 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AudioFilters = void 0;
4
4
  const bass = (g) => `bass=g=${g}:f=110:w=0.3`;
5
- /**
6
- * The available audio filters
7
- * @typedef {object} AudioFilters
8
- * @property {string} bassboost_low The bassboost filter (+15dB)
9
- * @property {string} bassboost The bassboost filter (+20dB)
10
- * @property {string} bassboost_high The bassboost filter (+30dB)
11
- * @property {string} 8D The 8D filter
12
- * @property {string} vaporwave The vaporwave filter
13
- * @property {string} nightcore The nightcore filter
14
- * @property {string} phaser The phaser filter
15
- * @property {string} tremolo The tremolo filter
16
- * @property {string} vibrato The vibrato filter
17
- * @property {string} reverse The reverse filter
18
- * @property {string} treble The treble filter
19
- * @property {string} normalizer The normalizer filter (dynamic audio normalizer based)
20
- * @property {string} normalizer2 The normalizer filter (audio compressor based)
21
- * @property {string} surrounding The surrounding filter
22
- * @property {string} pulsator The pulsator filter
23
- * @property {string} subboost The subboost filter
24
- * @property {string} karaoke The kakaoke filter
25
- * @property {string} flanger The flanger filter
26
- * @property {string} gate The gate filter
27
- * @property {string} haas The haas filter
28
- * @property {string} mcompand The mcompand filter
29
- * @property {string} mono The mono filter
30
- * @property {string} mstlr The mstlr filter
31
- * @property {string} mstrr The mstrr filter
32
- * @property {string} compressor The compressor filter
33
- * @property {string} expander The expander filter
34
- * @property {string} softlimiter The softlimiter filter
35
- * @property {string} chorus The chorus filter
36
- * @property {string} chorus2d The chorus2d filter
37
- * @property {string} chorus3d The chorus3d filter
38
- * @property {string} fadein The fadein filter
39
- * @property {string} dim The dim filter
40
- * @property {string} earrape The earrape filter
41
- */
42
- const FilterList = {
43
- bassboost_low: bass(15),
44
- bassboost: bass(20),
45
- bassboost_high: bass(30),
46
- "8D": "apulsator=hz=0.09",
47
- vaporwave: "aresample=48000,asetrate=48000*0.8",
48
- nightcore: "aresample=48000,asetrate=48000*1.25",
49
- phaser: "aphaser=in_gain=0.4",
50
- tremolo: "tremolo",
51
- vibrato: "vibrato=f=6.5",
52
- reverse: "areverse",
53
- treble: "treble=g=5",
54
- normalizer: "dynaudnorm=g=101",
55
- normalizer2: "acompressor",
56
- surrounding: "surround",
57
- pulsator: "apulsator=hz=1",
58
- subboost: "asubboost",
59
- karaoke: "stereotools=mlev=0.03",
60
- flanger: "flanger",
61
- gate: "agate",
62
- haas: "haas",
63
- mcompand: "mcompand",
64
- mono: "pan=mono|c0=.5*c0+.5*c1",
65
- mstlr: "stereotools=mode=ms>lr",
66
- mstrr: "stereotools=mode=ms>rr",
67
- compressor: "compand=points=-80/-105|-62/-80|-15.4/-15.4|0/-12|20/-7.6",
68
- expander: "compand=attacks=0:points=-80/-169|-54/-80|-49.5/-64.6|-41.1/-41.1|-25.8/-15|-10.8/-4.5|0/0|20/8.3",
69
- softlimiter: "compand=attacks=0:points=-80/-80|-12.4/-12.4|-6/-8|0/-6.8|20/-2.8",
70
- chorus: "chorus=0.7:0.9:55:0.4:0.25:2",
71
- chorus2d: "chorus=0.6:0.9:50|60:0.4|0.32:0.25|0.4:2|1.3",
72
- chorus3d: "chorus=0.5:0.9:50|60|40:0.4|0.32|0.3:0.25|0.4|0.3:2|2.3|1.3",
73
- fadein: "afade=t=in:ss=0:d=10",
74
- dim: `afftfilt="'real=re * (1-clip((b/nb)*b,0,1))':imag='im * (1-clip((b/nb)*b,0,1))'"`,
75
- earrape: "channelsplit,sidechaingate=level_in=64",
76
- *[Symbol.iterator]() {
5
+ class AudioFilters {
6
+ constructor() {
7
+ return AudioFilters;
8
+ }
9
+ static get filters() {
10
+ return {
11
+ bassboost_low: bass(15),
12
+ bassboost: bass(20),
13
+ bassboost_high: bass(30),
14
+ "8D": "apulsator=hz=0.09",
15
+ vaporwave: "aresample=48000,asetrate=48000*0.8",
16
+ nightcore: "aresample=48000,asetrate=48000*1.25",
17
+ phaser: "aphaser=in_gain=0.4",
18
+ tremolo: "tremolo",
19
+ vibrato: "vibrato=f=6.5",
20
+ reverse: "areverse",
21
+ treble: "treble=g=5",
22
+ normalizer2: "dynaudnorm=g=101",
23
+ normalizer: "acompressor",
24
+ surrounding: "surround",
25
+ pulsator: "apulsator=hz=1",
26
+ subboost: "asubboost",
27
+ karaoke: "stereotools=mlev=0.03",
28
+ flanger: "flanger",
29
+ gate: "agate",
30
+ haas: "haas",
31
+ mcompand: "mcompand",
32
+ mono: "pan=mono|c0=.5*c0+.5*c1",
33
+ mstlr: "stereotools=mode=ms>lr",
34
+ mstrr: "stereotools=mode=ms>rr",
35
+ compressor: "compand=points=-80/-105|-62/-80|-15.4/-15.4|0/-12|20/-7.6",
36
+ expander: "compand=attacks=0:points=-80/-169|-54/-80|-49.5/-64.6|-41.1/-41.1|-25.8/-15|-10.8/-4.5|0/0|20/8.3",
37
+ softlimiter: "compand=attacks=0:points=-80/-80|-12.4/-12.4|-6/-8|0/-6.8|20/-2.8",
38
+ chorus: "chorus=0.7:0.9:55:0.4:0.25:2",
39
+ chorus2d: "chorus=0.6:0.9:50|60:0.4|0.32:0.25|0.4:2|1.3",
40
+ chorus3d: "chorus=0.5:0.9:50|60|40:0.4|0.32|0.3:0.25|0.4|0.3:2|2.3|1.3",
41
+ fadein: "afade=t=in:ss=0:d=10",
42
+ dim: `afftfilt="'real=re * (1-clip((b/nb)*b,0,1))':imag='im * (1-clip((b/nb)*b,0,1))'"`,
43
+ earrape: "channelsplit,sidechaingate=level_in=64"
44
+ };
45
+ }
46
+ static get(name) {
47
+ return this.filters[name];
48
+ }
49
+ static has(name) {
50
+ return name in this.filters;
51
+ }
52
+ static *[Symbol.iterator]() {
77
53
  for (const [k, v] of Object.entries(this)) {
78
- if (typeof this[k] === "string")
54
+ if (typeof this.filters[k] === "string")
79
55
  yield { name: k, value: v };
80
56
  }
81
- },
82
- get names() {
83
- return Object.keys(this).filter((p) => !["names", "length"].includes(p) && typeof this[p] !== "function");
84
- },
85
- get length() {
86
- return Object.keys(this).filter((p) => !["names", "length"].includes(p) && typeof this[p] !== "function").length;
87
- },
88
- toString() {
57
+ }
58
+ static get names() {
59
+ return Object.keys(this).filter((p) => !["names", "length"].includes(p) && typeof this.filters[p] !== "function");
60
+ }
61
+ // @ts-expect-error AudioFilters.length
62
+ static get length() {
63
+ return Object.keys(this).filter((p) => !["names", "length"].includes(p) && typeof this.filters[p] !== "function").length;
64
+ }
65
+ static toString() {
89
66
  return this.names.map((m) => this[m]).join(","); // eslint-disable-line @typescript-eslint/no-explicit-any
90
- },
91
- create(filter) {
92
- if (!filter || !Array.isArray(filter))
67
+ }
68
+ /**
69
+ * Create ffmpeg args from the specified filters name
70
+ * @param filter The filter name
71
+ * @returns
72
+ */
73
+ static create(filters) {
74
+ if (!filters || !Array.isArray(filters))
93
75
  return this.toString();
94
- return filter
76
+ return filters
95
77
  .filter((predicate) => typeof predicate === "string")
96
- .map((m) => this[m])
78
+ .map((m) => this.get(m))
97
79
  .join(",");
98
- },
99
- define(filterName, value) {
100
- if (typeof this[filterName] && typeof this[filterName] === "function")
101
- return;
102
- this[filterName] = value;
103
- },
104
- defineBulk(filterArray) {
105
- filterArray.forEach((arr) => this.define(arr.name, arr.value));
106
80
  }
107
- };
108
- exports.AudioFilters = FilterList;
109
- exports.default = FilterList;
81
+ /**
82
+ * Defines audio filter
83
+ * @param filterName The name of the filter
84
+ * @param value The ffmpeg args
85
+ */
86
+ static define(filterName, value) {
87
+ this.filters[filterName] = value;
88
+ }
89
+ /**
90
+ * Defines multiple audio filters
91
+ * @param filtersArray Array of filters containing the filter name and ffmpeg args
92
+ */
93
+ static defineBulk(filtersArray) {
94
+ filtersArray.forEach((arr) => this.define(arr.name, arr.value));
95
+ }
96
+ }
97
+ exports.AudioFilters = AudioFilters;
98
+ exports.default = AudioFilters;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createFFmpegStream = exports.FFMPEG_ARGS_PIPED = exports.FFMPEG_ARGS_STRING = void 0;
4
+ const prism_media_1 = require("prism-media");
5
+ function FFMPEG_ARGS_STRING(stream, fmt) {
6
+ // prettier-ignore
7
+ return [
8
+ "-reconnect", "1",
9
+ "-reconnect_streamed", "1",
10
+ "-reconnect_delay_max", "5",
11
+ "-i", stream,
12
+ "-analyzeduration", "0",
13
+ "-loglevel", "0",
14
+ "-f", `${typeof fmt === "string" ? fmt : "s16le"}`,
15
+ "-ar", "48000",
16
+ "-ac", "2"
17
+ ];
18
+ }
19
+ exports.FFMPEG_ARGS_STRING = FFMPEG_ARGS_STRING;
20
+ function FFMPEG_ARGS_PIPED(fmt) {
21
+ // prettier-ignore
22
+ return [
23
+ "-analyzeduration", "0",
24
+ "-loglevel", "0",
25
+ "-f", `${typeof fmt === "string" ? fmt : "s16le"}`,
26
+ "-ar", "48000",
27
+ "-ac", "2"
28
+ ];
29
+ }
30
+ exports.FFMPEG_ARGS_PIPED = FFMPEG_ARGS_PIPED;
31
+ /**
32
+ * Creates FFmpeg stream
33
+ * @param stream The source stream
34
+ * @param options FFmpeg stream options
35
+ */
36
+ function createFFmpegStream(stream, options) {
37
+ if (options.skip && typeof stream !== "string")
38
+ return stream;
39
+ options ?? (options = {});
40
+ const args = typeof stream === "string" ? FFMPEG_ARGS_STRING(stream, options.fmt) : FFMPEG_ARGS_PIPED(options.fmt);
41
+ if (!Number.isNaN(options.seek))
42
+ args.unshift("-ss", String(options.seek));
43
+ if (Array.isArray(options.encoderArgs))
44
+ args.push(...options.encoderArgs);
45
+ const transcoder = new prism_media_1.FFmpeg({ shell: false, args });
46
+ transcoder.on("close", () => transcoder.destroy());
47
+ if (typeof stream !== "string") {
48
+ stream.on("error", () => transcoder.destroy());
49
+ stream.pipe(transcoder);
50
+ }
51
+ return transcoder;
52
+ }
53
+ exports.createFFmpegStream = createFFmpegStream;
@@ -112,11 +112,21 @@ class Util {
112
112
  static async getFetch() {
113
113
  if ("fetch" in globalThis)
114
114
  return globalThis.fetch;
115
- try {
116
- return await Promise.resolve().then(() => __importStar(require("undici"))).then((res) => res.default);
117
- }
118
- catch {
119
- // uh?
115
+ for (const lib of ["undici", "node-fetch"]) {
116
+ try {
117
+ return await Promise.resolve().then(() => __importStar(require(lib))).then((res) => res.fetch || res.default?.fetch || res.default);
118
+ }
119
+ catch {
120
+ try {
121
+ // eslint-disable-next-line
122
+ const res = require(lib);
123
+ if (res)
124
+ return res.fetch || res.default?.fetch || res.default;
125
+ }
126
+ catch {
127
+ // no?
128
+ }
129
+ }
120
130
  }
121
131
  }
122
132
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discord-player",
3
- "version": "5.3.0-dev.0",
3
+ "version": "5.3.0-dev.3",
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",
@@ -66,7 +66,6 @@
66
66
  "homepage": "https://discord-player.js.org",
67
67
  "dependencies": {
68
68
  "@discordjs/voice": "^0.11.0",
69
- "discord-ytdl-core": "^5.0.4",
70
69
  "libsodium-wrappers": "^0.7.10",
71
70
  "soundcloud-scraper": "^5.0.3",
72
71
  "spotify-url-info": "^3.1.2",