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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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.3",
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",
@@ -65,7 +65,7 @@ var require_package = __commonJS({
65
65
  docs: "docgen -s src/*.ts src/**/*.ts -o docs.json -c pages/index.yml -g -j jsdoc.config.json",
66
66
  lint: "prettier --check . && eslint .",
67
67
  "lint:fix": "eslint . --fix",
68
- prettier: "prettier --write **/*.{ts,json,yml,yaml,md}",
68
+ prettier: 'prettier --write "**/*.{ts,json,yml,yaml,md}"',
69
69
  build: "tsup",
70
70
  "build:check": "tsc --noEmit",
71
71
  update: "ncu -u --dep dev,prod && yarn up '**' -R",
@@ -108,43 +108,43 @@ var require_package = __commonJS({
108
108
  ],
109
109
  homepage: "https://distube.js.org/",
110
110
  dependencies: {
111
- "@distube/ytdl-core": "^4.11.1",
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
- tslib: "^2.3.1"
116
+ tslib: "^2.4.0"
117
117
  },
118
118
  devDependencies: {
119
- "@babel/core": "^7.17.8",
120
- "@babel/plugin-proposal-class-properties": "^7.16.7",
121
- "@babel/plugin-proposal-object-rest-spread": "^7.17.3",
122
- "@babel/preset-env": "^7.16.11",
123
- "@babel/preset-typescript": "^7.16.7",
124
- "@commitlint/cli": "^16.2.3",
125
- "@commitlint/config-conventional": "^16.2.1",
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.4.1",
129
- "@types/node": "^17.0.23",
130
- "@typescript-eslint/eslint-plugin": "^5.17.0",
131
- "@typescript-eslint/parser": "^5.17.0",
132
- "babel-jest": "^27.5.1",
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.12.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": "^38.1.4",
139
- husky: "^7.0.4",
140
- jest: "^27.5.1",
138
+ "eslint-plugin-jsdoc": "^39.3.3",
139
+ husky: "^8.0.1",
140
+ jest: "^28.1.3",
141
141
  "jsdoc-babel": "^0.5.0",
142
- "nano-staged": "^0.6.0",
143
- "npm-check-updates": "^12.5.4",
142
+ "nano-staged": "^0.8.0",
143
+ "npm-check-updates": "^15.3.0",
144
144
  pinst: "^3.0.0",
145
- prettier: "^2.6.1",
146
- tsup: "^5.12.1",
147
- typescript: "^4.6.3"
145
+ prettier: "^2.7.1",
146
+ tsup: "^6.1.3",
147
+ typescript: "^4.7.4"
148
148
  },
149
149
  peerDependencies: {
150
150
  "@discordjs/opus": "*",
@@ -191,6 +191,11 @@ var SearchResultType = /* @__PURE__ */ ((SearchResultType2) => {
191
191
  SearchResultType2["PLAYLIST"] = "playlist";
192
192
  return SearchResultType2;
193
193
  })(SearchResultType || {});
194
+ var StreamType = /* @__PURE__ */ ((StreamType2) => {
195
+ StreamType2[StreamType2["OPUS"] = 0] = "OPUS";
196
+ StreamType2[StreamType2["RAW"] = 1] = "RAW";
197
+ return StreamType2;
198
+ })(StreamType || {});
194
199
 
195
200
  // src/constant.ts
196
201
  var defaultFilters = {
@@ -224,13 +229,14 @@ var defaultOptions = {
224
229
  nsfw: false,
225
230
  emitAddSongWhenCreatingQueue: true,
226
231
  emitAddListWhenCreatingQueue: true,
227
- joinNewVoiceChannel: true
232
+ joinNewVoiceChannel: true,
233
+ streamType: 0 /* OPUS */
228
234
  };
229
235
 
230
236
  // src/struct/DisTubeError.ts
231
237
  import { inspect } from "node:util";
232
238
  var ERROR_MESSAGES = {
233
- 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})`,
234
240
  NUMBER_COMPARE: (name, expected, value) => `'${name}' must be ${expected} ${value}`,
235
241
  EMPTY_ARRAY: (name) => `'${name}' is an empty array`,
236
242
  EMPTY_FILTERED_ARRAY: (name, type) => `There is no valid '${type}' in the '${name}' array`,
@@ -246,7 +252,8 @@ var ERROR_MESSAGES = {
246
252
  VOICE_CONNECT_FAILED: (s) => `Cannot connect to the voice channel after ${s} seconds`,
247
253
  VOICE_MISSING_PERMS: "I do not have permission to join this voice channel",
248
254
  VOICE_RECONNECT_FAILED: "Cannot reconnect to the voice channel",
249
- VOICE_DIFFERENT_GUILD: "Cannot join a channel in a different guild",
255
+ VOICE_DIFFERENT_GUILD: "Cannot join a voice channel in a different guild",
256
+ VOICE_DIFFERENT_CLIENT: "Cannot join a voice channel created by a different client",
250
257
  NO_QUEUE: "There is no playing queue in this guild",
251
258
  QUEUE_EXIST: "This guild has a Queue already",
252
259
  PAUSED: "The queue has been paused already",
@@ -285,6 +292,7 @@ var DisTubeError = class extends Error {
285
292
  return this.errorCode;
286
293
  }
287
294
  };
295
+ __name(DisTubeError, "DisTubeError");
288
296
 
289
297
  // src/struct/TaskQueue.ts
290
298
  var Task = class {
@@ -298,6 +306,7 @@ var Task = class {
298
306
  });
299
307
  }
300
308
  };
309
+ __name(Task, "Task");
301
310
  var _tasks;
302
311
  var TaskQueue = class {
303
312
  constructor() {
@@ -318,6 +327,7 @@ var TaskQueue = class {
318
327
  return !!__privateGet(this, _tasks).find((t) => t.resolveInfo);
319
328
  }
320
329
  };
330
+ __name(TaskQueue, "TaskQueue");
321
331
  _tasks = new WeakMap();
322
332
 
323
333
  // src/struct/Playlist.ts
@@ -332,26 +342,33 @@ var Playlist = class {
332
342
  __publicField(this, "url");
333
343
  __publicField(this, "thumbnail");
334
344
  const { member, properties, metadata } = options;
335
- if (typeof playlist !== "object") {
336
- 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");
337
347
  }
338
348
  if (typeof properties !== "undefined" && !isRecord(properties)) {
339
349
  throw new DisTubeError("INVALID_TYPE", "object", properties, "properties");
340
350
  }
341
- const info = playlist;
342
- this.source = (info.source || properties?.source || "youtube").toLowerCase();
343
- this.songs = Array.isArray(info) ? info : info.items || info.songs;
344
- if (!Array.isArray(this.songs) || !this.songs.length) {
345
- 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;
346
366
  }
347
367
  this.songs.map((s) => s.constructor.name === "Song" && (s.playlist = this));
348
- this.member = member || info.member || void 0;
349
- 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`);
350
- this.url = info.url || info.webpage_url;
351
- this.thumbnail = info.thumbnail?.url || info.thumbnail || this.songs[0].thumbnail;
352
368
  if (properties)
353
369
  for (const [key, value] of Object.entries(properties))
354
370
  this[key] = value;
371
+ this.member = member;
355
372
  this.metadata = metadata;
356
373
  }
357
374
  get duration() {
@@ -380,44 +397,69 @@ var Playlist = class {
380
397
  this.songs.map((s) => s.constructor.name === "Song" && (s.metadata = metadata));
381
398
  }
382
399
  };
400
+ __name(Playlist, "Playlist");
383
401
  _metadata = new WeakMap();
384
402
  _member = new WeakMap();
385
403
 
386
404
  // src/struct/SearchResult.ts
387
- var SearchResult = class {
405
+ var ISearchResult = class {
388
406
  constructor(info) {
389
407
  __publicField(this, "source");
390
- __publicField(this, "type");
391
408
  __publicField(this, "id");
392
409
  __publicField(this, "name");
393
410
  __publicField(this, "url");
394
- __publicField(this, "views");
395
- __publicField(this, "isLive");
396
- __publicField(this, "duration");
397
- __publicField(this, "formattedDuration");
398
- __publicField(this, "thumbnail");
399
411
  __publicField(this, "uploader");
400
412
  this.source = "youtube";
401
- this.type = info.type === "video" ? "video" /* VIDEO */ : "playlist" /* PLAYLIST */;
402
413
  this.id = info.id;
403
414
  this.name = info.name;
404
415
  this.url = info.url;
405
- if (this.type === "video" /* VIDEO */) {
406
- info = info;
407
- this.views = info.views;
408
- this.isLive = info.isLive;
409
- this.duration = this.isLive ? 0 : toSecond(info.duration);
410
- this.formattedDuration = this.isLive ? "Live" : formatDuration(this.duration);
411
- this.thumbnail = info.thumbnail;
412
- } else if (this.type !== "playlist") {
413
- throw new DisTubeError("INVALID_TYPE", ["video", "playlist"], this.type, "SearchResult.type");
414
- }
415
416
  this.uploader = {
416
- name: (info.author || info.owner)?.name,
417
- 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
418
459
  };
419
460
  }
420
461
  };
462
+ __name(SearchResultPlaylist, "SearchResultPlaylist");
421
463
 
422
464
  // src/struct/Song.ts
423
465
  var _metadata2, _member2, _playlist;
@@ -552,112 +594,11 @@ var _Song = class {
552
594
  }
553
595
  };
554
596
  var Song = _Song;
597
+ __name(Song, "Song");
555
598
  _metadata2 = new WeakMap();
556
599
  _member2 = new WeakMap();
557
600
  _playlist = new WeakMap();
558
601
 
559
- // src/core/DisTubeOptions.ts
560
- var _validateOptions, validateOptions_fn;
561
- var Options = class {
562
- constructor(options) {
563
- __privateAdd(this, _validateOptions);
564
- __publicField(this, "plugins");
565
- __publicField(this, "emitNewSongOnly");
566
- __publicField(this, "leaveOnFinish");
567
- __publicField(this, "leaveOnStop");
568
- __publicField(this, "leaveOnEmpty");
569
- __publicField(this, "emptyCooldown");
570
- __publicField(this, "savePreviousSongs");
571
- __publicField(this, "searchSongs");
572
- __publicField(this, "searchCooldown");
573
- __publicField(this, "youtubeCookie");
574
- __publicField(this, "youtubeIdentityToken");
575
- __publicField(this, "customFilters");
576
- __publicField(this, "ytdlOptions");
577
- __publicField(this, "nsfw");
578
- __publicField(this, "emitAddSongWhenCreatingQueue");
579
- __publicField(this, "emitAddListWhenCreatingQueue");
580
- __publicField(this, "joinNewVoiceChannel");
581
- if (typeof options !== "object" || Array.isArray(options)) {
582
- throw new DisTubeError("INVALID_TYPE", "object", options, "DisTubeOptions");
583
- }
584
- const opts = { ...defaultOptions, ...options };
585
- this.plugins = opts.plugins;
586
- this.emitNewSongOnly = opts.emitNewSongOnly;
587
- this.leaveOnEmpty = opts.leaveOnEmpty;
588
- this.leaveOnFinish = opts.leaveOnFinish;
589
- this.leaveOnStop = opts.leaveOnStop;
590
- this.savePreviousSongs = opts.savePreviousSongs;
591
- this.searchSongs = opts.searchSongs;
592
- this.youtubeCookie = opts.youtubeCookie;
593
- this.youtubeIdentityToken = opts.youtubeIdentityToken;
594
- this.customFilters = opts.customFilters;
595
- this.ytdlOptions = opts.ytdlOptions;
596
- this.searchCooldown = opts.searchCooldown;
597
- this.emptyCooldown = opts.emptyCooldown;
598
- this.nsfw = opts.nsfw;
599
- this.emitAddSongWhenCreatingQueue = opts.emitAddSongWhenCreatingQueue;
600
- this.emitAddListWhenCreatingQueue = opts.emitAddListWhenCreatingQueue;
601
- this.joinNewVoiceChannel = opts.joinNewVoiceChannel;
602
- checkInvalidKey(opts, this, "DisTubeOptions");
603
- __privateMethod(this, _validateOptions, validateOptions_fn).call(this);
604
- }
605
- };
606
- _validateOptions = new WeakSet();
607
- validateOptions_fn = /* @__PURE__ */ __name(function(options = this) {
608
- if (typeof options.emitNewSongOnly !== "boolean") {
609
- throw new DisTubeError("INVALID_TYPE", "boolean", options.emitNewSongOnly, "DisTubeOptions.emitNewSongOnly");
610
- }
611
- if (typeof options.leaveOnEmpty !== "boolean") {
612
- throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnEmpty, "DisTubeOptions.leaveOnEmpty");
613
- }
614
- if (typeof options.leaveOnFinish !== "boolean") {
615
- throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnFinish, "DisTubeOptions.leaveOnFinish");
616
- }
617
- if (typeof options.leaveOnStop !== "boolean") {
618
- throw new DisTubeError("INVALID_TYPE", "boolean", options.leaveOnStop, "DisTubeOptions.leaveOnStop");
619
- }
620
- if (typeof options.savePreviousSongs !== "boolean") {
621
- throw new DisTubeError("INVALID_TYPE", "boolean", options.savePreviousSongs, "DisTubeOptions.savePreviousSongs");
622
- }
623
- if (typeof options.joinNewVoiceChannel !== "boolean") {
624
- throw new DisTubeError("INVALID_TYPE", "boolean", options.joinNewVoiceChannel, "DisTubeOptions.joinNewVoiceChannel");
625
- }
626
- if (typeof options.youtubeCookie !== "undefined" && typeof options.youtubeCookie !== "string") {
627
- throw new DisTubeError("INVALID_TYPE", "string", options.youtubeCookie, "DisTubeOptions.youtubeCookie");
628
- }
629
- if (typeof options.youtubeIdentityToken !== "undefined" && typeof options.youtubeIdentityToken !== "string") {
630
- throw new DisTubeError("INVALID_TYPE", "string", options.youtubeIdentityToken, "DisTubeOptions.youtubeIdentityToken");
631
- }
632
- if (typeof options.customFilters !== "undefined" && typeof options.customFilters !== "object" || Array.isArray(options.customFilters)) {
633
- throw new DisTubeError("INVALID_TYPE", "object", options.customFilters, "DisTubeOptions.customFilters");
634
- }
635
- if (typeof options.ytdlOptions !== "object" || Array.isArray(options.ytdlOptions)) {
636
- throw new DisTubeError("INVALID_TYPE", "object", options.ytdlOptions, "DisTubeOptions.ytdlOptions");
637
- }
638
- if (typeof options.searchCooldown !== "number" || isNaN(options.searchCooldown)) {
639
- throw new DisTubeError("INVALID_TYPE", "number", options.searchCooldown, "DisTubeOptions.searchCooldown");
640
- }
641
- if (typeof options.emptyCooldown !== "number" || isNaN(options.emptyCooldown)) {
642
- throw new DisTubeError("INVALID_TYPE", "number", options.emptyCooldown, "DisTubeOptions.emptyCooldown");
643
- }
644
- if (typeof options.searchSongs !== "number" || isNaN(options.searchSongs)) {
645
- throw new DisTubeError("INVALID_TYPE", "number", options.searchSongs, "DisTubeOptions.searchSongs");
646
- }
647
- if (!Array.isArray(options.plugins)) {
648
- throw new DisTubeError("INVALID_TYPE", "Array<Plugin>", options.plugins, "DisTubeOptions.plugins");
649
- }
650
- if (typeof options.nsfw !== "boolean") {
651
- throw new DisTubeError("INVALID_TYPE", "boolean", options.nsfw, "DisTubeOptions.nsfw");
652
- }
653
- if (typeof options.emitAddSongWhenCreatingQueue !== "boolean") {
654
- throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddSongWhenCreatingQueue, "DisTubeOptions.emitAddSongWhenCreatingQueue");
655
- }
656
- if (typeof options.emitAddListWhenCreatingQueue !== "boolean") {
657
- throw new DisTubeError("INVALID_TYPE", "boolean", options.emitAddListWhenCreatingQueue, "DisTubeOptions.emitAddListWhenCreatingQueue");
658
- }
659
- }, "#validateOptions");
660
-
661
602
  // src/core/DisTubeBase.ts
662
603
  var DisTubeBase = class {
663
604
  constructor(distube) {
@@ -686,75 +627,206 @@ var DisTubeBase = class {
686
627
  return this.distube.handler;
687
628
  }
688
629
  };
630
+ __name(DisTubeBase, "DisTubeBase");
689
631
 
690
- // src/core/DisTubeStream.ts
691
- import { FFmpeg } from "prism-media";
692
- import { StreamType } from "@discordjs/voice";
693
- var chooseBestVideoFormat = /* @__PURE__ */ __name((formats, isLive = false) => {
694
- let filter = /* @__PURE__ */ __name((format) => format.hasAudio, "filter");
695
- if (isLive)
696
- filter = /* @__PURE__ */ __name((format) => format.hasAudio && format.isHLS, "filter");
697
- formats = formats.filter(filter).sort((a, b) => Number(b.audioBitrate) - Number(a.audioBitrate) || Number(a.bitrate) - Number(b.bitrate));
698
- return formats.find((format) => !format.hasVideo) || formats.sort((a, b) => Number(a.bitrate) - Number(b.bitrate))[0];
699
- }, "chooseBestVideoFormat");
700
- var DisTubeStream = class {
701
- constructor(url, options) {
702
- __publicField(this, "type");
703
- __publicField(this, "stream");
704
- __publicField(this, "url");
705
- this.url = url;
706
- this.type = StreamType.Raw;
707
- const args = [
708
- "-reconnect",
709
- "1",
710
- "-reconnect_streamed",
711
- "1",
712
- "-reconnect_delay_max",
713
- "5",
714
- "-i",
715
- url,
716
- "-analyzeduration",
717
- "0",
718
- "-loglevel",
719
- "0",
720
- "-ar",
721
- "48000",
722
- "-ac",
723
- "2",
724
- "-f",
725
- "s16le"
726
- ];
727
- if (typeof options.seek === "number" && options.seek > 0) {
728
- args.unshift("-ss", options.seek.toString());
729
- }
730
- if (Array.isArray(options.ffmpegArgs)) {
731
- args.push(...options.ffmpegArgs);
732
- }
733
- 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);
734
693
  }
735
- static YouTube(formats, options = {}) {
736
- if (!formats || !formats.length)
737
- throw new DisTubeError("UNAVAILABLE_VIDEO");
738
- if (!options || typeof options !== "object" || Array.isArray(options)) {
739
- throw new DisTubeError("INVALID_TYPE", "object", options, "options");
740
- }
741
- const bestFormat = chooseBestVideoFormat(formats, options.isLive);
742
- if (!bestFormat)
743
- throw new DisTubeError("UNPLAYABLE_FORMATS");
744
- return new DisTubeStream(bestFormat.url, options);
694
+ get channel() {
695
+ return __privateGet(this, _channel);
745
696
  }
746
- static DirectLink(url, options = {}) {
747
- if (!options || typeof options !== "object" || Array.isArray(options)) {
748
- throw new DisTubeError("INVALID_TYPE", "object", options, "options");
749
- }
750
- if (typeof url !== "string" || !isURL(url)) {
751
- throw new DisTubeError("INVALID_TYPE", "an URL", url);
697
+ set channel(channel) {
698
+ if (!isSupportedVoiceChannel(channel)) {
699
+ throw new DisTubeError("INVALID_TYPE", "BaseGuildVoiceChannel", channel, "DisTubeVoice#channel");
752
700
  }
753
- return new DisTubeStream(url, options);
754
- }
755
- };
756
-
757
- // src/core/manager/BaseManager.ts
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");
712
+ }
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;
809
+ }
810
+ };
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");
828
+
829
+ // src/core/manager/BaseManager.ts
758
830
  import { Collection } from "discord.js";
759
831
  var BaseManager = class extends DisTubeBase {
760
832
  constructor() {
@@ -765,6 +837,7 @@ var BaseManager = class extends DisTubeBase {
765
837
  return this.collection.size;
766
838
  }
767
839
  };
840
+ __name(BaseManager, "BaseManager");
768
841
 
769
842
  // src/core/manager/GuildIdManager.ts
770
843
  var GuildIdManager = class extends BaseManager {
@@ -785,6 +858,124 @@ var GuildIdManager = class extends BaseManager {
785
858
  return this.collection.has(resolveGuildId(idOrInstance));
786
859
  }
787
860
  };
861
+ __name(GuildIdManager, "GuildIdManager");
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");
788
979
 
789
980
  // src/core/manager/QueueManager.ts
790
981
  var _voiceEventHandler, voiceEventHandler_fn, _handleSongFinish, handleSongFinish_fn, _handlePlayingError, handlePlayingError_fn, _emitPlaySong, emitPlaySong_fn;
@@ -817,7 +1008,7 @@ var QueueManager = class extends GuildIdManager {
817
1008
  const { duration, formats, isLive, source, streamURL } = queue.songs[0];
818
1009
  const ffmpegArgs = queue.filters.size ? ["-af", queue.filters.values.join(",")] : void 0;
819
1010
  const seek = duration ? queue.beginTime : void 0;
820
- const streamOptions = { ffmpegArgs, seek, isLive };
1011
+ const streamOptions = { ffmpegArgs, seek, isLive, type: this.options.streamType };
821
1012
  if (source === "youtube")
822
1013
  return DisTubeStream.YouTube(formats, streamOptions);
823
1014
  return DisTubeStream.DirectLink(streamURL, streamOptions);
@@ -831,8 +1022,8 @@ var QueueManager = class extends GuildIdManager {
831
1022
  }
832
1023
  if (queue.stopped)
833
1024
  return false;
834
- const song = queue.songs[0];
835
1025
  try {
1026
+ const song = queue.songs[0];
836
1027
  const { url, source, formats, streamURL } = song;
837
1028
  if (source === "youtube" && !formats)
838
1029
  song._patchYouTube(await this.handler.getYouTubeInfo(url));
@@ -861,6 +1052,7 @@ var QueueManager = class extends GuildIdManager {
861
1052
  }
862
1053
  }
863
1054
  };
1055
+ __name(QueueManager, "QueueManager");
864
1056
  _voiceEventHandler = new WeakSet();
865
1057
  voiceEventHandler_fn = /* @__PURE__ */ __name(function(queue) {
866
1058
  queue._listeners = {
@@ -893,377 +1085,69 @@ handleSongFinish_fn = /* @__PURE__ */ __name(async function(queue) {
893
1085
  queue.songs.unshift(queue.previousSongs.pop());
894
1086
  }
895
1087
  if (queue.songs.length <= 1 && (queue._next || queue.repeatMode === 0 /* DISABLED */)) {
896
- if (queue.autoplay) {
897
- try {
898
- await queue.addRelatedSong();
899
- } catch {
900
- this.emit("noRelated", queue);
901
- }
902
- }
903
- if (queue.songs.length <= 1) {
904
- if (this.options.leaveOnFinish)
905
- queue.voice.leave();
906
- if (!queue.autoplay)
907
- this.emit("finish", queue);
908
- queue.remove();
909
- return;
910
- }
911
- }
912
- const emitPlaySong = __privateMethod(this, _emitPlaySong, emitPlaySong_fn).call(this, queue);
913
- if (!queue._prev && (queue.repeatMode !== 1 /* SONG */ || queue._next)) {
914
- const prev = queue.songs.shift();
915
- delete prev.formats;
916
- delete prev.streamURL;
917
- if (this.options.savePreviousSongs)
918
- queue.previousSongs.push(prev);
919
- else
920
- queue.previousSongs.push({ id: prev.id });
921
- }
922
- queue._next = queue._prev = false;
923
- queue.beginTime = 0;
924
- const err = await this.playSong(queue);
925
- if (!err && emitPlaySong)
926
- this.emit("playSong", queue, queue.songs[0]);
927
- } finally {
928
- queue._taskQueue.resolve();
929
- }
930
- }, "#handleSongFinish");
931
- _handlePlayingError = new WeakSet();
932
- handlePlayingError_fn = /* @__PURE__ */ __name(function(queue, error) {
933
- const song = queue.songs.shift();
934
- try {
935
- error.name = "PlayingError";
936
- error.message = `${error.message}
937
- Id: ${song.id}
938
- Name: ${song.name}`;
939
- } catch {
940
- }
941
- this.emitError(error, queue.textChannel);
942
- if (queue.songs.length > 0) {
943
- this.playSong(queue).then((e) => {
944
- if (!e)
945
- this.emit("playSong", queue, queue.songs[0]);
946
- });
947
- } else {
948
- queue.stop();
949
- }
950
- }, "#handlePlayingError");
951
- _emitPlaySong = new WeakSet();
952
- emitPlaySong_fn = /* @__PURE__ */ __name(function(queue) {
953
- return !this.options.emitNewSongOnly || queue.repeatMode === 1 /* SONG */ && queue._next || queue.repeatMode !== 1 /* SONG */ && queue.songs[0]?.id !== queue.songs[1]?.id;
954
- }, "#emitPlaySong");
955
-
956
- // src/core/manager/FilterManager.ts
957
- var _validate, validate_fn, _resolveName, resolveName_fn, _resolveValue, resolveValue_fn, _apply, apply_fn;
958
- var FilterManager = class extends BaseManager {
959
- constructor(queue) {
960
- super(queue.distube);
961
- __privateAdd(this, _validate);
962
- __privateAdd(this, _resolveName);
963
- __privateAdd(this, _resolveValue);
964
- __privateAdd(this, _apply);
965
- __publicField(this, "queue");
966
- this.queue = queue;
967
- }
968
- add(filterOrFilters, override = false) {
969
- if (Array.isArray(filterOrFilters)) {
970
- const resolvedFilters = filterOrFilters.map((f) => __privateMethod(this, _validate, validate_fn).call(this, f));
971
- const newFilters = resolvedFilters.reduceRight((unique, o) => {
972
- if (!unique.some((obj) => obj === o && obj.name === o) && !unique.some((obj) => obj !== o.name && obj.name !== o.name)) {
973
- if (!this.has(o))
974
- unique.push(o);
975
- if (this.has(o) && override) {
976
- this.remove(o);
977
- unique.push(o);
978
- }
979
- }
980
- return unique;
981
- }, []).reverse();
982
- return this.set([...this.collection.values(), ...newFilters]);
983
- }
984
- return this.set([...this.collection.values(), filterOrFilters]);
985
- }
986
- clear() {
987
- return this.set([]);
988
- }
989
- set(filters) {
990
- this.collection.clear();
991
- for (const filter of filters) {
992
- const resolved = __privateMethod(this, _validate, validate_fn).call(this, filter);
993
- this.collection.set(__privateMethod(this, _resolveName, resolveName_fn).call(this, resolved), resolved);
994
- }
995
- __privateMethod(this, _apply, apply_fn).call(this);
996
- return this;
997
- }
998
- remove(filterOrFilters) {
999
- const remove = /* @__PURE__ */ __name((f) => this.collection.delete(__privateMethod(this, _resolveName, resolveName_fn).call(this, __privateMethod(this, _validate, validate_fn).call(this, f))), "remove");
1000
- if (Array.isArray(filterOrFilters))
1001
- filterOrFilters.map(remove);
1002
- else
1003
- remove(filterOrFilters);
1004
- __privateMethod(this, _apply, apply_fn).call(this);
1005
- return this;
1006
- }
1007
- has(filter) {
1008
- return this.collection.has(__privateMethod(this, _resolveName, resolveName_fn).call(this, filter));
1009
- }
1010
- get names() {
1011
- return this.collection.map((f) => __privateMethod(this, _resolveName, resolveName_fn).call(this, f));
1012
- }
1013
- get values() {
1014
- return this.collection.map((f) => __privateMethod(this, _resolveValue, resolveValue_fn).call(this, f));
1015
- }
1016
- toString() {
1017
- return this.names.toString();
1018
- }
1019
- };
1020
- _validate = new WeakSet();
1021
- validate_fn = /* @__PURE__ */ __name(function(filter) {
1022
- if (typeof filter === "string" && Object.prototype.hasOwnProperty.call(this.distube.filters, filter) || typeof filter === "object" && typeof filter.name === "string" && typeof filter.value === "string") {
1023
- return filter;
1024
- }
1025
- throw new DisTubeError("INVALID_TYPE", "FilterResolvable", filter, "filter");
1026
- }, "#validate");
1027
- _resolveName = new WeakSet();
1028
- resolveName_fn = /* @__PURE__ */ __name(function(filter) {
1029
- return typeof filter === "string" ? filter : filter.name;
1030
- }, "#resolveName");
1031
- _resolveValue = new WeakSet();
1032
- resolveValue_fn = /* @__PURE__ */ __name(function(filter) {
1033
- return typeof filter === "string" ? this.distube.filters[filter] : filter.value;
1034
- }, "#resolveValue");
1035
- _apply = new WeakSet();
1036
- apply_fn = /* @__PURE__ */ __name(function() {
1037
- this.queue.beginTime = this.queue.currentTime;
1038
- this.queues.playSong(this.queue);
1039
- }, "#apply");
1040
-
1041
- // src/core/voice/DisTubeVoice.ts
1042
- import { TypedEmitter } from "tiny-typed-emitter";
1043
- import {
1044
- AudioPlayerStatus,
1045
- VoiceConnectionDisconnectReason,
1046
- VoiceConnectionStatus,
1047
- createAudioPlayer,
1048
- createAudioResource,
1049
- joinVoiceChannel
1050
- } from "@discordjs/voice";
1051
- var _channel, _volume, _br, br_fn, _join, join_fn;
1052
- var DisTubeVoice = class extends TypedEmitter {
1053
- constructor(voiceManager, channel) {
1054
- super();
1055
- __privateAdd(this, _br);
1056
- __privateAdd(this, _join);
1057
- __publicField(this, "id");
1058
- __publicField(this, "voices");
1059
- __publicField(this, "audioPlayer");
1060
- __publicField(this, "connection");
1061
- __publicField(this, "audioResource");
1062
- __publicField(this, "emittedError");
1063
- __publicField(this, "isDisconnected", false);
1064
- __privateAdd(this, _channel, void 0);
1065
- __privateAdd(this, _volume, 100);
1066
- this.id = channel.guildId;
1067
- this.channel = channel;
1068
- this.voices = voiceManager;
1069
- this.voices.add(this.id, this);
1070
- this.audioPlayer = createAudioPlayer().on(AudioPlayerStatus.Idle, (oldState) => {
1071
- if (oldState.status !== AudioPlayerStatus.Idle) {
1072
- delete this.audioResource;
1073
- this.emit("finish");
1074
- }
1075
- }).on(AudioPlayerStatus.Playing, () => __privateMethod(this, _br, br_fn).call(this)).on("error", (error) => {
1076
- if (this.emittedError)
1077
- return;
1078
- this.emittedError = true;
1079
- this.emit("error", error);
1080
- });
1081
- this.connection.on(VoiceConnectionStatus.Disconnected, (_, newState) => {
1082
- if (newState.reason === VoiceConnectionDisconnectReason.Manual) {
1083
- this.leave();
1084
- } else if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {
1085
- entersState(this.connection, VoiceConnectionStatus.Connecting, 5e3).catch(() => {
1086
- if (![VoiceConnectionStatus.Ready, VoiceConnectionStatus.Connecting].includes(this.connection.state.status)) {
1087
- this.leave();
1088
- }
1089
- });
1090
- } else if (this.connection.rejoinAttempts < 5) {
1091
- setTimeout(() => {
1092
- this.connection.rejoin();
1093
- }, (this.connection.rejoinAttempts + 1) * 5e3).unref();
1094
- } else if (this.connection.state.status !== VoiceConnectionStatus.Destroyed) {
1095
- this.leave(new DisTubeError("VOICE_RECONNECT_FAILED"));
1096
- }
1097
- }).on(VoiceConnectionStatus.Destroyed, () => {
1098
- this.leave(new DisTubeError("VOICE_RECONNECT_FAILED"));
1099
- }).on("error", () => void 0);
1100
- this.connection.subscribe(this.audioPlayer);
1101
- }
1102
- get channel() {
1103
- return __privateGet(this, _channel);
1104
- }
1105
- set channel(channel) {
1106
- if (!isSupportedVoiceChannel(channel)) {
1107
- throw new DisTubeError("INVALID_TYPE", "BaseGuildVoiceChannel", channel, "DisTubeVoice#channel");
1108
- }
1109
- if (channel.guildId !== this.id)
1110
- throw new DisTubeError("VOICE_DIFFERENT_GUILD");
1111
- if (channel.id === __privateGet(this, _channel)?.id)
1112
- return;
1113
- if (!channel.joinable) {
1114
- if (channel.full)
1115
- throw new DisTubeError("VOICE_FULL");
1116
- else
1117
- throw new DisTubeError("VOICE_MISSING_PERMS");
1118
- }
1119
- this.connection = __privateMethod(this, _join, join_fn).call(this, channel);
1120
- __privateSet(this, _channel, channel);
1121
- __privateMethod(this, _br, br_fn).call(this);
1122
- }
1123
- async join(channel) {
1124
- const TIMEOUT = 3e4;
1125
- if (channel)
1126
- this.channel = channel;
1127
- try {
1128
- await entersState(this.connection, VoiceConnectionStatus.Ready, TIMEOUT);
1129
- } catch {
1130
- if (this.connection.state.status === VoiceConnectionStatus.Ready)
1131
- return this;
1132
- if (this.connection.state.status !== VoiceConnectionStatus.Destroyed)
1133
- this.connection.destroy();
1134
- this.voices.remove(this.id);
1135
- throw new DisTubeError("VOICE_CONNECT_FAILED", TIMEOUT / 1e3);
1136
- }
1137
- return this;
1138
- }
1139
- leave(error) {
1140
- this.stop(true);
1141
- if (!this.isDisconnected) {
1142
- this.emit("disconnect", error);
1143
- this.isDisconnected = true;
1144
- }
1145
- if (this.connection.state.status !== VoiceConnectionStatus.Destroyed)
1146
- this.connection.destroy();
1147
- this.voices.remove(this.id);
1148
- }
1149
- stop(force = false) {
1150
- this.audioPlayer.stop(force);
1151
- }
1152
- play(stream) {
1153
- this.emittedError = false;
1154
- stream.stream.on("error", (error) => {
1155
- if (this.emittedError || error.code === "ERR_STREAM_PREMATURE_CLOSE")
1156
- return;
1157
- this.emittedError = true;
1158
- this.emit("error", error);
1159
- });
1160
- this.audioResource = createAudioResource(stream.stream, {
1161
- inputType: stream.type,
1162
- inlineVolume: true
1163
- });
1164
- this.volume = __privateGet(this, _volume);
1165
- this.audioPlayer.play(this.audioResource);
1166
- }
1167
- set volume(volume) {
1168
- if (typeof volume !== "number" || isNaN(volume)) {
1169
- throw new DisTubeError("INVALID_TYPE", "number", volume, "volume");
1170
- }
1171
- if (volume < 0) {
1172
- throw new DisTubeError("NUMBER_COMPARE", "Volume", "bigger or equal to", 0);
1173
- }
1174
- __privateSet(this, _volume, volume);
1175
- this.audioResource?.volume?.setVolume(Math.pow(__privateGet(this, _volume) / 100, 0.5 / Math.log10(2)));
1176
- }
1177
- get volume() {
1178
- return __privateGet(this, _volume);
1179
- }
1180
- get playbackDuration() {
1181
- return (this.audioResource?.playbackDuration ?? 0) / 1e3;
1182
- }
1183
- pause() {
1184
- this.audioPlayer.pause();
1185
- }
1186
- unpause() {
1187
- this.audioPlayer.unpause();
1188
- }
1189
- get selfDeaf() {
1190
- return this.connection.joinConfig.selfDeaf;
1191
- }
1192
- get selfMute() {
1193
- return this.connection.joinConfig.selfMute;
1194
- }
1195
- setSelfDeaf(selfDeaf) {
1196
- if (typeof selfDeaf !== "boolean") {
1197
- throw new DisTubeError("INVALID_TYPE", "boolean", selfDeaf, "selfDeaf");
1198
- }
1199
- return this.connection.rejoin({
1200
- ...this.connection.joinConfig,
1201
- selfDeaf
1202
- });
1203
- }
1204
- setSelfMute(selfMute) {
1205
- if (typeof selfMute !== "boolean") {
1206
- throw new DisTubeError("INVALID_TYPE", "boolean", selfMute, "selfMute");
1207
- }
1208
- return this.connection.rejoin({
1209
- ...this.connection.joinConfig,
1210
- selfMute
1211
- });
1212
- }
1213
- get voiceState() {
1214
- return this.channel?.guild?.me?.voice;
1215
- }
1216
- };
1217
- _channel = new WeakMap();
1218
- _volume = new WeakMap();
1219
- _br = new WeakSet();
1220
- br_fn = /* @__PURE__ */ __name(function() {
1221
- if (this.audioResource?.encoder?.encoder)
1222
- this.audioResource.encoder.setBitrate(this.channel.bitrate);
1223
- }, "#br");
1224
- _join = new WeakSet();
1225
- join_fn = /* @__PURE__ */ __name(function(channel) {
1226
- return joinVoiceChannel({
1227
- channelId: channel.id,
1228
- guildId: this.id,
1229
- adapterCreator: channel.guild.voiceAdapterCreator,
1230
- group: channel.client.user?.id
1231
- });
1232
- }, "#join");
1233
-
1234
- // src/core/voice/DisTubeVoiceManager.ts
1235
- import { VoiceConnectionStatus as VoiceConnectionStatus2, getVoiceConnection } from "@discordjs/voice";
1236
- var DisTubeVoiceManager = class extends GuildIdManager {
1237
- create(channel) {
1238
- const existing = this.get(channel.guildId);
1239
- if (existing) {
1240
- existing.channel = channel;
1241
- return existing;
1088
+ if (queue.autoplay) {
1089
+ try {
1090
+ await queue.addRelatedSong();
1091
+ } catch {
1092
+ this.emit("noRelated", queue);
1093
+ }
1094
+ }
1095
+ if (queue.songs.length <= 1) {
1096
+ if (this.options.leaveOnFinish)
1097
+ queue.voice.leave();
1098
+ if (!queue.autoplay)
1099
+ this.emit("finish", queue);
1100
+ queue.remove();
1101
+ return;
1102
+ }
1242
1103
  }
1243
- 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();
1244
1121
  }
1245
- join(channel) {
1246
- const existing = this.get(channel.guildId);
1247
- if (existing)
1248
- return existing.join(channel);
1249
- 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 {
1250
1132
  }
1251
- leave(guild) {
1252
- const voice = this.get(guild);
1253
- if (voice) {
1254
- voice.leave();
1255
- } else {
1256
- const connection = getVoiceConnection(resolveGuildId(guild), this.client.user?.id) ?? getVoiceConnection(resolveGuildId(guild));
1257
- if (connection && connection.state.status !== VoiceConnectionStatus2.Destroyed) {
1258
- connection.destroy();
1259
- }
1260
- }
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();
1261
1141
  }
1262
- };
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");
1263
1147
 
1264
1148
  // src/core/DisTubeHandler.ts
1265
- import ytdl from "@distube/ytdl-core";
1266
1149
  import ytpl from "@distube/ytpl";
1150
+ import ytdl from "@distube/ytdl-core";
1267
1151
  var DisTubeHandler = class extends DisTubeBase {
1268
1152
  constructor(distube) {
1269
1153
  super(distube);
@@ -1327,11 +1211,10 @@ var DisTubeHandler = class extends DisTubeBase {
1327
1211
  song.member = options.member;
1328
1212
  return song;
1329
1213
  }
1330
- if (song instanceof SearchResult) {
1331
- if (song.type === "video" /* VIDEO */)
1332
- return new Song(song, options);
1214
+ if (song instanceof SearchResultVideo)
1215
+ return new Song(song, options);
1216
+ if (song instanceof SearchResultPlaylist)
1333
1217
  return this.resolvePlaylist(song.url, options);
1334
- }
1335
1218
  if (isObject(song))
1336
1219
  return new Song(song, options);
1337
1220
  if (ytpl.validateID(song))
@@ -1356,14 +1239,19 @@ var DisTubeHandler = class extends DisTubeBase {
1356
1239
  playlist.member = member;
1357
1240
  return playlist;
1358
1241
  }
1359
- let solvablePlaylist;
1360
1242
  if (typeof playlist === "string") {
1361
- solvablePlaylist = await ytpl(playlist, { limit: Infinity });
1362
- solvablePlaylist.items = solvablePlaylist.items.filter((v) => !v.thumbnail.includes("no_thumbnail")).map((v) => new Song(v, { member, metadata }));
1363
- } else {
1364
- solvablePlaylist = playlist;
1365
- }
1366
- 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 });
1367
1255
  }
1368
1256
  async searchSong(message, query) {
1369
1257
  if (!isMessageInstance(message))
@@ -1495,6 +1383,187 @@ var DisTubeHandler = class extends DisTubeBase {
1495
1383
  }
1496
1384
  }
1497
1385
  };
1386
+ __name(DisTubeHandler, "DisTubeHandler");
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");
1498
1567
 
1499
1568
  // src/struct/Queue.ts
1500
1569
  var _filters;
@@ -1516,12 +1585,8 @@ var Queue = class extends DisTubeBase {
1516
1585
  __publicField(this, "beginTime");
1517
1586
  __publicField(this, "textChannel");
1518
1587
  __publicField(this, "_emptyTimeout");
1519
- __publicField(this, "clientMember");
1520
1588
  __publicField(this, "_taskQueue");
1521
1589
  __publicField(this, "_listeners");
1522
- this.clientMember = voice.channel.guild?.me ?? (() => {
1523
- throw new DisTubeError("INVALID_TYPE", "GuildMember", null, "<VoiceChannel>.guild.me");
1524
- })();
1525
1590
  this.voice = voice;
1526
1591
  this.id = voice.id;
1527
1592
  this.volume = 50;
@@ -1541,6 +1606,9 @@ var Queue = class extends DisTubeBase {
1541
1606
  this._taskQueue = new TaskQueue();
1542
1607
  this._listeners = void 0;
1543
1608
  }
1609
+ get clientMember() {
1610
+ return this.voice.channel.guild.members.me ?? void 0;
1611
+ }
1544
1612
  get filters() {
1545
1613
  return __privateGet(this, _filters);
1546
1614
  }
@@ -1557,7 +1625,7 @@ var Queue = class extends DisTubeBase {
1557
1625
  return formatDuration(this.currentTime);
1558
1626
  }
1559
1627
  get voiceChannel() {
1560
- return this.clientMember.voice.channel;
1628
+ return this.clientMember?.voice?.channel ?? null;
1561
1629
  }
1562
1630
  get volume() {
1563
1631
  return this.voice.volume;
@@ -1755,6 +1823,7 @@ var Queue = class extends DisTubeBase {
1755
1823
  return this.autoplay;
1756
1824
  }
1757
1825
  };
1826
+ __name(Queue, "Queue");
1758
1827
  _filters = new WeakMap();
1759
1828
 
1760
1829
  // src/struct/Plugin.ts
@@ -1796,6 +1865,7 @@ var Plugin = class {
1796
1865
  return [];
1797
1866
  }
1798
1867
  };
1868
+ __name(Plugin, "Plugin");
1799
1869
 
1800
1870
  // src/struct/CustomPlugin.ts
1801
1871
  var CustomPlugin = class extends Plugin {
@@ -1804,6 +1874,7 @@ var CustomPlugin = class extends Plugin {
1804
1874
  __publicField(this, "type", "custom" /* CUSTOM */);
1805
1875
  }
1806
1876
  };
1877
+ __name(CustomPlugin, "CustomPlugin");
1807
1878
 
1808
1879
  // src/struct/ExtractorPlugin.ts
1809
1880
  var ExtractorPlugin = class extends Plugin {
@@ -1812,6 +1883,7 @@ var ExtractorPlugin = class extends Plugin {
1812
1883
  __publicField(this, "type", "extractor" /* EXTRACTOR */);
1813
1884
  }
1814
1885
  };
1886
+ __name(ExtractorPlugin, "ExtractorPlugin");
1815
1887
 
1816
1888
  // src/util.ts
1817
1889
  import { URL } from "url";
@@ -1829,6 +1901,7 @@ function formatDuration(sec) {
1829
1901
  return `${formatInt(minutes)}:${formatInt(seconds)}`;
1830
1902
  return `00:${formatInt(seconds)}`;
1831
1903
  }
1904
+ __name(formatDuration, "formatDuration");
1832
1905
  function toSecond(input) {
1833
1906
  if (!input)
1834
1907
  return 0;
@@ -1847,11 +1920,13 @@ function toSecond(input) {
1847
1920
  return Number(input.replace(/[^\d.]+/g, "")) || 0;
1848
1921
  }
1849
1922
  }
1923
+ __name(toSecond, "toSecond");
1850
1924
  function parseNumber(input) {
1851
1925
  if (typeof input === "string")
1852
1926
  return Number(input.replace(/[^\d.]+/g, "")) || 0;
1853
1927
  return Number(input) || 0;
1854
1928
  }
1929
+ __name(parseNumber, "parseNumber");
1855
1930
  function isURL(input) {
1856
1931
  if (typeof input !== "string" || input.includes(" "))
1857
1932
  return false;
@@ -1864,18 +1939,25 @@ function isURL(input) {
1864
1939
  }
1865
1940
  return true;
1866
1941
  }
1942
+ __name(isURL, "isURL");
1867
1943
  function checkIntents(options) {
1868
1944
  const intents = new IntentsBitField(options.intents);
1869
1945
  if (!intents.has(GatewayIntentBits.GuildVoiceStates))
1870
1946
  throw new DisTubeError("MISSING_INTENTS", "GuildVoiceStates");
1871
1947
  }
1948
+ __name(checkIntents, "checkIntents");
1872
1949
  function isVoiceChannelEmpty(voiceState) {
1873
- const voiceChannel = voiceState.guild?.me?.voice?.channel;
1950
+ const guild = voiceState.guild;
1951
+ const clientId = voiceState.client.user?.id;
1952
+ if (!guild || !clientId)
1953
+ return false;
1954
+ const voiceChannel = guild.members.me?.voice?.channel;
1874
1955
  if (!voiceChannel)
1875
1956
  return false;
1876
1957
  const members = voiceChannel.members.filter((m) => !m.user.bot);
1877
1958
  return !members.size;
1878
1959
  }
1960
+ __name(isVoiceChannelEmpty, "isVoiceChannelEmpty");
1879
1961
  function isSnowflake(id) {
1880
1962
  try {
1881
1963
  return SnowflakeUtil.deconstruct(id).timestamp > SnowflakeUtil.epoch;
@@ -1883,21 +1965,27 @@ function isSnowflake(id) {
1883
1965
  return false;
1884
1966
  }
1885
1967
  }
1968
+ __name(isSnowflake, "isSnowflake");
1886
1969
  function isMemberInstance(member) {
1887
1970
  return !!member && isSnowflake(member.id) && isSnowflake(member.guild?.id) && isSnowflake(member.user?.id) && member.id === member.user.id;
1888
1971
  }
1972
+ __name(isMemberInstance, "isMemberInstance");
1889
1973
  function isTextChannelInstance(channel) {
1890
- return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) && typeof channel.name === "string" && Constants.TextBasedChannelTypes.includes(channel.type);
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";
1891
1975
  }
1976
+ __name(isTextChannelInstance, "isTextChannelInstance");
1892
1977
  function isMessageInstance(message) {
1893
1978
  return !!message && isSnowflake(message.id) && isSnowflake(message.guildId) && isMemberInstance(message.member) && isTextChannelInstance(message.channel) && Constants.NonSystemMessageTypes.includes(message.type) && message.member.id === message.author?.id;
1894
1979
  }
1980
+ __name(isMessageInstance, "isMessageInstance");
1895
1981
  function isSupportedVoiceChannel(channel) {
1896
1982
  return !!channel && isSnowflake(channel.id) && isSnowflake(channel.guildId) && Constants.VoiceBasedChannelTypes.includes(channel.type);
1897
1983
  }
1984
+ __name(isSupportedVoiceChannel, "isSupportedVoiceChannel");
1898
1985
  function isGuildInstance(guild) {
1899
1986
  return !!guild && isSnowflake(guild.id) && isSnowflake(guild.ownerId) && typeof guild.name === "string";
1900
1987
  }
1988
+ __name(isGuildInstance, "isGuildInstance");
1901
1989
  function resolveGuildId(resolvable) {
1902
1990
  let guildId;
1903
1991
  if (typeof resolvable === "string") {
@@ -1915,9 +2003,11 @@ function resolveGuildId(resolvable) {
1915
2003
  throw new DisTubeError("INVALID_TYPE", "GuildIdResolvable", resolvable);
1916
2004
  return guildId;
1917
2005
  }
2006
+ __name(resolveGuildId, "resolveGuildId");
1918
2007
  function isClientInstance(client) {
1919
2008
  return !!client && typeof client.login === "function";
1920
2009
  }
2010
+ __name(isClientInstance, "isClientInstance");
1921
2011
  function checkInvalidKey(target, source, sourceName) {
1922
2012
  if (!isObject(target))
1923
2013
  throw new DisTubeError("INVALID_TYPE", "object", target, sourceName);
@@ -1926,38 +2016,15 @@ function checkInvalidKey(target, source, sourceName) {
1926
2016
  if (invalidKey)
1927
2017
  throw new DisTubeError("INVALID_KEY", sourceName, invalidKey);
1928
2018
  }
1929
- async function waitEvent(target, status, maxTime) {
1930
- let cleanup = /* @__PURE__ */ __name(() => {
1931
- }, "cleanup");
1932
- try {
1933
- await new Promise((resolve, reject) => {
1934
- const timeout = setTimeout(() => reject(new Error(`Didn't trigger ${status} within ${maxTime}ms`)), maxTime);
1935
- target.once(status, resolve);
1936
- target.once("error", reject);
1937
- cleanup = /* @__PURE__ */ __name(() => {
1938
- clearTimeout(timeout);
1939
- target.off(status, resolve);
1940
- target.off("error", reject);
1941
- }, "cleanup");
1942
- if (target?.state?.status === status)
1943
- resolve(0);
1944
- });
1945
- return target;
1946
- } finally {
1947
- cleanup();
1948
- }
1949
- }
1950
- async function entersState(target, status, maxTime) {
1951
- if (target.state.status === status)
1952
- return target;
1953
- return waitEvent(target, status, maxTime);
1954
- }
2019
+ __name(checkInvalidKey, "checkInvalidKey");
1955
2020
  function isObject(obj) {
1956
2021
  return typeof obj === "object" && obj !== null && !Array.isArray(obj);
1957
2022
  }
2023
+ __name(isObject, "isObject");
1958
2024
  function isRecord(obj) {
1959
2025
  return isObject(obj);
1960
2026
  }
2027
+ __name(isRecord, "isRecord");
1961
2028
 
1962
2029
  // src/plugin/http.ts
1963
2030
  import http from "http";
@@ -1969,6 +2036,7 @@ var HTTPPlugin = class extends ExtractorPlugin {
1969
2036
  return resolveHttpSong(url, { ...options, source: "http" });
1970
2037
  }
1971
2038
  };
2039
+ __name(HTTPPlugin, "HTTPPlugin");
1972
2040
 
1973
2041
  // src/plugin/https.ts
1974
2042
  import https from "https";
@@ -2003,6 +2071,7 @@ var HTTPSPlugin = class extends ExtractorPlugin {
2003
2071
  return resolveHttpSong(url, { ...options, source: "https" });
2004
2072
  }
2005
2073
  };
2074
+ __name(HTTPSPlugin, "HTTPSPlugin");
2006
2075
 
2007
2076
  // src/DisTube.ts
2008
2077
  import ytsr from "@distube/ytsr";
@@ -2047,7 +2116,7 @@ var DisTube = class extends TypedEmitter2 {
2047
2116
  if (!isObject(options))
2048
2117
  throw new DisTubeError("INVALID_TYPE", "object", options, "options");
2049
2118
  const { textChannel, member, skip, message, metadata } = {
2050
- member: voiceChannel.guild.me ?? void 0,
2119
+ member: voiceChannel.guild.members.me ?? void 0,
2051
2120
  textChannel: options?.message?.channel,
2052
2121
  skip: false,
2053
2122
  ...options
@@ -2095,12 +2164,12 @@ var DisTube = class extends TypedEmitter2 {
2095
2164
  if (!(e instanceof DisTubeError)) {
2096
2165
  try {
2097
2166
  e.name = "PlayError";
2098
- e.message = `${song?.url || song}
2167
+ e.message = `${typeof song === "string" ? song : song.url}
2099
2168
  ${e.message}`;
2100
2169
  } catch {
2101
2170
  }
2102
2171
  }
2103
- this.emitError(e, textChannel);
2172
+ throw e;
2104
2173
  } finally {
2105
2174
  if (queuing)
2106
2175
  queue?._taskQueue.resolve();
@@ -2112,7 +2181,7 @@ ${e.message}`;
2112
2181
  throw new DisTubeError("INVALID_TYPE", "Array", songs, "songs");
2113
2182
  if (!songs.length)
2114
2183
  throw new DisTubeError("EMPTY_ARRAY", "songs");
2115
- 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 */);
2116
2185
  if (!filteredSongs.length)
2117
2186
  throw new DisTubeError("NO_VALID_SONG");
2118
2187
  if (member && !isMemberInstance(member)) {
@@ -2134,7 +2203,7 @@ ${e.message}`;
2134
2203
  return new Playlist(resolvedSongs, { member, properties, metadata });
2135
2204
  }
2136
2205
  async search(string, options = {}) {
2137
- const opts = { type: "video", limit: 10, safeSearch: false, ...options };
2206
+ const opts = { type: "video" /* VIDEO */, limit: 10, safeSearch: false, ...options };
2138
2207
  if (typeof opts.type !== "string" || !["video", "playlist"].includes(opts.type)) {
2139
2208
  throw new DisTubeError("INVALID_TYPE", ["video", "playlist"], opts.type, "options.type");
2140
2209
  }
@@ -2147,7 +2216,11 @@ ${e.message}`;
2147
2216
  }
2148
2217
  try {
2149
2218
  const search = await ytsr(string, opts);
2150
- 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
+ });
2151
2224
  if (results.length === 0)
2152
2225
  throw new DisTubeError("NO_RESULT");
2153
2226
  return results;
@@ -2244,6 +2317,7 @@ ${e.message}`;
2244
2317
  }
2245
2318
  }
2246
2319
  };
2320
+ __name(DisTube, "DisTube");
2247
2321
  export {
2248
2322
  BaseManager,
2249
2323
  CustomPlugin,
@@ -2266,9 +2340,11 @@ export {
2266
2340
  Queue,
2267
2341
  QueueManager,
2268
2342
  RepeatMode,
2269
- SearchResult,
2343
+ SearchResultPlaylist,
2270
2344
  SearchResultType,
2345
+ SearchResultVideo,
2271
2346
  Song,
2347
+ StreamType,
2272
2348
  TaskQueue,
2273
2349
  checkIntents,
2274
2350
  checkInvalidKey,
@@ -2276,7 +2352,6 @@ export {
2276
2352
  DisTube as default,
2277
2353
  defaultFilters,
2278
2354
  defaultOptions,
2279
- entersState,
2280
2355
  formatDuration,
2281
2356
  getResponseHeaders,
2282
2357
  isClientInstance,