distube 4.0.0-dev.3 → 4.0.0-dev.6

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
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ "use strict";
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -56,7 +57,7 @@ var require_package = __commonJS({
56
57
  "package.json"(exports, module2) {
57
58
  module2.exports = {
58
59
  name: "distube",
59
- version: "4.0.0-dev.3",
60
+ version: "4.0.0-dev.6",
60
61
  description: "A Discord.js module to simplify your music commands and play songs with audio filters on Discord without any API key.",
61
62
  main: "./dist/index.js",
62
63
  module: "./dist/index.mjs",
@@ -77,7 +78,7 @@ var require_package = __commonJS({
77
78
  docs: "docgen -s src/*.ts src/**/*.ts -o docs.json -c pages/index.yml -g -j jsdoc.config.json",
78
79
  lint: "prettier --check . && eslint .",
79
80
  "lint:fix": "eslint . --fix",
80
- prettier: "prettier --write **/*.{ts,json,yml,yaml,md}",
81
+ prettier: 'prettier --write "**/*.{ts,json,yml,yaml,md}"',
81
82
  build: "tsup",
82
83
  "build:check": "tsc --noEmit",
83
84
  update: "ncu -u --dep dev,prod && yarn up '**' -R",
@@ -120,43 +121,43 @@ var require_package = __commonJS({
120
121
  ],
121
122
  homepage: "https://distube.js.org/",
122
123
  dependencies: {
123
- "@distube/ytdl-core": "^4.11.1",
124
+ "@distube/ytdl-core": "^4.11.3",
124
125
  "@distube/ytpl": "^1.1.1",
125
- "@distube/ytsr": "^1.1.5",
126
+ "@distube/ytsr": "^1.1.7",
126
127
  "prism-media": "https://codeload.github.com/distubejs/prism-media/tar.gz/main#workaround.tar.gz",
127
128
  "tiny-typed-emitter": "^2.1.0",
128
- tslib: "^2.3.1"
129
+ tslib: "^2.4.0"
129
130
  },
130
131
  devDependencies: {
131
- "@babel/core": "^7.17.8",
132
- "@babel/plugin-proposal-class-properties": "^7.16.7",
133
- "@babel/plugin-proposal-object-rest-spread": "^7.17.3",
134
- "@babel/preset-env": "^7.16.11",
135
- "@babel/preset-typescript": "^7.16.7",
136
- "@commitlint/cli": "^16.2.3",
137
- "@commitlint/config-conventional": "^16.2.1",
132
+ "@babel/core": "^7.18.6",
133
+ "@babel/plugin-proposal-class-properties": "^7.18.6",
134
+ "@babel/plugin-proposal-object-rest-spread": "^7.18.6",
135
+ "@babel/preset-env": "^7.18.6",
136
+ "@babel/preset-typescript": "^7.18.6",
137
+ "@commitlint/cli": "^17.0.3",
138
+ "@commitlint/config-conventional": "^17.0.3",
138
139
  "@discordjs/voice": "dev",
139
140
  "@distube/docgen": "distubejs/docgen",
140
- "@types/jest": "^27.4.1",
141
- "@types/node": "^17.0.23",
142
- "@typescript-eslint/eslint-plugin": "^5.17.0",
143
- "@typescript-eslint/parser": "^5.17.0",
144
- "babel-jest": "^27.5.1",
141
+ "@types/jest": "^28.1.5",
142
+ "@types/node": "^18.0.4",
143
+ "@typescript-eslint/eslint-plugin": "^5.30.6",
144
+ "@typescript-eslint/parser": "^5.30.6",
145
+ "babel-jest": "^28.1.3",
145
146
  "discord.js": "dev",
146
- eslint: "^8.12.0",
147
+ eslint: "^8.19.0",
147
148
  "eslint-config-distube": "^1.6.4",
148
149
  "eslint-config-prettier": "^8.5.0",
149
150
  "eslint-plugin-deprecation": "^1.3.2",
150
- "eslint-plugin-jsdoc": "^38.1.4",
151
- husky: "^7.0.4",
152
- jest: "^27.5.1",
151
+ "eslint-plugin-jsdoc": "^39.3.3",
152
+ husky: "^8.0.1",
153
+ jest: "^28.1.3",
153
154
  "jsdoc-babel": "^0.5.0",
154
- "nano-staged": "^0.6.0",
155
- "npm-check-updates": "^12.5.4",
155
+ "nano-staged": "^0.8.0",
156
+ "npm-check-updates": "^15.3.0",
156
157
  pinst: "^3.0.0",
157
- prettier: "^2.6.1",
158
- tsup: "^5.12.1",
159
- typescript: "^4.6.3"
158
+ prettier: "^2.7.1",
159
+ tsup: "^6.1.3",
160
+ typescript: "^4.7.4"
160
161
  },
161
162
  peerDependencies: {
162
163
  "@discordjs/opus": "*",
@@ -210,9 +211,11 @@ __export(src_exports, {
210
211
  Queue: () => Queue,
211
212
  QueueManager: () => QueueManager,
212
213
  RepeatMode: () => RepeatMode,
213
- SearchResult: () => SearchResult,
214
+ SearchResultPlaylist: () => SearchResultPlaylist,
214
215
  SearchResultType: () => SearchResultType,
216
+ SearchResultVideo: () => SearchResultVideo,
215
217
  Song: () => Song,
218
+ StreamType: () => StreamType,
216
219
  TaskQueue: () => TaskQueue,
217
220
  checkIntents: () => checkIntents,
218
221
  checkInvalidKey: () => checkInvalidKey,
@@ -220,7 +223,6 @@ __export(src_exports, {
220
223
  default: () => DisTube,
221
224
  defaultFilters: () => defaultFilters,
222
225
  defaultOptions: () => defaultOptions,
223
- entersState: () => entersState,
224
226
  formatDuration: () => formatDuration,
225
227
  getResponseHeaders: () => getResponseHeaders,
226
228
  isClientInstance: () => isClientInstance,
@@ -260,6 +262,11 @@ var SearchResultType = /* @__PURE__ */ ((SearchResultType2) => {
260
262
  SearchResultType2["PLAYLIST"] = "playlist";
261
263
  return SearchResultType2;
262
264
  })(SearchResultType || {});
265
+ var StreamType = /* @__PURE__ */ ((StreamType2) => {
266
+ StreamType2[StreamType2["OPUS"] = 0] = "OPUS";
267
+ StreamType2[StreamType2["RAW"] = 1] = "RAW";
268
+ return StreamType2;
269
+ })(StreamType || {});
263
270
 
264
271
  // src/constant.ts
265
272
  var defaultFilters = {
@@ -293,13 +300,14 @@ var defaultOptions = {
293
300
  nsfw: false,
294
301
  emitAddSongWhenCreatingQueue: true,
295
302
  emitAddListWhenCreatingQueue: true,
296
- joinNewVoiceChannel: true
303
+ joinNewVoiceChannel: true,
304
+ streamType: 0 /* OPUS */
297
305
  };
298
306
 
299
307
  // src/struct/DisTubeError.ts
300
308
  var import_node_util = require("util");
301
309
  var ERROR_MESSAGES = {
302
- INVALID_TYPE: (expected, got, name) => `Expected ${Array.isArray(expected) ? expected.map((e) => typeof e === "number" ? e : `'${e}'`).join(" or ") : `'${expected}'`}${name ? ` for '${name}'` : ""}, but got ${(0, import_node_util.inspect)(got)}`,
310
+ INVALID_TYPE: (expected, got, name) => `Expected ${Array.isArray(expected) ? expected.map((e) => typeof e === "number" ? e : `'${e}'`).join(" or ") : `'${expected}'`}${name ? ` for '${name}'` : ""}, but got ${(0, import_node_util.inspect)(got)} (${typeof got})`,
303
311
  NUMBER_COMPARE: (name, expected, value) => `'${name}' must be ${expected} ${value}`,
304
312
  EMPTY_ARRAY: (name) => `'${name}' is an empty array`,
305
313
  EMPTY_FILTERED_ARRAY: (name, type) => `There is no valid '${type}' in the '${name}' array`,
@@ -315,7 +323,8 @@ var ERROR_MESSAGES = {
315
323
  VOICE_CONNECT_FAILED: (s) => `Cannot connect to the voice channel after ${s} seconds`,
316
324
  VOICE_MISSING_PERMS: "I do not have permission to join this voice channel",
317
325
  VOICE_RECONNECT_FAILED: "Cannot reconnect to the voice channel",
318
- VOICE_DIFFERENT_GUILD: "Cannot join a channel in a different guild",
326
+ VOICE_DIFFERENT_GUILD: "Cannot join a voice channel in a different guild",
327
+ VOICE_DIFFERENT_CLIENT: "Cannot join a voice channel created by a different client",
319
328
  NO_QUEUE: "There is no playing queue in this guild",
320
329
  QUEUE_EXIST: "This guild has a Queue already",
321
330
  PAUSED: "The queue has been paused already",
@@ -354,6 +363,7 @@ var DisTubeError = class extends Error {
354
363
  return this.errorCode;
355
364
  }
356
365
  };
366
+ __name(DisTubeError, "DisTubeError");
357
367
 
358
368
  // src/struct/TaskQueue.ts
359
369
  var Task = class {
@@ -367,6 +377,7 @@ var Task = class {
367
377
  });
368
378
  }
369
379
  };
380
+ __name(Task, "Task");
370
381
  var _tasks;
371
382
  var TaskQueue = class {
372
383
  constructor() {
@@ -387,6 +398,7 @@ var TaskQueue = class {
387
398
  return !!__privateGet(this, _tasks).find((t) => t.resolveInfo);
388
399
  }
389
400
  };
401
+ __name(TaskQueue, "TaskQueue");
390
402
  _tasks = new WeakMap();
391
403
 
392
404
  // src/struct/Playlist.ts
@@ -401,26 +413,33 @@ var Playlist = class {
401
413
  __publicField(this, "url");
402
414
  __publicField(this, "thumbnail");
403
415
  const { member, properties, metadata } = options;
404
- if (typeof playlist !== "object") {
405
- throw new DisTubeError("INVALID_TYPE", ["Array<Song>", "object"], playlist, "playlist");
416
+ if (typeof playlist !== "object" || !Array.isArray(playlist) && ["source", "songs"].some((key) => !(key in playlist))) {
417
+ throw new DisTubeError("INVALID_TYPE", ["Array<Song>", "PlaylistInfo"], playlist, "playlist");
406
418
  }
407
419
  if (typeof properties !== "undefined" && !isRecord(properties)) {
408
420
  throw new DisTubeError("INVALID_TYPE", "object", properties, "properties");
409
421
  }
410
- const info = playlist;
411
- this.source = (info.source || properties?.source || "youtube").toLowerCase();
412
- this.songs = Array.isArray(info) ? info : info.items || info.songs;
413
- if (!Array.isArray(this.songs) || !this.songs.length) {
414
- throw new DisTubeError("EMPTY_PLAYLIST");
422
+ if (Array.isArray(playlist)) {
423
+ this.source = "youtube";
424
+ if (!playlist.length)
425
+ throw new DisTubeError("EMPTY_PLAYLIST");
426
+ this.songs = playlist;
427
+ this.name = this.songs[0].name ? `${this.songs[0].name} and ${this.songs.length - 1} more songs.` : `${this.songs.length} songs playlist`;
428
+ this.thumbnail = this.songs[0].thumbnail;
429
+ } else {
430
+ this.source = (playlist.source || "youtube").toLowerCase();
431
+ if (!Array.isArray(playlist.songs) || !playlist.songs.length)
432
+ throw new DisTubeError("EMPTY_PLAYLIST");
433
+ this.songs = playlist.songs;
434
+ this.name = playlist.name || playlist.title || (this.songs[0].name ? `${this.songs[0].name} and ${this.songs.length - 1} more songs.` : `${this.songs.length} songs playlist`);
435
+ this.url = playlist.url || playlist.webpage_url;
436
+ this.thumbnail = playlist.thumbnail || this.songs[0].thumbnail;
415
437
  }
416
438
  this.songs.map((s) => s.constructor.name === "Song" && (s.playlist = this));
417
- this.member = member || info.member || void 0;
418
- this.name = info.name || info.title || (this.songs[0].name ? `${this.songs[0].name} and ${this.songs.length - 1} more songs.` : `${this.songs.length} songs playlist`);
419
- this.url = info.url || info.webpage_url;
420
- this.thumbnail = info.thumbnail?.url || info.thumbnail || this.songs[0].thumbnail;
421
439
  if (properties)
422
440
  for (const [key, value] of Object.entries(properties))
423
441
  this[key] = value;
442
+ this.member = member;
424
443
  this.metadata = metadata;
425
444
  }
426
445
  get duration() {
@@ -449,44 +468,69 @@ var Playlist = class {
449
468
  this.songs.map((s) => s.constructor.name === "Song" && (s.metadata = metadata));
450
469
  }
451
470
  };
471
+ __name(Playlist, "Playlist");
452
472
  _metadata = new WeakMap();
453
473
  _member = new WeakMap();
454
474
 
455
475
  // src/struct/SearchResult.ts
456
- var SearchResult = class {
476
+ var ISearchResult = class {
457
477
  constructor(info) {
458
478
  __publicField(this, "source");
459
- __publicField(this, "type");
460
479
  __publicField(this, "id");
461
480
  __publicField(this, "name");
462
481
  __publicField(this, "url");
463
- __publicField(this, "views");
464
- __publicField(this, "isLive");
465
- __publicField(this, "duration");
466
- __publicField(this, "formattedDuration");
467
- __publicField(this, "thumbnail");
468
482
  __publicField(this, "uploader");
469
483
  this.source = "youtube";
470
- this.type = info.type === "video" ? "video" /* VIDEO */ : "playlist" /* PLAYLIST */;
471
484
  this.id = info.id;
472
485
  this.name = info.name;
473
486
  this.url = info.url;
474
- if (this.type === "video" /* VIDEO */) {
475
- info = info;
476
- this.views = info.views;
477
- this.isLive = info.isLive;
478
- this.duration = this.isLive ? 0 : toSecond(info.duration);
479
- this.formattedDuration = this.isLive ? "Live" : formatDuration(this.duration);
480
- this.thumbnail = info.thumbnail;
481
- } else if (this.type !== "playlist") {
482
- throw new DisTubeError("INVALID_TYPE", ["video", "playlist"], this.type, "SearchResult.type");
483
- }
484
487
  this.uploader = {
485
- name: (info.author || info.owner)?.name,
486
- url: (info.author || info.owner)?.url
488
+ name: void 0,
489
+ url: void 0
490
+ };
491
+ }
492
+ };
493
+ __name(ISearchResult, "ISearchResult");
494
+ var SearchResultVideo = class extends ISearchResult {
495
+ constructor(info) {
496
+ super(info);
497
+ __publicField(this, "type");
498
+ __publicField(this, "views");
499
+ __publicField(this, "isLive");
500
+ __publicField(this, "duration");
501
+ __publicField(this, "formattedDuration");
502
+ __publicField(this, "thumbnail");
503
+ if (info.type !== "video")
504
+ throw new DisTubeError("INVALID_TYPE", "video", info.type, "type");
505
+ this.type = "video" /* VIDEO */;
506
+ this.views = info.views;
507
+ this.isLive = info.isLive;
508
+ this.duration = this.isLive ? 0 : toSecond(info.duration);
509
+ this.formattedDuration = this.isLive ? "Live" : formatDuration(this.duration);
510
+ this.thumbnail = info.thumbnail;
511
+ this.uploader = {
512
+ name: info.author?.name,
513
+ url: info.author?.url
487
514
  };
488
515
  }
489
516
  };
517
+ __name(SearchResultVideo, "SearchResultVideo");
518
+ var SearchResultPlaylist = class extends ISearchResult {
519
+ constructor(info) {
520
+ super(info);
521
+ __publicField(this, "type");
522
+ __publicField(this, "length");
523
+ if (info.type !== "playlist")
524
+ throw new DisTubeError("INVALID_TYPE", "playlist", info.type, "type");
525
+ this.type = "playlist" /* PLAYLIST */;
526
+ this.length = info.length;
527
+ this.uploader = {
528
+ name: info.owner?.name,
529
+ url: info.owner?.url
530
+ };
531
+ }
532
+ };
533
+ __name(SearchResultPlaylist, "SearchResultPlaylist");
490
534
 
491
535
  // src/struct/Song.ts
492
536
  var _metadata2, _member2, _playlist;
@@ -621,112 +665,11 @@ var _Song = class {
621
665
  }
622
666
  };
623
667
  var Song = _Song;
668
+ __name(Song, "Song");
624
669
  _metadata2 = new WeakMap();
625
670
  _member2 = new WeakMap();
626
671
  _playlist = new WeakMap();
627
672
 
628
- // src/core/DisTubeOptions.ts
629
- var _validateOptions, validateOptions_fn;
630
- var Options = class {
631
- constructor(options) {
632
- __privateAdd(this, _validateOptions);
633
- __publicField(this, "plugins");
634
- __publicField(this, "emitNewSongOnly");
635
- __publicField(this, "leaveOnFinish");
636
- __publicField(this, "leaveOnStop");
637
- __publicField(this, "leaveOnEmpty");
638
- __publicField(this, "emptyCooldown");
639
- __publicField(this, "savePreviousSongs");
640
- __publicField(this, "searchSongs");
641
- __publicField(this, "searchCooldown");
642
- __publicField(this, "youtubeCookie");
643
- __publicField(this, "youtubeIdentityToken");
644
- __publicField(this, "customFilters");
645
- __publicField(this, "ytdlOptions");
646
- __publicField(this, "nsfw");
647
- __publicField(this, "emitAddSongWhenCreatingQueue");
648
- __publicField(this, "emitAddListWhenCreatingQueue");
649
- __publicField(this, "joinNewVoiceChannel");
650
- if (typeof options !== "object" || Array.isArray(options)) {
651
- throw new DisTubeError("INVALID_TYPE", "object", options, "DisTubeOptions");
652
- }
653
- const opts = { ...defaultOptions, ...options };
654
- this.plugins = opts.plugins;
655
- this.emitNewSongOnly = opts.emitNewSongOnly;
656
- this.leaveOnEmpty = opts.leaveOnEmpty;
657
- this.leaveOnFinish = opts.leaveOnFinish;
658
- this.leaveOnStop = opts.leaveOnStop;
659
- this.savePreviousSongs = opts.savePreviousSongs;
660
- this.searchSongs = opts.searchSongs;
661
- this.youtubeCookie = opts.youtubeCookie;
662
- this.youtubeIdentityToken = opts.youtubeIdentityToken;
663
- this.customFilters = opts.customFilters;
664
- this.ytdlOptions = opts.ytdlOptions;
665
- this.searchCooldown = opts.searchCooldown;
666
- this.emptyCooldown = opts.emptyCooldown;
667
- this.nsfw = opts.nsfw;
668
- this.emitAddSongWhenCreatingQueue = opts.emitAddSongWhenCreatingQueue;
669
- this.emitAddListWhenCreatingQueue = opts.emitAddListWhenCreatingQueue;
670
- this.joinNewVoiceChannel = opts.joinNewVoiceChannel;
671
- checkInvalidKey(opts, this, "DisTubeOptions");
672
- __privateMethod(this, _validateOptions, validateOptions_fn).call(this);
673
- }
674
- };
675
- _validateOptions = new WeakSet();
676
- validateOptions_fn = /* @__PURE__ */ __name(function(options = this) {
677
- if (typeof options.emitNewSongOnly !== "boolean") {
678
- throw new DisTubeError("INVALID_TYPE", "boolean", options.emitNewSongOnly, "DisTubeOptions.emitNewSongOnly");
679
- }
680
- if (typeof options.leaveOnEmpty !== "boolean") {
681
- throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnEmpty, "DisTubeOptions.leaveOnEmpty");
682
- }
683
- if (typeof options.leaveOnFinish !== "boolean") {
684
- throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnFinish, "DisTubeOptions.leaveOnFinish");
685
- }
686
- if (typeof options.leaveOnStop !== "boolean") {
687
- throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnStop, "DisTubeOptions.leaveOnStop");
688
- }
689
- if (typeof options.savePreviousSongs !== "boolean") {
690
- throw new DisTubeError("INVALID_TYPE", "boolean", options.savePreviousSongs, "DisTubeOptions.savePreviousSongs");
691
- }
692
- if (typeof options.joinNewVoiceChannel !== "boolean") {
693
- throw new DisTubeError("INVALID_TYPE", "boolean", options.joinNewVoiceChannel, "DisTubeOptions.joinNewVoiceChannel");
694
- }
695
- if (typeof options.youtubeCookie !== "undefined" && typeof options.youtubeCookie !== "string") {
696
- throw new DisTubeError("INVALID_TYPE", "string", options.youtubeCookie, "DisTubeOptions.youtubeCookie");
697
- }
698
- if (typeof options.youtubeIdentityToken !== "undefined" && typeof options.youtubeIdentityToken !== "string") {
699
- throw new DisTubeError("INVALID_TYPE", "string", options.youtubeIdentityToken, "DisTubeOptions.youtubeIdentityToken");
700
- }
701
- if (typeof options.customFilters !== "undefined" && typeof options.customFilters !== "object" || Array.isArray(options.customFilters)) {
702
- throw new DisTubeError("INVALID_TYPE", "object", options.customFilters, "DisTubeOptions.customFilters");
703
- }
704
- if (typeof options.ytdlOptions !== "object" || Array.isArray(options.ytdlOptions)) {
705
- throw new DisTubeError("INVALID_TYPE", "object", options.ytdlOptions, "DisTubeOptions.ytdlOptions");
706
- }
707
- if (typeof options.searchCooldown !== "number" || isNaN(options.searchCooldown)) {
708
- throw new DisTubeError("INVALID_TYPE", "number", options.searchCooldown, "DisTubeOptions.searchCooldown");
709
- }
710
- if (typeof options.emptyCooldown !== "number" || isNaN(options.emptyCooldown)) {
711
- throw new DisTubeError("INVALID_TYPE", "number", options.emptyCooldown, "DisTubeOptions.emptyCooldown");
712
- }
713
- if (typeof options.searchSongs !== "number" || isNaN(options.searchSongs)) {
714
- throw new DisTubeError("INVALID_TYPE", "number", options.searchSongs, "DisTubeOptions.searchSongs");
715
- }
716
- if (!Array.isArray(options.plugins)) {
717
- throw new DisTubeError("INVALID_TYPE", "Array<Plugin>", options.plugins, "DisTubeOptions.plugins");
718
- }
719
- if (typeof options.nsfw !== "boolean") {
720
- throw new DisTubeError("INVALID_TYPE", "boolean", options.nsfw, "DisTubeOptions.nsfw");
721
- }
722
- if (typeof options.emitAddSongWhenCreatingQueue !== "boolean") {
723
- throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddSongWhenCreatingQueue, "DisTubeOptions.emitAddSongWhenCreatingQueue");
724
- }
725
- if (typeof options.emitAddListWhenCreatingQueue !== "boolean") {
726
- throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddListWhenCreatingQueue, "DisTubeOptions.emitAddListWhenCreatingQueue");
727
- }
728
- }, "#validateOptions");
729
-
730
673
  // src/core/DisTubeBase.ts
731
674
  var DisTubeBase = class {
732
675
  constructor(distube) {
@@ -755,85 +698,209 @@ var DisTubeBase = class {
755
698
  return this.distube.handler;
756
699
  }
757
700
  };
701
+ __name(DisTubeBase, "DisTubeBase");
758
702
 
759
- // src/core/DisTubeStream.ts
760
- var import_prism_media = require("prism-media");
703
+ // src/core/DisTubeVoice.ts
704
+ var import_tiny_typed_emitter = require("tiny-typed-emitter");
761
705
  var import_voice = require("@discordjs/voice");
762
- var chooseBestVideoFormat = /* @__PURE__ */ __name((formats, isLive = false) => {
763
- let filter = /* @__PURE__ */ __name((format) => format.hasAudio, "filter");
764
- if (isLive)
765
- filter = /* @__PURE__ */ __name((format) => format.hasAudio && format.isHLS, "filter");
766
- formats = formats.filter(filter).sort((a, b) => Number(b.audioBitrate) - Number(a.audioBitrate) || Number(a.bitrate) - Number(b.bitrate));
767
- return formats.find((format) => !format.hasVideo) || formats.sort((a, b) => Number(a.bitrate) - Number(b.bitrate))[0];
768
- }, "chooseBestVideoFormat");
769
- var DisTubeStream = class {
770
- constructor(url, options) {
771
- __publicField(this, "type");
772
- __publicField(this, "stream");
773
- __publicField(this, "url");
774
- this.url = url;
775
- this.type = import_voice.StreamType.Raw;
776
- const args = [
777
- "-reconnect",
778
- "1",
779
- "-reconnect_streamed",
780
- "1",
781
- "-reconnect_delay_max",
782
- "5",
783
- "-i",
784
- url,
785
- "-analyzeduration",
786
- "0",
787
- "-loglevel",
788
- "0",
789
- "-ar",
790
- "48000",
791
- "-ac",
792
- "2",
793
- "-f",
794
- "s16le"
795
- ];
796
- if (typeof options.seek === "number" && options.seek > 0) {
797
- args.unshift("-ss", options.seek.toString());
798
- }
799
- if (Array.isArray(options.ffmpegArgs)) {
800
- args.push(...options.ffmpegArgs);
801
- }
802
- this.stream = new import_prism_media.FFmpeg({ args, shell: false });
706
+ var _channel, _volume, _br, br_fn, _join, join_fn;
707
+ var DisTubeVoice = class extends import_tiny_typed_emitter.TypedEmitter {
708
+ constructor(voiceManager, channel) {
709
+ super();
710
+ __privateAdd(this, _br);
711
+ __privateAdd(this, _join);
712
+ __publicField(this, "id");
713
+ __publicField(this, "voices");
714
+ __publicField(this, "audioPlayer");
715
+ __publicField(this, "connection");
716
+ __publicField(this, "audioResource");
717
+ __publicField(this, "emittedError");
718
+ __publicField(this, "isDisconnected", false);
719
+ __privateAdd(this, _channel, void 0);
720
+ __privateAdd(this, _volume, 100);
721
+ this.voices = voiceManager;
722
+ this.id = channel.guildId;
723
+ this.channel = channel;
724
+ this.voices.add(this.id, this);
725
+ this.audioPlayer = (0, import_voice.createAudioPlayer)().on(import_voice.AudioPlayerStatus.Idle, (oldState) => {
726
+ if (oldState.status !== import_voice.AudioPlayerStatus.Idle) {
727
+ delete this.audioResource;
728
+ this.emit("finish");
729
+ }
730
+ }).on(import_voice.AudioPlayerStatus.Playing, () => __privateMethod(this, _br, br_fn).call(this)).on("error", (error) => {
731
+ if (this.emittedError)
732
+ return;
733
+ this.emittedError = true;
734
+ this.emit("error", error);
735
+ });
736
+ this.connection.on(import_voice.VoiceConnectionStatus.Disconnected, (_, newState) => {
737
+ if (newState.reason === import_voice.VoiceConnectionDisconnectReason.Manual) {
738
+ this.leave();
739
+ } else if (newState.reason === import_voice.VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {
740
+ (0, import_voice.entersState)(this.connection, import_voice.VoiceConnectionStatus.Connecting, 5e3).catch(() => {
741
+ if (![import_voice.VoiceConnectionStatus.Ready, import_voice.VoiceConnectionStatus.Connecting].includes(this.connection.state.status)) {
742
+ this.leave();
743
+ }
744
+ });
745
+ } else if (this.connection.rejoinAttempts < 5) {
746
+ setTimeout(() => {
747
+ this.connection.rejoin();
748
+ }, (this.connection.rejoinAttempts + 1) * 5e3).unref();
749
+ } else if (this.connection.state.status !== import_voice.VoiceConnectionStatus.Destroyed) {
750
+ this.leave(new DisTubeError("VOICE_RECONNECT_FAILED"));
751
+ }
752
+ }).on(import_voice.VoiceConnectionStatus.Destroyed, () => {
753
+ this.leave();
754
+ }).on("error", () => void 0);
755
+ this.connection.subscribe(this.audioPlayer);
803
756
  }
804
- static YouTube(formats, options = {}) {
805
- if (!formats || !formats.length)
806
- throw new DisTubeError("UNAVAILABLE_VIDEO");
807
- if (!options || typeof options !== "object" || Array.isArray(options)) {
808
- throw new DisTubeError("INVALID_TYPE", "object", options, "options");
809
- }
810
- const bestFormat = chooseBestVideoFormat(formats, options.isLive);
811
- if (!bestFormat)
812
- throw new DisTubeError("UNPLAYABLE_FORMATS");
813
- return new DisTubeStream(bestFormat.url, options);
757
+ get channel() {
758
+ return __privateGet(this, _channel);
814
759
  }
815
- static DirectLink(url, options = {}) {
816
- if (!options || typeof options !== "object" || Array.isArray(options)) {
817
- throw new DisTubeError("INVALID_TYPE", "object", options, "options");
760
+ set channel(channel) {
761
+ if (!isSupportedVoiceChannel(channel)) {
762
+ throw new DisTubeError("INVALID_TYPE", "BaseGuildVoiceChannel", channel, "DisTubeVoice#channel");
818
763
  }
819
- if (typeof url !== "string" || !isURL(url)) {
820
- throw new DisTubeError("INVALID_TYPE", "an URL", url);
764
+ if (channel.guildId !== this.id)
765
+ throw new DisTubeError("VOICE_DIFFERENT_GUILD");
766
+ if (channel.client.user?.id !== this.voices.client.user?.id)
767
+ throw new DisTubeError("VOICE_DIFFERENT_CLIENT");
768
+ if (channel.id === __privateGet(this, _channel)?.id)
769
+ return;
770
+ if (!channel.joinable) {
771
+ if (channel.full)
772
+ throw new DisTubeError("VOICE_FULL");
773
+ else
774
+ throw new DisTubeError("VOICE_MISSING_PERMS");
821
775
  }
822
- return new DisTubeStream(url, options);
823
- }
824
- };
825
-
826
- // src/core/manager/BaseManager.ts
827
- var import_discord = require("discord.js");
828
- var BaseManager = class extends DisTubeBase {
829
- constructor() {
830
- super(...arguments);
831
- __publicField(this, "collection", new import_discord.Collection());
776
+ this.connection = __privateMethod(this, _join, join_fn).call(this, channel);
777
+ __privateSet(this, _channel, channel);
778
+ __privateMethod(this, _br, br_fn).call(this);
832
779
  }
833
- get size() {
834
- return this.collection.size;
780
+ async join(channel) {
781
+ const TIMEOUT = 3e4;
782
+ if (channel)
783
+ this.channel = channel;
784
+ try {
785
+ await (0, import_voice.entersState)(this.connection, import_voice.VoiceConnectionStatus.Ready, TIMEOUT);
786
+ } catch {
787
+ if (this.connection.state.status === import_voice.VoiceConnectionStatus.Ready)
788
+ return this;
789
+ if (this.connection.state.status !== import_voice.VoiceConnectionStatus.Destroyed)
790
+ this.connection.destroy();
791
+ this.voices.remove(this.id);
792
+ throw new DisTubeError("VOICE_CONNECT_FAILED", TIMEOUT / 1e3);
793
+ }
794
+ return this;
795
+ }
796
+ leave(error) {
797
+ this.stop(true);
798
+ if (!this.isDisconnected) {
799
+ this.emit("disconnect", error);
800
+ this.isDisconnected = true;
801
+ }
802
+ if (this.connection.state.status !== import_voice.VoiceConnectionStatus.Destroyed)
803
+ this.connection.destroy();
804
+ this.voices.remove(this.id);
805
+ }
806
+ stop(force = false) {
807
+ this.audioPlayer.stop(force);
808
+ }
809
+ play(stream) {
810
+ this.emittedError = false;
811
+ stream.stream.on("error", (error) => {
812
+ if (this.emittedError || error.code === "ERR_STREAM_PREMATURE_CLOSE")
813
+ return;
814
+ this.emittedError = true;
815
+ this.emit("error", error);
816
+ });
817
+ this.audioResource = (0, import_voice.createAudioResource)(stream.stream, {
818
+ inputType: stream.type,
819
+ inlineVolume: true
820
+ });
821
+ this.volume = __privateGet(this, _volume);
822
+ this.audioPlayer.play(this.audioResource);
823
+ }
824
+ set volume(volume) {
825
+ if (typeof volume !== "number" || isNaN(volume)) {
826
+ throw new DisTubeError("INVALID_TYPE", "number", volume, "volume");
827
+ }
828
+ if (volume < 0) {
829
+ throw new DisTubeError("NUMBER_COMPARE", "Volume", "bigger or equal to", 0);
830
+ }
831
+ __privateSet(this, _volume, volume);
832
+ this.audioResource?.volume?.setVolume(Math.pow(__privateGet(this, _volume) / 100, 0.5 / Math.log10(2)));
833
+ }
834
+ get volume() {
835
+ return __privateGet(this, _volume);
836
+ }
837
+ get playbackDuration() {
838
+ return (this.audioResource?.playbackDuration ?? 0) / 1e3;
839
+ }
840
+ pause() {
841
+ this.audioPlayer.pause();
842
+ }
843
+ unpause() {
844
+ this.audioPlayer.unpause();
845
+ }
846
+ get selfDeaf() {
847
+ return this.connection.joinConfig.selfDeaf;
848
+ }
849
+ get selfMute() {
850
+ return this.connection.joinConfig.selfMute;
851
+ }
852
+ setSelfDeaf(selfDeaf) {
853
+ if (typeof selfDeaf !== "boolean") {
854
+ throw new DisTubeError("INVALID_TYPE", "boolean", selfDeaf, "selfDeaf");
855
+ }
856
+ return this.connection.rejoin({
857
+ ...this.connection.joinConfig,
858
+ selfDeaf
859
+ });
860
+ }
861
+ setSelfMute(selfMute) {
862
+ if (typeof selfMute !== "boolean") {
863
+ throw new DisTubeError("INVALID_TYPE", "boolean", selfMute, "selfMute");
864
+ }
865
+ return this.connection.rejoin({
866
+ ...this.connection.joinConfig,
867
+ selfMute
868
+ });
869
+ }
870
+ get voiceState() {
871
+ return this.channel?.guild?.members?.me?.voice;
872
+ }
873
+ };
874
+ __name(DisTubeVoice, "DisTubeVoice");
875
+ _channel = new WeakMap();
876
+ _volume = new WeakMap();
877
+ _br = new WeakSet();
878
+ br_fn = /* @__PURE__ */ __name(function() {
879
+ if (this.audioResource?.encoder?.encoder)
880
+ this.audioResource.encoder.setBitrate(this.channel.bitrate);
881
+ }, "#br");
882
+ _join = new WeakSet();
883
+ join_fn = /* @__PURE__ */ __name(function(channel) {
884
+ return (0, import_voice.joinVoiceChannel)({
885
+ channelId: channel.id,
886
+ guildId: this.id,
887
+ adapterCreator: channel.guild.voiceAdapterCreator,
888
+ group: channel.client.user?.id
889
+ });
890
+ }, "#join");
891
+
892
+ // src/core/manager/BaseManager.ts
893
+ var import_discord = require("discord.js");
894
+ var BaseManager = class extends DisTubeBase {
895
+ constructor() {
896
+ super(...arguments);
897
+ __publicField(this, "collection", new import_discord.Collection());
898
+ }
899
+ get size() {
900
+ return this.collection.size;
835
901
  }
836
902
  };
903
+ __name(BaseManager, "BaseManager");
837
904
 
838
905
  // src/core/manager/GuildIdManager.ts
839
906
  var GuildIdManager = class extends BaseManager {
@@ -854,6 +921,124 @@ var GuildIdManager = class extends BaseManager {
854
921
  return this.collection.has(resolveGuildId(idOrInstance));
855
922
  }
856
923
  };
924
+ __name(GuildIdManager, "GuildIdManager");
925
+
926
+ // src/core/manager/DisTubeVoiceManager.ts
927
+ var import_voice2 = require("@discordjs/voice");
928
+ var DisTubeVoiceManager = class extends GuildIdManager {
929
+ create(channel) {
930
+ const existing = this.get(channel.guildId);
931
+ if (existing) {
932
+ existing.channel = channel;
933
+ return existing;
934
+ }
935
+ return new DisTubeVoice(this, channel);
936
+ }
937
+ join(channel) {
938
+ const existing = this.get(channel.guildId);
939
+ if (existing)
940
+ return existing.join(channel);
941
+ return this.create(channel).join();
942
+ }
943
+ leave(guild) {
944
+ const voice = this.get(guild);
945
+ if (voice) {
946
+ voice.leave();
947
+ } else {
948
+ const connection = (0, import_voice2.getVoiceConnection)(resolveGuildId(guild), this.client.user?.id) ?? (0, import_voice2.getVoiceConnection)(resolveGuildId(guild));
949
+ if (connection && connection.state.status !== import_voice2.VoiceConnectionStatus.Destroyed) {
950
+ connection.destroy();
951
+ }
952
+ }
953
+ }
954
+ };
955
+ __name(DisTubeVoiceManager, "DisTubeVoiceManager");
956
+
957
+ // src/core/manager/FilterManager.ts
958
+ var _validate, validate_fn, _resolveName, resolveName_fn, _resolveValue, resolveValue_fn, _apply, apply_fn;
959
+ var FilterManager = class extends BaseManager {
960
+ constructor(queue) {
961
+ super(queue.distube);
962
+ __privateAdd(this, _validate);
963
+ __privateAdd(this, _resolveName);
964
+ __privateAdd(this, _resolveValue);
965
+ __privateAdd(this, _apply);
966
+ __publicField(this, "queue");
967
+ this.queue = queue;
968
+ }
969
+ add(filterOrFilters, override = false) {
970
+ if (Array.isArray(filterOrFilters)) {
971
+ const resolvedFilters = filterOrFilters.map((f) => __privateMethod(this, _validate, validate_fn).call(this, f));
972
+ const newFilters = resolvedFilters.reduceRight((unique, o) => {
973
+ if (!unique.some((obj) => obj === o && obj.name === o) && !unique.some((obj) => obj !== o.name && obj.name !== o.name)) {
974
+ if (!this.has(o))
975
+ unique.push(o);
976
+ if (this.has(o) && override) {
977
+ this.remove(o);
978
+ unique.push(o);
979
+ }
980
+ }
981
+ return unique;
982
+ }, []).reverse();
983
+ return this.set([...this.collection.values(), ...newFilters]);
984
+ }
985
+ return this.set([...this.collection.values(), filterOrFilters]);
986
+ }
987
+ clear() {
988
+ return this.set([]);
989
+ }
990
+ set(filters) {
991
+ this.collection.clear();
992
+ for (const filter of filters) {
993
+ const resolved = __privateMethod(this, _validate, validate_fn).call(this, filter);
994
+ this.collection.set(__privateMethod(this, _resolveName, resolveName_fn).call(this, resolved), resolved);
995
+ }
996
+ __privateMethod(this, _apply, apply_fn).call(this);
997
+ return this;
998
+ }
999
+ remove(filterOrFilters) {
1000
+ const remove = /* @__PURE__ */ __name((f) => this.collection.delete(__privateMethod(this, _resolveName, resolveName_fn).call(this, __privateMethod(this, _validate, validate_fn).call(this, f))), "remove");
1001
+ if (Array.isArray(filterOrFilters))
1002
+ filterOrFilters.map(remove);
1003
+ else
1004
+ remove(filterOrFilters);
1005
+ __privateMethod(this, _apply, apply_fn).call(this);
1006
+ return this;
1007
+ }
1008
+ has(filter) {
1009
+ return this.collection.has(__privateMethod(this, _resolveName, resolveName_fn).call(this, filter));
1010
+ }
1011
+ get names() {
1012
+ return this.collection.map((f) => __privateMethod(this, _resolveName, resolveName_fn).call(this, f));
1013
+ }
1014
+ get values() {
1015
+ return this.collection.map((f) => __privateMethod(this, _resolveValue, resolveValue_fn).call(this, f));
1016
+ }
1017
+ toString() {
1018
+ return this.names.toString();
1019
+ }
1020
+ };
1021
+ __name(FilterManager, "FilterManager");
1022
+ _validate = new WeakSet();
1023
+ validate_fn = /* @__PURE__ */ __name(function(filter) {
1024
+ if (typeof filter === "string" && Object.prototype.hasOwnProperty.call(this.distube.filters, filter) || typeof filter === "object" && typeof filter.name === "string" && typeof filter.value === "string") {
1025
+ return filter;
1026
+ }
1027
+ throw new DisTubeError("INVALID_TYPE", "FilterResolvable", filter, "filter");
1028
+ }, "#validate");
1029
+ _resolveName = new WeakSet();
1030
+ resolveName_fn = /* @__PURE__ */ __name(function(filter) {
1031
+ return typeof filter === "string" ? filter : filter.name;
1032
+ }, "#resolveName");
1033
+ _resolveValue = new WeakSet();
1034
+ resolveValue_fn = /* @__PURE__ */ __name(function(filter) {
1035
+ return typeof filter === "string" ? this.distube.filters[filter] : filter.value;
1036
+ }, "#resolveValue");
1037
+ _apply = new WeakSet();
1038
+ apply_fn = /* @__PURE__ */ __name(function() {
1039
+ this.queue.beginTime = this.queue.currentTime;
1040
+ this.queues.playSong(this.queue);
1041
+ }, "#apply");
857
1042
 
858
1043
  // src/core/manager/QueueManager.ts
859
1044
  var _voiceEventHandler, voiceEventHandler_fn, _handleSongFinish, handleSongFinish_fn, _handlePlayingError, handlePlayingError_fn, _emitPlaySong, emitPlaySong_fn;
@@ -886,7 +1071,7 @@ var QueueManager = class extends GuildIdManager {
886
1071
  const { duration, formats, isLive, source, streamURL } = queue.songs[0];
887
1072
  const ffmpegArgs = queue.filters.size ? ["-af", queue.filters.values.join(",")] : void 0;
888
1073
  const seek = duration ? queue.beginTime : void 0;
889
- const streamOptions = { ffmpegArgs, seek, isLive };
1074
+ const streamOptions = { ffmpegArgs, seek, isLive, type: this.options.streamType };
890
1075
  if (source === "youtube")
891
1076
  return DisTubeStream.YouTube(formats, streamOptions);
892
1077
  return DisTubeStream.DirectLink(streamURL, streamOptions);
@@ -900,8 +1085,8 @@ var QueueManager = class extends GuildIdManager {
900
1085
  }
901
1086
  if (queue.stopped)
902
1087
  return false;
903
- const song = queue.songs[0];
904
1088
  try {
1089
+ const song = queue.songs[0];
905
1090
  const { url, source, formats, streamURL } = song;
906
1091
  if (source === "youtube" && !formats)
907
1092
  song._patchYouTube(await this.handler.getYouTubeInfo(url));
@@ -930,6 +1115,7 @@ var QueueManager = class extends GuildIdManager {
930
1115
  }
931
1116
  }
932
1117
  };
1118
+ __name(QueueManager, "QueueManager");
933
1119
  _voiceEventHandler = new WeakSet();
934
1120
  voiceEventHandler_fn = /* @__PURE__ */ __name(function(queue) {
935
1121
  queue._listeners = {
@@ -961,371 +1147,70 @@ handleSongFinish_fn = /* @__PURE__ */ __name(async function(queue) {
961
1147
  else
962
1148
  queue.songs.unshift(queue.previousSongs.pop());
963
1149
  }
964
- if (queue.songs.length <= 1 && (queue._next || queue.repeatMode === 0 /* DISABLED */)) {
965
- if (queue.autoplay) {
966
- try {
967
- await queue.addRelatedSong();
968
- } catch {
969
- this.emit("noRelated", queue);
970
- }
971
- }
972
- if (queue.songs.length <= 1) {
973
- if (this.options.leaveOnFinish)
974
- queue.voice.leave();
975
- if (!queue.autoplay)
976
- this.emit("finish", queue);
977
- queue.remove();
978
- return;
979
- }
980
- }
981
- const emitPlaySong = __privateMethod(this, _emitPlaySong, emitPlaySong_fn).call(this, queue);
982
- if (!queue._prev && (queue.repeatMode !== 1 /* SONG */ || queue._next)) {
983
- const prev = queue.songs.shift();
984
- delete prev.formats;
985
- delete prev.streamURL;
986
- if (this.options.savePreviousSongs)
987
- queue.previousSongs.push(prev);
988
- else
989
- queue.previousSongs.push({ id: prev.id });
990
- }
991
- queue._next = queue._prev = false;
992
- queue.beginTime = 0;
993
- const err = await this.playSong(queue);
994
- if (!err && emitPlaySong)
995
- this.emit("playSong", queue, queue.songs[0]);
996
- } finally {
997
- queue._taskQueue.resolve();
998
- }
999
- }, "#handleSongFinish");
1000
- _handlePlayingError = new WeakSet();
1001
- handlePlayingError_fn = /* @__PURE__ */ __name(function(queue, error) {
1002
- const song = queue.songs.shift();
1003
- try {
1004
- error.name = "PlayingError";
1005
- error.message = `${error.message}
1006
- Id: ${song.id}
1007
- Name: ${song.name}`;
1008
- } catch {
1009
- }
1010
- this.emitError(error, queue.textChannel);
1011
- if (queue.songs.length > 0) {
1012
- this.playSong(queue).then((e) => {
1013
- if (!e)
1014
- this.emit("playSong", queue, queue.songs[0]);
1015
- });
1016
- } else {
1017
- queue.stop();
1018
- }
1019
- }, "#handlePlayingError");
1020
- _emitPlaySong = new WeakSet();
1021
- emitPlaySong_fn = /* @__PURE__ */ __name(function(queue) {
1022
- return !this.options.emitNewSongOnly || queue.repeatMode === 1 /* SONG */ && queue._next || queue.repeatMode !== 1 /* SONG */ && queue.songs[0]?.id !== queue.songs[1]?.id;
1023
- }, "#emitPlaySong");
1024
-
1025
- // src/core/manager/FilterManager.ts
1026
- var _validate, validate_fn, _resolveName, resolveName_fn, _resolveValue, resolveValue_fn, _apply, apply_fn;
1027
- var FilterManager = class extends BaseManager {
1028
- constructor(queue) {
1029
- super(queue.distube);
1030
- __privateAdd(this, _validate);
1031
- __privateAdd(this, _resolveName);
1032
- __privateAdd(this, _resolveValue);
1033
- __privateAdd(this, _apply);
1034
- __publicField(this, "queue");
1035
- this.queue = queue;
1036
- }
1037
- add(filterOrFilters, override = false) {
1038
- if (Array.isArray(filterOrFilters)) {
1039
- const resolvedFilters = filterOrFilters.map((f) => __privateMethod(this, _validate, validate_fn).call(this, f));
1040
- const newFilters = resolvedFilters.reduceRight((unique, o) => {
1041
- if (!unique.some((obj) => obj === o && obj.name === o) && !unique.some((obj) => obj !== o.name && obj.name !== o.name)) {
1042
- if (!this.has(o))
1043
- unique.push(o);
1044
- if (this.has(o) && override) {
1045
- this.remove(o);
1046
- unique.push(o);
1047
- }
1048
- }
1049
- return unique;
1050
- }, []).reverse();
1051
- return this.set([...this.collection.values(), ...newFilters]);
1052
- }
1053
- return this.set([...this.collection.values(), filterOrFilters]);
1054
- }
1055
- clear() {
1056
- return this.set([]);
1057
- }
1058
- set(filters) {
1059
- this.collection.clear();
1060
- for (const filter of filters) {
1061
- const resolved = __privateMethod(this, _validate, validate_fn).call(this, filter);
1062
- this.collection.set(__privateMethod(this, _resolveName, resolveName_fn).call(this, resolved), resolved);
1063
- }
1064
- __privateMethod(this, _apply, apply_fn).call(this);
1065
- return this;
1066
- }
1067
- remove(filterOrFilters) {
1068
- const remove = /* @__PURE__ */ __name((f) => this.collection.delete(__privateMethod(this, _resolveName, resolveName_fn).call(this, __privateMethod(this, _validate, validate_fn).call(this, f))), "remove");
1069
- if (Array.isArray(filterOrFilters))
1070
- filterOrFilters.map(remove);
1071
- else
1072
- remove(filterOrFilters);
1073
- __privateMethod(this, _apply, apply_fn).call(this);
1074
- return this;
1075
- }
1076
- has(filter) {
1077
- return this.collection.has(__privateMethod(this, _resolveName, resolveName_fn).call(this, filter));
1078
- }
1079
- get names() {
1080
- return this.collection.map((f) => __privateMethod(this, _resolveName, resolveName_fn).call(this, f));
1081
- }
1082
- get values() {
1083
- return this.collection.map((f) => __privateMethod(this, _resolveValue, resolveValue_fn).call(this, f));
1084
- }
1085
- toString() {
1086
- return this.names.toString();
1087
- }
1088
- };
1089
- _validate = new WeakSet();
1090
- validate_fn = /* @__PURE__ */ __name(function(filter) {
1091
- if (typeof filter === "string" && Object.prototype.hasOwnProperty.call(this.distube.filters, filter) || typeof filter === "object" && typeof filter.name === "string" && typeof filter.value === "string") {
1092
- return filter;
1093
- }
1094
- throw new DisTubeError("INVALID_TYPE", "FilterResolvable", filter, "filter");
1095
- }, "#validate");
1096
- _resolveName = new WeakSet();
1097
- resolveName_fn = /* @__PURE__ */ __name(function(filter) {
1098
- return typeof filter === "string" ? filter : filter.name;
1099
- }, "#resolveName");
1100
- _resolveValue = new WeakSet();
1101
- resolveValue_fn = /* @__PURE__ */ __name(function(filter) {
1102
- return typeof filter === "string" ? this.distube.filters[filter] : filter.value;
1103
- }, "#resolveValue");
1104
- _apply = new WeakSet();
1105
- apply_fn = /* @__PURE__ */ __name(function() {
1106
- this.queue.beginTime = this.queue.currentTime;
1107
- this.queues.playSong(this.queue);
1108
- }, "#apply");
1109
-
1110
- // src/core/voice/DisTubeVoice.ts
1111
- var import_tiny_typed_emitter = require("tiny-typed-emitter");
1112
- var import_voice2 = require("@discordjs/voice");
1113
- var _channel, _volume, _br, br_fn, _join, join_fn;
1114
- var DisTubeVoice = class extends import_tiny_typed_emitter.TypedEmitter {
1115
- constructor(voiceManager, channel) {
1116
- super();
1117
- __privateAdd(this, _br);
1118
- __privateAdd(this, _join);
1119
- __publicField(this, "id");
1120
- __publicField(this, "voices");
1121
- __publicField(this, "audioPlayer");
1122
- __publicField(this, "connection");
1123
- __publicField(this, "audioResource");
1124
- __publicField(this, "emittedError");
1125
- __publicField(this, "isDisconnected", false);
1126
- __privateAdd(this, _channel, void 0);
1127
- __privateAdd(this, _volume, 100);
1128
- this.id = channel.guildId;
1129
- this.channel = channel;
1130
- this.voices = voiceManager;
1131
- this.voices.add(this.id, this);
1132
- this.audioPlayer = (0, import_voice2.createAudioPlayer)().on(import_voice2.AudioPlayerStatus.Idle, (oldState) => {
1133
- if (oldState.status !== import_voice2.AudioPlayerStatus.Idle) {
1134
- delete this.audioResource;
1135
- this.emit("finish");
1136
- }
1137
- }).on(import_voice2.AudioPlayerStatus.Playing, () => __privateMethod(this, _br, br_fn).call(this)).on("error", (error) => {
1138
- if (this.emittedError)
1139
- return;
1140
- this.emittedError = true;
1141
- this.emit("error", error);
1142
- });
1143
- this.connection.on(import_voice2.VoiceConnectionStatus.Disconnected, (_, newState) => {
1144
- if (newState.reason === import_voice2.VoiceConnectionDisconnectReason.Manual) {
1145
- this.leave();
1146
- } else if (newState.reason === import_voice2.VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {
1147
- entersState(this.connection, import_voice2.VoiceConnectionStatus.Connecting, 5e3).catch(() => {
1148
- if (![import_voice2.VoiceConnectionStatus.Ready, import_voice2.VoiceConnectionStatus.Connecting].includes(this.connection.state.status)) {
1149
- this.leave();
1150
- }
1151
- });
1152
- } else if (this.connection.rejoinAttempts < 5) {
1153
- setTimeout(() => {
1154
- this.connection.rejoin();
1155
- }, (this.connection.rejoinAttempts + 1) * 5e3).unref();
1156
- } else if (this.connection.state.status !== import_voice2.VoiceConnectionStatus.Destroyed) {
1157
- this.leave(new DisTubeError("VOICE_RECONNECT_FAILED"));
1158
- }
1159
- }).on(import_voice2.VoiceConnectionStatus.Destroyed, () => {
1160
- this.leave(new DisTubeError("VOICE_RECONNECT_FAILED"));
1161
- }).on("error", () => void 0);
1162
- this.connection.subscribe(this.audioPlayer);
1163
- }
1164
- get channel() {
1165
- return __privateGet(this, _channel);
1166
- }
1167
- set channel(channel) {
1168
- if (!isSupportedVoiceChannel(channel)) {
1169
- throw new DisTubeError("INVALID_TYPE", "BaseGuildVoiceChannel", channel, "DisTubeVoice#channel");
1170
- }
1171
- if (channel.guildId !== this.id)
1172
- throw new DisTubeError("VOICE_DIFFERENT_GUILD");
1173
- if (channel.id === __privateGet(this, _channel)?.id)
1174
- return;
1175
- if (!channel.joinable) {
1176
- if (channel.full)
1177
- throw new DisTubeError("VOICE_FULL");
1178
- else
1179
- throw new DisTubeError("VOICE_MISSING_PERMS");
1180
- }
1181
- this.connection = __privateMethod(this, _join, join_fn).call(this, channel);
1182
- __privateSet(this, _channel, channel);
1183
- __privateMethod(this, _br, br_fn).call(this);
1184
- }
1185
- async join(channel) {
1186
- const TIMEOUT = 3e4;
1187
- if (channel)
1188
- this.channel = channel;
1189
- try {
1190
- await entersState(this.connection, import_voice2.VoiceConnectionStatus.Ready, TIMEOUT);
1191
- } catch {
1192
- if (this.connection.state.status === import_voice2.VoiceConnectionStatus.Ready)
1193
- return this;
1194
- if (this.connection.state.status !== import_voice2.VoiceConnectionStatus.Destroyed)
1195
- this.connection.destroy();
1196
- this.voices.remove(this.id);
1197
- throw new DisTubeError("VOICE_CONNECT_FAILED", TIMEOUT / 1e3);
1198
- }
1199
- return this;
1200
- }
1201
- leave(error) {
1202
- this.stop(true);
1203
- if (!this.isDisconnected) {
1204
- this.emit("disconnect", error);
1205
- this.isDisconnected = true;
1206
- }
1207
- if (this.connection.state.status !== import_voice2.VoiceConnectionStatus.Destroyed)
1208
- this.connection.destroy();
1209
- this.voices.remove(this.id);
1210
- }
1211
- stop(force = false) {
1212
- this.audioPlayer.stop(force);
1213
- }
1214
- play(stream) {
1215
- this.emittedError = false;
1216
- stream.stream.on("error", (error) => {
1217
- if (this.emittedError || error.code === "ERR_STREAM_PREMATURE_CLOSE")
1218
- return;
1219
- this.emittedError = true;
1220
- this.emit("error", error);
1221
- });
1222
- this.audioResource = (0, import_voice2.createAudioResource)(stream.stream, {
1223
- inputType: stream.type,
1224
- inlineVolume: true
1225
- });
1226
- this.volume = __privateGet(this, _volume);
1227
- this.audioPlayer.play(this.audioResource);
1228
- }
1229
- set volume(volume) {
1230
- if (typeof volume !== "number" || isNaN(volume)) {
1231
- throw new DisTubeError("INVALID_TYPE", "number", volume, "volume");
1232
- }
1233
- if (volume < 0) {
1234
- throw new DisTubeError("NUMBER_COMPARE", "Volume", "bigger or equal to", 0);
1235
- }
1236
- __privateSet(this, _volume, volume);
1237
- this.audioResource?.volume?.setVolume(Math.pow(__privateGet(this, _volume) / 100, 0.5 / Math.log10(2)));
1238
- }
1239
- get volume() {
1240
- return __privateGet(this, _volume);
1241
- }
1242
- get playbackDuration() {
1243
- return (this.audioResource?.playbackDuration ?? 0) / 1e3;
1244
- }
1245
- pause() {
1246
- this.audioPlayer.pause();
1247
- }
1248
- unpause() {
1249
- this.audioPlayer.unpause();
1250
- }
1251
- get selfDeaf() {
1252
- return this.connection.joinConfig.selfDeaf;
1253
- }
1254
- get selfMute() {
1255
- return this.connection.joinConfig.selfMute;
1256
- }
1257
- setSelfDeaf(selfDeaf) {
1258
- if (typeof selfDeaf !== "boolean") {
1259
- throw new DisTubeError("INVALID_TYPE", "boolean", selfDeaf, "selfDeaf");
1260
- }
1261
- return this.connection.rejoin({
1262
- ...this.connection.joinConfig,
1263
- selfDeaf
1264
- });
1265
- }
1266
- setSelfMute(selfMute) {
1267
- if (typeof selfMute !== "boolean") {
1268
- throw new DisTubeError("INVALID_TYPE", "boolean", selfMute, "selfMute");
1269
- }
1270
- return this.connection.rejoin({
1271
- ...this.connection.joinConfig,
1272
- selfMute
1273
- });
1274
- }
1275
- get voiceState() {
1276
- return this.channel?.guild?.me?.voice;
1277
- }
1278
- };
1279
- _channel = new WeakMap();
1280
- _volume = new WeakMap();
1281
- _br = new WeakSet();
1282
- br_fn = /* @__PURE__ */ __name(function() {
1283
- if (this.audioResource?.encoder?.encoder)
1284
- this.audioResource.encoder.setBitrate(this.channel.bitrate);
1285
- }, "#br");
1286
- _join = new WeakSet();
1287
- join_fn = /* @__PURE__ */ __name(function(channel) {
1288
- return (0, import_voice2.joinVoiceChannel)({
1289
- channelId: channel.id,
1290
- guildId: this.id,
1291
- adapterCreator: channel.guild.voiceAdapterCreator,
1292
- group: channel.client.user?.id
1293
- });
1294
- }, "#join");
1295
-
1296
- // src/core/voice/DisTubeVoiceManager.ts
1297
- var import_voice3 = require("@discordjs/voice");
1298
- var DisTubeVoiceManager = class extends GuildIdManager {
1299
- create(channel) {
1300
- const existing = this.get(channel.guildId);
1301
- if (existing) {
1302
- existing.channel = channel;
1303
- return existing;
1304
- }
1305
- return new DisTubeVoice(this, channel);
1306
- }
1307
- join(channel) {
1308
- const existing = this.get(channel.guildId);
1309
- if (existing)
1310
- return existing.join(channel);
1311
- return this.create(channel).join();
1312
- }
1313
- leave(guild) {
1314
- const voice = this.get(guild);
1315
- if (voice) {
1316
- voice.leave();
1317
- } else {
1318
- const connection = (0, import_voice3.getVoiceConnection)(resolveGuildId(guild), this.client.user?.id) ?? (0, import_voice3.getVoiceConnection)(resolveGuildId(guild));
1319
- if (connection && connection.state.status !== import_voice3.VoiceConnectionStatus.Destroyed) {
1320
- connection.destroy();
1150
+ if (queue.songs.length <= 1 && (queue._next || queue.repeatMode === 0 /* DISABLED */)) {
1151
+ if (queue.autoplay) {
1152
+ try {
1153
+ await queue.addRelatedSong();
1154
+ } catch {
1155
+ this.emit("noRelated", queue);
1156
+ }
1157
+ }
1158
+ if (queue.songs.length <= 1) {
1159
+ if (this.options.leaveOnFinish)
1160
+ queue.voice.leave();
1161
+ if (!queue.autoplay)
1162
+ this.emit("finish", queue);
1163
+ queue.remove();
1164
+ return;
1321
1165
  }
1322
1166
  }
1167
+ const emitPlaySong = __privateMethod(this, _emitPlaySong, emitPlaySong_fn).call(this, queue);
1168
+ if (!queue._prev && (queue.repeatMode !== 1 /* SONG */ || queue._next)) {
1169
+ const prev = queue.songs.shift();
1170
+ delete prev.formats;
1171
+ delete prev.streamURL;
1172
+ if (this.options.savePreviousSongs)
1173
+ queue.previousSongs.push(prev);
1174
+ else
1175
+ queue.previousSongs.push({ id: prev.id });
1176
+ }
1177
+ queue._next = queue._prev = false;
1178
+ queue.beginTime = 0;
1179
+ const err = await this.playSong(queue);
1180
+ if (!err && emitPlaySong)
1181
+ this.emit("playSong", queue, queue.songs[0]);
1182
+ } finally {
1183
+ queue._taskQueue.resolve();
1323
1184
  }
1324
- };
1185
+ }, "#handleSongFinish");
1186
+ _handlePlayingError = new WeakSet();
1187
+ handlePlayingError_fn = /* @__PURE__ */ __name(function(queue, error) {
1188
+ const song = queue.songs.shift();
1189
+ try {
1190
+ error.name = "PlayingError";
1191
+ error.message = `${error.message}
1192
+ Id: ${song.id}
1193
+ Name: ${song.name}`;
1194
+ } catch {
1195
+ }
1196
+ this.emitError(error, queue.textChannel);
1197
+ if (queue.songs.length > 0) {
1198
+ this.playSong(queue).then((e) => {
1199
+ if (!e)
1200
+ this.emit("playSong", queue, queue.songs[0]);
1201
+ });
1202
+ } else {
1203
+ queue.stop();
1204
+ }
1205
+ }, "#handlePlayingError");
1206
+ _emitPlaySong = new WeakSet();
1207
+ emitPlaySong_fn = /* @__PURE__ */ __name(function(queue) {
1208
+ return !this.options.emitNewSongOnly || queue.repeatMode === 1 /* SONG */ && queue._next || queue.repeatMode !== 1 /* SONG */ && queue.songs[0]?.id !== queue.songs[1]?.id;
1209
+ }, "#emitPlaySong");
1325
1210
 
1326
1211
  // src/core/DisTubeHandler.ts
1327
- var import_ytdl_core = __toESM(require("@distube/ytdl-core"));
1328
1212
  var import_ytpl = __toESM(require("@distube/ytpl"));
1213
+ var import_ytdl_core = __toESM(require("@distube/ytdl-core"));
1329
1214
  var DisTubeHandler = class extends DisTubeBase {
1330
1215
  constructor(distube) {
1331
1216
  super(distube);
@@ -1389,11 +1274,10 @@ var DisTubeHandler = class extends DisTubeBase {
1389
1274
  song.member = options.member;
1390
1275
  return song;
1391
1276
  }
1392
- if (song instanceof SearchResult) {
1393
- if (song.type === "video" /* VIDEO */)
1394
- return new Song(song, options);
1277
+ if (song instanceof SearchResultVideo)
1278
+ return new Song(song, options);
1279
+ if (song instanceof SearchResultPlaylist)
1395
1280
  return this.resolvePlaylist(song.url, options);
1396
- }
1397
1281
  if (isObject(song))
1398
1282
  return new Song(song, options);
1399
1283
  if (import_ytpl.default.validateID(song))
@@ -1418,14 +1302,19 @@ var DisTubeHandler = class extends DisTubeBase {
1418
1302
  playlist.member = member;
1419
1303
  return playlist;
1420
1304
  }
1421
- let solvablePlaylist;
1422
1305
  if (typeof playlist === "string") {
1423
- solvablePlaylist = await (0, import_ytpl.default)(playlist, { limit: Infinity });
1424
- solvablePlaylist.items = solvablePlaylist.items.filter((v) => !v.thumbnail.includes("no_thumbnail")).map((v) => new Song(v, { member, metadata }));
1425
- } else {
1426
- solvablePlaylist = playlist;
1427
- }
1428
- return new Playlist(solvablePlaylist, { member, properties: { source }, metadata });
1306
+ const info = await (0, import_ytpl.default)(playlist, { limit: Infinity });
1307
+ const songs = info.items.filter((v) => !v.thumbnail.includes("no_thumbnail")).map((v) => new Song(v, { member, metadata }));
1308
+ return new Playlist({
1309
+ source,
1310
+ songs,
1311
+ member,
1312
+ name: info.title,
1313
+ url: info.url,
1314
+ thumbnail: songs[0].thumbnail
1315
+ }, { metadata });
1316
+ }
1317
+ return new Playlist(playlist, { member, properties: { source }, metadata });
1429
1318
  }
1430
1319
  async searchSong(message, query) {
1431
1320
  if (!isMessageInstance(message))
@@ -1557,6 +1446,187 @@ var DisTubeHandler = class extends DisTubeBase {
1557
1446
  }
1558
1447
  }
1559
1448
  };
1449
+ __name(DisTubeHandler, "DisTubeHandler");
1450
+
1451
+ // src/core/DisTubeOptions.ts
1452
+ var _validateOptions, validateOptions_fn;
1453
+ var Options = class {
1454
+ constructor(options) {
1455
+ __privateAdd(this, _validateOptions);
1456
+ __publicField(this, "plugins");
1457
+ __publicField(this, "emitNewSongOnly");
1458
+ __publicField(this, "leaveOnFinish");
1459
+ __publicField(this, "leaveOnStop");
1460
+ __publicField(this, "leaveOnEmpty");
1461
+ __publicField(this, "emptyCooldown");
1462
+ __publicField(this, "savePreviousSongs");
1463
+ __publicField(this, "searchSongs");
1464
+ __publicField(this, "searchCooldown");
1465
+ __publicField(this, "youtubeCookie");
1466
+ __publicField(this, "youtubeIdentityToken");
1467
+ __publicField(this, "customFilters");
1468
+ __publicField(this, "ytdlOptions");
1469
+ __publicField(this, "nsfw");
1470
+ __publicField(this, "emitAddSongWhenCreatingQueue");
1471
+ __publicField(this, "emitAddListWhenCreatingQueue");
1472
+ __publicField(this, "joinNewVoiceChannel");
1473
+ __publicField(this, "streamType");
1474
+ if (typeof options !== "object" || Array.isArray(options)) {
1475
+ throw new DisTubeError("INVALID_TYPE", "object", options, "DisTubeOptions");
1476
+ }
1477
+ const opts = { ...defaultOptions, ...options };
1478
+ this.plugins = opts.plugins;
1479
+ this.emitNewSongOnly = opts.emitNewSongOnly;
1480
+ this.leaveOnEmpty = opts.leaveOnEmpty;
1481
+ this.leaveOnFinish = opts.leaveOnFinish;
1482
+ this.leaveOnStop = opts.leaveOnStop;
1483
+ this.savePreviousSongs = opts.savePreviousSongs;
1484
+ this.searchSongs = opts.searchSongs;
1485
+ this.youtubeCookie = opts.youtubeCookie;
1486
+ this.youtubeIdentityToken = opts.youtubeIdentityToken;
1487
+ this.customFilters = opts.customFilters;
1488
+ this.ytdlOptions = opts.ytdlOptions;
1489
+ this.searchCooldown = opts.searchCooldown;
1490
+ this.emptyCooldown = opts.emptyCooldown;
1491
+ this.nsfw = opts.nsfw;
1492
+ this.emitAddSongWhenCreatingQueue = opts.emitAddSongWhenCreatingQueue;
1493
+ this.emitAddListWhenCreatingQueue = opts.emitAddListWhenCreatingQueue;
1494
+ this.joinNewVoiceChannel = opts.joinNewVoiceChannel;
1495
+ this.streamType = opts.streamType;
1496
+ checkInvalidKey(opts, this, "DisTubeOptions");
1497
+ __privateMethod(this, _validateOptions, validateOptions_fn).call(this);
1498
+ }
1499
+ };
1500
+ __name(Options, "Options");
1501
+ _validateOptions = new WeakSet();
1502
+ validateOptions_fn = /* @__PURE__ */ __name(function(options = this) {
1503
+ if (typeof options.emitNewSongOnly !== "boolean") {
1504
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.emitNewSongOnly, "DisTubeOptions.emitNewSongOnly");
1505
+ }
1506
+ if (typeof options.leaveOnEmpty !== "boolean") {
1507
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnEmpty, "DisTubeOptions.leaveOnEmpty");
1508
+ }
1509
+ if (typeof options.leaveOnFinish !== "boolean") {
1510
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnFinish, "DisTubeOptions.leaveOnFinish");
1511
+ }
1512
+ if (typeof options.leaveOnStop !== "boolean") {
1513
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnStop, "DisTubeOptions.leaveOnStop");
1514
+ }
1515
+ if (typeof options.savePreviousSongs !== "boolean") {
1516
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.savePreviousSongs, "DisTubeOptions.savePreviousSongs");
1517
+ }
1518
+ if (typeof options.joinNewVoiceChannel !== "boolean") {
1519
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.joinNewVoiceChannel, "DisTubeOptions.joinNewVoiceChannel");
1520
+ }
1521
+ if (typeof options.youtubeCookie !== "undefined" && typeof options.youtubeCookie !== "string") {
1522
+ throw new DisTubeError("INVALID_TYPE", "string", options.youtubeCookie, "DisTubeOptions.youtubeCookie");
1523
+ }
1524
+ if (typeof options.youtubeIdentityToken !== "undefined" && typeof options.youtubeIdentityToken !== "string") {
1525
+ throw new DisTubeError("INVALID_TYPE", "string", options.youtubeIdentityToken, "DisTubeOptions.youtubeIdentityToken");
1526
+ }
1527
+ if (typeof options.customFilters !== "undefined" && typeof options.customFilters !== "object" || Array.isArray(options.customFilters)) {
1528
+ throw new DisTubeError("INVALID_TYPE", "object", options.customFilters, "DisTubeOptions.customFilters");
1529
+ }
1530
+ if (typeof options.ytdlOptions !== "object" || Array.isArray(options.ytdlOptions)) {
1531
+ throw new DisTubeError("INVALID_TYPE", "object", options.ytdlOptions, "DisTubeOptions.ytdlOptions");
1532
+ }
1533
+ if (typeof options.searchCooldown !== "number" || isNaN(options.searchCooldown)) {
1534
+ throw new DisTubeError("INVALID_TYPE", "number", options.searchCooldown, "DisTubeOptions.searchCooldown");
1535
+ }
1536
+ if (typeof options.emptyCooldown !== "number" || isNaN(options.emptyCooldown)) {
1537
+ throw new DisTubeError("INVALID_TYPE", "number", options.emptyCooldown, "DisTubeOptions.emptyCooldown");
1538
+ }
1539
+ if (typeof options.searchSongs !== "number" || isNaN(options.searchSongs)) {
1540
+ throw new DisTubeError("INVALID_TYPE", "number", options.searchSongs, "DisTubeOptions.searchSongs");
1541
+ }
1542
+ if (!Array.isArray(options.plugins)) {
1543
+ throw new DisTubeError("INVALID_TYPE", "Array<Plugin>", options.plugins, "DisTubeOptions.plugins");
1544
+ }
1545
+ if (typeof options.nsfw !== "boolean") {
1546
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.nsfw, "DisTubeOptions.nsfw");
1547
+ }
1548
+ if (typeof options.emitAddSongWhenCreatingQueue !== "boolean") {
1549
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddSongWhenCreatingQueue, "DisTubeOptions.emitAddSongWhenCreatingQueue");
1550
+ }
1551
+ if (typeof options.emitAddListWhenCreatingQueue !== "boolean") {
1552
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddListWhenCreatingQueue, "DisTubeOptions.emitAddListWhenCreatingQueue");
1553
+ }
1554
+ if (typeof options.streamType !== "number" || isNaN(options.streamType) || !StreamType[options.streamType]) {
1555
+ throw new DisTubeError("INVALID_TYPE", "StreamType", options.streamType, "DisTubeOptions.streamType");
1556
+ }
1557
+ }, "#validateOptions");
1558
+
1559
+ // src/core/DisTubeStream.ts
1560
+ var import_prism_media = require("prism-media");
1561
+ var import_voice3 = require("@discordjs/voice");
1562
+ var chooseBestVideoFormat = /* @__PURE__ */ __name((formats, isLive = false) => {
1563
+ let filter = /* @__PURE__ */ __name((format) => format.hasAudio, "filter");
1564
+ if (isLive)
1565
+ filter = /* @__PURE__ */ __name((format) => format.hasAudio && format.isHLS, "filter");
1566
+ formats = formats.filter(filter).sort((a, b) => Number(b.audioBitrate) - Number(a.audioBitrate) || Number(a.bitrate) - Number(b.bitrate));
1567
+ return formats.find((format) => !format.hasVideo) || formats.sort((a, b) => Number(a.bitrate) - Number(b.bitrate))[0];
1568
+ }, "chooseBestVideoFormat");
1569
+ var DisTubeStream = class {
1570
+ constructor(url, options) {
1571
+ __publicField(this, "type");
1572
+ __publicField(this, "stream");
1573
+ __publicField(this, "url");
1574
+ this.url = url;
1575
+ this.type = !options.type ? import_voice3.StreamType.OggOpus : import_voice3.StreamType.Raw;
1576
+ const args = [
1577
+ "-reconnect",
1578
+ "1",
1579
+ "-reconnect_streamed",
1580
+ "1",
1581
+ "-reconnect_delay_max",
1582
+ "5",
1583
+ "-i",
1584
+ url,
1585
+ "-analyzeduration",
1586
+ "0",
1587
+ "-loglevel",
1588
+ "0",
1589
+ "-ar",
1590
+ "48000",
1591
+ "-ac",
1592
+ "2",
1593
+ "-f"
1594
+ ];
1595
+ if (!options.type) {
1596
+ args.push("opus", "-acodec", "libopus");
1597
+ } else {
1598
+ args.push("s16le");
1599
+ }
1600
+ if (typeof options.seek === "number" && options.seek > 0) {
1601
+ args.unshift("-ss", options.seek.toString());
1602
+ }
1603
+ if (Array.isArray(options.ffmpegArgs)) {
1604
+ args.push(...options.ffmpegArgs);
1605
+ }
1606
+ this.stream = new import_prism_media.FFmpeg({ args, shell: false });
1607
+ }
1608
+ static YouTube(formats, options = {}) {
1609
+ if (!formats || !formats.length)
1610
+ throw new DisTubeError("UNAVAILABLE_VIDEO");
1611
+ if (!options || typeof options !== "object" || Array.isArray(options)) {
1612
+ throw new DisTubeError("INVALID_TYPE", "object", options, "options");
1613
+ }
1614
+ const bestFormat = chooseBestVideoFormat(formats, options.isLive);
1615
+ if (!bestFormat)
1616
+ throw new DisTubeError("UNPLAYABLE_FORMATS");
1617
+ return new DisTubeStream(bestFormat.url, options);
1618
+ }
1619
+ static DirectLink(url, options = {}) {
1620
+ if (!options || typeof options !== "object" || Array.isArray(options)) {
1621
+ throw new DisTubeError("INVALID_TYPE", "object", options, "options");
1622
+ }
1623
+ if (typeof url !== "string" || !isURL(url)) {
1624
+ throw new DisTubeError("INVALID_TYPE", "an URL", url);
1625
+ }
1626
+ return new DisTubeStream(url, options);
1627
+ }
1628
+ };
1629
+ __name(DisTubeStream, "DisTubeStream");
1560
1630
 
1561
1631
  // src/struct/Queue.ts
1562
1632
  var _filters;
@@ -1578,12 +1648,8 @@ var Queue = class extends DisTubeBase {
1578
1648
  __publicField(this, "beginTime");
1579
1649
  __publicField(this, "textChannel");
1580
1650
  __publicField(this, "_emptyTimeout");
1581
- __publicField(this, "clientMember");
1582
1651
  __publicField(this, "_taskQueue");
1583
1652
  __publicField(this, "_listeners");
1584
- this.clientMember = voice.channel.guild?.me ?? (() => {
1585
- throw new DisTubeError("INVALID_TYPE", "GuildMember", null, "<VoiceChannel>.guild.me");
1586
- })();
1587
1653
  this.voice = voice;
1588
1654
  this.id = voice.id;
1589
1655
  this.volume = 50;
@@ -1603,6 +1669,9 @@ var Queue = class extends DisTubeBase {
1603
1669
  this._taskQueue = new TaskQueue();
1604
1670
  this._listeners = void 0;
1605
1671
  }
1672
+ get clientMember() {
1673
+ return this.voice.channel.guild.members.me ?? void 0;
1674
+ }
1606
1675
  get filters() {
1607
1676
  return __privateGet(this, _filters);
1608
1677
  }
@@ -1619,7 +1688,7 @@ var Queue = class extends DisTubeBase {
1619
1688
  return formatDuration(this.currentTime);
1620
1689
  }
1621
1690
  get voiceChannel() {
1622
- return this.clientMember.voice.channel;
1691
+ return this.clientMember?.voice?.channel ?? null;
1623
1692
  }
1624
1693
  get volume() {
1625
1694
  return this.voice.volume;
@@ -1817,6 +1886,7 @@ var Queue = class extends DisTubeBase {
1817
1886
  return this.autoplay;
1818
1887
  }
1819
1888
  };
1889
+ __name(Queue, "Queue");
1820
1890
  _filters = new WeakMap();
1821
1891
 
1822
1892
  // src/struct/Plugin.ts
@@ -1858,6 +1928,7 @@ var Plugin = class {
1858
1928
  return [];
1859
1929
  }
1860
1930
  };
1931
+ __name(Plugin, "Plugin");
1861
1932
 
1862
1933
  // src/struct/CustomPlugin.ts
1863
1934
  var CustomPlugin = class extends Plugin {
@@ -1866,6 +1937,7 @@ var CustomPlugin = class extends Plugin {
1866
1937
  __publicField(this, "type", "custom" /* CUSTOM */);
1867
1938
  }
1868
1939
  };
1940
+ __name(CustomPlugin, "CustomPlugin");
1869
1941
 
1870
1942
  // src/struct/ExtractorPlugin.ts
1871
1943
  var ExtractorPlugin = class extends Plugin {
@@ -1874,6 +1946,7 @@ var ExtractorPlugin = class extends Plugin {
1874
1946
  __publicField(this, "type", "extractor" /* EXTRACTOR */);
1875
1947
  }
1876
1948
  };
1949
+ __name(ExtractorPlugin, "ExtractorPlugin");
1877
1950
 
1878
1951
  // src/util.ts
1879
1952
  var import_url = require("url");
@@ -1891,6 +1964,7 @@ function formatDuration(sec) {
1891
1964
  return `${formatInt(minutes)}:${formatInt(seconds)}`;
1892
1965
  return `00:${formatInt(seconds)}`;
1893
1966
  }
1967
+ __name(formatDuration, "formatDuration");
1894
1968
  function toSecond(input) {
1895
1969
  if (!input)
1896
1970
  return 0;
@@ -1909,11 +1983,13 @@ function toSecond(input) {
1909
1983
  return Number(input.replace(/[^\d.]+/g, "")) || 0;
1910
1984
  }
1911
1985
  }
1986
+ __name(toSecond, "toSecond");
1912
1987
  function parseNumber(input) {
1913
1988
  if (typeof input === "string")
1914
1989
  return Number(input.replace(/[^\d.]+/g, "")) || 0;
1915
1990
  return Number(input) || 0;
1916
1991
  }
1992
+ __name(parseNumber, "parseNumber");
1917
1993
  function isURL(input) {
1918
1994
  if (typeof input !== "string" || input.includes(" "))
1919
1995
  return false;
@@ -1926,18 +2002,25 @@ function isURL(input) {
1926
2002
  }
1927
2003
  return true;
1928
2004
  }
2005
+ __name(isURL, "isURL");
1929
2006
  function checkIntents(options) {
1930
2007
  const intents = new import_discord2.IntentsBitField(options.intents);
1931
2008
  if (!intents.has(import_discord2.GatewayIntentBits.GuildVoiceStates))
1932
2009
  throw new DisTubeError("MISSING_INTENTS", "GuildVoiceStates");
1933
2010
  }
2011
+ __name(checkIntents, "checkIntents");
1934
2012
  function isVoiceChannelEmpty(voiceState) {
1935
- const voiceChannel = voiceState.guild?.me?.voice?.channel;
2013
+ const guild = voiceState.guild;
2014
+ const clientId = voiceState.client.user?.id;
2015
+ if (!guild || !clientId)
2016
+ return false;
2017
+ const voiceChannel = guild.members.me?.voice?.channel;
1936
2018
  if (!voiceChannel)
1937
2019
  return false;
1938
2020
  const members = voiceChannel.members.filter((m) => !m.user.bot);
1939
2021
  return !members.size;
1940
2022
  }
2023
+ __name(isVoiceChannelEmpty, "isVoiceChannelEmpty");
1941
2024
  function isSnowflake(id) {
1942
2025
  try {
1943
2026
  return import_discord2.SnowflakeUtil.deconstruct(id).timestamp > import_discord2.SnowflakeUtil.epoch;
@@ -1945,21 +2028,27 @@ function isSnowflake(id) {
1945
2028
  return false;
1946
2029
  }
1947
2030
  }
2031
+ __name(isSnowflake, "isSnowflake");
1948
2032
  function isMemberInstance(member) {
1949
2033
  return !!member && isSnowflake(member.id) && isSnowflake(member.guild?.id) && isSnowflake(member.user?.id) && member.id === member.user.id;
1950
2034
  }
2035
+ __name(isMemberInstance, "isMemberInstance");
1951
2036
  function isTextChannelInstance(channel) {
1952
- return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) && typeof channel.name === "string" && import_discord2.Constants.TextBasedChannelTypes.includes(channel.type);
2037
+ return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) && typeof channel.name === "string" && import_discord2.Constants.TextBasedChannelTypes.includes(channel.type) && typeof channel.nsfw === "boolean" && typeof channel.messages?.cache === "object" && typeof channel.send === "function";
1953
2038
  }
2039
+ __name(isTextChannelInstance, "isTextChannelInstance");
1954
2040
  function isMessageInstance(message) {
1955
2041
  return !!message && isSnowflake(message.id) && isSnowflake(message.guildId) && isMemberInstance(message.member) && isTextChannelInstance(message.channel) && import_discord2.Constants.NonSystemMessageTypes.includes(message.type) && message.member.id === message.author?.id;
1956
2042
  }
2043
+ __name(isMessageInstance, "isMessageInstance");
1957
2044
  function isSupportedVoiceChannel(channel) {
1958
2045
  return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) && import_discord2.Constants.VoiceBasedChannelTypes.includes(channel.type);
1959
2046
  }
2047
+ __name(isSupportedVoiceChannel, "isSupportedVoiceChannel");
1960
2048
  function isGuildInstance(guild) {
1961
2049
  return !!guild && isSnowflake(guild.id) && isSnowflake(guild.ownerId) && typeof guild.name === "string";
1962
2050
  }
2051
+ __name(isGuildInstance, "isGuildInstance");
1963
2052
  function resolveGuildId(resolvable) {
1964
2053
  let guildId;
1965
2054
  if (typeof resolvable === "string") {
@@ -1977,9 +2066,11 @@ function resolveGuildId(resolvable) {
1977
2066
  throw new DisTubeError("INVALID_TYPE", "GuildIdResolvable", resolvable);
1978
2067
  return guildId;
1979
2068
  }
2069
+ __name(resolveGuildId, "resolveGuildId");
1980
2070
  function isClientInstance(client) {
1981
2071
  return !!client && typeof client.login === "function";
1982
2072
  }
2073
+ __name(isClientInstance, "isClientInstance");
1983
2074
  function checkInvalidKey(target, source, sourceName) {
1984
2075
  if (!isObject(target))
1985
2076
  throw new DisTubeError("INVALID_TYPE", "object", target, sourceName);
@@ -1988,38 +2079,15 @@ function checkInvalidKey(target, source, sourceName) {
1988
2079
  if (invalidKey)
1989
2080
  throw new DisTubeError("INVALID_KEY", sourceName, invalidKey);
1990
2081
  }
1991
- async function waitEvent(target, status, maxTime) {
1992
- let cleanup = /* @__PURE__ */ __name(() => {
1993
- }, "cleanup");
1994
- try {
1995
- await new Promise((resolve, reject) => {
1996
- const timeout = setTimeout(() => reject(new Error(`Didn't trigger ${status} within ${maxTime}ms`)), maxTime);
1997
- target.once(status, resolve);
1998
- target.once("error", reject);
1999
- cleanup = /* @__PURE__ */ __name(() => {
2000
- clearTimeout(timeout);
2001
- target.off(status, resolve);
2002
- target.off("error", reject);
2003
- }, "cleanup");
2004
- if (target?.state?.status === status)
2005
- resolve(0);
2006
- });
2007
- return target;
2008
- } finally {
2009
- cleanup();
2010
- }
2011
- }
2012
- async function entersState(target, status, maxTime) {
2013
- if (target.state.status === status)
2014
- return target;
2015
- return waitEvent(target, status, maxTime);
2016
- }
2082
+ __name(checkInvalidKey, "checkInvalidKey");
2017
2083
  function isObject(obj) {
2018
2084
  return typeof obj === "object" && obj !== null && !Array.isArray(obj);
2019
2085
  }
2086
+ __name(isObject, "isObject");
2020
2087
  function isRecord(obj) {
2021
2088
  return isObject(obj);
2022
2089
  }
2090
+ __name(isRecord, "isRecord");
2023
2091
 
2024
2092
  // src/plugin/http.ts
2025
2093
  var import_http = __toESM(require("http"));
@@ -2031,6 +2099,7 @@ var HTTPPlugin = class extends ExtractorPlugin {
2031
2099
  return resolveHttpSong(url, { ...options, source: "http" });
2032
2100
  }
2033
2101
  };
2102
+ __name(HTTPPlugin, "HTTPPlugin");
2034
2103
 
2035
2104
  // src/plugin/https.ts
2036
2105
  var import_https = __toESM(require("https"));
@@ -2065,6 +2134,7 @@ var HTTPSPlugin = class extends ExtractorPlugin {
2065
2134
  return resolveHttpSong(url, { ...options, source: "https" });
2066
2135
  }
2067
2136
  };
2137
+ __name(HTTPSPlugin, "HTTPSPlugin");
2068
2138
 
2069
2139
  // src/DisTube.ts
2070
2140
  var import_ytsr = __toESM(require("@distube/ytsr"));
@@ -2109,7 +2179,7 @@ var DisTube = class extends import_tiny_typed_emitter2.TypedEmitter {
2109
2179
  if (!isObject(options))
2110
2180
  throw new DisTubeError("INVALID_TYPE", "object", options, "options");
2111
2181
  const { textChannel, member, skip, message, metadata } = {
2112
- member: voiceChannel.guild.me ?? void 0,
2182
+ member: voiceChannel.guild.members.me ?? void 0,
2113
2183
  textChannel: options?.message?.channel,
2114
2184
  skip: false,
2115
2185
  ...options
@@ -2157,12 +2227,12 @@ var DisTube = class extends import_tiny_typed_emitter2.TypedEmitter {
2157
2227
  if (!(e instanceof DisTubeError)) {
2158
2228
  try {
2159
2229
  e.name = "PlayError";
2160
- e.message = `${song?.url || song}
2230
+ e.message = `${typeof song === "string" ? song : song.url}
2161
2231
  ${e.message}`;
2162
2232
  } catch {
2163
2233
  }
2164
2234
  }
2165
- this.emitError(e, textChannel);
2235
+ throw e;
2166
2236
  } finally {
2167
2237
  if (queuing)
2168
2238
  queue?._taskQueue.resolve();
@@ -2174,7 +2244,7 @@ ${e.message}`;
2174
2244
  throw new DisTubeError("INVALID_TYPE", "Array", songs, "songs");
2175
2245
  if (!songs.length)
2176
2246
  throw new DisTubeError("EMPTY_ARRAY", "songs");
2177
- const filteredSongs = songs.filter((song) => song instanceof Song || song instanceof SearchResult && song.type === "video" || isURL(song));
2247
+ const filteredSongs = songs.filter((song) => song instanceof Song || isURL(song) || typeof song !== "string" && song.type === "video" /* VIDEO */);
2178
2248
  if (!filteredSongs.length)
2179
2249
  throw new DisTubeError("NO_VALID_SONG");
2180
2250
  if (member && !isMemberInstance(member)) {
@@ -2196,7 +2266,7 @@ ${e.message}`;
2196
2266
  return new Playlist(resolvedSongs, { member, properties, metadata });
2197
2267
  }
2198
2268
  async search(string, options = {}) {
2199
- const opts = { type: "video", limit: 10, safeSearch: false, ...options };
2269
+ const opts = { type: "video" /* VIDEO */, limit: 10, safeSearch: false, ...options };
2200
2270
  if (typeof opts.type !== "string" || !["video", "playlist"].includes(opts.type)) {
2201
2271
  throw new DisTubeError("INVALID_TYPE", ["video", "playlist"], opts.type, "options.type");
2202
2272
  }
@@ -2209,7 +2279,11 @@ ${e.message}`;
2209
2279
  }
2210
2280
  try {
2211
2281
  const search = await (0, import_ytsr.default)(string, opts);
2212
- const results = search.items.map((i) => new SearchResult(i));
2282
+ const results = search.items.map((i) => {
2283
+ if (i.type === "video")
2284
+ return new SearchResultVideo(i);
2285
+ return new SearchResultPlaylist(i);
2286
+ });
2213
2287
  if (results.length === 0)
2214
2288
  throw new DisTubeError("NO_RESULT");
2215
2289
  return results;
@@ -2306,6 +2380,7 @@ ${e.message}`;
2306
2380
  }
2307
2381
  }
2308
2382
  };
2383
+ __name(DisTube, "DisTube");
2309
2384
  // Annotate the CommonJS export names for ESM import in node:
2310
2385
  0 && (module.exports = {
2311
2386
  BaseManager,
@@ -2329,16 +2404,17 @@ ${e.message}`;
2329
2404
  Queue,
2330
2405
  QueueManager,
2331
2406
  RepeatMode,
2332
- SearchResult,
2407
+ SearchResultPlaylist,
2333
2408
  SearchResultType,
2409
+ SearchResultVideo,
2334
2410
  Song,
2411
+ StreamType,
2335
2412
  TaskQueue,
2336
2413
  checkIntents,
2337
2414
  checkInvalidKey,
2338
2415
  chooseBestVideoFormat,
2339
2416
  defaultFilters,
2340
2417
  defaultOptions,
2341
- entersState,
2342
2418
  formatDuration,
2343
2419
  getResponseHeaders,
2344
2420
  isClientInstance,