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.mjs CHANGED
@@ -44,7 +44,7 @@ var require_package = __commonJS({
44
44
  "package.json"(exports, module) {
45
45
  module.exports = {
46
46
  name: "distube",
47
- version: "4.0.0-dev.5",
47
+ version: "4.0.0-dev.6",
48
48
  description: "A Discord.js module to simplify your music commands and play songs with audio filters on Discord without any API key.",
49
49
  main: "./dist/index.js",
50
50
  module: "./dist/index.mjs",
@@ -110,41 +110,41 @@ var require_package = __commonJS({
110
110
  dependencies: {
111
111
  "@distube/ytdl-core": "^4.11.3",
112
112
  "@distube/ytpl": "^1.1.1",
113
- "@distube/ytsr": "^1.1.5",
113
+ "@distube/ytsr": "^1.1.7",
114
114
  "prism-media": "https://codeload.github.com/distubejs/prism-media/tar.gz/main#workaround.tar.gz",
115
115
  "tiny-typed-emitter": "^2.1.0",
116
116
  tslib: "^2.4.0"
117
117
  },
118
118
  devDependencies: {
119
- "@babel/core": "^7.18.0",
120
- "@babel/plugin-proposal-class-properties": "^7.17.12",
121
- "@babel/plugin-proposal-object-rest-spread": "^7.18.0",
122
- "@babel/preset-env": "^7.18.0",
123
- "@babel/preset-typescript": "^7.17.12",
124
- "@commitlint/cli": "^17.0.0",
125
- "@commitlint/config-conventional": "^17.0.0",
119
+ "@babel/core": "^7.18.6",
120
+ "@babel/plugin-proposal-class-properties": "^7.18.6",
121
+ "@babel/plugin-proposal-object-rest-spread": "^7.18.6",
122
+ "@babel/preset-env": "^7.18.6",
123
+ "@babel/preset-typescript": "^7.18.6",
124
+ "@commitlint/cli": "^17.0.3",
125
+ "@commitlint/config-conventional": "^17.0.3",
126
126
  "@discordjs/voice": "dev",
127
127
  "@distube/docgen": "distubejs/docgen",
128
- "@types/jest": "^27.5.1",
129
- "@types/node": "^17.0.35",
130
- "@typescript-eslint/eslint-plugin": "^5.25.0",
131
- "@typescript-eslint/parser": "^5.25.0",
132
- "babel-jest": "^28.1.0",
128
+ "@types/jest": "^28.1.5",
129
+ "@types/node": "^18.0.4",
130
+ "@typescript-eslint/eslint-plugin": "^5.30.6",
131
+ "@typescript-eslint/parser": "^5.30.6",
132
+ "babel-jest": "^28.1.3",
133
133
  "discord.js": "dev",
134
- eslint: "^8.15.0",
134
+ eslint: "^8.19.0",
135
135
  "eslint-config-distube": "^1.6.4",
136
136
  "eslint-config-prettier": "^8.5.0",
137
137
  "eslint-plugin-deprecation": "^1.3.2",
138
- "eslint-plugin-jsdoc": "^39.3.0",
138
+ "eslint-plugin-jsdoc": "^39.3.3",
139
139
  husky: "^8.0.1",
140
- jest: "^28.1.0",
140
+ jest: "^28.1.3",
141
141
  "jsdoc-babel": "^0.5.0",
142
142
  "nano-staged": "^0.8.0",
143
- "npm-check-updates": "^13.0.1",
143
+ "npm-check-updates": "^15.3.0",
144
144
  pinst: "^3.0.0",
145
- prettier: "^2.6.2",
146
- tsup: "^5.12.8",
147
- typescript: "^4.6.4"
145
+ prettier: "^2.7.1",
146
+ tsup: "^6.1.3",
147
+ typescript: "^4.7.4"
148
148
  },
149
149
  peerDependencies: {
150
150
  "@discordjs/opus": "*",
@@ -236,7 +236,7 @@ var defaultOptions = {
236
236
  // src/struct/DisTubeError.ts
237
237
  import { inspect } from "node:util";
238
238
  var ERROR_MESSAGES = {
239
- 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 ${inspect(got)}`,
239
+ 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 ${inspect(got)} (${typeof got})`,
240
240
  NUMBER_COMPARE: (name, expected, value) => `'${name}' must be ${expected} ${value}`,
241
241
  EMPTY_ARRAY: (name) => `'${name}' is an empty array`,
242
242
  EMPTY_FILTERED_ARRAY: (name, type) => `There is no valid '${type}' in the '${name}' array`,
@@ -342,26 +342,33 @@ var Playlist = class {
342
342
  __publicField(this, "url");
343
343
  __publicField(this, "thumbnail");
344
344
  const { member, properties, metadata } = options;
345
- if (typeof playlist !== "object") {
346
- throw new DisTubeError("INVALID_TYPE", ["Array<Song>", "object"], playlist, "playlist");
345
+ if (typeof playlist !== "object" || !Array.isArray(playlist) && ["source", "songs"].some((key) => !(key in playlist))) {
346
+ throw new DisTubeError("INVALID_TYPE", ["Array<Song>", "PlaylistInfo"], playlist, "playlist");
347
347
  }
348
348
  if (typeof properties !== "undefined" && !isRecord(properties)) {
349
349
  throw new DisTubeError("INVALID_TYPE", "object", properties, "properties");
350
350
  }
351
- const info = playlist;
352
- this.source = (info.source || properties?.source || "youtube").toLowerCase();
353
- this.songs = Array.isArray(info) ? info : info.items || info.songs;
354
- if (!Array.isArray(this.songs) || !this.songs.length) {
355
- throw new DisTubeError("EMPTY_PLAYLIST");
351
+ if (Array.isArray(playlist)) {
352
+ this.source = "youtube";
353
+ if (!playlist.length)
354
+ throw new DisTubeError("EMPTY_PLAYLIST");
355
+ this.songs = playlist;
356
+ this.name = this.songs[0].name ? `${this.songs[0].name} and ${this.songs.length - 1} more songs.` : `${this.songs.length} songs playlist`;
357
+ this.thumbnail = this.songs[0].thumbnail;
358
+ } else {
359
+ this.source = (playlist.source || "youtube").toLowerCase();
360
+ if (!Array.isArray(playlist.songs) || !playlist.songs.length)
361
+ throw new DisTubeError("EMPTY_PLAYLIST");
362
+ this.songs = playlist.songs;
363
+ 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`);
364
+ this.url = playlist.url || playlist.webpage_url;
365
+ this.thumbnail = playlist.thumbnail || this.songs[0].thumbnail;
356
366
  }
357
367
  this.songs.map((s) => s.constructor.name === "Song" && (s.playlist = this));
358
- this.member = member || info.member || void 0;
359
- 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`);
360
- this.url = info.url || info.webpage_url;
361
- this.thumbnail = info.thumbnail?.url || info.thumbnail || this.songs[0].thumbnail;
362
368
  if (properties)
363
369
  for (const [key, value] of Object.entries(properties))
364
370
  this[key] = value;
371
+ this.member = member;
365
372
  this.metadata = metadata;
366
373
  }
367
374
  get duration() {
@@ -395,41 +402,64 @@ _metadata = new WeakMap();
395
402
  _member = new WeakMap();
396
403
 
397
404
  // src/struct/SearchResult.ts
398
- var SearchResult = class {
405
+ var ISearchResult = class {
399
406
  constructor(info) {
400
407
  __publicField(this, "source");
401
- __publicField(this, "type");
402
408
  __publicField(this, "id");
403
409
  __publicField(this, "name");
404
410
  __publicField(this, "url");
405
- __publicField(this, "views");
406
- __publicField(this, "isLive");
407
- __publicField(this, "duration");
408
- __publicField(this, "formattedDuration");
409
- __publicField(this, "thumbnail");
410
411
  __publicField(this, "uploader");
411
412
  this.source = "youtube";
412
- this.type = info.type === "video" ? "video" /* VIDEO */ : "playlist" /* PLAYLIST */;
413
413
  this.id = info.id;
414
414
  this.name = info.name;
415
415
  this.url = info.url;
416
- if (this.type === "video" /* VIDEO */) {
417
- info = info;
418
- this.views = info.views;
419
- this.isLive = info.isLive;
420
- this.duration = this.isLive ? 0 : toSecond(info.duration);
421
- this.formattedDuration = this.isLive ? "Live" : formatDuration(this.duration);
422
- this.thumbnail = info.thumbnail;
423
- } else if (this.type !== "playlist") {
424
- throw new DisTubeError("INVALID_TYPE", ["video", "playlist"], this.type, "SearchResult.type");
425
- }
426
416
  this.uploader = {
427
- name: (info.author || info.owner)?.name,
428
- url: (info.author || info.owner)?.url
417
+ name: void 0,
418
+ url: void 0
419
+ };
420
+ }
421
+ };
422
+ __name(ISearchResult, "ISearchResult");
423
+ var SearchResultVideo = class extends ISearchResult {
424
+ constructor(info) {
425
+ super(info);
426
+ __publicField(this, "type");
427
+ __publicField(this, "views");
428
+ __publicField(this, "isLive");
429
+ __publicField(this, "duration");
430
+ __publicField(this, "formattedDuration");
431
+ __publicField(this, "thumbnail");
432
+ if (info.type !== "video")
433
+ throw new DisTubeError("INVALID_TYPE", "video", info.type, "type");
434
+ this.type = "video" /* VIDEO */;
435
+ this.views = info.views;
436
+ this.isLive = info.isLive;
437
+ this.duration = this.isLive ? 0 : toSecond(info.duration);
438
+ this.formattedDuration = this.isLive ? "Live" : formatDuration(this.duration);
439
+ this.thumbnail = info.thumbnail;
440
+ this.uploader = {
441
+ name: info.author?.name,
442
+ url: info.author?.url
443
+ };
444
+ }
445
+ };
446
+ __name(SearchResultVideo, "SearchResultVideo");
447
+ var SearchResultPlaylist = class extends ISearchResult {
448
+ constructor(info) {
449
+ super(info);
450
+ __publicField(this, "type");
451
+ __publicField(this, "length");
452
+ if (info.type !== "playlist")
453
+ throw new DisTubeError("INVALID_TYPE", "playlist", info.type, "type");
454
+ this.type = "playlist" /* PLAYLIST */;
455
+ this.length = info.length;
456
+ this.uploader = {
457
+ name: info.owner?.name,
458
+ url: info.owner?.url
429
459
  };
430
460
  }
431
461
  };
432
- __name(SearchResult, "SearchResult");
462
+ __name(SearchResultPlaylist, "SearchResultPlaylist");
433
463
 
434
464
  // src/struct/Song.ts
435
465
  var _metadata2, _member2, _playlist;
@@ -569,114 +599,6 @@ _metadata2 = new WeakMap();
569
599
  _member2 = new WeakMap();
570
600
  _playlist = new WeakMap();
571
601
 
572
- // src/core/DisTubeOptions.ts
573
- var _validateOptions, validateOptions_fn;
574
- var Options = class {
575
- constructor(options) {
576
- __privateAdd(this, _validateOptions);
577
- __publicField(this, "plugins");
578
- __publicField(this, "emitNewSongOnly");
579
- __publicField(this, "leaveOnFinish");
580
- __publicField(this, "leaveOnStop");
581
- __publicField(this, "leaveOnEmpty");
582
- __publicField(this, "emptyCooldown");
583
- __publicField(this, "savePreviousSongs");
584
- __publicField(this, "searchSongs");
585
- __publicField(this, "searchCooldown");
586
- __publicField(this, "youtubeCookie");
587
- __publicField(this, "youtubeIdentityToken");
588
- __publicField(this, "customFilters");
589
- __publicField(this, "ytdlOptions");
590
- __publicField(this, "nsfw");
591
- __publicField(this, "emitAddSongWhenCreatingQueue");
592
- __publicField(this, "emitAddListWhenCreatingQueue");
593
- __publicField(this, "joinNewVoiceChannel");
594
- __publicField(this, "streamType");
595
- if (typeof options !== "object" || Array.isArray(options)) {
596
- throw new DisTubeError("INVALID_TYPE", "object", options, "DisTubeOptions");
597
- }
598
- const opts = { ...defaultOptions, ...options };
599
- this.plugins = opts.plugins;
600
- this.emitNewSongOnly = opts.emitNewSongOnly;
601
- this.leaveOnEmpty = opts.leaveOnEmpty;
602
- this.leaveOnFinish = opts.leaveOnFinish;
603
- this.leaveOnStop = opts.leaveOnStop;
604
- this.savePreviousSongs = opts.savePreviousSongs;
605
- this.searchSongs = opts.searchSongs;
606
- this.youtubeCookie = opts.youtubeCookie;
607
- this.youtubeIdentityToken = opts.youtubeIdentityToken;
608
- this.customFilters = opts.customFilters;
609
- this.ytdlOptions = opts.ytdlOptions;
610
- this.searchCooldown = opts.searchCooldown;
611
- this.emptyCooldown = opts.emptyCooldown;
612
- this.nsfw = opts.nsfw;
613
- this.emitAddSongWhenCreatingQueue = opts.emitAddSongWhenCreatingQueue;
614
- this.emitAddListWhenCreatingQueue = opts.emitAddListWhenCreatingQueue;
615
- this.joinNewVoiceChannel = opts.joinNewVoiceChannel;
616
- this.streamType = opts.streamType;
617
- checkInvalidKey(opts, this, "DisTubeOptions");
618
- __privateMethod(this, _validateOptions, validateOptions_fn).call(this);
619
- }
620
- };
621
- __name(Options, "Options");
622
- _validateOptions = new WeakSet();
623
- validateOptions_fn = /* @__PURE__ */ __name(function(options = this) {
624
- if (typeof options.emitNewSongOnly !== "boolean") {
625
- throw new DisTubeError("INVALID_TYPE", "boolean", options.emitNewSongOnly, "DisTubeOptions.emitNewSongOnly");
626
- }
627
- if (typeof options.leaveOnEmpty !== "boolean") {
628
- throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnEmpty, "DisTubeOptions.leaveOnEmpty");
629
- }
630
- if (typeof options.leaveOnFinish !== "boolean") {
631
- throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnFinish, "DisTubeOptions.leaveOnFinish");
632
- }
633
- if (typeof options.leaveOnStop !== "boolean") {
634
- throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnStop, "DisTubeOptions.leaveOnStop");
635
- }
636
- if (typeof options.savePreviousSongs !== "boolean") {
637
- throw new DisTubeError("INVALID_TYPE", "boolean", options.savePreviousSongs, "DisTubeOptions.savePreviousSongs");
638
- }
639
- if (typeof options.joinNewVoiceChannel !== "boolean") {
640
- throw new DisTubeError("INVALID_TYPE", "boolean", options.joinNewVoiceChannel, "DisTubeOptions.joinNewVoiceChannel");
641
- }
642
- if (typeof options.youtubeCookie !== "undefined" && typeof options.youtubeCookie !== "string") {
643
- throw new DisTubeError("INVALID_TYPE", "string", options.youtubeCookie, "DisTubeOptions.youtubeCookie");
644
- }
645
- if (typeof options.youtubeIdentityToken !== "undefined" && typeof options.youtubeIdentityToken !== "string") {
646
- throw new DisTubeError("INVALID_TYPE", "string", options.youtubeIdentityToken, "DisTubeOptions.youtubeIdentityToken");
647
- }
648
- if (typeof options.customFilters !== "undefined" && typeof options.customFilters !== "object" || Array.isArray(options.customFilters)) {
649
- throw new DisTubeError("INVALID_TYPE", "object", options.customFilters, "DisTubeOptions.customFilters");
650
- }
651
- if (typeof options.ytdlOptions !== "object" || Array.isArray(options.ytdlOptions)) {
652
- throw new DisTubeError("INVALID_TYPE", "object", options.ytdlOptions, "DisTubeOptions.ytdlOptions");
653
- }
654
- if (typeof options.searchCooldown !== "number" || isNaN(options.searchCooldown)) {
655
- throw new DisTubeError("INVALID_TYPE", "number", options.searchCooldown, "DisTubeOptions.searchCooldown");
656
- }
657
- if (typeof options.emptyCooldown !== "number" || isNaN(options.emptyCooldown)) {
658
- throw new DisTubeError("INVALID_TYPE", "number", options.emptyCooldown, "DisTubeOptions.emptyCooldown");
659
- }
660
- if (typeof options.searchSongs !== "number" || isNaN(options.searchSongs)) {
661
- throw new DisTubeError("INVALID_TYPE", "number", options.searchSongs, "DisTubeOptions.searchSongs");
662
- }
663
- if (!Array.isArray(options.plugins)) {
664
- throw new DisTubeError("INVALID_TYPE", "Array<Plugin>", options.plugins, "DisTubeOptions.plugins");
665
- }
666
- if (typeof options.nsfw !== "boolean") {
667
- throw new DisTubeError("INVALID_TYPE", "boolean", options.nsfw, "DisTubeOptions.nsfw");
668
- }
669
- if (typeof options.emitAddSongWhenCreatingQueue !== "boolean") {
670
- throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddSongWhenCreatingQueue, "DisTubeOptions.emitAddSongWhenCreatingQueue");
671
- }
672
- if (typeof options.emitAddListWhenCreatingQueue !== "boolean") {
673
- throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddListWhenCreatingQueue, "DisTubeOptions.emitAddListWhenCreatingQueue");
674
- }
675
- if (typeof options.streamType !== "number" || isNaN(options.streamType) || !StreamType[options.streamType]) {
676
- throw new DisTubeError("INVALID_TYPE", "StreamType", options.streamType, "DisTubeOptions.streamType");
677
- }
678
- }, "#validateOptions");
679
-
680
602
  // src/core/DisTubeBase.ts
681
603
  var DisTubeBase = class {
682
604
  constructor(distube) {
@@ -707,77 +629,202 @@ var DisTubeBase = class {
707
629
  };
708
630
  __name(DisTubeBase, "DisTubeBase");
709
631
 
710
- // src/core/DisTubeStream.ts
711
- import { FFmpeg } from "prism-media";
712
- import { StreamType as DiscordVoiceStreamType } from "@discordjs/voice";
713
- var chooseBestVideoFormat = /* @__PURE__ */ __name((formats, isLive = false) => {
714
- let filter = /* @__PURE__ */ __name((format) => format.hasAudio, "filter");
715
- if (isLive)
716
- filter = /* @__PURE__ */ __name((format) => format.hasAudio && format.isHLS, "filter");
717
- formats = formats.filter(filter).sort((a, b) => Number(b.audioBitrate) - Number(a.audioBitrate) || Number(a.bitrate) - Number(b.bitrate));
718
- return formats.find((format) => !format.hasVideo) || formats.sort((a, b) => Number(a.bitrate) - Number(b.bitrate))[0];
719
- }, "chooseBestVideoFormat");
720
- var DisTubeStream = class {
721
- constructor(url, options) {
722
- __publicField(this, "type");
723
- __publicField(this, "stream");
724
- __publicField(this, "url");
725
- this.url = url;
726
- this.type = !options.type ? DiscordVoiceStreamType.Opus : DiscordVoiceStreamType.Raw;
727
- const args = [
728
- "-reconnect",
729
- "1",
730
- "-reconnect_streamed",
731
- "1",
732
- "-reconnect_delay_max",
733
- "5",
734
- "-i",
735
- url,
736
- "-analyzeduration",
737
- "0",
738
- "-loglevel",
739
- "0",
740
- "-ar",
741
- "48000",
742
- "-ac",
743
- "2",
744
- "-f"
745
- ];
746
- if (!options.type) {
747
- args.push("opus", "-acodec", "libopus");
748
- } else {
749
- args.push("s16le");
750
- }
751
- if (typeof options.seek === "number" && options.seek > 0) {
752
- args.unshift("-ss", options.seek.toString());
753
- }
754
- if (Array.isArray(options.ffmpegArgs)) {
755
- args.push(...options.ffmpegArgs);
756
- }
757
- this.stream = new FFmpeg({ args, shell: false });
632
+ // src/core/DisTubeVoice.ts
633
+ import { TypedEmitter } from "tiny-typed-emitter";
634
+ import {
635
+ AudioPlayerStatus,
636
+ VoiceConnectionDisconnectReason,
637
+ VoiceConnectionStatus,
638
+ createAudioPlayer,
639
+ createAudioResource,
640
+ entersState,
641
+ joinVoiceChannel
642
+ } from "@discordjs/voice";
643
+ var _channel, _volume, _br, br_fn, _join, join_fn;
644
+ var DisTubeVoice = class extends TypedEmitter {
645
+ constructor(voiceManager, channel) {
646
+ super();
647
+ __privateAdd(this, _br);
648
+ __privateAdd(this, _join);
649
+ __publicField(this, "id");
650
+ __publicField(this, "voices");
651
+ __publicField(this, "audioPlayer");
652
+ __publicField(this, "connection");
653
+ __publicField(this, "audioResource");
654
+ __publicField(this, "emittedError");
655
+ __publicField(this, "isDisconnected", false);
656
+ __privateAdd(this, _channel, void 0);
657
+ __privateAdd(this, _volume, 100);
658
+ this.voices = voiceManager;
659
+ this.id = channel.guildId;
660
+ this.channel = channel;
661
+ this.voices.add(this.id, this);
662
+ this.audioPlayer = createAudioPlayer().on(AudioPlayerStatus.Idle, (oldState) => {
663
+ if (oldState.status !== AudioPlayerStatus.Idle) {
664
+ delete this.audioResource;
665
+ this.emit("finish");
666
+ }
667
+ }).on(AudioPlayerStatus.Playing, () => __privateMethod(this, _br, br_fn).call(this)).on("error", (error) => {
668
+ if (this.emittedError)
669
+ return;
670
+ this.emittedError = true;
671
+ this.emit("error", error);
672
+ });
673
+ this.connection.on(VoiceConnectionStatus.Disconnected, (_, newState) => {
674
+ if (newState.reason === VoiceConnectionDisconnectReason.Manual) {
675
+ this.leave();
676
+ } else if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {
677
+ entersState(this.connection, VoiceConnectionStatus.Connecting, 5e3).catch(() => {
678
+ if (![VoiceConnectionStatus.Ready, VoiceConnectionStatus.Connecting].includes(this.connection.state.status)) {
679
+ this.leave();
680
+ }
681
+ });
682
+ } else if (this.connection.rejoinAttempts < 5) {
683
+ setTimeout(() => {
684
+ this.connection.rejoin();
685
+ }, (this.connection.rejoinAttempts + 1) * 5e3).unref();
686
+ } else if (this.connection.state.status !== VoiceConnectionStatus.Destroyed) {
687
+ this.leave(new DisTubeError("VOICE_RECONNECT_FAILED"));
688
+ }
689
+ }).on(VoiceConnectionStatus.Destroyed, () => {
690
+ this.leave();
691
+ }).on("error", () => void 0);
692
+ this.connection.subscribe(this.audioPlayer);
758
693
  }
759
- static YouTube(formats, options = {}) {
760
- if (!formats || !formats.length)
761
- throw new DisTubeError("UNAVAILABLE_VIDEO");
762
- if (!options || typeof options !== "object" || Array.isArray(options)) {
763
- throw new DisTubeError("INVALID_TYPE", "object", options, "options");
764
- }
765
- const bestFormat = chooseBestVideoFormat(formats, options.isLive);
766
- if (!bestFormat)
767
- throw new DisTubeError("UNPLAYABLE_FORMATS");
768
- return new DisTubeStream(bestFormat.url, options);
694
+ get channel() {
695
+ return __privateGet(this, _channel);
769
696
  }
770
- static DirectLink(url, options = {}) {
771
- if (!options || typeof options !== "object" || Array.isArray(options)) {
772
- throw new DisTubeError("INVALID_TYPE", "object", options, "options");
697
+ set channel(channel) {
698
+ if (!isSupportedVoiceChannel(channel)) {
699
+ throw new DisTubeError("INVALID_TYPE", "BaseGuildVoiceChannel", channel, "DisTubeVoice#channel");
773
700
  }
774
- if (typeof url !== "string" || !isURL(url)) {
775
- throw new DisTubeError("INVALID_TYPE", "an URL", url);
701
+ if (channel.guildId !== this.id)
702
+ throw new DisTubeError("VOICE_DIFFERENT_GUILD");
703
+ if (channel.client.user?.id !== this.voices.client.user?.id)
704
+ throw new DisTubeError("VOICE_DIFFERENT_CLIENT");
705
+ if (channel.id === __privateGet(this, _channel)?.id)
706
+ return;
707
+ if (!channel.joinable) {
708
+ if (channel.full)
709
+ throw new DisTubeError("VOICE_FULL");
710
+ else
711
+ throw new DisTubeError("VOICE_MISSING_PERMS");
776
712
  }
777
- return new DisTubeStream(url, options);
713
+ this.connection = __privateMethod(this, _join, join_fn).call(this, channel);
714
+ __privateSet(this, _channel, channel);
715
+ __privateMethod(this, _br, br_fn).call(this);
716
+ }
717
+ async join(channel) {
718
+ const TIMEOUT = 3e4;
719
+ if (channel)
720
+ this.channel = channel;
721
+ try {
722
+ await entersState(this.connection, VoiceConnectionStatus.Ready, TIMEOUT);
723
+ } catch {
724
+ if (this.connection.state.status === VoiceConnectionStatus.Ready)
725
+ return this;
726
+ if (this.connection.state.status !== VoiceConnectionStatus.Destroyed)
727
+ this.connection.destroy();
728
+ this.voices.remove(this.id);
729
+ throw new DisTubeError("VOICE_CONNECT_FAILED", TIMEOUT / 1e3);
730
+ }
731
+ return this;
732
+ }
733
+ leave(error) {
734
+ this.stop(true);
735
+ if (!this.isDisconnected) {
736
+ this.emit("disconnect", error);
737
+ this.isDisconnected = true;
738
+ }
739
+ if (this.connection.state.status !== VoiceConnectionStatus.Destroyed)
740
+ this.connection.destroy();
741
+ this.voices.remove(this.id);
742
+ }
743
+ stop(force = false) {
744
+ this.audioPlayer.stop(force);
745
+ }
746
+ play(stream) {
747
+ this.emittedError = false;
748
+ stream.stream.on("error", (error) => {
749
+ if (this.emittedError || error.code === "ERR_STREAM_PREMATURE_CLOSE")
750
+ return;
751
+ this.emittedError = true;
752
+ this.emit("error", error);
753
+ });
754
+ this.audioResource = createAudioResource(stream.stream, {
755
+ inputType: stream.type,
756
+ inlineVolume: true
757
+ });
758
+ this.volume = __privateGet(this, _volume);
759
+ this.audioPlayer.play(this.audioResource);
760
+ }
761
+ set volume(volume) {
762
+ if (typeof volume !== "number" || isNaN(volume)) {
763
+ throw new DisTubeError("INVALID_TYPE", "number", volume, "volume");
764
+ }
765
+ if (volume < 0) {
766
+ throw new DisTubeError("NUMBER_COMPARE", "Volume", "bigger or equal to", 0);
767
+ }
768
+ __privateSet(this, _volume, volume);
769
+ this.audioResource?.volume?.setVolume(Math.pow(__privateGet(this, _volume) / 100, 0.5 / Math.log10(2)));
770
+ }
771
+ get volume() {
772
+ return __privateGet(this, _volume);
773
+ }
774
+ get playbackDuration() {
775
+ return (this.audioResource?.playbackDuration ?? 0) / 1e3;
776
+ }
777
+ pause() {
778
+ this.audioPlayer.pause();
779
+ }
780
+ unpause() {
781
+ this.audioPlayer.unpause();
782
+ }
783
+ get selfDeaf() {
784
+ return this.connection.joinConfig.selfDeaf;
785
+ }
786
+ get selfMute() {
787
+ return this.connection.joinConfig.selfMute;
788
+ }
789
+ setSelfDeaf(selfDeaf) {
790
+ if (typeof selfDeaf !== "boolean") {
791
+ throw new DisTubeError("INVALID_TYPE", "boolean", selfDeaf, "selfDeaf");
792
+ }
793
+ return this.connection.rejoin({
794
+ ...this.connection.joinConfig,
795
+ selfDeaf
796
+ });
797
+ }
798
+ setSelfMute(selfMute) {
799
+ if (typeof selfMute !== "boolean") {
800
+ throw new DisTubeError("INVALID_TYPE", "boolean", selfMute, "selfMute");
801
+ }
802
+ return this.connection.rejoin({
803
+ ...this.connection.joinConfig,
804
+ selfMute
805
+ });
806
+ }
807
+ get voiceState() {
808
+ return this.channel?.guild?.members?.me?.voice;
778
809
  }
779
810
  };
780
- __name(DisTubeStream, "DisTubeStream");
811
+ __name(DisTubeVoice, "DisTubeVoice");
812
+ _channel = new WeakMap();
813
+ _volume = new WeakMap();
814
+ _br = new WeakSet();
815
+ br_fn = /* @__PURE__ */ __name(function() {
816
+ if (this.audioResource?.encoder?.encoder)
817
+ this.audioResource.encoder.setBitrate(this.channel.bitrate);
818
+ }, "#br");
819
+ _join = new WeakSet();
820
+ join_fn = /* @__PURE__ */ __name(function(channel) {
821
+ return joinVoiceChannel({
822
+ channelId: channel.id,
823
+ guildId: this.id,
824
+ adapterCreator: channel.guild.voiceAdapterCreator,
825
+ group: channel.client.user?.id
826
+ });
827
+ }, "#join");
781
828
 
782
829
  // src/core/manager/BaseManager.ts
783
830
  import { Collection } from "discord.js";
@@ -813,6 +860,123 @@ var GuildIdManager = class extends BaseManager {
813
860
  };
814
861
  __name(GuildIdManager, "GuildIdManager");
815
862
 
863
+ // src/core/manager/DisTubeVoiceManager.ts
864
+ import { VoiceConnectionStatus as VoiceConnectionStatus2, getVoiceConnection } from "@discordjs/voice";
865
+ var DisTubeVoiceManager = class extends GuildIdManager {
866
+ create(channel) {
867
+ const existing = this.get(channel.guildId);
868
+ if (existing) {
869
+ existing.channel = channel;
870
+ return existing;
871
+ }
872
+ return new DisTubeVoice(this, channel);
873
+ }
874
+ join(channel) {
875
+ const existing = this.get(channel.guildId);
876
+ if (existing)
877
+ return existing.join(channel);
878
+ return this.create(channel).join();
879
+ }
880
+ leave(guild) {
881
+ const voice = this.get(guild);
882
+ if (voice) {
883
+ voice.leave();
884
+ } else {
885
+ const connection = getVoiceConnection(resolveGuildId(guild), this.client.user?.id) ?? getVoiceConnection(resolveGuildId(guild));
886
+ if (connection && connection.state.status !== VoiceConnectionStatus2.Destroyed) {
887
+ connection.destroy();
888
+ }
889
+ }
890
+ }
891
+ };
892
+ __name(DisTubeVoiceManager, "DisTubeVoiceManager");
893
+
894
+ // src/core/manager/FilterManager.ts
895
+ var _validate, validate_fn, _resolveName, resolveName_fn, _resolveValue, resolveValue_fn, _apply, apply_fn;
896
+ var FilterManager = class extends BaseManager {
897
+ constructor(queue) {
898
+ super(queue.distube);
899
+ __privateAdd(this, _validate);
900
+ __privateAdd(this, _resolveName);
901
+ __privateAdd(this, _resolveValue);
902
+ __privateAdd(this, _apply);
903
+ __publicField(this, "queue");
904
+ this.queue = queue;
905
+ }
906
+ add(filterOrFilters, override = false) {
907
+ if (Array.isArray(filterOrFilters)) {
908
+ const resolvedFilters = filterOrFilters.map((f) => __privateMethod(this, _validate, validate_fn).call(this, f));
909
+ const newFilters = resolvedFilters.reduceRight((unique, o) => {
910
+ if (!unique.some((obj) => obj === o && obj.name === o) && !unique.some((obj) => obj !== o.name && obj.name !== o.name)) {
911
+ if (!this.has(o))
912
+ unique.push(o);
913
+ if (this.has(o) && override) {
914
+ this.remove(o);
915
+ unique.push(o);
916
+ }
917
+ }
918
+ return unique;
919
+ }, []).reverse();
920
+ return this.set([...this.collection.values(), ...newFilters]);
921
+ }
922
+ return this.set([...this.collection.values(), filterOrFilters]);
923
+ }
924
+ clear() {
925
+ return this.set([]);
926
+ }
927
+ set(filters) {
928
+ this.collection.clear();
929
+ for (const filter of filters) {
930
+ const resolved = __privateMethod(this, _validate, validate_fn).call(this, filter);
931
+ this.collection.set(__privateMethod(this, _resolveName, resolveName_fn).call(this, resolved), resolved);
932
+ }
933
+ __privateMethod(this, _apply, apply_fn).call(this);
934
+ return this;
935
+ }
936
+ remove(filterOrFilters) {
937
+ const remove = /* @__PURE__ */ __name((f) => this.collection.delete(__privateMethod(this, _resolveName, resolveName_fn).call(this, __privateMethod(this, _validate, validate_fn).call(this, f))), "remove");
938
+ if (Array.isArray(filterOrFilters))
939
+ filterOrFilters.map(remove);
940
+ else
941
+ remove(filterOrFilters);
942
+ __privateMethod(this, _apply, apply_fn).call(this);
943
+ return this;
944
+ }
945
+ has(filter) {
946
+ return this.collection.has(__privateMethod(this, _resolveName, resolveName_fn).call(this, filter));
947
+ }
948
+ get names() {
949
+ return this.collection.map((f) => __privateMethod(this, _resolveName, resolveName_fn).call(this, f));
950
+ }
951
+ get values() {
952
+ return this.collection.map((f) => __privateMethod(this, _resolveValue, resolveValue_fn).call(this, f));
953
+ }
954
+ toString() {
955
+ return this.names.toString();
956
+ }
957
+ };
958
+ __name(FilterManager, "FilterManager");
959
+ _validate = new WeakSet();
960
+ validate_fn = /* @__PURE__ */ __name(function(filter) {
961
+ if (typeof filter === "string" && Object.prototype.hasOwnProperty.call(this.distube.filters, filter) || typeof filter === "object" && typeof filter.name === "string" && typeof filter.value === "string") {
962
+ return filter;
963
+ }
964
+ throw new DisTubeError("INVALID_TYPE", "FilterResolvable", filter, "filter");
965
+ }, "#validate");
966
+ _resolveName = new WeakSet();
967
+ resolveName_fn = /* @__PURE__ */ __name(function(filter) {
968
+ return typeof filter === "string" ? filter : filter.name;
969
+ }, "#resolveName");
970
+ _resolveValue = new WeakSet();
971
+ resolveValue_fn = /* @__PURE__ */ __name(function(filter) {
972
+ return typeof filter === "string" ? this.distube.filters[filter] : filter.value;
973
+ }, "#resolveValue");
974
+ _apply = new WeakSet();
975
+ apply_fn = /* @__PURE__ */ __name(function() {
976
+ this.queue.beginTime = this.queue.currentTime;
977
+ this.queues.playSong(this.queue);
978
+ }, "#apply");
979
+
816
980
  // src/core/manager/QueueManager.ts
817
981
  var _voiceEventHandler, voiceEventHandler_fn, _handleSongFinish, handleSongFinish_fn, _handlePlayingError, handlePlayingError_fn, _emitPlaySong, emitPlaySong_fn;
818
982
  var QueueManager = class extends GuildIdManager {
@@ -932,371 +1096,58 @@ handleSongFinish_fn = /* @__PURE__ */ __name(async function(queue) {
932
1096
  if (this.options.leaveOnFinish)
933
1097
  queue.voice.leave();
934
1098
  if (!queue.autoplay)
935
- this.emit("finish", queue);
936
- queue.remove();
937
- return;
938
- }
939
- }
940
- const emitPlaySong = __privateMethod(this, _emitPlaySong, emitPlaySong_fn).call(this, queue);
941
- if (!queue._prev && (queue.repeatMode !== 1 /* SONG */ || queue._next)) {
942
- const prev = queue.songs.shift();
943
- delete prev.formats;
944
- delete prev.streamURL;
945
- if (this.options.savePreviousSongs)
946
- queue.previousSongs.push(prev);
947
- else
948
- queue.previousSongs.push({ id: prev.id });
949
- }
950
- queue._next = queue._prev = false;
951
- queue.beginTime = 0;
952
- const err = await this.playSong(queue);
953
- if (!err && emitPlaySong)
954
- this.emit("playSong", queue, queue.songs[0]);
955
- } finally {
956
- queue._taskQueue.resolve();
957
- }
958
- }, "#handleSongFinish");
959
- _handlePlayingError = new WeakSet();
960
- handlePlayingError_fn = /* @__PURE__ */ __name(function(queue, error) {
961
- const song = queue.songs.shift();
962
- try {
963
- error.name = "PlayingError";
964
- error.message = `${error.message}
965
- Id: ${song.id}
966
- Name: ${song.name}`;
967
- } catch {
968
- }
969
- this.emitError(error, queue.textChannel);
970
- if (queue.songs.length > 0) {
971
- this.playSong(queue).then((e) => {
972
- if (!e)
973
- this.emit("playSong", queue, queue.songs[0]);
974
- });
975
- } else {
976
- queue.stop();
977
- }
978
- }, "#handlePlayingError");
979
- _emitPlaySong = new WeakSet();
980
- emitPlaySong_fn = /* @__PURE__ */ __name(function(queue) {
981
- return !this.options.emitNewSongOnly || queue.repeatMode === 1 /* SONG */ && queue._next || queue.repeatMode !== 1 /* SONG */ && queue.songs[0]?.id !== queue.songs[1]?.id;
982
- }, "#emitPlaySong");
983
-
984
- // src/core/manager/FilterManager.ts
985
- var _validate, validate_fn, _resolveName, resolveName_fn, _resolveValue, resolveValue_fn, _apply, apply_fn;
986
- var FilterManager = class extends BaseManager {
987
- constructor(queue) {
988
- super(queue.distube);
989
- __privateAdd(this, _validate);
990
- __privateAdd(this, _resolveName);
991
- __privateAdd(this, _resolveValue);
992
- __privateAdd(this, _apply);
993
- __publicField(this, "queue");
994
- this.queue = queue;
995
- }
996
- add(filterOrFilters, override = false) {
997
- if (Array.isArray(filterOrFilters)) {
998
- const resolvedFilters = filterOrFilters.map((f) => __privateMethod(this, _validate, validate_fn).call(this, f));
999
- const newFilters = resolvedFilters.reduceRight((unique, o) => {
1000
- if (!unique.some((obj) => obj === o && obj.name === o) && !unique.some((obj) => obj !== o.name && obj.name !== o.name)) {
1001
- if (!this.has(o))
1002
- unique.push(o);
1003
- if (this.has(o) && override) {
1004
- this.remove(o);
1005
- unique.push(o);
1006
- }
1007
- }
1008
- return unique;
1009
- }, []).reverse();
1010
- return this.set([...this.collection.values(), ...newFilters]);
1011
- }
1012
- return this.set([...this.collection.values(), filterOrFilters]);
1013
- }
1014
- clear() {
1015
- return this.set([]);
1016
- }
1017
- set(filters) {
1018
- this.collection.clear();
1019
- for (const filter of filters) {
1020
- const resolved = __privateMethod(this, _validate, validate_fn).call(this, filter);
1021
- this.collection.set(__privateMethod(this, _resolveName, resolveName_fn).call(this, resolved), resolved);
1022
- }
1023
- __privateMethod(this, _apply, apply_fn).call(this);
1024
- return this;
1025
- }
1026
- remove(filterOrFilters) {
1027
- const remove = /* @__PURE__ */ __name((f) => this.collection.delete(__privateMethod(this, _resolveName, resolveName_fn).call(this, __privateMethod(this, _validate, validate_fn).call(this, f))), "remove");
1028
- if (Array.isArray(filterOrFilters))
1029
- filterOrFilters.map(remove);
1030
- else
1031
- remove(filterOrFilters);
1032
- __privateMethod(this, _apply, apply_fn).call(this);
1033
- return this;
1034
- }
1035
- has(filter) {
1036
- return this.collection.has(__privateMethod(this, _resolveName, resolveName_fn).call(this, filter));
1037
- }
1038
- get names() {
1039
- return this.collection.map((f) => __privateMethod(this, _resolveName, resolveName_fn).call(this, f));
1040
- }
1041
- get values() {
1042
- return this.collection.map((f) => __privateMethod(this, _resolveValue, resolveValue_fn).call(this, f));
1043
- }
1044
- toString() {
1045
- return this.names.toString();
1046
- }
1047
- };
1048
- __name(FilterManager, "FilterManager");
1049
- _validate = new WeakSet();
1050
- validate_fn = /* @__PURE__ */ __name(function(filter) {
1051
- if (typeof filter === "string" && Object.prototype.hasOwnProperty.call(this.distube.filters, filter) || typeof filter === "object" && typeof filter.name === "string" && typeof filter.value === "string") {
1052
- return filter;
1053
- }
1054
- throw new DisTubeError("INVALID_TYPE", "FilterResolvable", filter, "filter");
1055
- }, "#validate");
1056
- _resolveName = new WeakSet();
1057
- resolveName_fn = /* @__PURE__ */ __name(function(filter) {
1058
- return typeof filter === "string" ? filter : filter.name;
1059
- }, "#resolveName");
1060
- _resolveValue = new WeakSet();
1061
- resolveValue_fn = /* @__PURE__ */ __name(function(filter) {
1062
- return typeof filter === "string" ? this.distube.filters[filter] : filter.value;
1063
- }, "#resolveValue");
1064
- _apply = new WeakSet();
1065
- apply_fn = /* @__PURE__ */ __name(function() {
1066
- this.queue.beginTime = this.queue.currentTime;
1067
- this.queues.playSong(this.queue);
1068
- }, "#apply");
1069
-
1070
- // src/core/voice/DisTubeVoice.ts
1071
- import { TypedEmitter } from "tiny-typed-emitter";
1072
- import {
1073
- AudioPlayerStatus,
1074
- VoiceConnectionDisconnectReason,
1075
- VoiceConnectionStatus,
1076
- createAudioPlayer,
1077
- createAudioResource,
1078
- joinVoiceChannel
1079
- } from "@discordjs/voice";
1080
- var _channel, _volume, _br, br_fn, _join, join_fn;
1081
- var DisTubeVoice = class extends TypedEmitter {
1082
- constructor(voiceManager, channel) {
1083
- super();
1084
- __privateAdd(this, _br);
1085
- __privateAdd(this, _join);
1086
- __publicField(this, "id");
1087
- __publicField(this, "voices");
1088
- __publicField(this, "audioPlayer");
1089
- __publicField(this, "connection");
1090
- __publicField(this, "audioResource");
1091
- __publicField(this, "emittedError");
1092
- __publicField(this, "isDisconnected", false);
1093
- __privateAdd(this, _channel, void 0);
1094
- __privateAdd(this, _volume, 100);
1095
- this.voices = voiceManager;
1096
- this.id = channel.guildId;
1097
- this.channel = channel;
1098
- this.voices.add(this.id, this);
1099
- this.audioPlayer = createAudioPlayer().on(AudioPlayerStatus.Idle, (oldState) => {
1100
- if (oldState.status !== AudioPlayerStatus.Idle) {
1101
- delete this.audioResource;
1102
- this.emit("finish");
1103
- }
1104
- }).on(AudioPlayerStatus.Playing, () => __privateMethod(this, _br, br_fn).call(this)).on("error", (error) => {
1105
- if (this.emittedError)
1106
- return;
1107
- this.emittedError = true;
1108
- this.emit("error", error);
1109
- });
1110
- this.connection.on(VoiceConnectionStatus.Disconnected, (_, newState) => {
1111
- if (newState.reason === VoiceConnectionDisconnectReason.Manual) {
1112
- this.leave();
1113
- } else if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {
1114
- entersState(this.connection, VoiceConnectionStatus.Connecting, 5e3).catch(() => {
1115
- if (![VoiceConnectionStatus.Ready, VoiceConnectionStatus.Connecting].includes(this.connection.state.status)) {
1116
- this.leave();
1117
- }
1118
- });
1119
- } else if (this.connection.rejoinAttempts < 5) {
1120
- setTimeout(() => {
1121
- this.connection.rejoin();
1122
- }, (this.connection.rejoinAttempts + 1) * 5e3).unref();
1123
- } else if (this.connection.state.status !== VoiceConnectionStatus.Destroyed) {
1124
- this.leave(new DisTubeError("VOICE_RECONNECT_FAILED"));
1125
- }
1126
- }).on(VoiceConnectionStatus.Destroyed, () => {
1127
- this.leave(new DisTubeError("VOICE_RECONNECT_FAILED"));
1128
- }).on("error", () => void 0);
1129
- this.connection.subscribe(this.audioPlayer);
1130
- }
1131
- get channel() {
1132
- return __privateGet(this, _channel);
1133
- }
1134
- set channel(channel) {
1135
- if (!isSupportedVoiceChannel(channel)) {
1136
- throw new DisTubeError("INVALID_TYPE", "BaseGuildVoiceChannel", channel, "DisTubeVoice#channel");
1137
- }
1138
- if (channel.guildId !== this.id)
1139
- throw new DisTubeError("VOICE_DIFFERENT_GUILD");
1140
- if (channel.client.user?.id !== this.voices.client.user?.id)
1141
- throw new DisTubeError("VOICE_DIFFERENT_CLIENT");
1142
- if (channel.id === __privateGet(this, _channel)?.id)
1143
- return;
1144
- if (!channel.joinable) {
1145
- if (channel.full)
1146
- throw new DisTubeError("VOICE_FULL");
1147
- else
1148
- throw new DisTubeError("VOICE_MISSING_PERMS");
1149
- }
1150
- this.connection = __privateMethod(this, _join, join_fn).call(this, channel);
1151
- __privateSet(this, _channel, channel);
1152
- __privateMethod(this, _br, br_fn).call(this);
1153
- }
1154
- async join(channel) {
1155
- const TIMEOUT = 3e4;
1156
- if (channel)
1157
- this.channel = channel;
1158
- try {
1159
- await entersState(this.connection, VoiceConnectionStatus.Ready, TIMEOUT);
1160
- } catch {
1161
- if (this.connection.state.status === VoiceConnectionStatus.Ready)
1162
- return this;
1163
- if (this.connection.state.status !== VoiceConnectionStatus.Destroyed)
1164
- this.connection.destroy();
1165
- this.voices.remove(this.id);
1166
- throw new DisTubeError("VOICE_CONNECT_FAILED", TIMEOUT / 1e3);
1167
- }
1168
- return this;
1169
- }
1170
- leave(error) {
1171
- this.stop(true);
1172
- if (!this.isDisconnected) {
1173
- this.emit("disconnect", error);
1174
- this.isDisconnected = true;
1175
- }
1176
- if (this.connection.state.status !== VoiceConnectionStatus.Destroyed)
1177
- this.connection.destroy();
1178
- this.voices.remove(this.id);
1179
- }
1180
- stop(force = false) {
1181
- this.audioPlayer.stop(force);
1182
- }
1183
- play(stream) {
1184
- this.emittedError = false;
1185
- stream.stream.on("error", (error) => {
1186
- if (this.emittedError || error.code === "ERR_STREAM_PREMATURE_CLOSE")
1187
- return;
1188
- this.emittedError = true;
1189
- this.emit("error", error);
1190
- });
1191
- this.audioResource = createAudioResource(stream.stream, {
1192
- inputType: stream.type,
1193
- inlineVolume: true
1194
- });
1195
- this.volume = __privateGet(this, _volume);
1196
- this.audioPlayer.play(this.audioResource);
1197
- }
1198
- set volume(volume) {
1199
- if (typeof volume !== "number" || isNaN(volume)) {
1200
- throw new DisTubeError("INVALID_TYPE", "number", volume, "volume");
1201
- }
1202
- if (volume < 0) {
1203
- throw new DisTubeError("NUMBER_COMPARE", "Volume", "bigger or equal to", 0);
1204
- }
1205
- __privateSet(this, _volume, volume);
1206
- this.audioResource?.volume?.setVolume(Math.pow(__privateGet(this, _volume) / 100, 0.5 / Math.log10(2)));
1207
- }
1208
- get volume() {
1209
- return __privateGet(this, _volume);
1210
- }
1211
- get playbackDuration() {
1212
- return (this.audioResource?.playbackDuration ?? 0) / 1e3;
1213
- }
1214
- pause() {
1215
- this.audioPlayer.pause();
1216
- }
1217
- unpause() {
1218
- this.audioPlayer.unpause();
1219
- }
1220
- get selfDeaf() {
1221
- return this.connection.joinConfig.selfDeaf;
1222
- }
1223
- get selfMute() {
1224
- return this.connection.joinConfig.selfMute;
1225
- }
1226
- setSelfDeaf(selfDeaf) {
1227
- if (typeof selfDeaf !== "boolean") {
1228
- throw new DisTubeError("INVALID_TYPE", "boolean", selfDeaf, "selfDeaf");
1229
- }
1230
- return this.connection.rejoin({
1231
- ...this.connection.joinConfig,
1232
- selfDeaf
1233
- });
1234
- }
1235
- setSelfMute(selfMute) {
1236
- if (typeof selfMute !== "boolean") {
1237
- throw new DisTubeError("INVALID_TYPE", "boolean", selfMute, "selfMute");
1238
- }
1239
- return this.connection.rejoin({
1240
- ...this.connection.joinConfig,
1241
- selfMute
1242
- });
1243
- }
1244
- get voiceState() {
1245
- return getClientMember(this.channel?.guild)?.voice;
1246
- }
1247
- };
1248
- __name(DisTubeVoice, "DisTubeVoice");
1249
- _channel = new WeakMap();
1250
- _volume = new WeakMap();
1251
- _br = new WeakSet();
1252
- br_fn = /* @__PURE__ */ __name(function() {
1253
- if (this.audioResource?.encoder?.encoder)
1254
- this.audioResource.encoder.setBitrate(this.channel.bitrate);
1255
- }, "#br");
1256
- _join = new WeakSet();
1257
- join_fn = /* @__PURE__ */ __name(function(channel) {
1258
- return joinVoiceChannel({
1259
- channelId: channel.id,
1260
- guildId: this.id,
1261
- adapterCreator: channel.guild.voiceAdapterCreator,
1262
- group: channel.client.user?.id
1263
- });
1264
- }, "#join");
1265
-
1266
- // src/core/voice/DisTubeVoiceManager.ts
1267
- import { VoiceConnectionStatus as VoiceConnectionStatus2, getVoiceConnection } from "@discordjs/voice";
1268
- var DisTubeVoiceManager = class extends GuildIdManager {
1269
- create(channel) {
1270
- const existing = this.get(channel.guildId);
1271
- if (existing) {
1272
- existing.channel = channel;
1273
- return existing;
1099
+ this.emit("finish", queue);
1100
+ queue.remove();
1101
+ return;
1102
+ }
1274
1103
  }
1275
- return new DisTubeVoice(this, channel);
1104
+ const emitPlaySong = __privateMethod(this, _emitPlaySong, emitPlaySong_fn).call(this, queue);
1105
+ if (!queue._prev && (queue.repeatMode !== 1 /* SONG */ || queue._next)) {
1106
+ const prev = queue.songs.shift();
1107
+ delete prev.formats;
1108
+ delete prev.streamURL;
1109
+ if (this.options.savePreviousSongs)
1110
+ queue.previousSongs.push(prev);
1111
+ else
1112
+ queue.previousSongs.push({ id: prev.id });
1113
+ }
1114
+ queue._next = queue._prev = false;
1115
+ queue.beginTime = 0;
1116
+ const err = await this.playSong(queue);
1117
+ if (!err && emitPlaySong)
1118
+ this.emit("playSong", queue, queue.songs[0]);
1119
+ } finally {
1120
+ queue._taskQueue.resolve();
1276
1121
  }
1277
- join(channel) {
1278
- const existing = this.get(channel.guildId);
1279
- if (existing)
1280
- return existing.join(channel);
1281
- return this.create(channel).join();
1122
+ }, "#handleSongFinish");
1123
+ _handlePlayingError = new WeakSet();
1124
+ handlePlayingError_fn = /* @__PURE__ */ __name(function(queue, error) {
1125
+ const song = queue.songs.shift();
1126
+ try {
1127
+ error.name = "PlayingError";
1128
+ error.message = `${error.message}
1129
+ Id: ${song.id}
1130
+ Name: ${song.name}`;
1131
+ } catch {
1282
1132
  }
1283
- leave(guild) {
1284
- const voice = this.get(guild);
1285
- if (voice) {
1286
- voice.leave();
1287
- } else {
1288
- const connection = getVoiceConnection(resolveGuildId(guild), this.client.user?.id) ?? getVoiceConnection(resolveGuildId(guild));
1289
- if (connection && connection.state.status !== VoiceConnectionStatus2.Destroyed) {
1290
- connection.destroy();
1291
- }
1292
- }
1133
+ this.emitError(error, queue.textChannel);
1134
+ if (queue.songs.length > 0) {
1135
+ this.playSong(queue).then((e) => {
1136
+ if (!e)
1137
+ this.emit("playSong", queue, queue.songs[0]);
1138
+ });
1139
+ } else {
1140
+ queue.stop();
1293
1141
  }
1294
- };
1295
- __name(DisTubeVoiceManager, "DisTubeVoiceManager");
1142
+ }, "#handlePlayingError");
1143
+ _emitPlaySong = new WeakSet();
1144
+ emitPlaySong_fn = /* @__PURE__ */ __name(function(queue) {
1145
+ return !this.options.emitNewSongOnly || queue.repeatMode === 1 /* SONG */ && queue._next || queue.repeatMode !== 1 /* SONG */ && queue.songs[0]?.id !== queue.songs[1]?.id;
1146
+ }, "#emitPlaySong");
1296
1147
 
1297
1148
  // src/core/DisTubeHandler.ts
1298
- import ytdl from "@distube/ytdl-core";
1299
1149
  import ytpl from "@distube/ytpl";
1150
+ import ytdl from "@distube/ytdl-core";
1300
1151
  var DisTubeHandler = class extends DisTubeBase {
1301
1152
  constructor(distube) {
1302
1153
  super(distube);
@@ -1360,11 +1211,10 @@ var DisTubeHandler = class extends DisTubeBase {
1360
1211
  song.member = options.member;
1361
1212
  return song;
1362
1213
  }
1363
- if (song instanceof SearchResult) {
1364
- if (song.type === "video" /* VIDEO */)
1365
- return new Song(song, options);
1214
+ if (song instanceof SearchResultVideo)
1215
+ return new Song(song, options);
1216
+ if (song instanceof SearchResultPlaylist)
1366
1217
  return this.resolvePlaylist(song.url, options);
1367
- }
1368
1218
  if (isObject(song))
1369
1219
  return new Song(song, options);
1370
1220
  if (ytpl.validateID(song))
@@ -1389,14 +1239,19 @@ var DisTubeHandler = class extends DisTubeBase {
1389
1239
  playlist.member = member;
1390
1240
  return playlist;
1391
1241
  }
1392
- let solvablePlaylist;
1393
1242
  if (typeof playlist === "string") {
1394
- solvablePlaylist = await ytpl(playlist, { limit: Infinity });
1395
- solvablePlaylist.items = solvablePlaylist.items.filter((v) => !v.thumbnail.includes("no_thumbnail")).map((v) => new Song(v, { member, metadata }));
1396
- } else {
1397
- solvablePlaylist = playlist;
1398
- }
1399
- return new Playlist(solvablePlaylist, { member, properties: { source }, metadata });
1243
+ const info = await ytpl(playlist, { limit: Infinity });
1244
+ const songs = info.items.filter((v) => !v.thumbnail.includes("no_thumbnail")).map((v) => new Song(v, { member, metadata }));
1245
+ return new Playlist({
1246
+ source,
1247
+ songs,
1248
+ member,
1249
+ name: info.title,
1250
+ url: info.url,
1251
+ thumbnail: songs[0].thumbnail
1252
+ }, { metadata });
1253
+ }
1254
+ return new Playlist(playlist, { member, properties: { source }, metadata });
1400
1255
  }
1401
1256
  async searchSong(message, query) {
1402
1257
  if (!isMessageInstance(message))
@@ -1530,6 +1385,186 @@ var DisTubeHandler = class extends DisTubeBase {
1530
1385
  };
1531
1386
  __name(DisTubeHandler, "DisTubeHandler");
1532
1387
 
1388
+ // src/core/DisTubeOptions.ts
1389
+ var _validateOptions, validateOptions_fn;
1390
+ var Options = class {
1391
+ constructor(options) {
1392
+ __privateAdd(this, _validateOptions);
1393
+ __publicField(this, "plugins");
1394
+ __publicField(this, "emitNewSongOnly");
1395
+ __publicField(this, "leaveOnFinish");
1396
+ __publicField(this, "leaveOnStop");
1397
+ __publicField(this, "leaveOnEmpty");
1398
+ __publicField(this, "emptyCooldown");
1399
+ __publicField(this, "savePreviousSongs");
1400
+ __publicField(this, "searchSongs");
1401
+ __publicField(this, "searchCooldown");
1402
+ __publicField(this, "youtubeCookie");
1403
+ __publicField(this, "youtubeIdentityToken");
1404
+ __publicField(this, "customFilters");
1405
+ __publicField(this, "ytdlOptions");
1406
+ __publicField(this, "nsfw");
1407
+ __publicField(this, "emitAddSongWhenCreatingQueue");
1408
+ __publicField(this, "emitAddListWhenCreatingQueue");
1409
+ __publicField(this, "joinNewVoiceChannel");
1410
+ __publicField(this, "streamType");
1411
+ if (typeof options !== "object" || Array.isArray(options)) {
1412
+ throw new DisTubeError("INVALID_TYPE", "object", options, "DisTubeOptions");
1413
+ }
1414
+ const opts = { ...defaultOptions, ...options };
1415
+ this.plugins = opts.plugins;
1416
+ this.emitNewSongOnly = opts.emitNewSongOnly;
1417
+ this.leaveOnEmpty = opts.leaveOnEmpty;
1418
+ this.leaveOnFinish = opts.leaveOnFinish;
1419
+ this.leaveOnStop = opts.leaveOnStop;
1420
+ this.savePreviousSongs = opts.savePreviousSongs;
1421
+ this.searchSongs = opts.searchSongs;
1422
+ this.youtubeCookie = opts.youtubeCookie;
1423
+ this.youtubeIdentityToken = opts.youtubeIdentityToken;
1424
+ this.customFilters = opts.customFilters;
1425
+ this.ytdlOptions = opts.ytdlOptions;
1426
+ this.searchCooldown = opts.searchCooldown;
1427
+ this.emptyCooldown = opts.emptyCooldown;
1428
+ this.nsfw = opts.nsfw;
1429
+ this.emitAddSongWhenCreatingQueue = opts.emitAddSongWhenCreatingQueue;
1430
+ this.emitAddListWhenCreatingQueue = opts.emitAddListWhenCreatingQueue;
1431
+ this.joinNewVoiceChannel = opts.joinNewVoiceChannel;
1432
+ this.streamType = opts.streamType;
1433
+ checkInvalidKey(opts, this, "DisTubeOptions");
1434
+ __privateMethod(this, _validateOptions, validateOptions_fn).call(this);
1435
+ }
1436
+ };
1437
+ __name(Options, "Options");
1438
+ _validateOptions = new WeakSet();
1439
+ validateOptions_fn = /* @__PURE__ */ __name(function(options = this) {
1440
+ if (typeof options.emitNewSongOnly !== "boolean") {
1441
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.emitNewSongOnly, "DisTubeOptions.emitNewSongOnly");
1442
+ }
1443
+ if (typeof options.leaveOnEmpty !== "boolean") {
1444
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnEmpty, "DisTubeOptions.leaveOnEmpty");
1445
+ }
1446
+ if (typeof options.leaveOnFinish !== "boolean") {
1447
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnFinish, "DisTubeOptions.leaveOnFinish");
1448
+ }
1449
+ if (typeof options.leaveOnStop !== "boolean") {
1450
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnStop, "DisTubeOptions.leaveOnStop");
1451
+ }
1452
+ if (typeof options.savePreviousSongs !== "boolean") {
1453
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.savePreviousSongs, "DisTubeOptions.savePreviousSongs");
1454
+ }
1455
+ if (typeof options.joinNewVoiceChannel !== "boolean") {
1456
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.joinNewVoiceChannel, "DisTubeOptions.joinNewVoiceChannel");
1457
+ }
1458
+ if (typeof options.youtubeCookie !== "undefined" && typeof options.youtubeCookie !== "string") {
1459
+ throw new DisTubeError("INVALID_TYPE", "string", options.youtubeCookie, "DisTubeOptions.youtubeCookie");
1460
+ }
1461
+ if (typeof options.youtubeIdentityToken !== "undefined" && typeof options.youtubeIdentityToken !== "string") {
1462
+ throw new DisTubeError("INVALID_TYPE", "string", options.youtubeIdentityToken, "DisTubeOptions.youtubeIdentityToken");
1463
+ }
1464
+ if (typeof options.customFilters !== "undefined" && typeof options.customFilters !== "object" || Array.isArray(options.customFilters)) {
1465
+ throw new DisTubeError("INVALID_TYPE", "object", options.customFilters, "DisTubeOptions.customFilters");
1466
+ }
1467
+ if (typeof options.ytdlOptions !== "object" || Array.isArray(options.ytdlOptions)) {
1468
+ throw new DisTubeError("INVALID_TYPE", "object", options.ytdlOptions, "DisTubeOptions.ytdlOptions");
1469
+ }
1470
+ if (typeof options.searchCooldown !== "number" || isNaN(options.searchCooldown)) {
1471
+ throw new DisTubeError("INVALID_TYPE", "number", options.searchCooldown, "DisTubeOptions.searchCooldown");
1472
+ }
1473
+ if (typeof options.emptyCooldown !== "number" || isNaN(options.emptyCooldown)) {
1474
+ throw new DisTubeError("INVALID_TYPE", "number", options.emptyCooldown, "DisTubeOptions.emptyCooldown");
1475
+ }
1476
+ if (typeof options.searchSongs !== "number" || isNaN(options.searchSongs)) {
1477
+ throw new DisTubeError("INVALID_TYPE", "number", options.searchSongs, "DisTubeOptions.searchSongs");
1478
+ }
1479
+ if (!Array.isArray(options.plugins)) {
1480
+ throw new DisTubeError("INVALID_TYPE", "Array<Plugin>", options.plugins, "DisTubeOptions.plugins");
1481
+ }
1482
+ if (typeof options.nsfw !== "boolean") {
1483
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.nsfw, "DisTubeOptions.nsfw");
1484
+ }
1485
+ if (typeof options.emitAddSongWhenCreatingQueue !== "boolean") {
1486
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddSongWhenCreatingQueue, "DisTubeOptions.emitAddSongWhenCreatingQueue");
1487
+ }
1488
+ if (typeof options.emitAddListWhenCreatingQueue !== "boolean") {
1489
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddListWhenCreatingQueue, "DisTubeOptions.emitAddListWhenCreatingQueue");
1490
+ }
1491
+ if (typeof options.streamType !== "number" || isNaN(options.streamType) || !StreamType[options.streamType]) {
1492
+ throw new DisTubeError("INVALID_TYPE", "StreamType", options.streamType, "DisTubeOptions.streamType");
1493
+ }
1494
+ }, "#validateOptions");
1495
+
1496
+ // src/core/DisTubeStream.ts
1497
+ import { FFmpeg } from "prism-media";
1498
+ import { StreamType as DiscordVoiceStreamType } from "@discordjs/voice";
1499
+ var chooseBestVideoFormat = /* @__PURE__ */ __name((formats, isLive = false) => {
1500
+ let filter = /* @__PURE__ */ __name((format) => format.hasAudio, "filter");
1501
+ if (isLive)
1502
+ filter = /* @__PURE__ */ __name((format) => format.hasAudio && format.isHLS, "filter");
1503
+ formats = formats.filter(filter).sort((a, b) => Number(b.audioBitrate) - Number(a.audioBitrate) || Number(a.bitrate) - Number(b.bitrate));
1504
+ return formats.find((format) => !format.hasVideo) || formats.sort((a, b) => Number(a.bitrate) - Number(b.bitrate))[0];
1505
+ }, "chooseBestVideoFormat");
1506
+ var DisTubeStream = class {
1507
+ constructor(url, options) {
1508
+ __publicField(this, "type");
1509
+ __publicField(this, "stream");
1510
+ __publicField(this, "url");
1511
+ this.url = url;
1512
+ this.type = !options.type ? DiscordVoiceStreamType.OggOpus : DiscordVoiceStreamType.Raw;
1513
+ const args = [
1514
+ "-reconnect",
1515
+ "1",
1516
+ "-reconnect_streamed",
1517
+ "1",
1518
+ "-reconnect_delay_max",
1519
+ "5",
1520
+ "-i",
1521
+ url,
1522
+ "-analyzeduration",
1523
+ "0",
1524
+ "-loglevel",
1525
+ "0",
1526
+ "-ar",
1527
+ "48000",
1528
+ "-ac",
1529
+ "2",
1530
+ "-f"
1531
+ ];
1532
+ if (!options.type) {
1533
+ args.push("opus", "-acodec", "libopus");
1534
+ } else {
1535
+ args.push("s16le");
1536
+ }
1537
+ if (typeof options.seek === "number" && options.seek > 0) {
1538
+ args.unshift("-ss", options.seek.toString());
1539
+ }
1540
+ if (Array.isArray(options.ffmpegArgs)) {
1541
+ args.push(...options.ffmpegArgs);
1542
+ }
1543
+ this.stream = new FFmpeg({ args, shell: false });
1544
+ }
1545
+ static YouTube(formats, options = {}) {
1546
+ if (!formats || !formats.length)
1547
+ throw new DisTubeError("UNAVAILABLE_VIDEO");
1548
+ if (!options || typeof options !== "object" || Array.isArray(options)) {
1549
+ throw new DisTubeError("INVALID_TYPE", "object", options, "options");
1550
+ }
1551
+ const bestFormat = chooseBestVideoFormat(formats, options.isLive);
1552
+ if (!bestFormat)
1553
+ throw new DisTubeError("UNPLAYABLE_FORMATS");
1554
+ return new DisTubeStream(bestFormat.url, options);
1555
+ }
1556
+ static DirectLink(url, options = {}) {
1557
+ if (!options || typeof options !== "object" || Array.isArray(options)) {
1558
+ throw new DisTubeError("INVALID_TYPE", "object", options, "options");
1559
+ }
1560
+ if (typeof url !== "string" || !isURL(url)) {
1561
+ throw new DisTubeError("INVALID_TYPE", "an URL", url);
1562
+ }
1563
+ return new DisTubeStream(url, options);
1564
+ }
1565
+ };
1566
+ __name(DisTubeStream, "DisTubeStream");
1567
+
1533
1568
  // src/struct/Queue.ts
1534
1569
  var _filters;
1535
1570
  var Queue = class extends DisTubeBase {
@@ -1572,7 +1607,7 @@ var Queue = class extends DisTubeBase {
1572
1607
  this._listeners = void 0;
1573
1608
  }
1574
1609
  get clientMember() {
1575
- return getClientMember(this.voice.channel.guild);
1610
+ return this.voice.channel.guild.members.me ?? void 0;
1576
1611
  }
1577
1612
  get filters() {
1578
1613
  return __privateGet(this, _filters);
@@ -1916,7 +1951,7 @@ function isVoiceChannelEmpty(voiceState) {
1916
1951
  const clientId = voiceState.client.user?.id;
1917
1952
  if (!guild || !clientId)
1918
1953
  return false;
1919
- const voiceChannel = guild.members.resolve(clientId)?.voice?.channel;
1954
+ const voiceChannel = guild.members.me?.voice?.channel;
1920
1955
  if (!voiceChannel)
1921
1956
  return false;
1922
1957
  const members = voiceChannel.members.filter((m) => !m.user.bot);
@@ -1936,7 +1971,7 @@ function isMemberInstance(member) {
1936
1971
  }
1937
1972
  __name(isMemberInstance, "isMemberInstance");
1938
1973
  function isTextChannelInstance(channel) {
1939
- return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) && typeof channel.name === "string" && Constants.TextBasedChannelTypes.includes(channel.type) && typeof channel.messages?.cache === "object";
1974
+ return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) && typeof channel.name === "string" && Constants.TextBasedChannelTypes.includes(channel.type) && typeof channel.nsfw === "boolean" && typeof channel.messages?.cache === "object" && typeof channel.send === "function";
1940
1975
  }
1941
1976
  __name(isTextChannelInstance, "isTextChannelInstance");
1942
1977
  function isMessageInstance(message) {
@@ -1982,34 +2017,6 @@ function checkInvalidKey(target, source, sourceName) {
1982
2017
  throw new DisTubeError("INVALID_KEY", sourceName, invalidKey);
1983
2018
  }
1984
2019
  __name(checkInvalidKey, "checkInvalidKey");
1985
- async function waitEvent(target, status, maxTime) {
1986
- let cleanup = /* @__PURE__ */ __name(() => {
1987
- }, "cleanup");
1988
- try {
1989
- await new Promise((resolve, reject) => {
1990
- const timeout = setTimeout(() => reject(new Error(`Didn't trigger ${status} within ${maxTime}ms`)), maxTime);
1991
- target.once(status, resolve);
1992
- target.once("error", reject);
1993
- cleanup = /* @__PURE__ */ __name(() => {
1994
- clearTimeout(timeout);
1995
- target.off(status, resolve);
1996
- target.off("error", reject);
1997
- }, "cleanup");
1998
- if (target?.state?.status === status)
1999
- resolve(0);
2000
- });
2001
- return target;
2002
- } finally {
2003
- cleanup();
2004
- }
2005
- }
2006
- __name(waitEvent, "waitEvent");
2007
- async function entersState(target, status, maxTime) {
2008
- if (target.state.status === status)
2009
- return target;
2010
- return waitEvent(target, status, maxTime);
2011
- }
2012
- __name(entersState, "entersState");
2013
2020
  function isObject(obj) {
2014
2021
  return typeof obj === "object" && obj !== null && !Array.isArray(obj);
2015
2022
  }
@@ -2018,16 +2025,6 @@ function isRecord(obj) {
2018
2025
  return isObject(obj);
2019
2026
  }
2020
2027
  __name(isRecord, "isRecord");
2021
- function getClientMember(guild) {
2022
- const clientUser = guild.client.user;
2023
- if (!clientUser)
2024
- return void 0;
2025
- const clientMember = guild.members.resolve(clientUser);
2026
- if (!clientMember)
2027
- return void 0;
2028
- return clientMember;
2029
- }
2030
- __name(getClientMember, "getClientMember");
2031
2028
 
2032
2029
  // src/plugin/http.ts
2033
2030
  import http from "http";
@@ -2119,7 +2116,7 @@ var DisTube = class extends TypedEmitter2 {
2119
2116
  if (!isObject(options))
2120
2117
  throw new DisTubeError("INVALID_TYPE", "object", options, "options");
2121
2118
  const { textChannel, member, skip, message, metadata } = {
2122
- member: getClientMember(voiceChannel.guild),
2119
+ member: voiceChannel.guild.members.me ?? void 0,
2123
2120
  textChannel: options?.message?.channel,
2124
2121
  skip: false,
2125
2122
  ...options
@@ -2167,12 +2164,12 @@ var DisTube = class extends TypedEmitter2 {
2167
2164
  if (!(e instanceof DisTubeError)) {
2168
2165
  try {
2169
2166
  e.name = "PlayError";
2170
- e.message = `${song?.url || song}
2167
+ e.message = `${typeof song === "string" ? song : song.url}
2171
2168
  ${e.message}`;
2172
2169
  } catch {
2173
2170
  }
2174
2171
  }
2175
- this.emitError(e, textChannel);
2172
+ throw e;
2176
2173
  } finally {
2177
2174
  if (queuing)
2178
2175
  queue?._taskQueue.resolve();
@@ -2184,7 +2181,7 @@ ${e.message}`;
2184
2181
  throw new DisTubeError("INVALID_TYPE", "Array", songs, "songs");
2185
2182
  if (!songs.length)
2186
2183
  throw new DisTubeError("EMPTY_ARRAY", "songs");
2187
- const filteredSongs = songs.filter((song) => song instanceof Song || song instanceof SearchResult && song.type === "video" || isURL(song));
2184
+ const filteredSongs = songs.filter((song) => song instanceof Song || isURL(song) || typeof song !== "string" && song.type === "video" /* VIDEO */);
2188
2185
  if (!filteredSongs.length)
2189
2186
  throw new DisTubeError("NO_VALID_SONG");
2190
2187
  if (member && !isMemberInstance(member)) {
@@ -2206,7 +2203,7 @@ ${e.message}`;
2206
2203
  return new Playlist(resolvedSongs, { member, properties, metadata });
2207
2204
  }
2208
2205
  async search(string, options = {}) {
2209
- const opts = { type: "video", limit: 10, safeSearch: false, ...options };
2206
+ const opts = { type: "video" /* VIDEO */, limit: 10, safeSearch: false, ...options };
2210
2207
  if (typeof opts.type !== "string" || !["video", "playlist"].includes(opts.type)) {
2211
2208
  throw new DisTubeError("INVALID_TYPE", ["video", "playlist"], opts.type, "options.type");
2212
2209
  }
@@ -2219,7 +2216,11 @@ ${e.message}`;
2219
2216
  }
2220
2217
  try {
2221
2218
  const search = await ytsr(string, opts);
2222
- const results = search.items.map((i) => new SearchResult(i));
2219
+ const results = search.items.map((i) => {
2220
+ if (i.type === "video")
2221
+ return new SearchResultVideo(i);
2222
+ return new SearchResultPlaylist(i);
2223
+ });
2223
2224
  if (results.length === 0)
2224
2225
  throw new DisTubeError("NO_RESULT");
2225
2226
  return results;
@@ -2339,8 +2340,9 @@ export {
2339
2340
  Queue,
2340
2341
  QueueManager,
2341
2342
  RepeatMode,
2342
- SearchResult,
2343
+ SearchResultPlaylist,
2343
2344
  SearchResultType,
2345
+ SearchResultVideo,
2344
2346
  Song,
2345
2347
  StreamType,
2346
2348
  TaskQueue,
@@ -2350,9 +2352,7 @@ export {
2350
2352
  DisTube as default,
2351
2353
  defaultFilters,
2352
2354
  defaultOptions,
2353
- entersState,
2354
2355
  formatDuration,
2355
- getClientMember,
2356
2356
  getResponseHeaders,
2357
2357
  isClientInstance,
2358
2358
  isGuildInstance,