distube 4.1.1 → 4.2.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/index.js CHANGED
@@ -60,10 +60,10 @@ var __privateMethod = (obj, member, method) => {
60
60
 
61
61
  // package.json
62
62
  var require_package = __commonJS({
63
- "package.json"(exports, module2) {
63
+ "package.json"(exports2, module2) {
64
64
  module2.exports = {
65
65
  name: "distube",
66
- version: "4.1.1",
66
+ version: "4.2.0",
67
67
  description: "A Discord.js module to simplify your music commands and play songs with audio filters on Discord without any API key.",
68
68
  main: "./dist/index.js",
69
69
  types: "./dist/index.d.ts",
@@ -77,16 +77,16 @@ var require_package = __commonJS({
77
77
  ],
78
78
  scripts: {
79
79
  test: "jest",
80
- docs: "docgen -s src/**/*.ts -o docs.json -c pages/index.yml -g -j jsdoc.config.json",
80
+ docs: "typedoc",
81
81
  lint: "prettier --check . && eslint .",
82
82
  "lint:fix": "eslint . --fix",
83
83
  prettier: 'prettier --write "**/*.{ts,json,yml,yaml,md}"',
84
84
  build: "tsup",
85
85
  "build:check": "tsc --noEmit",
86
- update: "ncu -u && yarn up '**' -R",
87
- postinstall: "husky install",
88
- prepublishOnly: "yarn lint && yarn test",
89
- prepack: "yarn build && pinst --disable",
86
+ update: "pnpm up -L",
87
+ postinstall: "husky",
88
+ prepublishOnly: "pnpm run lint && pnpm run test",
89
+ prepack: "pnpm run build && pinst --disable",
90
90
  postpack: "pinst --enable",
91
91
  "dev:add-docs-to-worktree": "git worktree add --track -b docs docs origin/docs"
92
92
  },
@@ -112,70 +112,50 @@ var require_package = __commonJS({
112
112
  bugs: {
113
113
  url: "https://github.com/skick1234/DisTube/issues"
114
114
  },
115
- funding: [
116
- {
117
- type: "individual",
118
- url: "https://paypal.me/Skickkk"
119
- },
120
- {
121
- type: "patreon",
122
- url: "https://patreon.com/DisTube"
123
- }
124
- ],
115
+ funding: "https://github.com/skick1234/DisTube?sponsor=1",
125
116
  homepage: "https://distube.js.org/",
126
117
  dependencies: {
127
- "@distube/ytdl-core": "^4.13.2",
118
+ "@distube/ytdl-core": "^4.13.3",
128
119
  "@distube/ytpl": "^1.2.1",
129
- "@distube/ytsr": "^1.2.0",
130
- "prism-media": "npm:@distube/prism-media@latest",
120
+ "@distube/ytsr": "^2.0.0",
131
121
  "tiny-typed-emitter": "^2.1.0",
132
122
  "tough-cookie": "^4.1.3",
133
123
  tslib: "^2.6.2",
134
- undici: "^5.27.2"
124
+ undici: "^6.13.0"
135
125
  },
136
126
  devDependencies: {
137
- "@babel/core": "^7.23.2",
138
- "@babel/plugin-proposal-class-properties": "^7.18.6",
139
- "@babel/plugin-proposal-object-rest-spread": "^7.20.7",
140
- "@babel/plugin-transform-private-methods": "^7.22.5",
141
- "@babel/preset-env": "^7.23.2",
142
- "@babel/preset-typescript": "^7.23.2",
143
- "@commitlint/cli": "^18.2.0",
144
- "@commitlint/config-conventional": "^18.1.0",
145
- "@discordjs/voice": "^0.16.0",
146
- "@distubejs/docgen": "distubejs/docgen",
147
- "@types/jest": "^29.5.8",
148
- "@types/node": "^20.9.0",
127
+ "@babel/core": "^7.24.4",
128
+ "@babel/plugin-transform-class-properties": "^7.24.1",
129
+ "@babel/plugin-transform-object-rest-spread": "^7.24.1",
130
+ "@babel/plugin-transform-private-methods": "^7.24.1",
131
+ "@babel/preset-env": "^7.24.4",
132
+ "@babel/preset-typescript": "^7.24.1",
133
+ "@commitlint/cli": "^19.2.2",
134
+ "@commitlint/config-conventional": "^19.2.2",
135
+ "@discordjs/voice": "^0.16.1",
136
+ "@types/jest": "^29.5.12",
137
+ "@types/node": "^20.12.7",
149
138
  "@types/tough-cookie": "^4.0.5",
150
- "@typescript-eslint/eslint-plugin": "^6.10.0",
151
- "@typescript-eslint/parser": "^6.10.0",
139
+ "@typescript-eslint/eslint-plugin": "^7.7.0",
140
+ "@typescript-eslint/parser": "^7.7.0",
152
141
  "babel-jest": "^29.7.0",
153
- "discord.js": "^14.13.0",
154
- eslint: "^8.53.0",
155
- "eslint-config-distube": "^1.6.4",
156
- "eslint-config-prettier": "^9.0.0",
157
- "eslint-plugin-deprecation": "^2.0.0",
158
- "eslint-plugin-jsdoc": "^46.8.2",
159
- husky: "^8.0.3",
142
+ "discord.js": "^14.14.1",
143
+ eslint: "^8.57.0",
144
+ "eslint-config-distube": "^1.7.0",
145
+ husky: "^9.0.11",
160
146
  jest: "^29.7.0",
161
- "jsdoc-babel": "^0.5.0",
162
147
  "nano-staged": "^0.8.0",
163
- "npm-check-updates": "^16.14.6",
164
148
  pinst: "^3.0.0",
165
- prettier: "^3.0.3",
166
- tsup: "^7.2.0",
167
- typescript: "^5.2.2"
149
+ prettier: "^3.2.5",
150
+ tsup: "^8.0.2",
151
+ typedoc: "^0.25.13",
152
+ "typedoc-material-theme": "^1.0.2",
153
+ typescript: "^5.4.5"
168
154
  },
169
155
  peerDependencies: {
170
- "@discordjs/opus": "*",
171
156
  "@discordjs/voice": "*",
172
157
  "discord.js": "14"
173
158
  },
174
- peerDependenciesMeta: {
175
- "@discordjs/opus": {
176
- optional: true
177
- }
178
- },
179
159
  "nano-staged": {
180
160
  "*.ts": [
181
161
  "prettier --write",
@@ -186,9 +166,8 @@ var require_package = __commonJS({
186
166
  ]
187
167
  },
188
168
  engines: {
189
- node: ">=16.9.0"
190
- },
191
- packageManager: "yarn@3.6.1"
169
+ node: ">=18.17"
170
+ }
192
171
  };
193
172
  }
194
173
  });
@@ -290,6 +269,7 @@ var Events = /* @__PURE__ */ ((Events2) => {
290
269
  Events2["SEARCH_DONE"] = "searchDone";
291
270
  Events2["SEARCH_INVALID_ANSWER"] = "searchInvalidAnswer";
292
271
  Events2["SEARCH_RESULT"] = "searchResult";
272
+ Events2["FFMPEG_DEBUG"] = "ffmpegDebug";
293
273
  return Events2;
294
274
  })(Events || {});
295
275
 
@@ -327,7 +307,12 @@ var defaultOptions = {
327
307
  emitAddListWhenCreatingQueue: true,
328
308
  joinNewVoiceChannel: true,
329
309
  streamType: 0 /* OPUS */,
330
- directLink: true
310
+ directLink: true,
311
+ ffmpegPath: "ffmpeg",
312
+ ffmpegDefaultArgs: {
313
+ analyzeduration: 0,
314
+ hide_banner: true
315
+ }
331
316
  };
332
317
 
333
318
  // src/struct/DisTubeError.ts
@@ -411,15 +396,13 @@ var _TaskQueue = class _TaskQueue {
411
396
  constructor() {
412
397
  /**
413
398
  * The task array
414
- * @type {Task[]}
415
- * @private
416
399
  */
417
400
  __privateAdd(this, _tasks, []);
418
401
  }
419
402
  /**
420
403
  * Waits for last task finished and queues a new task
421
- * @param {boolean} [resolveInfo=false] Whether the task is a resolving info task
422
- * @returns {Promise<void>}
404
+ *
405
+ * @param resolveInfo - Whether the task is a resolving info task
423
406
  */
424
407
  queuing(resolveInfo = false) {
425
408
  const next = this.remaining ? __privateGet(this, _tasks)[__privateGet(this, _tasks).length - 1].promise : Promise.resolve();
@@ -434,14 +417,12 @@ var _TaskQueue = class _TaskQueue {
434
417
  }
435
418
  /**
436
419
  * The remaining number of tasks
437
- * @type {number}
438
420
  */
439
421
  get remaining() {
440
422
  return __privateGet(this, _tasks).length;
441
423
  }
442
424
  /**
443
425
  * Whether or not having a resolving info task
444
- * @type {boolean}
445
426
  */
446
427
  get hasResolveTask() {
447
428
  return __privateGet(this, _tasks).some((t) => t.resolveInfo);
@@ -456,11 +437,9 @@ var _metadata, _member;
456
437
  var _Playlist = class _Playlist {
457
438
  /**
458
439
  * Create a playlist
459
- * @param {Song[]|PlaylistInfo} playlist Playlist
460
- * @param {Object} [options] Optional options
461
- * @param {Discord.GuildMember} [options.member] Requested user
462
- * @param {Object} [options.properties] Custom properties
463
- * @param {T} [options.metadata] Playlist metadata
440
+ *
441
+ * @param playlist - Playlist
442
+ * @param options - Optional options
464
443
  */
465
444
  constructor(playlist, options = {}) {
466
445
  __publicField(this, "source");
@@ -504,21 +483,18 @@ var _Playlist = class _Playlist {
504
483
  }
505
484
  /**
506
485
  * Playlist duration in second.
507
- * @type {number}
508
486
  */
509
487
  get duration() {
510
488
  return this.songs.reduce((prev, next) => prev + next.duration, 0);
511
489
  }
512
490
  /**
513
491
  * Formatted duration string `hh:mm:ss`.
514
- * @type {string}
515
492
  */
516
493
  get formattedDuration() {
517
494
  return formatDuration(this.duration);
518
495
  }
519
496
  /**
520
497
  * User requested.
521
- * @type {Discord.GuildMember?}
522
498
  */
523
499
  get member() {
524
500
  return __privateGet(this, _member);
@@ -531,7 +507,6 @@ var _Playlist = class _Playlist {
531
507
  }
532
508
  /**
533
509
  * User requested.
534
- * @type {Discord.User?}
535
510
  */
536
511
  get user() {
537
512
  return this.member?.user;
@@ -553,7 +528,8 @@ var Playlist = _Playlist;
553
528
  var _ISearchResult = class _ISearchResult {
554
529
  /**
555
530
  * Create a search result
556
- * @param {Object} info ytsr result
531
+ *
532
+ * @param info - ytsr result
557
533
  */
558
534
  constructor(info) {
559
535
  __publicField(this, "source");
@@ -621,11 +597,9 @@ var _metadata2, _member2, _playlist;
621
597
  var _Song = class _Song {
622
598
  /**
623
599
  * Create a Song
624
- * @param {ytdl.videoInfo|SearchResult|OtherSongInfo} info Raw info
625
- * @param {Object} [options] Optional options
626
- * @param {Discord.GuildMember} [options.member] Requested user
627
- * @param {string} [options.source="youtube"] Song source
628
- * @param {T} [options.metadata] Song metadata
600
+ *
601
+ * @param info - Raw info
602
+ * @param options - Optional options
629
603
  */
630
604
  constructor(info, options = {}) {
631
605
  __publicField(this, "source");
@@ -702,8 +676,8 @@ var _Song = class _Song {
702
676
  }
703
677
  /**
704
678
  * Patch data from other source
705
- * @param {OtherSongInfo} info Video info
706
- * @private
679
+ *
680
+ * @param info - Video info
707
681
  */
708
682
  _patchOther(info) {
709
683
  this.id = info.id;
@@ -737,7 +711,6 @@ var _Song = class _Song {
737
711
  }
738
712
  /**
739
713
  * The playlist added this song
740
- * @type {Playlist?}
741
714
  */
742
715
  get playlist() {
743
716
  return __privateGet(this, _playlist);
@@ -750,7 +723,6 @@ var _Song = class _Song {
750
723
  }
751
724
  /**
752
725
  * User requested.
753
- * @type {Discord.GuildMember?}
754
726
  */
755
727
  get member() {
756
728
  return __privateGet(this, _member2);
@@ -761,7 +733,6 @@ var _Song = class _Song {
761
733
  }
762
734
  /**
763
735
  * User requested.
764
- * @type {Discord.User?}
765
736
  */
766
737
  get user() {
767
738
  return this.member?.user;
@@ -787,57 +758,48 @@ var _DisTubeBase = class _DisTubeBase {
787
758
  }
788
759
  /**
789
760
  * Emit the {@link DisTube} of this base
790
- * @param {string} eventName Event name
791
- * @param {...any} args arguments
792
- * @returns {boolean}
761
+ *
762
+ * @param eventName - Event name
763
+ * @param args - arguments
793
764
  */
794
765
  emit(eventName, ...args) {
795
766
  return this.distube.emit(eventName, ...args);
796
767
  }
797
768
  /**
798
769
  * Emit error event
799
- * @param {Error} error error
800
- * @param {Discord.BaseGuildTextChannel} [channel] Text channel where the error is encountered.
770
+ *
771
+ * @param error - error
772
+ * @param channel - Text channel where the error is encountered.
801
773
  */
802
774
  emitError(error, channel) {
803
775
  this.distube.emitError(error, channel);
804
776
  }
805
777
  /**
806
778
  * The queue manager
807
- * @type {QueueManager}
808
- * @readonly
809
779
  */
810
780
  get queues() {
811
781
  return this.distube.queues;
812
782
  }
813
783
  /**
814
784
  * The voice manager
815
- * @type {DisTubeVoiceManager}
816
- * @readonly
817
785
  */
818
786
  get voices() {
819
787
  return this.distube.voices;
820
788
  }
821
789
  /**
822
790
  * Discord.js client
823
- * @type {Discord.Client}
824
- * @readonly
825
791
  */
826
792
  get client() {
827
793
  return this.distube.client;
828
794
  }
829
795
  /**
830
796
  * DisTube options
831
- * @type {DisTubeOptions}
832
- * @readonly
833
797
  */
834
798
  get options() {
835
799
  return this.distube.options;
836
800
  }
837
801
  /**
838
802
  * DisTube handler
839
- * @type {DisTubeHandler}
840
- * @readonly
841
803
  */
842
804
  get handler() {
843
805
  return this.distube.handler;
@@ -863,6 +825,7 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
863
825
  __publicField(this, "audioResource");
864
826
  __publicField(this, "emittedError");
865
827
  __publicField(this, "isDisconnected", false);
828
+ __publicField(this, "stream");
866
829
  __privateAdd(this, _channel, void 0);
867
830
  __privateAdd(this, _volume, 100);
868
831
  this.voices = voiceManager;
@@ -906,7 +869,6 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
906
869
  }
907
870
  /**
908
871
  * The voice channel id the bot is in
909
- * @type {Snowflake?}
910
872
  */
911
873
  get channelId() {
912
874
  return this.connection?.joinConfig?.channelId ?? void 0;
@@ -949,8 +911,8 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
949
911
  }
950
912
  /**
951
913
  * Join a voice channel with this connection
952
- * @param {Discord.BaseGuildVoiceChannel} [channel] A voice channel
953
- * @returns {Promise<DisTubeVoice>}
914
+ *
915
+ * @param channel - A voice channel
954
916
  */
955
917
  async join(channel) {
956
918
  const TIMEOUT = 3e4;
@@ -970,7 +932,8 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
970
932
  }
971
933
  /**
972
934
  * Leave the voice channel of this connection
973
- * @param {Error} [error] Optional, an error to emit with 'error' event.
935
+ *
936
+ * @param error - Optional, an error to emit with 'error' event.
974
937
  */
975
938
  leave(error) {
976
939
  this.stop(true);
@@ -984,33 +947,36 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
984
947
  }
985
948
  /**
986
949
  * Stop the playing stream
987
- * @param {boolean} [force=false] If true, will force the {@link DisTubeVoice#audioPlayer} to enter the Idle state
988
- * even if the {@link DisTubeVoice#audioResource} has silence padding frames.
989
- * @private
950
+ *
951
+ * @param force - If true, will force the {@link DisTubeVoice#audioPlayer} to enter the Idle state even
952
+ * if the {@link DisTubeVoice#audioResource} has silence padding frames.
990
953
  */
991
954
  stop(force = false) {
992
955
  this.audioPlayer.stop(force);
956
+ this.stream?.kill?.();
993
957
  }
994
958
  /**
995
- * Play a readable stream
996
- * @private
997
- * @param {DisTubeStream} stream Readable stream
959
+ * Play a {@link DisTubeStream}
960
+ *
961
+ * @param dtStream - DisTubeStream
998
962
  */
999
- play(stream) {
963
+ play(dtStream) {
1000
964
  this.emittedError = false;
1001
- stream.stream.on("error", (error) => {
965
+ dtStream.stream.on("error", (error) => {
1002
966
  if (this.emittedError || error.code === "ERR_STREAM_PREMATURE_CLOSE")
1003
967
  return;
1004
968
  this.emittedError = true;
1005
969
  this.emit("error", error);
1006
970
  });
1007
- this.audioResource = (0, import_voice.createAudioResource)(stream.stream, {
1008
- inputType: stream.type,
971
+ this.audioResource = (0, import_voice.createAudioResource)(dtStream.stream, {
972
+ inputType: dtStream.type,
1009
973
  inlineVolume: true
1010
974
  });
1011
975
  this.volume = __privateGet(this, _volume);
1012
976
  if (this.audioPlayer.state.status !== import_voice.AudioPlayerStatus.Paused)
1013
977
  this.audioPlayer.play(this.audioResource);
978
+ this.stream?.kill?.();
979
+ this.stream = dtStream;
1014
980
  }
1015
981
  set volume(volume) {
1016
982
  if (typeof volume !== "number" || isNaN(volume)) {
@@ -1027,7 +993,6 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
1027
993
  }
1028
994
  /**
1029
995
  * Playback duration of the audio resource in seconds
1030
- * @type {number}
1031
996
  */
1032
997
  get playbackDuration() {
1033
998
  return (this.audioResource?.playbackDuration ?? 0) / 1e3;
@@ -1046,22 +1011,22 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
1046
1011
  }
1047
1012
  /**
1048
1013
  * Whether the bot is self-deafened
1049
- * @type {boolean}
1050
1014
  */
1051
1015
  get selfDeaf() {
1052
1016
  return this.connection.joinConfig.selfDeaf;
1053
1017
  }
1054
1018
  /**
1055
1019
  * Whether the bot is self-muted
1056
- * @type {boolean}
1057
1020
  */
1058
1021
  get selfMute() {
1059
1022
  return this.connection.joinConfig.selfMute;
1060
1023
  }
1061
1024
  /**
1062
1025
  * Self-deafens/undeafens the bot.
1063
- * @param {boolean} selfDeaf Whether or not the bot should be self-deafened
1064
- * @returns {boolean} true if the voice state was successfully updated, otherwise false
1026
+ *
1027
+ * @param selfDeaf - Whether or not the bot should be self-deafened
1028
+ *
1029
+ * @returns true if the voice state was successfully updated, otherwise false
1065
1030
  */
1066
1031
  setSelfDeaf(selfDeaf) {
1067
1032
  if (typeof selfDeaf !== "boolean") {
@@ -1074,8 +1039,10 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
1074
1039
  }
1075
1040
  /**
1076
1041
  * Self-mutes/unmutes the bot.
1077
- * @param {boolean} selfMute Whether or not the bot should be self-muted
1078
- * @returns {boolean} true if the voice state was successfully updated, otherwise false
1042
+ *
1043
+ * @param selfMute - Whether or not the bot should be self-muted
1044
+ *
1045
+ * @returns true if the voice state was successfully updated, otherwise false
1079
1046
  */
1080
1047
  setSelfMute(selfMute) {
1081
1048
  if (typeof selfMute !== "boolean") {
@@ -1088,7 +1055,6 @@ var _DisTubeVoice = class _DisTubeVoice extends import_tiny_typed_emitter.TypedE
1088
1055
  }
1089
1056
  /**
1090
1057
  * The voice state of this connection
1091
- * @type {Discord.VoiceState?}
1092
1058
  */
1093
1059
  get voiceState() {
1094
1060
  return this.channel?.guild?.members?.me?.voice;
@@ -1114,60 +1080,94 @@ __name(_DisTubeVoice, "DisTubeVoice");
1114
1080
  var DisTubeVoice = _DisTubeVoice;
1115
1081
 
1116
1082
  // src/core/DisTubeStream.ts
1117
- var import_prism_media = require("prism-media");
1083
+ var import_child_process = require("child_process");
1084
+ var import_node_stream = require("stream");
1085
+ var import_tiny_typed_emitter2 = require("tiny-typed-emitter");
1118
1086
  var import_voice2 = require("@discordjs/voice");
1119
1087
  var chooseBestVideoFormat = /* @__PURE__ */ __name(({ duration, formats, isLive }) => formats && formats.filter((f) => f.hasAudio && (duration < 10 * 60 || f.hasVideo) && (!isLive || f.isHLS)).sort((a, b) => Number(b.audioBitrate) - Number(a.audioBitrate) || Number(a.bitrate) - Number(b.bitrate))[0], "chooseBestVideoFormat");
1120
- var _DisTubeStream = class _DisTubeStream {
1088
+ var _DisTubeStream = class _DisTubeStream extends import_tiny_typed_emitter2.TypedEmitter {
1121
1089
  /**
1122
1090
  * Create a DisTubeStream to play with {@link DisTubeVoice}
1123
- * @param {string} url Stream URL
1124
- * @param {StreamOptions} options Stream options
1125
- * @private
1091
+ *
1092
+ * @param url - Stream URL
1093
+ * @param options - Stream options
1126
1094
  */
1127
- constructor(url, options) {
1128
- __publicField(this, "type");
1095
+ constructor(url, { ffmpeg, seek, type }) {
1096
+ super();
1097
+ __publicField(this, "killed", false);
1098
+ __publicField(this, "process");
1129
1099
  __publicField(this, "stream");
1100
+ __publicField(this, "type");
1130
1101
  __publicField(this, "url");
1131
1102
  this.url = url;
1132
- this.type = !options.type ? import_voice2.StreamType.OggOpus : import_voice2.StreamType.Raw;
1133
- const args = [
1134
- "-reconnect",
1135
- "1",
1136
- "-reconnect_streamed",
1137
- "1",
1138
- "-reconnect_delay_max",
1139
- "5",
1140
- "-i",
1141
- url,
1142
- "-analyzeduration",
1143
- "0",
1144
- "-loglevel",
1145
- "0",
1146
- "-ar",
1147
- "48000",
1148
- "-ac",
1149
- "2",
1150
- "-f"
1151
- ];
1152
- if (!options.type)
1153
- args.push("opus", "-acodec", "libopus");
1154
- else
1155
- args.push("s16le");
1156
- if (typeof options.seek === "number" && options.seek > 0)
1157
- args.unshift("-ss", options.seek.toString());
1158
- if (Array.isArray(options.ffmpegArgs) && options.ffmpegArgs.length)
1159
- args.push(...options.ffmpegArgs);
1160
- this.stream = new import_prism_media.FFmpeg({ args, shell: false });
1161
- this.stream._readableState && (this.stream._readableState.highWaterMark = 1 << 25);
1162
- }
1163
- /**
1164
- * Create a stream from ytdl video formats
1165
- * @param {Song} song A YouTube Song
1166
- * @param {StreamOptions} options options
1167
- * @returns {DisTubeStream}
1168
- * @private
1169
- */
1170
- static YouTube(song, options = {}) {
1103
+ this.type = !type ? import_voice2.StreamType.OggOpus : import_voice2.StreamType.Raw;
1104
+ const opts = {
1105
+ reconnect: 1,
1106
+ reconnect_on_network_error: 1,
1107
+ reconnect_streamed: 1,
1108
+ reconnect_delay_max: 5,
1109
+ i: url,
1110
+ ar: 48e3,
1111
+ ac: 2,
1112
+ ...ffmpeg.args
1113
+ };
1114
+ if (!type) {
1115
+ opts.f = "opus";
1116
+ opts.acodec = "libopus";
1117
+ } else {
1118
+ opts.f = "s16le";
1119
+ }
1120
+ if (typeof seek === "number" && seek > 0)
1121
+ opts.ss = seek.toString();
1122
+ if (typeof ffmpeg.args === "object")
1123
+ Object.assign(opts, ffmpeg.args);
1124
+ this.process = (0, import_child_process.spawn)(
1125
+ ffmpeg.path,
1126
+ [
1127
+ ...Object.entries(opts).flatMap(
1128
+ ([key, value]) => Array.isArray(value) ? value.filter(Boolean).map((v) => [`-${key}`, String(v)]) : value == null || value === false ? [] : [value === true ? `-${key}` : [`-${key}`, String(value)]]
1129
+ ).flat(),
1130
+ "pipe:1"
1131
+ ],
1132
+ { stdio: ["ignore", "pipe", "pipe"] }
1133
+ ).on("error", (err) => this.debug(`[process] error: ${err.message}`)).on("exit", (code, signal) => {
1134
+ this.debug(`[process] exit: code=${code ?? "unknown"} signal=${signal ?? "unknown"}`);
1135
+ if (!code || [0, 255].includes(code))
1136
+ return;
1137
+ this.debug(`[process] error: ffmpeg exited with code ${code}`);
1138
+ });
1139
+ if (!this.process.stdout || !this.process.stderr) {
1140
+ this.kill();
1141
+ throw new Error("Failed to create ffmpeg process");
1142
+ }
1143
+ this.stream = new import_node_stream.PassThrough();
1144
+ this.stream.on("close", () => this.kill()).on("error", (err) => this.debug(`[stream] error: ${err.message}`)).on("finish", () => this.debug("[stream] log: stream finished"));
1145
+ this.process.stdout.pipe(this.stream);
1146
+ this.process.stderr.setEncoding("utf8")?.on("data", (data) => {
1147
+ const lines = data.split(/\r\n|\r|\n/u);
1148
+ for (const line of lines) {
1149
+ if (/^\s*$/.test(line))
1150
+ continue;
1151
+ this.debug(`[ffmpeg] log: ${line}`);
1152
+ }
1153
+ });
1154
+ }
1155
+ debug(debug) {
1156
+ this.emit("debug", debug);
1157
+ }
1158
+ kill() {
1159
+ if (this.killed)
1160
+ return;
1161
+ this.process.kill("SIGKILL");
1162
+ this.killed = true;
1163
+ }
1164
+ /**
1165
+ * Create a stream from a YouTube {@link Song}
1166
+ *
1167
+ * @param song - A YouTube Song
1168
+ * @param options - options
1169
+ */
1170
+ static YouTube(song, options) {
1171
1171
  if (song.source !== "youtube")
1172
1172
  throw new DisTubeError("INVALID_TYPE", "youtube", song.source, "Song#source");
1173
1173
  if (!song.formats?.length)
@@ -1182,18 +1182,17 @@ var _DisTubeStream = class _DisTubeStream {
1182
1182
  }
1183
1183
  /**
1184
1184
  * Create a stream from a stream url
1185
- * @param {string} url stream url
1186
- * @param {StreamOptions} options options
1187
- * @returns {DisTubeStream}
1188
- * @private
1185
+ *
1186
+ * @param url - stream url
1187
+ * @param options - options
1189
1188
  */
1190
- static DirectLink(url, options = {}) {
1191
- if (!options || typeof options !== "object" || Array.isArray(options)) {
1192
- throw new DisTubeError("INVALID_TYPE", "object", options, "options");
1193
- }
1189
+ static DirectLink(url, options) {
1194
1190
  if (typeof url !== "string" || !isURL(url)) {
1195
1191
  throw new DisTubeError("INVALID_TYPE", "an URL", url);
1196
1192
  }
1193
+ if (!options || typeof options !== "object" || Array.isArray(options)) {
1194
+ throw new DisTubeError("INVALID_TYPE", "object", options, "options");
1195
+ }
1197
1196
  return new _DisTubeStream(url, options);
1198
1197
  }
1199
1198
  };
@@ -1233,7 +1232,7 @@ var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
1233
1232
  delete queue._emptyTimeout;
1234
1233
  if (isVoiceChannelEmpty(oldState)) {
1235
1234
  queue.voice.leave();
1236
- this.emit("empty", queue);
1235
+ this.emit("empty" /* EMPTY */, queue);
1237
1236
  if (queue.stopped)
1238
1237
  queue.remove();
1239
1238
  }
@@ -1267,9 +1266,8 @@ var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
1267
1266
  return jar.getCookieStringSync("https://www.youtube.com");
1268
1267
  }
1269
1268
  /**
1270
- * @param {string} url url
1271
- * @param {boolean} [basic=false] getBasicInfo?
1272
- * @returns {Promise<ytdl.videoInfo>}
1269
+ * @param url - url
1270
+ * @param basic - getBasicInfo?
1273
1271
  */
1274
1272
  getYouTubeInfo(url, basic = false) {
1275
1273
  if (basic)
@@ -1278,10 +1276,13 @@ var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
1278
1276
  }
1279
1277
  /**
1280
1278
  * Resolve a url or a supported object to a {@link Song} or {@link Playlist}
1281
- * @param {string|Song|SearchResult|Playlist} song URL | {@link Song}| {@link SearchResult} | {@link Playlist}
1282
- * @param {ResolveOptions} [options] Optional options
1283
- * @returns {Promise<Song|Playlist|null>} Resolved
1284
- * @throws {DisTubeError}
1279
+ *
1280
+ * @throws {@link DisTubeError}
1281
+ *
1282
+ * @param song - URL | {@link Song}| {@link SearchResult} | {@link Playlist}
1283
+ * @param options - Optional options
1284
+ *
1285
+ * @returns Resolved
1285
1286
  */
1286
1287
  async resolve(song, options = {}) {
1287
1288
  if (song instanceof Song || song instanceof Playlist) {
@@ -1315,9 +1316,9 @@ var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
1315
1316
  }
1316
1317
  /**
1317
1318
  * Resolve Song[] or YouTube playlist url to a Playlist
1318
- * @param {Playlist|Song[]|string} playlist Resolvable playlist
1319
- * @param {ResolvePlaylistOptions} options Optional options
1320
- * @returns {Promise<Playlist>}
1319
+ *
1320
+ * @param playlist - Resolvable playlist
1321
+ * @param options - Optional options
1321
1322
  */
1322
1323
  async resolvePlaylist(playlist, options = {}) {
1323
1324
  const { member, source, metadata } = { source: "youtube", ...options };
@@ -1346,11 +1347,14 @@ var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
1346
1347
  return new Playlist(playlist, { member, properties: { source }, metadata });
1347
1348
  }
1348
1349
  /**
1349
- * Search for a song, fire {@link DisTube#event:error} if not found.
1350
- * @param {Discord.Message} message The original message from an user
1351
- * @param {string} query The query string
1352
- * @returns {Promise<SearchResult?>} Song info
1353
- * @throws {DisTubeError}
1350
+ * Search for a song, fire {@link DisTube#error} if not found.
1351
+ *
1352
+ * @throws {@link DisTubeError}
1353
+ *
1354
+ * @param message - The original message from an user
1355
+ * @param query - The query string
1356
+ *
1357
+ * @returns Song info
1354
1358
  */
1355
1359
  async searchSong(message, query) {
1356
1360
  if (!isMessageInstance(message))
@@ -1364,7 +1368,7 @@ var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
1364
1368
  limit,
1365
1369
  safeSearch: this.options.nsfw ? false : !isNsfwChannel(message.channel)
1366
1370
  }).catch(() => {
1367
- if (!this.emit("searchNoResult", message, query)) {
1371
+ if (!this.emit("searchNoResult" /* SEARCH_NO_RESULT */, message, query)) {
1368
1372
  console.warn("searchNoResult event does not have any listeners! Emits `error` event instead.");
1369
1373
  throw new DisTubeError("NO_RESULT");
1370
1374
  }
@@ -1376,13 +1380,16 @@ var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
1376
1380
  /**
1377
1381
  * Create a message collector for selecting search results.
1378
1382
  *
1379
- * Needed events: {@link DisTube#event:searchResult}, {@link DisTube#event:searchCancel},
1380
- * {@link DisTube#event:searchInvalidAnswer}, {@link DisTube#event:searchDone}.
1381
- * @param {Discord.Message} message The original message from an user
1382
- * @param {Array<SearchResult|Song|Playlist>} results The search results
1383
- * @param {string?} [query] The query string
1384
- * @returns {Promise<SearchResult|Song|Playlist|null>} Selected result
1385
- * @throws {DisTubeError}
1383
+ * Needed events: {@link DisTube#searchResult}, {@link DisTube#searchCancel},
1384
+ * {@link DisTube#searchInvalidAnswer}, {@link DisTube#searchDone}.
1385
+ *
1386
+ * @throws {@link DisTubeError}
1387
+ *
1388
+ * @param message - The original message from an user
1389
+ * @param results - The search results
1390
+ * @param query - The query string
1391
+ *
1392
+ * @returns Selected result
1386
1393
  */
1387
1394
  async createSearchMessageCollector(message, results, query) {
1388
1395
  if (!isMessageInstance(message))
@@ -1392,11 +1399,11 @@ var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
1392
1399
  }
1393
1400
  if (this.options.searchSongs > 1) {
1394
1401
  const searchEvents = [
1395
- "searchNoResult",
1396
- "searchResult",
1397
- "searchCancel",
1398
- "searchInvalidAnswer",
1399
- "searchDone"
1402
+ "searchNoResult" /* SEARCH_NO_RESULT */,
1403
+ "searchResult" /* SEARCH_RESULT */,
1404
+ "searchCancel" /* SEARCH_CANCEL */,
1405
+ "searchInvalidAnswer" /* SEARCH_INVALID_ANSWER */,
1406
+ "searchDone" /* SEARCH_DONE */
1400
1407
  ];
1401
1408
  for (const evn of searchEvents) {
1402
1409
  if (this.distube.listenerCount(evn) === 0) {
@@ -1413,7 +1420,7 @@ var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
1413
1420
  let result = results[0];
1414
1421
  if (limit > 1) {
1415
1422
  results.splice(limit);
1416
- this.emit("searchResult", message, results, query);
1423
+ this.emit("searchResult" /* SEARCH_RESULT */, message, results, query);
1417
1424
  const answers = await message.channel.awaitMessages({
1418
1425
  filter: (m) => m.author.id === message.author.id,
1419
1426
  max: 1,
@@ -1422,26 +1429,27 @@ var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
1422
1429
  }).catch(() => void 0);
1423
1430
  const ans = answers?.first();
1424
1431
  if (!ans) {
1425
- this.emit("searchCancel", message, query);
1432
+ this.emit("searchCancel" /* SEARCH_CANCEL */, message, query);
1426
1433
  return null;
1427
1434
  }
1428
1435
  const index = parseInt(ans.content, 10);
1429
1436
  if (isNaN(index) || index > results.length || index < 1) {
1430
- this.emit("searchInvalidAnswer", message, ans, query);
1437
+ this.emit("searchInvalidAnswer" /* SEARCH_INVALID_ANSWER */, message, ans, query);
1431
1438
  return null;
1432
1439
  }
1433
- this.emit("searchDone", message, ans, query);
1440
+ this.emit("searchDone" /* SEARCH_DONE */, message, ans, query);
1434
1441
  result = results[index - 1];
1435
1442
  }
1436
1443
  return result;
1437
1444
  }
1438
1445
  /**
1439
1446
  * Play or add a {@link Playlist} to the queue.
1440
- * @param {Discord.BaseGuildVoiceChannel} voiceChannel A voice channel
1441
- * @param {Playlist|string} playlist A YouTube playlist url | a Playlist
1442
- * @param {PlayHandlerOptions} [options] Optional options
1443
- * @returns {Promise<void>}
1444
- * @throws {DisTubeError}
1447
+ *
1448
+ * @throws {@link DisTubeError}
1449
+ *
1450
+ * @param voiceChannel - A voice channel
1451
+ * @param playlist - A YouTube playlist url | a Playlist
1452
+ * @param options - Optional options
1445
1453
  */
1446
1454
  async playPlaylist(voiceChannel, playlist, options = {}) {
1447
1455
  const { textChannel, skip } = { skip: false, ...options };
@@ -1464,23 +1472,24 @@ var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
1464
1472
  if (skip)
1465
1473
  queue.skip();
1466
1474
  else
1467
- this.emit("addList", queue, playlist);
1475
+ this.emit("addList" /* ADD_LIST */, queue, playlist);
1468
1476
  } else {
1469
1477
  const newQueue = await this.queues.create(voiceChannel, playlist.songs, textChannel);
1470
1478
  if (newQueue instanceof Queue) {
1471
1479
  if (this.options.emitAddListWhenCreatingQueue)
1472
- this.emit("addList", newQueue, playlist);
1473
- this.emit("playSong", newQueue, newQueue.songs[0]);
1480
+ this.emit("addList" /* ADD_LIST */, newQueue, playlist);
1481
+ this.emit("playSong" /* PLAY_SONG */, newQueue, newQueue.songs[0]);
1474
1482
  }
1475
1483
  }
1476
1484
  }
1477
1485
  /**
1478
1486
  * Play or add a {@link Song} to the queue.
1479
- * @param {Discord.BaseGuildVoiceChannel} voiceChannel A voice channel
1480
- * @param {Song} song A YouTube playlist url | a Playlist
1481
- * @param {PlayHandlerOptions} [options] Optional options
1482
- * @returns {Promise<void>}
1483
- * @throws {DisTubeError}
1487
+ *
1488
+ * @throws {@link DisTubeError}
1489
+ *
1490
+ * @param voiceChannel - A voice channel
1491
+ * @param song - A YouTube playlist url | a Playlist
1492
+ * @param options - Optional options
1484
1493
  */
1485
1494
  async playSong(voiceChannel, song, options = {}) {
1486
1495
  if (!(song instanceof Song))
@@ -1498,27 +1507,26 @@ var _DisTubeHandler = class _DisTubeHandler extends DisTubeBase {
1498
1507
  if (skip)
1499
1508
  queue.skip();
1500
1509
  else
1501
- this.emit("addSong", queue, song);
1510
+ this.emit("addSong" /* ADD_SONG */, queue, song);
1502
1511
  } else {
1503
1512
  const newQueue = await this.queues.create(voiceChannel, song, textChannel);
1504
1513
  if (newQueue instanceof Queue) {
1505
1514
  if (this.options.emitAddSongWhenCreatingQueue)
1506
- this.emit("addSong", newQueue, song);
1507
- this.emit("playSong", newQueue, song);
1515
+ this.emit("addSong" /* ADD_SONG */, newQueue, song);
1516
+ this.emit("playSong" /* PLAY_SONG */, newQueue, song);
1508
1517
  }
1509
1518
  }
1510
1519
  }
1511
1520
  /**
1512
1521
  * Get {@link Song}'s stream info and attach it to the song.
1513
- * @param {Song} song A Song
1522
+ *
1523
+ * @param song - A Song
1514
1524
  */
1515
1525
  async attachStreamInfo(song) {
1516
- const { url, source, formats, streamURL } = song;
1526
+ const { url, source } = song;
1517
1527
  if (source === "youtube") {
1518
- if (!formats || !chooseBestVideoFormat(song)) {
1519
- song._patchYouTube(await this.handler.getYouTubeInfo(url));
1520
- }
1521
- } else if (!streamURL) {
1528
+ song._patchYouTube(await this.handler.getYouTubeInfo(url));
1529
+ } else {
1522
1530
  for (const plugin of [...this.distube.extractorPlugins, ...this.distube.customPlugins]) {
1523
1531
  if (await plugin.validate(url)) {
1524
1532
  const info = [plugin.getStreamURL(url), plugin.getRelatedSongs(url)];
@@ -1558,6 +1566,8 @@ var _Options = class _Options {
1558
1566
  __publicField(this, "joinNewVoiceChannel");
1559
1567
  __publicField(this, "streamType");
1560
1568
  __publicField(this, "directLink");
1569
+ __publicField(this, "ffmpegPath");
1570
+ __publicField(this, "ffmpegDefaultArgs");
1561
1571
  if (typeof options !== "object" || Array.isArray(options)) {
1562
1572
  throw new DisTubeError("INVALID_TYPE", "object", options, "DisTubeOptions");
1563
1573
  }
@@ -1580,6 +1590,8 @@ var _Options = class _Options {
1580
1590
  this.joinNewVoiceChannel = opts.joinNewVoiceChannel;
1581
1591
  this.streamType = opts.streamType;
1582
1592
  this.directLink = opts.directLink;
1593
+ this.ffmpegPath = opts.ffmpegPath;
1594
+ this.ffmpegDefaultArgs = opts.ffmpegDefaultArgs;
1583
1595
  checkInvalidKey(opts, this, "DisTubeOptions");
1584
1596
  __privateMethod(this, _validateOptions, validateOptions_fn).call(this);
1585
1597
  }
@@ -1599,8 +1611,8 @@ validateOptions_fn = /* @__PURE__ */ __name(function(options = this) {
1599
1611
  "directLink"
1600
1612
  ]);
1601
1613
  const numberOptions = /* @__PURE__ */ new Set(["searchCooldown", "emptyCooldown", "searchSongs"]);
1602
- const stringOptions = /* @__PURE__ */ new Set();
1603
- const objectOptions = /* @__PURE__ */ new Set(["customFilters", "ytdlOptions"]);
1614
+ const stringOptions = /* @__PURE__ */ new Set(["ffmpegPath"]);
1615
+ const objectOptions = /* @__PURE__ */ new Set(["customFilters", "ytdlOptions", "ffmpegDefaultArgs"]);
1604
1616
  const optionalOptions = /* @__PURE__ */ new Set(["youtubeCookie", "customFilters"]);
1605
1617
  for (const [key, value] of Object.entries(options)) {
1606
1618
  if (value === void 0 && optionalOptions.has(key))
@@ -1640,14 +1652,11 @@ var _BaseManager = class _BaseManager extends DisTubeBase {
1640
1652
  super(...arguments);
1641
1653
  /**
1642
1654
  * The collection of items for this manager.
1643
- * @type {Collection}
1644
- * @name BaseManager#collection
1645
1655
  */
1646
1656
  __publicField(this, "collection", new import_discord2.Collection());
1647
1657
  }
1648
1658
  /**
1649
1659
  * The size of the collection.
1650
- * @type {number}
1651
1660
  */
1652
1661
  get size() {
1653
1662
  return this.collection.size;
@@ -1663,7 +1672,8 @@ var _GuildIdManager = class _GuildIdManager extends BaseManager {
1663
1672
  const existing = this.get(id);
1664
1673
  if (existing)
1665
1674
  return this;
1666
- return this.collection.set(id, data);
1675
+ this.collection.set(id, data);
1676
+ return this;
1667
1677
  }
1668
1678
  get(idOrInstance) {
1669
1679
  return this.collection.get(resolveGuildId(idOrInstance));
@@ -1683,21 +1693,16 @@ var import_voice3 = require("@discordjs/voice");
1683
1693
  var _DisTubeVoiceManager = class _DisTubeVoiceManager extends GuildIdManager {
1684
1694
  /**
1685
1695
  * Get a {@link DisTubeVoice}.
1686
- * @method get
1687
- * @memberof DisTubeVoiceManager#
1688
- * @param {GuildIdResolvable} guild The queue resolvable to resolve
1689
- * @returns {DisTubeVoice?}
1696
+ *
1697
+ * @param guild - The queue resolvable to resolve
1690
1698
  */
1691
1699
  /**
1692
1700
  * Collection of {@link DisTubeVoice}.
1693
- * @name DisTubeVoiceManager#collection
1694
- * @type {Discord.Collection<string, DisTubeVoice>}
1695
1701
  */
1696
1702
  /**
1697
1703
  * Create a {@link DisTubeVoice}
1698
- * @param {Discord.BaseGuildVoiceChannel} channel A voice channel to join
1699
- * @returns {DisTubeVoice}
1700
- * @private
1704
+ *
1705
+ * @param channel - A voice channel to join
1701
1706
  */
1702
1707
  create(channel) {
1703
1708
  const existing = this.get(channel.guildId);
@@ -1709,8 +1714,8 @@ var _DisTubeVoiceManager = class _DisTubeVoiceManager extends GuildIdManager {
1709
1714
  }
1710
1715
  /**
1711
1716
  * Join a voice channel
1712
- * @param {Discord.BaseGuildVoiceChannel} channel A voice channel to join
1713
- * @returns {Promise<DisTubeVoice>}
1717
+ *
1718
+ * @param channel - A voice channel to join
1714
1719
  */
1715
1720
  join(channel) {
1716
1721
  const existing = this.get(channel.guildId);
@@ -1720,7 +1725,8 @@ var _DisTubeVoiceManager = class _DisTubeVoiceManager extends GuildIdManager {
1720
1725
  }
1721
1726
  /**
1722
1727
  * Leave the connected voice channel in a guild
1723
- * @param {GuildIdResolvable} guild Queue Resolvable
1728
+ *
1729
+ * @param guild - Queue Resolvable
1724
1730
  */
1725
1731
  leave(guild) {
1726
1732
  const voice = this.get(guild);
@@ -1747,17 +1753,15 @@ var _FilterManager = class _FilterManager extends BaseManager {
1747
1753
  __privateAdd(this, _removeFn);
1748
1754
  /**
1749
1755
  * Collection of {@link Filter}.
1750
- * @name FilterManager#collection
1751
- * @type {Discord.Collection<string, DisTubeVoice>}
1752
1756
  */
1753
1757
  __publicField(this, "queue");
1754
1758
  this.queue = queue;
1755
1759
  }
1756
1760
  /**
1757
1761
  * Enable a filter or multiple filters to the manager
1758
- * @param {FilterResolvable|FilterResolvable[]} filterOrFilters The filter or filters to enable
1759
- * @param {boolean} [override=false] Wether or not override the applied filter with new filter value
1760
- * @returns {FilterManager}
1762
+ *
1763
+ * @param filterOrFilters - The filter or filters to enable
1764
+ * @param override - Wether or not override the applied filter with new filter value
1761
1765
  */
1762
1766
  add(filterOrFilters, override = false) {
1763
1767
  if (Array.isArray(filterOrFilters)) {
@@ -1776,15 +1780,14 @@ var _FilterManager = class _FilterManager extends BaseManager {
1776
1780
  }
1777
1781
  /**
1778
1782
  * Clear enabled filters of the manager
1779
- * @returns {FilterManager}
1780
1783
  */
1781
1784
  clear() {
1782
1785
  return this.set([]);
1783
1786
  }
1784
1787
  /**
1785
1788
  * Set the filters applied to the manager
1786
- * @param {FilterResolvable[]} filters The filters to apply
1787
- * @returns {FilterManager}
1789
+ *
1790
+ * @param filters - The filters to apply
1788
1791
  */
1789
1792
  set(filters) {
1790
1793
  if (!Array.isArray(filters))
@@ -1799,8 +1802,8 @@ var _FilterManager = class _FilterManager extends BaseManager {
1799
1802
  }
1800
1803
  /**
1801
1804
  * Disable a filter or multiple filters
1802
- * @param {FilterResolvable|FilterResolvable[]} filterOrFilters The filter or filters to disable
1803
- * @returns {FilterManager}
1805
+ *
1806
+ * @param filterOrFilters - The filter or filters to disable
1804
1807
  */
1805
1808
  remove(filterOrFilters) {
1806
1809
  if (Array.isArray(filterOrFilters))
@@ -1812,30 +1815,26 @@ var _FilterManager = class _FilterManager extends BaseManager {
1812
1815
  }
1813
1816
  /**
1814
1817
  * Check whether a filter enabled or not
1815
- * @param {FilterResolvable} filter The filter to check
1816
- * @returns {boolean}
1818
+ *
1819
+ * @param filter - The filter to check
1817
1820
  */
1818
1821
  has(filter) {
1819
1822
  return this.collection.has(typeof filter === "string" ? filter : __privateMethod(this, _resolve, resolve_fn).call(this, filter).name);
1820
1823
  }
1821
1824
  /**
1822
1825
  * Array of enabled filter names
1823
- * @type {Array<string>}
1824
- * @readonly
1825
1826
  */
1826
1827
  get names() {
1827
1828
  return [...this.collection.keys()];
1828
1829
  }
1829
1830
  /**
1830
1831
  * Array of enabled filters
1831
- * @type {Array<Filter>}
1832
- * @readonly
1833
1832
  */
1834
1833
  get values() {
1835
1834
  return [...this.collection.values()];
1836
1835
  }
1837
1836
  get ffmpegArgs() {
1838
- return this.size ? ["-af", this.values.map((f) => f.value).join(",")] : [];
1837
+ return this.size ? { af: this.values.map((f) => f.value).join(",") } : {};
1839
1838
  }
1840
1839
  toString() {
1841
1840
  return this.names.toString();
@@ -1873,51 +1872,46 @@ var _QueueManager = class _QueueManager extends GuildIdManager {
1873
1872
  super(...arguments);
1874
1873
  /**
1875
1874
  * Get a Queue from this QueueManager.
1876
- * @method get
1877
- * @memberof QueueManager#
1878
- * @param {GuildIdResolvable} guild Resolvable thing from a guild
1879
- * @returns {Queue?}
1875
+ *
1876
+ * @param guild - Resolvable thing from a guild
1880
1877
  */
1881
1878
  /**
1882
1879
  * Listen to DisTubeVoice events and handle the Queue
1883
- * @private
1884
- * @param {Queue} queue Queue
1880
+ *
1881
+ * @param queue - Queue
1885
1882
  */
1886
1883
  __privateAdd(this, _voiceEventHandler);
1887
1884
  /**
1888
1885
  * Whether or not emit playSong event
1889
- * @param {Queue} queue Queue
1890
- * @private
1891
- * @returns {boolean}
1886
+ *
1887
+ * @param queue - Queue
1892
1888
  */
1893
1889
  __privateAdd(this, _emitPlaySong);
1894
1890
  /**
1895
1891
  * Handle the queue when a Song finish
1896
- * @private
1897
- * @param {Queue} queue queue
1898
- * @returns {Promise<void>}
1892
+ *
1893
+ * @param queue - queue
1899
1894
  */
1900
1895
  __privateAdd(this, _handleSongFinish);
1901
1896
  /**
1902
1897
  * Handle error while playing
1903
- * @private
1904
- * @param {Queue} queue queue
1905
- * @param {Error} error error
1898
+ *
1899
+ * @param queue - queue
1900
+ * @param error - error
1906
1901
  */
1907
1902
  __privateAdd(this, _handlePlayingError);
1908
1903
  }
1909
1904
  /**
1910
1905
  * Collection of {@link Queue}.
1911
- * @name QueueManager#collection
1912
- * @type {Discord.Collection<string, Queue>}
1913
1906
  */
1914
1907
  /**
1915
1908
  * Create a {@link Queue}
1916
- * @private
1917
- * @param {Discord.BaseGuildVoiceChannel} channel A voice channel
1918
- * @param {Song|Song[]} song First song
1919
- * @param {Discord.BaseGuildTextChannel} textChannel Default text channel
1920
- * @returns {Promise<Queue|true>} Returns `true` if encounter an error
1909
+ *
1910
+ * @param channel - A voice channel
1911
+ * @param song - First song
1912
+ * @param textChannel - Default text channel
1913
+ *
1914
+ * @returns Returns `true` if encounter an error
1921
1915
  */
1922
1916
  async create(channel, song, textChannel) {
1923
1917
  if (this.has(channel.guildId))
@@ -1929,7 +1923,7 @@ var _QueueManager = class _QueueManager extends GuildIdManager {
1929
1923
  await voice.join();
1930
1924
  __privateMethod(this, _voiceEventHandler, voiceEventHandler_fn).call(this, queue);
1931
1925
  this.add(queue.id, queue);
1932
- this.emit("initQueue", queue);
1926
+ this.emit("initQueue" /* INIT_QUEUE */, queue);
1933
1927
  const err = await this.playSong(queue);
1934
1928
  return err || queue;
1935
1929
  } finally {
@@ -1938,14 +1932,20 @@ var _QueueManager = class _QueueManager extends GuildIdManager {
1938
1932
  }
1939
1933
  /**
1940
1934
  * Create a ytdl stream
1941
- * @param {Queue} queue Queue
1942
- * @returns {DisTubeStream}
1935
+ *
1936
+ * @param queue - Queue
1943
1937
  */
1944
1938
  createStream(queue) {
1945
1939
  const song = queue.songs[0];
1946
1940
  const { duration, source, streamURL } = song;
1947
1941
  const streamOptions = {
1948
- ffmpegArgs: queue.filters.ffmpegArgs,
1942
+ ffmpeg: {
1943
+ path: this.options.ffmpegPath,
1944
+ args: {
1945
+ ...this.options.ffmpegDefaultArgs,
1946
+ ...queue.filters.ffmpegArgs
1947
+ }
1948
+ },
1949
1949
  seek: duration ? queue.beginTime : void 0,
1950
1950
  type: this.options.streamType
1951
1951
  };
@@ -1955,9 +1955,10 @@ var _QueueManager = class _QueueManager extends GuildIdManager {
1955
1955
  }
1956
1956
  /**
1957
1957
  * Play a song on voice connection
1958
- * @private
1959
- * @param {Queue} queue The guild queue
1960
- * @returns {Promise<boolean>} error?
1958
+ *
1959
+ * @param queue - The guild queue
1960
+ *
1961
+ * @returns error?
1961
1962
  */
1962
1963
  async playSong(queue) {
1963
1964
  if (!queue)
@@ -1974,6 +1975,7 @@ var _QueueManager = class _QueueManager extends GuildIdManager {
1974
1975
  return true;
1975
1976
  }
1976
1977
  const stream = this.createStream(queue);
1978
+ stream.on("debug", (data) => this.emit("ffmpegDebug" /* FFMPEG_DEBUG */, `[${queue.id}]: ${data}`));
1977
1979
  queue.voice.play(stream);
1978
1980
  song.streamURL = stream.url;
1979
1981
  return false;
@@ -1988,7 +1990,7 @@ voiceEventHandler_fn = /* @__PURE__ */ __name(function(queue) {
1988
1990
  queue._listeners = {
1989
1991
  disconnect: (error) => {
1990
1992
  queue.remove();
1991
- this.emit("disconnect", queue);
1993
+ this.emit("disconnect" /* DISCONNECT */, queue);
1992
1994
  if (error)
1993
1995
  this.emitError(error, queue.textChannel);
1994
1996
  },
@@ -2005,7 +2007,7 @@ emitPlaySong_fn = /* @__PURE__ */ __name(function(queue) {
2005
2007
  }, "#emitPlaySong");
2006
2008
  _handleSongFinish = new WeakSet();
2007
2009
  handleSongFinish_fn = /* @__PURE__ */ __name(async function(queue) {
2008
- this.emit("finishSong", queue, queue.songs[0]);
2010
+ this.emit("finishSong" /* FINISH_SONG */, queue, queue.songs[0]);
2009
2011
  await queue._taskQueue.queuing();
2010
2012
  try {
2011
2013
  if (queue.stopped)
@@ -2023,14 +2025,14 @@ handleSongFinish_fn = /* @__PURE__ */ __name(async function(queue) {
2023
2025
  try {
2024
2026
  await queue.addRelatedSong();
2025
2027
  } catch {
2026
- this.emit("noRelated", queue);
2028
+ this.emit("noRelated" /* NO_RELATED */, queue);
2027
2029
  }
2028
2030
  }
2029
2031
  if (queue.songs.length <= 1) {
2030
2032
  if (this.options.leaveOnFinish)
2031
2033
  queue.voice.leave();
2032
2034
  if (!queue.autoplay)
2033
- this.emit("finish", queue);
2035
+ this.emit("finish" /* FINISH */, queue);
2034
2036
  queue.remove();
2035
2037
  return;
2036
2038
  }
@@ -2049,7 +2051,7 @@ handleSongFinish_fn = /* @__PURE__ */ __name(async function(queue) {
2049
2051
  queue.beginTime = 0;
2050
2052
  const err = await this.playSong(queue);
2051
2053
  if (!err && emitPlaySong)
2052
- this.emit("playSong", queue, queue.songs[0]);
2054
+ this.emit("playSong" /* PLAY_SONG */, queue, queue.songs[0]);
2053
2055
  } finally {
2054
2056
  queue._taskQueue.resolve();
2055
2057
  }
@@ -2070,7 +2072,7 @@ Name: ${song.name}`;
2070
2072
  queue.beginTime = 0;
2071
2073
  this.playSong(queue).then((e) => {
2072
2074
  if (!e)
2073
- this.emit("playSong", queue, queue.songs[0]);
2075
+ this.emit("playSong" /* PLAY_SONG */, queue, queue.songs[0]);
2074
2076
  });
2075
2077
  } else {
2076
2078
  queue.stop();
@@ -2084,10 +2086,11 @@ var _filters;
2084
2086
  var _Queue = class _Queue extends DisTubeBase {
2085
2087
  /**
2086
2088
  * Create a queue for the guild
2087
- * @param {DisTube} distube DisTube
2088
- * @param {DisTubeVoice} voice Voice connection
2089
- * @param {Song|Song[]} song First song(s)
2090
- * @param {Discord.BaseGuildTextChannel?} textChannel Default text channel
2089
+ *
2090
+ * @param distube - DisTube
2091
+ * @param voice - Voice connection
2092
+ * @param song - First song(s)
2093
+ * @param textChannel - Default text channel
2091
2094
  */
2092
2095
  constructor(distube, voice, song, textChannel) {
2093
2096
  super(distube);
@@ -2129,55 +2132,42 @@ var _Queue = class _Queue extends DisTubeBase {
2129
2132
  }
2130
2133
  /**
2131
2134
  * The client user as a `GuildMember` of this queue's guild
2132
- * @type {Discord.GuildMember?}
2133
2135
  */
2134
2136
  get clientMember() {
2135
2137
  return this.voice.channel.guild.members.me ?? void 0;
2136
2138
  }
2137
2139
  /**
2138
2140
  * The filter manager of the queue
2139
- * @type {FilterManager}
2140
- * @readonly
2141
2141
  */
2142
2142
  get filters() {
2143
2143
  return __privateGet(this, _filters);
2144
2144
  }
2145
2145
  /**
2146
2146
  * Formatted duration string.
2147
- * @type {string}
2148
- * @readonly
2149
2147
  */
2150
2148
  get formattedDuration() {
2151
2149
  return formatDuration(this.duration);
2152
2150
  }
2153
2151
  /**
2154
2152
  * Queue's duration.
2155
- * @type {number}
2156
- * @readonly
2157
2153
  */
2158
2154
  get duration() {
2159
2155
  return this.songs.length ? this.songs.reduce((prev, next) => prev + next.duration, 0) : 0;
2160
2156
  }
2161
2157
  /**
2162
2158
  * What time in the song is playing (in seconds).
2163
- * @type {number}
2164
- * @readonly
2165
2159
  */
2166
2160
  get currentTime() {
2167
2161
  return this.voice.playbackDuration + this.beginTime;
2168
2162
  }
2169
2163
  /**
2170
2164
  * Formatted {@link Queue#currentTime} string.
2171
- * @type {string}
2172
- * @readonly
2173
2165
  */
2174
2166
  get formattedCurrentTime() {
2175
2167
  return formatDuration(this.currentTime);
2176
2168
  }
2177
2169
  /**
2178
2170
  * The voice channel playing in.
2179
- * @type {Discord.VoiceChannel|Discord.StageChannel|null}
2180
- * @readonly
2181
2171
  */
2182
2172
  get voiceChannel() {
2183
2173
  return this.clientMember?.voice?.channel ?? null;
@@ -2189,12 +2179,12 @@ var _Queue = class _Queue extends DisTubeBase {
2189
2179
  this.voice.volume = value;
2190
2180
  }
2191
2181
  /**
2192
- * @private
2193
- * Add a Song or an array of Song to the queue
2194
- * @param {Song|Song[]} song Song to add
2195
- * @param {number} [position=0] Position to add, <= 0 to add to the end of the queue
2196
- * @throws {Error}
2197
- * @returns {Queue} The guild queue
2182
+ * @throws {DisTubeError}
2183
+ *
2184
+ * @param song - Song to add
2185
+ * @param position - Position to add, \<= 0 to add to the end of the queue
2186
+ *
2187
+ * @returns The guild queue
2198
2188
  */
2199
2189
  addToQueue(song, position = 0) {
2200
2190
  if (!song || Array.isArray(song) && !song.length) {
@@ -2221,7 +2211,8 @@ var _Queue = class _Queue extends DisTubeBase {
2221
2211
  }
2222
2212
  /**
2223
2213
  * Pause the guild stream
2224
- * @returns {Queue} The guild queue
2214
+ *
2215
+ * @returns The guild queue
2225
2216
  */
2226
2217
  pause() {
2227
2218
  if (this.paused)
@@ -2233,7 +2224,8 @@ var _Queue = class _Queue extends DisTubeBase {
2233
2224
  }
2234
2225
  /**
2235
2226
  * Resume the guild stream
2236
- * @returns {Queue} The guild queue
2227
+ *
2228
+ * @returns The guild queue
2237
2229
  */
2238
2230
  resume() {
2239
2231
  if (this.playing)
@@ -2245,19 +2237,21 @@ var _Queue = class _Queue extends DisTubeBase {
2245
2237
  }
2246
2238
  /**
2247
2239
  * Set the guild stream's volume
2248
- * @param {number} percent The percentage of volume you want to set
2249
- * @returns {Queue} The guild queue
2240
+ *
2241
+ * @param percent - The percentage of volume you want to set
2242
+ *
2243
+ * @returns The guild queue
2250
2244
  */
2251
2245
  setVolume(percent) {
2252
2246
  this.volume = percent;
2253
2247
  return this;
2254
2248
  }
2255
2249
  /**
2256
- * Skip the playing song if there is a next song in the queue.
2257
- * <info>If {@link Queue#autoplay} is `true` and there is no up next song,
2258
- * DisTube will add and play a related song.</info>
2259
- * @returns {Promise<Song>} The song will skip to
2260
- * @throws {Error}
2250
+ * Skip the playing song if there is a next song in the queue. <info>If {@link
2251
+ * Queue#autoplay} is `true` and there is no up next song, DisTube will add and
2252
+ * play a related song.</info>
2253
+ *
2254
+ * @returns The song will skip to
2261
2255
  */
2262
2256
  async skip() {
2263
2257
  await this._taskQueue.queuing();
@@ -2278,8 +2272,8 @@ var _Queue = class _Queue extends DisTubeBase {
2278
2272
  }
2279
2273
  /**
2280
2274
  * Play the previous song if exists
2281
- * @returns {Promise<Song>} The guild queue
2282
- * @throws {Error}
2275
+ *
2276
+ * @returns The guild queue
2283
2277
  */
2284
2278
  async previous() {
2285
2279
  await this._taskQueue.queuing();
@@ -2299,7 +2293,8 @@ var _Queue = class _Queue extends DisTubeBase {
2299
2293
  }
2300
2294
  /**
2301
2295
  * Shuffle the queue's songs
2302
- * @returns {Promise<Queue>} The guild queue
2296
+ *
2297
+ * @returns The guild queue
2303
2298
  */
2304
2299
  async shuffle() {
2305
2300
  await this._taskQueue.queuing();
@@ -2318,12 +2313,13 @@ var _Queue = class _Queue extends DisTubeBase {
2318
2313
  }
2319
2314
  }
2320
2315
  /**
2321
- * Jump to the song position in the queue.
2322
- * The next one is 1, 2,...
2323
- * The previous one is -1, -2,...
2324
- * @param {number} position The song position to play
2325
- * @returns {Promise<Song>} The new Song will be played
2326
- * @throws {Error} if `num` is invalid number
2316
+ * Jump to the song position in the queue. The next one is 1, 2,... The previous
2317
+ * one is -1, -2,...
2318
+ * if `num` is invalid number
2319
+ *
2320
+ * @param position - The song position to play
2321
+ *
2322
+ * @returns The new Song will be played
2327
2323
  */
2328
2324
  async jump(position) {
2329
2325
  await this._taskQueue.queuing();
@@ -2359,10 +2355,12 @@ var _Queue = class _Queue extends DisTubeBase {
2359
2355
  }
2360
2356
  }
2361
2357
  /**
2362
- * Set the repeat mode of the guild queue.\
2358
+ * Set the repeat mode of the guild queue.
2363
2359
  * Toggle mode `(Disabled -> Song -> Queue -> Disabled ->...)` if `mode` is `undefined`
2364
- * @param {RepeatMode?} [mode] The repeat modes (toggle if `undefined`)
2365
- * @returns {RepeatMode} The new repeat mode
2360
+ *
2361
+ * @param mode - The repeat modes (toggle if `undefined`)
2362
+ *
2363
+ * @returns The new repeat mode
2366
2364
  */
2367
2365
  setRepeatMode(mode) {
2368
2366
  if (mode !== void 0 && !Object.values(RepeatMode).includes(mode)) {
@@ -2378,8 +2376,10 @@ var _Queue = class _Queue extends DisTubeBase {
2378
2376
  }
2379
2377
  /**
2380
2378
  * Set the playing time to another position
2381
- * @param {number} time Time in seconds
2382
- * @returns {Queue} The guild queue
2379
+ *
2380
+ * @param time - Time in seconds
2381
+ *
2382
+ * @returns The guild queue
2383
2383
  */
2384
2384
  seek(time) {
2385
2385
  if (typeof time !== "number")
@@ -2392,8 +2392,8 @@ var _Queue = class _Queue extends DisTubeBase {
2392
2392
  }
2393
2393
  /**
2394
2394
  * Add a related song of the playing song to the queue
2395
- * @returns {Promise<Song>} The added song
2396
- * @throws {Error}
2395
+ *
2396
+ * @returns The added song
2397
2397
  */
2398
2398
  async addRelatedSong() {
2399
2399
  if (!this.songs?.[0])
@@ -2426,9 +2426,8 @@ var _Queue = class _Queue extends DisTubeBase {
2426
2426
  }
2427
2427
  }
2428
2428
  /**
2429
- * Remove the queue from the manager
2430
- * (This does not leave the voice channel even if {@link DisTubeOptions|DisTubeOptions.leaveOnStop} is enabled)
2431
- * @private
2429
+ * Remove the queue from the manager (This does not leave the voice channel even if
2430
+ * {@link DisTubeOptions | DisTubeOptions.leaveOnStop} is enabled)
2432
2431
  */
2433
2432
  remove() {
2434
2433
  this.stopped = true;
@@ -2440,11 +2439,12 @@ var _Queue = class _Queue extends DisTubeBase {
2440
2439
  }
2441
2440
  }
2442
2441
  this.queues.remove(this.id);
2443
- this.emit("deleteQueue", this);
2442
+ this.emit("deleteQueue" /* DELETE_QUEUE */, this);
2444
2443
  }
2445
2444
  /**
2446
2445
  * Toggle autoplay mode
2447
- * @returns {boolean} Autoplay mode state
2446
+ *
2447
+ * @returns Autoplay mode state
2448
2448
  */
2449
2449
  toggleAutoplay() {
2450
2450
  this.autoplay = !this.autoplay;
@@ -2465,70 +2465,59 @@ var _Plugin = class _Plugin {
2465
2465
  }
2466
2466
  /**
2467
2467
  * Type of the plugin
2468
- * @name Plugin#type
2469
- * @type {PluginType}
2470
2468
  */
2471
2469
  /**
2472
2470
  * Emit an event to the {@link DisTube} class
2473
- * @param {string} eventName Event name
2474
- * @param {...any} args arguments
2475
- * @returns {boolean}
2471
+ *
2472
+ * @param eventName - Event name
2473
+ * @param args - arguments
2476
2474
  */
2477
2475
  emit(eventName, ...args) {
2478
2476
  return this.distube.emit(eventName, ...args);
2479
2477
  }
2480
2478
  /**
2481
2479
  * Emit error event to the {@link DisTube} class
2482
- * @param {Error} error error
2483
- * @param {Discord.BaseGuildTextChannel} [channel] Text channel where the error is encountered.
2480
+ *
2481
+ * @param error - error
2482
+ * @param channel - Text channel where the error is encountered.
2484
2483
  */
2485
2484
  emitError(error, channel) {
2486
2485
  this.distube.emitError(error, channel);
2487
2486
  }
2488
2487
  /**
2489
2488
  * The queue manager
2490
- * @type {QueueManager}
2491
- * @readonly
2492
2489
  */
2493
2490
  get queues() {
2494
2491
  return this.distube.queues;
2495
2492
  }
2496
2493
  /**
2497
2494
  * The voice manager
2498
- * @type {DisTubeVoiceManager}
2499
- * @readonly
2500
2495
  */
2501
2496
  get voices() {
2502
2497
  return this.distube.voices;
2503
2498
  }
2504
2499
  /**
2505
2500
  * Discord.js client
2506
- * @type {Discord.Client}
2507
- * @readonly
2508
2501
  */
2509
2502
  get client() {
2510
2503
  return this.distube.client;
2511
2504
  }
2512
2505
  /**
2513
2506
  * DisTube options
2514
- * @type {DisTubeOptions}
2515
- * @readonly
2516
2507
  */
2517
2508
  get options() {
2518
2509
  return this.distube.options;
2519
2510
  }
2520
2511
  /**
2521
2512
  * DisTube handler
2522
- * @type {DisTubeHandler}
2523
- * @readonly
2524
2513
  */
2525
2514
  get handler() {
2526
2515
  return this.distube.handler;
2527
2516
  }
2528
2517
  /**
2529
2518
  * Check if the string is working with this plugin
2530
- * @param {string} _string Input string
2531
- * @returns {boolean|Promise<boolean>}
2519
+ *
2520
+ * @param _string - Input string
2532
2521
  */
2533
2522
  validate(_string) {
2534
2523
  return false;
@@ -2536,17 +2525,18 @@ var _Plugin = class _Plugin {
2536
2525
  /**
2537
2526
  * Get the stream url from {@link Song#url}. Returns {@link Song#url} by default.
2538
2527
  * Not needed if the plugin plays song from YouTube.
2539
- * @param {string} url Input url
2540
- * @returns {string|Promise<string>}
2528
+ *
2529
+ * @param url - Input url
2541
2530
  */
2542
2531
  getStreamURL(url) {
2543
2532
  return url;
2544
2533
  }
2545
2534
  /**
2546
- * Get related songs from a supported url. {@link Song#member} should be `undefined`.
2547
- * Not needed to add {@link Song#related} because it will be added with this function later.
2548
- * @param {string} _url Input url
2549
- * @returns {Song[]|Promise<Song[]>}
2535
+ * Get related songs from a supported url. {@link Song#member} should be
2536
+ * `undefined`. Not needed to add {@link Song#related} because it will be added
2537
+ * with this function later.
2538
+ *
2539
+ * @param _url - Input url
2550
2540
  */
2551
2541
  getRelatedSongs(_url) {
2552
2542
  return [];
@@ -2763,10 +2753,10 @@ var DirectLinkPlugin = _DirectLinkPlugin;
2763
2753
 
2764
2754
  // src/DisTube.ts
2765
2755
  var import_ytsr = __toESM(require("@distube/ytsr"));
2766
- var import_tiny_typed_emitter2 = require("tiny-typed-emitter");
2756
+ var import_tiny_typed_emitter3 = require("tiny-typed-emitter");
2767
2757
  var { version } = require_package();
2768
2758
  var _getQueue, getQueue_fn;
2769
- var _DisTube = class _DisTube extends import_tiny_typed_emitter2.TypedEmitter {
2759
+ var _DisTube = class _DisTube extends import_tiny_typed_emitter3.TypedEmitter {
2770
2760
  constructor(client, otp = {}) {
2771
2761
  super();
2772
2762
  __privateAdd(this, _getQueue);
@@ -2799,21 +2789,16 @@ var _DisTube = class _DisTube extends import_tiny_typed_emitter2.TypedEmitter {
2799
2789
  }
2800
2790
  /**
2801
2791
  * DisTube version
2802
- * @type {string}
2803
2792
  */
2804
2793
  get version() {
2805
2794
  return version;
2806
2795
  }
2807
2796
  /**
2808
- * Play / add a song or playlist from url. Search and play a song if it is not a valid url.
2797
+ * Play / add a song or playlist from url. Search and play a song if it is not a
2798
+ * valid url.
2809
2799
  *
2810
- * @param {Discord.BaseGuildVoiceChannel} voiceChannel The channel will be joined if the bot isn't in any channels,
2811
- * the bot will be moved to this channel if {@link DisTubeOptions}.joinNewVoiceChannel is `true`
2812
- * @param {string|Song|SearchResult|Playlist} song URL | Search string |
2813
- * {@link Song} | {@link SearchResult} | {@link Playlist}
2814
- * @param {PlayOptions} [options] Optional options
2815
- * @throws {DisTubeError}
2816
2800
  * @example
2801
+ * ```ts
2817
2802
  * client.on('message', (message) => {
2818
2803
  * if (!message.content.startsWith(config.prefix)) return;
2819
2804
  * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
@@ -2825,7 +2810,14 @@ var _DisTube = class _DisTube extends import_tiny_typed_emitter2.TypedEmitter {
2825
2810
  * message
2826
2811
  * });
2827
2812
  * });
2828
- * @returns {Promise<void>}
2813
+ * ```ts
2814
+ *
2815
+ * @throws {@link DisTubeError}
2816
+ *
2817
+ * @param voiceChannel - The channel will be joined if the bot isn't in any channels, the bot will be
2818
+ * moved to this channel if {@link DisTubeOptions}.joinNewVoiceChannel is `true`
2819
+ * @param song - URL | Search string | {@link Song} | {@link SearchResult} | {@link Playlist}
2820
+ * @param options - Optional options
2829
2821
  */
2830
2822
  async play(voiceChannel, song, options = {}) {
2831
2823
  if (!isSupportedVoiceChannel(voiceChannel)) {
@@ -2895,10 +2887,9 @@ ${e.message}`;
2895
2887
  }
2896
2888
  /**
2897
2889
  * Create a custom playlist
2898
- * @returns {Promise<Playlist>}
2899
- * @param {Array<string|Song|SearchResult>} songs Array of url, Song or SearchResult
2900
- * @param {CustomPlaylistOptions} [options] Optional options
2890
+ *
2901
2891
  * @example
2892
+ * ```ts
2902
2893
  * const songs = ["https://www.youtube.com/watch?v=xxx", "https://www.youtube.com/watch?v=yyy"];
2903
2894
  * const playlist = await distube.createCustomPlaylist(songs, {
2904
2895
  * member: message.member,
@@ -2906,6 +2897,10 @@ ${e.message}`;
2906
2897
  * parallel: true
2907
2898
  * });
2908
2899
  * distube.play(voiceChannel, playlist, { ... });
2900
+ * ```ts
2901
+ *
2902
+ * @param songs - Array of url, Song or SearchResult
2903
+ * @param options - Optional options
2909
2904
  */
2910
2905
  async createCustomPlaylist(songs, options = {}) {
2911
2906
  const { member, properties, parallel, metadata } = { parallel: true, ...options };
@@ -2926,13 +2921,14 @@ ${e.message}`;
2926
2921
  const promises = filteredSongs.map(
2927
2922
  (song) => this.handler.resolve(song, { member, metadata }).catch(() => void 0)
2928
2923
  );
2929
- resolvedSongs = (await Promise.all(promises)).filter((s) => Boolean(s));
2924
+ resolvedSongs = (await Promise.all(promises)).filter((s) => s instanceof Song);
2930
2925
  } else {
2931
- const resolved = [];
2926
+ resolvedSongs = [];
2932
2927
  for (const song of filteredSongs) {
2933
- resolved.push(await this.handler.resolve(song, { member, metadata }).catch(() => void 0));
2928
+ const resolved = await this.handler.resolve(song, { member, metadata }).catch(() => void 0);
2929
+ if (resolved instanceof Song)
2930
+ resolvedSongs.push(resolved);
2934
2931
  }
2935
- resolvedSongs = resolved.filter((s) => Boolean(s));
2936
2932
  }
2937
2933
  return new Playlist(resolvedSongs, { member, properties, metadata });
2938
2934
  }
@@ -2940,13 +2936,13 @@ ${e.message}`;
2940
2936
  * Search for a song. You can customize how user answers instead of send a number.
2941
2937
  * Then use {@link DisTube#play} to play it.
2942
2938
  *
2943
- * @param {string} string The string search for
2944
- * @param {Object} options Search options
2945
- * @param {number} [options.limit=10] Limit the results
2946
- * @param {SearchResultType} [options.type=SearchResultType.VIDEO] Type of results (`video` or `playlist`).
2947
- * @param {boolean} [options.safeSearch=false] Whether or not use safe search (YouTube restricted mode)
2948
- * @throws {Error}
2949
- * @returns {Promise<Array<SearchResult>>} Array of results
2939
+ * @param string - The string search for
2940
+ * @param options - Search options
2941
+ * @param options.limit - Limit the results
2942
+ * @param options.type - Type of results (`video` or `playlist`).
2943
+ * @param options.safeSearch - Whether or not use safe search (YouTube restricted mode)
2944
+ *
2945
+ * @returns Array of results
2950
2946
  */
2951
2947
  async search(string, options = {}) {
2952
2948
  const opts = { type: "video" /* VIDEO */, limit: 10, safeSearch: false, ...options };
@@ -2979,10 +2975,9 @@ ${e.message}`;
2979
2975
  }
2980
2976
  /**
2981
2977
  * Get the guild queue
2982
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
2983
- * @returns {Queue?}
2984
- * @throws {Error}
2978
+ *
2985
2979
  * @example
2980
+ * ```ts
2986
2981
  * client.on('message', (message) => {
2987
2982
  * if (!message.content.startsWith(config.prefix)) return;
2988
2983
  * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
@@ -2994,34 +2989,38 @@ ${e.message}`;
2994
2989
  * ).join("\n"));
2995
2990
  * }
2996
2991
  * });
2992
+ * ```ts
2993
+ *
2994
+ * @param guild - The type can be resolved to give a {@link Queue}
2997
2995
  */
2998
2996
  getQueue(guild) {
2999
2997
  return this.queues.get(guild);
3000
2998
  }
3001
2999
  /**
3002
3000
  * Pause the guild stream
3003
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
3004
- * @returns {Queue} The guild queue
3005
- * @throws {Error}
3001
+ *
3002
+ * @param guild - The type can be resolved to give a {@link Queue}
3003
+ *
3004
+ * @returns The guild queue
3006
3005
  */
3007
3006
  pause(guild) {
3008
3007
  return __privateMethod(this, _getQueue, getQueue_fn).call(this, guild).pause();
3009
3008
  }
3010
3009
  /**
3011
3010
  * Resume the guild stream
3012
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
3013
- * @returns {Queue} The guild queue
3014
- * @throws {Error}
3011
+ *
3012
+ * @param guild - The type can be resolved to give a {@link Queue}
3013
+ *
3014
+ * @returns The guild queue
3015
3015
  */
3016
3016
  resume(guild) {
3017
3017
  return __privateMethod(this, _getQueue, getQueue_fn).call(this, guild).resume();
3018
3018
  }
3019
3019
  /**
3020
3020
  * Stop the guild stream
3021
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
3022
- * @returns {Promise<void>}
3023
- * @throws {Error}
3021
+ *
3024
3022
  * @example
3023
+ * ```ts
3025
3024
  * client.on('message', (message) => {
3026
3025
  * if (!message.content.startsWith(config.prefix)) return;
3027
3026
  * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
@@ -3031,17 +3030,18 @@ ${e.message}`;
3031
3030
  * message.channel.send("Stopped the queue!");
3032
3031
  * }
3033
3032
  * });
3033
+ * ```ts
3034
+ *
3035
+ * @param guild - The type can be resolved to give a {@link Queue}
3034
3036
  */
3035
3037
  stop(guild) {
3036
3038
  return __privateMethod(this, _getQueue, getQueue_fn).call(this, guild).stop();
3037
3039
  }
3038
3040
  /**
3039
3041
  * Set the guild stream's volume
3040
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
3041
- * @param {number} percent The percentage of volume you want to set
3042
- * @returns {Queue} The guild queue
3043
- * @throws {Error}
3042
+ *
3044
3043
  * @example
3044
+ * ```ts
3045
3045
  * client.on('message', (message) => {
3046
3046
  * if (!message.content.startsWith(config.prefix)) return;
3047
3047
  * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
@@ -3049,18 +3049,23 @@ ${e.message}`;
3049
3049
  * if (command == "volume")
3050
3050
  * distube.setVolume(message, Number(args[0]));
3051
3051
  * });
3052
+ * ```ts
3053
+ *
3054
+ * @param guild - The type can be resolved to give a {@link Queue}
3055
+ * @param percent - The percentage of volume you want to set
3056
+ *
3057
+ * @returns The guild queue
3052
3058
  */
3053
3059
  setVolume(guild, percent) {
3054
3060
  return __privateMethod(this, _getQueue, getQueue_fn).call(this, guild).setVolume(percent);
3055
3061
  }
3056
3062
  /**
3057
- * Skip the playing song if there is a next song in the queue.
3058
- * <info>If {@link Queue#autoplay} is `true` and there is no up next song,
3059
- * DisTube will add and play a related song.</info>
3060
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
3061
- * @returns {Promise<Song>} The new Song will be played
3062
- * @throws {Error}
3063
+ * Skip the playing song if there is a next song in the queue. <info>If {@link
3064
+ * Queue#autoplay} is `true` and there is no up next song, DisTube will add and
3065
+ * play a related song.</info>
3066
+ *
3063
3067
  * @example
3068
+ * ```ts
3064
3069
  * client.on('message', (message) => {
3065
3070
  * if (!message.content.startsWith(config.prefix)) return;
3066
3071
  * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
@@ -3068,16 +3073,20 @@ ${e.message}`;
3068
3073
  * if (command == "skip")
3069
3074
  * distube.skip(message);
3070
3075
  * });
3076
+ * ```ts
3077
+ *
3078
+ * @param guild - The type can be resolved to give a {@link Queue}
3079
+ *
3080
+ * @returns The new Song will be played
3071
3081
  */
3072
3082
  skip(guild) {
3073
3083
  return __privateMethod(this, _getQueue, getQueue_fn).call(this, guild).skip();
3074
3084
  }
3075
3085
  /**
3076
3086
  * Play the previous song
3077
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
3078
- * @returns {Promise<Song>} The new Song will be played
3079
- * @throws {Error}
3087
+ *
3080
3088
  * @example
3089
+ * ```ts
3081
3090
  * client.on('message', (message) => {
3082
3091
  * if (!message.content.startsWith(config.prefix)) return;
3083
3092
  * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
@@ -3085,15 +3094,20 @@ ${e.message}`;
3085
3094
  * if (command == "previous")
3086
3095
  * distube.previous(message);
3087
3096
  * });
3097
+ * ```ts
3098
+ *
3099
+ * @param guild - The type can be resolved to give a {@link Queue}
3100
+ *
3101
+ * @returns The new Song will be played
3088
3102
  */
3089
3103
  previous(guild) {
3090
3104
  return __privateMethod(this, _getQueue, getQueue_fn).call(this, guild).previous();
3091
3105
  }
3092
3106
  /**
3093
3107
  * Shuffle the guild queue songs
3094
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
3095
- * @returns {Promise<Queue>} The guild queue
3108
+ *
3096
3109
  * @example
3110
+ * ```ts
3097
3111
  * client.on('message', (message) => {
3098
3112
  * if (!message.content.startsWith(config.prefix)) return;
3099
3113
  * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
@@ -3101,19 +3115,21 @@ ${e.message}`;
3101
3115
  * if (command == "shuffle")
3102
3116
  * distube.shuffle(message);
3103
3117
  * });
3118
+ * ```ts
3119
+ *
3120
+ * @param guild - The type can be resolved to give a {@link Queue}
3121
+ *
3122
+ * @returns The guild queue
3104
3123
  */
3105
3124
  shuffle(guild) {
3106
3125
  return __privateMethod(this, _getQueue, getQueue_fn).call(this, guild).shuffle();
3107
3126
  }
3108
3127
  /**
3109
- * Jump to the song number in the queue.
3110
- * The next one is 1, 2,...
3111
- * The previous one is -1, -2,...
3112
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
3113
- * @param {number} num The song number to play
3114
- * @returns {Promise<Song>} The new Song will be played
3115
- * @throws {Error} if `num` is invalid number (0 < num < {@link Queue#songs}.length)
3128
+ * Jump to the song number in the queue. The next one is 1, 2,... The previous one
3129
+ * is -1, -2,...
3130
+ *
3116
3131
  * @example
3132
+ * ```ts
3117
3133
  * client.on('message', (message) => {
3118
3134
  * if (!message.content.startsWith(config.prefix)) return;
3119
3135
  * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
@@ -3122,17 +3138,22 @@ ${e.message}`;
3122
3138
  * distube.jump(message, parseInt(args[0]))
3123
3139
  * .catch(err => message.channel.send("Invalid song number."));
3124
3140
  * });
3141
+ * ```ts
3142
+ *
3143
+ * @param guild - The type can be resolved to give a {@link Queue}
3144
+ * @param num - The song number to play
3145
+ *
3146
+ * @returns The new Song will be played
3125
3147
  */
3126
3148
  jump(guild, num) {
3127
3149
  return __privateMethod(this, _getQueue, getQueue_fn).call(this, guild).jump(num);
3128
3150
  }
3129
3151
  /**
3130
- * Set the repeat mode of the guild queue.\
3152
+ * Set the repeat mode of the guild queue.
3131
3153
  * Toggle mode `(Disabled -> Song -> Queue -> Disabled ->...)` if `mode` is `undefined`
3132
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
3133
- * @param {RepeatMode?} [mode] The repeat modes (toggle if `undefined`)
3134
- * @returns {RepeatMode} The new repeat mode
3154
+ *
3135
3155
  * @example
3156
+ * ```ts
3136
3157
  * client.on('message', (message) => {
3137
3158
  * if (!message.content.startsWith(config.prefix)) return;
3138
3159
  * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
@@ -3143,7 +3164,9 @@ ${e.message}`;
3143
3164
  * message.channel.send("Set repeat mode to `" + mode + "`");
3144
3165
  * }
3145
3166
  * });
3167
+ * ```ts
3146
3168
  * @example
3169
+ * ```ts
3147
3170
  * const { RepeatMode } = require("distube");
3148
3171
  * let mode;
3149
3172
  * switch(distube.setRepeatMode(message, parseInt(args[0]))) {
@@ -3158,16 +3181,21 @@ ${e.message}`;
3158
3181
  * break;
3159
3182
  * }
3160
3183
  * message.channel.send("Set repeat mode to `" + mode + "`");
3184
+ * ```ts
3185
+ *
3186
+ * @param guild - The type can be resolved to give a {@link Queue}
3187
+ * @param mode - The repeat modes (toggle if `undefined`)
3188
+ *
3189
+ * @returns The new repeat mode
3161
3190
  */
3162
3191
  setRepeatMode(guild, mode) {
3163
3192
  return __privateMethod(this, _getQueue, getQueue_fn).call(this, guild).setRepeatMode(mode);
3164
3193
  }
3165
3194
  /**
3166
3195
  * Toggle autoplay mode
3167
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
3168
- * @returns {boolean} Autoplay mode state
3169
- * @throws {Error}
3196
+ *
3170
3197
  * @example
3198
+ * ```ts
3171
3199
  * client.on('message', (message) => {
3172
3200
  * if (!message.content.startsWith(config.prefix)) return;
3173
3201
  * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
@@ -3177,6 +3205,11 @@ ${e.message}`;
3177
3205
  * message.channel.send("Set autoplay mode to `" + (mode ? "On" : "Off") + "`");
3178
3206
  * }
3179
3207
  * });
3208
+ * ```ts
3209
+ *
3210
+ * @param guild - The type can be resolved to give a {@link Queue}
3211
+ *
3212
+ * @returns Autoplay mode state
3180
3213
  */
3181
3214
  toggleAutoplay(guild) {
3182
3215
  const queue = __privateMethod(this, _getQueue, getQueue_fn).call(this, guild);
@@ -3185,18 +3218,19 @@ ${e.message}`;
3185
3218
  }
3186
3219
  /**
3187
3220
  * Add related song to the queue
3188
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
3189
- * @returns {Promise<Song>} The guild queue
3221
+ *
3222
+ * @param guild - The type can be resolved to give a {@link Queue}
3223
+ *
3224
+ * @returns The guild queue
3190
3225
  */
3191
3226
  addRelatedSong(guild) {
3192
3227
  return __privateMethod(this, _getQueue, getQueue_fn).call(this, guild).addRelatedSong();
3193
3228
  }
3194
3229
  /**
3195
3230
  * Set the playing time to another position
3196
- * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}
3197
- * @param {number} time Time in seconds
3198
- * @returns {Queue} Seeked queue
3231
+ *
3199
3232
  * @example
3233
+ * ```ts
3200
3234
  * client.on('message', message => {
3201
3235
  * if (!message.content.startsWith(config.prefix)) return;
3202
3236
  * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
@@ -3204,19 +3238,25 @@ ${e.message}`;
3204
3238
  * if (command = 'seek')
3205
3239
  * distube.seek(message, Number(args[0]));
3206
3240
  * });
3241
+ * ```ts
3242
+ *
3243
+ * @param guild - The type can be resolved to give a {@link Queue}
3244
+ * @param time - Time in seconds
3245
+ *
3246
+ * @returns Seeked queue
3207
3247
  */
3208
3248
  seek(guild, time) {
3209
3249
  return __privateMethod(this, _getQueue, getQueue_fn).call(this, guild).seek(time);
3210
3250
  }
3211
3251
  /**
3212
3252
  * Emit error event
3213
- * @param {Error} error error
3214
- * @param {Discord.BaseGuildTextChannel} [channel] Text channel where the error is encountered.
3215
- * @private
3253
+ *
3254
+ * @param error - error
3255
+ * @param channel - Text channel where the error is encountered.
3216
3256
  */
3217
3257
  emitError(error, channel) {
3218
- if (this.listeners("error").length) {
3219
- this.emit("error", channel, error);
3258
+ if (this.listeners("error" /* ERROR */).length) {
3259
+ this.emit("error" /* ERROR */, channel, error);
3220
3260
  } else {
3221
3261
  console.error(error);
3222
3262
  console.warn("Unhandled 'error' event.");