distube 4.0.0-dev.5 → 4.0.1

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.1",
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,46 +110,47 @@ 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.8",
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
- tslib: "^2.4.0"
116
+ tslib: "^2.4.0",
117
+ undici: "^5.8.0"
117
118
  },
118
119
  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",
126
- "@discordjs/voice": "dev",
120
+ "@babel/core": "^7.18.9",
121
+ "@babel/plugin-proposal-class-properties": "^7.18.6",
122
+ "@babel/plugin-proposal-object-rest-spread": "^7.18.9",
123
+ "@babel/preset-env": "^7.18.9",
124
+ "@babel/preset-typescript": "^7.18.6",
125
+ "@commitlint/cli": "^17.0.3",
126
+ "@commitlint/config-conventional": "^17.0.3",
127
+ "@discordjs/voice": "^0.11.0",
127
128
  "@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",
133
- "discord.js": "dev",
134
- eslint: "^8.15.0",
129
+ "@types/jest": "^28.1.6",
130
+ "@types/node": "^18.0.6",
131
+ "@typescript-eslint/eslint-plugin": "^5.30.7",
132
+ "@typescript-eslint/parser": "^5.30.7",
133
+ "babel-jest": "^28.1.3",
134
+ "discord.js": "^14.0.2",
135
+ eslint: "^8.20.0",
135
136
  "eslint-config-distube": "^1.6.4",
136
137
  "eslint-config-prettier": "^8.5.0",
137
138
  "eslint-plugin-deprecation": "^1.3.2",
138
- "eslint-plugin-jsdoc": "^39.3.0",
139
+ "eslint-plugin-jsdoc": "^39.3.3",
139
140
  husky: "^8.0.1",
140
- jest: "^28.1.0",
141
+ jest: "^28.1.3",
141
142
  "jsdoc-babel": "^0.5.0",
142
143
  "nano-staged": "^0.8.0",
143
- "npm-check-updates": "^13.0.1",
144
+ "npm-check-updates": "^15.3.4",
144
145
  pinst: "^3.0.0",
145
- prettier: "^2.6.2",
146
- tsup: "^5.12.8",
147
- typescript: "^4.6.4"
146
+ prettier: "^2.7.1",
147
+ tsup: "^6.1.3",
148
+ typescript: "^4.7.4"
148
149
  },
149
150
  peerDependencies: {
150
151
  "@discordjs/opus": "*",
151
152
  "@discordjs/voice": "*",
152
- "discord.js": "14||^14.0.0-dev"
153
+ "discord.js": "14"
153
154
  },
154
155
  peerDependenciesMeta: {
155
156
  "@discordjs/opus": {
@@ -168,8 +169,7 @@ var require_package = __commonJS({
168
169
  engines: {
169
170
  node: ">=16.9.0"
170
171
  },
171
- packageManager: "yarn@3.2.0",
172
- stableVersion: "4.0.0-dev"
172
+ packageManager: "yarn@3.2.0"
173
173
  };
174
174
  }
175
175
  });
@@ -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,23 +342,31 @@ 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
+ this.member = member || void 0;
359
+ } else {
360
+ this.source = (playlist.source || "youtube").toLowerCase();
361
+ if (!Array.isArray(playlist.songs) || !playlist.songs.length)
362
+ throw new DisTubeError("EMPTY_PLAYLIST");
363
+ this.songs = playlist.songs;
364
+ 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`);
365
+ this.url = playlist.url || playlist.webpage_url;
366
+ this.thumbnail = playlist.thumbnail || this.songs[0].thumbnail;
367
+ this.member = member || playlist.member || void 0;
356
368
  }
357
369
  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
370
  if (properties)
363
371
  for (const [key, value] of Object.entries(properties))
364
372
  this[key] = value;
@@ -395,41 +403,64 @@ _metadata = new WeakMap();
395
403
  _member = new WeakMap();
396
404
 
397
405
  // src/struct/SearchResult.ts
398
- var SearchResult = class {
406
+ var ISearchResult = class {
399
407
  constructor(info) {
400
408
  __publicField(this, "source");
401
- __publicField(this, "type");
402
409
  __publicField(this, "id");
403
410
  __publicField(this, "name");
404
411
  __publicField(this, "url");
405
- __publicField(this, "views");
406
- __publicField(this, "isLive");
407
- __publicField(this, "duration");
408
- __publicField(this, "formattedDuration");
409
- __publicField(this, "thumbnail");
410
412
  __publicField(this, "uploader");
411
413
  this.source = "youtube";
412
- this.type = info.type === "video" ? "video" /* VIDEO */ : "playlist" /* PLAYLIST */;
413
414
  this.id = info.id;
414
415
  this.name = info.name;
415
416
  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
417
  this.uploader = {
427
- name: (info.author || info.owner)?.name,
428
- url: (info.author || info.owner)?.url
418
+ name: void 0,
419
+ url: void 0
420
+ };
421
+ }
422
+ };
423
+ __name(ISearchResult, "ISearchResult");
424
+ var SearchResultVideo = class extends ISearchResult {
425
+ constructor(info) {
426
+ super(info);
427
+ __publicField(this, "type");
428
+ __publicField(this, "views");
429
+ __publicField(this, "isLive");
430
+ __publicField(this, "duration");
431
+ __publicField(this, "formattedDuration");
432
+ __publicField(this, "thumbnail");
433
+ if (info.type !== "video")
434
+ throw new DisTubeError("INVALID_TYPE", "video", info.type, "type");
435
+ this.type = "video" /* VIDEO */;
436
+ this.views = info.views;
437
+ this.isLive = info.isLive;
438
+ this.duration = this.isLive ? 0 : toSecond(info.duration);
439
+ this.formattedDuration = this.isLive ? "Live" : formatDuration(this.duration);
440
+ this.thumbnail = info.thumbnail;
441
+ this.uploader = {
442
+ name: info.author?.name,
443
+ url: info.author?.url
444
+ };
445
+ }
446
+ };
447
+ __name(SearchResultVideo, "SearchResultVideo");
448
+ var SearchResultPlaylist = class extends ISearchResult {
449
+ constructor(info) {
450
+ super(info);
451
+ __publicField(this, "type");
452
+ __publicField(this, "length");
453
+ if (info.type !== "playlist")
454
+ throw new DisTubeError("INVALID_TYPE", "playlist", info.type, "type");
455
+ this.type = "playlist" /* PLAYLIST */;
456
+ this.length = info.length;
457
+ this.uploader = {
458
+ name: info.owner?.name,
459
+ url: info.owner?.url
429
460
  };
430
461
  }
431
462
  };
432
- __name(SearchResult, "SearchResult");
463
+ __name(SearchResultPlaylist, "SearchResultPlaylist");
433
464
 
434
465
  // src/struct/Song.ts
435
466
  var _metadata2, _member2, _playlist;
@@ -569,114 +600,6 @@ _metadata2 = new WeakMap();
569
600
  _member2 = new WeakMap();
570
601
  _playlist = new WeakMap();
571
602
 
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
603
  // src/core/DisTubeBase.ts
681
604
  var DisTubeBase = class {
682
605
  constructor(distube) {
@@ -707,77 +630,202 @@ var DisTubeBase = class {
707
630
  };
708
631
  __name(DisTubeBase, "DisTubeBase");
709
632
 
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 });
633
+ // src/core/DisTubeVoice.ts
634
+ import { TypedEmitter } from "tiny-typed-emitter";
635
+ import {
636
+ AudioPlayerStatus,
637
+ VoiceConnectionDisconnectReason,
638
+ VoiceConnectionStatus,
639
+ createAudioPlayer,
640
+ createAudioResource,
641
+ entersState,
642
+ joinVoiceChannel
643
+ } from "@discordjs/voice";
644
+ var _channel, _volume, _br, br_fn, _join, join_fn;
645
+ var DisTubeVoice = class extends TypedEmitter {
646
+ constructor(voiceManager, channel) {
647
+ super();
648
+ __privateAdd(this, _br);
649
+ __privateAdd(this, _join);
650
+ __publicField(this, "id");
651
+ __publicField(this, "voices");
652
+ __publicField(this, "audioPlayer");
653
+ __publicField(this, "connection");
654
+ __publicField(this, "audioResource");
655
+ __publicField(this, "emittedError");
656
+ __publicField(this, "isDisconnected", false);
657
+ __privateAdd(this, _channel, void 0);
658
+ __privateAdd(this, _volume, 100);
659
+ this.voices = voiceManager;
660
+ this.id = channel.guildId;
661
+ this.channel = channel;
662
+ this.voices.add(this.id, this);
663
+ this.audioPlayer = createAudioPlayer().on(AudioPlayerStatus.Idle, (oldState) => {
664
+ if (oldState.status !== AudioPlayerStatus.Idle) {
665
+ delete this.audioResource;
666
+ this.emit("finish");
667
+ }
668
+ }).on(AudioPlayerStatus.Playing, () => __privateMethod(this, _br, br_fn).call(this)).on("error", (error) => {
669
+ if (this.emittedError)
670
+ return;
671
+ this.emittedError = true;
672
+ this.emit("error", error);
673
+ });
674
+ this.connection.on(VoiceConnectionStatus.Disconnected, (_, newState) => {
675
+ if (newState.reason === VoiceConnectionDisconnectReason.Manual) {
676
+ this.leave();
677
+ } else if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {
678
+ entersState(this.connection, VoiceConnectionStatus.Connecting, 5e3).catch(() => {
679
+ if (![VoiceConnectionStatus.Ready, VoiceConnectionStatus.Connecting].includes(this.connection.state.status)) {
680
+ this.leave();
681
+ }
682
+ });
683
+ } else if (this.connection.rejoinAttempts < 5) {
684
+ setTimeout(() => {
685
+ this.connection.rejoin();
686
+ }, (this.connection.rejoinAttempts + 1) * 5e3).unref();
687
+ } else if (this.connection.state.status !== VoiceConnectionStatus.Destroyed) {
688
+ this.leave(new DisTubeError("VOICE_RECONNECT_FAILED"));
689
+ }
690
+ }).on(VoiceConnectionStatus.Destroyed, () => {
691
+ this.leave();
692
+ }).on("error", () => void 0);
693
+ this.connection.subscribe(this.audioPlayer);
758
694
  }
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);
695
+ get channel() {
696
+ return __privateGet(this, _channel);
769
697
  }
770
- static DirectLink(url, options = {}) {
771
- if (!options || typeof options !== "object" || Array.isArray(options)) {
772
- throw new DisTubeError("INVALID_TYPE", "object", options, "options");
698
+ set channel(channel) {
699
+ if (!isSupportedVoiceChannel(channel)) {
700
+ throw new DisTubeError("INVALID_TYPE", "BaseGuildVoiceChannel", channel, "DisTubeVoice#channel");
773
701
  }
774
- if (typeof url !== "string" || !isURL(url)) {
775
- throw new DisTubeError("INVALID_TYPE", "an URL", url);
702
+ if (channel.guildId !== this.id)
703
+ throw new DisTubeError("VOICE_DIFFERENT_GUILD");
704
+ if (channel.client.user?.id !== this.voices.client.user?.id)
705
+ throw new DisTubeError("VOICE_DIFFERENT_CLIENT");
706
+ if (channel.id === __privateGet(this, _channel)?.id)
707
+ return;
708
+ if (!channel.joinable) {
709
+ if (channel.full)
710
+ throw new DisTubeError("VOICE_FULL");
711
+ else
712
+ throw new DisTubeError("VOICE_MISSING_PERMS");
776
713
  }
777
- return new DisTubeStream(url, options);
714
+ this.connection = __privateMethod(this, _join, join_fn).call(this, channel);
715
+ __privateSet(this, _channel, channel);
716
+ __privateMethod(this, _br, br_fn).call(this);
717
+ }
718
+ async join(channel) {
719
+ const TIMEOUT = 3e4;
720
+ if (channel)
721
+ this.channel = channel;
722
+ try {
723
+ await entersState(this.connection, VoiceConnectionStatus.Ready, TIMEOUT);
724
+ } catch {
725
+ if (this.connection.state.status === VoiceConnectionStatus.Ready)
726
+ return this;
727
+ if (this.connection.state.status !== VoiceConnectionStatus.Destroyed)
728
+ this.connection.destroy();
729
+ this.voices.remove(this.id);
730
+ throw new DisTubeError("VOICE_CONNECT_FAILED", TIMEOUT / 1e3);
731
+ }
732
+ return this;
733
+ }
734
+ leave(error) {
735
+ this.stop(true);
736
+ if (!this.isDisconnected) {
737
+ this.emit("disconnect", error);
738
+ this.isDisconnected = true;
739
+ }
740
+ if (this.connection.state.status !== VoiceConnectionStatus.Destroyed)
741
+ this.connection.destroy();
742
+ this.voices.remove(this.id);
743
+ }
744
+ stop(force = false) {
745
+ this.audioPlayer.stop(force);
746
+ }
747
+ play(stream) {
748
+ this.emittedError = false;
749
+ stream.stream.on("error", (error) => {
750
+ if (this.emittedError || error.code === "ERR_STREAM_PREMATURE_CLOSE")
751
+ return;
752
+ this.emittedError = true;
753
+ this.emit("error", error);
754
+ });
755
+ this.audioResource = createAudioResource(stream.stream, {
756
+ inputType: stream.type,
757
+ inlineVolume: true
758
+ });
759
+ this.volume = __privateGet(this, _volume);
760
+ this.audioPlayer.play(this.audioResource);
761
+ }
762
+ set volume(volume) {
763
+ if (typeof volume !== "number" || isNaN(volume)) {
764
+ throw new DisTubeError("INVALID_TYPE", "number", volume, "volume");
765
+ }
766
+ if (volume < 0) {
767
+ throw new DisTubeError("NUMBER_COMPARE", "Volume", "bigger or equal to", 0);
768
+ }
769
+ __privateSet(this, _volume, volume);
770
+ this.audioResource?.volume?.setVolume(Math.pow(__privateGet(this, _volume) / 100, 0.5 / Math.log10(2)));
771
+ }
772
+ get volume() {
773
+ return __privateGet(this, _volume);
774
+ }
775
+ get playbackDuration() {
776
+ return (this.audioResource?.playbackDuration ?? 0) / 1e3;
777
+ }
778
+ pause() {
779
+ this.audioPlayer.pause();
780
+ }
781
+ unpause() {
782
+ this.audioPlayer.unpause();
783
+ }
784
+ get selfDeaf() {
785
+ return this.connection.joinConfig.selfDeaf;
786
+ }
787
+ get selfMute() {
788
+ return this.connection.joinConfig.selfMute;
789
+ }
790
+ setSelfDeaf(selfDeaf) {
791
+ if (typeof selfDeaf !== "boolean") {
792
+ throw new DisTubeError("INVALID_TYPE", "boolean", selfDeaf, "selfDeaf");
793
+ }
794
+ return this.connection.rejoin({
795
+ ...this.connection.joinConfig,
796
+ selfDeaf
797
+ });
798
+ }
799
+ setSelfMute(selfMute) {
800
+ if (typeof selfMute !== "boolean") {
801
+ throw new DisTubeError("INVALID_TYPE", "boolean", selfMute, "selfMute");
802
+ }
803
+ return this.connection.rejoin({
804
+ ...this.connection.joinConfig,
805
+ selfMute
806
+ });
807
+ }
808
+ get voiceState() {
809
+ return this.channel?.guild?.members?.me?.voice;
778
810
  }
779
811
  };
780
- __name(DisTubeStream, "DisTubeStream");
812
+ __name(DisTubeVoice, "DisTubeVoice");
813
+ _channel = new WeakMap();
814
+ _volume = new WeakMap();
815
+ _br = new WeakSet();
816
+ br_fn = /* @__PURE__ */ __name(function() {
817
+ if (this.audioResource?.encoder?.encoder)
818
+ this.audioResource.encoder.setBitrate(this.channel.bitrate);
819
+ }, "#br");
820
+ _join = new WeakSet();
821
+ join_fn = /* @__PURE__ */ __name(function(channel) {
822
+ return joinVoiceChannel({
823
+ channelId: channel.id,
824
+ guildId: this.id,
825
+ adapterCreator: channel.guild.voiceAdapterCreator,
826
+ group: channel.client.user?.id
827
+ });
828
+ }, "#join");
781
829
 
782
830
  // src/core/manager/BaseManager.ts
783
831
  import { Collection } from "discord.js";
@@ -813,6 +861,123 @@ var GuildIdManager = class extends BaseManager {
813
861
  };
814
862
  __name(GuildIdManager, "GuildIdManager");
815
863
 
864
+ // src/core/manager/DisTubeVoiceManager.ts
865
+ import { VoiceConnectionStatus as VoiceConnectionStatus2, getVoiceConnection } from "@discordjs/voice";
866
+ var DisTubeVoiceManager = class extends GuildIdManager {
867
+ create(channel) {
868
+ const existing = this.get(channel.guildId);
869
+ if (existing) {
870
+ existing.channel = channel;
871
+ return existing;
872
+ }
873
+ return new DisTubeVoice(this, channel);
874
+ }
875
+ join(channel) {
876
+ const existing = this.get(channel.guildId);
877
+ if (existing)
878
+ return existing.join(channel);
879
+ return this.create(channel).join();
880
+ }
881
+ leave(guild) {
882
+ const voice = this.get(guild);
883
+ if (voice) {
884
+ voice.leave();
885
+ } else {
886
+ const connection = getVoiceConnection(resolveGuildId(guild), this.client.user?.id) ?? getVoiceConnection(resolveGuildId(guild));
887
+ if (connection && connection.state.status !== VoiceConnectionStatus2.Destroyed) {
888
+ connection.destroy();
889
+ }
890
+ }
891
+ }
892
+ };
893
+ __name(DisTubeVoiceManager, "DisTubeVoiceManager");
894
+
895
+ // src/core/manager/FilterManager.ts
896
+ var _validate, validate_fn, _resolveName, resolveName_fn, _resolveValue, resolveValue_fn, _apply, apply_fn;
897
+ var FilterManager = class extends BaseManager {
898
+ constructor(queue) {
899
+ super(queue.distube);
900
+ __privateAdd(this, _validate);
901
+ __privateAdd(this, _resolveName);
902
+ __privateAdd(this, _resolveValue);
903
+ __privateAdd(this, _apply);
904
+ __publicField(this, "queue");
905
+ this.queue = queue;
906
+ }
907
+ add(filterOrFilters, override = false) {
908
+ if (Array.isArray(filterOrFilters)) {
909
+ const resolvedFilters = filterOrFilters.map((f) => __privateMethod(this, _validate, validate_fn).call(this, f));
910
+ const newFilters = resolvedFilters.reduceRight((unique, o) => {
911
+ if (!unique.some((obj) => obj === o && obj.name === o) && !unique.some((obj) => obj !== o.name && obj.name !== o.name)) {
912
+ if (!this.has(o))
913
+ unique.push(o);
914
+ if (this.has(o) && override) {
915
+ this.remove(o);
916
+ unique.push(o);
917
+ }
918
+ }
919
+ return unique;
920
+ }, []).reverse();
921
+ return this.set([...this.collection.values(), ...newFilters]);
922
+ }
923
+ return this.set([...this.collection.values(), filterOrFilters]);
924
+ }
925
+ clear() {
926
+ return this.set([]);
927
+ }
928
+ set(filters) {
929
+ this.collection.clear();
930
+ for (const filter of filters) {
931
+ const resolved = __privateMethod(this, _validate, validate_fn).call(this, filter);
932
+ this.collection.set(__privateMethod(this, _resolveName, resolveName_fn).call(this, resolved), resolved);
933
+ }
934
+ __privateMethod(this, _apply, apply_fn).call(this);
935
+ return this;
936
+ }
937
+ remove(filterOrFilters) {
938
+ const remove = /* @__PURE__ */ __name((f) => this.collection.delete(__privateMethod(this, _resolveName, resolveName_fn).call(this, __privateMethod(this, _validate, validate_fn).call(this, f))), "remove");
939
+ if (Array.isArray(filterOrFilters))
940
+ filterOrFilters.map(remove);
941
+ else
942
+ remove(filterOrFilters);
943
+ __privateMethod(this, _apply, apply_fn).call(this);
944
+ return this;
945
+ }
946
+ has(filter) {
947
+ return this.collection.has(__privateMethod(this, _resolveName, resolveName_fn).call(this, filter));
948
+ }
949
+ get names() {
950
+ return this.collection.map((f) => __privateMethod(this, _resolveName, resolveName_fn).call(this, f));
951
+ }
952
+ get values() {
953
+ return this.collection.map((f) => __privateMethod(this, _resolveValue, resolveValue_fn).call(this, f));
954
+ }
955
+ toString() {
956
+ return this.names.toString();
957
+ }
958
+ };
959
+ __name(FilterManager, "FilterManager");
960
+ _validate = new WeakSet();
961
+ validate_fn = /* @__PURE__ */ __name(function(filter) {
962
+ if (typeof filter === "string" && Object.prototype.hasOwnProperty.call(this.distube.filters, filter) || typeof filter === "object" && typeof filter.name === "string" && typeof filter.value === "string") {
963
+ return filter;
964
+ }
965
+ throw new DisTubeError("INVALID_TYPE", "FilterResolvable", filter, "filter");
966
+ }, "#validate");
967
+ _resolveName = new WeakSet();
968
+ resolveName_fn = /* @__PURE__ */ __name(function(filter) {
969
+ return typeof filter === "string" ? filter : filter.name;
970
+ }, "#resolveName");
971
+ _resolveValue = new WeakSet();
972
+ resolveValue_fn = /* @__PURE__ */ __name(function(filter) {
973
+ return typeof filter === "string" ? this.distube.filters[filter] : filter.value;
974
+ }, "#resolveValue");
975
+ _apply = new WeakSet();
976
+ apply_fn = /* @__PURE__ */ __name(function() {
977
+ this.queue.beginTime = this.queue.currentTime;
978
+ this.queues.playSong(this.queue);
979
+ }, "#apply");
980
+
816
981
  // src/core/manager/QueueManager.ts
817
982
  var _voiceEventHandler, voiceEventHandler_fn, _handleSongFinish, handleSongFinish_fn, _handlePlayingError, handlePlayingError_fn, _emitPlaySong, emitPlaySong_fn;
818
983
  var QueueManager = class extends GuildIdManager {
@@ -943,360 +1108,49 @@ handleSongFinish_fn = /* @__PURE__ */ __name(async function(queue) {
943
1108
  delete prev.formats;
944
1109
  delete prev.streamURL;
945
1110
  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;
1111
+ queue.previousSongs.push(prev);
1112
+ else
1113
+ queue.previousSongs.push({ id: prev.id });
1274
1114
  }
1275
- return new DisTubeVoice(this, channel);
1115
+ queue._next = queue._prev = false;
1116
+ queue.beginTime = 0;
1117
+ const err = await this.playSong(queue);
1118
+ if (!err && emitPlaySong)
1119
+ this.emit("playSong", queue, queue.songs[0]);
1120
+ } finally {
1121
+ queue._taskQueue.resolve();
1276
1122
  }
1277
- join(channel) {
1278
- const existing = this.get(channel.guildId);
1279
- if (existing)
1280
- return existing.join(channel);
1281
- return this.create(channel).join();
1123
+ }, "#handleSongFinish");
1124
+ _handlePlayingError = new WeakSet();
1125
+ handlePlayingError_fn = /* @__PURE__ */ __name(function(queue, error) {
1126
+ const song = queue.songs.shift();
1127
+ try {
1128
+ error.name = "PlayingError";
1129
+ error.message = `${error.message}
1130
+ Id: ${song.id}
1131
+ Name: ${song.name}`;
1132
+ } catch {
1282
1133
  }
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
- }
1134
+ this.emitError(error, queue.textChannel);
1135
+ if (queue.songs.length > 0) {
1136
+ queue._next = queue._prev = false;
1137
+ queue.beginTime = 0;
1138
+ this.playSong(queue).then((e) => {
1139
+ if (!e)
1140
+ this.emit("playSong", queue, queue.songs[0]);
1141
+ });
1142
+ } else {
1143
+ queue.stop();
1293
1144
  }
1294
- };
1295
- __name(DisTubeVoiceManager, "DisTubeVoiceManager");
1145
+ }, "#handlePlayingError");
1146
+ _emitPlaySong = new WeakSet();
1147
+ emitPlaySong_fn = /* @__PURE__ */ __name(function(queue) {
1148
+ return !this.options.emitNewSongOnly || queue.repeatMode === 1 /* SONG */ && queue._next || queue.repeatMode !== 1 /* SONG */ && queue.songs[0]?.id !== queue.songs[1]?.id;
1149
+ }, "#emitPlaySong");
1296
1150
 
1297
1151
  // src/core/DisTubeHandler.ts
1298
- import ytdl from "@distube/ytdl-core";
1299
1152
  import ytpl from "@distube/ytpl";
1153
+ import ytdl from "@distube/ytdl-core";
1300
1154
  var DisTubeHandler = class extends DisTubeBase {
1301
1155
  constructor(distube) {
1302
1156
  super(distube);
@@ -1360,13 +1214,15 @@ var DisTubeHandler = class extends DisTubeBase {
1360
1214
  song.member = options.member;
1361
1215
  return song;
1362
1216
  }
1363
- if (song instanceof SearchResult) {
1364
- if (song.type === "video" /* VIDEO */)
1365
- return new Song(song, options);
1217
+ if (song instanceof SearchResultVideo)
1218
+ return new Song(song, options);
1219
+ if (song instanceof SearchResultPlaylist)
1366
1220
  return this.resolvePlaylist(song.url, options);
1367
- }
1368
- if (isObject(song))
1221
+ if (isObject(song)) {
1222
+ if (!("url" in song) && !("id" in song))
1223
+ throw new DisTubeError("CANNOT_RESOLVE_SONG", song);
1369
1224
  return new Song(song, options);
1225
+ }
1370
1226
  if (ytpl.validateID(song))
1371
1227
  return this.resolvePlaylist(song, options);
1372
1228
  if (ytdl.validateURL(song))
@@ -1389,14 +1245,19 @@ var DisTubeHandler = class extends DisTubeBase {
1389
1245
  playlist.member = member;
1390
1246
  return playlist;
1391
1247
  }
1392
- let solvablePlaylist;
1393
1248
  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 });
1249
+ const info = await ytpl(playlist, { limit: Infinity });
1250
+ const songs = info.items.filter((v) => !v.thumbnail.includes("no_thumbnail")).map((v) => new Song(v, { member, metadata }));
1251
+ return new Playlist({
1252
+ source,
1253
+ songs,
1254
+ member,
1255
+ name: info.title,
1256
+ url: info.url,
1257
+ thumbnail: songs[0].thumbnail
1258
+ }, { metadata });
1259
+ }
1260
+ return new Playlist(playlist, { member, properties: { source }, metadata });
1400
1261
  }
1401
1262
  async searchSong(message, query) {
1402
1263
  if (!isMessageInstance(message))
@@ -1530,6 +1391,186 @@ var DisTubeHandler = class extends DisTubeBase {
1530
1391
  };
1531
1392
  __name(DisTubeHandler, "DisTubeHandler");
1532
1393
 
1394
+ // src/core/DisTubeOptions.ts
1395
+ var _validateOptions, validateOptions_fn;
1396
+ var Options = class {
1397
+ constructor(options) {
1398
+ __privateAdd(this, _validateOptions);
1399
+ __publicField(this, "plugins");
1400
+ __publicField(this, "emitNewSongOnly");
1401
+ __publicField(this, "leaveOnFinish");
1402
+ __publicField(this, "leaveOnStop");
1403
+ __publicField(this, "leaveOnEmpty");
1404
+ __publicField(this, "emptyCooldown");
1405
+ __publicField(this, "savePreviousSongs");
1406
+ __publicField(this, "searchSongs");
1407
+ __publicField(this, "searchCooldown");
1408
+ __publicField(this, "youtubeCookie");
1409
+ __publicField(this, "youtubeIdentityToken");
1410
+ __publicField(this, "customFilters");
1411
+ __publicField(this, "ytdlOptions");
1412
+ __publicField(this, "nsfw");
1413
+ __publicField(this, "emitAddSongWhenCreatingQueue");
1414
+ __publicField(this, "emitAddListWhenCreatingQueue");
1415
+ __publicField(this, "joinNewVoiceChannel");
1416
+ __publicField(this, "streamType");
1417
+ if (typeof options !== "object" || Array.isArray(options)) {
1418
+ throw new DisTubeError("INVALID_TYPE", "object", options, "DisTubeOptions");
1419
+ }
1420
+ const opts = { ...defaultOptions, ...options };
1421
+ this.plugins = opts.plugins;
1422
+ this.emitNewSongOnly = opts.emitNewSongOnly;
1423
+ this.leaveOnEmpty = opts.leaveOnEmpty;
1424
+ this.leaveOnFinish = opts.leaveOnFinish;
1425
+ this.leaveOnStop = opts.leaveOnStop;
1426
+ this.savePreviousSongs = opts.savePreviousSongs;
1427
+ this.searchSongs = opts.searchSongs;
1428
+ this.youtubeCookie = opts.youtubeCookie;
1429
+ this.youtubeIdentityToken = opts.youtubeIdentityToken;
1430
+ this.customFilters = opts.customFilters;
1431
+ this.ytdlOptions = opts.ytdlOptions;
1432
+ this.searchCooldown = opts.searchCooldown;
1433
+ this.emptyCooldown = opts.emptyCooldown;
1434
+ this.nsfw = opts.nsfw;
1435
+ this.emitAddSongWhenCreatingQueue = opts.emitAddSongWhenCreatingQueue;
1436
+ this.emitAddListWhenCreatingQueue = opts.emitAddListWhenCreatingQueue;
1437
+ this.joinNewVoiceChannel = opts.joinNewVoiceChannel;
1438
+ this.streamType = opts.streamType;
1439
+ checkInvalidKey(opts, this, "DisTubeOptions");
1440
+ __privateMethod(this, _validateOptions, validateOptions_fn).call(this);
1441
+ }
1442
+ };
1443
+ __name(Options, "Options");
1444
+ _validateOptions = new WeakSet();
1445
+ validateOptions_fn = /* @__PURE__ */ __name(function(options = this) {
1446
+ if (typeof options.emitNewSongOnly !== "boolean") {
1447
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.emitNewSongOnly, "DisTubeOptions.emitNewSongOnly");
1448
+ }
1449
+ if (typeof options.leaveOnEmpty !== "boolean") {
1450
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnEmpty, "DisTubeOptions.leaveOnEmpty");
1451
+ }
1452
+ if (typeof options.leaveOnFinish !== "boolean") {
1453
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnFinish, "DisTubeOptions.leaveOnFinish");
1454
+ }
1455
+ if (typeof options.leaveOnStop !== "boolean") {
1456
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnStop, "DisTubeOptions.leaveOnStop");
1457
+ }
1458
+ if (typeof options.savePreviousSongs !== "boolean") {
1459
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.savePreviousSongs, "DisTubeOptions.savePreviousSongs");
1460
+ }
1461
+ if (typeof options.joinNewVoiceChannel !== "boolean") {
1462
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.joinNewVoiceChannel, "DisTubeOptions.joinNewVoiceChannel");
1463
+ }
1464
+ if (typeof options.youtubeCookie !== "undefined" && typeof options.youtubeCookie !== "string") {
1465
+ throw new DisTubeError("INVALID_TYPE", "string", options.youtubeCookie, "DisTubeOptions.youtubeCookie");
1466
+ }
1467
+ if (typeof options.youtubeIdentityToken !== "undefined" && typeof options.youtubeIdentityToken !== "string") {
1468
+ throw new DisTubeError("INVALID_TYPE", "string", options.youtubeIdentityToken, "DisTubeOptions.youtubeIdentityToken");
1469
+ }
1470
+ if (typeof options.customFilters !== "undefined" && typeof options.customFilters !== "object" || Array.isArray(options.customFilters)) {
1471
+ throw new DisTubeError("INVALID_TYPE", "object", options.customFilters, "DisTubeOptions.customFilters");
1472
+ }
1473
+ if (typeof options.ytdlOptions !== "object" || Array.isArray(options.ytdlOptions)) {
1474
+ throw new DisTubeError("INVALID_TYPE", "object", options.ytdlOptions, "DisTubeOptions.ytdlOptions");
1475
+ }
1476
+ if (typeof options.searchCooldown !== "number" || isNaN(options.searchCooldown)) {
1477
+ throw new DisTubeError("INVALID_TYPE", "number", options.searchCooldown, "DisTubeOptions.searchCooldown");
1478
+ }
1479
+ if (typeof options.emptyCooldown !== "number" || isNaN(options.emptyCooldown)) {
1480
+ throw new DisTubeError("INVALID_TYPE", "number", options.emptyCooldown, "DisTubeOptions.emptyCooldown");
1481
+ }
1482
+ if (typeof options.searchSongs !== "number" || isNaN(options.searchSongs)) {
1483
+ throw new DisTubeError("INVALID_TYPE", "number", options.searchSongs, "DisTubeOptions.searchSongs");
1484
+ }
1485
+ if (!Array.isArray(options.plugins)) {
1486
+ throw new DisTubeError("INVALID_TYPE", "Array<Plugin>", options.plugins, "DisTubeOptions.plugins");
1487
+ }
1488
+ if (typeof options.nsfw !== "boolean") {
1489
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.nsfw, "DisTubeOptions.nsfw");
1490
+ }
1491
+ if (typeof options.emitAddSongWhenCreatingQueue !== "boolean") {
1492
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddSongWhenCreatingQueue, "DisTubeOptions.emitAddSongWhenCreatingQueue");
1493
+ }
1494
+ if (typeof options.emitAddListWhenCreatingQueue !== "boolean") {
1495
+ throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddListWhenCreatingQueue, "DisTubeOptions.emitAddListWhenCreatingQueue");
1496
+ }
1497
+ if (typeof options.streamType !== "number" || isNaN(options.streamType) || !StreamType[options.streamType]) {
1498
+ throw new DisTubeError("INVALID_TYPE", "StreamType", options.streamType, "DisTubeOptions.streamType");
1499
+ }
1500
+ }, "#validateOptions");
1501
+
1502
+ // src/core/DisTubeStream.ts
1503
+ import { FFmpeg } from "prism-media";
1504
+ import { StreamType as DiscordVoiceStreamType } from "@discordjs/voice";
1505
+ var chooseBestVideoFormat = /* @__PURE__ */ __name((formats, isLive = false) => {
1506
+ let filter = /* @__PURE__ */ __name((format) => format.hasAudio, "filter");
1507
+ if (isLive)
1508
+ filter = /* @__PURE__ */ __name((format) => format.hasAudio && format.isHLS, "filter");
1509
+ formats = formats.filter(filter).sort((a, b) => Number(b.audioBitrate) - Number(a.audioBitrate) || Number(a.bitrate) - Number(b.bitrate));
1510
+ return formats.find((format) => !format.hasVideo) || formats.sort((a, b) => Number(a.bitrate) - Number(b.bitrate))[0];
1511
+ }, "chooseBestVideoFormat");
1512
+ var DisTubeStream = class {
1513
+ constructor(url, options) {
1514
+ __publicField(this, "type");
1515
+ __publicField(this, "stream");
1516
+ __publicField(this, "url");
1517
+ this.url = url;
1518
+ this.type = !options.type ? DiscordVoiceStreamType.OggOpus : DiscordVoiceStreamType.Raw;
1519
+ const args = [
1520
+ "-reconnect",
1521
+ "1",
1522
+ "-reconnect_streamed",
1523
+ "1",
1524
+ "-reconnect_delay_max",
1525
+ "5",
1526
+ "-i",
1527
+ url,
1528
+ "-analyzeduration",
1529
+ "0",
1530
+ "-loglevel",
1531
+ "0",
1532
+ "-ar",
1533
+ "48000",
1534
+ "-ac",
1535
+ "2",
1536
+ "-f"
1537
+ ];
1538
+ if (!options.type) {
1539
+ args.push("opus", "-acodec", "libopus");
1540
+ } else {
1541
+ args.push("s16le");
1542
+ }
1543
+ if (typeof options.seek === "number" && options.seek > 0) {
1544
+ args.unshift("-ss", options.seek.toString());
1545
+ }
1546
+ if (Array.isArray(options.ffmpegArgs)) {
1547
+ args.push(...options.ffmpegArgs);
1548
+ }
1549
+ this.stream = new FFmpeg({ args, shell: false });
1550
+ }
1551
+ static YouTube(formats, options = {}) {
1552
+ if (!formats || !formats.length)
1553
+ throw new DisTubeError("UNAVAILABLE_VIDEO");
1554
+ if (!options || typeof options !== "object" || Array.isArray(options)) {
1555
+ throw new DisTubeError("INVALID_TYPE", "object", options, "options");
1556
+ }
1557
+ const bestFormat = chooseBestVideoFormat(formats, options.isLive);
1558
+ if (!bestFormat)
1559
+ throw new DisTubeError("UNPLAYABLE_FORMATS");
1560
+ return new DisTubeStream(bestFormat.url, options);
1561
+ }
1562
+ static DirectLink(url, options = {}) {
1563
+ if (!options || typeof options !== "object" || Array.isArray(options)) {
1564
+ throw new DisTubeError("INVALID_TYPE", "object", options, "options");
1565
+ }
1566
+ if (typeof url !== "string" || !isURL(url)) {
1567
+ throw new DisTubeError("INVALID_TYPE", "an URL", url);
1568
+ }
1569
+ return new DisTubeStream(url, options);
1570
+ }
1571
+ };
1572
+ __name(DisTubeStream, "DisTubeStream");
1573
+
1533
1574
  // src/struct/Queue.ts
1534
1575
  var _filters;
1535
1576
  var Queue = class extends DisTubeBase {
@@ -1572,7 +1613,7 @@ var Queue = class extends DisTubeBase {
1572
1613
  this._listeners = void 0;
1573
1614
  }
1574
1615
  get clientMember() {
1575
- return getClientMember(this.voice.channel.guild);
1616
+ return this.voice.channel.guild.members.me ?? void 0;
1576
1617
  }
1577
1618
  get filters() {
1578
1619
  return __privateGet(this, _filters);
@@ -1916,7 +1957,7 @@ function isVoiceChannelEmpty(voiceState) {
1916
1957
  const clientId = voiceState.client.user?.id;
1917
1958
  if (!guild || !clientId)
1918
1959
  return false;
1919
- const voiceChannel = guild.members.resolve(clientId)?.voice?.channel;
1960
+ const voiceChannel = guild.members.me?.voice?.channel;
1920
1961
  if (!voiceChannel)
1921
1962
  return false;
1922
1963
  const members = voiceChannel.members.filter((m) => !m.user.bot);
@@ -1936,7 +1977,7 @@ function isMemberInstance(member) {
1936
1977
  }
1937
1978
  __name(isMemberInstance, "isMemberInstance");
1938
1979
  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";
1980
+ return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) && typeof channel.name === "string" && Constants.TextBasedChannelTypes.includes(channel.type) && typeof channel.nsfw === "boolean" && "messages" in channel && typeof channel.send === "function";
1940
1981
  }
1941
1982
  __name(isTextChannelInstance, "isTextChannelInstance");
1942
1983
  function isMessageInstance(message) {
@@ -1982,34 +2023,6 @@ function checkInvalidKey(target, source, sourceName) {
1982
2023
  throw new DisTubeError("INVALID_KEY", sourceName, invalidKey);
1983
2024
  }
1984
2025
  __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
2026
  function isObject(obj) {
2014
2027
  return typeof obj === "object" && obj !== null && !Array.isArray(obj);
2015
2028
  }
@@ -2018,63 +2031,26 @@ function isRecord(obj) {
2018
2031
  return isObject(obj);
2019
2032
  }
2020
2033
  __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
2034
 
2032
- // src/plugin/http.ts
2033
- import http from "http";
2034
- var HTTPPlugin = class extends ExtractorPlugin {
2035
+ // src/plugin/DirectLink.ts
2036
+ import { request } from "undici";
2037
+ var DirectLinkPlugin = class extends ExtractorPlugin {
2035
2038
  async validate(url) {
2036
- return validateAudioURL(http, "http:", url);
2037
- }
2038
- async resolve(url, options = {}) {
2039
- return resolveHttpSong(url, { ...options, source: "http" });
2040
- }
2041
- };
2042
- __name(HTTPPlugin, "HTTPPlugin");
2043
-
2044
- // src/plugin/https.ts
2045
- import https from "https";
2046
- import { URL as URL2 } from "url";
2047
- var getResponseHeaders = /* @__PURE__ */ __name(async (httpModule, url) => new Promise((resolve, reject) => {
2048
- httpModule.get(url).on("response", (res) => {
2049
- resolve(res.headers);
2050
- }).on("error", reject);
2051
- }), "getResponseHeaders");
2052
- var validateAudioURL = /* @__PURE__ */ __name(async (httpModule, protocol, url) => {
2053
- if (new URL2(url).protocol.toLowerCase() !== protocol) {
2039
+ const headers = await request(url, { method: "HEAD" }).then((res) => res.headers);
2040
+ const type = headers["content-type"];
2041
+ if (type?.startsWith("audio"))
2042
+ return true;
2054
2043
  return false;
2055
2044
  }
2056
- const headers = await getResponseHeaders(httpModule, url), type = headers["content-type"];
2057
- if (type?.startsWith("audio")) {
2058
- return true;
2059
- }
2060
- return false;
2061
- }, "validateAudioURL");
2062
- var resolveHttpSong = /* @__PURE__ */ __name(async (url, options) => {
2063
- url = url.replace(/\/+$/, "");
2064
- return new Song({
2065
- name: url.substring(url.lastIndexOf("/") + 1).replace(/((\?|#).*)?$/, "") || url,
2066
- url
2067
- }, options);
2068
- }, "resolveHttpSong");
2069
- var HTTPSPlugin = class extends ExtractorPlugin {
2070
- async validate(url) {
2071
- return validateAudioURL(https, "https:", url);
2072
- }
2073
2045
  async resolve(url, options = {}) {
2074
- return resolveHttpSong(url, { ...options, source: "https" });
2046
+ url = url.replace(/\/+$/, "");
2047
+ return new Song({
2048
+ name: url.substring(url.lastIndexOf("/") + 1).replace(/((\?|#).*)?$/, "") || url,
2049
+ url
2050
+ }, options);
2075
2051
  }
2076
2052
  };
2077
- __name(HTTPSPlugin, "HTTPSPlugin");
2053
+ __name(DirectLinkPlugin, "DirectLinkPlugin");
2078
2054
 
2079
2055
  // src/DisTube.ts
2080
2056
  import ytsr from "@distube/ytsr";
@@ -2101,7 +2077,7 @@ var DisTube = class extends TypedEmitter2 {
2101
2077
  this.handler = new DisTubeHandler(this);
2102
2078
  this.queues = new QueueManager(this);
2103
2079
  this.filters = { ...defaultFilters, ...this.options.customFilters };
2104
- this.options.plugins.push(new HTTPPlugin(), new HTTPSPlugin());
2080
+ this.options.plugins.push(new DirectLinkPlugin());
2105
2081
  this.options.plugins.map((p) => p.init(this));
2106
2082
  this.extractorPlugins = this.options.plugins.filter((p) => p.type === "extractor");
2107
2083
  this.customPlugins = this.options.plugins.filter((p) => p.type === "custom");
@@ -2119,7 +2095,7 @@ var DisTube = class extends TypedEmitter2 {
2119
2095
  if (!isObject(options))
2120
2096
  throw new DisTubeError("INVALID_TYPE", "object", options, "options");
2121
2097
  const { textChannel, member, skip, message, metadata } = {
2122
- member: getClientMember(voiceChannel.guild),
2098
+ member: voiceChannel.guild.members.me ?? void 0,
2123
2099
  textChannel: options?.message?.channel,
2124
2100
  skip: false,
2125
2101
  ...options
@@ -2167,12 +2143,12 @@ var DisTube = class extends TypedEmitter2 {
2167
2143
  if (!(e instanceof DisTubeError)) {
2168
2144
  try {
2169
2145
  e.name = "PlayError";
2170
- e.message = `${song?.url || song}
2146
+ e.message = `${typeof song === "string" ? song : song.url}
2171
2147
  ${e.message}`;
2172
2148
  } catch {
2173
2149
  }
2174
2150
  }
2175
- this.emitError(e, textChannel);
2151
+ throw e;
2176
2152
  } finally {
2177
2153
  if (queuing)
2178
2154
  queue?._taskQueue.resolve();
@@ -2184,7 +2160,7 @@ ${e.message}`;
2184
2160
  throw new DisTubeError("INVALID_TYPE", "Array", songs, "songs");
2185
2161
  if (!songs.length)
2186
2162
  throw new DisTubeError("EMPTY_ARRAY", "songs");
2187
- const filteredSongs = songs.filter((song) => song instanceof Song || song instanceof SearchResult && song.type === "video" || isURL(song));
2163
+ const filteredSongs = songs.filter((song) => song instanceof Song || isURL(song) || typeof song !== "string" && song.type === "video" /* VIDEO */);
2188
2164
  if (!filteredSongs.length)
2189
2165
  throw new DisTubeError("NO_VALID_SONG");
2190
2166
  if (member && !isMemberInstance(member)) {
@@ -2206,7 +2182,7 @@ ${e.message}`;
2206
2182
  return new Playlist(resolvedSongs, { member, properties, metadata });
2207
2183
  }
2208
2184
  async search(string, options = {}) {
2209
- const opts = { type: "video", limit: 10, safeSearch: false, ...options };
2185
+ const opts = { type: "video" /* VIDEO */, limit: 10, safeSearch: false, ...options };
2210
2186
  if (typeof opts.type !== "string" || !["video", "playlist"].includes(opts.type)) {
2211
2187
  throw new DisTubeError("INVALID_TYPE", ["video", "playlist"], opts.type, "options.type");
2212
2188
  }
@@ -2219,7 +2195,11 @@ ${e.message}`;
2219
2195
  }
2220
2196
  try {
2221
2197
  const search = await ytsr(string, opts);
2222
- const results = search.items.map((i) => new SearchResult(i));
2198
+ const results = search.items.map((i) => {
2199
+ if (i.type === "video")
2200
+ return new SearchResultVideo(i);
2201
+ return new SearchResultPlaylist(i);
2202
+ });
2223
2203
  if (results.length === 0)
2224
2204
  throw new DisTubeError("NO_RESULT");
2225
2205
  return results;
@@ -2320,6 +2300,7 @@ __name(DisTube, "DisTube");
2320
2300
  export {
2321
2301
  BaseManager,
2322
2302
  CustomPlugin,
2303
+ DirectLinkPlugin,
2323
2304
  DisTube,
2324
2305
  DisTubeBase,
2325
2306
  DisTubeError,
@@ -2330,8 +2311,6 @@ export {
2330
2311
  ExtractorPlugin,
2331
2312
  FilterManager,
2332
2313
  GuildIdManager,
2333
- HTTPPlugin,
2334
- HTTPSPlugin,
2335
2314
  Options,
2336
2315
  Playlist,
2337
2316
  Plugin,
@@ -2339,8 +2318,9 @@ export {
2339
2318
  Queue,
2340
2319
  QueueManager,
2341
2320
  RepeatMode,
2342
- SearchResult,
2321
+ SearchResultPlaylist,
2343
2322
  SearchResultType,
2323
+ SearchResultVideo,
2344
2324
  Song,
2345
2325
  StreamType,
2346
2326
  TaskQueue,
@@ -2350,10 +2330,7 @@ export {
2350
2330
  DisTube as default,
2351
2331
  defaultFilters,
2352
2332
  defaultOptions,
2353
- entersState,
2354
2333
  formatDuration,
2355
- getClientMember,
2356
- getResponseHeaders,
2357
2334
  isClientInstance,
2358
2335
  isGuildInstance,
2359
2336
  isMemberInstance,
@@ -2367,9 +2344,7 @@ export {
2367
2344
  isVoiceChannelEmpty,
2368
2345
  parseNumber,
2369
2346
  resolveGuildId,
2370
- resolveHttpSong,
2371
2347
  toSecond,
2372
- validateAudioURL,
2373
2348
  version
2374
2349
  };
2375
2350
  //# sourceMappingURL=index.mjs.map