distube 4.0.0-dev.5 → 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.5",
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",
@@ -122,41 +123,41 @@ var require_package = __commonJS({
122
123
  dependencies: {
123
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
129
  tslib: "^2.4.0"
129
130
  },
130
131
  devDependencies: {
131
- "@babel/core": "^7.18.0",
132
- "@babel/plugin-proposal-class-properties": "^7.17.12",
133
- "@babel/plugin-proposal-object-rest-spread": "^7.18.0",
134
- "@babel/preset-env": "^7.18.0",
135
- "@babel/preset-typescript": "^7.17.12",
136
- "@commitlint/cli": "^17.0.0",
137
- "@commitlint/config-conventional": "^17.0.0",
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.5.1",
141
- "@types/node": "^17.0.35",
142
- "@typescript-eslint/eslint-plugin": "^5.25.0",
143
- "@typescript-eslint/parser": "^5.25.0",
144
- "babel-jest": "^28.1.0",
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.15.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": "^39.3.0",
151
+ "eslint-plugin-jsdoc": "^39.3.3",
151
152
  husky: "^8.0.1",
152
- jest: "^28.1.0",
153
+ jest: "^28.1.3",
153
154
  "jsdoc-babel": "^0.5.0",
154
155
  "nano-staged": "^0.8.0",
155
- "npm-check-updates": "^13.0.1",
156
+ "npm-check-updates": "^15.3.0",
156
157
  pinst: "^3.0.0",
157
- prettier: "^2.6.2",
158
- tsup: "^5.12.8",
159
- typescript: "^4.6.4"
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,8 +211,9 @@ __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,
216
218
  StreamType: () => StreamType,
217
219
  TaskQueue: () => TaskQueue,
@@ -221,9 +223,7 @@ __export(src_exports, {
221
223
  default: () => DisTube,
222
224
  defaultFilters: () => defaultFilters,
223
225
  defaultOptions: () => defaultOptions,
224
- entersState: () => entersState,
225
226
  formatDuration: () => formatDuration,
226
- getClientMember: () => getClientMember,
227
227
  getResponseHeaders: () => getResponseHeaders,
228
228
  isClientInstance: () => isClientInstance,
229
229
  isGuildInstance: () => isGuildInstance,
@@ -307,7 +307,7 @@ var defaultOptions = {
307
307
  // src/struct/DisTubeError.ts
308
308
  var import_node_util = require("util");
309
309
  var ERROR_MESSAGES = {
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)}`,
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})`,
311
311
  NUMBER_COMPARE: (name, expected, value) => `'${name}' must be ${expected} ${value}`,
312
312
  EMPTY_ARRAY: (name) => `'${name}' is an empty array`,
313
313
  EMPTY_FILTERED_ARRAY: (name, type) => `There is no valid '${type}' in the '${name}' array`,
@@ -413,26 +413,33 @@ var Playlist = class {
413
413
  __publicField(this, "url");
414
414
  __publicField(this, "thumbnail");
415
415
  const { member, properties, metadata } = options;
416
- if (typeof playlist !== "object") {
417
- 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");
418
418
  }
419
419
  if (typeof properties !== "undefined" && !isRecord(properties)) {
420
420
  throw new DisTubeError("INVALID_TYPE", "object", properties, "properties");
421
421
  }
422
- const info = playlist;
423
- this.source = (info.source || properties?.source || "youtube").toLowerCase();
424
- this.songs = Array.isArray(info) ? info : info.items || info.songs;
425
- if (!Array.isArray(this.songs) || !this.songs.length) {
426
- 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;
427
437
  }
428
438
  this.songs.map((s) => s.constructor.name === "Song" && (s.playlist = this));
429
- this.member = member || info.member || void 0;
430
- 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`);
431
- this.url = info.url || info.webpage_url;
432
- this.thumbnail = info.thumbnail?.url || info.thumbnail || this.songs[0].thumbnail;
433
439
  if (properties)
434
440
  for (const [key, value] of Object.entries(properties))
435
441
  this[key] = value;
442
+ this.member = member;
436
443
  this.metadata = metadata;
437
444
  }
438
445
  get duration() {
@@ -466,41 +473,64 @@ _metadata = new WeakMap();
466
473
  _member = new WeakMap();
467
474
 
468
475
  // src/struct/SearchResult.ts
469
- var SearchResult = class {
476
+ var ISearchResult = class {
470
477
  constructor(info) {
471
478
  __publicField(this, "source");
472
- __publicField(this, "type");
473
479
  __publicField(this, "id");
474
480
  __publicField(this, "name");
475
481
  __publicField(this, "url");
476
- __publicField(this, "views");
477
- __publicField(this, "isLive");
478
- __publicField(this, "duration");
479
- __publicField(this, "formattedDuration");
480
- __publicField(this, "thumbnail");
481
482
  __publicField(this, "uploader");
482
483
  this.source = "youtube";
483
- this.type = info.type === "video" ? "video" /* VIDEO */ : "playlist" /* PLAYLIST */;
484
484
  this.id = info.id;
485
485
  this.name = info.name;
486
486
  this.url = info.url;
487
- if (this.type === "video" /* VIDEO */) {
488
- info = info;
489
- this.views = info.views;
490
- this.isLive = info.isLive;
491
- this.duration = this.isLive ? 0 : toSecond(info.duration);
492
- this.formattedDuration = this.isLive ? "Live" : formatDuration(this.duration);
493
- this.thumbnail = info.thumbnail;
494
- } else if (this.type !== "playlist") {
495
- throw new DisTubeError("INVALID_TYPE", ["video", "playlist"], this.type, "SearchResult.type");
496
- }
497
487
  this.uploader = {
498
- name: (info.author || info.owner)?.name,
499
- 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
500
514
  };
501
515
  }
502
516
  };
503
- __name(SearchResult, "SearchResult");
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");
504
534
 
505
535
  // src/struct/Song.ts
506
536
  var _metadata2, _member2, _playlist;
@@ -640,114 +670,6 @@ _metadata2 = new WeakMap();
640
670
  _member2 = new WeakMap();
641
671
  _playlist = new WeakMap();
642
672
 
643
- // src/core/DisTubeOptions.ts
644
- var _validateOptions, validateOptions_fn;
645
- var Options = class {
646
- constructor(options) {
647
- __privateAdd(this, _validateOptions);
648
- __publicField(this, "plugins");
649
- __publicField(this, "emitNewSongOnly");
650
- __publicField(this, "leaveOnFinish");
651
- __publicField(this, "leaveOnStop");
652
- __publicField(this, "leaveOnEmpty");
653
- __publicField(this, "emptyCooldown");
654
- __publicField(this, "savePreviousSongs");
655
- __publicField(this, "searchSongs");
656
- __publicField(this, "searchCooldown");
657
- __publicField(this, "youtubeCookie");
658
- __publicField(this, "youtubeIdentityToken");
659
- __publicField(this, "customFilters");
660
- __publicField(this, "ytdlOptions");
661
- __publicField(this, "nsfw");
662
- __publicField(this, "emitAddSongWhenCreatingQueue");
663
- __publicField(this, "emitAddListWhenCreatingQueue");
664
- __publicField(this, "joinNewVoiceChannel");
665
- __publicField(this, "streamType");
666
- if (typeof options !== "object" || Array.isArray(options)) {
667
- throw new DisTubeError("INVALID_TYPE", "object", options, "DisTubeOptions");
668
- }
669
- const opts = { ...defaultOptions, ...options };
670
- this.plugins = opts.plugins;
671
- this.emitNewSongOnly = opts.emitNewSongOnly;
672
- this.leaveOnEmpty = opts.leaveOnEmpty;
673
- this.leaveOnFinish = opts.leaveOnFinish;
674
- this.leaveOnStop = opts.leaveOnStop;
675
- this.savePreviousSongs = opts.savePreviousSongs;
676
- this.searchSongs = opts.searchSongs;
677
- this.youtubeCookie = opts.youtubeCookie;
678
- this.youtubeIdentityToken = opts.youtubeIdentityToken;
679
- this.customFilters = opts.customFilters;
680
- this.ytdlOptions = opts.ytdlOptions;
681
- this.searchCooldown = opts.searchCooldown;
682
- this.emptyCooldown = opts.emptyCooldown;
683
- this.nsfw = opts.nsfw;
684
- this.emitAddSongWhenCreatingQueue = opts.emitAddSongWhenCreatingQueue;
685
- this.emitAddListWhenCreatingQueue = opts.emitAddListWhenCreatingQueue;
686
- this.joinNewVoiceChannel = opts.joinNewVoiceChannel;
687
- this.streamType = opts.streamType;
688
- checkInvalidKey(opts, this, "DisTubeOptions");
689
- __privateMethod(this, _validateOptions, validateOptions_fn).call(this);
690
- }
691
- };
692
- __name(Options, "Options");
693
- _validateOptions = new WeakSet();
694
- validateOptions_fn = /* @__PURE__ */ __name(function(options = this) {
695
- if (typeof options.emitNewSongOnly !== "boolean") {
696
- throw new DisTubeError("INVALID_TYPE", "boolean", options.emitNewSongOnly, "DisTubeOptions.emitNewSongOnly");
697
- }
698
- if (typeof options.leaveOnEmpty !== "boolean") {
699
- throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnEmpty, "DisTubeOptions.leaveOnEmpty");
700
- }
701
- if (typeof options.leaveOnFinish !== "boolean") {
702
- throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnFinish, "DisTubeOptions.leaveOnFinish");
703
- }
704
- if (typeof options.leaveOnStop !== "boolean") {
705
- throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnStop, "DisTubeOptions.leaveOnStop");
706
- }
707
- if (typeof options.savePreviousSongs !== "boolean") {
708
- throw new DisTubeError("INVALID_TYPE", "boolean", options.savePreviousSongs, "DisTubeOptions.savePreviousSongs");
709
- }
710
- if (typeof options.joinNewVoiceChannel !== "boolean") {
711
- throw new DisTubeError("INVALID_TYPE", "boolean", options.joinNewVoiceChannel, "DisTubeOptions.joinNewVoiceChannel");
712
- }
713
- if (typeof options.youtubeCookie !== "undefined" && typeof options.youtubeCookie !== "string") {
714
- throw new DisTubeError("INVALID_TYPE", "string", options.youtubeCookie, "DisTubeOptions.youtubeCookie");
715
- }
716
- if (typeof options.youtubeIdentityToken !== "undefined" && typeof options.youtubeIdentityToken !== "string") {
717
- throw new DisTubeError("INVALID_TYPE", "string", options.youtubeIdentityToken, "DisTubeOptions.youtubeIdentityToken");
718
- }
719
- if (typeof options.customFilters !== "undefined" && typeof options.customFilters !== "object" || Array.isArray(options.customFilters)) {
720
- throw new DisTubeError("INVALID_TYPE", "object", options.customFilters, "DisTubeOptions.customFilters");
721
- }
722
- if (typeof options.ytdlOptions !== "object" || Array.isArray(options.ytdlOptions)) {
723
- throw new DisTubeError("INVALID_TYPE", "object", options.ytdlOptions, "DisTubeOptions.ytdlOptions");
724
- }
725
- if (typeof options.searchCooldown !== "number" || isNaN(options.searchCooldown)) {
726
- throw new DisTubeError("INVALID_TYPE", "number", options.searchCooldown, "DisTubeOptions.searchCooldown");
727
- }
728
- if (typeof options.emptyCooldown !== "number" || isNaN(options.emptyCooldown)) {
729
- throw new DisTubeError("INVALID_TYPE", "number", options.emptyCooldown, "DisTubeOptions.emptyCooldown");
730
- }
731
- if (typeof options.searchSongs !== "number" || isNaN(options.searchSongs)) {
732
- throw new DisTubeError("INVALID_TYPE", "number", options.searchSongs, "DisTubeOptions.searchSongs");
733
- }
734
- if (!Array.isArray(options.plugins)) {
735
- throw new DisTubeError("INVALID_TYPE", "Array<Plugin>", options.plugins, "DisTubeOptions.plugins");
736
- }
737
- if (typeof options.nsfw !== "boolean") {
738
- throw new DisTubeError("INVALID_TYPE", "boolean", options.nsfw, "DisTubeOptions.nsfw");
739
- }
740
- if (typeof options.emitAddSongWhenCreatingQueue !== "boolean") {
741
- throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddSongWhenCreatingQueue, "DisTubeOptions.emitAddSongWhenCreatingQueue");
742
- }
743
- if (typeof options.emitAddListWhenCreatingQueue !== "boolean") {
744
- throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddListWhenCreatingQueue, "DisTubeOptions.emitAddListWhenCreatingQueue");
745
- }
746
- if (typeof options.streamType !== "number" || isNaN(options.streamType) || !StreamType[options.streamType]) {
747
- throw new DisTubeError("INVALID_TYPE", "StreamType", options.streamType, "DisTubeOptions.streamType");
748
- }
749
- }, "#validateOptions");
750
-
751
673
  // src/core/DisTubeBase.ts
752
674
  var DisTubeBase = class {
753
675
  constructor(distube) {
@@ -778,77 +700,194 @@ var DisTubeBase = class {
778
700
  };
779
701
  __name(DisTubeBase, "DisTubeBase");
780
702
 
781
- // src/core/DisTubeStream.ts
782
- var import_prism_media = require("prism-media");
703
+ // src/core/DisTubeVoice.ts
704
+ var import_tiny_typed_emitter = require("tiny-typed-emitter");
783
705
  var import_voice = require("@discordjs/voice");
784
- var chooseBestVideoFormat = /* @__PURE__ */ __name((formats, isLive = false) => {
785
- let filter = /* @__PURE__ */ __name((format) => format.hasAudio, "filter");
786
- if (isLive)
787
- filter = /* @__PURE__ */ __name((format) => format.hasAudio && format.isHLS, "filter");
788
- formats = formats.filter(filter).sort((a, b) => Number(b.audioBitrate) - Number(a.audioBitrate) || Number(a.bitrate) - Number(b.bitrate));
789
- return formats.find((format) => !format.hasVideo) || formats.sort((a, b) => Number(a.bitrate) - Number(b.bitrate))[0];
790
- }, "chooseBestVideoFormat");
791
- var DisTubeStream = class {
792
- constructor(url, options) {
793
- __publicField(this, "type");
794
- __publicField(this, "stream");
795
- __publicField(this, "url");
796
- this.url = url;
797
- this.type = !options.type ? import_voice.StreamType.Opus : import_voice.StreamType.Raw;
798
- const args = [
799
- "-reconnect",
800
- "1",
801
- "-reconnect_streamed",
802
- "1",
803
- "-reconnect_delay_max",
804
- "5",
805
- "-i",
806
- url,
807
- "-analyzeduration",
808
- "0",
809
- "-loglevel",
810
- "0",
811
- "-ar",
812
- "48000",
813
- "-ac",
814
- "2",
815
- "-f"
816
- ];
817
- if (!options.type) {
818
- args.push("opus", "-acodec", "libopus");
819
- } else {
820
- args.push("s16le");
821
- }
822
- if (typeof options.seek === "number" && options.seek > 0) {
823
- args.unshift("-ss", options.seek.toString());
824
- }
825
- if (Array.isArray(options.ffmpegArgs)) {
826
- args.push(...options.ffmpegArgs);
827
- }
828
- 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);
829
756
  }
830
- static YouTube(formats, options = {}) {
831
- if (!formats || !formats.length)
832
- throw new DisTubeError("UNAVAILABLE_VIDEO");
833
- if (!options || typeof options !== "object" || Array.isArray(options)) {
834
- throw new DisTubeError("INVALID_TYPE", "object", options, "options");
835
- }
836
- const bestFormat = chooseBestVideoFormat(formats, options.isLive);
837
- if (!bestFormat)
838
- throw new DisTubeError("UNPLAYABLE_FORMATS");
839
- return new DisTubeStream(bestFormat.url, options);
757
+ get channel() {
758
+ return __privateGet(this, _channel);
840
759
  }
841
- static DirectLink(url, options = {}) {
842
- if (!options || typeof options !== "object" || Array.isArray(options)) {
843
- 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");
844
763
  }
845
- if (typeof url !== "string" || !isURL(url)) {
846
- 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");
847
775
  }
848
- return new DisTubeStream(url, options);
776
+ this.connection = __privateMethod(this, _join, join_fn).call(this, channel);
777
+ __privateSet(this, _channel, channel);
778
+ __privateMethod(this, _br, br_fn).call(this);
779
+ }
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;
849
872
  }
850
873
  };
851
- __name(DisTubeStream, "DisTubeStream");
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");
852
891
 
853
892
  // src/core/manager/BaseManager.ts
854
893
  var import_discord = require("discord.js");
@@ -884,6 +923,123 @@ var GuildIdManager = class extends BaseManager {
884
923
  };
885
924
  __name(GuildIdManager, "GuildIdManager");
886
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");
1042
+
887
1043
  // src/core/manager/QueueManager.ts
888
1044
  var _voiceEventHandler, voiceEventHandler_fn, _handleSongFinish, handleSongFinish_fn, _handlePlayingError, handlePlayingError_fn, _emitPlaySong, emitPlaySong_fn;
889
1045
  var QueueManager = class extends GuildIdManager {
@@ -1000,367 +1156,61 @@ handleSongFinish_fn = /* @__PURE__ */ __name(async function(queue) {
1000
1156
  }
1001
1157
  }
1002
1158
  if (queue.songs.length <= 1) {
1003
- if (this.options.leaveOnFinish)
1004
- queue.voice.leave();
1005
- if (!queue.autoplay)
1006
- this.emit("finish", queue);
1007
- queue.remove();
1008
- return;
1009
- }
1010
- }
1011
- const emitPlaySong = __privateMethod(this, _emitPlaySong, emitPlaySong_fn).call(this, queue);
1012
- if (!queue._prev && (queue.repeatMode !== 1 /* SONG */ || queue._next)) {
1013
- const prev = queue.songs.shift();
1014
- delete prev.formats;
1015
- delete prev.streamURL;
1016
- if (this.options.savePreviousSongs)
1017
- queue.previousSongs.push(prev);
1018
- else
1019
- queue.previousSongs.push({ id: prev.id });
1020
- }
1021
- queue._next = queue._prev = false;
1022
- queue.beginTime = 0;
1023
- const err = await this.playSong(queue);
1024
- if (!err && emitPlaySong)
1025
- this.emit("playSong", queue, queue.songs[0]);
1026
- } finally {
1027
- queue._taskQueue.resolve();
1028
- }
1029
- }, "#handleSongFinish");
1030
- _handlePlayingError = new WeakSet();
1031
- handlePlayingError_fn = /* @__PURE__ */ __name(function(queue, error) {
1032
- const song = queue.songs.shift();
1033
- try {
1034
- error.name = "PlayingError";
1035
- error.message = `${error.message}
1036
- Id: ${song.id}
1037
- Name: ${song.name}`;
1038
- } catch {
1039
- }
1040
- this.emitError(error, queue.textChannel);
1041
- if (queue.songs.length > 0) {
1042
- this.playSong(queue).then((e) => {
1043
- if (!e)
1044
- this.emit("playSong", queue, queue.songs[0]);
1045
- });
1046
- } else {
1047
- queue.stop();
1048
- }
1049
- }, "#handlePlayingError");
1050
- _emitPlaySong = new WeakSet();
1051
- emitPlaySong_fn = /* @__PURE__ */ __name(function(queue) {
1052
- return !this.options.emitNewSongOnly || queue.repeatMode === 1 /* SONG */ && queue._next || queue.repeatMode !== 1 /* SONG */ && queue.songs[0]?.id !== queue.songs[1]?.id;
1053
- }, "#emitPlaySong");
1054
-
1055
- // src/core/manager/FilterManager.ts
1056
- var _validate, validate_fn, _resolveName, resolveName_fn, _resolveValue, resolveValue_fn, _apply, apply_fn;
1057
- var FilterManager = class extends BaseManager {
1058
- constructor(queue) {
1059
- super(queue.distube);
1060
- __privateAdd(this, _validate);
1061
- __privateAdd(this, _resolveName);
1062
- __privateAdd(this, _resolveValue);
1063
- __privateAdd(this, _apply);
1064
- __publicField(this, "queue");
1065
- this.queue = queue;
1066
- }
1067
- add(filterOrFilters, override = false) {
1068
- if (Array.isArray(filterOrFilters)) {
1069
- const resolvedFilters = filterOrFilters.map((f) => __privateMethod(this, _validate, validate_fn).call(this, f));
1070
- const newFilters = resolvedFilters.reduceRight((unique, o) => {
1071
- if (!unique.some((obj) => obj === o && obj.name === o) && !unique.some((obj) => obj !== o.name && obj.name !== o.name)) {
1072
- if (!this.has(o))
1073
- unique.push(o);
1074
- if (this.has(o) && override) {
1075
- this.remove(o);
1076
- unique.push(o);
1077
- }
1078
- }
1079
- return unique;
1080
- }, []).reverse();
1081
- return this.set([...this.collection.values(), ...newFilters]);
1082
- }
1083
- return this.set([...this.collection.values(), filterOrFilters]);
1084
- }
1085
- clear() {
1086
- return this.set([]);
1087
- }
1088
- set(filters) {
1089
- this.collection.clear();
1090
- for (const filter of filters) {
1091
- const resolved = __privateMethod(this, _validate, validate_fn).call(this, filter);
1092
- this.collection.set(__privateMethod(this, _resolveName, resolveName_fn).call(this, resolved), resolved);
1093
- }
1094
- __privateMethod(this, _apply, apply_fn).call(this);
1095
- return this;
1096
- }
1097
- remove(filterOrFilters) {
1098
- const remove = /* @__PURE__ */ __name((f) => this.collection.delete(__privateMethod(this, _resolveName, resolveName_fn).call(this, __privateMethod(this, _validate, validate_fn).call(this, f))), "remove");
1099
- if (Array.isArray(filterOrFilters))
1100
- filterOrFilters.map(remove);
1101
- else
1102
- remove(filterOrFilters);
1103
- __privateMethod(this, _apply, apply_fn).call(this);
1104
- return this;
1105
- }
1106
- has(filter) {
1107
- return this.collection.has(__privateMethod(this, _resolveName, resolveName_fn).call(this, filter));
1108
- }
1109
- get names() {
1110
- return this.collection.map((f) => __privateMethod(this, _resolveName, resolveName_fn).call(this, f));
1111
- }
1112
- get values() {
1113
- return this.collection.map((f) => __privateMethod(this, _resolveValue, resolveValue_fn).call(this, f));
1114
- }
1115
- toString() {
1116
- return this.names.toString();
1117
- }
1118
- };
1119
- __name(FilterManager, "FilterManager");
1120
- _validate = new WeakSet();
1121
- validate_fn = /* @__PURE__ */ __name(function(filter) {
1122
- if (typeof filter === "string" && Object.prototype.hasOwnProperty.call(this.distube.filters, filter) || typeof filter === "object" && typeof filter.name === "string" && typeof filter.value === "string") {
1123
- return filter;
1124
- }
1125
- throw new DisTubeError("INVALID_TYPE", "FilterResolvable", filter, "filter");
1126
- }, "#validate");
1127
- _resolveName = new WeakSet();
1128
- resolveName_fn = /* @__PURE__ */ __name(function(filter) {
1129
- return typeof filter === "string" ? filter : filter.name;
1130
- }, "#resolveName");
1131
- _resolveValue = new WeakSet();
1132
- resolveValue_fn = /* @__PURE__ */ __name(function(filter) {
1133
- return typeof filter === "string" ? this.distube.filters[filter] : filter.value;
1134
- }, "#resolveValue");
1135
- _apply = new WeakSet();
1136
- apply_fn = /* @__PURE__ */ __name(function() {
1137
- this.queue.beginTime = this.queue.currentTime;
1138
- this.queues.playSong(this.queue);
1139
- }, "#apply");
1140
-
1141
- // src/core/voice/DisTubeVoice.ts
1142
- var import_tiny_typed_emitter = require("tiny-typed-emitter");
1143
- var import_voice2 = require("@discordjs/voice");
1144
- var _channel, _volume, _br, br_fn, _join, join_fn;
1145
- var DisTubeVoice = class extends import_tiny_typed_emitter.TypedEmitter {
1146
- constructor(voiceManager, channel) {
1147
- super();
1148
- __privateAdd(this, _br);
1149
- __privateAdd(this, _join);
1150
- __publicField(this, "id");
1151
- __publicField(this, "voices");
1152
- __publicField(this, "audioPlayer");
1153
- __publicField(this, "connection");
1154
- __publicField(this, "audioResource");
1155
- __publicField(this, "emittedError");
1156
- __publicField(this, "isDisconnected", false);
1157
- __privateAdd(this, _channel, void 0);
1158
- __privateAdd(this, _volume, 100);
1159
- this.voices = voiceManager;
1160
- this.id = channel.guildId;
1161
- this.channel = channel;
1162
- this.voices.add(this.id, this);
1163
- this.audioPlayer = (0, import_voice2.createAudioPlayer)().on(import_voice2.AudioPlayerStatus.Idle, (oldState) => {
1164
- if (oldState.status !== import_voice2.AudioPlayerStatus.Idle) {
1165
- delete this.audioResource;
1166
- this.emit("finish");
1167
- }
1168
- }).on(import_voice2.AudioPlayerStatus.Playing, () => __privateMethod(this, _br, br_fn).call(this)).on("error", (error) => {
1169
- if (this.emittedError)
1170
- return;
1171
- this.emittedError = true;
1172
- this.emit("error", error);
1173
- });
1174
- this.connection.on(import_voice2.VoiceConnectionStatus.Disconnected, (_, newState) => {
1175
- if (newState.reason === import_voice2.VoiceConnectionDisconnectReason.Manual) {
1176
- this.leave();
1177
- } else if (newState.reason === import_voice2.VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {
1178
- entersState(this.connection, import_voice2.VoiceConnectionStatus.Connecting, 5e3).catch(() => {
1179
- if (![import_voice2.VoiceConnectionStatus.Ready, import_voice2.VoiceConnectionStatus.Connecting].includes(this.connection.state.status)) {
1180
- this.leave();
1181
- }
1182
- });
1183
- } else if (this.connection.rejoinAttempts < 5) {
1184
- setTimeout(() => {
1185
- this.connection.rejoin();
1186
- }, (this.connection.rejoinAttempts + 1) * 5e3).unref();
1187
- } else if (this.connection.state.status !== import_voice2.VoiceConnectionStatus.Destroyed) {
1188
- this.leave(new DisTubeError("VOICE_RECONNECT_FAILED"));
1189
- }
1190
- }).on(import_voice2.VoiceConnectionStatus.Destroyed, () => {
1191
- this.leave(new DisTubeError("VOICE_RECONNECT_FAILED"));
1192
- }).on("error", () => void 0);
1193
- this.connection.subscribe(this.audioPlayer);
1194
- }
1195
- get channel() {
1196
- return __privateGet(this, _channel);
1197
- }
1198
- set channel(channel) {
1199
- if (!isSupportedVoiceChannel(channel)) {
1200
- throw new DisTubeError("INVALID_TYPE", "BaseGuildVoiceChannel", channel, "DisTubeVoice#channel");
1201
- }
1202
- if (channel.guildId !== this.id)
1203
- throw new DisTubeError("VOICE_DIFFERENT_GUILD");
1204
- if (channel.client.user?.id !== this.voices.client.user?.id)
1205
- throw new DisTubeError("VOICE_DIFFERENT_CLIENT");
1206
- if (channel.id === __privateGet(this, _channel)?.id)
1207
- return;
1208
- if (!channel.joinable) {
1209
- if (channel.full)
1210
- throw new DisTubeError("VOICE_FULL");
1211
- else
1212
- throw new DisTubeError("VOICE_MISSING_PERMS");
1213
- }
1214
- this.connection = __privateMethod(this, _join, join_fn).call(this, channel);
1215
- __privateSet(this, _channel, channel);
1216
- __privateMethod(this, _br, br_fn).call(this);
1217
- }
1218
- async join(channel) {
1219
- const TIMEOUT = 3e4;
1220
- if (channel)
1221
- this.channel = channel;
1222
- try {
1223
- await entersState(this.connection, import_voice2.VoiceConnectionStatus.Ready, TIMEOUT);
1224
- } catch {
1225
- if (this.connection.state.status === import_voice2.VoiceConnectionStatus.Ready)
1226
- return this;
1227
- if (this.connection.state.status !== import_voice2.VoiceConnectionStatus.Destroyed)
1228
- this.connection.destroy();
1229
- this.voices.remove(this.id);
1230
- throw new DisTubeError("VOICE_CONNECT_FAILED", TIMEOUT / 1e3);
1231
- }
1232
- return this;
1233
- }
1234
- leave(error) {
1235
- this.stop(true);
1236
- if (!this.isDisconnected) {
1237
- this.emit("disconnect", error);
1238
- this.isDisconnected = true;
1239
- }
1240
- if (this.connection.state.status !== import_voice2.VoiceConnectionStatus.Destroyed)
1241
- this.connection.destroy();
1242
- this.voices.remove(this.id);
1243
- }
1244
- stop(force = false) {
1245
- this.audioPlayer.stop(force);
1246
- }
1247
- play(stream) {
1248
- this.emittedError = false;
1249
- stream.stream.on("error", (error) => {
1250
- if (this.emittedError || error.code === "ERR_STREAM_PREMATURE_CLOSE")
1251
- return;
1252
- this.emittedError = true;
1253
- this.emit("error", error);
1254
- });
1255
- this.audioResource = (0, import_voice2.createAudioResource)(stream.stream, {
1256
- inputType: stream.type,
1257
- inlineVolume: true
1258
- });
1259
- this.volume = __privateGet(this, _volume);
1260
- this.audioPlayer.play(this.audioResource);
1261
- }
1262
- set volume(volume) {
1263
- if (typeof volume !== "number" || isNaN(volume)) {
1264
- throw new DisTubeError("INVALID_TYPE", "number", volume, "volume");
1265
- }
1266
- if (volume < 0) {
1267
- throw new DisTubeError("NUMBER_COMPARE", "Volume", "bigger or equal to", 0);
1268
- }
1269
- __privateSet(this, _volume, volume);
1270
- this.audioResource?.volume?.setVolume(Math.pow(__privateGet(this, _volume) / 100, 0.5 / Math.log10(2)));
1271
- }
1272
- get volume() {
1273
- return __privateGet(this, _volume);
1274
- }
1275
- get playbackDuration() {
1276
- return (this.audioResource?.playbackDuration ?? 0) / 1e3;
1277
- }
1278
- pause() {
1279
- this.audioPlayer.pause();
1280
- }
1281
- unpause() {
1282
- this.audioPlayer.unpause();
1283
- }
1284
- get selfDeaf() {
1285
- return this.connection.joinConfig.selfDeaf;
1286
- }
1287
- get selfMute() {
1288
- return this.connection.joinConfig.selfMute;
1289
- }
1290
- setSelfDeaf(selfDeaf) {
1291
- if (typeof selfDeaf !== "boolean") {
1292
- throw new DisTubeError("INVALID_TYPE", "boolean", selfDeaf, "selfDeaf");
1293
- }
1294
- return this.connection.rejoin({
1295
- ...this.connection.joinConfig,
1296
- selfDeaf
1297
- });
1298
- }
1299
- setSelfMute(selfMute) {
1300
- if (typeof selfMute !== "boolean") {
1301
- throw new DisTubeError("INVALID_TYPE", "boolean", selfMute, "selfMute");
1302
- }
1303
- return this.connection.rejoin({
1304
- ...this.connection.joinConfig,
1305
- selfMute
1306
- });
1307
- }
1308
- get voiceState() {
1309
- return getClientMember(this.channel?.guild)?.voice;
1310
- }
1311
- };
1312
- __name(DisTubeVoice, "DisTubeVoice");
1313
- _channel = new WeakMap();
1314
- _volume = new WeakMap();
1315
- _br = new WeakSet();
1316
- br_fn = /* @__PURE__ */ __name(function() {
1317
- if (this.audioResource?.encoder?.encoder)
1318
- this.audioResource.encoder.setBitrate(this.channel.bitrate);
1319
- }, "#br");
1320
- _join = new WeakSet();
1321
- join_fn = /* @__PURE__ */ __name(function(channel) {
1322
- return (0, import_voice2.joinVoiceChannel)({
1323
- channelId: channel.id,
1324
- guildId: this.id,
1325
- adapterCreator: channel.guild.voiceAdapterCreator,
1326
- group: channel.client.user?.id
1327
- });
1328
- }, "#join");
1329
-
1330
- // src/core/voice/DisTubeVoiceManager.ts
1331
- var import_voice3 = require("@discordjs/voice");
1332
- var DisTubeVoiceManager = class extends GuildIdManager {
1333
- create(channel) {
1334
- const existing = this.get(channel.guildId);
1335
- if (existing) {
1336
- existing.channel = channel;
1337
- return existing;
1159
+ if (this.options.leaveOnFinish)
1160
+ queue.voice.leave();
1161
+ if (!queue.autoplay)
1162
+ this.emit("finish", queue);
1163
+ queue.remove();
1164
+ return;
1165
+ }
1338
1166
  }
1339
- return new DisTubeVoice(this, channel);
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();
1340
1184
  }
1341
- join(channel) {
1342
- const existing = this.get(channel.guildId);
1343
- if (existing)
1344
- return existing.join(channel);
1345
- return this.create(channel).join();
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 {
1346
1195
  }
1347
- leave(guild) {
1348
- const voice = this.get(guild);
1349
- if (voice) {
1350
- voice.leave();
1351
- } else {
1352
- const connection = (0, import_voice3.getVoiceConnection)(resolveGuildId(guild), this.client.user?.id) ?? (0, import_voice3.getVoiceConnection)(resolveGuildId(guild));
1353
- if (connection && connection.state.status !== import_voice3.VoiceConnectionStatus.Destroyed) {
1354
- connection.destroy();
1355
- }
1356
- }
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();
1357
1204
  }
1358
- };
1359
- __name(DisTubeVoiceManager, "DisTubeVoiceManager");
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");
1360
1210
 
1361
1211
  // src/core/DisTubeHandler.ts
1362
- var import_ytdl_core = __toESM(require("@distube/ytdl-core"));
1363
1212
  var import_ytpl = __toESM(require("@distube/ytpl"));
1213
+ var import_ytdl_core = __toESM(require("@distube/ytdl-core"));
1364
1214
  var DisTubeHandler = class extends DisTubeBase {
1365
1215
  constructor(distube) {
1366
1216
  super(distube);
@@ -1424,11 +1274,10 @@ var DisTubeHandler = class extends DisTubeBase {
1424
1274
  song.member = options.member;
1425
1275
  return song;
1426
1276
  }
1427
- if (song instanceof SearchResult) {
1428
- if (song.type === "video" /* VIDEO */)
1429
- return new Song(song, options);
1277
+ if (song instanceof SearchResultVideo)
1278
+ return new Song(song, options);
1279
+ if (song instanceof SearchResultPlaylist)
1430
1280
  return this.resolvePlaylist(song.url, options);
1431
- }
1432
1281
  if (isObject(song))
1433
1282
  return new Song(song, options);
1434
1283
  if (import_ytpl.default.validateID(song))
@@ -1453,14 +1302,19 @@ var DisTubeHandler = class extends DisTubeBase {
1453
1302
  playlist.member = member;
1454
1303
  return playlist;
1455
1304
  }
1456
- let solvablePlaylist;
1457
1305
  if (typeof playlist === "string") {
1458
- solvablePlaylist = await (0, import_ytpl.default)(playlist, { limit: Infinity });
1459
- solvablePlaylist.items = solvablePlaylist.items.filter((v) => !v.thumbnail.includes("no_thumbnail")).map((v) => new Song(v, { member, metadata }));
1460
- } else {
1461
- solvablePlaylist = playlist;
1462
- }
1463
- 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 });
1464
1318
  }
1465
1319
  async searchSong(message, query) {
1466
1320
  if (!isMessageInstance(message))
@@ -1594,6 +1448,186 @@ var DisTubeHandler = class extends DisTubeBase {
1594
1448
  };
1595
1449
  __name(DisTubeHandler, "DisTubeHandler");
1596
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");
1630
+
1597
1631
  // src/struct/Queue.ts
1598
1632
  var _filters;
1599
1633
  var Queue = class extends DisTubeBase {
@@ -1636,7 +1670,7 @@ var Queue = class extends DisTubeBase {
1636
1670
  this._listeners = void 0;
1637
1671
  }
1638
1672
  get clientMember() {
1639
- return getClientMember(this.voice.channel.guild);
1673
+ return this.voice.channel.guild.members.me ?? void 0;
1640
1674
  }
1641
1675
  get filters() {
1642
1676
  return __privateGet(this, _filters);
@@ -1980,7 +2014,7 @@ function isVoiceChannelEmpty(voiceState) {
1980
2014
  const clientId = voiceState.client.user?.id;
1981
2015
  if (!guild || !clientId)
1982
2016
  return false;
1983
- const voiceChannel = guild.members.resolve(clientId)?.voice?.channel;
2017
+ const voiceChannel = guild.members.me?.voice?.channel;
1984
2018
  if (!voiceChannel)
1985
2019
  return false;
1986
2020
  const members = voiceChannel.members.filter((m) => !m.user.bot);
@@ -2000,7 +2034,7 @@ function isMemberInstance(member) {
2000
2034
  }
2001
2035
  __name(isMemberInstance, "isMemberInstance");
2002
2036
  function isTextChannelInstance(channel) {
2003
- return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) && typeof channel.name === "string" && import_discord2.Constants.TextBasedChannelTypes.includes(channel.type) && typeof channel.messages?.cache === "object";
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";
2004
2038
  }
2005
2039
  __name(isTextChannelInstance, "isTextChannelInstance");
2006
2040
  function isMessageInstance(message) {
@@ -2046,34 +2080,6 @@ function checkInvalidKey(target, source, sourceName) {
2046
2080
  throw new DisTubeError("INVALID_KEY", sourceName, invalidKey);
2047
2081
  }
2048
2082
  __name(checkInvalidKey, "checkInvalidKey");
2049
- async function waitEvent(target, status, maxTime) {
2050
- let cleanup = /* @__PURE__ */ __name(() => {
2051
- }, "cleanup");
2052
- try {
2053
- await new Promise((resolve, reject) => {
2054
- const timeout = setTimeout(() => reject(new Error(`Didn't trigger ${status} within ${maxTime}ms`)), maxTime);
2055
- target.once(status, resolve);
2056
- target.once("error", reject);
2057
- cleanup = /* @__PURE__ */ __name(() => {
2058
- clearTimeout(timeout);
2059
- target.off(status, resolve);
2060
- target.off("error", reject);
2061
- }, "cleanup");
2062
- if (target?.state?.status === status)
2063
- resolve(0);
2064
- });
2065
- return target;
2066
- } finally {
2067
- cleanup();
2068
- }
2069
- }
2070
- __name(waitEvent, "waitEvent");
2071
- async function entersState(target, status, maxTime) {
2072
- if (target.state.status === status)
2073
- return target;
2074
- return waitEvent(target, status, maxTime);
2075
- }
2076
- __name(entersState, "entersState");
2077
2083
  function isObject(obj) {
2078
2084
  return typeof obj === "object" && obj !== null && !Array.isArray(obj);
2079
2085
  }
@@ -2082,16 +2088,6 @@ function isRecord(obj) {
2082
2088
  return isObject(obj);
2083
2089
  }
2084
2090
  __name(isRecord, "isRecord");
2085
- function getClientMember(guild) {
2086
- const clientUser = guild.client.user;
2087
- if (!clientUser)
2088
- return void 0;
2089
- const clientMember = guild.members.resolve(clientUser);
2090
- if (!clientMember)
2091
- return void 0;
2092
- return clientMember;
2093
- }
2094
- __name(getClientMember, "getClientMember");
2095
2091
 
2096
2092
  // src/plugin/http.ts
2097
2093
  var import_http = __toESM(require("http"));
@@ -2183,7 +2179,7 @@ var DisTube = class extends import_tiny_typed_emitter2.TypedEmitter {
2183
2179
  if (!isObject(options))
2184
2180
  throw new DisTubeError("INVALID_TYPE", "object", options, "options");
2185
2181
  const { textChannel, member, skip, message, metadata } = {
2186
- member: getClientMember(voiceChannel.guild),
2182
+ member: voiceChannel.guild.members.me ?? void 0,
2187
2183
  textChannel: options?.message?.channel,
2188
2184
  skip: false,
2189
2185
  ...options
@@ -2231,12 +2227,12 @@ var DisTube = class extends import_tiny_typed_emitter2.TypedEmitter {
2231
2227
  if (!(e instanceof DisTubeError)) {
2232
2228
  try {
2233
2229
  e.name = "PlayError";
2234
- e.message = `${song?.url || song}
2230
+ e.message = `${typeof song === "string" ? song : song.url}
2235
2231
  ${e.message}`;
2236
2232
  } catch {
2237
2233
  }
2238
2234
  }
2239
- this.emitError(e, textChannel);
2235
+ throw e;
2240
2236
  } finally {
2241
2237
  if (queuing)
2242
2238
  queue?._taskQueue.resolve();
@@ -2248,7 +2244,7 @@ ${e.message}`;
2248
2244
  throw new DisTubeError("INVALID_TYPE", "Array", songs, "songs");
2249
2245
  if (!songs.length)
2250
2246
  throw new DisTubeError("EMPTY_ARRAY", "songs");
2251
- 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 */);
2252
2248
  if (!filteredSongs.length)
2253
2249
  throw new DisTubeError("NO_VALID_SONG");
2254
2250
  if (member && !isMemberInstance(member)) {
@@ -2270,7 +2266,7 @@ ${e.message}`;
2270
2266
  return new Playlist(resolvedSongs, { member, properties, metadata });
2271
2267
  }
2272
2268
  async search(string, options = {}) {
2273
- const opts = { type: "video", limit: 10, safeSearch: false, ...options };
2269
+ const opts = { type: "video" /* VIDEO */, limit: 10, safeSearch: false, ...options };
2274
2270
  if (typeof opts.type !== "string" || !["video", "playlist"].includes(opts.type)) {
2275
2271
  throw new DisTubeError("INVALID_TYPE", ["video", "playlist"], opts.type, "options.type");
2276
2272
  }
@@ -2283,7 +2279,11 @@ ${e.message}`;
2283
2279
  }
2284
2280
  try {
2285
2281
  const search = await (0, import_ytsr.default)(string, opts);
2286
- 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
+ });
2287
2287
  if (results.length === 0)
2288
2288
  throw new DisTubeError("NO_RESULT");
2289
2289
  return results;
@@ -2404,8 +2404,9 @@ __name(DisTube, "DisTube");
2404
2404
  Queue,
2405
2405
  QueueManager,
2406
2406
  RepeatMode,
2407
- SearchResult,
2407
+ SearchResultPlaylist,
2408
2408
  SearchResultType,
2409
+ SearchResultVideo,
2409
2410
  Song,
2410
2411
  StreamType,
2411
2412
  TaskQueue,
@@ -2414,9 +2415,7 @@ __name(DisTube, "DisTube");
2414
2415
  chooseBestVideoFormat,
2415
2416
  defaultFilters,
2416
2417
  defaultOptions,
2417
- entersState,
2418
2418
  formatDuration,
2419
- getClientMember,
2420
2419
  getResponseHeaders,
2421
2420
  isClientInstance,
2422
2421
  isGuildInstance,