distube 4.2.1 → 5.0.0

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.d.ts CHANGED
@@ -1,33 +1,39 @@
1
- import * as ytdl from '@distube/ytdl-core';
2
- import ytdl__default, { Cookie } from '@distube/ytdl-core';
3
1
  import * as discord_js from 'discord.js';
4
- import { GuildTextBasedChannel, Message, Snowflake, VoiceBasedChannel, VoiceState, Guild, GuildMember, Interaction, Client, Collection, ClientOptions } from 'discord.js';
5
- import ytpl from '@distube/ytpl';
6
- import { Video, Playlist as Playlist$1 } from '@distube/ytsr';
2
+ import { Snowflake, Message, GuildTextBasedChannel, VoiceBasedChannel, VoiceState, Guild, GuildMember, Interaction, Client, Collection, ClientOptions } from 'discord.js';
7
3
  import { TypedEmitter } from 'tiny-typed-emitter';
8
- import { AudioPlayer, VoiceConnection, AudioResource, StreamType as StreamType$1 } from '@discordjs/voice';
9
- import { PassThrough } from 'node:stream';
4
+ import { AudioPlayer, VoiceConnection, AudioResource } from '@discordjs/voice';
5
+ import { Transform, TransformCallback } from 'stream';
10
6
  import { ChildProcess } from 'child_process';
11
7
 
12
8
  type Awaitable<T = any> = T | PromiseLike<T>;
9
+ declare enum Events {
10
+ ERROR = "error",
11
+ ADD_LIST = "addList",
12
+ ADD_SONG = "addSong",
13
+ PLAY_SONG = "playSong",
14
+ FINISH_SONG = "finishSong",
15
+ EMPTY = "empty",
16
+ FINISH = "finish",
17
+ INIT_QUEUE = "initQueue",
18
+ NO_RELATED = "noRelated",
19
+ DISCONNECT = "disconnect",
20
+ DELETE_QUEUE = "deleteQueue",
21
+ FFMPEG_DEBUG = "ffmpegDebug",
22
+ DEBUG = "debug"
23
+ }
13
24
  type DisTubeEvents = {
14
- addList: [queue: Queue, playlist: Playlist];
15
- addSong: [queue: Queue, song: Song];
16
- deleteQueue: [queue: Queue];
17
- disconnect: [queue: Queue];
18
- empty: [queue: Queue];
19
- error: [channel: GuildTextBasedChannel | undefined, error: Error];
20
- ffmpegDebug: [debug: string];
21
- finish: [queue: Queue];
22
- finishSong: [queue: Queue, song: Song];
23
- initQueue: [queue: Queue];
24
- noRelated: [queue: Queue];
25
- playSong: [queue: Queue, song: Song];
26
- searchCancel: [message: Message<true>, query: string];
27
- searchDone: [message: Message<true>, answer: Message<true>, query: string];
28
- searchInvalidAnswer: [message: Message<true>, answer: Message<true>, query: string];
29
- searchNoResult: [message: Message<true>, query: string];
30
- searchResult: [message: Message<true>, results: SearchResult[], query: string];
25
+ [Events.ADD_LIST]: [queue: Queue, playlist: Playlist];
26
+ [Events.ADD_SONG]: [queue: Queue, song: Song];
27
+ [Events.DELETE_QUEUE]: [queue: Queue];
28
+ [Events.DISCONNECT]: [queue: Queue];
29
+ [Events.ERROR]: [error: Error, queue: Queue, song: Song | undefined];
30
+ [Events.FFMPEG_DEBUG]: [debug: string];
31
+ [Events.DEBUG]: [debug: string];
32
+ [Events.FINISH]: [queue: Queue];
33
+ [Events.FINISH_SONG]: [queue: Queue, song: Song];
34
+ [Events.INIT_QUEUE]: [queue: Queue];
35
+ [Events.NO_RELATED]: [queue: Queue, error: DisTubeError];
36
+ [Events.PLAY_SONG]: [queue: Queue, song: Song];
31
37
  };
32
38
  type TypedDisTubeEvents = {
33
39
  [K in keyof DisTubeEvents]: (...args: DisTubeEvents[K]) => Awaitable;
@@ -39,7 +45,6 @@ type DisTubeVoiceEvents = {
39
45
  };
40
46
  /**
41
47
  * An FFmpeg audio filter object
42
- *
43
48
  * ```ts
44
49
  * {
45
50
  * name: "bassboost",
@@ -59,24 +64,20 @@ interface Filter {
59
64
  }
60
65
  /**
61
66
  * Data that resolves to give an FFmpeg audio filter. This can be:
62
- *
63
67
  * - A name of a default filters or custom filters (`string`)
64
68
  * - A {@link Filter} object
65
- *
66
69
  * @see {@link defaultFilters}
67
70
  * @see {@link DisTubeOptions|DisTubeOptions.customFilters}
68
71
  */
69
72
  type FilterResolvable = string | Filter;
70
73
  /**
71
74
  * FFmpeg Filters
72
- *
73
75
  * ```ts
74
76
  * {
75
77
  * "Filter Name": "Filter Value",
76
78
  * "bassboost": "bass=g=10"
77
79
  * }
78
- * ```ts
79
- *
80
+ * ```
80
81
  * @see {@link defaultFilters}
81
82
  */
82
83
  type Filters = Record<string, string>;
@@ -85,59 +86,24 @@ type Filters = Record<string, string>;
85
86
  */
86
87
  type DisTubeOptions = {
87
88
  /**
88
- * DisTube plugins
89
+ * DisTube plugins.
90
+ * The order of this effects the priority of the plugins when verifying the input.
89
91
  */
90
- plugins?: (CustomPlugin | ExtractorPlugin)[];
92
+ plugins?: DisTubePlugin[];
91
93
  /**
92
- * Whether or not emitting {@link DisTube#playSong} event when looping a song
94
+ * Whether or not emitting {@link Events.PLAY_SONG} event when looping a song
93
95
  * or next song is the same as the previous one
94
96
  */
95
97
  emitNewSongOnly?: boolean;
96
- /**
97
- * Whether or not leaving voice channel if the voice channel is empty after {@link
98
- * DisTubeOptions}.emptyCooldown seconds
99
- */
100
- leaveOnEmpty?: boolean;
101
- /**
102
- * Whether or not leaving voice channel when the queue ends
103
- */
104
- leaveOnFinish?: boolean;
105
- /**
106
- * Whether or not leaving voice channel after using {@link DisTube#stop} function
107
- */
108
- leaveOnStop?: boolean;
109
- /**
110
- * Built-in leave on empty cooldown in seconds (When leaveOnEmpty is true)
111
- */
112
- emptyCooldown?: number;
113
98
  /**
114
99
  * Whether or not saving the previous songs of the queue and enable {@link
115
- * DisTube#previous} method
100
+ * DisTube#previous} method. Disable it may help to reduce the memory usage
116
101
  */
117
102
  savePreviousSongs?: boolean;
118
- /**
119
- * Limit of search results emits in {@link DisTube#searchResult} event when
120
- * {@link DisTube#play} method executed. If `searchSongs <= 1`, play the first
121
- * result
122
- */
123
- searchSongs?: number;
124
- /**
125
- * Built-in search cooldown in seconds (When searchSongs is bigger than 0)
126
- */
127
- searchCooldown?: number;
128
- /**
129
- * YouTube cookies. Guide: {@link
130
- * https://github.com/skick1234/DisTube/wiki/YouTube-Cookies | YouTube Cookies}
131
- */
132
- youtubeCookie?: Cookie[] | string;
133
103
  /**
134
104
  * Override {@link defaultFilters} or add more ffmpeg filters
135
105
  */
136
106
  customFilters?: Filters;
137
- /**
138
- * `ytdl-core` get info options
139
- */
140
- ytdlOptions?: ytdl__default.downloadOptions;
141
107
  /**
142
108
  * Whether or not playing age-restricted content and disabling safe search in
143
109
  * non-NSFW channel
@@ -156,25 +122,6 @@ type DisTubeOptions = {
156
122
  * method
157
123
  */
158
124
  joinNewVoiceChannel?: boolean;
159
- /**
160
- * Decide the {@link DisTubeStream#type} will be used (Not the same as {@link
161
- * DisTubeStream#type})
162
- */
163
- streamType?: StreamType;
164
- /**
165
- * Whether or not playing a song with direct link
166
- */
167
- directLink?: boolean;
168
- /**
169
- * FFmpeg path
170
- * @deprecated
171
- */
172
- ffmpegPath?: string;
173
- /**
174
- * FFmpeg default arguments
175
- * @deprecated
176
- */
177
- ffmpegDefaultArgs?: FFmpegArgs;
178
125
  /**
179
126
  * FFmpeg options
180
127
  */
@@ -186,16 +133,11 @@ type DisTubeOptions = {
186
133
  /**
187
134
  * FFmpeg default arguments
188
135
  */
189
- args?: {
190
- global?: FFmpegArgs;
191
- input?: FFmpegArgs;
192
- output?: FFmpegArgs;
193
- };
136
+ args?: Partial<FFmpegArgs>;
194
137
  };
195
138
  };
196
139
  /**
197
140
  * Data that can be resolved to give a guild id string. This can be:
198
- *
199
141
  * - A guild id string | a guild {@link https://discord.js.org/#/docs/main/stable/class/Snowflake|Snowflake}
200
142
  * - A {@link https://discord.js.org/#/docs/main/stable/class/Guild | Guild}
201
143
  * - A {@link https://discord.js.org/#/docs/main/stable/class/Message | Message}
@@ -213,55 +155,34 @@ type DisTubeOptions = {
213
155
  * - A {@link Queue}
214
156
  */
215
157
  type GuildIdResolvable = Queue | DisTubeVoice | Snowflake | Message | GuildTextBasedChannel | VoiceBasedChannel | VoiceState | Guild | GuildMember | Interaction | string;
216
- interface OtherSongInfo {
217
- src: string;
158
+ interface SongInfo {
159
+ plugin: DisTubePlugin | null;
160
+ source: string;
161
+ playFromSource: boolean;
162
+ streamURL?: string;
218
163
  id?: string;
219
- title?: string;
220
164
  name?: string;
221
- is_live?: boolean;
222
165
  isLive?: boolean;
223
- _duration_raw?: string | number;
224
- duration?: string | number;
225
- webpage_url?: string;
226
- url: string;
166
+ duration?: number;
167
+ url?: string;
227
168
  thumbnail?: string;
228
- related?: RelatedSong[];
229
- view_count?: string | number;
230
- views?: string | number;
231
- like_count?: string | number;
232
- likes?: string | number;
233
- dislike_count?: string | number;
234
- dislikes?: string | number;
235
- repost_count?: string | number;
236
- reposts?: string | number;
237
- uploader?: string | {
238
- name: string;
239
- url: string;
169
+ views?: number;
170
+ likes?: number;
171
+ dislikes?: number;
172
+ reposts?: number;
173
+ uploader?: {
174
+ name?: string;
175
+ url?: string;
240
176
  };
241
- uploader_url?: string;
242
- age_limit?: string | number;
243
- chapters?: Chapter[];
244
- age_restricted?: boolean;
245
- }
246
- interface Chapter {
247
- title: string;
248
- start_time: number;
177
+ ageRestricted?: boolean;
249
178
  }
250
179
  interface PlaylistInfo {
251
180
  source: string;
252
- member?: GuildMember;
253
181
  songs: Song[];
182
+ id?: string;
254
183
  name?: string;
255
184
  url?: string;
256
185
  thumbnail?: string;
257
- /**
258
- * @deprecated Use {@link PlaylistInfo#name}
259
- */
260
- title?: string;
261
- /**
262
- * @deprecated Use {@link PlaylistInfo#url}
263
- */
264
- webpage_url?: string;
265
186
  }
266
187
  type RelatedSong = Omit<Song, "related">;
267
188
  type PlayHandlerOptions = {
@@ -280,7 +201,7 @@ type PlayHandlerOptions = {
280
201
  */
281
202
  textChannel?: GuildTextBasedChannel;
282
203
  };
283
- interface PlayOptions extends PlayHandlerOptions, ResolveOptions<any> {
204
+ interface PlayOptions<T = unknown> extends PlayHandlerOptions, ResolveOptions<T> {
284
205
  /**
285
206
  * Called message (For built-in search events. If this is a {@link
286
207
  * https://developer.mozilla.org/en-US/docs/Glossary/Falsy | falsy value}, it will
@@ -309,10 +230,6 @@ interface CustomPlaylistOptions {
309
230
  * A guild member creating the playlist
310
231
  */
311
232
  member?: GuildMember;
312
- /**
313
- * Additional properties such as `name`
314
- */
315
- properties?: Record<string, any>;
316
233
  /**
317
234
  * Whether or not fetch the songs in parallel
318
235
  */
@@ -321,10 +238,25 @@ interface CustomPlaylistOptions {
321
238
  * Metadata
322
239
  */
323
240
  metadata?: any;
241
+ /**
242
+ * Playlist name
243
+ */
244
+ name?: string;
245
+ /**
246
+ * Playlist source
247
+ */
248
+ source?: string;
249
+ /**
250
+ * Playlist url
251
+ */
252
+ url?: string;
253
+ /**
254
+ * Playlist thumbnail
255
+ */
256
+ thumbnail?: string;
324
257
  }
325
258
  /**
326
259
  * The repeat mode of a {@link Queue}
327
- *
328
260
  * - `DISABLED` = 0
329
261
  * - `SONG` = 1
330
262
  * - `QUEUE` = 2
@@ -336,61 +268,37 @@ declare enum RepeatMode {
336
268
  }
337
269
  /**
338
270
  * All available plugin types:
339
- *
340
- * - `CUSTOM` = `"custom"`: {@link CustomPlugin}
341
271
  * - `EXTRACTOR` = `"extractor"`: {@link ExtractorPlugin}
272
+ * - `INFO_EXTRACTOR` = `"info-extractor"`: {@link InfoExtractorPlugin}
273
+ * - `PLAYABLE_EXTRACTOR` = `"playable-extractor"`: {@link PlayableExtractorPlugin}
342
274
  */
343
275
  declare enum PluginType {
344
- CUSTOM = "custom",
345
- EXTRACTOR = "extractor"
276
+ EXTRACTOR = "extractor",
277
+ INFO_EXTRACTOR = "info-extractor",
278
+ PLAYABLE_EXTRACTOR = "playable-extractor"
346
279
  }
280
+ type DisTubePlugin = ExtractorPlugin | InfoExtractorPlugin | PlayableExtractorPlugin;
281
+ type FFmpegArg = Record<string, string | number | boolean | Array<string | null | undefined> | null | undefined>;
347
282
  /**
348
- * Search result types:
349
- *
350
- * - `VIDEO` = `"video"`
351
- * - `PLAYLIST` = `"playlist"`
283
+ * FFmpeg arguments for different use cases
352
284
  */
353
- declare enum SearchResultType {
354
- VIDEO = "video",
355
- PLAYLIST = "playlist"
356
- }
285
+ type FFmpegArgs = {
286
+ global: FFmpegArg;
287
+ input: FFmpegArg;
288
+ output: FFmpegArg;
289
+ };
357
290
  /**
358
- * Stream types:
359
- *
360
- * - `OPUS` = `0` (Better quality, use more resources - **Recommended**)
361
- * - `RAW` = `1` (Better performance, use less resources)
291
+ * FFmpeg options
362
292
  */
363
- declare enum StreamType {
364
- OPUS = 0,
365
- RAW = 1
366
- }
367
- declare enum Events {
368
- ERROR = "error",
369
- ADD_LIST = "addList",
370
- ADD_SONG = "addSong",
371
- PLAY_SONG = "playSong",
372
- FINISH_SONG = "finishSong",
373
- EMPTY = "empty",
374
- FINISH = "finish",
375
- INIT_QUEUE = "initQueue",
376
- NO_RELATED = "noRelated",
377
- DISCONNECT = "disconnect",
378
- DELETE_QUEUE = "deleteQueue",
379
- SEARCH_CANCEL = "searchCancel",
380
- SEARCH_NO_RESULT = "searchNoResult",
381
- SEARCH_DONE = "searchDone",
382
- SEARCH_INVALID_ANSWER = "searchInvalidAnswer",
383
- SEARCH_RESULT = "searchResult",
384
- FFMPEG_DEBUG = "ffmpegDebug"
385
- }
386
- type FFmpegArgs = Record<string, string | number | boolean | Array<string | null | undefined> | null | undefined>;
387
293
  type FFmpegOptions = {
294
+ /**
295
+ * Path to the ffmpeg executable
296
+ */
388
297
  path: string;
389
- args: {
390
- global: FFmpegArgs;
391
- input: FFmpegArgs;
392
- output: FFmpegArgs;
393
- };
298
+ /**
299
+ * Arguments
300
+ */
301
+ args: FFmpegArgs;
394
302
  };
395
303
 
396
304
  /**
@@ -400,20 +308,11 @@ declare const defaultFilters: Filters;
400
308
  declare const defaultOptions: {
401
309
  plugins: never[];
402
310
  emitNewSongOnly: false;
403
- leaveOnEmpty: true;
404
- leaveOnFinish: false;
405
- leaveOnStop: true;
406
311
  savePreviousSongs: true;
407
- searchSongs: number;
408
- ytdlOptions: {};
409
- searchCooldown: number;
410
- emptyCooldown: number;
411
312
  nsfw: false;
412
313
  emitAddSongWhenCreatingQueue: true;
413
314
  emitAddListWhenCreatingQueue: true;
414
315
  joinNewVoiceChannel: true;
415
- streamType: StreamType.OPUS;
416
- directLink: true;
417
316
  };
418
317
 
419
318
  declare const ERROR_MESSAGES: {
@@ -430,6 +329,7 @@ declare const ERROR_MESSAGES: {
430
329
  ENABLED_OPTION: (o: string) => string;
431
330
  NOT_IN_VOICE: string;
432
331
  VOICE_FULL: string;
332
+ VOICE_ALREADY_CREATED: string;
433
333
  VOICE_CONNECT_FAILED: (s: number) => string;
434
334
  VOICE_MISSING_PERMS: string;
435
335
  VOICE_RECONNECT_FAILED: string;
@@ -439,21 +339,26 @@ declare const ERROR_MESSAGES: {
439
339
  FFMPEG_NOT_INSTALLED: (path: string) => string;
440
340
  NO_QUEUE: string;
441
341
  QUEUE_EXIST: string;
342
+ QUEUE_STOPPED: string;
442
343
  PAUSED: string;
443
344
  RESUMED: string;
444
345
  NO_PREVIOUS: string;
445
346
  NO_UP_NEXT: string;
446
347
  NO_SONG_POSITION: string;
447
- NO_PLAYING: string;
448
- NO_RESULT: string;
348
+ NO_PLAYING_SONG: string;
449
349
  NO_RELATED: string;
450
350
  CANNOT_PLAY_RELATED: string;
451
351
  UNAVAILABLE_VIDEO: string;
452
352
  UNPLAYABLE_FORMATS: string;
453
353
  NON_NSFW: string;
454
354
  NOT_SUPPORTED_URL: string;
455
- CANNOT_RESOLVE_SONG: (t: any) => string;
355
+ NOT_SUPPORTED_SONG: (song: string) => string;
456
356
  NO_VALID_SONG: string;
357
+ CANNOT_RESOLVE_SONG: (t: any) => string;
358
+ CANNOT_GET_STREAM_URL: (song: string) => string;
359
+ CANNOT_GET_SEARCH_QUERY: (song: string) => string;
360
+ NO_RESULT: (query: string) => string;
361
+ NO_STREAM_URL: (song: string) => string;
457
362
  EMPTY_FILTERED_PLAYLIST: string;
458
363
  EMPTY_PLAYLIST: string;
459
364
  };
@@ -463,12 +368,12 @@ type StaticErrorCode = {
463
368
  [K in ErrorCode]-?: ErrorMessage[K] extends string ? K : never;
464
369
  }[ErrorCode];
465
370
  type TemplateErrorCode = Exclude<keyof typeof ERROR_MESSAGES, StaticErrorCode>;
466
- declare class DisTubeError<T extends string> extends Error {
371
+ declare class DisTubeError<T extends string = any> extends Error {
467
372
  errorCode: string;
468
- constructor(code: StaticErrorCode);
373
+ constructor(code: T extends StaticErrorCode ? T : never);
469
374
  constructor(code: T extends TemplateErrorCode ? T : never, ...args: Parameters<ErrorMessage[typeof code]>);
470
375
  constructor(code: TemplateErrorCode, _: never);
471
- constructor(code: T extends ErrorCode ? "This is built-in error code" : T, message: string);
376
+ constructor(code: T extends ErrorCode ? never : T, message: string);
472
377
  get name(): string;
473
378
  get code(): string;
474
379
  }
@@ -480,10 +385,8 @@ declare class TaskQueue {
480
385
  #private;
481
386
  /**
482
387
  * Waits for last task finished and queues a new task
483
- *
484
- * @param resolveInfo - Whether the task is a resolving info task
485
388
  */
486
- queuing(resolveInfo?: boolean): Promise<void>;
389
+ queuing(): Promise<void>;
487
390
  /**
488
391
  * Removes the finished task and processes the next task
489
392
  */
@@ -492,10 +395,6 @@ declare class TaskQueue {
492
395
  * The remaining number of tasks
493
396
  */
494
397
  get remaining(): number;
495
- /**
496
- * Whether or not having a resolving info task
497
- */
498
- get hasResolveTask(): boolean;
499
398
  }
500
399
 
501
400
  /**
@@ -503,23 +402,36 @@ declare class TaskQueue {
503
402
  */
504
403
  declare class Playlist<T = unknown> implements PlaylistInfo {
505
404
  #private;
405
+ /**
406
+ * Playlist source.
407
+ */
506
408
  source: string;
409
+ /**
410
+ * Songs in the playlist.
411
+ */
507
412
  songs: Song[];
508
- name: string;
413
+ /**
414
+ * Playlist ID.
415
+ */
416
+ id?: string;
417
+ /**
418
+ * Playlist name.
419
+ */
420
+ name?: string;
421
+ /**
422
+ * Playlist URL.
423
+ */
509
424
  url?: string;
425
+ /**
426
+ * Playlist thumbnail.
427
+ */
510
428
  thumbnail?: string;
511
- [x: string]: any;
512
429
  /**
513
- * Create a playlist
514
- *
515
- * @param playlist - Playlist
516
- * @param options - Optional options
430
+ * Create a Playlist
431
+ * @param playlist - Raw playlist info
432
+ * @param options - Optional data
517
433
  */
518
- constructor(playlist: Song[] | PlaylistInfo, options?: {
519
- member?: GuildMember;
520
- properties?: Record<string, any>;
521
- metadata?: T;
522
- });
434
+ constructor(playlist: PlaylistInfo, { member, metadata }?: ResolveOptions<T>);
523
435
  /**
524
436
  * Playlist duration in second.
525
437
  */
@@ -537,146 +449,154 @@ declare class Playlist<T = unknown> implements PlaylistInfo {
537
449
  * User requested.
538
450
  */
539
451
  get user(): discord_js.User | undefined;
540
- get metadata(): T;
541
- set metadata(metadata: T);
542
- }
543
-
544
- /**
545
- * A abstract class representing a search result.
546
- *
547
- * @virtual
548
- */
549
- declare abstract class ISearchResult {
550
- source: "youtube";
551
- abstract type: SearchResultType;
552
- id: string;
553
- name: string;
554
- url: string;
555
- uploader: {
556
- name?: string;
557
- url?: string;
558
- };
559
452
  /**
560
- * Create a search result
561
- *
562
- * @param info - ytsr result
453
+ * Optional metadata that can be used to identify the playlist.
563
454
  */
564
- constructor(info: Video | Playlist$1);
565
- }
566
- /**
567
- * A class representing a video search result.
568
- */
569
- declare class SearchResultVideo extends ISearchResult {
570
- type: SearchResultType.VIDEO;
571
- views: number;
572
- isLive: boolean;
573
- duration: number;
574
- formattedDuration: string;
575
- thumbnail: string;
576
- constructor(info: Video);
577
- }
578
- /**
579
- * A video or playlist search result
580
- */
581
- type SearchResult = SearchResultVideo | SearchResultPlaylist;
582
- /**
583
- * A class representing a playlist search result.
584
- */
585
- declare class SearchResultPlaylist extends ISearchResult {
586
- type: SearchResultType.PLAYLIST;
587
- length: number;
588
- constructor(info: Playlist$1);
455
+ get metadata(): T;
456
+ set metadata(metadata: T);
589
457
  }
590
458
 
591
459
  /**
592
460
  * Class representing a song.
593
- *
594
- * <info>If {@link Song} is added from a YouTube {@link SearchResult} or {@link
595
- * Playlist}, some info will be missing to save your resources. It will be filled
596
- * when emitting {@link DisTube#playSong} event.
597
- *
598
- * Missing info: {@link Song#likes}, {@link Song#dislikes}, {@link Song#streamURL},
599
- * {@link Song#related}, {@link Song#chapters}, {@link Song#age_restricted}</info>
600
461
  */
601
462
  declare class Song<T = unknown> {
602
463
  #private;
464
+ /**
465
+ * The source of this song info
466
+ */
603
467
  source: string;
604
- formats?: ytdl__default.videoFormat[];
468
+ /**
469
+ * Song ID.
470
+ */
605
471
  id?: string;
472
+ /**
473
+ * Song name.
474
+ */
606
475
  name?: string;
607
- isLive: boolean;
476
+ /**
477
+ * Indicates if the song is an active live.
478
+ */
479
+ isLive?: boolean;
480
+ /**
481
+ * Song duration.
482
+ */
608
483
  duration: number;
609
- formattedDuration?: string;
610
- url: string;
611
- streamURL?: string;
484
+ /**
485
+ * Formatted duration string (`hh:mm:ss`, `mm:ss` or `Live`).
486
+ */
487
+ formattedDuration: string;
488
+ /**
489
+ * Song URL.
490
+ */
491
+ url?: string;
492
+ /**
493
+ * Song thumbnail.
494
+ */
612
495
  thumbnail?: string;
613
- related: RelatedSong[];
614
- views: number;
615
- likes: number;
616
- dislikes: number;
496
+ /**
497
+ * Song view count
498
+ */
499
+ views?: number;
500
+ /**
501
+ * Song like count
502
+ */
503
+ likes?: number;
504
+ /**
505
+ * Song dislike count
506
+ */
507
+ dislikes?: number;
508
+ /**
509
+ * Song repost (share) count
510
+ */
511
+ reposts?: number;
512
+ /**
513
+ * Song uploader
514
+ */
617
515
  uploader: {
618
516
  name?: string;
619
517
  url?: string;
620
518
  };
621
- age_restricted: boolean;
622
- chapters: Chapter[];
623
- reposts: number;
624
519
  /**
625
- * Create a Song
626
- *
627
- * @param info - Raw info
628
- * @param options - Optional options
520
+ * Whether or not an age-restricted content
629
521
  */
630
- constructor(info: ytdl__default.videoInfo | SearchResult | OtherSongInfo | ytdl__default.relatedVideo | RelatedSong | ytpl.result["items"][number], options?: {
631
- member?: GuildMember;
632
- source?: string;
633
- metadata?: T;
634
- });
635
- _patchYouTube(i: ytdl__default.videoInfo | SearchResult): void;
522
+ ageRestricted?: boolean;
636
523
  /**
637
- * Patch data from other source
524
+ * Stream info
525
+ */
526
+ stream: {
527
+ /**
528
+ * The stream of this song will be played from source
529
+ */
530
+ playFromSource: true;
531
+ /**
532
+ * Stream URL of this song
533
+ */
534
+ url?: string;
535
+ } | {
536
+ /**
537
+ * The stream of this song will be played from another song
538
+ */
539
+ playFromSource: false;
540
+ /**
541
+ * The song that this song will be played from
542
+ */
543
+ song?: Song<T>;
544
+ };
545
+ /**
546
+ * The plugin that created this song
547
+ */
548
+ plugin: DisTubePlugin | null;
549
+ /**
550
+ * Create a Song
638
551
  *
639
- * @param info - Video info
552
+ * @param info - Raw song info
553
+ * @param options - Optional data
640
554
  */
641
- _patchOther(info: OtherSongInfo): void;
555
+ constructor(info: SongInfo, { member, metadata }?: ResolveOptions<T>);
642
556
  /**
643
- * The playlist added this song
557
+ * The playlist this song belongs to
644
558
  */
645
559
  get playlist(): Playlist | undefined;
646
560
  set playlist(playlist: Playlist | undefined);
647
561
  /**
648
- * User requested.
562
+ * User requested to play this song.
649
563
  */
650
564
  get member(): GuildMember | undefined;
651
565
  set member(member: GuildMember | undefined);
652
566
  /**
653
- * User requested.
567
+ * User requested to play this song.
654
568
  */
655
569
  get user(): discord_js.User | undefined;
570
+ /**
571
+ * Optional metadata that can be used to identify the song. This is attached by the
572
+ * {@link DisTube#play} method.
573
+ */
656
574
  get metadata(): T;
657
575
  set metadata(metadata: T);
576
+ toString(): string;
658
577
  }
659
578
 
660
- /**
661
- * @virtual
662
- */
663
579
  declare abstract class DisTubeBase {
664
580
  distube: DisTube;
665
581
  constructor(distube: DisTube);
666
582
  /**
667
583
  * Emit the {@link DisTube} of this base
668
- *
669
584
  * @param eventName - Event name
670
585
  * @param args - arguments
671
586
  */
672
587
  emit(eventName: keyof DisTubeEvents, ...args: any): boolean;
673
588
  /**
674
589
  * Emit error event
675
- *
676
590
  * @param error - error
677
- * @param channel - Text channel where the error is encountered.
591
+ * @param queue - The queue encountered the error
592
+ * @param song - The playing song when encountered the error
593
+ */
594
+ emitError(error: Error, queue: Queue, song?: Song): void;
595
+ /**
596
+ * Emit debug event
597
+ * @param message - debug message
678
598
  */
679
- emitError(error: Error, channel?: GuildTextBasedChannel): void;
599
+ debug(message: string): void;
680
600
  /**
681
601
  * The queue manager
682
602
  */
@@ -697,6 +617,10 @@ declare abstract class DisTubeBase {
697
617
  * DisTube handler
698
618
  */
699
619
  get handler(): DisTubeHandler;
620
+ /**
621
+ * DisTube plugins
622
+ */
623
+ get plugins(): DisTubePlugin[];
700
624
  }
701
625
 
702
626
  /**
@@ -708,7 +632,6 @@ declare class DisTubeVoice extends TypedEmitter<DisTubeVoiceEvents> {
708
632
  readonly voices: DisTubeVoiceManager;
709
633
  readonly audioPlayer: AudioPlayer;
710
634
  connection: VoiceConnection;
711
- audioResource?: AudioResource;
712
635
  emittedError: boolean;
713
636
  isDisconnected: boolean;
714
637
  stream?: DisTubeStream;
@@ -721,30 +644,29 @@ declare class DisTubeVoice extends TypedEmitter<DisTubeVoiceEvents> {
721
644
  set channel(channel: VoiceBasedChannel);
722
645
  /**
723
646
  * Join a voice channel with this connection
724
- *
725
647
  * @param channel - A voice channel
726
648
  */
727
649
  join(channel?: VoiceBasedChannel): Promise<DisTubeVoice>;
728
650
  /**
729
651
  * Leave the voice channel of this connection
730
- *
731
652
  * @param error - Optional, an error to emit with 'error' event.
732
653
  */
733
654
  leave(error?: Error): void;
734
655
  /**
735
656
  * Stop the playing stream
736
- *
737
657
  * @param force - If true, will force the {@link DisTubeVoice#audioPlayer} to enter the Idle state even
738
- * if the {@link DisTubeVoice#audioResource} has silence padding frames.
658
+ * if the {@link DisTubeStream#audioResource} has silence padding frames.
739
659
  */
740
660
  stop(force?: boolean): void;
741
661
  /**
742
662
  * Play a {@link DisTubeStream}
743
- *
744
663
  * @param dtStream - DisTubeStream
745
664
  */
746
665
  play(dtStream: DisTubeStream): void;
747
666
  set volume(volume: number);
667
+ /**
668
+ * Get or set the volume percentage
669
+ */
748
670
  get volume(): number;
749
671
  /**
750
672
  * Playback duration of the audio resource in seconds
@@ -762,17 +684,13 @@ declare class DisTubeVoice extends TypedEmitter<DisTubeVoiceEvents> {
762
684
  get selfMute(): boolean;
763
685
  /**
764
686
  * Self-deafens/undeafens the bot.
765
- *
766
687
  * @param selfDeaf - Whether or not the bot should be self-deafened
767
- *
768
688
  * @returns true if the voice state was successfully updated, otherwise false
769
689
  */
770
690
  setSelfDeaf(selfDeaf: boolean): boolean;
771
691
  /**
772
692
  * Self-mutes/unmutes the bot.
773
- *
774
693
  * @param selfMute - Whether or not the bot should be self-muted
775
- *
776
694
  * @returns true if the voice state was successfully updated, otherwise false
777
695
  */
778
696
  setSelfMute(selfMute: boolean): boolean;
@@ -782,12 +700,20 @@ declare class DisTubeVoice extends TypedEmitter<DisTubeVoiceEvents> {
782
700
  get voiceState(): VoiceState | undefined;
783
701
  }
784
702
 
703
+ /**
704
+ * Options for {@link DisTubeStream}
705
+ */
785
706
  interface StreamOptions {
707
+ /**
708
+ * FFmpeg options
709
+ */
786
710
  ffmpeg: FFmpegOptions;
711
+ /**
712
+ * Seek time (in seconds).
713
+ * @default 0
714
+ */
787
715
  seek?: number;
788
- type?: StreamType;
789
716
  }
790
- declare const chooseBestVideoFormat: ({ duration, formats, isLive }: Song) => ytdl.videoFormat | undefined;
791
717
  declare const checkFFmpeg: (distube: DisTube) => void;
792
718
  /**
793
719
  * Create a stream to play with {@link DisTubeVoice}
@@ -796,34 +722,26 @@ declare class DisTubeStream extends TypedEmitter<{
796
722
  debug: (debug: string) => Awaitable;
797
723
  error: (error: Error) => Awaitable;
798
724
  }> {
799
- private killed;
800
- process: ChildProcess;
801
- stream: PassThrough;
802
- type: StreamType$1;
803
- url: string;
725
+ #private;
726
+ process?: ChildProcess;
727
+ stream: VolumeTransformer;
728
+ audioResource: AudioResource;
804
729
  /**
805
730
  * Create a DisTubeStream to play with {@link DisTubeVoice}
806
- *
807
731
  * @param url - Stream URL
808
732
  * @param options - Stream options
809
733
  */
810
- constructor(url: string, { ffmpeg, seek, type }: StreamOptions);
734
+ constructor(url: string, options: StreamOptions);
735
+ spawn(): void;
811
736
  private debug;
737
+ setVolume(volume: number): void;
812
738
  kill(): void;
813
- /**
814
- * Create a stream from a YouTube {@link Song}
815
- *
816
- * @param song - A YouTube Song
817
- * @param options - options
818
- */
819
- static YouTube(song: Song, options: StreamOptions): DisTubeStream;
820
- /**
821
- * Create a stream from a stream url
822
- *
823
- * @param url - stream url
824
- * @param options - options
825
- */
826
- static DirectLink(url: string, options: StreamOptions): DisTubeStream;
739
+ }
740
+ declare class VolumeTransformer extends Transform {
741
+ private buffer;
742
+ private readonly extrema;
743
+ vol: number;
744
+ _transform(newChunk: Buffer, _encoding: BufferEncoding, done: TransformCallback): void;
827
745
  }
828
746
 
829
747
  /**
@@ -831,109 +749,41 @@ declare class DisTubeStream extends TypedEmitter<{
831
749
  */
832
750
  declare class DisTubeHandler extends DisTubeBase {
833
751
  #private;
834
- constructor(distube: DisTube);
835
- get ytdlOptions(): ytdl__default.getInfoOptions;
836
- get ytCookie(): string;
837
- /**
838
- * @param url - url
839
- * @param basic - getBasicInfo?
840
- */
841
- getYouTubeInfo(url: string, basic?: boolean): Promise<ytdl__default.videoInfo>;
842
752
  resolve<T = unknown>(song: Song<T>, options?: Omit<ResolveOptions, "metadata">): Promise<Song<T>>;
843
753
  resolve<T = unknown>(song: Playlist<T>, options?: Omit<ResolveOptions, "metadata">): Promise<Playlist<T>>;
844
- resolve<T = unknown>(song: string | SearchResult, options?: ResolveOptions<T>): Promise<Song<T> | Playlist<T>>;
845
- resolve<T = unknown>(song: ytdl__default.videoInfo | OtherSongInfo | ytdl__default.relatedVideo, options?: ResolveOptions<T>): Promise<Song<T>>;
754
+ resolve<T = unknown>(song: string, options?: ResolveOptions<T>): Promise<Song<T> | Playlist<T>>;
755
+ resolve<T = unknown>(song: Song, options: ResolveOptions<T>): Promise<Song<T>>;
846
756
  resolve<T = unknown>(song: Playlist, options: ResolveOptions<T>): Promise<Playlist<T>>;
847
- resolve(song: string | ytdl__default.videoInfo | Song | Playlist | SearchResult | OtherSongInfo | ytdl__default.relatedVideo, options?: ResolveOptions): Promise<Song | Playlist>;
848
- resolvePlaylist<T = unknown>(playlist: Playlist<T> | Song<T>[] | string, options?: Omit<ResolvePlaylistOptions, "metadata">): Promise<Playlist<T>>;
849
- resolvePlaylist<T = undefined>(playlist: Playlist | Song[] | string, options: ResolvePlaylistOptions<T>): Promise<Playlist<T>>;
850
- resolvePlaylist(playlist: Playlist | Song[] | string, options?: ResolvePlaylistOptions): Promise<Playlist>;
851
- /**
852
- * Search for a song, fire {@link DisTube#error} if not found.
853
- *
854
- * @throws {@link DisTubeError}
855
- *
856
- * @param message - The original message from an user
857
- * @param query - The query string
858
- *
859
- * @returns Song info
860
- */
861
- searchSong(message: Message<true>, query: string): Promise<SearchResult | null>;
862
- /**
863
- * Create a message collector for selecting search results.
864
- *
865
- * Needed events: {@link DisTube#searchResult}, {@link DisTube#searchCancel},
866
- * {@link DisTube#searchInvalidAnswer}, {@link DisTube#searchDone}.
867
- *
868
- * @throws {@link DisTubeError}
869
- *
870
- * @param message - The original message from an user
871
- * @param results - The search results
872
- * @param query - The query string
873
- *
874
- * @returns Selected result
875
- */
876
- createSearchMessageCollector<R extends SearchResult | Song | Playlist>(message: Message<true>, results: Array<R>, query?: string): Promise<R | null>;
877
- /**
878
- * Play or add a {@link Playlist} to the queue.
879
- *
880
- * @throws {@link DisTubeError}
881
- *
882
- * @param voiceChannel - A voice channel
883
- * @param playlist - A YouTube playlist url | a Playlist
884
- * @param options - Optional options
885
- */
886
- playPlaylist(voiceChannel: VoiceBasedChannel, playlist: Playlist, options?: PlayHandlerOptions): Promise<void>;
887
- /**
888
- * Play or add a {@link Song} to the queue.
889
- *
890
- * @throws {@link DisTubeError}
891
- *
892
- * @param voiceChannel - A voice channel
893
- * @param song - A YouTube playlist url | a Playlist
894
- * @param options - Optional options
895
- */
896
- playSong(voiceChannel: VoiceBasedChannel, song: Song, options?: PlayHandlerOptions): Promise<void>;
757
+ resolve(song: string | Song | Playlist, options?: ResolveOptions): Promise<Song | Playlist>;
758
+ _getPluginFromURL(url: string): Promise<DisTubePlugin | null>;
759
+ _getPluginFromSong(song: Song): Promise<DisTubePlugin | null>;
760
+ _getPluginFromSong<T extends PluginType>(song: Song, types: T[], validate?: boolean): Promise<(DisTubePlugin & {
761
+ type: T;
762
+ }) | null>;
897
763
  /**
898
764
  * Get {@link Song}'s stream info and attach it to the song.
899
- *
900
765
  * @param song - A Song
901
766
  */
902
767
  attachStreamInfo(song: Song): Promise<void>;
768
+ followRedirectLink(url: string, maxRedirect?: number): Promise<string>;
903
769
  }
904
770
 
905
771
  declare class Options {
906
772
  #private;
907
- plugins: (CustomPlugin | ExtractorPlugin)[];
773
+ plugins: DisTubePlugin[];
908
774
  emitNewSongOnly: boolean;
909
- leaveOnFinish: boolean;
910
- leaveOnStop: boolean;
911
- leaveOnEmpty: boolean;
912
- emptyCooldown: number;
913
775
  savePreviousSongs: boolean;
914
- searchSongs: number;
915
- searchCooldown: number;
916
- youtubeCookie?: Cookie[] | string;
917
776
  customFilters?: Filters;
918
- ytdlOptions: ytdl__default.getInfoOptions;
919
777
  nsfw: boolean;
920
778
  emitAddSongWhenCreatingQueue: boolean;
921
779
  emitAddListWhenCreatingQueue: boolean;
922
780
  joinNewVoiceChannel: boolean;
923
- streamType: StreamType;
924
- directLink: boolean;
925
- /** @deprecated */
926
- ffmpegPath: undefined;
927
- /** @deprecated */
928
- ffmpegDefaultArgs: undefined;
929
781
  ffmpeg: FFmpegOptions;
930
782
  constructor(options: DisTubeOptions);
931
783
  }
932
784
 
933
785
  /**
934
786
  * Manages the collection of a data model.
935
- *
936
- * @virtual
937
787
  */
938
788
  declare abstract class BaseManager<V> extends DisTubeBase {
939
789
  /**
@@ -948,8 +798,6 @@ declare abstract class BaseManager<V> extends DisTubeBase {
948
798
 
949
799
  /**
950
800
  * Manages the collection of a data model paired with a guild id.
951
- *
952
- * @virtual
953
801
  */
954
802
  declare abstract class GuildIdManager<V> extends BaseManager<V> {
955
803
  add(idOrInstance: GuildIdResolvable, data: V): this;
@@ -959,32 +807,21 @@ declare abstract class GuildIdManager<V> extends BaseManager<V> {
959
807
  }
960
808
 
961
809
  /**
962
- * Manages voice connections for {@link DisTube}
810
+ * Manages voice connections
963
811
  */
964
812
  declare class DisTubeVoiceManager extends GuildIdManager<DisTubeVoice> {
965
813
  /**
966
- * Get a {@link DisTubeVoice}.
967
- *
968
- * @param guild - The queue resolvable to resolve
969
- */
970
- /**
971
- * Collection of {@link DisTubeVoice}.
972
- */
973
- /**
974
- * Create a {@link DisTubeVoice}
975
- *
814
+ * Create a {@link DisTubeVoice} instance
976
815
  * @param channel - A voice channel to join
977
816
  */
978
817
  create(channel: VoiceBasedChannel): DisTubeVoice;
979
818
  /**
980
- * Join a voice channel
981
- *
819
+ * Join a voice channel and wait until the connection is ready
982
820
  * @param channel - A voice channel to join
983
821
  */
984
822
  join(channel: VoiceBasedChannel): Promise<DisTubeVoice>;
985
823
  /**
986
824
  * Leave the connected voice channel in a guild
987
- *
988
825
  * @param guild - Queue Resolvable
989
826
  */
990
827
  leave(guild: GuildIdResolvable): void;
@@ -996,13 +833,12 @@ declare class DisTubeVoiceManager extends GuildIdManager<DisTubeVoice> {
996
833
  declare class FilterManager extends BaseManager<Filter> {
997
834
  #private;
998
835
  /**
999
- * Collection of {@link Filter}.
836
+ * The queue to manage
1000
837
  */
1001
838
  queue: Queue;
1002
839
  constructor(queue: Queue);
1003
840
  /**
1004
841
  * Enable a filter or multiple filters to the manager
1005
- *
1006
842
  * @param filterOrFilters - The filter or filters to enable
1007
843
  * @param override - Wether or not override the applied filter with new filter value
1008
844
  */
@@ -1013,19 +849,16 @@ declare class FilterManager extends BaseManager<Filter> {
1013
849
  clear(): this;
1014
850
  /**
1015
851
  * Set the filters applied to the manager
1016
- *
1017
852
  * @param filters - The filters to apply
1018
853
  */
1019
854
  set(filters: FilterResolvable[]): this;
1020
855
  /**
1021
856
  * Disable a filter or multiple filters
1022
- *
1023
857
  * @param filterOrFilters - The filter or filters to disable
1024
858
  */
1025
859
  remove(filterOrFilters: FilterResolvable | FilterResolvable[]): this;
1026
860
  /**
1027
861
  * Check whether a filter enabled or not
1028
- *
1029
862
  * @param filter - The filter to check
1030
863
  */
1031
864
  has(filter: FilterResolvable): boolean;
@@ -1037,7 +870,7 @@ declare class FilterManager extends BaseManager<Filter> {
1037
870
  * Array of enabled filters
1038
871
  */
1039
872
  get values(): Filter[];
1040
- get ffmpegArgs(): FFmpegArgs;
873
+ get ffmpegArgs(): FFmpegArg;
1041
874
  toString(): string;
1042
875
  }
1043
876
 
@@ -1046,33 +879,19 @@ declare class FilterManager extends BaseManager<Filter> {
1046
879
  */
1047
880
  declare class QueueManager extends GuildIdManager<Queue> {
1048
881
  #private;
1049
- /**
1050
- * Collection of {@link Queue}.
1051
- */
1052
882
  /**
1053
883
  * Create a {@link Queue}
1054
- *
1055
884
  * @param channel - A voice channel
1056
- * @param song - First song
1057
885
  * @param textChannel - Default text channel
1058
- *
1059
886
  * @returns Returns `true` if encounter an error
1060
887
  */
1061
- create(channel: VoiceBasedChannel, song: Song[] | Song, textChannel?: GuildTextBasedChannel): Promise<Queue | true>;
1062
- /**
1063
- * Create a ytdl stream
1064
- *
1065
- * @param queue - Queue
1066
- */
1067
- createStream(queue: Queue): DisTubeStream;
888
+ create(channel: VoiceBasedChannel, textChannel?: GuildTextBasedChannel): Promise<Queue>;
1068
889
  /**
1069
- * Play a song on voice connection
1070
- *
1071
- * @param queue - The guild queue
1072
- *
1073
- * @returns error?
890
+ * Play a song on voice connection with queue properties
891
+ * @param queue - The guild queue to play
892
+ * @param emitPlaySong - Whether or not emit {@link Events.PLAY_SONG} event
1074
893
  */
1075
- playSong(queue: Queue): Promise<boolean>;
894
+ playSong(queue: Queue, emitPlaySong?: boolean): Promise<void>;
1076
895
  }
1077
896
 
1078
897
  /**
@@ -1080,31 +899,79 @@ declare class QueueManager extends GuildIdManager<Queue> {
1080
899
  */
1081
900
  declare class Queue extends DisTubeBase {
1082
901
  #private;
902
+ /**
903
+ * Queue id (Guild id)
904
+ */
1083
905
  readonly id: Snowflake;
906
+ /**
907
+ * Voice connection of this queue.
908
+ */
1084
909
  voice: DisTubeVoice;
910
+ /**
911
+ * List of songs in the queue (The first one is the playing song)
912
+ */
1085
913
  songs: Song[];
914
+ /**
915
+ * List of the previous songs.
916
+ */
1086
917
  previousSongs: Song[];
918
+ /**
919
+ * Whether stream is currently stopped.
920
+ */
1087
921
  stopped: boolean;
1088
- _next: boolean;
1089
- _prev: boolean;
922
+ /**
923
+ * Whether or not the stream is currently playing.
924
+ */
1090
925
  playing: boolean;
926
+ /**
927
+ * Whether or not the stream is currently paused.
928
+ */
1091
929
  paused: boolean;
930
+ /**
931
+ * Type of repeat mode (`0` is disabled, `1` is repeating a song, `2` is repeating
932
+ * all the queue). Default value: `0` (disabled)
933
+ */
1092
934
  repeatMode: RepeatMode;
935
+ /**
936
+ * Whether or not the autoplay mode is enabled. Default value: `false`
937
+ */
1093
938
  autoplay: boolean;
1094
- beginTime: number;
939
+ /**
940
+ * FFmpeg arguments for the current queue. Default value is defined with {@link DisTubeOptions}.ffmpeg.args.
941
+ * `af` output argument will be replaced with {@link Queue#filters} manager
942
+ */
943
+ ffmpegArgs: FFmpegArgs;
944
+ /**
945
+ * The text channel of the Queue. (Default: where the first command is called).
946
+ */
1095
947
  textChannel?: GuildTextBasedChannel;
1096
- _emptyTimeout?: NodeJS.Timeout;
948
+ /**
949
+ * What time in the song to begin (in seconds).
950
+ */
951
+ _beginTime: number;
952
+ /**
953
+ * Whether or not the last song was skipped to next song.
954
+ */
955
+ _next: boolean;
956
+ /**
957
+ * Whether or not the last song was skipped to previous song.
958
+ */
959
+ _prev: boolean;
960
+ /**
961
+ * Task queuing system
962
+ */
1097
963
  _taskQueue: TaskQueue;
964
+ /**
965
+ * {@link DisTubeVoice} listener
966
+ */
1098
967
  _listeners?: DisTubeVoiceEvents;
1099
968
  /**
1100
969
  * Create a queue for the guild
1101
- *
1102
970
  * @param distube - DisTube
1103
971
  * @param voice - Voice connection
1104
- * @param song - First song(s)
1105
972
  * @param textChannel - Default text channel
1106
973
  */
1107
- constructor(distube: DisTube, voice: DisTubeVoice, song: Song | Song[], textChannel?: GuildTextBasedChannel);
974
+ constructor(distube: DisTube, voice: DisTubeVoice, textChannel?: GuildTextBasedChannel);
1108
975
  /**
1109
976
  * The client user as a `GuildMember` of this queue's guild
1110
977
  */
@@ -1133,34 +1000,31 @@ declare class Queue extends DisTubeBase {
1133
1000
  * The voice channel playing in.
1134
1001
  */
1135
1002
  get voiceChannel(): discord_js.VoiceBasedChannel | null;
1003
+ /**
1004
+ * Get or set the stream volume. Default value: `50`.
1005
+ */
1136
1006
  get volume(): number;
1137
1007
  set volume(value: number);
1138
1008
  /**
1139
1009
  * @throws {DisTubeError}
1140
- *
1141
1010
  * @param song - Song to add
1142
1011
  * @param position - Position to add, \<= 0 to add to the end of the queue
1143
- *
1144
1012
  * @returns The guild queue
1145
1013
  */
1146
1014
  addToQueue(song: Song | Song[], position?: number): Queue;
1147
1015
  /**
1148
1016
  * Pause the guild stream
1149
- *
1150
1017
  * @returns The guild queue
1151
1018
  */
1152
1019
  pause(): Queue;
1153
1020
  /**
1154
1021
  * Resume the guild stream
1155
- *
1156
1022
  * @returns The guild queue
1157
1023
  */
1158
1024
  resume(): Queue;
1159
1025
  /**
1160
1026
  * Set the guild stream's volume
1161
- *
1162
1027
  * @param percent - The percentage of volume you want to set
1163
- *
1164
1028
  * @returns The guild queue
1165
1029
  */
1166
1030
  setVolume(percent: number): Queue;
@@ -1168,19 +1032,16 @@ declare class Queue extends DisTubeBase {
1168
1032
  * Skip the playing song if there is a next song in the queue. <info>If {@link
1169
1033
  * Queue#autoplay} is `true` and there is no up next song, DisTube will add and
1170
1034
  * play a related song.</info>
1171
- *
1172
1035
  * @returns The song will skip to
1173
1036
  */
1174
1037
  skip(): Promise<Song>;
1175
1038
  /**
1176
1039
  * Play the previous song if exists
1177
- *
1178
1040
  * @returns The guild queue
1179
1041
  */
1180
1042
  previous(): Promise<Song>;
1181
1043
  /**
1182
1044
  * Shuffle the queue's songs
1183
- *
1184
1045
  * @returns The guild queue
1185
1046
  */
1186
1047
  shuffle(): Promise<Queue>;
@@ -1188,32 +1049,25 @@ declare class Queue extends DisTubeBase {
1188
1049
  * Jump to the song position in the queue. The next one is 1, 2,... The previous
1189
1050
  * one is -1, -2,...
1190
1051
  * if `num` is invalid number
1191
- *
1192
1052
  * @param position - The song position to play
1193
- *
1194
1053
  * @returns The new Song will be played
1195
1054
  */
1196
1055
  jump(position: number): Promise<Song>;
1197
1056
  /**
1198
1057
  * Set the repeat mode of the guild queue.
1199
1058
  * Toggle mode `(Disabled -> Song -> Queue -> Disabled ->...)` if `mode` is `undefined`
1200
- *
1201
1059
  * @param mode - The repeat modes (toggle if `undefined`)
1202
- *
1203
1060
  * @returns The new repeat mode
1204
1061
  */
1205
1062
  setRepeatMode(mode?: RepeatMode): RepeatMode;
1206
1063
  /**
1207
1064
  * Set the playing time to another position
1208
- *
1209
1065
  * @param time - Time in seconds
1210
- *
1211
1066
  * @returns The guild queue
1212
1067
  */
1213
1068
  seek(time: number): Queue;
1214
1069
  /**
1215
1070
  * Add a related song of the playing song to the queue
1216
- *
1217
1071
  * @returns The added song
1218
1072
  */
1219
1073
  addRelatedSong(): Promise<Song>;
@@ -1222,144 +1076,136 @@ declare class Queue extends DisTubeBase {
1222
1076
  */
1223
1077
  stop(): Promise<void>;
1224
1078
  /**
1225
- * Remove the queue from the manager (This does not leave the voice channel even if
1226
- * {@link DisTubeOptions | DisTubeOptions.leaveOnStop} is enabled)
1079
+ * Remove the queue from the manager
1227
1080
  */
1228
1081
  remove(): void;
1229
1082
  /**
1230
1083
  * Toggle autoplay mode
1231
- *
1232
1084
  * @returns Autoplay mode state
1233
1085
  */
1234
1086
  toggleAutoplay(): boolean;
1087
+ /**
1088
+ * Play the queue
1089
+ * @param emitPlaySong - Whether or not emit {@link Events.PLAY_SONG} event
1090
+ */
1091
+ play(emitPlaySong?: boolean): Promise<void>;
1235
1092
  }
1236
1093
 
1237
1094
  /**
1238
1095
  * DisTube Plugin
1239
- *
1240
- * @virtual
1241
1096
  */
1242
1097
  declare abstract class Plugin {
1243
- abstract type: PluginType;
1244
- distube: DisTube;
1245
- init(distube: DisTube): void;
1246
1098
  /**
1247
1099
  * Type of the plugin
1248
1100
  */
1101
+ abstract readonly type: PluginType;
1249
1102
  /**
1250
- * Emit an event to the {@link DisTube} class
1251
- *
1252
- * @param eventName - Event name
1253
- * @param args - arguments
1254
- */
1255
- emit(eventName: keyof DisTubeEvents, ...args: any): boolean;
1256
- /**
1257
- * Emit error event to the {@link DisTube} class
1258
- *
1259
- * @param error - error
1260
- * @param channel - Text channel where the error is encountered.
1261
- */
1262
- emitError(error: Error, channel?: GuildTextBasedChannel): void;
1263
- /**
1264
- * The queue manager
1103
+ * DisTube
1265
1104
  */
1266
- get queues(): QueueManager;
1105
+ distube: DisTube;
1106
+ init(distube: DisTube): void;
1267
1107
  /**
1268
- * The voice manager
1108
+ * Get related songs from a supported url.
1109
+ * @param song - Input song
1269
1110
  */
1270
- get voices(): DisTubeVoiceManager;
1271
- /**
1272
- * Discord.js client
1273
- */
1274
- get client(): Client;
1111
+ abstract getRelatedSongs(song: Song): Awaitable<Song[]>;
1112
+ }
1113
+
1114
+ /**
1115
+ * This plugin can extract the info, search, and play a song directly from its source
1116
+ */
1117
+ declare abstract class ExtractorPlugin extends Plugin {
1118
+ readonly type = PluginType.EXTRACTOR;
1275
1119
  /**
1276
- * DisTube options
1120
+ * Check if the url is working with this plugin
1121
+ * @param url - Input url
1277
1122
  */
1278
- get options(): Options;
1123
+ abstract validate(url: string): Awaitable<boolean>;
1279
1124
  /**
1280
- * DisTube handler
1125
+ * Resolve the validated url to a {@link Song} or a {@link Playlist}.
1126
+ * @param url - URL
1127
+ * @param options - Optional options
1281
1128
  */
1282
- get handler(): DisTubeHandler;
1129
+ abstract resolve<T>(url: string, options: ResolveOptions<T>): Awaitable<Song<T> | Playlist<T>>;
1283
1130
  /**
1284
- * Check if the string is working with this plugin
1285
- *
1286
- * @param _string - Input string
1131
+ * Search for a Song which playable from this plugin's source
1132
+ * @param query - Search query
1133
+ * @param options - Optional options
1287
1134
  */
1288
- validate(_string: string): Awaitable<boolean>;
1135
+ abstract searchSong<T>(query: string, options: ResolveOptions<T>): Awaitable<Song<T> | null>;
1289
1136
  /**
1290
1137
  * Get the stream url from {@link Song#url}. Returns {@link Song#url} by default.
1291
1138
  * Not needed if the plugin plays song from YouTube.
1292
- *
1293
- * @param url - Input url
1294
- */
1295
- getStreamURL(url: string): Awaitable<string>;
1296
- /**
1297
- * Get related songs from a supported url. {@link Song#member} should be
1298
- * `undefined`. Not needed to add {@link Song#related} because it will be added
1299
- * with this function later.
1300
- *
1301
- * @param _url - Input url
1139
+ * @param song - Input song
1302
1140
  */
1303
- getRelatedSongs(_url: string): Awaitable<RelatedSong[]>;
1141
+ abstract getStreamURL<T>(song: Song<T>): Awaitable<string>;
1304
1142
  }
1305
1143
 
1306
1144
  /**
1307
- * Custom Plugin
1308
- *
1309
- * @virtual
1145
+ * This plugin only can extract the info from supported links, but not play song directly from its source
1310
1146
  */
1311
- declare abstract class CustomPlugin extends Plugin {
1312
- readonly type = PluginType.CUSTOM;
1313
- abstract play(voiceChannel: VoiceBasedChannel, song: string, options: PlayOptions): Awaitable<void>;
1147
+ declare abstract class InfoExtractorPlugin extends Plugin {
1148
+ readonly type = PluginType.INFO_EXTRACTOR;
1149
+ /**
1150
+ * Check if the url is working with this plugin
1151
+ * @param url - Input url
1152
+ */
1153
+ abstract validate(url: string): Awaitable<boolean>;
1154
+ /**
1155
+ * Resolve the validated url to a {@link Song} or a {@link Playlist}.
1156
+ * @param url - URL
1157
+ * @param options - Optional options
1158
+ */
1159
+ abstract resolve<T>(url: string, options: ResolveOptions<T>): Awaitable<Song<T> | Playlist<T>>;
1160
+ /**
1161
+ * Create a search query to be used in {@link ExtractorPlugin#searchSong}
1162
+ * @param song - Input song
1163
+ */
1164
+ abstract createSearchQuery<T>(song: Song<T>): Awaitable<string>;
1314
1165
  }
1315
1166
 
1316
1167
  /**
1317
- * Extractor Plugin
1318
- *
1319
- * @virtual
1168
+ * This plugin can extract and play song from supported links, but cannot search for songs from its source
1320
1169
  */
1321
- declare abstract class ExtractorPlugin extends Plugin {
1322
- readonly type = PluginType.EXTRACTOR;
1323
- abstract resolve<T = unknown>(url: string, options: {
1324
- member?: GuildMember;
1325
- metadata?: T;
1326
- }): Awaitable<Song<T> | Playlist<T>>;
1170
+ declare abstract class PlayableExtractorPlugin extends Plugin {
1171
+ readonly type = PluginType.PLAYABLE_EXTRACTOR;
1172
+ /**
1173
+ * Check if the url is working with this plugin
1174
+ * @param url - Input url
1175
+ */
1176
+ abstract validate(url: string): Awaitable<boolean>;
1177
+ /**
1178
+ * Resolve the validated url to a {@link Song} or a {@link Playlist}.
1179
+ * @param url - URL
1180
+ * @param options - Optional options
1181
+ */
1182
+ abstract resolve<T>(url: string, options: ResolveOptions<T>): Awaitable<Song<T> | Playlist<T>>;
1183
+ /**
1184
+ * Get the stream url from {@link Song#url}. Returns {@link Song#url} by default.
1185
+ * Not needed if the plugin plays song from YouTube.
1186
+ * @param song - Input song
1187
+ */
1188
+ abstract getStreamURL<T>(song: Song<T>): Awaitable<string>;
1327
1189
  }
1328
1190
 
1329
1191
  /**
1330
1192
  * Format duration to string
1331
- *
1332
1193
  * @param sec - Duration in seconds
1333
1194
  */
1334
1195
  declare function formatDuration(sec: number): string;
1335
- /**
1336
- * Convert formatted duration to seconds
1337
- *
1338
- * @param input - Formatted duration string
1339
- */
1340
- declare function toSecond(input: any): number;
1341
- /**
1342
- * Parse number from input
1343
- *
1344
- * @param input - Any
1345
- */
1346
- declare function parseNumber(input: any): number;
1347
1196
  declare const SUPPORTED_PROTOCOL: readonly ["https:", "http:", "file:"];
1348
1197
  /**
1349
1198
  * Check if the string is an URL
1350
- *
1351
1199
  * @param input - input
1352
1200
  */
1353
1201
  declare function isURL(input: any): input is `${(typeof SUPPORTED_PROTOCOL)[number]}//${string}`;
1354
1202
  /**
1355
1203
  * Check if the Client has enough intents to using DisTube
1356
- *
1357
1204
  * @param options - options
1358
1205
  */
1359
1206
  declare function checkIntents(options: ClientOptions): void;
1360
1207
  /**
1361
1208
  * Check if the voice channel is empty
1362
- *
1363
1209
  * @param voiceState - voiceState
1364
1210
  */
1365
1211
  declare function isVoiceChannelEmpty(voiceState: VoiceState): boolean;
@@ -1373,296 +1219,132 @@ declare function resolveGuildId(resolvable: GuildIdResolvable): Snowflake;
1373
1219
  declare function isClientInstance(client: any): client is Client;
1374
1220
  declare function checkInvalidKey(target: Record<string, any>, source: Record<string, any> | string[], sourceName: string): void;
1375
1221
  declare function isObject(obj: any): obj is object;
1376
- declare function isRecord<T = unknown>(obj: any): obj is Record<string, T>;
1377
1222
  type KeyOf<T> = T extends object ? (keyof T)[] : [];
1378
1223
  declare function objectKeys<T>(obj: T): KeyOf<T>;
1379
1224
  declare function isNsfwChannel(channel?: GuildTextBasedChannel): boolean;
1380
1225
  type Falsy = undefined | null | false | 0 | "";
1381
1226
  declare const isTruthy: <T>(x: T | Falsy) => x is T;
1382
1227
 
1383
- declare class DirectLinkPlugin extends ExtractorPlugin {
1384
- validate(url: string): Promise<boolean>;
1385
- resolve(url: string, options?: {
1386
- member?: GuildMember;
1387
- metadata?: any;
1388
- }): Song<any>;
1389
- }
1390
-
1391
1228
  declare const version: string;
1392
- interface DisTube extends TypedEmitter<TypedDisTubeEvents> {
1229
+ /**
1230
+ * DisTube class
1231
+ */
1232
+ declare class DisTube extends TypedEmitter<TypedDisTubeEvents> {
1233
+ #private;
1393
1234
  /**
1394
1235
  * @event
1395
1236
  * Emitted after DisTube add a new playlist to the playing {@link Queue}.
1396
- *
1397
- * @example
1398
- * ```ts
1399
- * distube.on("addList", (queue, playlist) => queue.textChannel.send(
1400
- * `Added \`${playlist.name}\` playlist (${playlist.songs.length} songs) to the queue!`
1401
- * ));
1402
- * ```
1403
- *
1404
1237
  * @param queue - The guild queue
1405
1238
  * @param playlist - Playlist info
1406
1239
  */
1407
- [Events.ADD_LIST]: (queue: Queue, playlist: Playlist) => Awaitable;
1240
+ static readonly [Events.ADD_LIST]: (queue: Queue, playlist: Playlist) => Awaitable;
1408
1241
  /**
1409
1242
  * @event
1410
1243
  * Emitted after DisTube add a new song to the playing {@link Queue}.
1411
- *
1412
- * @example
1413
- * ```ts
1414
- * distube.on("addSong", (queue, song) => queue.textChannel.send(
1415
- * `Added ${song.name} - \`${song.formattedDuration}\` to the queue by ${song.user}.`
1416
- * ));
1417
- * ```
1418
- *
1419
1244
  * @param queue - The guild queue
1420
1245
  * @param song - Added song
1421
1246
  */
1422
- [Events.ADD_SONG]: (queue: Queue, song: Song) => Awaitable;
1247
+ static readonly [Events.ADD_SONG]: (queue: Queue, song: Song) => Awaitable;
1423
1248
  /**
1424
1249
  * @event
1425
1250
  * Emitted when a {@link Queue} is deleted with any reasons.
1426
- *
1427
1251
  * @param queue - The guild queue
1428
1252
  */
1429
- [Events.DELETE_QUEUE]: (queue: Queue) => Awaitable;
1253
+ static readonly [Events.DELETE_QUEUE]: (queue: Queue) => Awaitable;
1430
1254
  /**
1431
1255
  * @event
1432
1256
  * Emitted when the bot is disconnected to a voice channel.
1433
- *
1434
1257
  * @param queue - The guild queue
1435
1258
  */
1436
- [Events.DISCONNECT]: (queue: Queue) => Awaitable;
1259
+ static readonly [Events.DISCONNECT]: (queue: Queue) => Awaitable;
1437
1260
  /**
1438
1261
  * @event
1439
- * Emitted when there is no user in the voice channel, {@link DisTubeOptions}.leaveOnEmpty
1440
- * is `true` and there is a playing queue.
1441
- *
1442
- * If there is no playing queue (stopped and {@link DisTubeOptions}.leaveOnStop is
1443
- * `false`), it will leave the channel without emitting this event.
1444
- *
1445
- * @example
1446
- * ```ts
1447
- * distube.on("empty", queue => queue.textChannel.send("Channel is empty. Leaving the channel"))
1448
- * ```
1449
- *
1450
- * @param queue - The guild queue
1262
+ * Emitted when DisTube encounters an error while playing songs.
1263
+ * @param error - error
1264
+ * @param queue - The queue encountered the error
1265
+ * @param song - The playing song when encountered the error
1451
1266
  */
1452
- [Events.EMPTY]: (queue: Queue) => Awaitable;
1267
+ static readonly [Events.ERROR]: (error: Error, queue: Queue, song?: Song) => Awaitable;
1453
1268
  /**
1454
1269
  * @event
1455
- * Emitted when DisTube encounters an error while playing songs.
1456
- *
1457
- * @example
1458
- * ```ts
1459
- * distube.on('error', (channel, e) => {
1460
- * if (channel) channel.send(`An error encountered: ${e}`)
1461
- * else console.error(e)
1462
- * })
1463
- * ```
1464
- *
1465
- * @param channel - Text channel where the error is encountered.
1466
- * @param error - The error encountered
1270
+ * Emitted for logging FFmpeg debug information.
1271
+ * @param debug - Debug message string.
1467
1272
  */
1468
- [Events.ERROR]: (channel: GuildTextBasedChannel | undefined, error: Error) => Awaitable;
1273
+ static readonly [Events.FFMPEG_DEBUG]: (debug: string) => Awaitable;
1469
1274
  /**
1470
1275
  * @event
1471
- * Emitted for FFmpeg debugging information.
1276
+ * Emitted to provide debug information from DisTube's operation.
1277
+ * Useful for troubleshooting or logging purposes.
1472
1278
  *
1473
- * @param debug - The debug information
1279
+ * @param debug - Debug message string.
1474
1280
  */
1475
- [Events.FFMPEG_DEBUG]: (debug: string) => Awaitable;
1281
+ static readonly [Events.DEBUG]: (debug: string) => Awaitable;
1476
1282
  /**
1477
1283
  * @event
1478
- * Emitted when there is no more song in the queue and {@link Queue#autoplay} is
1479
- * `false`. DisTube will leave voice channel if {@link
1480
- * DisTubeOptions}.leaveOnFinish is `true`.
1481
- *
1482
- * @example
1483
- * ```ts
1484
- * distube.on("finish", queue => queue.textChannel.send("No more song in queue"));
1485
- * ```
1486
- *
1284
+ * Emitted when there is no more song in the queue and {@link Queue#autoplay} is `false`.
1487
1285
  * @param queue - The guild queue
1488
1286
  */
1489
- [Events.FINISH]: (queue: Queue) => Awaitable;
1287
+ static readonly [Events.FINISH]: (queue: Queue) => Awaitable;
1490
1288
  /**
1491
1289
  * @event
1492
1290
  * Emitted when DisTube finished a song.
1493
- *
1494
- * @example
1495
- * ```ts
1496
- * distube.on("finishSong", (queue, song) => queue.textChannel.send(`${song.name} has finished!`));
1497
- * ```
1498
- *
1499
1291
  * @param queue - The guild queue
1500
1292
  * @param song - Finished song
1501
1293
  */
1502
- [Events.FINISH_SONG]: (queue: Queue, song: Song) => Awaitable;
1294
+ static readonly [Events.FINISH_SONG]: (queue: Queue, song: Song) => Awaitable;
1503
1295
  /**
1504
1296
  * @event
1505
1297
  * Emitted when DisTube initialize a queue to change queue default properties.
1506
- *
1507
- * @example
1508
- * ```ts
1509
- * distube.on("initQueue", queue => {
1510
- * queue.autoplay = false;
1511
- * queue.volume = 100;
1512
- * });
1513
- * ```ts
1514
- *
1515
1298
  * @param queue - The guild queue
1516
1299
  */
1517
- [Events.INIT_QUEUE]: (queue: Queue) => Awaitable;
1300
+ static readonly [Events.INIT_QUEUE]: (queue: Queue) => Awaitable;
1518
1301
  /**
1519
1302
  * @event
1520
1303
  * Emitted when {@link Queue#autoplay} is `true`, {@link Queue#songs} is empty, and
1521
1304
  * DisTube cannot find related songs to play.
1522
- *
1523
- * @example
1524
- * ```ts
1525
- * distube.on("noRelated", queue => queue.textChannel.send("Can't find related video to play."));
1526
- * ```ts
1527
- *
1528
1305
  * @param queue - The guild queue
1529
1306
  */
1530
- [Events.NO_RELATED]: (queue: Queue) => Awaitable;
1307
+ static readonly [Events.NO_RELATED]: (queue: Queue) => Awaitable;
1531
1308
  /**
1532
1309
  * @event
1533
1310
  * Emitted when DisTube play a song.
1534
- *
1535
1311
  * If {@link DisTubeOptions}.emitNewSongOnly is `true`, this event is not emitted
1536
1312
  * when looping a song or next song is the previous one.
1537
- *
1538
- * @example
1539
- * ```ts
1540
- * distube.on("playSong", (queue, song) => queue.textChannel.send(
1541
- * `Playing \`${song.name}\` - \`${song.formattedDuration}\`\nRequested by: ${song.user}`
1542
- * ));
1543
- * ```ts
1544
- *
1545
1313
  * @param queue - The guild queue
1546
1314
  * @param song - Playing song
1547
1315
  */
1548
- [Events.PLAY_SONG]: (queue: Queue, song: Song) => Awaitable;
1316
+ static readonly [Events.PLAY_SONG]: (queue: Queue, song: Song) => Awaitable;
1549
1317
  /**
1550
- * @event
1551
- * Emitted when {@link DisTubeOptions | DisTubeOptions.searchSongs} bigger than 0,
1552
- * and the search canceled due to {@link DisTubeOptions |
1553
- * DisTubeOptions.searchTimeout}.
1554
- *
1555
- * @example
1556
- * ```ts
1557
- * // DisTubeOptions.searchSongs > 0
1558
- * distube.on("searchCancel", (message) => message.channel.send(`Searching canceled`));
1559
- * ```ts
1560
- *
1561
- * @param message - The user message called play method
1562
- * @param query - The search query
1318
+ * DisTube internal handler
1563
1319
  */
1564
- [Events.SEARCH_CANCEL]: (message: Message, query: string) => Awaitable;
1320
+ readonly handler: DisTubeHandler;
1565
1321
  /**
1566
- * @event
1567
- * Emitted when {@link DisTubeOptions | DisTubeOptions.searchSongs} bigger than 0,
1568
- * and after the user chose a search result to play.
1569
- *
1570
- * @param message - The user message called play method
1571
- * @param answer - The answered message of user
1572
- * @param query - The search query
1322
+ * DisTube options
1573
1323
  */
1574
- [Events.SEARCH_DONE]: (message: Message, answer: string, query: string) => Awaitable;
1324
+ readonly options: Options;
1575
1325
  /**
1576
- * @event
1577
- * Emitted when {@link DisTubeOptions | DisTubeOptions.searchSongs} bigger than 0,
1578
- * and the search canceled due to user's next message is not a number or out of
1579
- * results range.
1580
- *
1581
- * @example
1582
- * ```ts
1583
- * // DisTubeOptions.searchSongs > 0
1584
- * distube.on("searchInvalidAnswer", (message) => message.channel.send(`You answered an invalid number!`));
1585
- * ```ts
1586
- *
1587
- * @param message - The user message called play method
1588
- * @param answer - The answered message of user
1589
- * @param query - The search query
1326
+ * Discord.js v14 client
1590
1327
  */
1591
- [Events.SEARCH_INVALID_ANSWER]: (message: Message, answer: string, query: string) => Awaitable;
1328
+ readonly client: Client;
1592
1329
  /**
1593
- * @event
1594
- * Emitted when DisTube cannot find any results for the query.
1595
- *
1596
- * @example
1597
- * ```ts
1598
- * distube.on("searchNoResult", (message, query) => message.channel.send(`No result found for ${query}!`));
1599
- * ```ts
1600
- *
1601
- * @param message - The user message called play method
1602
- * @param query - The search query
1330
+ * Queues manager
1603
1331
  */
1604
- [Events.SEARCH_NO_RESULT]: (message: Message, query: string) => Awaitable;
1332
+ readonly queues: QueueManager;
1605
1333
  /**
1606
- * @event
1607
- * Emitted when {@link DisTubeOptions | DisTubeOptions.searchSongs} bigger than 0,
1608
- * and song param of {@link DisTube#play} is invalid url. DisTube will wait for
1609
- * user's next message to choose a song manually. <info>{@link
1610
- * https://support.google.com/youtube/answer/7354993 | Safe search} is enabled if
1611
- * {@link DisTubeOptions}.nsfw is disabled and the message's channel is not a nsfw
1612
- * channel.</info>
1613
- *
1614
- * @example
1615
- * ```ts
1616
- * // DisTubeOptions.searchSongs > 0
1617
- * distube.on("searchResult", (message, results) => {
1618
- * message.channel.send(`**Choose an option from below**\n${
1619
- * results.map((song, i) => `**${i + 1}**. ${song.name} - \`${song.formattedDuration}\``).join("\n")
1620
- * }\n*Enter anything else or wait 60 seconds to cancel*`);
1621
- * });
1622
- * ```ts
1623
- *
1624
- * @param message - The user message called play method
1625
- * @param results - Searched results
1626
- * @param query - The search query
1334
+ * DisTube voice connections manager
1627
1335
  */
1628
- [Events.SEARCH_RESULT]: (message: Message, results: SearchResult[], query: string) => Awaitable;
1629
- }
1630
- /**
1631
- * DisTube class
1632
- */
1633
- declare class DisTube extends TypedEmitter<TypedDisTubeEvents> {
1634
- #private;
1635
- readonly handler: DisTubeHandler;
1636
- readonly options: Options;
1637
- readonly client: Client;
1638
- readonly queues: QueueManager;
1639
1336
  readonly voices: DisTubeVoiceManager;
1640
- readonly extractorPlugins: ExtractorPlugin[];
1641
- readonly customPlugins: CustomPlugin[];
1642
- readonly filters: Filters;
1643
1337
  /**
1644
- * @deprecated Use `youtubeCookie: Cookie[]` instead. Guide: {@link
1645
- * https://github.com/skick1234/DisTube/wiki/YouTube-Cookies | YouTube Cookies}
1338
+ * DisTube plugins
1339
+ */
1340
+ readonly plugins: DisTubePlugin[];
1341
+ /**
1342
+ * DisTube ffmpeg audio filters
1646
1343
  */
1647
- constructor(client: Client, opts: DisTubeOptions & {
1648
- youtubeCookie: string;
1649
- });
1344
+ readonly filters: Filters;
1650
1345
  /**
1651
1346
  * Create a new DisTube class.
1652
- *
1653
- * @example
1654
- * ```ts
1655
- * const Discord = require('discord.js'),
1656
- * DisTube = require('distube'),
1657
- * client = new Discord.Client();
1658
- * // Create a new DisTube
1659
- * const distube = new DisTube.default(client, { searchSongs: 10 });
1660
- * // client.DisTube = distube // make it access easily
1661
- * client.login("Your Discord Bot Token")
1662
- * ```ts
1663
- *
1664
1347
  * @throws {@link DisTubeError}
1665
- *
1666
1348
  * @param client - Discord.JS client
1667
1349
  * @param opts - Custom DisTube options
1668
1350
  */
@@ -1673,141 +1355,47 @@ declare class DisTube extends TypedEmitter<TypedDisTubeEvents> {
1673
1355
  */
1674
1356
  get version(): string;
1675
1357
  /**
1676
- * Play / add a song or playlist from url. Search and play a song if it is not a
1677
- * valid url.
1678
- *
1679
- * @example
1680
- * ```ts
1681
- * client.on('message', (message) => {
1682
- * if (!message.content.startsWith(config.prefix)) return;
1683
- * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
1684
- * const command = args.shift();
1685
- * if (command == "play")
1686
- * distube.play(message.member.voice.channel, args.join(" "), {
1687
- * member: message.member,
1688
- * textChannel: message.channel,
1689
- * message
1690
- * });
1691
- * });
1692
- * ```ts
1693
- *
1358
+ * Play / add a song or playlist from url.
1359
+ * Search and play a song (with {@link ExtractorPlugin}) if it is not a valid url.
1694
1360
  * @throws {@link DisTubeError}
1695
- *
1696
1361
  * @param voiceChannel - The channel will be joined if the bot isn't in any channels, the bot will be
1697
1362
  * moved to this channel if {@link DisTubeOptions}.joinNewVoiceChannel is `true`
1698
- * @param song - URL | Search string | {@link Song} | {@link SearchResult} | {@link Playlist}
1363
+ * @param song - URL | Search string | {@link Song} | {@link Playlist}
1699
1364
  * @param options - Optional options
1700
1365
  */
1701
- play(voiceChannel: VoiceBasedChannel, song: string | Song | SearchResult | Playlist, options?: PlayOptions): Promise<void>;
1366
+ play<T = unknown>(voiceChannel: VoiceBasedChannel, song: string | Song | Playlist, options?: PlayOptions<T>): Promise<void>;
1702
1367
  /**
1703
1368
  * Create a custom playlist
1704
- *
1705
- * @example
1706
- * ```ts
1707
- * const songs = ["https://www.youtube.com/watch?v=xxx", "https://www.youtube.com/watch?v=yyy"];
1708
- * const playlist = await distube.createCustomPlaylist(songs, {
1709
- * member: message.member,
1710
- * properties: { name: "My playlist name", source: "custom" },
1711
- * parallel: true
1712
- * });
1713
- * distube.play(voiceChannel, playlist, { ... });
1714
- * ```ts
1715
- *
1716
- * @param songs - Array of url, Song or SearchResult
1369
+ * @param songs - Array of url or Song
1717
1370
  * @param options - Optional options
1718
1371
  */
1719
- createCustomPlaylist(songs: (string | Song | SearchResult)[], options?: CustomPlaylistOptions): Promise<Playlist>;
1720
- search(string: string, options?: {
1721
- type?: SearchResultType.VIDEO;
1722
- limit?: number;
1723
- safeSearch?: boolean;
1724
- retried?: boolean;
1725
- }): Promise<Array<SearchResultVideo>>;
1726
- search(string: string, options: {
1727
- type: SearchResultType.PLAYLIST;
1728
- limit?: number;
1729
- safeSearch?: boolean;
1730
- retried?: boolean;
1731
- }): Promise<Array<SearchResultPlaylist>>;
1732
- search(string: string, options?: {
1733
- type?: SearchResultType;
1734
- limit?: number;
1735
- safeSearch?: boolean;
1736
- retried?: boolean;
1737
- }): Promise<Array<SearchResult>>;
1372
+ createCustomPlaylist(songs: (string | Song)[], { member, parallel, metadata, name, source, url, thumbnail }?: CustomPlaylistOptions): Promise<Playlist>;
1738
1373
  /**
1739
1374
  * Get the guild queue
1740
- *
1741
- * @example
1742
- * ```ts
1743
- * client.on('message', (message) => {
1744
- * if (!message.content.startsWith(config.prefix)) return;
1745
- * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
1746
- * const command = args.shift();
1747
- * if (command == "queue") {
1748
- * const queue = distube.getQueue(message);
1749
- * message.channel.send('Current queue:\n' + queue.songs.map((song, id) =>
1750
- * `**${id+1}**. [${song.name}](${song.url}) - \`${song.formattedDuration}\``
1751
- * ).join("\n"));
1752
- * }
1753
- * });
1754
- * ```ts
1755
- *
1756
1375
  * @param guild - The type can be resolved to give a {@link Queue}
1757
1376
  */
1758
1377
  getQueue(guild: GuildIdResolvable): Queue | undefined;
1759
1378
  /**
1760
1379
  * Pause the guild stream
1761
- *
1762
1380
  * @param guild - The type can be resolved to give a {@link Queue}
1763
- *
1764
1381
  * @returns The guild queue
1765
1382
  */
1766
1383
  pause(guild: GuildIdResolvable): Queue;
1767
1384
  /**
1768
1385
  * Resume the guild stream
1769
- *
1770
1386
  * @param guild - The type can be resolved to give a {@link Queue}
1771
- *
1772
1387
  * @returns The guild queue
1773
1388
  */
1774
1389
  resume(guild: GuildIdResolvable): Queue;
1775
1390
  /**
1776
1391
  * Stop the guild stream
1777
- *
1778
- * @example
1779
- * ```ts
1780
- * client.on('message', (message) => {
1781
- * if (!message.content.startsWith(config.prefix)) return;
1782
- * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
1783
- * const command = args.shift();
1784
- * if (command == "stop") {
1785
- * distube.stop(message);
1786
- * message.channel.send("Stopped the queue!");
1787
- * }
1788
- * });
1789
- * ```ts
1790
- *
1791
1392
  * @param guild - The type can be resolved to give a {@link Queue}
1792
1393
  */
1793
1394
  stop(guild: GuildIdResolvable): Promise<void>;
1794
1395
  /**
1795
1396
  * Set the guild stream's volume
1796
- *
1797
- * @example
1798
- * ```ts
1799
- * client.on('message', (message) => {
1800
- * if (!message.content.startsWith(config.prefix)) return;
1801
- * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
1802
- * const command = args.shift();
1803
- * if (command == "volume")
1804
- * distube.setVolume(message, Number(args[0]));
1805
- * });
1806
- * ```ts
1807
- *
1808
1397
  * @param guild - The type can be resolved to give a {@link Queue}
1809
1398
  * @param percent - The percentage of volume you want to set
1810
- *
1811
1399
  * @returns The guild queue
1812
1400
  */
1813
1401
  setVolume(guild: GuildIdResolvable, percent: number): Queue;
@@ -1815,180 +1403,69 @@ declare class DisTube extends TypedEmitter<TypedDisTubeEvents> {
1815
1403
  * Skip the playing song if there is a next song in the queue. <info>If {@link
1816
1404
  * Queue#autoplay} is `true` and there is no up next song, DisTube will add and
1817
1405
  * play a related song.</info>
1818
- *
1819
- * @example
1820
- * ```ts
1821
- * client.on('message', (message) => {
1822
- * if (!message.content.startsWith(config.prefix)) return;
1823
- * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
1824
- * const command = args.shift();
1825
- * if (command == "skip")
1826
- * distube.skip(message);
1827
- * });
1828
- * ```ts
1829
- *
1830
1406
  * @param guild - The type can be resolved to give a {@link Queue}
1831
- *
1832
1407
  * @returns The new Song will be played
1833
1408
  */
1834
1409
  skip(guild: GuildIdResolvable): Promise<Song>;
1835
1410
  /**
1836
1411
  * Play the previous song
1837
- *
1838
- * @example
1839
- * ```ts
1840
- * client.on('message', (message) => {
1841
- * if (!message.content.startsWith(config.prefix)) return;
1842
- * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
1843
- * const command = args.shift();
1844
- * if (command == "previous")
1845
- * distube.previous(message);
1846
- * });
1847
- * ```ts
1848
- *
1849
1412
  * @param guild - The type can be resolved to give a {@link Queue}
1850
- *
1851
1413
  * @returns The new Song will be played
1852
1414
  */
1853
1415
  previous(guild: GuildIdResolvable): Promise<Song>;
1854
1416
  /**
1855
1417
  * Shuffle the guild queue songs
1856
- *
1857
- * @example
1858
- * ```ts
1859
- * client.on('message', (message) => {
1860
- * if (!message.content.startsWith(config.prefix)) return;
1861
- * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
1862
- * const command = args.shift();
1863
- * if (command == "shuffle")
1864
- * distube.shuffle(message);
1865
- * });
1866
- * ```ts
1867
- *
1868
1418
  * @param guild - The type can be resolved to give a {@link Queue}
1869
- *
1870
1419
  * @returns The guild queue
1871
1420
  */
1872
1421
  shuffle(guild: GuildIdResolvable): Promise<Queue>;
1873
1422
  /**
1874
1423
  * Jump to the song number in the queue. The next one is 1, 2,... The previous one
1875
1424
  * is -1, -2,...
1876
- *
1877
- * @example
1878
- * ```ts
1879
- * client.on('message', (message) => {
1880
- * if (!message.content.startsWith(config.prefix)) return;
1881
- * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
1882
- * const command = args.shift();
1883
- * if (command == "jump")
1884
- * distube.jump(message, parseInt(args[0]))
1885
- * .catch(err => message.channel.send("Invalid song number."));
1886
- * });
1887
- * ```ts
1888
- *
1889
1425
  * @param guild - The type can be resolved to give a {@link Queue}
1890
1426
  * @param num - The song number to play
1891
- *
1892
1427
  * @returns The new Song will be played
1893
1428
  */
1894
1429
  jump(guild: GuildIdResolvable, num: number): Promise<Song>;
1895
1430
  /**
1896
1431
  * Set the repeat mode of the guild queue.
1897
1432
  * Toggle mode `(Disabled -> Song -> Queue -> Disabled ->...)` if `mode` is `undefined`
1898
- *
1899
- * @example
1900
- * ```ts
1901
- * client.on('message', (message) => {
1902
- * if (!message.content.startsWith(config.prefix)) return;
1903
- * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
1904
- * const command = args.shift();
1905
- * if (command == "repeat") {
1906
- * let mode = distube.setRepeatMode(message, parseInt(args[0]));
1907
- * mode = mode ? mode == 2 ? "Repeat queue" : "Repeat song" : "Off";
1908
- * message.channel.send("Set repeat mode to `" + mode + "`");
1909
- * }
1910
- * });
1911
- * ```ts
1912
- * @example
1913
- * ```ts
1914
- * const { RepeatMode } = require("distube");
1915
- * let mode;
1916
- * switch(distube.setRepeatMode(message, parseInt(args[0]))) {
1917
- * case RepeatMode.DISABLED:
1918
- * mode = "Off";
1919
- * break;
1920
- * case RepeatMode.SONG:
1921
- * mode = "Repeat a song";
1922
- * break;
1923
- * case RepeatMode.QUEUE:
1924
- * mode = "Repeat all queue";
1925
- * break;
1926
- * }
1927
- * message.channel.send("Set repeat mode to `" + mode + "`");
1928
- * ```ts
1929
- *
1930
1433
  * @param guild - The type can be resolved to give a {@link Queue}
1931
1434
  * @param mode - The repeat modes (toggle if `undefined`)
1932
- *
1933
1435
  * @returns The new repeat mode
1934
1436
  */
1935
- setRepeatMode(guild: GuildIdResolvable, mode?: number): number;
1437
+ setRepeatMode(guild: GuildIdResolvable, mode?: RepeatMode): RepeatMode;
1936
1438
  /**
1937
1439
  * Toggle autoplay mode
1938
- *
1939
- * @example
1940
- * ```ts
1941
- * client.on('message', (message) => {
1942
- * if (!message.content.startsWith(config.prefix)) return;
1943
- * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
1944
- * const command = args.shift();
1945
- * if (command == "autoplay") {
1946
- * const mode = distube.toggleAutoplay(message);
1947
- * message.channel.send("Set autoplay mode to `" + (mode ? "On" : "Off") + "`");
1948
- * }
1949
- * });
1950
- * ```ts
1951
- *
1952
1440
  * @param guild - The type can be resolved to give a {@link Queue}
1953
- *
1954
1441
  * @returns Autoplay mode state
1955
1442
  */
1956
1443
  toggleAutoplay(guild: GuildIdResolvable): boolean;
1957
1444
  /**
1958
1445
  * Add related song to the queue
1959
- *
1960
1446
  * @param guild - The type can be resolved to give a {@link Queue}
1961
- *
1962
1447
  * @returns The guild queue
1963
1448
  */
1964
1449
  addRelatedSong(guild: GuildIdResolvable): Promise<Song>;
1965
1450
  /**
1966
1451
  * Set the playing time to another position
1967
- *
1968
- * @example
1969
- * ```ts
1970
- * client.on('message', message => {
1971
- * if (!message.content.startsWith(config.prefix)) return;
1972
- * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
1973
- * const command = args.shift();
1974
- * if (command = 'seek')
1975
- * distube.seek(message, Number(args[0]));
1976
- * });
1977
- * ```ts
1978
- *
1979
1452
  * @param guild - The type can be resolved to give a {@link Queue}
1980
1453
  * @param time - Time in seconds
1981
- *
1982
1454
  * @returns Seeked queue
1983
1455
  */
1984
1456
  seek(guild: GuildIdResolvable, time: number): Queue;
1985
1457
  /**
1986
1458
  * Emit error event
1987
- *
1988
1459
  * @param error - error
1989
- * @param channel - Text channel where the error is encountered.
1460
+ * @param queue - The queue encountered the error
1461
+ * @param song - The playing song when encountered the error
1462
+ */
1463
+ emitError(error: Error, queue: Queue, song?: Song): void;
1464
+ /**
1465
+ * Emit debug event
1466
+ * @param message - debug message
1990
1467
  */
1991
- emitError(error: Error, channel?: GuildTextBasedChannel): void;
1468
+ debug(message: string): void;
1992
1469
  }
1993
1470
 
1994
- export { type Awaitable, BaseManager, type Chapter, type CustomPlaylistOptions, CustomPlugin, DirectLinkPlugin, DisTube, DisTubeBase, DisTubeError, type DisTubeEvents, DisTubeHandler, type DisTubeOptions, DisTubeStream, DisTubeVoice, type DisTubeVoiceEvents, DisTubeVoiceManager, Events, ExtractorPlugin, type FFmpegArgs, type FFmpegOptions, type Filter, FilterManager, type FilterResolvable, type Filters, GuildIdManager, type GuildIdResolvable, Options, type OtherSongInfo, type PlayHandlerOptions, type PlayOptions, Playlist, type PlaylistInfo, Plugin, PluginType, Queue, QueueManager, type RelatedSong, RepeatMode, type ResolveOptions, type ResolvePlaylistOptions, type SearchResult, SearchResultPlaylist, SearchResultType, SearchResultVideo, Song, StreamType, TaskQueue, type TypedDisTubeEvents, checkFFmpeg, checkIntents, checkInvalidKey, chooseBestVideoFormat, DisTube as default, defaultFilters, defaultOptions, formatDuration, isClientInstance, isGuildInstance, isMemberInstance, isMessageInstance, isNsfwChannel, isObject, isRecord, isSnowflake, isSupportedVoiceChannel, isTextChannelInstance, isTruthy, isURL, isVoiceChannelEmpty, objectKeys, parseNumber, resolveGuildId, toSecond, version };
1471
+ export { type Awaitable, BaseManager, type CustomPlaylistOptions, DisTube, DisTubeBase, DisTubeError, type DisTubeEvents, DisTubeHandler, type DisTubeOptions, type DisTubePlugin, DisTubeStream, DisTubeVoice, type DisTubeVoiceEvents, DisTubeVoiceManager, Events, ExtractorPlugin, type FFmpegArg, type FFmpegArgs, type FFmpegOptions, type Falsy, type Filter, FilterManager, type FilterResolvable, type Filters, GuildIdManager, type GuildIdResolvable, InfoExtractorPlugin, type KeyOf, Options, type PlayHandlerOptions, type PlayOptions, PlayableExtractorPlugin, Playlist, type PlaylistInfo, Plugin, PluginType, Queue, QueueManager, type RelatedSong, RepeatMode, type ResolveOptions, type ResolvePlaylistOptions, Song, type SongInfo, type StreamOptions, TaskQueue, type TypedDisTubeEvents, checkFFmpeg, checkIntents, checkInvalidKey, DisTube as default, defaultFilters, defaultOptions, formatDuration, isClientInstance, isGuildInstance, isMemberInstance, isMessageInstance, isNsfwChannel, isObject, isSnowflake, isSupportedVoiceChannel, isTextChannelInstance, isTruthy, isURL, isVoiceChannelEmpty, objectKeys, resolveGuildId, version };