distube 4.0.1 → 4.0.2

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/type.ts","../src/constant.ts","../src/struct/DisTubeError.ts","../src/struct/TaskQueue.ts","../src/struct/Playlist.ts","../src/struct/SearchResult.ts","../src/struct/Song.ts","../src/core/DisTubeBase.ts","../src/core/DisTubeVoice.ts","../src/core/manager/BaseManager.ts","../src/core/manager/GuildIdManager.ts","../src/core/manager/DisTubeVoiceManager.ts","../src/core/manager/FilterManager.ts","../src/core/manager/QueueManager.ts","../src/core/DisTubeHandler.ts","../src/core/DisTubeOptions.ts","../src/core/DisTubeStream.ts","../src/struct/Queue.ts","../src/struct/Plugin.ts","../src/struct/CustomPlugin.ts","../src/struct/ExtractorPlugin.ts","../src/util.ts","../src/plugin/DirectLink.ts","../src/DisTube.ts"],"sourcesContent":["import type ytdl from \"@distube/ytdl-core\";\nimport type {\n Guild,\n GuildMember,\n GuildTextBasedChannel,\n Interaction,\n Message,\n Snowflake,\n VoiceBasedChannel,\n VoiceState,\n} from \"discord.js\";\nimport type { CustomPlugin, DisTubeVoice, ExtractorPlugin, Playlist, Queue, SearchResult, Song } from \".\";\n\nexport type Awaitable<T = any> = T | PromiseLike<T>;\n\nexport type DisTubeVoiceEvents = {\n disconnect: (error?: Error) => Awaitable;\n error: (error: Error) => Awaitable;\n finish: () => Awaitable;\n};\n\nexport type DisTubeEvents = {\n error: (channel: GuildTextBasedChannel | undefined, error: Error) => Awaitable;\n addList: (queue: Queue, playlist: Playlist) => Awaitable;\n addSong: (queue: Queue, song: Song) => Awaitable;\n playSong: (queue: Queue, song: Song) => Awaitable;\n finishSong: (queue: Queue, song: Song) => Awaitable;\n empty: (queue: Queue) => Awaitable;\n finish: (queue: Queue) => Awaitable;\n initQueue: (queue: Queue) => Awaitable;\n noRelated: (queue: Queue) => Awaitable;\n disconnect: (queue: Queue) => Awaitable;\n deleteQueue: (queue: Queue) => Awaitable;\n searchCancel: (message: Message<true>, query: string) => Awaitable;\n searchNoResult: (message: Message<true>, query: string) => Awaitable;\n searchDone: (message: Message<true>, answer: Message<true>, query: string) => Awaitable;\n searchInvalidAnswer: (message: Message<true>, answer: Message<true>, query: string) => Awaitable;\n searchResult: (message: Message<true>, results: SearchResult[], query: string) => Awaitable;\n};\n\n/**\n * An FFmpeg audio filter object\n * ```\n * {\n * name: \"bassboost\",\n * value: \"bass=g=10\"\n * }\n * ```\n * @typedef {Object} Filter\n * @prop {string} name Name of the filter\n * @prop {string} value FFmpeg audio filter(s)\n */\nexport interface Filter {\n name: string;\n value: string;\n}\n\n/**\n * Data that resolves to give an FFmpeg audio filter. This can be:\n * - A name of a default filters or custom filters (`string`)\n * - A {@link Filter} object\n * @typedef {string|Filter} FilterResolvable\n * @see {@link defaultFilters}\n * @see {@link DisTubeOptions|DisTubeOptions.customFilters}\n */\nexport type FilterResolvable = string | Filter;\n\n/**\n * FFmpeg Filters\n * ```\n * {\n * \"Filter Name\": \"Filter Value\",\n * \"bassboost\": \"bass=g=10\"\n * }\n * ```\n * @typedef {Object.<string, string>} Filters\n * @see {@link defaultFilters}\n */\nexport type Filters = Record<string, string>;\n\n/**\n * DisTube options.\n * @typedef {Object} DisTubeOptions\n * @prop {Array<CustomPlugin|ExtractorPlugin>} [plugins] DisTube plugins.\n * @prop {boolean} [emitNewSongOnly=false] Whether or not emitting {@link DisTube#event:playSong} event\n * when looping a song or next song is the same as the previous one\n * @prop {boolean} [leaveOnEmpty=true] Whether or not leaving voice channel\n * if the voice channel is empty after {@link DisTubeOptions}.emptyCooldown seconds.\n * @prop {boolean} [leaveOnFinish=false] Whether or not leaving voice channel when the queue ends.\n * @prop {boolean} [leaveOnStop=true] Whether or not leaving voice channel after using {@link DisTube#stop} function.\n * @prop {boolean} [savePreviousSongs=true] Whether or not saving the previous songs of the queue\n * and enable {@link DisTube#previous} method\n * @prop {number} [searchSongs=0] Limit of search results emits in {@link DisTube#event:searchResult} event\n * when {@link DisTube#play} method executed. If `searchSongs <= 1`, play the first result\n * @prop {string} [youtubeCookie] YouTube cookies. Read how to get it in\n * {@link https://github.com/fent/node-ytdl-core/blob/997efdd5dd9063363f6ef668bb364e83970756e7/example/cookies.js#L6-L12|YTDL's Example}\n * @prop {string} [youtubeIdentityToken] If not given; ytdl-core will try to find it.\n * You can find this by going to a video's watch page; viewing the source; and searching for \"ID_TOKEN\".\n * @prop {Filters} [customFilters] Override {@link defaultFilters} or add more ffmpeg filters.\n * Example=`{ \"Filter name\"=\"Filter value\"; \"8d\"=\"apulsator=hz=0.075\" }`\n * @prop {ytdl.getInfoOptions} [ytdlOptions] `ytdl-core` get info options\n * @prop {number} [searchCooldown=60] Built-in search cooldown in seconds (When searchSongs is bigger than 0)\n * @prop {number} [emptyCooldown=60] Built-in leave on empty cooldown in seconds (When leaveOnEmpty is true)\n * @prop {boolean} [nsfw=false] Whether or not playing age-restricted content\n * and disabling safe search in non-NSFW channel.\n * @prop {boolean} [emitAddListWhenCreatingQueue=true] Whether or not emitting `addList` event when creating a new Queue\n * @prop {boolean} [emitAddSongWhenCreatingQueue=true] Whether or not emitting `addSong` event when creating a new Queue\n * @prop {boolean} [joinNewVoiceChannel=true] Whether or not joining the new voice channel\n * when using {@link DisTube#play} method\n * @prop {StreamType} [streamType=StreamType.OPUS] Decide the {@link DisTubeStream#type} will be used\n * (Not the same as {@link DisTubeStream#type})\n */\nexport interface DisTubeOptions {\n plugins?: (CustomPlugin | ExtractorPlugin)[];\n emitNewSongOnly?: boolean;\n leaveOnFinish?: boolean;\n leaveOnStop?: boolean;\n leaveOnEmpty?: boolean;\n emptyCooldown?: number;\n savePreviousSongs?: boolean;\n searchSongs?: number;\n searchCooldown?: number;\n youtubeCookie?: string;\n youtubeIdentityToken?: string;\n customFilters?: Filters;\n ytdlOptions?: ytdl.downloadOptions;\n nsfw?: boolean;\n emitAddSongWhenCreatingQueue?: boolean;\n emitAddListWhenCreatingQueue?: boolean;\n joinNewVoiceChannel?: boolean;\n streamType?: StreamType;\n}\n\n/**\n * Data that can be resolved to give a guild id string. This can be:\n * - A guild id string | a guild {@link https://discord.js.org/#/docs/main/stable/class/Snowflake|Snowflake}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/Guild|Guild}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/Message|Message}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/BaseGuildVoiceChannel|BaseGuildVoiceChannel}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/BaseGuildTextChannel|BaseGuildTextChannel}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/VoiceState|VoiceState}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/GuildMember|GuildMember}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/Interaction|Interaction}\n * - A {@link DisTubeVoice}\n * - A {@link Queue}\n * @typedef {\n * Discord.Snowflake|\n * Discord.Guild|\n * Discord.Message|\n * Discord.BaseGuildVoiceChannel|\n * Discord.BaseGuildTextChannel|\n * Discord.VoiceState|\n * Discord.GuildMember|\n * Discord.Interaction|\n * DisTubeVoice|\n * Queue|\n * string\n * } GuildIdResolvable\n */\nexport type GuildIdResolvable =\n | Queue\n | DisTubeVoice\n | Snowflake\n | Message\n | GuildTextBasedChannel\n | VoiceBasedChannel\n | VoiceState\n | Guild\n | GuildMember\n | Interaction\n | string;\n\nexport interface OtherSongInfo {\n src?: string;\n id?: string;\n title?: string;\n name?: string;\n is_live?: boolean;\n isLive?: boolean;\n _duration_raw?: string | number;\n duration?: string | number;\n webpage_url?: string;\n url: string;\n thumbnail?: string;\n related?: RelatedSong[];\n view_count?: string | number;\n views?: string | number;\n like_count?: string | number;\n likes?: string | number;\n dislike_count?: string | number;\n dislikes?: string | number;\n repost_count?: string | number;\n reposts?: string | number;\n uploader?: string | { name: string; url: string };\n uploader_url?: string;\n age_limit?: string | number;\n chapters?: Chapter[];\n age_restricted?: boolean;\n}\n\nexport interface Chapter {\n title: string;\n start_time: number;\n}\n\nexport interface PlaylistInfo {\n source: string;\n member?: GuildMember;\n songs: Song[];\n name?: string;\n url?: string;\n thumbnail?: string;\n /** @deprecated */\n title?: string;\n /** @deprecated */\n webpage_url?: string;\n}\n\nexport type RelatedSong = Omit<Song, \"related\">;\n\n/**\n * @typedef {Object} PlayHandlerOptions\n * @param {Discord.BaseGuildTextChannel} [options.textChannel] The default text channel of the queue\n * @param {boolean} [options.skip=false] Skip the playing song (if exists) and play the added playlist instantly\n * @param {number} [options.position=0] Position of the song/playlist to add to the queue,\n * <= 0 to add to the end of the queue.\n */\nexport type PlayHandlerOptions = {\n skip?: boolean;\n position?: number;\n textChannel?: GuildTextBasedChannel;\n};\n\n/**\n * @typedef {Object} PlayOptions\n * @param {Discord.GuildMember} [member] Requested user (default is your bot)\n * @param {Discord.BaseGuildTextChannel} [textChannel] Default {@link Queue#textChannel}\n * @param {boolean} [skip=false]\n * Skip the playing song (if exists) and play the added song/playlist if `position` is 1.\n * If `position` is defined and not equal to 1, it will skip to the next song instead of the added song\n * @param {number} [position=0] Position of the song/playlist to add to the queue,\n * <= 0 to add to the end of the queue.\n * @param {Discord.Message} [message] Called message (For built-in search events. If this is a {@link https://developer.mozilla.org/en-US/docs/Glossary/Falsy|falsy value}, it will play the first result instead)\n * @param {*} [metadata] Optional metadata that can be attached to the song/playlist will be played,\n * This is useful for identification purposes when the song/playlist is passed around in events.\n * See {@link Song#metadata} or {@link Playlist#metadata}\n */\nexport interface PlayOptions extends PlayHandlerOptions, ResolveOptions<any> {\n message?: Message;\n}\n\n/**\n * @typedef {Object} ResolveOptions\n * @param {Discord.GuildMember} [member] Requested user\n * @param {*} [metadata] Metadata\n */\nexport interface ResolveOptions<T = unknown> {\n member?: GuildMember;\n metadata?: T;\n}\n\n/**\n * @typedef {ResolveOptions} ResolvePlaylistOptions\n * @param {string} [source] Source of the playlist\n */\nexport interface ResolvePlaylistOptions<T = unknown> extends ResolveOptions<T> {\n source?: string;\n}\n\n/**\n * @typedef {Object} CustomPlaylistOptions\n * @param {Discord.GuildMember} [member] A guild member creating the playlist\n * @param {Object} [properties] Additional properties such as `name`\n * @param {boolean} [parallel=true] Whether or not fetch the songs in parallel\n * @param {*} [metadata] Metadata\n */\nexport interface CustomPlaylistOptions {\n member?: GuildMember;\n properties?: Record<string, any>;\n parallel?: boolean;\n metadata?: any;\n}\n\n/**\n * The repeat mode of a {@link Queue} (enum)\n * * `DISABLED` = 0\n * * `SONG` = 1\n * * `QUEUE` = 2\n * @typedef {number} RepeatMode\n */\nexport enum RepeatMode {\n DISABLED,\n SONG,\n QUEUE,\n}\n\n/**\n * All available plugin types:\n * * `CUSTOM` = `\"custom\"`: {@link CustomPlugin}\n * * `EXTRACTOR` = `\"extractor\"`: {@link ExtractorPlugin}\n * @typedef {\"custom\"|\"extractor\"} PluginType\n */\nexport enum PluginType {\n CUSTOM = \"custom\",\n EXTRACTOR = \"extractor\",\n}\n\n/**\n * Search result types:\n * * `VIDEO` = `\"video\"`\n * * `PLAYLIST` = `\"playlist\"`\n * @typedef {\"video\"|\"playlist\"} SearchResultType\n */\nexport enum SearchResultType {\n VIDEO = \"video\",\n PLAYLIST = \"playlist\",\n}\n\n/**\n *\n * Stream types:\n * * `OPUS` = `0` (Better quality, use more resources - **Recommended**)\n * * `RAW` = `1` (Better performance, use less resources)\n * @typedef {number} StreamType\n * @type {StreamType}\n */\nexport enum StreamType {\n OPUS,\n RAW,\n}\n","import { StreamType } from \".\";\nimport type { Filters } from \".\";\n\n/**\n * Default DisTube audio filters.\n * @typedef {Object} defaultFilters\n * @prop {string} 3d 3d\n * @prop {string} bassboost bassboost\n * @prop {string} echo echo\n * @prop {string} karaoke karaoke\n * @prop {string} nightcore nightcore\n * @prop {string} vaporwave vaporwave\n * @prop {string} flanger flanger\n * @prop {string} gate gate\n * @prop {string} haas haas\n * @prop {string} reverse reverse\n * @prop {string} surround surround\n * @prop {string} mcompand mcompand\n * @prop {string} phaser phaser\n * @prop {string} tremolo tremolo\n * @prop {string} earwax earwax\n */\nexport const defaultFilters: Filters = {\n \"3d\": \"apulsator=hz=0.125\",\n bassboost: \"bass=g=10\",\n echo: \"aecho=0.8:0.9:1000:0.3\",\n flanger: \"flanger\",\n gate: \"agate\",\n haas: \"haas\",\n karaoke: \"stereotools=mlev=0.1\",\n nightcore: \"asetrate=48000*1.25,aresample=48000,bass=g=5\",\n reverse: \"areverse\",\n vaporwave: \"asetrate=48000*0.8,aresample=48000,atempo=1.1\",\n mcompand: \"mcompand\",\n phaser: \"aphaser\",\n tremolo: \"tremolo\",\n surround: \"surround\",\n earwax: \"earwax\",\n};\n\nexport const defaultOptions = {\n plugins: [],\n emitNewSongOnly: false,\n leaveOnEmpty: true,\n leaveOnFinish: false,\n leaveOnStop: true,\n savePreviousSongs: true,\n searchSongs: 0,\n ytdlOptions: {},\n searchCooldown: 60,\n emptyCooldown: 60,\n nsfw: false,\n emitAddSongWhenCreatingQueue: true,\n emitAddListWhenCreatingQueue: true,\n joinNewVoiceChannel: true,\n streamType: StreamType.OPUS,\n};\n","import { inspect } from \"node:util\";\n\nconst ERROR_MESSAGES = {\n INVALID_TYPE: (expected: (number | string) | readonly (number | string)[], got: any, name?: string) =>\n `Expected ${\n Array.isArray(expected) ? expected.map(e => (typeof e === \"number\" ? e : `'${e}'`)).join(\" or \") : `'${expected}'`\n }${name ? ` for '${name}'` : \"\"}, but got ${inspect(got)} (${typeof got})`,\n NUMBER_COMPARE: (name: string, expected: string, value: number) => `'${name}' must be ${expected} ${value}`,\n EMPTY_ARRAY: (name: string) => `'${name}' is an empty array`,\n EMPTY_FILTERED_ARRAY: (name: string, type: string) => `There is no valid '${type}' in the '${name}' array`,\n EMPTY_STRING: (name: string) => `'${name}' string must not be empty`,\n INVALID_KEY: (obj: string, key: string) => `'${key}' does not need to be provided in ${obj}`,\n MISSING_KEY: (obj: string, key: string) => `'${key}' needs to be provided in ${obj}`,\n MISSING_KEYS: (obj: string, key: string[], all: boolean) =>\n `${key.map(k => `'${k}'`).join(all ? \" and \" : \" or \")} need to be provided in ${obj}`,\n\n MISSING_INTENTS: (i: string) => `${i} intent must be provided for the Client`,\n DISABLED_OPTION: (o: string) => `DisTubeOptions.${o} is disabled`,\n ENABLED_OPTION: (o: string) => `DisTubeOptions.${o} is enabled`,\n\n NOT_IN_VOICE: \"User is not in any voice channel\",\n VOICE_FULL: \"The voice channel is full\",\n VOICE_CONNECT_FAILED: (s: number) => `Cannot connect to the voice channel after ${s} seconds`,\n VOICE_MISSING_PERMS: \"I do not have permission to join this voice channel\",\n VOICE_RECONNECT_FAILED: \"Cannot reconnect to the voice channel\",\n VOICE_DIFFERENT_GUILD: \"Cannot join a voice channel in a different guild\",\n VOICE_DIFFERENT_CLIENT: \"Cannot join a voice channel created by a different client\",\n\n NO_QUEUE: \"There is no playing queue in this guild\",\n QUEUE_EXIST: \"This guild has a Queue already\",\n PAUSED: \"The queue has been paused already\",\n RESUMED: \"The queue has been playing already\",\n NO_PREVIOUS: \"There is no previous song in this queue\",\n NO_UP_NEXT: \"There is no up next song\",\n NO_SONG_POSITION: \"Does not have any song at this position\",\n NO_PLAYING: \"There is no playing song in the queue\",\n\n NO_RESULT: \"No result found\",\n NO_RELATED: \"Cannot find any related songs\",\n CANNOT_PLAY_RELATED: \"Cannot play the related song\",\n UNAVAILABLE_VIDEO: \"This video is unavailable\",\n UNPLAYABLE_FORMATS: \"No playable format found\",\n NON_NSFW: \"Cannot play age-restricted content in non-NSFW channel\",\n NOT_SUPPORTED_URL: \"This url is not supported\",\n CANNOT_RESOLVE_SONG: (t: any) => `Cannot resolve ${inspect(t)} to a Song`,\n NO_VALID_SONG: \"'songs' array does not have any valid Song, SearchResult or url\",\n EMPTY_FILTERED_PLAYLIST:\n \"There is no valid video in the playlist\\n\" +\n \"Maybe age-restricted contents is filtered because you are in non-NSFW channel\",\n EMPTY_PLAYLIST: \"There is no valid video in the playlist\",\n};\n\ntype ErrorMessage = typeof ERROR_MESSAGES;\ntype ErrorCode = keyof ErrorMessage;\ntype StaticErrorCode = { [K in ErrorCode]-?: ErrorMessage[K] extends string ? K : never }[ErrorCode];\ntype TemplateErrorCode = Exclude<keyof typeof ERROR_MESSAGES, StaticErrorCode>;\n\nconst haveCode = (code: string): code is ErrorCode => Object.keys(ERROR_MESSAGES).includes(code);\nconst parseMessage = (m: string | ((...x: any) => string), ...args: any) => (typeof m === \"string\" ? m : m(...args));\nconst getErrorMessage = (code: string, ...args: any): string =>\n haveCode(code) ? parseMessage(ERROR_MESSAGES[code], ...args) : args[0];\nexport class DisTubeError<T extends string> extends Error {\n errorCode: string;\n constructor(code: StaticErrorCode);\n constructor(code: T extends TemplateErrorCode ? T : never, ...args: Parameters<ErrorMessage[typeof code]>);\n constructor(code: TemplateErrorCode, _: never);\n constructor(code: T extends ErrorCode ? \"This is built-in error code\" : T, message: string);\n constructor(code: string, ...args: any) {\n super(getErrorMessage(code, ...args));\n\n this.errorCode = code;\n if (Error.captureStackTrace) Error.captureStackTrace(this, DisTubeError);\n }\n\n override get name() {\n return `DisTubeError [${this.errorCode}]`;\n }\n\n get code() {\n return this.errorCode;\n }\n}\n","class Task {\n resolve!: () => void;\n promise: Promise<void>;\n resolveInfo: boolean;\n constructor(resolveInfo: boolean) {\n this.resolveInfo = resolveInfo;\n this.promise = new Promise<void>(res => {\n this.resolve = res;\n });\n }\n}\n\n/**\n * Task queuing system\n * @private\n */\nexport class TaskQueue {\n /**\n * The task array\n * @type {Task[]}\n * @private\n */\n #tasks: Task[] = [];\n\n /**\n * Waits for last task finished and queues a new task\n * @param {boolean} [resolveInfo=false] Whether the task is a resolving info task\n * @returns {Promise<void>}\n */\n public queuing(resolveInfo = false): Promise<void> {\n const next = this.remaining ? this.#tasks[this.#tasks.length - 1].promise : Promise.resolve();\n this.#tasks.push(new Task(resolveInfo));\n return next;\n }\n\n /**\n * Removes the finished task and processes the next task\n */\n public resolve(): void {\n this.#tasks.shift()?.resolve();\n }\n\n /**\n * The remaining number of tasks\n * @type {number}\n */\n public get remaining(): number {\n return this.#tasks.length;\n }\n\n /**\n * Whether or not having a resolving info task\n * @type {boolean}\n */\n public get hasResolveTask(): boolean {\n return !!this.#tasks.find(t => t.resolveInfo);\n }\n}\n","import { DisTubeError, formatDuration, isMemberInstance, isRecord } from \"..\";\nimport type { PlaylistInfo, Song } from \"..\";\nimport type { GuildMember } from \"discord.js\";\n\n/**\n * Class representing a playlist.\n * @prop {string} source Playlist source\n * @template T - The type for the metadata (if any) of the playlist\n */\nexport class Playlist<T = unknown> implements PlaylistInfo {\n source!: string;\n songs!: Song[];\n name!: string;\n #metadata!: T;\n #member?: GuildMember;\n url?: string;\n thumbnail?: string;\n [x: string]: any;\n /**\n * Create a playlist\n * @param {Song[]|PlaylistInfo} playlist Playlist\n * @param {Object} [options] Optional options\n * @param {Discord.GuildMember} [options.member] Requested user\n * @param {Object} [options.properties] Custom properties\n * @param {T} [options.metadata] Playlist metadata\n */\n constructor(\n playlist: Song[] | PlaylistInfo,\n options: {\n member?: GuildMember;\n properties?: Record<string, any>;\n metadata?: T;\n } = {},\n ) {\n const { member, properties, metadata } = options;\n\n if (\n typeof playlist !== \"object\" ||\n (!Array.isArray(playlist) && [\"source\", \"songs\"].some(key => !(key in playlist)))\n ) {\n throw new DisTubeError(\"INVALID_TYPE\", [\"Array<Song>\", \"PlaylistInfo\"], playlist, \"playlist\");\n }\n if (typeof properties !== \"undefined\" && !isRecord<any>(properties)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", properties, \"properties\");\n }\n\n if (Array.isArray(playlist)) {\n /**\n * The source of the playlist\n * @type {string}\n */\n this.source = \"youtube\";\n if (!playlist.length) throw new DisTubeError(\"EMPTY_PLAYLIST\");\n /**\n * Playlist songs.\n * @type {Array<Song>}\n */\n this.songs = playlist;\n /**\n * Playlist name.\n * @type {string}\n */\n this.name = this.songs[0].name\n ? `${this.songs[0].name} and ${this.songs.length - 1} more songs.`\n : `${this.songs.length} songs playlist`;\n this.thumbnail = this.songs[0].thumbnail;\n this.member = member || undefined;\n } else {\n this.source = (playlist.source || \"youtube\").toLowerCase();\n if (!Array.isArray(playlist.songs) || !playlist.songs.length) throw new DisTubeError(\"EMPTY_PLAYLIST\");\n this.songs = playlist.songs;\n this.name =\n playlist.name ||\n // eslint-disable-next-line deprecation/deprecation\n playlist.title ||\n (this.songs[0].name\n ? `${this.songs[0].name} and ${this.songs.length - 1} more songs.`\n : `${this.songs.length} songs playlist`);\n /**\n * Playlist URL.\n * @type {string}\n */\n // eslint-disable-next-line deprecation/deprecation\n this.url = playlist.url || playlist.webpage_url;\n /**\n * Playlist thumbnail.\n * @type {string?}\n */\n this.thumbnail = playlist.thumbnail || this.songs[0].thumbnail;\n this.member = member || playlist.member || undefined;\n }\n this.songs.map(s => s.constructor.name === \"Song\" && (s.playlist = this));\n if (properties) for (const [key, value] of Object.entries(properties)) this[key] = value;\n /**\n * Optional metadata that can be used to identify the playlist.\n * @type {T}\n */\n this.metadata = metadata as T;\n }\n\n /**\n * Playlist duration in second.\n * @type {number}\n */\n get duration() {\n return this.songs?.reduce((prev, next) => prev + (next.duration || 0), 0) || 0;\n }\n\n /**\n * Formatted duration string `hh:mm:ss`.\n * @type {string}\n */\n get formattedDuration() {\n return formatDuration(this.duration);\n }\n\n /**\n * User requested.\n * @type {Discord.GuildMember?}\n */\n get member() {\n return this.#member;\n }\n\n set member(member: GuildMember | undefined) {\n if (!isMemberInstance(member)) return;\n this.#member = member;\n this.songs.map(s => s.constructor.name === \"Song\" && (s.member = this.member));\n }\n\n /**\n * User requested.\n * @type {Discord.User?}\n */\n get user() {\n return this.member?.user;\n }\n\n get metadata() {\n return this.#metadata;\n }\n\n set metadata(metadata: T) {\n this.#metadata = metadata;\n this.songs.map(s => s.constructor.name === \"Song\" && (s.metadata = metadata));\n }\n}\n","import { DisTubeError, SearchResultType, formatDuration, toSecond } from \"..\";\nimport type { Playlist, Video } from \"@distube/ytsr\";\n\n/**\n * A abstract class representing a search result.\n * @abstract\n * @private\n */\nabstract class ISearchResult {\n source: \"youtube\";\n abstract type: SearchResultType;\n id: string;\n name: string;\n url: string;\n uploader: {\n name?: string;\n url?: string;\n };\n\n /**\n * Create a search result\n * @param {Object} info ytsr result\n */\n constructor(info: Video | Playlist) {\n /**\n * The source of the search result\n * @type {\"youtube\"}\n */\n this.source = \"youtube\";\n /**\n * YouTube video or playlist id\n * @type {string}\n */\n this.id = info.id;\n /**\n * Video or playlist title.\n * @type {string}\n */\n this.name = info.name;\n /**\n * Video or playlist URL.\n * @type {string}\n */\n this.url = info.url;\n /**\n * Video or playlist uploader\n * @type {Object}\n * @prop {string?} name Uploader name\n * @prop {string?} url Uploader url\n */\n this.uploader = {\n name: undefined,\n url: undefined,\n };\n }\n}\n\n/**\n * A class representing a video search result.\n * @extends ISearchResult\n */\nexport class SearchResultVideo extends ISearchResult {\n type: SearchResultType.VIDEO;\n views: number;\n isLive: boolean;\n duration: number;\n formattedDuration: string;\n thumbnail: string;\n constructor(info: Video) {\n super(info);\n if (info.type !== \"video\") throw new DisTubeError(\"INVALID_TYPE\", \"video\", info.type, \"type\");\n /**\n * Type of SearchResult\n * @type {SearchResultType.VIDEO}\n */\n this.type = SearchResultType.VIDEO;\n /**\n * Video views count\n * @type {number}\n */\n this.views = info.views;\n /**\n * Indicates if the video is an active live.\n * @type {boolean}\n */\n this.isLive = info.isLive;\n /**\n * Video duration.\n * @type {number}\n */\n this.duration = this.isLive ? 0 : toSecond(info.duration);\n /**\n * Formatted duration string `hh:mm:ss` or `mm:ss`.\n * @type {string}\n */\n this.formattedDuration = this.isLive ? \"Live\" : formatDuration(this.duration);\n /**\n * Video thumbnail.\n * @type {string}\n */\n this.thumbnail = info.thumbnail;\n this.uploader = {\n name: info.author?.name,\n url: info.author?.url,\n };\n }\n}\n\n/**\n * A video or playlist search result\n * @typedef {SearchResultVideo|SearchResultPlaylist} SearchResult\n */\nexport type SearchResult = SearchResultVideo | SearchResultPlaylist;\n\n/**\n * A class representing a playlist search result.\n * @extends ISearchResult\n */\nexport class SearchResultPlaylist extends ISearchResult {\n type: SearchResultType.PLAYLIST;\n length: number;\n constructor(info: Playlist) {\n super(info);\n if (info.type !== \"playlist\") throw new DisTubeError(\"INVALID_TYPE\", \"playlist\", info.type, \"type\");\n /**\n * Type of SearchResult\n * @type {SearchResultType.PLAYLIST}\n */\n this.type = SearchResultType.PLAYLIST;\n /**\n * Length of the playlist\n * @type {number}\n */\n this.length = info.length;\n this.uploader = {\n name: info.owner?.name,\n url: info.owner?.url,\n };\n }\n}\n","import { Playlist } from \"./Playlist\";\nimport { DisTubeError, formatDuration, isMemberInstance, parseNumber, toSecond } from \"..\";\nimport type ytdl from \"@distube/ytdl-core\";\nimport type { GuildMember } from \"discord.js\";\nimport type { Chapter, OtherSongInfo, RelatedSong, SearchResult } from \"..\";\n\n/**\n * Class representing a song.\n *\n * <info>If {@link Song} is added from a YouTube {@link SearchResult} or {@link Playlist},\n * some info will be missing to save your resources. It will be filled when emitting {@link DisTube#playSong} event.\n *\n * Missing info: {@link Song#likes}, {@link Song#dislikes}, {@link Song#streamURL},\n * {@link Song#related}, {@link Song#chapters}, {@link Song#age_restricted}</info>\n * @template T - The type for the metadata (if any) of the song\n */\nexport class Song<T = unknown> {\n source!: string;\n #metadata!: T;\n formats?: ytdl.videoFormat[];\n #member?: GuildMember;\n id?: string;\n name?: string;\n isLive!: boolean;\n duration!: number;\n formattedDuration?: string;\n url!: string;\n streamURL?: string;\n thumbnail?: string;\n related!: RelatedSong[];\n views!: number;\n likes!: number;\n dislikes!: number;\n uploader!: {\n name?: string;\n url?: string;\n };\n age_restricted!: boolean;\n chapters!: Chapter[];\n reposts!: number;\n #playlist?: Playlist;\n /**\n * Create a Song\n * @param {ytdl.videoInfo|SearchResult|OtherSongInfo} info Raw info\n * @param {Object} [options] Optional options\n * @param {Discord.GuildMember} [options.member] Requested user\n * @param {string} [options.source=\"youtube\"] Song source\n * @param {T} [options.metadata] Song metadata\n */\n constructor(\n info: ytdl.videoInfo | SearchResult | OtherSongInfo | ytdl.relatedVideo | RelatedSong,\n options: {\n member?: GuildMember;\n source?: string;\n metadata?: T;\n } = {},\n ) {\n const { member, source, metadata } = { source: \"youtube\", ...options };\n\n if (\n typeof source !== \"string\" ||\n ((info as OtherSongInfo).src && typeof (info as OtherSongInfo).src !== \"string\")\n ) {\n throw new DisTubeError(\"INVALID_TYPE\", \"string\", source, \"source\");\n }\n /**\n * The source of the song\n * @type {string}\n */\n this.source = ((info as OtherSongInfo)?.src || source).toLowerCase();\n /**\n * Optional metadata that can be used to identify the song. This is attached by the {@link DisTube#play} method.\n * @type {T}\n */\n this.metadata = metadata as T;\n this.member = member;\n if (this.source === \"youtube\") {\n this._patchYouTube(info as ytdl.videoInfo);\n } else {\n this._patchOther(info as OtherSongInfo);\n }\n }\n\n _patchYouTube(i: ytdl.videoInfo | SearchResult) {\n // FIXME\n const info = i as any;\n if (info.full === true) {\n /**\n * Stream formats (Available if the song is from YouTube and playing)\n * @type {ytdl.videoFormat[]?}\n * @private\n */\n this.formats = info.formats;\n // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports\n const err = require(\"@distube/ytdl-core/lib/utils\").playError(info.player_response, [\n \"UNPLAYABLE\",\n \"LIVE_STREAM_OFFLINE\",\n \"LOGIN_REQUIRED\",\n ]);\n if (err) throw err;\n\n if (!info.formats?.length) throw new DisTubeError(\"UNAVAILABLE_VIDEO\");\n }\n const details = info.videoDetails || info;\n /**\n * YouTube video id\n * @type {string?}\n */\n this.id = details.videoId || details.id;\n /**\n * Song name.\n * @type {string?}\n */\n this.name = details.title || details.name;\n /**\n * Indicates if the video is an active live.\n * @type {boolean}\n */\n this.isLive = !!details.isLive;\n /**\n * Song duration.\n * @type {number}\n */\n this.duration = this.isLive ? 0 : toSecond(details.lengthSeconds || details.length_seconds || details.duration);\n /**\n * Formatted duration string (`hh:mm:ss`, `mm:ss` or `Live`).\n * @type {string?}\n */\n this.formattedDuration = this.isLive ? \"Live\" : formatDuration(this.duration);\n /**\n * Song URL.\n * @type {string}\n */\n this.url = `https://www.youtube.com/watch?v=${this.id}`;\n /**\n * Stream / Download URL (Available if the song is playing)\n * @type {string?}\n */\n this.streamURL = undefined;\n /**\n * Song thumbnail.\n * @type {string?}\n */\n this.thumbnail =\n details.thumbnails?.sort((a: any, b: any) => b.width - a.width)?.[0]?.url ||\n details.thumbnail?.url ||\n details.thumbnail;\n /**\n * Related songs (without {@link Song#related} properties)\n * @type {Song[]}\n */\n this.related = info?.related_videos || details.related || [];\n if (!Array.isArray(this.related)) throw new DisTubeError(\"INVALID_TYPE\", \"Array\", this.related, \"Song#related\");\n this.related = this.related.map((v: any) => new Song(v, { source: this.source, metadata: this.metadata }));\n /**\n * Song views count\n * @type {number}\n */\n this.views = parseNumber(details.viewCount || details.view_count || details.views);\n /**\n * Song like count\n * @type {number}\n */\n this.likes = parseNumber(details.likes);\n /**\n * Song dislike count\n * @type {number}\n */\n this.dislikes = parseNumber(details.dislikes);\n /**\n * Song uploader\n * @type {Object}\n * @prop {string?} name Uploader name\n * @prop {string?} url Uploader url\n */\n this.uploader = {\n name: info.uploader?.name || details.author?.name,\n url: info.uploader?.url || details.author?.channel_url || details.author?.url,\n };\n /**\n * Whether or not an age-restricted content\n * @type {boolean}\n */\n this.age_restricted = !!details.age_restricted;\n /**\n * @typedef {Object} Chapter\n * @prop {string} title Chapter title\n * @prop {number} start_time Chapter start time in seconds\n */\n /**\n * Chapters information (YouTube only)\n * @type {Chapter[]}\n */\n this.chapters = details.chapters || [];\n /**\n * Song repost count\n * @type {number}\n */\n this.reposts = 0;\n }\n\n /**\n * Patch data from other source\n * @param {OtherSongInfo} info Video info\n * @private\n */\n _patchOther(info: OtherSongInfo) {\n this.id = info.id;\n this.name = info.title || info.name;\n this.isLive = Boolean(info.is_live || info.isLive);\n this.duration = this.isLive ? 0 : toSecond(info._duration_raw || info.duration);\n this.formattedDuration = this.isLive ? \"Live\" : formatDuration(this.duration);\n this.url = info.webpage_url || info.url;\n this.thumbnail = info.thumbnail;\n this.related = info.related || [];\n if (!Array.isArray(this.related)) throw new DisTubeError(\"INVALID_TYPE\", \"Array\", this.related, \"Song#related\");\n this.related = this.related.map(i => new Song(i, { source: this.source, metadata: this.metadata }));\n this.views = parseNumber(info.view_count || info.views);\n this.likes = parseNumber(info.like_count || info.likes);\n this.dislikes = parseNumber(info.dislike_count || info.dislikes);\n this.reposts = parseNumber(info.repost_count || info.reposts);\n if (typeof info.uploader === \"string\") {\n this.uploader = {\n name: info.uploader,\n url: info.uploader_url,\n };\n } else {\n this.uploader = {\n name: info.uploader?.name,\n url: info.uploader?.url,\n };\n }\n this.age_restricted = info.age_restricted || (!!info.age_limit && parseNumber(info.age_limit) >= 18);\n this.chapters = info.chapters || [];\n }\n\n /**\n * The playlist added this song\n * @type {Playlist?}\n */\n get playlist() {\n return this.#playlist;\n }\n\n set playlist(playlist: Playlist | undefined) {\n if (!(playlist instanceof Playlist)) throw new DisTubeError(\"INVALID_TYPE\", \"Playlist\", playlist, \"Song#playlist\");\n this.#playlist = playlist;\n this.member = playlist.member;\n }\n\n /**\n * User requested.\n * @type {Discord.GuildMember?}\n */\n get member() {\n return this.#member;\n }\n\n set member(member: GuildMember | undefined) {\n if (isMemberInstance(member)) this.#member = member;\n }\n\n /**\n * User requested.\n * @type {Discord.User?}\n */\n get user() {\n return this.member?.user;\n }\n\n get metadata() {\n return this.#metadata;\n }\n\n set metadata(metadata: T) {\n this.#metadata = metadata;\n }\n}\n","import type { Client, GuildTextBasedChannel } from \"discord.js\";\nimport type { DisTube, DisTubeEvents, DisTubeHandler, DisTubeVoiceManager, Options, QueueManager } from \"..\";\n\n/**\n * @private\n * @abstract\n */\nexport abstract class DisTubeBase {\n distube: DisTube;\n constructor(distube: DisTube) {\n /**\n * DisTube\n * @type {DisTube}\n */\n this.distube = distube;\n }\n /**\n * Emit the {@link DisTube} of this base\n * @param {string} eventName Event name\n * @param {...any} args arguments\n * @returns {boolean}\n */\n emit(eventName: keyof DisTubeEvents, ...args: any): boolean {\n return this.distube.emit(eventName, ...args);\n }\n /**\n * Emit error event\n * @param {Error} error error\n * @param {Discord.BaseGuildTextChannel} [channel] Text channel where the error is encountered.\n */\n emitError(error: Error, channel?: GuildTextBasedChannel) {\n this.distube.emitError(error, channel);\n }\n /**\n * The queue manager\n * @type {QueueManager}\n * @readonly\n */\n get queues(): QueueManager {\n return this.distube.queues;\n }\n /**\n * The voice manager\n * @type {DisTubeVoiceManager}\n * @readonly\n */\n get voices(): DisTubeVoiceManager {\n return this.distube.voices;\n }\n /**\n * Discord.js client\n * @type {Discord.Client}\n * @readonly\n */\n get client(): Client {\n return this.distube.client;\n }\n /**\n * DisTube options\n * @type {DisTubeOptions}\n * @readonly\n */\n get options(): Options {\n return this.distube.options;\n }\n /**\n * DisTube handler\n * @type {DisTubeHandler}\n * @readonly\n */\n get handler(): DisTubeHandler {\n return this.distube.handler;\n }\n}\n","import { TypedEmitter } from \"tiny-typed-emitter\";\nimport { DisTubeError, isSupportedVoiceChannel } from \"..\";\nimport {\n AudioPlayerStatus,\n VoiceConnectionDisconnectReason,\n VoiceConnectionStatus,\n createAudioPlayer,\n createAudioResource,\n entersState,\n joinVoiceChannel,\n} from \"@discordjs/voice\";\nimport type { Snowflake, VoiceBasedChannel, VoiceState } from \"discord.js\";\nimport type { DisTubeStream, DisTubeVoiceEvents, DisTubeVoiceManager } from \"..\";\nimport type { AudioPlayer, AudioResource, VoiceConnection } from \"@discordjs/voice\";\n\n/**\n * Create a voice connection to the voice channel\n */\nexport class DisTubeVoice extends TypedEmitter<DisTubeVoiceEvents> {\n readonly id: Snowflake;\n readonly voices: DisTubeVoiceManager;\n readonly audioPlayer: AudioPlayer;\n connection!: VoiceConnection;\n audioResource?: AudioResource;\n emittedError!: boolean;\n isDisconnected = false;\n #channel!: VoiceBasedChannel;\n #volume = 100;\n constructor(voiceManager: DisTubeVoiceManager, channel: VoiceBasedChannel) {\n super();\n /**\n * The voice manager that instantiated this connection\n * @type {DisTubeVoiceManager}\n */\n this.voices = voiceManager;\n this.id = channel.guildId;\n this.channel = channel;\n this.voices.add(this.id, this);\n this.audioPlayer = createAudioPlayer()\n .on(AudioPlayerStatus.Idle, oldState => {\n if (oldState.status !== AudioPlayerStatus.Idle) {\n delete this.audioResource;\n this.emit(\"finish\");\n }\n })\n .on(AudioPlayerStatus.Playing, () => this.#br())\n .on(\"error\", error => {\n if (this.emittedError) return;\n this.emittedError = true;\n this.emit(\"error\", error);\n });\n this.connection\n .on(VoiceConnectionStatus.Disconnected, (_, newState) => {\n if (newState.reason === VoiceConnectionDisconnectReason.Manual) {\n this.leave();\n } else if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {\n entersState(this.connection, VoiceConnectionStatus.Connecting, 5e3).catch(() => {\n if (\n ![VoiceConnectionStatus.Ready, VoiceConnectionStatus.Connecting].includes(this.connection.state.status)\n ) {\n this.leave();\n }\n });\n } else if (this.connection.rejoinAttempts < 5) {\n setTimeout(() => {\n this.connection.rejoin();\n }, (this.connection.rejoinAttempts + 1) * 5e3).unref();\n } else if (this.connection.state.status !== VoiceConnectionStatus.Destroyed) {\n this.leave(new DisTubeError(\"VOICE_RECONNECT_FAILED\"));\n }\n })\n .on(VoiceConnectionStatus.Destroyed, () => {\n this.leave();\n })\n .on(\"error\", () => undefined);\n this.connection.subscribe(this.audioPlayer);\n /**\n * Get or set the volume percentage\n * @name DisTubeVoice#volume\n * @type {number}\n */\n }\n #br() {\n if (this.audioResource?.encoder?.encoder) this.audioResource.encoder.setBitrate(this.channel.bitrate);\n }\n get channel() {\n return this.#channel;\n }\n set channel(channel: VoiceBasedChannel) {\n if (!isSupportedVoiceChannel(channel)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"BaseGuildVoiceChannel\", channel, \"DisTubeVoice#channel\");\n }\n if (channel.guildId !== this.id) throw new DisTubeError(\"VOICE_DIFFERENT_GUILD\");\n if (channel.client.user?.id !== this.voices.client.user?.id) throw new DisTubeError(\"VOICE_DIFFERENT_CLIENT\");\n if (channel.id === this.#channel?.id) return;\n if (!channel.joinable) {\n if (channel.full) throw new DisTubeError(\"VOICE_FULL\");\n else throw new DisTubeError(\"VOICE_MISSING_PERMS\");\n }\n this.connection = this.#join(channel);\n this.#channel = channel;\n this.#br();\n }\n #join(channel: VoiceBasedChannel) {\n return joinVoiceChannel({\n channelId: channel.id,\n guildId: this.id,\n adapterCreator: channel.guild.voiceAdapterCreator,\n group: channel.client.user?.id,\n });\n }\n /**\n * Join a voice channel with this connection\n * @param {Discord.BaseGuildVoiceChannel} [channel] A voice channel\n * @returns {Promise<DisTubeVoice>}\n */\n async join(channel?: VoiceBasedChannel): Promise<DisTubeVoice> {\n const TIMEOUT = 30e3;\n if (channel) this.channel = channel;\n try {\n await entersState(this.connection, VoiceConnectionStatus.Ready, TIMEOUT);\n } catch {\n if (this.connection.state.status === VoiceConnectionStatus.Ready) return this;\n if (this.connection.state.status !== VoiceConnectionStatus.Destroyed) this.connection.destroy();\n this.voices.remove(this.id);\n throw new DisTubeError(\"VOICE_CONNECT_FAILED\", TIMEOUT / 1e3);\n }\n return this;\n }\n /**\n * Leave the voice channel of this connection\n * @param {Error} [error] Optional, an error to emit with 'error' event.\n */\n leave(error?: Error) {\n this.stop(true);\n if (!this.isDisconnected) {\n this.emit(\"disconnect\", error);\n this.isDisconnected = true;\n }\n if (this.connection.state.status !== VoiceConnectionStatus.Destroyed) this.connection.destroy();\n this.voices.remove(this.id);\n }\n /**\n * Stop the playing stream\n * @param {boolean} [force=false] If true, will force the {@link DisTubeVoice#audioPlayer} to enter the Idle state\n * even if the {@link DisTubeVoice#audioResource} has silence padding frames.\n * @private\n */\n stop(force = false) {\n this.audioPlayer.stop(force);\n }\n /**\n * Play a readable stream\n * @private\n * @param {DisTubeStream} stream Readable stream\n */\n play(stream: DisTubeStream) {\n this.emittedError = false;\n stream.stream.on(\"error\", (error: NodeJS.ErrnoException) => {\n if (this.emittedError || error.code === \"ERR_STREAM_PREMATURE_CLOSE\") return;\n this.emittedError = true;\n this.emit(\"error\", error);\n });\n this.audioResource = createAudioResource(stream.stream, {\n inputType: stream.type,\n inlineVolume: true,\n });\n this.volume = this.#volume;\n this.audioPlayer.play(this.audioResource);\n }\n set volume(volume: number) {\n if (typeof volume !== \"number\" || isNaN(volume)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", volume, \"volume\");\n }\n if (volume < 0) {\n throw new DisTubeError(\"NUMBER_COMPARE\", \"Volume\", \"bigger or equal to\", 0);\n }\n this.#volume = volume;\n this.audioResource?.volume?.setVolume(Math.pow(this.#volume / 100, 0.5 / Math.log10(2)));\n }\n get volume() {\n return this.#volume;\n }\n /**\n * Playback duration of the audio resource in seconds\n * @type {number}\n */\n get playbackDuration() {\n return (this.audioResource?.playbackDuration ?? 0) / 1000;\n }\n pause() {\n this.audioPlayer.pause();\n }\n unpause() {\n this.audioPlayer.unpause();\n }\n /**\n * Whether the bot is self-deafened\n * @type {boolean}\n */\n get selfDeaf(): boolean {\n return this.connection.joinConfig.selfDeaf;\n }\n /**\n * Whether the bot is self-muted\n * @type {boolean}\n */\n get selfMute(): boolean {\n return this.connection.joinConfig.selfMute;\n }\n /**\n * Self-deafens/undeafens the bot.\n * @param {boolean} selfDeaf Whether or not the bot should be self-deafened\n * @returns {boolean} true if the voice state was successfully updated, otherwise false\n */\n setSelfDeaf(selfDeaf: boolean): boolean {\n if (typeof selfDeaf !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", selfDeaf, \"selfDeaf\");\n }\n return this.connection.rejoin({\n ...this.connection.joinConfig,\n selfDeaf,\n });\n }\n /**\n * Self-mutes/unmutes the bot.\n * @param {boolean} selfMute Whether or not the bot should be self-muted\n * @returns {boolean} true if the voice state was successfully updated, otherwise false\n */\n setSelfMute(selfMute: boolean): boolean {\n if (typeof selfMute !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", selfMute, \"selfMute\");\n }\n return this.connection.rejoin({\n ...this.connection.joinConfig,\n selfMute,\n });\n }\n /**\n * The voice state of this connection\n * @type {Discord.VoiceState?}\n */\n get voiceState(): VoiceState | undefined {\n return this.channel?.guild?.members?.me?.voice;\n }\n}\n","import { DisTubeBase } from \"..\";\nimport { Collection } from \"discord.js\";\n\n/**\n * Manages the collection of a data model.\n * @abstract\n * @private\n * @extends DisTubeBase\n */\nexport abstract class BaseManager<V> extends DisTubeBase {\n /**\n * The collection of items for this manager.\n * @type {Discord.Collection}\n */\n collection = new Collection<string, V>();\n /**\n * The size of the collection.\n * @type {Discord.Collection}\n * @abstract\n */\n get size() {\n return this.collection.size;\n }\n}\n","import { BaseManager } from \".\";\nimport { resolveGuildId } from \"../..\";\nimport type { GuildIdResolvable } from \"../..\";\n\n/**\n * Manages the collection of a data model paired with a guild id.\n * @abstract\n * @private\n * @extends BaseManager\n */\nexport abstract class GuildIdManager<V> extends BaseManager<V> {\n add(idOrInstance: GuildIdResolvable, data: V) {\n const id = resolveGuildId(idOrInstance);\n const existing = this.get(id);\n if (existing) return this;\n return this.collection.set(id, data);\n }\n get(idOrInstance: GuildIdResolvable): V | undefined {\n return this.collection.get(resolveGuildId(idOrInstance));\n }\n remove(idOrInstance: GuildIdResolvable): boolean {\n return this.collection.delete(resolveGuildId(idOrInstance));\n }\n has(idOrInstance: GuildIdResolvable): boolean {\n return this.collection.has(resolveGuildId(idOrInstance));\n }\n}\n","import { DisTubeVoice } from \"../DisTubeVoice\";\nimport { resolveGuildId } from \"../..\";\nimport { GuildIdManager } from \".\";\nimport { VoiceConnectionStatus, getVoiceConnection } from \"@discordjs/voice\";\nimport type { GuildIdResolvable } from \"../..\";\nimport type { VoiceBasedChannel } from \"discord.js\";\n\n/**\n * Manages voice connections for {@link DisTube}\n * @extends BaseManager\n */\nexport class DisTubeVoiceManager extends GuildIdManager<DisTubeVoice> {\n /**\n * Get a {@link DisTubeVoice}.\n * @method get\n * @memberof DisTubeVoiceManager#\n * @param {GuildIdResolvable} guild The queue resolvable to resolve\n * @returns {DisTubeVoice?}\n */\n /**\n * Collection of {@link DisTubeVoice}.\n * @name DisTubeVoiceManager#collection\n * @type {Discord.Collection<string, DisTubeVoice>}\n */\n /**\n * Create a {@link DisTubeVoice}\n * @param {Discord.BaseGuildVoiceChannel} channel A voice channel to join\n * @returns {DisTubeVoice}\n * @private\n */\n create(channel: VoiceBasedChannel): DisTubeVoice {\n const existing = this.get(channel.guildId);\n if (existing) {\n existing.channel = channel;\n return existing;\n }\n return new DisTubeVoice(this, channel);\n }\n /**\n * Join a voice channel\n * @param {Discord.BaseGuildVoiceChannel} channel A voice channel to join\n * @returns {Promise<DisTubeVoice>}\n */\n join(channel: VoiceBasedChannel): Promise<DisTubeVoice> {\n const existing = this.get(channel.guildId);\n if (existing) return existing.join(channel);\n return this.create(channel).join();\n }\n /**\n * Leave the connected voice channel in a guild\n * @param {GuildIdResolvable} guild Queue Resolvable\n */\n leave(guild: GuildIdResolvable) {\n const voice = this.get(guild);\n if (voice) {\n voice.leave();\n } else {\n const connection =\n getVoiceConnection(resolveGuildId(guild), this.client.user?.id) ?? getVoiceConnection(resolveGuildId(guild));\n if (connection && connection.state.status !== VoiceConnectionStatus.Destroyed) {\n connection.destroy();\n }\n }\n }\n}\n","import { BaseManager } from \".\";\nimport { DisTubeError } from \"../..\";\nimport type { FilterResolvable, Queue } from \"../..\";\n\n/**\n * Manage filters of a playing {@link Queue}\n * @extends {BaseManager}\n */\nexport class FilterManager extends BaseManager<FilterResolvable> {\n queue: Queue;\n constructor(queue: Queue) {\n super(queue.distube);\n this.queue = queue;\n }\n\n #validate(filter: FilterResolvable): FilterResolvable {\n if (\n (typeof filter === \"string\" && Object.prototype.hasOwnProperty.call(this.distube.filters, filter)) ||\n (typeof filter === \"object\" && typeof filter.name === \"string\" && typeof filter.value === \"string\")\n ) {\n return filter;\n }\n\n throw new DisTubeError(\"INVALID_TYPE\", \"FilterResolvable\", filter, \"filter\");\n }\n\n #resolveName(filter: FilterResolvable): string {\n return typeof filter === \"string\" ? filter : filter.name;\n }\n\n #resolveValue(filter: FilterResolvable): string {\n return typeof filter === \"string\" ? this.distube.filters[filter] : filter.value;\n }\n\n #apply() {\n this.queue.beginTime = this.queue.currentTime;\n this.queues.playSong(this.queue);\n }\n\n /**\n * Enable a filter or multiple filters to the manager\n * @param {FilterResolvable|FilterResolvable[]} filterOrFilters The filter or filters to enable\n * @param {boolean} [override=false] Wether or not override the applied filter with new filter value\n * @returns {FilterManager}\n */\n add(filterOrFilters: FilterResolvable | FilterResolvable[], override = false) {\n if (Array.isArray(filterOrFilters)) {\n const resolvedFilters = filterOrFilters.map(f => this.#validate(f));\n const newFilters = resolvedFilters\n .reduceRight((unique, o: any) => {\n if (\n !unique.some((obj: any) => obj === o && obj.name === o) &&\n !unique.some((obj: any) => obj !== o.name && obj.name !== o.name)\n ) {\n if (!this.has(o)) unique.push(o);\n if (this.has(o) && override) {\n this.remove(o);\n unique.push(o);\n }\n }\n return unique;\n }, [] as FilterResolvable[])\n .reverse();\n return this.set([...this.collection.values(), ...newFilters]);\n }\n return this.set([...this.collection.values(), filterOrFilters]);\n }\n\n /**\n * Clear enabled filters of the manager\n * @returns {FilterManager}\n */\n clear() {\n return this.set([]);\n }\n\n /**\n * Set the filters applied to the manager\n * @param {FilterResolvable[]} filters The filters to apply\n * @returns {FilterManager}\n */\n set(filters: FilterResolvable[]) {\n this.collection.clear();\n for (const filter of filters) {\n const resolved = this.#validate(filter);\n this.collection.set(this.#resolveName(resolved), resolved);\n }\n this.#apply();\n return this;\n }\n\n /**\n * Disable a filter or multiple filters\n * @param {FilterResolvable|FilterResolvable[]} filterOrFilters The filter or filters to disable\n * @returns {FilterManager}\n */\n remove(filterOrFilters: FilterResolvable | FilterResolvable[]) {\n const remove = (f: FilterResolvable) => this.collection.delete(this.#resolveName(this.#validate(f)));\n if (Array.isArray(filterOrFilters)) filterOrFilters.map(remove);\n else remove(filterOrFilters);\n this.#apply();\n return this;\n }\n\n /**\n * Check whether a filter enabled or not\n * @param {FilterResolvable} filter The filter to check\n * @returns {boolean}\n */\n has(filter: FilterResolvable) {\n return this.collection.has(this.#resolveName(filter));\n }\n\n /**\n * Array of enabled filter name\n * @type {Array<string>}\n * @readonly\n */\n get names() {\n return this.collection.map(f => this.#resolveName(f));\n }\n\n get values() {\n return this.collection.map(f => this.#resolveValue(f));\n }\n\n override toString() {\n return this.names.toString();\n }\n}\n","import { GuildIdManager } from \".\";\nimport { DisTubeError, DisTubeStream, Queue, RepeatMode } from \"../..\";\nimport type { DisTubeVoiceEvents, Song } from \"../..\";\nimport type { GuildTextBasedChannel, VoiceBasedChannel } from \"discord.js\";\n\n/**\n * Queue manager\n * @extends GuildIdManager\n */\nexport class QueueManager extends GuildIdManager<Queue> {\n /**\n * Collection of {@link Queue}.\n * @name QueueManager#collection\n * @type {Discord.Collection<string, Queue>}\n */\n /**\n * Create a {@link Queue}\n * @private\n * @param {Discord.BaseGuildVoiceChannel} channel A voice channel\n * @param {Song|Song[]} song First song\n * @param {Discord.BaseGuildTextChannel} textChannel Default text channel\n * @returns {Promise<Queue|true>} Returns `true` if encounter an error\n */\n async create(\n channel: VoiceBasedChannel,\n song: Song[] | Song,\n textChannel?: GuildTextBasedChannel,\n ): Promise<Queue | true> {\n if (this.has(channel.guildId)) throw new DisTubeError(\"QUEUE_EXIST\");\n const voice = this.voices.create(channel);\n const queue = new Queue(this.distube, voice, song, textChannel);\n await queue._taskQueue.queuing();\n try {\n await voice.join();\n this.#voiceEventHandler(queue);\n this.add(queue.id, queue);\n this.emit(\"initQueue\", queue);\n const err = await this.playSong(queue);\n return err || queue;\n } finally {\n queue._taskQueue.resolve();\n }\n }\n /**\n * Get a Queue from this QueueManager.\n * @method get\n * @memberof QueueManager#\n * @param {GuildIdResolvable} guild Resolvable thing from a guild\n * @returns {Queue?}\n */\n /**\n * Listen to DisTubeVoice events and handle the Queue\n * @private\n * @param {Queue} queue Queue\n */\n #voiceEventHandler(queue: Queue) {\n queue._listeners = {\n disconnect: error => {\n queue.remove();\n this.emit(\"disconnect\", queue);\n if (error) this.emitError(error, queue.textChannel);\n },\n error: error => this.#handlePlayingError(queue, error),\n finish: () => this.#handleSongFinish(queue),\n };\n for (const event of Object.keys(queue._listeners) as (keyof DisTubeVoiceEvents)[]) {\n queue.voice.on(event, queue._listeners[event]);\n }\n }\n /**\n * Handle the queue when a Song finish\n * @private\n * @param {Queue} queue queue\n * @returns {Promise<void>}\n */\n async #handleSongFinish(queue: Queue): Promise<void> {\n this.emit(\"finishSong\", queue, queue.songs[0]);\n await queue._taskQueue.queuing();\n try {\n if (queue.stopped) return;\n if (queue.repeatMode === RepeatMode.QUEUE && !queue._prev) queue.songs.push(queue.songs[0]);\n if (queue._prev) {\n if (queue.repeatMode === RepeatMode.QUEUE) queue.songs.unshift(queue.songs.pop() as Song);\n else queue.songs.unshift(queue.previousSongs.pop() as Song);\n }\n if (queue.songs.length <= 1 && (queue._next || queue.repeatMode === RepeatMode.DISABLED)) {\n if (queue.autoplay) {\n try {\n await queue.addRelatedSong();\n } catch {\n this.emit(\"noRelated\", queue);\n }\n }\n if (queue.songs.length <= 1) {\n if (this.options.leaveOnFinish) queue.voice.leave();\n if (!queue.autoplay) this.emit(\"finish\", queue);\n queue.remove();\n return;\n }\n }\n const emitPlaySong = this.#emitPlaySong(queue);\n if (!queue._prev && (queue.repeatMode !== RepeatMode.SONG || queue._next)) {\n const prev = queue.songs.shift() as Song;\n delete prev.formats;\n delete prev.streamURL;\n if (this.options.savePreviousSongs) queue.previousSongs.push(prev);\n else queue.previousSongs.push({ id: prev.id } as Song);\n }\n queue._next = queue._prev = false;\n queue.beginTime = 0;\n const err = await this.playSong(queue);\n if (!err && emitPlaySong) this.emit(\"playSong\", queue, queue.songs[0]);\n } finally {\n queue._taskQueue.resolve();\n }\n }\n /**\n * Handle error while playing\n * @private\n * @param {Queue} queue queue\n * @param {Error} error error\n */\n #handlePlayingError(queue: Queue, error: Error) {\n const song = queue.songs.shift() as Song;\n try {\n error.name = \"PlayingError\";\n error.message = `${error.message}\\nId: ${song.id}\\nName: ${song.name}`;\n } catch {}\n this.emitError(error, queue.textChannel);\n if (queue.songs.length > 0) {\n queue._next = queue._prev = false;\n queue.beginTime = 0;\n this.playSong(queue).then(e => {\n if (!e) this.emit(\"playSong\", queue, queue.songs[0]);\n });\n } else {\n queue.stop();\n }\n }\n\n /**\n * Create a ytdl stream\n * @param {Queue} queue Queue\n * @returns {DisTubeStream}\n */\n createStream(queue: Queue): DisTubeStream {\n const { duration, formats, isLive, source, streamURL } = queue.songs[0];\n const ffmpegArgs = queue.filters.size ? [\"-af\", queue.filters.values.join(\",\")] : undefined;\n const seek = duration ? queue.beginTime : undefined;\n const streamOptions = { ffmpegArgs, seek, isLive, type: this.options.streamType };\n if (source === \"youtube\") return DisTubeStream.YouTube(formats, streamOptions);\n return DisTubeStream.DirectLink(streamURL as string, streamOptions);\n }\n\n /**\n * Play a song on voice connection\n * @private\n * @param {Queue} queue The guild queue\n * @returns {Promise<boolean>} error?\n */\n async playSong(queue: Queue): Promise<boolean> {\n if (!queue) return true;\n if (!queue.songs.length) {\n queue.stop();\n return true;\n }\n if (queue.stopped) return false;\n try {\n const song = queue.songs[0];\n const { url, source, formats, streamURL } = song;\n if (source === \"youtube\" && !formats) song._patchYouTube(await this.handler.getYouTubeInfo(url));\n if (source !== \"youtube\" && !streamURL) {\n for (const plugin of [...this.distube.extractorPlugins, ...this.distube.customPlugins]) {\n if (await plugin.validate(url)) {\n const info = [plugin.getStreamURL(url), plugin.getRelatedSongs(url)] as const;\n const result = await Promise.all(info);\n song.streamURL = result[0];\n song.related = result[1];\n break;\n }\n }\n }\n const stream = this.createStream(queue);\n queue.voice.play(stream);\n song.streamURL = stream.url;\n if (queue.stopped) queue.stop();\n else if (queue.paused) queue.voice.pause();\n return false;\n } catch (e: any) {\n this.#handlePlayingError(queue, e);\n return true;\n }\n }\n /**\n * Whether or not emit playSong event\n * @param {Queue} queue Queue\n * @private\n * @returns {boolean}\n */\n #emitPlaySong(queue: Queue): boolean {\n return (\n !this.options.emitNewSongOnly ||\n (queue.repeatMode === RepeatMode.SONG && queue._next) ||\n (queue.repeatMode !== RepeatMode.SONG && queue.songs[0]?.id !== queue.songs[1]?.id)\n );\n }\n}\n","import ytpl from \"@distube/ytpl\";\nimport ytdl from \"@distube/ytdl-core\";\nimport { DisTubeBase } from \".\";\nimport {\n DisTubeError,\n Playlist,\n Queue,\n SearchResultPlaylist,\n SearchResultVideo,\n Song,\n isMessageInstance,\n isObject,\n isURL,\n isVoiceChannelEmpty,\n} from \"..\";\nimport type { Message, TextChannel, VoiceBasedChannel } from \"discord.js\";\nimport type {\n DisTube,\n OtherSongInfo,\n PlayHandlerOptions,\n ResolveOptions,\n ResolvePlaylistOptions,\n SearchResult,\n} from \"..\";\n\n/**\n * DisTube's Handler\n * @extends DisTubeBase\n * @private\n */\nexport class DisTubeHandler extends DisTubeBase {\n constructor(distube: DisTube) {\n super(distube);\n\n const client = this.client;\n if (this.options.leaveOnEmpty) {\n client.on(\"voiceStateUpdate\", oldState => {\n if (!oldState?.channel) return;\n const queue = this.queues.get(oldState);\n if (!queue) {\n if (isVoiceChannelEmpty(oldState)) {\n setTimeout(() => {\n if (!this.queues.get(oldState) && isVoiceChannelEmpty(oldState)) this.voices.leave(oldState);\n }, this.options.emptyCooldown * 1e3).unref();\n }\n return;\n }\n if (queue._emptyTimeout) {\n clearTimeout(queue._emptyTimeout);\n delete queue._emptyTimeout;\n }\n if (isVoiceChannelEmpty(oldState)) {\n queue._emptyTimeout = setTimeout(() => {\n delete queue._emptyTimeout;\n if (isVoiceChannelEmpty(oldState)) {\n queue.voice.leave();\n this.emit(\"empty\", queue);\n if (queue.stopped) queue.remove();\n }\n }, this.options.emptyCooldown * 1e3).unref();\n }\n });\n }\n }\n\n get ytdlOptions(): ytdl.getInfoOptions {\n const options: any = this.options.ytdlOptions;\n if (this.options.youtubeCookie) {\n if (!options.requestOptions) options.requestOptions = {};\n if (!options.requestOptions.headers) options.requestOptions.headers = {};\n options.requestOptions.headers.cookie = this.options.youtubeCookie;\n if (this.options.youtubeIdentityToken) {\n options.requestOptions.headers[\"x-youtube-identity-token\"] = this.options.youtubeIdentityToken;\n }\n }\n return options;\n }\n\n /**\n * @param {string} url url\n * @param {boolean} [basic=false] getBasicInfo?\n * @returns {Promise<ytdl.videoInfo>}\n */\n getYouTubeInfo(url: string, basic = false): Promise<ytdl.videoInfo> {\n if (basic) return ytdl.getBasicInfo(url, this.ytdlOptions);\n return ytdl.getInfo(url, this.ytdlOptions);\n }\n\n resolve<T = unknown>(song: Song<T>, options?: Omit<ResolveOptions, \"metadata\">): Promise<Song<T>>;\n resolve<T = unknown>(song: Playlist<T>, options?: Omit<ResolveOptions, \"metadata\">): Promise<Playlist<T>>;\n resolve<T = unknown>(song: string | SearchResult, options?: ResolveOptions<T>): Promise<Song<T> | Playlist<T>>;\n resolve<T = unknown>(\n song: ytdl.videoInfo | OtherSongInfo | ytdl.relatedVideo,\n options?: ResolveOptions<T>,\n ): Promise<Song<T>>;\n resolve<T = unknown>(song: Playlist, options: ResolveOptions<T>): Promise<Playlist<T>>;\n resolve(\n song: string | ytdl.videoInfo | Song | Playlist | SearchResult | OtherSongInfo | ytdl.relatedVideo,\n options?: ResolveOptions,\n ): Promise<Song | Playlist>;\n /**\n * Resolve a url or a supported object to a {@link Song} or {@link Playlist}\n * @param {string|Song|SearchResult|Playlist} song URL | {@link Song}| {@link SearchResult} | {@link Playlist}\n * @param {ResolveOptions} [options] Optional options\n * @returns {Promise<Song|Playlist|null>} Resolved\n */\n async resolve(\n song: string | ytdl.videoInfo | Song | Playlist | SearchResult | OtherSongInfo | ytdl.relatedVideo,\n options: ResolveOptions = {},\n ): Promise<Song | Playlist> {\n if (song instanceof Song || song instanceof Playlist) {\n if (\"metadata\" in options) song.metadata = options.metadata;\n if (\"member\" in options) song.member = options.member;\n return song;\n }\n if (song instanceof SearchResultVideo) return new Song(song, options);\n if (song instanceof SearchResultPlaylist) return this.resolvePlaylist(song.url, options);\n if (isObject(song)) {\n if (!(\"url\" in song) && !(\"id\" in song)) throw new DisTubeError(\"CANNOT_RESOLVE_SONG\", song);\n return new Song(song, options);\n }\n if (ytpl.validateID(song)) return this.resolvePlaylist(song, options);\n if (ytdl.validateURL(song)) return new Song(await this.getYouTubeInfo(song), options);\n if (isURL(song)) {\n for (const plugin of this.distube.extractorPlugins) {\n if (await plugin.validate(song)) return plugin.resolve(song, options);\n }\n throw new DisTubeError(\"NOT_SUPPORTED_URL\");\n }\n throw new DisTubeError(\"CANNOT_RESOLVE_SONG\", song);\n }\n\n resolvePlaylist<T = unknown>(\n playlist: Playlist<T> | Song<T>[] | string,\n options?: Omit<ResolvePlaylistOptions, \"metadata\">,\n ): Promise<Playlist<T>>;\n resolvePlaylist<T = undefined>(\n playlist: Playlist | Song[] | string,\n options: ResolvePlaylistOptions<T>,\n ): Promise<Playlist<T>>;\n resolvePlaylist(playlist: Playlist | Song[] | string, options?: ResolvePlaylistOptions): Promise<Playlist>;\n /**\n * Resolve Song[] or YouTube playlist url to a Playlist\n * @param {Playlist|Song[]|string} playlist Resolvable playlist\n * @param {ResolvePlaylistOptions} options Optional options\n * @returns {Promise<Playlist>}\n */\n async resolvePlaylist(playlist: Playlist | Song[] | string, options: ResolvePlaylistOptions = {}): Promise<Playlist> {\n const { member, source, metadata } = { source: \"youtube\", ...options };\n if (playlist instanceof Playlist) {\n if (\"metadata\" in options) playlist.metadata = metadata;\n if (\"member\" in options) playlist.member = member;\n return playlist;\n }\n if (typeof playlist === \"string\") {\n const info = await ytpl(playlist, { limit: Infinity });\n const songs = info.items\n .filter(v => !v.thumbnail.includes(\"no_thumbnail\"))\n .map(v => new Song(v as OtherSongInfo, { member, metadata }));\n return new Playlist(\n {\n source,\n songs,\n member,\n name: info.title,\n url: info.url,\n thumbnail: songs[0].thumbnail,\n },\n { metadata },\n );\n }\n return new Playlist(playlist, { member, properties: { source }, metadata });\n }\n\n /**\n * Search for a song, fire {@link DisTube#event:error} if not found.\n * @param {Discord.Message} message The original message from an user\n * @param {string} query The query string\n * @returns {Promise<SearchResult?>} Song info\n */\n async searchSong(message: Message<true>, query: string): Promise<SearchResult | null> {\n if (!isMessageInstance(message)) throw new DisTubeError(\"INVALID_TYPE\", \"Discord.Message\", message, \"message\");\n if (typeof query !== \"string\") throw new DisTubeError(\"INVALID_TYPE\", \"string\", query, \"query\");\n if (query.length === 0) throw new DisTubeError(\"EMPTY_STRING\", \"query\");\n const limit = this.options.searchSongs > 1 ? this.options.searchSongs : 1;\n const results = await this.distube\n .search(query, {\n limit,\n safeSearch: this.options.nsfw ? false : !(message.channel as TextChannel)?.nsfw,\n })\n .catch(() => {\n if (!this.emit(\"searchNoResult\", message, query)) {\n // eslint-disable-next-line no-console\n console.warn(\"searchNoResult event does not have any listeners! Emits `error` event instead.\");\n throw new DisTubeError(\"NO_RESULT\");\n }\n });\n if (!results) return null;\n return this.createSearchMessageCollector(message, results, query);\n }\n\n /**\n * Create a message collector for selecting search results.\n *\n * Needed events: {@link DisTube#event:searchResult}, {@link DisTube#event:searchCancel},\n * {@link DisTube#event:searchInvalidAnswer}, {@link DisTube#event:searchDone}.\n * @param {Discord.Message} message The original message from an user\n * @param {Array<SearchResult|Song|Playlist>} results The search results\n * @param {string?} [query] The query string\n * @returns {Promise<SearchResult|Song|Playlist|null>} Selected result\n */\n async createSearchMessageCollector<R extends SearchResult | Song | Playlist>(\n message: Message<true>,\n results: Array<R>,\n query?: string,\n ): Promise<R | null> {\n if (!isMessageInstance(message)) throw new DisTubeError(\"INVALID_TYPE\", \"Discord.Message\", message, \"message\");\n if (!Array.isArray(results) || results.length == 0) {\n throw new DisTubeError(\"INVALID_TYPE\", \"Array<SearchResult|Song|Playlist>\", results, \"results\");\n }\n if (this.options.searchSongs > 1) {\n const searchEvents = [\n \"searchNoResult\",\n \"searchResult\",\n \"searchCancel\",\n \"searchInvalidAnswer\",\n \"searchDone\",\n ] as const;\n for (const evn of searchEvents) {\n if (this.distube.listenerCount(evn) === 0) {\n /* eslint-disable no-console */\n console.warn(`\"searchSongs\" option is disabled due to missing \"${evn}\" listener.`);\n console.warn(\n `If you don't want to use \"${evn}\" event, simply add an empty listener (not recommended):\\n` +\n `<DisTube>.on(\"${evn}\", () => {})`,\n );\n /* eslint-enable no-console */\n this.options.searchSongs = 0;\n }\n }\n }\n const limit = this.options.searchSongs > 1 ? this.options.searchSongs : 1;\n let result = results[0];\n if (limit > 1) {\n results.splice(limit);\n this.emit(\"searchResult\", message, results, query);\n const c = message.channel;\n const answers = await c\n .awaitMessages({\n filter: (m: Message) => m.author.id === message.author.id,\n max: 1,\n time: this.options.searchCooldown * 1e3,\n errors: [\"time\"],\n })\n .catch(() => undefined);\n const ans = answers?.first();\n if (!ans) {\n this.emit(\"searchCancel\", message, query);\n return null;\n }\n const index = parseInt(ans.content, 10);\n if (isNaN(index) || index > results.length || index < 1) {\n this.emit(\"searchInvalidAnswer\", message, ans, query);\n return null;\n }\n this.emit(\"searchDone\", message, ans, query);\n result = results[index - 1];\n }\n return result;\n }\n\n /**\n * Play or add a {@link Playlist} to the queue.\n * @returns {Promise<void>}\n * @param {Discord.BaseGuildVoiceChannel} voiceChannel A voice channel\n * @param {Playlist|string} playlist A YouTube playlist url | a Playlist\n * @param {PlayHandlerOptions} [options] Optional options\n */\n async playPlaylist(\n voiceChannel: VoiceBasedChannel,\n playlist: Playlist,\n options: PlayHandlerOptions = {},\n ): Promise<void> {\n const { textChannel, skip } = { skip: false, ...options };\n const position = Number(options.position) || (skip ? 1 : 0);\n if (!(playlist instanceof Playlist)) throw new DisTubeError(\"INVALID_TYPE\", \"Playlist\", playlist, \"playlist\");\n\n const queue = this.queues.get(voiceChannel);\n\n if (!this.options.nsfw && !((queue?.textChannel || textChannel) as TextChannel)?.nsfw) {\n playlist.songs = playlist.songs.filter(s => !s.age_restricted);\n }\n if (!playlist.songs.length) {\n if (!this.options.nsfw && !(textChannel as TextChannel)?.nsfw) {\n throw new DisTubeError(\"EMPTY_FILTERED_PLAYLIST\");\n }\n throw new DisTubeError(\"EMPTY_PLAYLIST\");\n }\n if (queue) {\n if (this.options.joinNewVoiceChannel) queue.voice.channel = voiceChannel;\n queue.addToQueue(playlist.songs, position);\n if (skip) queue.skip();\n else this.emit(\"addList\", queue, playlist);\n } else {\n const newQueue = await this.queues.create(voiceChannel, playlist.songs, textChannel);\n if (newQueue instanceof Queue) {\n if (this.options.emitAddListWhenCreatingQueue) this.emit(\"addList\", newQueue, playlist);\n this.emit(\"playSong\", newQueue, newQueue.songs[0]);\n }\n }\n }\n\n /**\n * Play or add a {@link Song} to the queue.\n * @returns {Promise<void>}\n * @param {Discord.BaseGuildVoiceChannel} voiceChannel A voice channel\n * @param {Song} song A YouTube playlist url | a Playlist\n * @param {PlayHandlerOptions} [options] Optional options\n */\n async playSong(voiceChannel: VoiceBasedChannel, song: Song, options: PlayHandlerOptions = {}): Promise<void> {\n if (!(song instanceof Song)) throw new DisTubeError(\"INVALID_TYPE\", \"Song\", song, \"song\");\n const { textChannel, skip } = { skip: false, ...options };\n const position = Number(options.position) || (skip ? 1 : 0);\n\n const queue = this.queues.get(voiceChannel);\n if (!this.options.nsfw && song.age_restricted && !((queue?.textChannel || textChannel) as TextChannel)?.nsfw) {\n throw new DisTubeError(\"NON_NSFW\");\n }\n if (queue) {\n if (this.options.joinNewVoiceChannel) queue.voice.channel = voiceChannel;\n queue.addToQueue(song, position);\n if (skip) queue.skip();\n else this.emit(\"addSong\", queue, song);\n } else {\n const newQueue = await this.queues.create(voiceChannel, song, textChannel);\n if (newQueue instanceof Queue) {\n if (this.options.emitAddSongWhenCreatingQueue) this.emit(\"addSong\", newQueue, song);\n this.emit(\"playSong\", newQueue, song);\n }\n }\n }\n}\n","import { DisTubeError, StreamType, checkInvalidKey, defaultOptions } from \"..\";\nimport type ytdl from \"@distube/ytdl-core\";\nimport type { CustomPlugin, DisTubeOptions, ExtractorPlugin, Filters } from \"..\";\n\nexport class Options {\n plugins: (CustomPlugin | ExtractorPlugin)[];\n emitNewSongOnly: boolean;\n leaveOnFinish: boolean;\n leaveOnStop: boolean;\n leaveOnEmpty: boolean;\n emptyCooldown: number;\n savePreviousSongs: boolean;\n searchSongs: number;\n searchCooldown: number;\n youtubeCookie?: string;\n youtubeIdentityToken?: string;\n customFilters?: Filters;\n ytdlOptions: ytdl.getInfoOptions;\n nsfw: boolean;\n emitAddSongWhenCreatingQueue: boolean;\n emitAddListWhenCreatingQueue: boolean;\n joinNewVoiceChannel: boolean;\n streamType: StreamType;\n constructor(options: DisTubeOptions) {\n if (typeof options !== \"object\" || Array.isArray(options)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", options, \"DisTubeOptions\");\n }\n const opts = { ...defaultOptions, ...options };\n this.plugins = opts.plugins;\n this.emitNewSongOnly = opts.emitNewSongOnly;\n this.leaveOnEmpty = opts.leaveOnEmpty;\n this.leaveOnFinish = opts.leaveOnFinish;\n this.leaveOnStop = opts.leaveOnStop;\n this.savePreviousSongs = opts.savePreviousSongs;\n this.searchSongs = opts.searchSongs;\n this.youtubeCookie = opts.youtubeCookie;\n this.youtubeIdentityToken = opts.youtubeIdentityToken;\n this.customFilters = opts.customFilters;\n this.ytdlOptions = opts.ytdlOptions;\n this.searchCooldown = opts.searchCooldown;\n this.emptyCooldown = opts.emptyCooldown;\n this.nsfw = opts.nsfw;\n this.emitAddSongWhenCreatingQueue = opts.emitAddSongWhenCreatingQueue;\n this.emitAddListWhenCreatingQueue = opts.emitAddListWhenCreatingQueue;\n this.joinNewVoiceChannel = opts.joinNewVoiceChannel;\n this.streamType = opts.streamType;\n checkInvalidKey(opts, this, \"DisTubeOptions\");\n this.#validateOptions();\n }\n\n #validateOptions(options = this) {\n if (typeof options.emitNewSongOnly !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.emitNewSongOnly, \"DisTubeOptions.emitNewSongOnly\");\n }\n if (typeof options.leaveOnEmpty !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.leaveOnEmpty, \"DisTubeOptions.leaveOnEmpty\");\n }\n if (typeof options.leaveOnFinish !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.leaveOnFinish, \"DisTubeOptions.leaveOnFinish\");\n }\n if (typeof options.leaveOnStop !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.leaveOnStop, \"DisTubeOptions.leaveOnStop\");\n }\n if (typeof options.savePreviousSongs !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.savePreviousSongs, \"DisTubeOptions.savePreviousSongs\");\n }\n if (typeof options.joinNewVoiceChannel !== \"boolean\") {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n \"boolean\",\n options.joinNewVoiceChannel,\n \"DisTubeOptions.joinNewVoiceChannel\",\n );\n }\n if (typeof options.youtubeCookie !== \"undefined\" && typeof options.youtubeCookie !== \"string\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"string\", options.youtubeCookie, \"DisTubeOptions.youtubeCookie\");\n }\n if (typeof options.youtubeIdentityToken !== \"undefined\" && typeof options.youtubeIdentityToken !== \"string\") {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n \"string\",\n options.youtubeIdentityToken,\n \"DisTubeOptions.youtubeIdentityToken\",\n );\n }\n if (\n (typeof options.customFilters !== \"undefined\" && typeof options.customFilters !== \"object\") ||\n Array.isArray(options.customFilters)\n ) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", options.customFilters, \"DisTubeOptions.customFilters\");\n }\n if (typeof options.ytdlOptions !== \"object\" || Array.isArray(options.ytdlOptions)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", options.ytdlOptions, \"DisTubeOptions.ytdlOptions\");\n }\n if (typeof options.searchCooldown !== \"number\" || isNaN(options.searchCooldown)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", options.searchCooldown, \"DisTubeOptions.searchCooldown\");\n }\n if (typeof options.emptyCooldown !== \"number\" || isNaN(options.emptyCooldown)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", options.emptyCooldown, \"DisTubeOptions.emptyCooldown\");\n }\n if (typeof options.searchSongs !== \"number\" || isNaN(options.searchSongs)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", options.searchSongs, \"DisTubeOptions.searchSongs\");\n }\n if (!Array.isArray(options.plugins)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"Array<Plugin>\", options.plugins, \"DisTubeOptions.plugins\");\n }\n if (typeof options.nsfw !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.nsfw, \"DisTubeOptions.nsfw\");\n }\n if (typeof options.emitAddSongWhenCreatingQueue !== \"boolean\") {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n \"boolean\",\n options.emitAddSongWhenCreatingQueue,\n \"DisTubeOptions.emitAddSongWhenCreatingQueue\",\n );\n }\n if (typeof options.emitAddListWhenCreatingQueue !== \"boolean\") {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n \"boolean\",\n options.emitAddListWhenCreatingQueue,\n \"DisTubeOptions.emitAddListWhenCreatingQueue\",\n );\n }\n if (typeof options.streamType !== \"number\" || isNaN(options.streamType) || !StreamType[options.streamType]) {\n throw new DisTubeError(\"INVALID_TYPE\", \"StreamType\", options.streamType, \"DisTubeOptions.streamType\");\n }\n }\n}\n","import { FFmpeg } from \"prism-media\";\nimport { DisTubeError, isURL } from \"..\";\nimport { StreamType as DiscordVoiceStreamType } from \"@discordjs/voice\";\nimport type ytdl from \"@distube/ytdl-core\";\nimport type { StreamType } from \"..\";\n\ninterface StreamOptions {\n seek?: number;\n ffmpegArgs?: string[];\n isLive?: boolean;\n type?: StreamType;\n}\n\nexport const chooseBestVideoFormat = (formats: ytdl.videoFormat[], isLive = false) => {\n let filter = (format: ytdl.videoFormat) => format.hasAudio;\n if (isLive) filter = (format: ytdl.videoFormat) => format.hasAudio && format.isHLS;\n formats = formats\n .filter(filter)\n .sort((a, b) => Number(b.audioBitrate) - Number(a.audioBitrate) || Number(a.bitrate) - Number(b.bitrate));\n return formats.find(format => !format.hasVideo) || formats.sort((a, b) => Number(a.bitrate) - Number(b.bitrate))[0];\n};\n\n/**\n * Create a stream to play with {@link DisTubeVoice}\n * @private\n */\nexport class DisTubeStream {\n /**\n * Create a stream from ytdl video formats\n * @param {ytdl.videoFormat[]} formats ytdl video formats\n * @param {StreamOptions} options options\n * @returns {DisTubeStream}\n * @private\n */\n static YouTube(formats: ytdl.videoFormat[] | undefined, options: StreamOptions = {}): DisTubeStream {\n if (!formats || !formats.length) throw new DisTubeError(\"UNAVAILABLE_VIDEO\");\n if (!options || typeof options !== \"object\" || Array.isArray(options)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", options, \"options\");\n }\n const bestFormat = chooseBestVideoFormat(formats, options.isLive);\n if (!bestFormat) throw new DisTubeError(\"UNPLAYABLE_FORMATS\");\n return new DisTubeStream(bestFormat.url, options);\n }\n /**\n * Create a stream from a stream url\n * @param {string} url stream url\n * @param {StreamOptions} options options\n * @returns {DisTubeStream}\n * @private\n */\n static DirectLink(url: string, options: StreamOptions = {}): DisTubeStream {\n if (!options || typeof options !== \"object\" || Array.isArray(options)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", options, \"options\");\n }\n if (typeof url !== \"string\" || !isURL(url)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"an URL\", url);\n }\n return new DisTubeStream(url, options);\n }\n type: DiscordVoiceStreamType;\n stream: FFmpeg;\n url: string;\n /**\n * Create a DisTubeStream to play with {@link DisTubeVoice}\n * @param {string} url Stream URL\n * @param {StreamOptions} options Stream options\n * @private\n */\n constructor(url: string, options: StreamOptions) {\n /**\n * Stream URL\n * @type {string}\n */\n this.url = url;\n /**\n * Stream type\n * @type {DiscordVoice.StreamType}\n */\n this.type = !options.type ? DiscordVoiceStreamType.OggOpus : DiscordVoiceStreamType.Raw;\n const args = [\n \"-reconnect\",\n \"1\",\n \"-reconnect_streamed\",\n \"1\",\n \"-reconnect_delay_max\",\n \"5\",\n \"-i\",\n url,\n \"-analyzeduration\",\n \"0\",\n \"-loglevel\",\n \"0\",\n \"-ar\",\n \"48000\",\n \"-ac\",\n \"2\",\n \"-f\",\n ];\n if (!options.type) {\n args.push(\"opus\", \"-acodec\", \"libopus\");\n } else {\n args.push(\"s16le\");\n }\n if (typeof options.seek === \"number\" && options.seek > 0) {\n args.unshift(\"-ss\", options.seek.toString());\n }\n if (Array.isArray(options.ffmpegArgs)) {\n args.push(...options.ffmpegArgs);\n }\n /**\n * FFmpeg stream\n * @type {FFmpeg}\n */\n this.stream = new FFmpeg({ args, shell: false });\n }\n}\n","import { DisTubeBase, FilterManager } from \"../core\";\nimport { DisTubeError, RepeatMode, Song, TaskQueue, formatDuration } from \"..\";\nimport type { GuildTextBasedChannel, Snowflake } from \"discord.js\";\nimport type { DisTube, DisTubeVoice, DisTubeVoiceEvents } from \"..\";\n\n/**\n * Represents a queue.\n * @extends DisTubeBase\n */\nexport class Queue extends DisTubeBase {\n readonly id: Snowflake;\n voice: DisTubeVoice;\n songs: Song[];\n previousSongs: Song[];\n stopped: boolean;\n _next: boolean;\n _prev: boolean;\n playing: boolean;\n paused: boolean;\n repeatMode: RepeatMode;\n autoplay: boolean;\n #filters: FilterManager;\n beginTime: number;\n textChannel?: GuildTextBasedChannel;\n _emptyTimeout?: NodeJS.Timeout;\n _taskQueue: TaskQueue;\n _listeners?: DisTubeVoiceEvents;\n /**\n * Create a queue for the guild\n * @param {DisTube} distube DisTube\n * @param {DisTubeVoice} voice Voice connection\n * @param {Song|Song[]} song First song(s)\n * @param {Discord.BaseGuildTextChannel?} textChannel Default text channel\n */\n constructor(distube: DisTube, voice: DisTubeVoice, song: Song | Song[], textChannel?: GuildTextBasedChannel) {\n super(distube);\n /**\n * Voice connection of this queue.\n * @type {DisTubeVoice}\n */\n this.voice = voice;\n /**\n * Queue id (Guild id)\n * @type {Discord.Snowflake}\n */\n this.id = voice.id;\n /**\n * Get or set the stream volume. Default value: `50`.\n * @type {number}\n */\n this.volume = 50;\n /**\n * List of songs in the queue (The first one is the playing song)\n * @type {Array<Song>}\n */\n this.songs = Array.isArray(song) ? [...song] : [song];\n /**\n * List of the previous songs.\n * @type {Array<Song>}\n */\n this.previousSongs = [];\n /**\n * Whether stream is currently stopped.\n * @type {boolean}\n * @private\n */\n this.stopped = false;\n /**\n * Whether or not the last song was skipped to next song.\n * @type {boolean}\n * @private\n */\n this._next = false;\n /**\n * Whether or not the last song was skipped to previous song.\n * @type {boolean}\n * @private\n */\n this._prev = false;\n /**\n * Whether or not the stream is currently playing.\n * @type {boolean}\n */\n this.playing = true;\n /**\n * Whether or not the stream is currently paused.\n * @type {boolean}\n */\n this.paused = false;\n /**\n * Type of repeat mode (`0` is disabled, `1` is repeating a song, `2` is repeating all the queue).\n * Default value: `0` (disabled)\n * @type {RepeatMode}\n */\n this.repeatMode = RepeatMode.DISABLED;\n /**\n * Whether or not the autoplay mode is enabled.\n * Default value: `false`\n * @type {boolean}\n */\n this.autoplay = false;\n this.#filters = new FilterManager(this);\n /**\n * What time in the song to begin (in seconds).\n * @type {number}\n */\n this.beginTime = 0;\n /**\n * The text channel of the Queue. (Default: where the first command is called).\n * @type {Discord.TextChannel?}\n */\n this.textChannel = textChannel;\n /**\n * Timeout for checking empty channel\n * @type {*}\n * @private\n */\n this._emptyTimeout = undefined;\n /**\n * Task queuing system\n * @type {TaskQueue}\n * @private\n */\n this._taskQueue = new TaskQueue();\n /**\n * DisTubeVoice listener\n * @type {Object}\n * @private\n */\n this._listeners = undefined;\n }\n /**\n * The client user as a `GuildMember` of this queue's guild\n * @type {Discord.GuildMember?}\n */\n get clientMember() {\n return this.voice.channel.guild.members.me ?? undefined;\n }\n /**\n * The filter manager of the queue\n * @type {FilterManager}\n * @readonly\n */\n get filters() {\n return this.#filters;\n }\n /**\n * Formatted duration string.\n * @type {string}\n * @readonly\n */\n get formattedDuration() {\n return formatDuration(this.duration);\n }\n /**\n * Queue's duration.\n * @type {number}\n * @readonly\n */\n get duration() {\n return this.songs.length ? this.songs.reduce((prev, next) => prev + next.duration, 0) : 0;\n }\n /**\n * What time in the song is playing (in seconds).\n * @type {number}\n * @readonly\n */\n get currentTime() {\n return this.voice.playbackDuration + this.beginTime;\n }\n /**\n * Formatted {@link Queue#currentTime} string.\n * @type {string}\n * @readonly\n */\n get formattedCurrentTime() {\n return formatDuration(this.currentTime);\n }\n /**\n * The voice channel playing in.\n * @type {Discord.VoiceChannel|Discord.StageChannel|null}\n * @readonly\n */\n get voiceChannel() {\n return this.clientMember?.voice?.channel ?? null;\n }\n get volume() {\n return this.voice.volume;\n }\n set volume(value: number) {\n this.voice.volume = value;\n }\n /**\n * @private\n * Add a Song or an array of Song to the queue\n * @param {Song|Song[]} song Song to add\n * @param {number} [position=0] Position to add, <= 0 to add to the end of the queue\n * @throws {Error}\n * @returns {Queue} The guild queue\n */\n addToQueue(song: Song | Song[], position = 0): Queue {\n if (!song || (Array.isArray(song) && !song.length)) {\n throw new DisTubeError(\"INVALID_TYPE\", [\"Song\", \"Array<Song>\"], song, \"song\");\n }\n if (typeof position !== \"number\" || !Number.isInteger(position)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"integer\", position, \"position\");\n }\n if (position <= 0) {\n if (Array.isArray(song)) this.songs.push(...song);\n else this.songs.push(song);\n } else if (Array.isArray(song)) {\n this.songs.splice(position, 0, ...song);\n } else {\n this.songs.splice(position, 0, song);\n }\n if (Array.isArray(song)) song.map(s => delete s.formats);\n else delete song.formats;\n return this;\n }\n /**\n * Pause the guild stream\n * @returns {Queue} The guild queue\n */\n pause(): Queue {\n if (this.paused) throw new DisTubeError(\"PAUSED\");\n this.playing = false;\n this.paused = true;\n this.voice.pause();\n return this;\n }\n /**\n * Resume the guild stream\n * @returns {Queue} The guild queue\n */\n resume(): Queue {\n if (this.playing) throw new DisTubeError(\"RESUMED\");\n this.playing = true;\n this.paused = false;\n this.voice.unpause();\n return this;\n }\n /**\n * Set the guild stream's volume\n * @param {number} percent The percentage of volume you want to set\n * @returns {Queue} The guild queue\n */\n setVolume(percent: number): Queue {\n this.volume = percent;\n return this;\n }\n\n /**\n * Skip the playing song if there is a next song in the queue.\n * <info>If {@link Queue#autoplay} is `true` and there is no up next song,\n * DisTube will add and play a related song.</info>\n * @returns {Promise<Song>} The song will skip to\n * @throws {Error}\n */\n async skip(): Promise<Song> {\n await this._taskQueue.queuing();\n try {\n if (this.songs.length <= 1) {\n if (this.autoplay) await this.addRelatedSong();\n else throw new DisTubeError(\"NO_UP_NEXT\");\n }\n const song = this.songs[1];\n this._next = true;\n this.voice.stop();\n return song;\n } finally {\n this._taskQueue.resolve();\n }\n }\n\n /**\n * Play the previous song if exists\n * @returns {Promise<Song>} The guild queue\n * @throws {Error}\n */\n async previous(): Promise<Song> {\n await this._taskQueue.queuing();\n try {\n if (!this.options.savePreviousSongs) throw new DisTubeError(\"DISABLED_OPTION\", \"savePreviousSongs\");\n if (this.previousSongs?.length === 0 && this.repeatMode !== RepeatMode.QUEUE) {\n throw new DisTubeError(\"NO_PREVIOUS\");\n }\n const song =\n this.repeatMode === 2 ? this.songs[this.songs.length - 1] : this.previousSongs[this.previousSongs.length - 1];\n this._prev = true;\n this.voice.stop();\n return song;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Shuffle the queue's songs\n * @returns {Promise<Queue>} The guild queue\n */\n async shuffle(): Promise<Queue> {\n await this._taskQueue.queuing();\n try {\n const playing = this.songs.shift();\n if (playing === undefined) return this;\n for (let i = this.songs.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [this.songs[i], this.songs[j]] = [this.songs[j], this.songs[i]];\n }\n this.songs.unshift(playing);\n return this;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Jump to the song position in the queue.\n * The next one is 1, 2,...\n * The previous one is -1, -2,...\n * @param {number} position The song position to play\n * @returns {Promise<Song>} The new Song will be played\n * @throws {Error} if `num` is invalid number\n */\n async jump(position: number): Promise<Song> {\n await this._taskQueue.queuing();\n try {\n if (typeof position !== \"number\") throw new DisTubeError(\"INVALID_TYPE\", \"number\", position, \"position\");\n if (!position || position > this.songs.length || -position > this.previousSongs.length) {\n throw new DisTubeError(\"NO_SONG_POSITION\");\n }\n let nextSong: Song;\n if (position > 0) {\n const nextSongs = this.songs.splice(position - 1);\n if (this.options.savePreviousSongs) {\n this.previousSongs.push(...this.songs);\n } else {\n this.previousSongs.push(...this.songs.map(s => ({ id: s.id } as Song)));\n }\n this.songs = nextSongs;\n this._next = true;\n nextSong = nextSongs[1];\n } else if (!this.options.savePreviousSongs) {\n throw new DisTubeError(\"DISABLED_OPTION\", \"savePreviousSongs\");\n } else {\n this._prev = true;\n if (position !== -1) this.songs.unshift(...this.previousSongs.splice(position + 1));\n nextSong = this.previousSongs[this.previousSongs.length - 1];\n }\n this.voice.stop();\n return nextSong;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Set the repeat mode of the guild queue.\\\n * Toggle mode `(Disabled -> Song -> Queue -> Disabled ->...)` if `mode` is `undefined`\n * @param {RepeatMode?} [mode] The repeat modes (toggle if `undefined`)\n * @returns {RepeatMode} The new repeat mode\n */\n setRepeatMode(mode?: RepeatMode): RepeatMode {\n if (mode !== undefined && !Object.values(RepeatMode).includes(mode)) {\n throw new DisTubeError(\"INVALID_TYPE\", [\"RepeatMode\", \"undefined\"], mode, \"mode\");\n }\n if (mode === undefined) this.repeatMode = (this.repeatMode + 1) % 3;\n else if (this.repeatMode === mode) this.repeatMode = RepeatMode.DISABLED;\n else this.repeatMode = mode;\n return this.repeatMode;\n }\n /**\n * Set the playing time to another position\n * @param {number} time Time in seconds\n * @returns {Queue} The guild queue\n */\n seek(time: number): Queue {\n if (typeof time !== \"number\") throw new DisTubeError(\"INVALID_TYPE\", \"number\", time, \"time\");\n if (isNaN(time) || time < 0) throw new DisTubeError(\"NUMBER_COMPARE\", \"time\", \"bigger or equal to\", 0);\n this.beginTime = time;\n this.queues.playSong(this);\n return this;\n }\n /**\n * Add a related song of the playing song to the queue\n * @returns {Promise<Song>} The added song\n * @throws {Error}\n */\n async addRelatedSong(): Promise<Song> {\n if (!this.songs?.[0]) throw new DisTubeError(\"NO_PLAYING\");\n const related = this.songs[0].related.find(v => !this.previousSongs.map(s => s.id).includes(v.id));\n if (!related || !(related instanceof Song)) throw new DisTubeError(\"NO_RELATED\");\n const song = await this.handler.resolve(related, { member: this.clientMember, metadata: related.metadata });\n if (!(song instanceof Song)) throw new DisTubeError(\"CANNOT_PLAY_RELATED\");\n this.addToQueue(song);\n return song;\n }\n /**\n * Stop the guild stream and delete the queue\n */\n async stop() {\n await this._taskQueue.queuing();\n try {\n this.playing = false;\n this.paused = false;\n this.stopped = true;\n if (this.options.leaveOnStop) this.voice.leave();\n else this.voice.stop();\n this.remove();\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Remove the queue from the manager\n * (This does not leave the voice channel even if {@link DisTubeOptions|DisTubeOptions.leaveOnStop} is enabled)\n * @private\n */\n remove() {\n this.stopped = true;\n this.songs = [];\n this.previousSongs = [];\n if (this._listeners) {\n for (const event of Object.keys(this._listeners) as (keyof DisTubeVoiceEvents)[]) {\n this.voice.removeListener(event, this._listeners[event]);\n }\n }\n this.queues.remove(this.id);\n this.emit(\"deleteQueue\", this);\n }\n /**\n * Toggle autoplay mode\n * @returns {boolean} Autoplay mode state\n */\n toggleAutoplay(): boolean {\n this.autoplay = !this.autoplay;\n return this.autoplay;\n }\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\nimport type { Client, GuildTextBasedChannel } from \"discord.js\";\nimport type {\n Awaitable,\n DisTube,\n DisTubeEvents,\n DisTubeHandler,\n DisTubeVoiceManager,\n Options,\n PluginType,\n QueueManager,\n RelatedSong,\n} from \"..\";\n\n/**\n * DisTube Plugin\n * @abstract\n * @private\n */\nexport abstract class Plugin {\n abstract type: PluginType;\n distube!: DisTube;\n init(distube: DisTube) {\n /**\n * DisTube\n * @type {DisTube}\n */\n this.distube = distube;\n }\n /**\n * Type of the plugin\n * @name Plugin#type\n * @type {PluginType}\n */\n /**\n * Emit an event to the {@link DisTube} class\n * @param {string} eventName Event name\n * @param {...any} args arguments\n * @returns {boolean}\n */\n emit(eventName: keyof DisTubeEvents, ...args: any): boolean {\n return this.distube.emit(eventName, ...args);\n }\n /**\n * Emit error event to the {@link DisTube} class\n * @param {Error} error error\n * @param {Discord.BaseGuildTextChannel} [channel] Text channel where the error is encountered.\n */\n emitError(error: Error, channel?: GuildTextBasedChannel) {\n this.distube.emitError(error, channel);\n }\n /**\n * The queue manager\n * @type {QueueManager}\n * @readonly\n */\n get queues(): QueueManager {\n return this.distube.queues;\n }\n /**\n * The voice manager\n * @type {DisTubeVoiceManager}\n * @readonly\n */\n get voices(): DisTubeVoiceManager {\n return this.distube.voices;\n }\n /**\n * Discord.js client\n * @type {Discord.Client}\n * @readonly\n */\n get client(): Client {\n return this.distube.client;\n }\n /**\n * DisTube options\n * @type {DisTubeOptions}\n * @readonly\n */\n get options(): Options {\n return this.distube.options;\n }\n /**\n * DisTube handler\n * @type {DisTubeHandler}\n * @readonly\n */\n get handler(): DisTubeHandler {\n return this.distube.handler;\n }\n /**\n * Check if the string is working with this plugin\n * @param {string} _string Input string\n * @returns {boolean|Promise<boolean>}\n */\n validate(_string: string): Awaitable<boolean> {\n return false;\n }\n /**\n * Get the stream url from {@link Song#url}. Returns {@link Song#url} by default.\n * Not needed if the plugin plays song from YouTube.\n * @param {string} url Input url\n * @returns {string|Promise<string>}\n */\n getStreamURL(url: string): Awaitable<string> {\n return url;\n }\n /**\n * Get related songs from a supported url. {@link Song#member} should be `undefined`.\n * Not needed to add {@link Song#related} because it will be added with this function later.\n * @param {string} _url Input url\n * @returns {Song[]|Promise<Song[]>}\n */\n getRelatedSongs(_url: string): Awaitable<RelatedSong[]> {\n return [];\n }\n}\n","import { Plugin } from \".\";\nimport { PluginType } from \"..\";\nimport type { VoiceBasedChannel } from \"discord.js\";\nimport type { Awaitable, PlayOptions } from \"..\";\n\n/**\n * Custom Plugin\n * @extends Plugin\n * @abstract\n */\nexport abstract class CustomPlugin extends Plugin {\n readonly type = PluginType.CUSTOM;\n abstract play(voiceChannel: VoiceBasedChannel, song: string, options: PlayOptions): Awaitable<void>;\n}\n\n/**\n * This method will be executed if the url is validated.\n * @param {Discord.BaseGuildVoiceChannel} voiceChannel The voice channel will be joined\n * @param {string} song Validated `song`\n * @param {PlayOptions} [options] Optional options\n * @returns {Promise<void>}\n * @abstract\n * @method play\n * @memberof CustomPlugin#\n */\n\n/**\n * Check if the string is working with this plugin\n * @param {string} string String need to validate\n * @returns {boolean|Promise<boolean>}\n * @method validate\n * @memberof CustomPlugin#\n */\n","import { Plugin } from \".\";\nimport { PluginType } from \"..\";\nimport type { GuildMember } from \"discord.js\";\nimport type { Awaitable, Playlist, Song } from \"..\";\n\n/**\n * Extractor Plugin\n * @extends Plugin\n * @abstract\n */\nexport abstract class ExtractorPlugin extends Plugin {\n readonly type = PluginType.EXTRACTOR;\n abstract resolve<T = unknown>(\n url: string,\n options: { member?: GuildMember; metadata?: T },\n ): Awaitable<Song<T> | Playlist<T>>;\n}\n\n/**\n * Resolve the validated url to a {@link Song} or a {@link Playlist}.\n *\n * @param {string} url URL\n * @param {Object} [options] Optional options\n * @param {Discord.GuildMember} [options.member] Requested user\n * @param {*} [options.metadata] Metadata\n * @returns {Song|Playlist|Promise<Song|Playlist>}\n * @method resolve\n * @memberof ExtractorPlugin#\n * @abstract\n */\n\n/**\n * Check if the url is working with this plugin\n * @param {string} url Input url\n * @returns {boolean|Promise<boolean>}\n * @method validate\n * @memberof ExtractorPlugin#\n */\n","import { URL } from \"url\";\nimport { DisTubeError, DisTubeVoice, Queue } from \".\";\nimport { Constants, GatewayIntentBits, IntentsBitField, SnowflakeUtil } from \"discord.js\";\nimport type { GuildIdResolvable } from \".\";\nimport type {\n Client,\n ClientOptions,\n Guild,\n GuildMember,\n GuildTextBasedChannel,\n Message,\n Snowflake,\n VoiceBasedChannel,\n VoiceState,\n} from \"discord.js\";\n\nconst formatInt = (int: number) => (int < 10 ? `0${int}` : int);\n\n/**\n * Format duration to string\n * @param {number} sec Duration in seconds\n * @returns {string}\n */\nexport function formatDuration(sec: number): string {\n if (!sec || !Number(sec)) return \"00:00\";\n const seconds = Math.round(sec % 60);\n const minutes = Math.floor((sec % 3600) / 60);\n const hours = Math.floor(sec / 3600);\n if (hours > 0) return `${formatInt(hours)}:${formatInt(minutes)}:${formatInt(seconds)}`;\n if (minutes > 0) return `${formatInt(minutes)}:${formatInt(seconds)}`;\n return `00:${formatInt(seconds)}`;\n}\n/**\n * Convert formatted duration to seconds\n * @param {*} input Formatted duration string\n * @returns {number}\n */\nexport function toSecond(input: any): number {\n if (!input) return 0;\n if (typeof input !== \"string\") return Number(input) || 0;\n if (input.match(/:/g)) {\n const time = input.split(\":\").reverse();\n let s = 0;\n for (let i = 0; i < 3; i++) if (time[i]) s += Number(time[i].replace(/[^\\d.]+/g, \"\")) * Math.pow(60, i);\n if (time.length > 3) s += Number(time[3].replace(/[^\\d.]+/g, \"\")) * 24 * 60 * 60;\n return s;\n } else {\n return Number(input.replace(/[^\\d.]+/g, \"\")) || 0;\n }\n}\n/**\n * Parse number from input\n * @param {*} input Any\n * @returns {number}\n */\nexport function parseNumber(input: any): number {\n if (typeof input === \"string\") return Number(input.replace(/[^\\d.]+/g, \"\")) || 0;\n return Number(input) || 0;\n}\n/**\n * Check if the string is an URL\n * @param {string} input input\n * @returns {boolean}\n */\nexport function isURL(input: any): input is `http://${string}` | `https://${string}` {\n if (typeof input !== \"string\" || input.includes(\" \")) return false;\n try {\n const url = new URL(input);\n if (![\"https:\", \"http:\"].includes(url.protocol) || !url.host) return false;\n } catch {\n return false;\n }\n return true;\n}\n/**\n * Check if the Client has enough intents to using DisTube\n * @param {ClientOptions} options options\n */\nexport function checkIntents(options: ClientOptions): void {\n const intents = new IntentsBitField(options.intents);\n if (!intents.has(GatewayIntentBits.GuildVoiceStates)) throw new DisTubeError(\"MISSING_INTENTS\", \"GuildVoiceStates\");\n}\n\n/**\n * Check if the voice channel is empty\n * @param {Discord.VoiceState} voiceState voiceState\n * @returns {boolean}\n */\nexport function isVoiceChannelEmpty(voiceState: VoiceState): boolean {\n const guild = voiceState.guild;\n const clientId = voiceState.client.user?.id;\n if (!guild || !clientId) return false;\n const voiceChannel = guild.members.me?.voice?.channel;\n if (!voiceChannel) return false;\n const members = voiceChannel.members.filter(m => !m.user.bot);\n return !members.size;\n}\n\nexport function isSnowflake(id: any): id is Snowflake {\n try {\n return SnowflakeUtil.deconstruct(id).timestamp > SnowflakeUtil.epoch;\n } catch {\n return false;\n }\n}\n\nexport function isMemberInstance(member: any): member is GuildMember {\n return (\n !!member &&\n isSnowflake(member.id) &&\n isSnowflake(member.guild?.id) &&\n isSnowflake(member.user?.id) &&\n member.id === member.user.id\n );\n}\n\nexport function isTextChannelInstance(channel: any): channel is GuildTextBasedChannel {\n return (\n !!channel &&\n isSnowflake(channel.id) &&\n isSnowflake(channel.guildId) &&\n typeof channel.name === \"string\" &&\n Constants.TextBasedChannelTypes.includes(channel.type) &&\n typeof channel.nsfw === \"boolean\" &&\n \"messages\" in channel &&\n typeof channel.send === \"function\"\n );\n}\n\nexport function isMessageInstance(message: any): message is Message<true> {\n // Simple check for using distube normally\n return (\n !!message &&\n isSnowflake(message.id) &&\n isSnowflake(message.guildId) &&\n isMemberInstance(message.member) &&\n isTextChannelInstance(message.channel) &&\n Constants.NonSystemMessageTypes.includes(message.type) &&\n message.member.id === message.author?.id\n );\n}\n\nexport function isSupportedVoiceChannel(channel: any): channel is VoiceBasedChannel {\n return (\n !!channel &&\n isSnowflake(channel.id) &&\n isSnowflake(channel.guildId) &&\n Constants.VoiceBasedChannelTypes.includes(channel.type)\n );\n}\n\nexport function isGuildInstance(guild: any): guild is Guild {\n return !!guild && isSnowflake(guild.id) && isSnowflake(guild.ownerId) && typeof guild.name === \"string\";\n}\n\nexport function resolveGuildId(resolvable: GuildIdResolvable): Snowflake {\n let guildId: string | undefined;\n if (typeof resolvable === \"string\") {\n guildId = resolvable;\n } else if (isObject(resolvable)) {\n if (\"guildId\" in resolvable && resolvable.guildId) {\n guildId = resolvable.guildId;\n } else if (resolvable instanceof Queue || resolvable instanceof DisTubeVoice || isGuildInstance(resolvable)) {\n guildId = resolvable.id;\n } else if (\"guild\" in resolvable && isGuildInstance(resolvable.guild)) {\n guildId = resolvable.guild.id;\n }\n }\n if (!isSnowflake(guildId)) throw new DisTubeError(\"INVALID_TYPE\", \"GuildIdResolvable\", resolvable);\n return guildId;\n}\n\nexport function isClientInstance(client: any): client is Client {\n return !!client && typeof client.login === \"function\";\n}\n\nexport function checkInvalidKey(\n target: Record<string, any>,\n source: Record<string, any> | string[],\n sourceName: string,\n) {\n if (!isObject(target)) throw new DisTubeError(\"INVALID_TYPE\", \"object\", target, sourceName);\n const sourceKeys = Array.isArray(source) ? source : Object.keys(source);\n const invalidKey = Object.keys(target).find(key => !sourceKeys.includes(key));\n if (invalidKey) throw new DisTubeError(\"INVALID_KEY\", sourceName, invalidKey);\n}\n\nexport function isObject(obj: any): obj is object {\n return typeof obj === \"object\" && obj !== null && !Array.isArray(obj);\n}\n\nexport function isRecord<T = unknown>(obj: any): obj is Record<string, T> {\n return isObject(obj);\n}\n","import { request } from \"undici\";\nimport { ExtractorPlugin, Song } from \"..\";\nimport type { GuildMember } from \"discord.js\";\n\nexport class DirectLinkPlugin extends ExtractorPlugin {\n override async validate(url: string) {\n const headers = await request(url, { method: \"HEAD\" }).then(res => res.headers);\n const type = headers[\"content-type\"];\n\n if (type?.startsWith(\"audio\")) return true;\n return false;\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async resolve(url: string, options: { member?: GuildMember; metadata?: any } = {}) {\n url = url.replace(/\\/+$/, \"\");\n return new Song(\n {\n name: url.substring(url.lastIndexOf(\"/\") + 1).replace(/((\\?|#).*)?$/, \"\") || url,\n url,\n },\n options,\n );\n }\n}\n","import ytsr from \"@distube/ytsr\";\nimport { TypedEmitter } from \"tiny-typed-emitter\";\nimport {\n DirectLinkPlugin,\n DisTubeError,\n DisTubeHandler,\n DisTubeVoiceManager,\n Options,\n Playlist,\n QueueManager,\n SearchResultPlaylist,\n SearchResultType,\n SearchResultVideo,\n Song,\n checkIntents,\n defaultFilters,\n isClientInstance,\n isMemberInstance,\n isMessageInstance,\n isObject,\n isSupportedVoiceChannel,\n isTextChannelInstance,\n isURL,\n} from \".\";\nimport type { Client, GuildTextBasedChannel, VoiceBasedChannel } from \"discord.js\";\nimport type {\n CustomPlaylistOptions,\n CustomPlugin,\n DisTubeEvents,\n DisTubeOptions,\n ExtractorPlugin,\n Filters,\n GuildIdResolvable,\n PlayOptions,\n Queue,\n SearchResult,\n} from \".\";\n\n// Cannot be `import` as it's not under TS root dir\n// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports\nexport const { version }: { version: string } = require(\"../package.json\");\n\n/**\n * DisTube class\n * @extends EventEmitter\n */\nexport class DisTube extends TypedEmitter<DisTubeEvents> {\n readonly handler: DisTubeHandler;\n readonly options: Options;\n readonly client: Client;\n readonly queues: QueueManager;\n readonly voices: DisTubeVoiceManager;\n readonly extractorPlugins: ExtractorPlugin[];\n readonly customPlugins: CustomPlugin[];\n readonly filters: Filters;\n /**\n * Create a new DisTube class.\n * @param {Discord.Client} client Discord.JS client\n * @param {DisTubeOptions} [otp] Custom DisTube options\n * @example\n * const Discord = require('discord.js'),\n * DisTube = require('distube'),\n * client = new Discord.Client();\n * // Create a new DisTube\n * const distube = new DisTube.default(client, { searchSongs: 10 });\n * // client.DisTube = distube // make it access easily\n * client.login(\"Your Discord Bot Token\")\n */\n constructor(client: Client, otp: DisTubeOptions = {}) {\n super();\n this.setMaxListeners(1);\n if (!isClientInstance(client)) throw new DisTubeError(\"INVALID_TYPE\", \"Discord.Client\", client, \"client\");\n /**\n * Discord.JS client\n * @type {Discord.Client}\n */\n this.client = client;\n checkIntents(client.options);\n /**\n * DisTube options\n * @type {DisTubeOptions}\n */\n this.options = new Options(otp);\n /**\n * Voice connections manager\n * @type {DisTubeVoiceManager}\n */\n this.voices = new DisTubeVoiceManager(this);\n /**\n * DisTube's Handler\n * @type {DisTubeHandler}\n * @private\n */\n this.handler = new DisTubeHandler(this);\n /**\n * Queues manager\n * @type {QueueManager}\n */\n this.queues = new QueueManager(this);\n /**\n * DisTube filters\n * @type {Filters}\n */\n this.filters = { ...defaultFilters, ...this.options.customFilters };\n // Default plugin\n this.options.plugins.push(new DirectLinkPlugin());\n this.options.plugins.map(p => p.init(this));\n /**\n * Extractor Plugins\n * @type {ExtractorPlugin[]}\n * @private\n */\n this.extractorPlugins = this.options.plugins.filter((p): p is ExtractorPlugin => p.type === \"extractor\");\n /**\n * Custom Plugins\n * @type {CustomPlugin[]}\n * @private\n */\n this.customPlugins = this.options.plugins.filter((p): p is CustomPlugin => p.type === \"custom\");\n }\n\n static get version() {\n return version;\n }\n\n /**\n * DisTube version\n * @type {string}\n */\n get version() {\n return version;\n }\n\n /**\n * Play / add a song or playlist from url. Search and play a song if it is not a valid url.\n *\n * @param {Discord.BaseGuildVoiceChannel} voiceChannel The channel will be joined if the bot isn't in any channels,\n * the bot will be moved to this channel if `options.move` is `true`\n * @param {string|Song|SearchResult|Playlist} song URL | Search string |\n * {@link Song} | {@link SearchResult} | {@link Playlist}\n * @param {PlayOptions} [options] Optional options\n * @throws {DisTubeError}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"play\")\n * distube.play(message.member.voice.channel, args.join(\" \"), {\n * member: message.member,\n * textChannel: message.channel,\n * message\n * });\n * });\n * @returns {Promise<void>}\n */\n async play(\n voiceChannel: VoiceBasedChannel,\n song: string | Song | SearchResult | Playlist,\n options: PlayOptions = {},\n ): Promise<void> {\n if (!isSupportedVoiceChannel(voiceChannel)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"BaseGuildVoiceChannel\", voiceChannel, \"voiceChannel\");\n }\n if (!isObject(options)) throw new DisTubeError(\"INVALID_TYPE\", \"object\", options, \"options\");\n\n const { textChannel, member, skip, message, metadata } = {\n member: voiceChannel.guild.members.me ?? undefined,\n textChannel: options?.message?.channel,\n skip: false,\n ...options,\n };\n const position = Number(options.position) || (skip ? 1 : 0);\n\n if (message && !isMessageInstance(message)) {\n throw new DisTubeError(\"INVALID_TYPE\", [\"Discord.Message\", \"a falsy value\"], message, \"options.message\");\n }\n if (textChannel && !isTextChannelInstance(textChannel)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"Discord.GuildTextBasedChannel\", textChannel, \"options.textChannel\");\n }\n if (member && !isMemberInstance(member)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"Discord.GuildMember\", member, \"options.member\");\n }\n const queue = this.getQueue(voiceChannel);\n const queuing = !!queue && !queue._taskQueue.hasResolveTask;\n if (queuing) await queue?._taskQueue.queuing(true);\n try {\n if (typeof song === \"string\") {\n for (const plugin of this.customPlugins) {\n if (await plugin.validate(song)) {\n await plugin.play(voiceChannel, song, options);\n return;\n }\n }\n }\n if (typeof song === \"string\" && !isURL(song)) {\n if (!message) {\n song = (await this.search(song, { limit: 1 }))[0];\n } else {\n const result = await this.handler.searchSong(message, song);\n if (!result) return;\n song = result;\n }\n }\n song = await this.handler.resolve(song, { member, metadata });\n if (song instanceof Playlist) {\n await this.handler.playPlaylist(voiceChannel, song, { textChannel, skip, position });\n } else {\n await this.handler.playSong(voiceChannel, song, { textChannel, skip, position });\n }\n } catch (e: any) {\n if (!(e instanceof DisTubeError)) {\n try {\n e.name = \"PlayError\";\n e.message = `${typeof song === \"string\" ? song : song.url}\\n${e.message}`;\n } catch {}\n }\n throw e;\n } finally {\n if (queuing) queue?._taskQueue.resolve();\n }\n }\n\n /**\n * Create a custom playlist\n * @returns {Promise<Playlist>}\n * @param {Array<string|Song|SearchResult>} songs Array of url, Song or SearchResult\n * @param {CustomPlaylistOptions} [options] Optional options\n * @example\n * const songs = [\"https://www.youtube.com/watch?v=xxx\", \"https://www.youtube.com/watch?v=yyy\"];\n * const playlist = await distube.createCustomPlaylist(songs, {\n * member: message.member,\n * properties: { name: \"My playlist name\", source: \"custom\" },\n * parallel: true\n * });\n * distube.play(voiceChannel, playlist, { ... });\n */\n async createCustomPlaylist(\n songs: (string | Song | SearchResult)[],\n options: CustomPlaylistOptions = {},\n ): Promise<Playlist> {\n const { member, properties, parallel, metadata } = { parallel: true, ...options };\n if (!Array.isArray(songs)) throw new DisTubeError(\"INVALID_TYPE\", \"Array\", songs, \"songs\");\n if (!songs.length) throw new DisTubeError(\"EMPTY_ARRAY\", \"songs\");\n const filteredSongs = songs.filter(\n song => song instanceof Song || isURL(song) || (typeof song !== \"string\" && song.type === SearchResultType.VIDEO),\n );\n if (!filteredSongs.length) throw new DisTubeError(\"NO_VALID_SONG\");\n if (member && !isMemberInstance(member)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"Discord.Member\", member, \"options.member\");\n }\n if (!filteredSongs.length) throw new DisTubeError(\"NO_VALID_SONG\");\n let resolvedSongs: Song[];\n if (parallel) {\n const promises = filteredSongs.map((song: string | Song | SearchResult) =>\n this.handler.resolve(song, { member, metadata }).catch(() => undefined),\n );\n resolvedSongs = (await Promise.all(promises)).filter((s: any): s is Song => !!s);\n } else {\n const resolved = [];\n for (const song of filteredSongs) {\n resolved.push(await this.handler.resolve(song, { member, metadata }).catch(() => undefined));\n }\n resolvedSongs = resolved.filter((s: any): s is Song => !!s);\n }\n return new Playlist(resolvedSongs, { member, properties, metadata });\n }\n\n search(\n string: string,\n options?: { type?: SearchResultType; limit?: number; safeSearch?: boolean; retried?: boolean },\n ): Promise<Array<SearchResult>>;\n search(\n string: string,\n options?: { type?: SearchResultType.VIDEO; limit?: number; safeSearch?: boolean; retried?: boolean },\n ): Promise<Array<SearchResultVideo>>;\n search(\n string: string,\n options: { type: SearchResultType.PLAYLIST; limit?: number; safeSearch?: boolean; retried?: boolean },\n ): Promise<Array<SearchResultPlaylist>>;\n /**\n * Search for a song. You can customize how user answers instead of send a number.\n * Then use {@link DisTube#play} to play it.\n *\n * @param {string} string The string search for\n * @param {Object} options Search options\n * @param {number} [options.limit=10] Limit the results\n * @param {SearchResultType} [options.type=SearchResultType.VIDEO] Type of results (`video` or `playlist`).\n * @param {boolean} [options.safeSearch=false] Whether or not use safe search (YouTube restricted mode)\n * @throws {Error}\n * @returns {Promise<Array<SearchResult>>} Array of results\n */\n async search(\n string: string,\n options: {\n type?: SearchResultType;\n limit?: number;\n safeSearch?: boolean;\n retried?: boolean;\n } = {},\n ): Promise<Array<SearchResult>> {\n const opts = { type: SearchResultType.VIDEO, limit: 10, safeSearch: false, ...options };\n if (typeof opts.type !== \"string\" || ![\"video\", \"playlist\"].includes(opts.type)) {\n throw new DisTubeError(\"INVALID_TYPE\", [\"video\", \"playlist\"], opts.type, \"options.type\");\n }\n if (typeof opts.limit !== \"number\") throw new DisTubeError(\"INVALID_TYPE\", \"number\", opts.limit, \"options.limit\");\n if (opts.limit < 1) throw new DisTubeError(\"NUMBER_COMPARE\", \"option.limit\", \"bigger or equal to\", 1);\n if (typeof opts.safeSearch !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", opts.safeSearch, \"options.safeSearch\");\n }\n\n try {\n const search = await ytsr(string, opts);\n const results = search.items.map(i => {\n if (i.type === \"video\") return new SearchResultVideo(i);\n return new SearchResultPlaylist(i as any);\n });\n if (results.length === 0) throw new DisTubeError(\"NO_RESULT\");\n return results;\n } catch (e) {\n if (options.retried) throw e;\n options.retried = true;\n return this.search(string, options);\n }\n }\n\n /**\n * Get the guild queue\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Queue?}\n * @throws {Error}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"queue\") {\n * const queue = distube.getQueue(message);\n * message.channel.send('Current queue:\\n' + queue.songs.map((song, id) =>\n * `**${id+1}**. [${song.name}](${song.url}) - \\`${song.formattedDuration}\\``\n * ).join(\"\\n\"));\n * }\n * });\n */\n getQueue(guild: GuildIdResolvable): Queue | undefined {\n return this.queues.get(guild);\n }\n\n /**\n * Pause the guild stream\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Queue} The guild queue\n * @throws {Error}\n */\n pause(guild: GuildIdResolvable): Queue {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.pause();\n }\n\n /**\n * Resume the guild stream\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Queue} The guild queue\n * @throws {Error}\n */\n resume(guild: GuildIdResolvable): Queue {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.resume();\n }\n\n /**\n * Stop the guild stream\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Promise<void>}\n * @throws {Error}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"stop\") {\n * distube.stop(message);\n * message.channel.send(\"Stopped the queue!\");\n * }\n * });\n */\n stop(guild: GuildIdResolvable): Promise<void> {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.stop();\n }\n\n /**\n * Set the guild stream's volume\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @param {number} percent The percentage of volume you want to set\n * @returns {Queue} The guild queue\n * @throws {Error}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"volume\")\n * distube.setVolume(message, Number(args[0]));\n * });\n */\n setVolume(guild: GuildIdResolvable, percent: number): Queue {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.setVolume(percent);\n }\n\n /**\n * Skip the playing song if there is a next song in the queue.\n * <info>If {@link Queue#autoplay} is `true` and there is no up next song,\n * DisTube will add and play a related song.</info>\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Promise<Song>} The new Song will be played\n * @throws {Error}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"skip\")\n * distube.skip(message);\n * });\n */\n skip(guild: GuildIdResolvable): Promise<Song> {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.skip();\n }\n\n /**\n * Play the previous song\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Promise<Song>} The new Song will be played\n * @throws {Error}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"previous\")\n * distube.previous(message);\n * });\n */\n previous(guild: GuildIdResolvable): Promise<Song> {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.previous();\n }\n\n /**\n * Shuffle the guild queue songs\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Promise<Queue>} The guild queue\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"shuffle\")\n * distube.shuffle(message);\n * });\n */\n shuffle(guild: GuildIdResolvable): Promise<Queue> {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.shuffle();\n }\n\n /**\n * Jump to the song number in the queue.\n * The next one is 1, 2,...\n * The previous one is -1, -2,...\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @param {number} num The song number to play\n * @returns {Promise<Song>} The new Song will be played\n * @throws {Error} if `num` is invalid number (0 < num < {@link Queue#songs}.length)\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"jump\")\n * distube.jump(message, parseInt(args[0]))\n * .catch(err => message.channel.send(\"Invalid song number.\"));\n * });\n */\n jump(guild: GuildIdResolvable, num: number): Promise<Song> {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.jump(num);\n }\n\n /**\n * Set the repeat mode of the guild queue.\\\n * Toggle mode `(Disabled -> Song -> Queue -> Disabled ->...)` if `mode` is `undefined`\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @param {RepeatMode?} [mode] The repeat modes (toggle if `undefined`)\n * @returns {RepeatMode} The new repeat mode\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"repeat\") {\n * let mode = distube.setRepeatMode(message, parseInt(args[0]));\n * mode = mode ? mode == 2 ? \"Repeat queue\" : \"Repeat song\" : \"Off\";\n * message.channel.send(\"Set repeat mode to `\" + mode + \"`\");\n * }\n * });\n * @example\n * const { RepeatMode } = require(\"distube\");\n * let mode;\n * switch(distube.setRepeatMode(message, parseInt(args[0]))) {\n * case RepeatMode.DISABLED:\n * mode = \"Off\";\n * break;\n * case RepeatMode.SONG:\n * mode = \"Repeat a song\";\n * break;\n * case RepeatMode.QUEUE:\n * mode = \"Repeat all queue\";\n * break;\n * }\n * message.channel.send(\"Set repeat mode to `\" + mode + \"`\");\n */\n setRepeatMode(guild: GuildIdResolvable, mode?: number): number {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.setRepeatMode(mode);\n }\n\n /**\n * Toggle autoplay mode\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {boolean} Autoplay mode state\n * @throws {Error}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"autoplay\") {\n * const mode = distube.toggleAutoplay(message);\n * message.channel.send(\"Set autoplay mode to `\" + (mode ? \"On\" : \"Off\") + \"`\");\n * }\n * });\n */\n toggleAutoplay(guild: GuildIdResolvable): boolean {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n q.autoplay = !q.autoplay;\n return q.autoplay;\n }\n\n /**\n * Add related song to the queue\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Promise<Song>} The guild queue\n */\n addRelatedSong(guild: GuildIdResolvable): Promise<Song> {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.addRelatedSong();\n }\n\n /**\n * Set the playing time to another position\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @param {number} time Time in seconds\n * @returns {Queue} Seeked queue\n * @example\n * client.on('message', message => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command = 'seek')\n * distube.seek(message, Number(args[0]));\n * });\n */\n seek(guild: GuildIdResolvable, time: number): Queue {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.seek(time);\n }\n\n /**\n * Emit error event\n * @param {Error} error error\n * @param {Discord.BaseGuildTextChannel} [channel] Text channel where the error is encountered.\n * @private\n */\n emitError(error: Error, channel?: GuildTextBasedChannel): void {\n if (this.listeners(\"error\").length) {\n this.emit(\"error\", channel, error);\n } else {\n /* eslint-disable no-console */\n console.error(error);\n console.warn(\"Unhandled 'error' event.\");\n console.warn(\n \"See: https://distube.js.org/#/docs/DisTube/stable/class/DisTube?scrollTo=e-error and https://nodejs.org/api/events.html#events_error_events\",\n );\n /* eslint-enable no-console */\n }\n }\n}\n\nexport default DisTube;\n\n/**\n * Emitted after DisTube add a new playlist to the playing {@link Queue}.\n *\n * @event DisTube#addList\n * @param {Queue} queue The guild queue\n * @param {Playlist} playlist Playlist info\n * @example\n * distube.on(\"addList\", (queue, playlist) => queue.textChannel.send(\n * `Added \\`${playlist.name}\\` playlist (${playlist.songs.length} songs) to the queue!`\n * ));\n */\n\n/**\n * Emitted after DisTube add a new song to the playing {@link Queue}.\n *\n * @event DisTube#addSong\n * @param {Queue} queue The guild queue\n * @param {Song} song Added song\n * @example\n * distube.on(\"addSong\", (queue, song) => queue.textChannel.send(\n * `Added ${song.name} - \\`${song.formattedDuration}\\` to the queue by ${song.user}.`\n * ));\n */\n\n/**\n * Emitted when there is no user in the voice channel,\n * {@link DisTubeOptions}.leaveOnEmpty is `true` and there is a playing queue.\n *\n * If there is no playing queue (stopped and {@link DisTubeOptions}.leaveOnStop is `false`),\n * it will leave the channel without emitting this event.\n * @event DisTube#empty\n * @param {Queue} queue The guild queue\n * @example\n * distube.on(\"empty\", queue => queue.textChannel.send(\"Channel is empty. Leaving the channel\"))\n */\n\n/**\n * Emitted when DisTube encounters an error while playing songs.\n *\n * @event DisTube#error\n * @param {Discord.BaseGuildTextChannel?} channel Text channel where the error is encountered.\n * @param {Error} error The error encountered\n * @example\n * distube.on('error', (channel, e) => {\n * if (channel) channel.send(`An error encountered: ${e}`)\n * else console.error(e)\n * })\n */\n\n/**\n * Emitted when there is no more song in the queue and {@link Queue#autoplay} is `false`.\n * DisTube will leave voice channel if {@link DisTubeOptions}.leaveOnFinish is `true`.\n *\n * @event DisTube#finish\n * @param {Queue} queue The guild queue\n * @example\n * distube.on(\"finish\", queue => queue.textChannel.send(\"No more song in queue\"));\n */\n\n/**\n * Emitted when DisTube initialize a queue to change queue default properties.\n *\n * @event DisTube#initQueue\n * @param {Queue} queue The guild queue\n * @example\n * distube.on(\"initQueue\", queue => {\n * queue.autoplay = false;\n * queue.volume = 100;\n * });\n */\n\n/**\n * Emitted when {@link Queue#autoplay} is `true`, {@link Queue#songs} is empty,\n * and DisTube cannot find related songs to play.\n *\n * @event DisTube#noRelated\n * @param {Queue} queue The guild queue\n * @example\n * distube.on(\"noRelated\", queue => queue.textChannel.send(\"Can't find related video to play.\"));\n */\n\n/**\n * Emitted when DisTube play a song.\n *\n * If {@link DisTubeOptions}.emitNewSongOnly is `true`,\n * this event is not emitted when looping a song or next song is the previous one.\n *\n * @event DisTube#playSong\n * @param {Queue} queue The guild queue\n * @param {Song} song Playing song\n * @example\n * distube.on(\"playSong\", (queue, song) => queue.textChannel.send(\n * `Playing \\`${song.name}\\` - \\`${song.formattedDuration}\\`\\nRequested by: ${song.user}`\n * ));\n */\n\n/**\n * Emitted when DisTube cannot find any results for the query.\n *\n * @event DisTube#searchNoResult\n * @param {Discord.Message} message The user message called play method\n * @param {string} query The search query\n * @example\n * distube.on(\"searchNoResult\", (message, query) => message.channel.send(`No result found for ${query}!`));\n */\n\n/**\n * Emitted when {@link DisTubeOptions|DisTubeOptions.searchSongs} bigger than 0,\n * and song param of {@link DisTube#play} is invalid url.\n * DisTube will wait for user's next message to choose a song manually.\n * <info>{@link https://support.google.com/youtube/answer/7354993|Safe search} is enabled\n * if {@link DisTubeOptions}.nsfw is disabled and the message's channel is not a nsfw channel.</info>\n *\n * @event DisTube#searchResult\n * @param {Discord.Message} message The user message called play method\n * @param {Array<SearchResult>} results Searched results\n * @param {string} query The search query\n * @example\n * // DisTubeOptions.searchSongs > 0\n * distube.on(\"searchResult\", (message, results) => {\n * message.channel.send(`**Choose an option from below**\\n${\n * results.map((song, i) => `**${i + 1}**. ${song.name} - \\`${song.formattedDuration}\\``).join(\"\\n\")\n * }\\n*Enter anything else or wait 60 seconds to cancel*`);\n * });\n */\n\n/**\n * Emitted when {@link DisTubeOptions|DisTubeOptions.searchSongs} bigger than 0,\n * and the search canceled due to {@link DisTubeOptions|DisTubeOptions.searchTimeout}.\n *\n * @event DisTube#searchCancel\n * @param {Discord.Message} message The user message called play method\n * @param {string} query The search query\n * @example\n * // DisTubeOptions.searchSongs > 0\n * distube.on(\"searchCancel\", (message) => message.channel.send(`Searching canceled`));\n */\n\n/**\n * Emitted when {@link DisTubeOptions|DisTubeOptions.searchSongs} bigger than 0,\n * and the search canceled due to user's next message is not a number or out of results range.\n *\n * @event DisTube#searchInvalidAnswer\n * @param {Discord.Message} message The user message called play method\n * @param {Discord.Message} answer The answered message of user\n * @param {string} query The search query\n * @example\n * // DisTubeOptions.searchSongs > 0\n * distube.on(\"searchInvalidAnswer\", (message) => message.channel.send(`You answered an invalid number!`));\n */\n\n/**\n * Emitted when {@link DisTubeOptions|DisTubeOptions.searchSongs} bigger than 0,\n * and after the user chose a search result to play.\n *\n * @event DisTube#searchDone\n * @param {Discord.Message} message The user message called play method\n * @param {Discord.Message} answer The answered message of user\n * @param {string} query The search query\n */\n\n/**\n * Emitted when the bot is disconnected to a voice channel.\n *\n * @event DisTube#disconnect\n * @param {Queue} queue The guild queue\n */\n\n/**\n * Emitted when a {@link Queue} is deleted with any reasons.\n *\n * @event DisTube#deleteQueue\n * @param {Queue} queue The guild queue\n */\n\n/**\n * Emitted when DisTube finished a song.\n *\n * @event DisTube#finishSong\n * @param {Queue} queue The guild queue\n * @param {Song} song Finished song\n */\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/type.ts","../src/constant.ts","../src/struct/DisTubeError.ts","../src/struct/TaskQueue.ts","../src/struct/Playlist.ts","../src/struct/SearchResult.ts","../src/struct/Song.ts","../src/core/DisTubeBase.ts","../src/core/DisTubeVoice.ts","../src/core/manager/BaseManager.ts","../src/core/manager/GuildIdManager.ts","../src/core/manager/DisTubeVoiceManager.ts","../src/core/manager/FilterManager.ts","../src/core/manager/QueueManager.ts","../src/core/DisTubeHandler.ts","../src/core/DisTubeOptions.ts","../src/core/DisTubeStream.ts","../src/struct/Queue.ts","../src/struct/Plugin.ts","../src/struct/CustomPlugin.ts","../src/struct/ExtractorPlugin.ts","../src/util.ts","../src/plugin/DirectLink.ts","../src/DisTube.ts"],"sourcesContent":["import type ytdl from \"@distube/ytdl-core\";\nimport type {\n Guild,\n GuildMember,\n GuildTextBasedChannel,\n Interaction,\n Message,\n Snowflake,\n VoiceBasedChannel,\n VoiceState,\n} from \"discord.js\";\nimport type { CustomPlugin, DisTubeVoice, ExtractorPlugin, Playlist, Queue, SearchResult, Song } from \".\";\n\nexport type Awaitable<T = any> = T | PromiseLike<T>;\n\nexport type DisTubeVoiceEvents = {\n disconnect: (error?: Error) => Awaitable;\n error: (error: Error) => Awaitable;\n finish: () => Awaitable;\n};\n\nexport type DisTubeEvents = {\n error: (channel: GuildTextBasedChannel | undefined, error: Error) => Awaitable;\n addList: (queue: Queue, playlist: Playlist) => Awaitable;\n addSong: (queue: Queue, song: Song) => Awaitable;\n playSong: (queue: Queue, song: Song) => Awaitable;\n finishSong: (queue: Queue, song: Song) => Awaitable;\n empty: (queue: Queue) => Awaitable;\n finish: (queue: Queue) => Awaitable;\n initQueue: (queue: Queue) => Awaitable;\n noRelated: (queue: Queue) => Awaitable;\n disconnect: (queue: Queue) => Awaitable;\n deleteQueue: (queue: Queue) => Awaitable;\n searchCancel: (message: Message<true>, query: string) => Awaitable;\n searchNoResult: (message: Message<true>, query: string) => Awaitable;\n searchDone: (message: Message<true>, answer: Message<true>, query: string) => Awaitable;\n searchInvalidAnswer: (message: Message<true>, answer: Message<true>, query: string) => Awaitable;\n searchResult: (message: Message<true>, results: SearchResult[], query: string) => Awaitable;\n};\n\n/**\n * An FFmpeg audio filter object\n * ```\n * {\n * name: \"bassboost\",\n * value: \"bass=g=10\"\n * }\n * ```\n * @typedef {Object} Filter\n * @prop {string} name Name of the filter\n * @prop {string} value FFmpeg audio filter(s)\n */\nexport interface Filter {\n name: string;\n value: string;\n}\n\n/**\n * Data that resolves to give an FFmpeg audio filter. This can be:\n * - A name of a default filters or custom filters (`string`)\n * - A {@link Filter} object\n * @typedef {string|Filter} FilterResolvable\n * @see {@link defaultFilters}\n * @see {@link DisTubeOptions|DisTubeOptions.customFilters}\n */\nexport type FilterResolvable = string | Filter;\n\n/**\n * FFmpeg Filters\n * ```\n * {\n * \"Filter Name\": \"Filter Value\",\n * \"bassboost\": \"bass=g=10\"\n * }\n * ```\n * @typedef {Object.<string, string>} Filters\n * @see {@link defaultFilters}\n */\nexport type Filters = Record<string, string>;\n\n/**\n * DisTube options.\n * @typedef {Object} DisTubeOptions\n * @prop {Array<CustomPlugin|ExtractorPlugin>} [plugins] DisTube plugins.\n * @prop {boolean} [emitNewSongOnly=false] Whether or not emitting {@link DisTube#event:playSong} event\n * when looping a song or next song is the same as the previous one\n * @prop {boolean} [leaveOnEmpty=true] Whether or not leaving voice channel\n * if the voice channel is empty after {@link DisTubeOptions}.emptyCooldown seconds.\n * @prop {boolean} [leaveOnFinish=false] Whether or not leaving voice channel when the queue ends.\n * @prop {boolean} [leaveOnStop=true] Whether or not leaving voice channel after using {@link DisTube#stop} function.\n * @prop {boolean} [savePreviousSongs=true] Whether or not saving the previous songs of the queue\n * and enable {@link DisTube#previous} method\n * @prop {number} [searchSongs=0] Limit of search results emits in {@link DisTube#event:searchResult} event\n * when {@link DisTube#play} method executed. If `searchSongs <= 1`, play the first result\n * @prop {string} [youtubeCookie] YouTube cookies. Read how to get it in\n * {@link https://github.com/fent/node-ytdl-core/blob/997efdd5dd9063363f6ef668bb364e83970756e7/example/cookies.js#L6-L12|YTDL's Example}\n * @prop {string} [youtubeIdentityToken] If not given; ytdl-core will try to find it.\n * You can find this by going to a video's watch page; viewing the source; and searching for \"ID_TOKEN\".\n * @prop {Filters} [customFilters] Override {@link defaultFilters} or add more ffmpeg filters.\n * Example=`{ \"Filter name\"=\"Filter value\"; \"8d\"=\"apulsator=hz=0.075\" }`\n * @prop {ytdl.getInfoOptions} [ytdlOptions] `ytdl-core` get info options\n * @prop {number} [searchCooldown=60] Built-in search cooldown in seconds (When searchSongs is bigger than 0)\n * @prop {number} [emptyCooldown=60] Built-in leave on empty cooldown in seconds (When leaveOnEmpty is true)\n * @prop {boolean} [nsfw=false] Whether or not playing age-restricted content\n * and disabling safe search in non-NSFW channel.\n * @prop {boolean} [emitAddListWhenCreatingQueue=true] Whether or not emitting `addList` event when creating a new Queue\n * @prop {boolean} [emitAddSongWhenCreatingQueue=true] Whether or not emitting `addSong` event when creating a new Queue\n * @prop {boolean} [joinNewVoiceChannel=true] Whether or not joining the new voice channel\n * when using {@link DisTube#play} method\n * @prop {StreamType} [streamType=StreamType.OPUS] Decide the {@link DisTubeStream#type} will be used\n * (Not the same as {@link DisTubeStream#type})\n * @prop {boolean} [directLink=true] Whether or not play direct link of the song\n */\nexport interface DisTubeOptions {\n plugins?: (CustomPlugin | ExtractorPlugin)[];\n emitNewSongOnly?: boolean;\n leaveOnFinish?: boolean;\n leaveOnStop?: boolean;\n leaveOnEmpty?: boolean;\n emptyCooldown?: number;\n savePreviousSongs?: boolean;\n searchSongs?: number;\n searchCooldown?: number;\n youtubeCookie?: string;\n youtubeIdentityToken?: string;\n customFilters?: Filters;\n ytdlOptions?: ytdl.downloadOptions;\n nsfw?: boolean;\n emitAddSongWhenCreatingQueue?: boolean;\n emitAddListWhenCreatingQueue?: boolean;\n joinNewVoiceChannel?: boolean;\n streamType?: StreamType;\n directLink?: boolean;\n}\n\n/**\n * Data that can be resolved to give a guild id string. This can be:\n * - A guild id string | a guild {@link https://discord.js.org/#/docs/main/stable/class/Snowflake|Snowflake}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/Guild|Guild}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/Message|Message}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/BaseGuildVoiceChannel|BaseGuildVoiceChannel}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/BaseGuildTextChannel|BaseGuildTextChannel}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/VoiceState|VoiceState}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/GuildMember|GuildMember}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/Interaction|Interaction}\n * - A {@link DisTubeVoice}\n * - A {@link Queue}\n * @typedef {\n * Discord.Snowflake|\n * Discord.Guild|\n * Discord.Message|\n * Discord.BaseGuildVoiceChannel|\n * Discord.BaseGuildTextChannel|\n * Discord.VoiceState|\n * Discord.GuildMember|\n * Discord.Interaction|\n * DisTubeVoice|\n * Queue|\n * string\n * } GuildIdResolvable\n */\nexport type GuildIdResolvable =\n | Queue\n | DisTubeVoice\n | Snowflake\n | Message\n | GuildTextBasedChannel\n | VoiceBasedChannel\n | VoiceState\n | Guild\n | GuildMember\n | Interaction\n | string;\n\nexport interface OtherSongInfo {\n src?: string;\n id?: string;\n title?: string;\n name?: string;\n is_live?: boolean;\n isLive?: boolean;\n _duration_raw?: string | number;\n duration?: string | number;\n webpage_url?: string;\n url: string;\n thumbnail?: string;\n related?: RelatedSong[];\n view_count?: string | number;\n views?: string | number;\n like_count?: string | number;\n likes?: string | number;\n dislike_count?: string | number;\n dislikes?: string | number;\n repost_count?: string | number;\n reposts?: string | number;\n uploader?: string | { name: string; url: string };\n uploader_url?: string;\n age_limit?: string | number;\n chapters?: Chapter[];\n age_restricted?: boolean;\n}\n\nexport interface Chapter {\n title: string;\n start_time: number;\n}\n\nexport interface PlaylistInfo {\n source: string;\n member?: GuildMember;\n songs: Song[];\n name?: string;\n url?: string;\n thumbnail?: string;\n /** @deprecated */\n title?: string;\n /** @deprecated */\n webpage_url?: string;\n}\n\nexport type RelatedSong = Omit<Song, \"related\">;\n\n/**\n * @typedef {Object} PlayHandlerOptions\n * @param {Discord.BaseGuildTextChannel} [options.textChannel] The default text channel of the queue\n * @param {boolean} [options.skip=false] Skip the playing song (if exists) and play the added playlist instantly\n * @param {number} [options.position=0] Position of the song/playlist to add to the queue,\n * <= 0 to add to the end of the queue.\n */\nexport type PlayHandlerOptions = {\n skip?: boolean;\n position?: number;\n textChannel?: GuildTextBasedChannel;\n};\n\n/**\n * @typedef {Object} PlayOptions\n * @param {Discord.GuildMember} [member] Requested user (default is your bot)\n * @param {Discord.BaseGuildTextChannel} [textChannel] Default {@link Queue#textChannel}\n * @param {boolean} [skip=false]\n * Skip the playing song (if exists) and play the added song/playlist if `position` is 1.\n * If `position` is defined and not equal to 1, it will skip to the next song instead of the added song\n * @param {number} [position=0] Position of the song/playlist to add to the queue,\n * <= 0 to add to the end of the queue.\n * @param {Discord.Message} [message] Called message (For built-in search events. If this is a {@link https://developer.mozilla.org/en-US/docs/Glossary/Falsy|falsy value}, it will play the first result instead)\n * @param {*} [metadata] Optional metadata that can be attached to the song/playlist will be played,\n * This is useful for identification purposes when the song/playlist is passed around in events.\n * See {@link Song#metadata} or {@link Playlist#metadata}\n */\nexport interface PlayOptions extends PlayHandlerOptions, ResolveOptions<any> {\n message?: Message;\n}\n\n/**\n * @typedef {Object} ResolveOptions\n * @param {Discord.GuildMember} [member] Requested user\n * @param {*} [metadata] Metadata\n */\nexport interface ResolveOptions<T = unknown> {\n member?: GuildMember;\n metadata?: T;\n}\n\n/**\n * @typedef {ResolveOptions} ResolvePlaylistOptions\n * @param {string} [source] Source of the playlist\n */\nexport interface ResolvePlaylistOptions<T = unknown> extends ResolveOptions<T> {\n source?: string;\n}\n\n/**\n * @typedef {Object} CustomPlaylistOptions\n * @param {Discord.GuildMember} [member] A guild member creating the playlist\n * @param {Object} [properties] Additional properties such as `name`\n * @param {boolean} [parallel=true] Whether or not fetch the songs in parallel\n * @param {*} [metadata] Metadata\n */\nexport interface CustomPlaylistOptions {\n member?: GuildMember;\n properties?: Record<string, any>;\n parallel?: boolean;\n metadata?: any;\n}\n\n/**\n * The repeat mode of a {@link Queue} (enum)\n * * `DISABLED` = 0\n * * `SONG` = 1\n * * `QUEUE` = 2\n * @typedef {number} RepeatMode\n */\nexport enum RepeatMode {\n DISABLED,\n SONG,\n QUEUE,\n}\n\n/**\n * All available plugin types:\n * * `CUSTOM` = `\"custom\"`: {@link CustomPlugin}\n * * `EXTRACTOR` = `\"extractor\"`: {@link ExtractorPlugin}\n * @typedef {\"custom\"|\"extractor\"} PluginType\n */\nexport enum PluginType {\n CUSTOM = \"custom\",\n EXTRACTOR = \"extractor\",\n}\n\n/**\n * Search result types:\n * * `VIDEO` = `\"video\"`\n * * `PLAYLIST` = `\"playlist\"`\n * @typedef {\"video\"|\"playlist\"} SearchResultType\n */\nexport enum SearchResultType {\n VIDEO = \"video\",\n PLAYLIST = \"playlist\",\n}\n\n/**\n *\n * Stream types:\n * * `OPUS` = `0` (Better quality, use more resources - **Recommended**)\n * * `RAW` = `1` (Better performance, use less resources)\n * @typedef {number} StreamType\n * @type {StreamType}\n */\nexport enum StreamType {\n OPUS,\n RAW,\n}\n","import { StreamType } from \".\";\nimport type { Filters } from \".\";\n\n/**\n * Default DisTube audio filters.\n * @typedef {Object} defaultFilters\n * @prop {string} 3d 3d\n * @prop {string} bassboost bassboost\n * @prop {string} echo echo\n * @prop {string} karaoke karaoke\n * @prop {string} nightcore nightcore\n * @prop {string} vaporwave vaporwave\n * @prop {string} flanger flanger\n * @prop {string} gate gate\n * @prop {string} haas haas\n * @prop {string} reverse reverse\n * @prop {string} surround surround\n * @prop {string} mcompand mcompand\n * @prop {string} phaser phaser\n * @prop {string} tremolo tremolo\n * @prop {string} earwax earwax\n */\nexport const defaultFilters: Filters = {\n \"3d\": \"apulsator=hz=0.125\",\n bassboost: \"bass=g=10\",\n echo: \"aecho=0.8:0.9:1000:0.3\",\n flanger: \"flanger\",\n gate: \"agate\",\n haas: \"haas\",\n karaoke: \"stereotools=mlev=0.1\",\n nightcore: \"asetrate=48000*1.25,aresample=48000,bass=g=5\",\n reverse: \"areverse\",\n vaporwave: \"asetrate=48000*0.8,aresample=48000,atempo=1.1\",\n mcompand: \"mcompand\",\n phaser: \"aphaser\",\n tremolo: \"tremolo\",\n surround: \"surround\",\n earwax: \"earwax\",\n};\n\nexport const defaultOptions = {\n plugins: [],\n emitNewSongOnly: false,\n leaveOnEmpty: true,\n leaveOnFinish: false,\n leaveOnStop: true,\n savePreviousSongs: true,\n searchSongs: 0,\n ytdlOptions: {},\n searchCooldown: 60,\n emptyCooldown: 60,\n nsfw: false,\n emitAddSongWhenCreatingQueue: true,\n emitAddListWhenCreatingQueue: true,\n joinNewVoiceChannel: true,\n streamType: StreamType.OPUS,\n directLink: true,\n};\n","import { inspect } from \"node:util\";\n\nconst ERROR_MESSAGES = {\n INVALID_TYPE: (expected: (number | string) | readonly (number | string)[], got: any, name?: string) =>\n `Expected ${\n Array.isArray(expected) ? expected.map(e => (typeof e === \"number\" ? e : `'${e}'`)).join(\" or \") : `'${expected}'`\n }${name ? ` for '${name}'` : \"\"}, but got ${inspect(got)} (${typeof got})`,\n NUMBER_COMPARE: (name: string, expected: string, value: number) => `'${name}' must be ${expected} ${value}`,\n EMPTY_ARRAY: (name: string) => `'${name}' is an empty array`,\n EMPTY_FILTERED_ARRAY: (name: string, type: string) => `There is no valid '${type}' in the '${name}' array`,\n EMPTY_STRING: (name: string) => `'${name}' string must not be empty`,\n INVALID_KEY: (obj: string, key: string) => `'${key}' does not need to be provided in ${obj}`,\n MISSING_KEY: (obj: string, key: string) => `'${key}' needs to be provided in ${obj}`,\n MISSING_KEYS: (obj: string, key: string[], all: boolean) =>\n `${key.map(k => `'${k}'`).join(all ? \" and \" : \" or \")} need to be provided in ${obj}`,\n\n MISSING_INTENTS: (i: string) => `${i} intent must be provided for the Client`,\n DISABLED_OPTION: (o: string) => `DisTubeOptions.${o} is disabled`,\n ENABLED_OPTION: (o: string) => `DisTubeOptions.${o} is enabled`,\n\n NOT_IN_VOICE: \"User is not in any voice channel\",\n VOICE_FULL: \"The voice channel is full\",\n VOICE_CONNECT_FAILED: (s: number) => `Cannot connect to the voice channel after ${s} seconds`,\n VOICE_MISSING_PERMS: \"I do not have permission to join this voice channel\",\n VOICE_RECONNECT_FAILED: \"Cannot reconnect to the voice channel\",\n VOICE_DIFFERENT_GUILD: \"Cannot join a voice channel in a different guild\",\n VOICE_DIFFERENT_CLIENT: \"Cannot join a voice channel created by a different client\",\n\n NO_QUEUE: \"There is no playing queue in this guild\",\n QUEUE_EXIST: \"This guild has a Queue already\",\n PAUSED: \"The queue has been paused already\",\n RESUMED: \"The queue has been playing already\",\n NO_PREVIOUS: \"There is no previous song in this queue\",\n NO_UP_NEXT: \"There is no up next song\",\n NO_SONG_POSITION: \"Does not have any song at this position\",\n NO_PLAYING: \"There is no playing song in the queue\",\n\n NO_RESULT: \"No result found\",\n NO_RELATED: \"Cannot find any related songs\",\n CANNOT_PLAY_RELATED: \"Cannot play the related song\",\n UNAVAILABLE_VIDEO: \"This video is unavailable\",\n UNPLAYABLE_FORMATS: \"No playable format found\",\n NON_NSFW: \"Cannot play age-restricted content in non-NSFW channel\",\n NOT_SUPPORTED_URL: \"This url is not supported\",\n CANNOT_RESOLVE_SONG: (t: any) => `Cannot resolve ${inspect(t)} to a Song`,\n NO_VALID_SONG: \"'songs' array does not have any valid Song, SearchResult or url\",\n EMPTY_FILTERED_PLAYLIST:\n \"There is no valid video in the playlist\\n\" +\n \"Maybe age-restricted contents is filtered because you are in non-NSFW channel\",\n EMPTY_PLAYLIST: \"There is no valid video in the playlist\",\n};\n\ntype ErrorMessage = typeof ERROR_MESSAGES;\ntype ErrorCode = keyof ErrorMessage;\ntype StaticErrorCode = { [K in ErrorCode]-?: ErrorMessage[K] extends string ? K : never }[ErrorCode];\ntype TemplateErrorCode = Exclude<keyof typeof ERROR_MESSAGES, StaticErrorCode>;\n\nconst haveCode = (code: string): code is ErrorCode => Object.keys(ERROR_MESSAGES).includes(code);\nconst parseMessage = (m: string | ((...x: any) => string), ...args: any) => (typeof m === \"string\" ? m : m(...args));\nconst getErrorMessage = (code: string, ...args: any): string =>\n haveCode(code) ? parseMessage(ERROR_MESSAGES[code], ...args) : args[0];\nexport class DisTubeError<T extends string> extends Error {\n errorCode: string;\n constructor(code: StaticErrorCode);\n constructor(code: T extends TemplateErrorCode ? T : never, ...args: Parameters<ErrorMessage[typeof code]>);\n constructor(code: TemplateErrorCode, _: never);\n constructor(code: T extends ErrorCode ? \"This is built-in error code\" : T, message: string);\n constructor(code: string, ...args: any) {\n super(getErrorMessage(code, ...args));\n\n this.errorCode = code;\n if (Error.captureStackTrace) Error.captureStackTrace(this, DisTubeError);\n }\n\n override get name() {\n return `DisTubeError [${this.errorCode}]`;\n }\n\n get code() {\n return this.errorCode;\n }\n}\n","class Task {\n resolve!: () => void;\n promise: Promise<void>;\n resolveInfo: boolean;\n constructor(resolveInfo: boolean) {\n this.resolveInfo = resolveInfo;\n this.promise = new Promise<void>(res => {\n this.resolve = res;\n });\n }\n}\n\n/**\n * Task queuing system\n * @private\n */\nexport class TaskQueue {\n /**\n * The task array\n * @type {Task[]}\n * @private\n */\n #tasks: Task[] = [];\n\n /**\n * Waits for last task finished and queues a new task\n * @param {boolean} [resolveInfo=false] Whether the task is a resolving info task\n * @returns {Promise<void>}\n */\n public queuing(resolveInfo = false): Promise<void> {\n const next = this.remaining ? this.#tasks[this.#tasks.length - 1].promise : Promise.resolve();\n this.#tasks.push(new Task(resolveInfo));\n return next;\n }\n\n /**\n * Removes the finished task and processes the next task\n */\n public resolve(): void {\n this.#tasks.shift()?.resolve();\n }\n\n /**\n * The remaining number of tasks\n * @type {number}\n */\n public get remaining(): number {\n return this.#tasks.length;\n }\n\n /**\n * Whether or not having a resolving info task\n * @type {boolean}\n */\n public get hasResolveTask(): boolean {\n return !!this.#tasks.find(t => t.resolveInfo);\n }\n}\n","import { DisTubeError, formatDuration, isMemberInstance, isRecord } from \"..\";\nimport type { PlaylistInfo, Song } from \"..\";\nimport type { GuildMember } from \"discord.js\";\n\n/**\n * Class representing a playlist.\n * @prop {string} source Playlist source\n * @template T - The type for the metadata (if any) of the playlist\n */\nexport class Playlist<T = unknown> implements PlaylistInfo {\n source!: string;\n songs!: Song[];\n name!: string;\n #metadata!: T;\n #member?: GuildMember;\n url?: string;\n thumbnail?: string;\n [x: string]: any;\n /**\n * Create a playlist\n * @param {Song[]|PlaylistInfo} playlist Playlist\n * @param {Object} [options] Optional options\n * @param {Discord.GuildMember} [options.member] Requested user\n * @param {Object} [options.properties] Custom properties\n * @param {T} [options.metadata] Playlist metadata\n */\n constructor(\n playlist: Song[] | PlaylistInfo,\n options: {\n member?: GuildMember;\n properties?: Record<string, any>;\n metadata?: T;\n } = {},\n ) {\n const { member, properties, metadata } = options;\n\n if (\n typeof playlist !== \"object\" ||\n (!Array.isArray(playlist) && [\"source\", \"songs\"].some(key => !(key in playlist)))\n ) {\n throw new DisTubeError(\"INVALID_TYPE\", [\"Array<Song>\", \"PlaylistInfo\"], playlist, \"playlist\");\n }\n if (typeof properties !== \"undefined\" && !isRecord<any>(properties)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", properties, \"properties\");\n }\n\n if (Array.isArray(playlist)) {\n /**\n * The source of the playlist\n * @type {string}\n */\n this.source = \"youtube\";\n if (!playlist.length) throw new DisTubeError(\"EMPTY_PLAYLIST\");\n /**\n * Playlist songs.\n * @type {Array<Song>}\n */\n this.songs = playlist;\n /**\n * Playlist name.\n * @type {string}\n */\n this.name = this.songs[0].name\n ? `${this.songs[0].name} and ${this.songs.length - 1} more songs.`\n : `${this.songs.length} songs playlist`;\n this.thumbnail = this.songs[0].thumbnail;\n this.member = member || undefined;\n } else {\n this.source = (playlist.source || \"youtube\").toLowerCase();\n if (!Array.isArray(playlist.songs) || !playlist.songs.length) throw new DisTubeError(\"EMPTY_PLAYLIST\");\n this.songs = playlist.songs;\n this.name =\n playlist.name ||\n // eslint-disable-next-line deprecation/deprecation\n playlist.title ||\n (this.songs[0].name\n ? `${this.songs[0].name} and ${this.songs.length - 1} more songs.`\n : `${this.songs.length} songs playlist`);\n /**\n * Playlist URL.\n * @type {string}\n */\n // eslint-disable-next-line deprecation/deprecation\n this.url = playlist.url || playlist.webpage_url;\n /**\n * Playlist thumbnail.\n * @type {string?}\n */\n this.thumbnail = playlist.thumbnail || this.songs[0].thumbnail;\n this.member = member || playlist.member || undefined;\n }\n this.songs.map(s => s.constructor.name === \"Song\" && (s.playlist = this));\n if (properties) for (const [key, value] of Object.entries(properties)) this[key] = value;\n /**\n * Optional metadata that can be used to identify the playlist.\n * @type {T}\n */\n this.metadata = metadata as T;\n }\n\n /**\n * Playlist duration in second.\n * @type {number}\n */\n get duration() {\n return this.songs?.reduce((prev, next) => prev + (next.duration || 0), 0) || 0;\n }\n\n /**\n * Formatted duration string `hh:mm:ss`.\n * @type {string}\n */\n get formattedDuration() {\n return formatDuration(this.duration);\n }\n\n /**\n * User requested.\n * @type {Discord.GuildMember?}\n */\n get member() {\n return this.#member;\n }\n\n set member(member: GuildMember | undefined) {\n if (!isMemberInstance(member)) return;\n this.#member = member;\n this.songs.map(s => s.constructor.name === \"Song\" && (s.member = this.member));\n }\n\n /**\n * User requested.\n * @type {Discord.User?}\n */\n get user() {\n return this.member?.user;\n }\n\n get metadata() {\n return this.#metadata;\n }\n\n set metadata(metadata: T) {\n this.#metadata = metadata;\n this.songs.map(s => s.constructor.name === \"Song\" && (s.metadata = metadata));\n }\n}\n","import { DisTubeError, SearchResultType, formatDuration, toSecond } from \"..\";\nimport type { Playlist, Video } from \"@distube/ytsr\";\n\n/**\n * A abstract class representing a search result.\n * @abstract\n * @private\n */\nabstract class ISearchResult {\n source: \"youtube\";\n abstract type: SearchResultType;\n id: string;\n name: string;\n url: string;\n uploader: {\n name?: string;\n url?: string;\n };\n\n /**\n * Create a search result\n * @param {Object} info ytsr result\n */\n constructor(info: Video | Playlist) {\n /**\n * The source of the search result\n * @type {\"youtube\"}\n */\n this.source = \"youtube\";\n /**\n * YouTube video or playlist id\n * @type {string}\n */\n this.id = info.id;\n /**\n * Video or playlist title.\n * @type {string}\n */\n this.name = info.name;\n /**\n * Video or playlist URL.\n * @type {string}\n */\n this.url = info.url;\n /**\n * Video or playlist uploader\n * @type {Object}\n * @prop {string?} name Uploader name\n * @prop {string?} url Uploader url\n */\n this.uploader = {\n name: undefined,\n url: undefined,\n };\n }\n}\n\n/**\n * A class representing a video search result.\n * @extends ISearchResult\n */\nexport class SearchResultVideo extends ISearchResult {\n type: SearchResultType.VIDEO;\n views: number;\n isLive: boolean;\n duration: number;\n formattedDuration: string;\n thumbnail: string;\n constructor(info: Video) {\n super(info);\n if (info.type !== \"video\") throw new DisTubeError(\"INVALID_TYPE\", \"video\", info.type, \"type\");\n /**\n * Type of SearchResult\n * @type {SearchResultType.VIDEO}\n */\n this.type = SearchResultType.VIDEO;\n /**\n * Video views count\n * @type {number}\n */\n this.views = info.views;\n /**\n * Indicates if the video is an active live.\n * @type {boolean}\n */\n this.isLive = info.isLive;\n /**\n * Video duration.\n * @type {number}\n */\n this.duration = this.isLive ? 0 : toSecond(info.duration);\n /**\n * Formatted duration string `hh:mm:ss` or `mm:ss`.\n * @type {string}\n */\n this.formattedDuration = this.isLive ? \"Live\" : formatDuration(this.duration);\n /**\n * Video thumbnail.\n * @type {string}\n */\n this.thumbnail = info.thumbnail;\n this.uploader = {\n name: info.author?.name,\n url: info.author?.url,\n };\n }\n}\n\n/**\n * A video or playlist search result\n * @typedef {SearchResultVideo|SearchResultPlaylist} SearchResult\n */\nexport type SearchResult = SearchResultVideo | SearchResultPlaylist;\n\n/**\n * A class representing a playlist search result.\n * @extends ISearchResult\n */\nexport class SearchResultPlaylist extends ISearchResult {\n type: SearchResultType.PLAYLIST;\n length: number;\n constructor(info: Playlist) {\n super(info);\n if (info.type !== \"playlist\") throw new DisTubeError(\"INVALID_TYPE\", \"playlist\", info.type, \"type\");\n /**\n * Type of SearchResult\n * @type {SearchResultType.PLAYLIST}\n */\n this.type = SearchResultType.PLAYLIST;\n /**\n * Length of the playlist\n * @type {number}\n */\n this.length = info.length;\n this.uploader = {\n name: info.owner?.name,\n url: info.owner?.url,\n };\n }\n}\n","import { Playlist } from \"./Playlist\";\nimport { DisTubeError, formatDuration, isMemberInstance, parseNumber, toSecond } from \"..\";\nimport type ytdl from \"@distube/ytdl-core\";\nimport type { GuildMember } from \"discord.js\";\nimport type { Chapter, OtherSongInfo, RelatedSong, SearchResult } from \"..\";\n\n/**\n * Class representing a song.\n *\n * <info>If {@link Song} is added from a YouTube {@link SearchResult} or {@link Playlist},\n * some info will be missing to save your resources. It will be filled when emitting {@link DisTube#playSong} event.\n *\n * Missing info: {@link Song#likes}, {@link Song#dislikes}, {@link Song#streamURL},\n * {@link Song#related}, {@link Song#chapters}, {@link Song#age_restricted}</info>\n * @template T - The type for the metadata (if any) of the song\n */\nexport class Song<T = unknown> {\n source!: string;\n #metadata!: T;\n formats?: ytdl.videoFormat[];\n #member?: GuildMember;\n id?: string;\n name?: string;\n isLive!: boolean;\n duration!: number;\n formattedDuration?: string;\n url!: string;\n streamURL?: string;\n thumbnail?: string;\n related!: RelatedSong[];\n views!: number;\n likes!: number;\n dislikes!: number;\n uploader!: {\n name?: string;\n url?: string;\n };\n age_restricted!: boolean;\n chapters!: Chapter[];\n reposts!: number;\n #playlist?: Playlist;\n /**\n * Create a Song\n * @param {ytdl.videoInfo|SearchResult|OtherSongInfo} info Raw info\n * @param {Object} [options] Optional options\n * @param {Discord.GuildMember} [options.member] Requested user\n * @param {string} [options.source=\"youtube\"] Song source\n * @param {T} [options.metadata] Song metadata\n */\n constructor(\n info: ytdl.videoInfo | SearchResult | OtherSongInfo | ytdl.relatedVideo | RelatedSong,\n options: {\n member?: GuildMember;\n source?: string;\n metadata?: T;\n } = {},\n ) {\n const { member, source, metadata } = { source: \"youtube\", ...options };\n\n if (\n typeof source !== \"string\" ||\n ((info as OtherSongInfo).src && typeof (info as OtherSongInfo).src !== \"string\")\n ) {\n throw new DisTubeError(\"INVALID_TYPE\", \"string\", source, \"source\");\n }\n /**\n * The source of the song\n * @type {string}\n */\n this.source = ((info as OtherSongInfo)?.src || source).toLowerCase();\n /**\n * Optional metadata that can be used to identify the song. This is attached by the {@link DisTube#play} method.\n * @type {T}\n */\n this.metadata = metadata as T;\n this.member = member;\n if (this.source === \"youtube\") {\n this._patchYouTube(info as ytdl.videoInfo);\n } else {\n this._patchOther(info as OtherSongInfo);\n }\n }\n\n _patchYouTube(i: ytdl.videoInfo | SearchResult) {\n // FIXME\n const info = i as any;\n if (info.full === true) {\n /**\n * Stream formats (Available if the song is from YouTube and playing)\n * @type {ytdl.videoFormat[]?}\n * @private\n */\n this.formats = info.formats;\n // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports\n const err = require(\"@distube/ytdl-core/lib/utils\").playError(info.player_response, [\n \"UNPLAYABLE\",\n \"LIVE_STREAM_OFFLINE\",\n \"LOGIN_REQUIRED\",\n ]);\n if (err) throw err;\n\n if (!info.formats?.length) throw new DisTubeError(\"UNAVAILABLE_VIDEO\");\n }\n const details = info.videoDetails || info;\n /**\n * YouTube video id\n * @type {string?}\n */\n this.id = details.videoId || details.id;\n /**\n * Song name.\n * @type {string?}\n */\n this.name = details.title || details.name;\n /**\n * Indicates if the video is an active live.\n * @type {boolean}\n */\n this.isLive = !!details.isLive;\n /**\n * Song duration.\n * @type {number}\n */\n this.duration = this.isLive ? 0 : toSecond(details.lengthSeconds || details.length_seconds || details.duration);\n /**\n * Formatted duration string (`hh:mm:ss`, `mm:ss` or `Live`).\n * @type {string?}\n */\n this.formattedDuration = this.isLive ? \"Live\" : formatDuration(this.duration);\n /**\n * Song URL.\n * @type {string}\n */\n this.url = `https://www.youtube.com/watch?v=${this.id}`;\n /**\n * Stream / Download URL (Available if the song is playing)\n * @type {string?}\n */\n this.streamURL = undefined;\n /**\n * Song thumbnail.\n * @type {string?}\n */\n this.thumbnail =\n details.thumbnails?.sort((a: any, b: any) => b.width - a.width)?.[0]?.url ||\n details.thumbnail?.url ||\n details.thumbnail;\n /**\n * Related songs (without {@link Song#related} properties)\n * @type {Song[]}\n */\n this.related = info?.related_videos || details.related || [];\n if (!Array.isArray(this.related)) throw new DisTubeError(\"INVALID_TYPE\", \"Array\", this.related, \"Song#related\");\n this.related = this.related.map((v: any) => new Song(v, { source: this.source, metadata: this.metadata }));\n /**\n * Song views count\n * @type {number}\n */\n this.views = parseNumber(details.viewCount || details.view_count || details.views);\n /**\n * Song like count\n * @type {number}\n */\n this.likes = parseNumber(details.likes);\n /**\n * Song dislike count\n * @type {number}\n */\n this.dislikes = parseNumber(details.dislikes);\n /**\n * Song uploader\n * @type {Object}\n * @prop {string?} name Uploader name\n * @prop {string?} url Uploader url\n */\n this.uploader = {\n name: info.uploader?.name || details.author?.name,\n url: info.uploader?.url || details.author?.channel_url || details.author?.url,\n };\n /**\n * Whether or not an age-restricted content\n * @type {boolean}\n */\n this.age_restricted = !!details.age_restricted;\n /**\n * @typedef {Object} Chapter\n * @prop {string} title Chapter title\n * @prop {number} start_time Chapter start time in seconds\n */\n /**\n * Chapters information (YouTube only)\n * @type {Chapter[]}\n */\n this.chapters = details.chapters || [];\n /**\n * Song repost count\n * @type {number}\n */\n this.reposts = 0;\n }\n\n /**\n * Patch data from other source\n * @param {OtherSongInfo} info Video info\n * @private\n */\n _patchOther(info: OtherSongInfo) {\n this.id = info.id;\n this.name = info.title || info.name;\n this.isLive = Boolean(info.is_live || info.isLive);\n this.duration = this.isLive ? 0 : toSecond(info._duration_raw || info.duration);\n this.formattedDuration = this.isLive ? \"Live\" : formatDuration(this.duration);\n this.url = info.webpage_url || info.url;\n this.thumbnail = info.thumbnail;\n this.related = info.related || [];\n if (!Array.isArray(this.related)) throw new DisTubeError(\"INVALID_TYPE\", \"Array\", this.related, \"Song#related\");\n this.related = this.related.map(i => new Song(i, { source: this.source, metadata: this.metadata }));\n this.views = parseNumber(info.view_count || info.views);\n this.likes = parseNumber(info.like_count || info.likes);\n this.dislikes = parseNumber(info.dislike_count || info.dislikes);\n this.reposts = parseNumber(info.repost_count || info.reposts);\n if (typeof info.uploader === \"string\") {\n this.uploader = {\n name: info.uploader,\n url: info.uploader_url,\n };\n } else {\n this.uploader = {\n name: info.uploader?.name,\n url: info.uploader?.url,\n };\n }\n this.age_restricted = info.age_restricted || (!!info.age_limit && parseNumber(info.age_limit) >= 18);\n this.chapters = info.chapters || [];\n }\n\n /**\n * The playlist added this song\n * @type {Playlist?}\n */\n get playlist() {\n return this.#playlist;\n }\n\n set playlist(playlist: Playlist | undefined) {\n if (!(playlist instanceof Playlist)) throw new DisTubeError(\"INVALID_TYPE\", \"Playlist\", playlist, \"Song#playlist\");\n this.#playlist = playlist;\n this.member = playlist.member;\n }\n\n /**\n * User requested.\n * @type {Discord.GuildMember?}\n */\n get member() {\n return this.#member;\n }\n\n set member(member: GuildMember | undefined) {\n if (isMemberInstance(member)) this.#member = member;\n }\n\n /**\n * User requested.\n * @type {Discord.User?}\n */\n get user() {\n return this.member?.user;\n }\n\n get metadata() {\n return this.#metadata;\n }\n\n set metadata(metadata: T) {\n this.#metadata = metadata;\n }\n}\n","import type { Client, GuildTextBasedChannel } from \"discord.js\";\nimport type { DisTube, DisTubeEvents, DisTubeHandler, DisTubeVoiceManager, Options, QueueManager } from \"..\";\n\n/**\n * @private\n * @abstract\n */\nexport abstract class DisTubeBase {\n distube: DisTube;\n constructor(distube: DisTube) {\n /**\n * DisTube\n * @type {DisTube}\n */\n this.distube = distube;\n }\n /**\n * Emit the {@link DisTube} of this base\n * @param {string} eventName Event name\n * @param {...any} args arguments\n * @returns {boolean}\n */\n emit(eventName: keyof DisTubeEvents, ...args: any): boolean {\n return this.distube.emit(eventName, ...args);\n }\n /**\n * Emit error event\n * @param {Error} error error\n * @param {Discord.BaseGuildTextChannel} [channel] Text channel where the error is encountered.\n */\n emitError(error: Error, channel?: GuildTextBasedChannel) {\n this.distube.emitError(error, channel);\n }\n /**\n * The queue manager\n * @type {QueueManager}\n * @readonly\n */\n get queues(): QueueManager {\n return this.distube.queues;\n }\n /**\n * The voice manager\n * @type {DisTubeVoiceManager}\n * @readonly\n */\n get voices(): DisTubeVoiceManager {\n return this.distube.voices;\n }\n /**\n * Discord.js client\n * @type {Discord.Client}\n * @readonly\n */\n get client(): Client {\n return this.distube.client;\n }\n /**\n * DisTube options\n * @type {DisTubeOptions}\n * @readonly\n */\n get options(): Options {\n return this.distube.options;\n }\n /**\n * DisTube handler\n * @type {DisTubeHandler}\n * @readonly\n */\n get handler(): DisTubeHandler {\n return this.distube.handler;\n }\n}\n","import { TypedEmitter } from \"tiny-typed-emitter\";\nimport { DisTubeError, isSupportedVoiceChannel } from \"..\";\nimport {\n AudioPlayerStatus,\n VoiceConnectionDisconnectReason,\n VoiceConnectionStatus,\n createAudioPlayer,\n createAudioResource,\n entersState,\n joinVoiceChannel,\n} from \"@discordjs/voice\";\nimport type { Snowflake, VoiceBasedChannel, VoiceState } from \"discord.js\";\nimport type { DisTubeStream, DisTubeVoiceEvents, DisTubeVoiceManager } from \"..\";\nimport type { AudioPlayer, AudioResource, VoiceConnection } from \"@discordjs/voice\";\n\n/**\n * Create a voice connection to the voice channel\n */\nexport class DisTubeVoice extends TypedEmitter<DisTubeVoiceEvents> {\n readonly id: Snowflake;\n readonly voices: DisTubeVoiceManager;\n readonly audioPlayer: AudioPlayer;\n connection!: VoiceConnection;\n audioResource?: AudioResource;\n emittedError!: boolean;\n isDisconnected = false;\n #channel!: VoiceBasedChannel;\n #volume = 100;\n constructor(voiceManager: DisTubeVoiceManager, channel: VoiceBasedChannel) {\n super();\n /**\n * The voice manager that instantiated this connection\n * @type {DisTubeVoiceManager}\n */\n this.voices = voiceManager;\n this.id = channel.guildId;\n this.channel = channel;\n this.voices.add(this.id, this);\n this.audioPlayer = createAudioPlayer()\n .on(AudioPlayerStatus.Idle, oldState => {\n if (oldState.status !== AudioPlayerStatus.Idle) {\n delete this.audioResource;\n this.emit(\"finish\");\n }\n })\n .on(AudioPlayerStatus.Playing, () => this.#br())\n .on(\"error\", error => {\n if (this.emittedError) return;\n this.emittedError = true;\n this.emit(\"error\", error);\n });\n this.connection\n .on(VoiceConnectionStatus.Disconnected, (_, newState) => {\n if (newState.reason === VoiceConnectionDisconnectReason.Manual) {\n this.leave();\n } else if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {\n entersState(this.connection, VoiceConnectionStatus.Connecting, 5e3).catch(() => {\n if (\n ![VoiceConnectionStatus.Ready, VoiceConnectionStatus.Connecting].includes(this.connection.state.status)\n ) {\n this.leave();\n }\n });\n } else if (this.connection.rejoinAttempts < 5) {\n setTimeout(() => {\n this.connection.rejoin();\n }, (this.connection.rejoinAttempts + 1) * 5e3).unref();\n } else if (this.connection.state.status !== VoiceConnectionStatus.Destroyed) {\n this.leave(new DisTubeError(\"VOICE_RECONNECT_FAILED\"));\n }\n })\n .on(VoiceConnectionStatus.Destroyed, () => {\n this.leave();\n })\n .on(\"error\", () => undefined);\n this.connection.subscribe(this.audioPlayer);\n /**\n * Get or set the volume percentage\n * @name DisTubeVoice#volume\n * @type {number}\n */\n }\n #br() {\n if (this.audioResource?.encoder?.encoder) this.audioResource.encoder.setBitrate(this.channel.bitrate);\n }\n get channel() {\n return this.#channel;\n }\n set channel(channel: VoiceBasedChannel) {\n if (!isSupportedVoiceChannel(channel)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"BaseGuildVoiceChannel\", channel, \"DisTubeVoice#channel\");\n }\n if (channel.guildId !== this.id) throw new DisTubeError(\"VOICE_DIFFERENT_GUILD\");\n if (channel.client.user?.id !== this.voices.client.user?.id) throw new DisTubeError(\"VOICE_DIFFERENT_CLIENT\");\n if (channel.id === this.#channel?.id) return;\n if (!channel.joinable) {\n if (channel.full) throw new DisTubeError(\"VOICE_FULL\");\n else throw new DisTubeError(\"VOICE_MISSING_PERMS\");\n }\n this.connection = this.#join(channel);\n this.#channel = channel;\n this.#br();\n }\n #join(channel: VoiceBasedChannel) {\n return joinVoiceChannel({\n channelId: channel.id,\n guildId: this.id,\n adapterCreator: channel.guild.voiceAdapterCreator,\n group: channel.client.user?.id,\n });\n }\n /**\n * Join a voice channel with this connection\n * @param {Discord.BaseGuildVoiceChannel} [channel] A voice channel\n * @returns {Promise<DisTubeVoice>}\n */\n async join(channel?: VoiceBasedChannel): Promise<DisTubeVoice> {\n const TIMEOUT = 30e3;\n if (channel) this.channel = channel;\n try {\n await entersState(this.connection, VoiceConnectionStatus.Ready, TIMEOUT);\n } catch {\n if (this.connection.state.status === VoiceConnectionStatus.Ready) return this;\n if (this.connection.state.status !== VoiceConnectionStatus.Destroyed) this.connection.destroy();\n this.voices.remove(this.id);\n throw new DisTubeError(\"VOICE_CONNECT_FAILED\", TIMEOUT / 1e3);\n }\n return this;\n }\n /**\n * Leave the voice channel of this connection\n * @param {Error} [error] Optional, an error to emit with 'error' event.\n */\n leave(error?: Error) {\n this.stop(true);\n if (!this.isDisconnected) {\n this.emit(\"disconnect\", error);\n this.isDisconnected = true;\n }\n if (this.connection.state.status !== VoiceConnectionStatus.Destroyed) this.connection.destroy();\n this.voices.remove(this.id);\n }\n /**\n * Stop the playing stream\n * @param {boolean} [force=false] If true, will force the {@link DisTubeVoice#audioPlayer} to enter the Idle state\n * even if the {@link DisTubeVoice#audioResource} has silence padding frames.\n * @private\n */\n stop(force = false) {\n this.audioPlayer.stop(force);\n }\n /**\n * Play a readable stream\n * @private\n * @param {DisTubeStream} stream Readable stream\n */\n play(stream: DisTubeStream) {\n this.emittedError = false;\n stream.stream.on(\"error\", (error: NodeJS.ErrnoException) => {\n if (this.emittedError || error.code === \"ERR_STREAM_PREMATURE_CLOSE\") return;\n this.emittedError = true;\n this.emit(\"error\", error);\n });\n this.audioResource = createAudioResource(stream.stream, {\n inputType: stream.type,\n inlineVolume: true,\n });\n this.volume = this.#volume;\n this.audioPlayer.play(this.audioResource);\n }\n set volume(volume: number) {\n if (typeof volume !== \"number\" || isNaN(volume)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", volume, \"volume\");\n }\n if (volume < 0) {\n throw new DisTubeError(\"NUMBER_COMPARE\", \"Volume\", \"bigger or equal to\", 0);\n }\n this.#volume = volume;\n this.audioResource?.volume?.setVolume(Math.pow(this.#volume / 100, 0.5 / Math.log10(2)));\n }\n get volume() {\n return this.#volume;\n }\n /**\n * Playback duration of the audio resource in seconds\n * @type {number}\n */\n get playbackDuration() {\n return (this.audioResource?.playbackDuration ?? 0) / 1000;\n }\n pause() {\n this.audioPlayer.pause();\n }\n unpause() {\n this.audioPlayer.unpause();\n }\n /**\n * Whether the bot is self-deafened\n * @type {boolean}\n */\n get selfDeaf(): boolean {\n return this.connection.joinConfig.selfDeaf;\n }\n /**\n * Whether the bot is self-muted\n * @type {boolean}\n */\n get selfMute(): boolean {\n return this.connection.joinConfig.selfMute;\n }\n /**\n * Self-deafens/undeafens the bot.\n * @param {boolean} selfDeaf Whether or not the bot should be self-deafened\n * @returns {boolean} true if the voice state was successfully updated, otherwise false\n */\n setSelfDeaf(selfDeaf: boolean): boolean {\n if (typeof selfDeaf !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", selfDeaf, \"selfDeaf\");\n }\n return this.connection.rejoin({\n ...this.connection.joinConfig,\n selfDeaf,\n });\n }\n /**\n * Self-mutes/unmutes the bot.\n * @param {boolean} selfMute Whether or not the bot should be self-muted\n * @returns {boolean} true if the voice state was successfully updated, otherwise false\n */\n setSelfMute(selfMute: boolean): boolean {\n if (typeof selfMute !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", selfMute, \"selfMute\");\n }\n return this.connection.rejoin({\n ...this.connection.joinConfig,\n selfMute,\n });\n }\n /**\n * The voice state of this connection\n * @type {Discord.VoiceState?}\n */\n get voiceState(): VoiceState | undefined {\n return this.channel?.guild?.members?.me?.voice;\n }\n}\n","import { DisTubeBase } from \"..\";\nimport { Collection } from \"discord.js\";\n\n/**\n * Manages the collection of a data model.\n * @abstract\n * @private\n * @extends DisTubeBase\n */\nexport abstract class BaseManager<V> extends DisTubeBase {\n /**\n * The collection of items for this manager.\n * @type {Discord.Collection}\n */\n collection = new Collection<string, V>();\n /**\n * The size of the collection.\n * @type {Discord.Collection}\n * @abstract\n */\n get size() {\n return this.collection.size;\n }\n}\n","import { BaseManager } from \".\";\nimport { resolveGuildId } from \"../..\";\nimport type { GuildIdResolvable } from \"../..\";\n\n/**\n * Manages the collection of a data model paired with a guild id.\n * @abstract\n * @private\n * @extends BaseManager\n */\nexport abstract class GuildIdManager<V> extends BaseManager<V> {\n add(idOrInstance: GuildIdResolvable, data: V) {\n const id = resolveGuildId(idOrInstance);\n const existing = this.get(id);\n if (existing) return this;\n return this.collection.set(id, data);\n }\n get(idOrInstance: GuildIdResolvable): V | undefined {\n return this.collection.get(resolveGuildId(idOrInstance));\n }\n remove(idOrInstance: GuildIdResolvable): boolean {\n return this.collection.delete(resolveGuildId(idOrInstance));\n }\n has(idOrInstance: GuildIdResolvable): boolean {\n return this.collection.has(resolveGuildId(idOrInstance));\n }\n}\n","import { DisTubeVoice } from \"../DisTubeVoice\";\nimport { resolveGuildId } from \"../..\";\nimport { GuildIdManager } from \".\";\nimport { VoiceConnectionStatus, getVoiceConnection } from \"@discordjs/voice\";\nimport type { GuildIdResolvable } from \"../..\";\nimport type { VoiceBasedChannel } from \"discord.js\";\n\n/**\n * Manages voice connections for {@link DisTube}\n * @extends BaseManager\n */\nexport class DisTubeVoiceManager extends GuildIdManager<DisTubeVoice> {\n /**\n * Get a {@link DisTubeVoice}.\n * @method get\n * @memberof DisTubeVoiceManager#\n * @param {GuildIdResolvable} guild The queue resolvable to resolve\n * @returns {DisTubeVoice?}\n */\n /**\n * Collection of {@link DisTubeVoice}.\n * @name DisTubeVoiceManager#collection\n * @type {Discord.Collection<string, DisTubeVoice>}\n */\n /**\n * Create a {@link DisTubeVoice}\n * @param {Discord.BaseGuildVoiceChannel} channel A voice channel to join\n * @returns {DisTubeVoice}\n * @private\n */\n create(channel: VoiceBasedChannel): DisTubeVoice {\n const existing = this.get(channel.guildId);\n if (existing) {\n existing.channel = channel;\n return existing;\n }\n return new DisTubeVoice(this, channel);\n }\n /**\n * Join a voice channel\n * @param {Discord.BaseGuildVoiceChannel} channel A voice channel to join\n * @returns {Promise<DisTubeVoice>}\n */\n join(channel: VoiceBasedChannel): Promise<DisTubeVoice> {\n const existing = this.get(channel.guildId);\n if (existing) return existing.join(channel);\n return this.create(channel).join();\n }\n /**\n * Leave the connected voice channel in a guild\n * @param {GuildIdResolvable} guild Queue Resolvable\n */\n leave(guild: GuildIdResolvable) {\n const voice = this.get(guild);\n if (voice) {\n voice.leave();\n } else {\n const connection =\n getVoiceConnection(resolveGuildId(guild), this.client.user?.id) ?? getVoiceConnection(resolveGuildId(guild));\n if (connection && connection.state.status !== VoiceConnectionStatus.Destroyed) {\n connection.destroy();\n }\n }\n }\n}\n","import { BaseManager } from \".\";\nimport { DisTubeError } from \"../..\";\nimport type { FilterResolvable, Queue } from \"../..\";\n\n/**\n * Manage filters of a playing {@link Queue}\n * @extends {BaseManager}\n */\nexport class FilterManager extends BaseManager<FilterResolvable> {\n queue: Queue;\n constructor(queue: Queue) {\n super(queue.distube);\n this.queue = queue;\n }\n\n #validate(filter: FilterResolvable): FilterResolvable {\n if (\n (typeof filter === \"string\" && Object.prototype.hasOwnProperty.call(this.distube.filters, filter)) ||\n (typeof filter === \"object\" && typeof filter.name === \"string\" && typeof filter.value === \"string\")\n ) {\n return filter;\n }\n\n throw new DisTubeError(\"INVALID_TYPE\", \"FilterResolvable\", filter, \"filter\");\n }\n\n #resolveName(filter: FilterResolvable): string {\n return typeof filter === \"string\" ? filter : filter.name;\n }\n\n #resolveValue(filter: FilterResolvable): string {\n return typeof filter === \"string\" ? this.distube.filters[filter] : filter.value;\n }\n\n #apply() {\n this.queue.beginTime = this.queue.currentTime;\n this.queues.playSong(this.queue);\n }\n\n /**\n * Enable a filter or multiple filters to the manager\n * @param {FilterResolvable|FilterResolvable[]} filterOrFilters The filter or filters to enable\n * @param {boolean} [override=false] Wether or not override the applied filter with new filter value\n * @returns {FilterManager}\n */\n add(filterOrFilters: FilterResolvable | FilterResolvable[], override = false) {\n if (Array.isArray(filterOrFilters)) {\n const resolvedFilters = filterOrFilters.map(f => this.#validate(f));\n const newFilters = resolvedFilters\n .reduceRight((unique, o: any) => {\n if (\n !unique.some((obj: any) => obj === o && obj.name === o) &&\n !unique.some((obj: any) => obj !== o.name && obj.name !== o.name)\n ) {\n if (!this.has(o)) unique.push(o);\n if (this.has(o) && override) {\n this.remove(o);\n unique.push(o);\n }\n }\n return unique;\n }, [] as FilterResolvable[])\n .reverse();\n return this.set([...this.collection.values(), ...newFilters]);\n }\n return this.set([...this.collection.values(), filterOrFilters]);\n }\n\n /**\n * Clear enabled filters of the manager\n * @returns {FilterManager}\n */\n clear() {\n return this.set([]);\n }\n\n /**\n * Set the filters applied to the manager\n * @param {FilterResolvable[]} filters The filters to apply\n * @returns {FilterManager}\n */\n set(filters: FilterResolvable[]) {\n this.collection.clear();\n for (const filter of filters) {\n const resolved = this.#validate(filter);\n this.collection.set(this.#resolveName(resolved), resolved);\n }\n this.#apply();\n return this;\n }\n\n /**\n * Disable a filter or multiple filters\n * @param {FilterResolvable|FilterResolvable[]} filterOrFilters The filter or filters to disable\n * @returns {FilterManager}\n */\n remove(filterOrFilters: FilterResolvable | FilterResolvable[]) {\n const remove = (f: FilterResolvable) => this.collection.delete(this.#resolveName(this.#validate(f)));\n if (Array.isArray(filterOrFilters)) filterOrFilters.map(remove);\n else remove(filterOrFilters);\n this.#apply();\n return this;\n }\n\n /**\n * Check whether a filter enabled or not\n * @param {FilterResolvable} filter The filter to check\n * @returns {boolean}\n */\n has(filter: FilterResolvable) {\n return this.collection.has(this.#resolveName(filter));\n }\n\n /**\n * Array of enabled filter name\n * @type {Array<string>}\n * @readonly\n */\n get names() {\n return this.collection.map(f => this.#resolveName(f));\n }\n\n get values() {\n return this.collection.map(f => this.#resolveValue(f));\n }\n\n override toString() {\n return this.names.toString();\n }\n}\n","import { GuildIdManager } from \".\";\nimport { DisTubeError, DisTubeStream, Queue, RepeatMode } from \"../..\";\nimport type { DisTubeVoiceEvents, Song } from \"../..\";\nimport type { GuildTextBasedChannel, VoiceBasedChannel } from \"discord.js\";\n\n/**\n * Queue manager\n * @extends GuildIdManager\n */\nexport class QueueManager extends GuildIdManager<Queue> {\n /**\n * Collection of {@link Queue}.\n * @name QueueManager#collection\n * @type {Discord.Collection<string, Queue>}\n */\n /**\n * Create a {@link Queue}\n * @private\n * @param {Discord.BaseGuildVoiceChannel} channel A voice channel\n * @param {Song|Song[]} song First song\n * @param {Discord.BaseGuildTextChannel} textChannel Default text channel\n * @returns {Promise<Queue|true>} Returns `true` if encounter an error\n */\n async create(\n channel: VoiceBasedChannel,\n song: Song[] | Song,\n textChannel?: GuildTextBasedChannel,\n ): Promise<Queue | true> {\n if (this.has(channel.guildId)) throw new DisTubeError(\"QUEUE_EXIST\");\n const voice = this.voices.create(channel);\n const queue = new Queue(this.distube, voice, song, textChannel);\n await queue._taskQueue.queuing();\n try {\n await voice.join();\n this.#voiceEventHandler(queue);\n this.add(queue.id, queue);\n this.emit(\"initQueue\", queue);\n const err = await this.playSong(queue);\n return err || queue;\n } finally {\n queue._taskQueue.resolve();\n }\n }\n /**\n * Get a Queue from this QueueManager.\n * @method get\n * @memberof QueueManager#\n * @param {GuildIdResolvable} guild Resolvable thing from a guild\n * @returns {Queue?}\n */\n /**\n * Listen to DisTubeVoice events and handle the Queue\n * @private\n * @param {Queue} queue Queue\n */\n #voiceEventHandler(queue: Queue) {\n queue._listeners = {\n disconnect: error => {\n queue.remove();\n this.emit(\"disconnect\", queue);\n if (error) this.emitError(error, queue.textChannel);\n },\n error: error => this.#handlePlayingError(queue, error),\n finish: () => this.#handleSongFinish(queue),\n };\n for (const event of Object.keys(queue._listeners) as (keyof DisTubeVoiceEvents)[]) {\n queue.voice.on(event, queue._listeners[event]);\n }\n }\n /**\n * Handle the queue when a Song finish\n * @private\n * @param {Queue} queue queue\n * @returns {Promise<void>}\n */\n async #handleSongFinish(queue: Queue): Promise<void> {\n this.emit(\"finishSong\", queue, queue.songs[0]);\n await queue._taskQueue.queuing();\n try {\n if (queue.stopped) return;\n if (queue.repeatMode === RepeatMode.QUEUE && !queue._prev) queue.songs.push(queue.songs[0]);\n if (queue._prev) {\n if (queue.repeatMode === RepeatMode.QUEUE) queue.songs.unshift(queue.songs.pop() as Song);\n else queue.songs.unshift(queue.previousSongs.pop() as Song);\n }\n if (queue.songs.length <= 1 && (queue._next || queue.repeatMode === RepeatMode.DISABLED)) {\n if (queue.autoplay) {\n try {\n await queue.addRelatedSong();\n } catch {\n this.emit(\"noRelated\", queue);\n }\n }\n if (queue.songs.length <= 1) {\n if (this.options.leaveOnFinish) queue.voice.leave();\n if (!queue.autoplay) this.emit(\"finish\", queue);\n queue.remove();\n return;\n }\n }\n const emitPlaySong = this.#emitPlaySong(queue);\n if (!queue._prev && (queue.repeatMode !== RepeatMode.SONG || queue._next)) {\n const prev = queue.songs.shift() as Song;\n delete prev.formats;\n delete prev.streamURL;\n if (this.options.savePreviousSongs) queue.previousSongs.push(prev);\n else queue.previousSongs.push({ id: prev.id } as Song);\n }\n queue._next = queue._prev = false;\n queue.beginTime = 0;\n const err = await this.playSong(queue);\n if (!err && emitPlaySong) this.emit(\"playSong\", queue, queue.songs[0]);\n } finally {\n queue._taskQueue.resolve();\n }\n }\n /**\n * Handle error while playing\n * @private\n * @param {Queue} queue queue\n * @param {Error} error error\n */\n #handlePlayingError(queue: Queue, error: Error) {\n const song = queue.songs.shift() as Song;\n try {\n error.name = \"PlayingError\";\n error.message = `${error.message}\\nId: ${song.id}\\nName: ${song.name}`;\n } catch {}\n this.emitError(error, queue.textChannel);\n if (queue.songs.length > 0) {\n queue._next = queue._prev = false;\n queue.beginTime = 0;\n this.playSong(queue).then(e => {\n if (!e) this.emit(\"playSong\", queue, queue.songs[0]);\n });\n } else {\n queue.stop();\n }\n }\n\n /**\n * Create a ytdl stream\n * @param {Queue} queue Queue\n * @returns {DisTubeStream}\n */\n createStream(queue: Queue): DisTubeStream {\n const { duration, formats, isLive, source, streamURL } = queue.songs[0];\n const ffmpegArgs = queue.filters.size ? [\"-af\", queue.filters.values.join(\",\")] : undefined;\n const seek = duration ? queue.beginTime : undefined;\n const streamOptions = { ffmpegArgs, seek, isLive, type: this.options.streamType };\n if (source === \"youtube\") return DisTubeStream.YouTube(formats, streamOptions);\n return DisTubeStream.DirectLink(streamURL as string, streamOptions);\n }\n\n /**\n * Play a song on voice connection\n * @private\n * @param {Queue} queue The guild queue\n * @returns {Promise<boolean>} error?\n */\n async playSong(queue: Queue): Promise<boolean> {\n if (!queue) return true;\n if (!queue.songs.length) {\n queue.stop();\n return true;\n }\n if (queue.stopped) return false;\n try {\n const song = queue.songs[0];\n const { url, source, formats, streamURL } = song;\n if (source === \"youtube\" && !formats) song._patchYouTube(await this.handler.getYouTubeInfo(url));\n if (source !== \"youtube\" && !streamURL) {\n for (const plugin of [...this.distube.extractorPlugins, ...this.distube.customPlugins]) {\n if (await plugin.validate(url)) {\n const info = [plugin.getStreamURL(url), plugin.getRelatedSongs(url)] as const;\n const result = await Promise.all(info);\n song.streamURL = result[0];\n song.related = result[1];\n break;\n }\n }\n }\n const stream = this.createStream(queue);\n queue.voice.play(stream);\n song.streamURL = stream.url;\n if (queue.stopped) queue.stop();\n else if (queue.paused) queue.voice.pause();\n return false;\n } catch (e: any) {\n this.#handlePlayingError(queue, e);\n return true;\n }\n }\n /**\n * Whether or not emit playSong event\n * @param {Queue} queue Queue\n * @private\n * @returns {boolean}\n */\n #emitPlaySong(queue: Queue): boolean {\n return (\n !this.options.emitNewSongOnly ||\n (queue.repeatMode === RepeatMode.SONG && queue._next) ||\n (queue.repeatMode !== RepeatMode.SONG && queue.songs[0]?.id !== queue.songs[1]?.id)\n );\n }\n}\n","import ytpl from \"@distube/ytpl\";\nimport ytdl from \"@distube/ytdl-core\";\nimport { DisTubeBase } from \".\";\nimport {\n DisTubeError,\n Playlist,\n Queue,\n SearchResultPlaylist,\n SearchResultVideo,\n Song,\n isMessageInstance,\n isObject,\n isURL,\n isVoiceChannelEmpty,\n} from \"..\";\nimport type { Message, TextChannel, VoiceBasedChannel } from \"discord.js\";\nimport type {\n DisTube,\n OtherSongInfo,\n PlayHandlerOptions,\n ResolveOptions,\n ResolvePlaylistOptions,\n SearchResult,\n} from \"..\";\n\n/**\n * DisTube's Handler\n * @extends DisTubeBase\n * @private\n */\nexport class DisTubeHandler extends DisTubeBase {\n constructor(distube: DisTube) {\n super(distube);\n\n const client = this.client;\n if (this.options.leaveOnEmpty) {\n client.on(\"voiceStateUpdate\", oldState => {\n if (!oldState?.channel) return;\n const queue = this.queues.get(oldState);\n if (!queue) {\n if (isVoiceChannelEmpty(oldState)) {\n setTimeout(() => {\n if (!this.queues.get(oldState) && isVoiceChannelEmpty(oldState)) this.voices.leave(oldState);\n }, this.options.emptyCooldown * 1e3).unref();\n }\n return;\n }\n if (queue._emptyTimeout) {\n clearTimeout(queue._emptyTimeout);\n delete queue._emptyTimeout;\n }\n if (isVoiceChannelEmpty(oldState)) {\n queue._emptyTimeout = setTimeout(() => {\n delete queue._emptyTimeout;\n if (isVoiceChannelEmpty(oldState)) {\n queue.voice.leave();\n this.emit(\"empty\", queue);\n if (queue.stopped) queue.remove();\n }\n }, this.options.emptyCooldown * 1e3).unref();\n }\n });\n }\n }\n\n get ytdlOptions(): ytdl.getInfoOptions {\n const options: any = this.options.ytdlOptions;\n if (this.options.youtubeCookie) {\n if (!options.requestOptions) options.requestOptions = {};\n if (!options.requestOptions.headers) options.requestOptions.headers = {};\n options.requestOptions.headers.cookie = this.options.youtubeCookie;\n if (this.options.youtubeIdentityToken) {\n options.requestOptions.headers[\"x-youtube-identity-token\"] = this.options.youtubeIdentityToken;\n }\n }\n return options;\n }\n\n /**\n * @param {string} url url\n * @param {boolean} [basic=false] getBasicInfo?\n * @returns {Promise<ytdl.videoInfo>}\n */\n getYouTubeInfo(url: string, basic = false): Promise<ytdl.videoInfo> {\n if (basic) return ytdl.getBasicInfo(url, this.ytdlOptions);\n return ytdl.getInfo(url, this.ytdlOptions);\n }\n\n resolve<T = unknown>(song: Song<T>, options?: Omit<ResolveOptions, \"metadata\">): Promise<Song<T>>;\n resolve<T = unknown>(song: Playlist<T>, options?: Omit<ResolveOptions, \"metadata\">): Promise<Playlist<T>>;\n resolve<T = unknown>(song: string | SearchResult, options?: ResolveOptions<T>): Promise<Song<T> | Playlist<T>>;\n resolve<T = unknown>(\n song: ytdl.videoInfo | OtherSongInfo | ytdl.relatedVideo,\n options?: ResolveOptions<T>,\n ): Promise<Song<T>>;\n resolve<T = unknown>(song: Playlist, options: ResolveOptions<T>): Promise<Playlist<T>>;\n resolve(\n song: string | ytdl.videoInfo | Song | Playlist | SearchResult | OtherSongInfo | ytdl.relatedVideo,\n options?: ResolveOptions,\n ): Promise<Song | Playlist>;\n /**\n * Resolve a url or a supported object to a {@link Song} or {@link Playlist}\n * @param {string|Song|SearchResult|Playlist} song URL | {@link Song}| {@link SearchResult} | {@link Playlist}\n * @param {ResolveOptions} [options] Optional options\n * @returns {Promise<Song|Playlist|null>} Resolved\n */\n async resolve(\n song: string | ytdl.videoInfo | Song | Playlist | SearchResult | OtherSongInfo | ytdl.relatedVideo,\n options: ResolveOptions = {},\n ): Promise<Song | Playlist> {\n if (song instanceof Song || song instanceof Playlist) {\n if (\"metadata\" in options) song.metadata = options.metadata;\n if (\"member\" in options) song.member = options.member;\n return song;\n }\n if (song instanceof SearchResultVideo) return new Song(song, options);\n if (song instanceof SearchResultPlaylist) return this.resolvePlaylist(song.url, options);\n if (isObject(song)) {\n if (!(\"url\" in song) && !(\"id\" in song)) throw new DisTubeError(\"CANNOT_RESOLVE_SONG\", song);\n return new Song(song, options);\n }\n if (ytpl.validateID(song)) return this.resolvePlaylist(song, options);\n if (ytdl.validateURL(song)) return new Song(await this.getYouTubeInfo(song), options);\n if (isURL(song)) {\n for (const plugin of this.distube.extractorPlugins) {\n if (await plugin.validate(song)) return plugin.resolve(song, options);\n }\n throw new DisTubeError(\"NOT_SUPPORTED_URL\");\n }\n throw new DisTubeError(\"CANNOT_RESOLVE_SONG\", song);\n }\n\n resolvePlaylist<T = unknown>(\n playlist: Playlist<T> | Song<T>[] | string,\n options?: Omit<ResolvePlaylistOptions, \"metadata\">,\n ): Promise<Playlist<T>>;\n resolvePlaylist<T = undefined>(\n playlist: Playlist | Song[] | string,\n options: ResolvePlaylistOptions<T>,\n ): Promise<Playlist<T>>;\n resolvePlaylist(playlist: Playlist | Song[] | string, options?: ResolvePlaylistOptions): Promise<Playlist>;\n /**\n * Resolve Song[] or YouTube playlist url to a Playlist\n * @param {Playlist|Song[]|string} playlist Resolvable playlist\n * @param {ResolvePlaylistOptions} options Optional options\n * @returns {Promise<Playlist>}\n */\n async resolvePlaylist(playlist: Playlist | Song[] | string, options: ResolvePlaylistOptions = {}): Promise<Playlist> {\n const { member, source, metadata } = { source: \"youtube\", ...options };\n if (playlist instanceof Playlist) {\n if (\"metadata\" in options) playlist.metadata = metadata;\n if (\"member\" in options) playlist.member = member;\n return playlist;\n }\n if (typeof playlist === \"string\") {\n const info = await ytpl(playlist, { limit: Infinity });\n const songs = info.items\n .filter(v => !v.thumbnail.includes(\"no_thumbnail\"))\n .map(v => new Song(v as OtherSongInfo, { member, metadata }));\n return new Playlist(\n {\n source,\n songs,\n member,\n name: info.title,\n url: info.url,\n thumbnail: songs[0].thumbnail,\n },\n { metadata },\n );\n }\n return new Playlist(playlist, { member, properties: { source }, metadata });\n }\n\n /**\n * Search for a song, fire {@link DisTube#event:error} if not found.\n * @param {Discord.Message} message The original message from an user\n * @param {string} query The query string\n * @returns {Promise<SearchResult?>} Song info\n */\n async searchSong(message: Message<true>, query: string): Promise<SearchResult | null> {\n if (!isMessageInstance(message)) throw new DisTubeError(\"INVALID_TYPE\", \"Discord.Message\", message, \"message\");\n if (typeof query !== \"string\") throw new DisTubeError(\"INVALID_TYPE\", \"string\", query, \"query\");\n if (query.length === 0) throw new DisTubeError(\"EMPTY_STRING\", \"query\");\n const limit = this.options.searchSongs > 1 ? this.options.searchSongs : 1;\n const results = await this.distube\n .search(query, {\n limit,\n safeSearch: this.options.nsfw ? false : !(message.channel as TextChannel)?.nsfw,\n })\n .catch(() => {\n if (!this.emit(\"searchNoResult\", message, query)) {\n // eslint-disable-next-line no-console\n console.warn(\"searchNoResult event does not have any listeners! Emits `error` event instead.\");\n throw new DisTubeError(\"NO_RESULT\");\n }\n });\n if (!results) return null;\n return this.createSearchMessageCollector(message, results, query);\n }\n\n /**\n * Create a message collector for selecting search results.\n *\n * Needed events: {@link DisTube#event:searchResult}, {@link DisTube#event:searchCancel},\n * {@link DisTube#event:searchInvalidAnswer}, {@link DisTube#event:searchDone}.\n * @param {Discord.Message} message The original message from an user\n * @param {Array<SearchResult|Song|Playlist>} results The search results\n * @param {string?} [query] The query string\n * @returns {Promise<SearchResult|Song|Playlist|null>} Selected result\n */\n async createSearchMessageCollector<R extends SearchResult | Song | Playlist>(\n message: Message<true>,\n results: Array<R>,\n query?: string,\n ): Promise<R | null> {\n if (!isMessageInstance(message)) throw new DisTubeError(\"INVALID_TYPE\", \"Discord.Message\", message, \"message\");\n if (!Array.isArray(results) || results.length == 0) {\n throw new DisTubeError(\"INVALID_TYPE\", \"Array<SearchResult|Song|Playlist>\", results, \"results\");\n }\n if (this.options.searchSongs > 1) {\n const searchEvents = [\n \"searchNoResult\",\n \"searchResult\",\n \"searchCancel\",\n \"searchInvalidAnswer\",\n \"searchDone\",\n ] as const;\n for (const evn of searchEvents) {\n if (this.distube.listenerCount(evn) === 0) {\n /* eslint-disable no-console */\n console.warn(`\"searchSongs\" option is disabled due to missing \"${evn}\" listener.`);\n console.warn(\n `If you don't want to use \"${evn}\" event, simply add an empty listener (not recommended):\\n` +\n `<DisTube>.on(\"${evn}\", () => {})`,\n );\n /* eslint-enable no-console */\n this.options.searchSongs = 0;\n }\n }\n }\n const limit = this.options.searchSongs > 1 ? this.options.searchSongs : 1;\n let result = results[0];\n if (limit > 1) {\n results.splice(limit);\n this.emit(\"searchResult\", message, results, query);\n const c = message.channel;\n const answers = await c\n .awaitMessages({\n filter: (m: Message) => m.author.id === message.author.id,\n max: 1,\n time: this.options.searchCooldown * 1e3,\n errors: [\"time\"],\n })\n .catch(() => undefined);\n const ans = answers?.first();\n if (!ans) {\n this.emit(\"searchCancel\", message, query);\n return null;\n }\n const index = parseInt(ans.content, 10);\n if (isNaN(index) || index > results.length || index < 1) {\n this.emit(\"searchInvalidAnswer\", message, ans, query);\n return null;\n }\n this.emit(\"searchDone\", message, ans, query);\n result = results[index - 1];\n }\n return result;\n }\n\n /**\n * Play or add a {@link Playlist} to the queue.\n * @returns {Promise<void>}\n * @param {Discord.BaseGuildVoiceChannel} voiceChannel A voice channel\n * @param {Playlist|string} playlist A YouTube playlist url | a Playlist\n * @param {PlayHandlerOptions} [options] Optional options\n */\n async playPlaylist(\n voiceChannel: VoiceBasedChannel,\n playlist: Playlist,\n options: PlayHandlerOptions = {},\n ): Promise<void> {\n const { textChannel, skip } = { skip: false, ...options };\n const position = Number(options.position) || (skip ? 1 : 0);\n if (!(playlist instanceof Playlist)) throw new DisTubeError(\"INVALID_TYPE\", \"Playlist\", playlist, \"playlist\");\n\n const queue = this.queues.get(voiceChannel);\n\n if (!this.options.nsfw && !((queue?.textChannel || textChannel) as TextChannel)?.nsfw) {\n playlist.songs = playlist.songs.filter(s => !s.age_restricted);\n }\n if (!playlist.songs.length) {\n if (!this.options.nsfw && !(textChannel as TextChannel)?.nsfw) {\n throw new DisTubeError(\"EMPTY_FILTERED_PLAYLIST\");\n }\n throw new DisTubeError(\"EMPTY_PLAYLIST\");\n }\n if (queue) {\n if (this.options.joinNewVoiceChannel) queue.voice.channel = voiceChannel;\n queue.addToQueue(playlist.songs, position);\n if (skip) queue.skip();\n else this.emit(\"addList\", queue, playlist);\n } else {\n const newQueue = await this.queues.create(voiceChannel, playlist.songs, textChannel);\n if (newQueue instanceof Queue) {\n if (this.options.emitAddListWhenCreatingQueue) this.emit(\"addList\", newQueue, playlist);\n this.emit(\"playSong\", newQueue, newQueue.songs[0]);\n }\n }\n }\n\n /**\n * Play or add a {@link Song} to the queue.\n * @returns {Promise<void>}\n * @param {Discord.BaseGuildVoiceChannel} voiceChannel A voice channel\n * @param {Song} song A YouTube playlist url | a Playlist\n * @param {PlayHandlerOptions} [options] Optional options\n */\n async playSong(voiceChannel: VoiceBasedChannel, song: Song, options: PlayHandlerOptions = {}): Promise<void> {\n if (!(song instanceof Song)) throw new DisTubeError(\"INVALID_TYPE\", \"Song\", song, \"song\");\n const { textChannel, skip } = { skip: false, ...options };\n const position = Number(options.position) || (skip ? 1 : 0);\n\n const queue = this.queues.get(voiceChannel);\n if (!this.options.nsfw && song.age_restricted && !((queue?.textChannel || textChannel) as TextChannel)?.nsfw) {\n throw new DisTubeError(\"NON_NSFW\");\n }\n if (queue) {\n if (this.options.joinNewVoiceChannel) queue.voice.channel = voiceChannel;\n queue.addToQueue(song, position);\n if (skip) queue.skip();\n else this.emit(\"addSong\", queue, song);\n } else {\n const newQueue = await this.queues.create(voiceChannel, song, textChannel);\n if (newQueue instanceof Queue) {\n if (this.options.emitAddSongWhenCreatingQueue) this.emit(\"addSong\", newQueue, song);\n this.emit(\"playSong\", newQueue, song);\n }\n }\n }\n}\n","import { DisTubeError, StreamType, checkInvalidKey, defaultOptions } from \"..\";\nimport type ytdl from \"@distube/ytdl-core\";\nimport type { CustomPlugin, DisTubeOptions, ExtractorPlugin, Filters } from \"..\";\n\nexport class Options {\n plugins: (CustomPlugin | ExtractorPlugin)[];\n emitNewSongOnly: boolean;\n leaveOnFinish: boolean;\n leaveOnStop: boolean;\n leaveOnEmpty: boolean;\n emptyCooldown: number;\n savePreviousSongs: boolean;\n searchSongs: number;\n searchCooldown: number;\n youtubeCookie?: string;\n youtubeIdentityToken?: string;\n customFilters?: Filters;\n ytdlOptions: ytdl.getInfoOptions;\n nsfw: boolean;\n emitAddSongWhenCreatingQueue: boolean;\n emitAddListWhenCreatingQueue: boolean;\n joinNewVoiceChannel: boolean;\n streamType: StreamType;\n directLink: boolean;\n constructor(options: DisTubeOptions) {\n if (typeof options !== \"object\" || Array.isArray(options)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", options, \"DisTubeOptions\");\n }\n const opts = { ...defaultOptions, ...options };\n this.plugins = opts.plugins;\n this.emitNewSongOnly = opts.emitNewSongOnly;\n this.leaveOnEmpty = opts.leaveOnEmpty;\n this.leaveOnFinish = opts.leaveOnFinish;\n this.leaveOnStop = opts.leaveOnStop;\n this.savePreviousSongs = opts.savePreviousSongs;\n this.searchSongs = opts.searchSongs;\n this.youtubeCookie = opts.youtubeCookie;\n this.youtubeIdentityToken = opts.youtubeIdentityToken;\n this.customFilters = opts.customFilters;\n this.ytdlOptions = opts.ytdlOptions;\n this.searchCooldown = opts.searchCooldown;\n this.emptyCooldown = opts.emptyCooldown;\n this.nsfw = opts.nsfw;\n this.emitAddSongWhenCreatingQueue = opts.emitAddSongWhenCreatingQueue;\n this.emitAddListWhenCreatingQueue = opts.emitAddListWhenCreatingQueue;\n this.joinNewVoiceChannel = opts.joinNewVoiceChannel;\n this.streamType = opts.streamType;\n this.directLink = opts.directLink;\n checkInvalidKey(opts, this, \"DisTubeOptions\");\n this.#validateOptions();\n }\n\n #validateOptions(options = this) {\n if (typeof options.emitNewSongOnly !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.emitNewSongOnly, \"DisTubeOptions.emitNewSongOnly\");\n }\n if (typeof options.leaveOnEmpty !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.leaveOnEmpty, \"DisTubeOptions.leaveOnEmpty\");\n }\n if (typeof options.leaveOnFinish !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.leaveOnFinish, \"DisTubeOptions.leaveOnFinish\");\n }\n if (typeof options.leaveOnStop !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.leaveOnStop, \"DisTubeOptions.leaveOnStop\");\n }\n if (typeof options.savePreviousSongs !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.savePreviousSongs, \"DisTubeOptions.savePreviousSongs\");\n }\n if (typeof options.joinNewVoiceChannel !== \"boolean\") {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n \"boolean\",\n options.joinNewVoiceChannel,\n \"DisTubeOptions.joinNewVoiceChannel\",\n );\n }\n if (typeof options.youtubeCookie !== \"undefined\" && typeof options.youtubeCookie !== \"string\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"string\", options.youtubeCookie, \"DisTubeOptions.youtubeCookie\");\n }\n if (typeof options.youtubeIdentityToken !== \"undefined\" && typeof options.youtubeIdentityToken !== \"string\") {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n \"string\",\n options.youtubeIdentityToken,\n \"DisTubeOptions.youtubeIdentityToken\",\n );\n }\n if (\n (typeof options.customFilters !== \"undefined\" && typeof options.customFilters !== \"object\") ||\n Array.isArray(options.customFilters)\n ) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", options.customFilters, \"DisTubeOptions.customFilters\");\n }\n if (typeof options.ytdlOptions !== \"object\" || Array.isArray(options.ytdlOptions)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", options.ytdlOptions, \"DisTubeOptions.ytdlOptions\");\n }\n if (typeof options.searchCooldown !== \"number\" || isNaN(options.searchCooldown)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", options.searchCooldown, \"DisTubeOptions.searchCooldown\");\n }\n if (typeof options.emptyCooldown !== \"number\" || isNaN(options.emptyCooldown)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", options.emptyCooldown, \"DisTubeOptions.emptyCooldown\");\n }\n if (typeof options.searchSongs !== \"number\" || isNaN(options.searchSongs)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", options.searchSongs, \"DisTubeOptions.searchSongs\");\n }\n if (!Array.isArray(options.plugins)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"Array<Plugin>\", options.plugins, \"DisTubeOptions.plugins\");\n }\n if (typeof options.nsfw !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.nsfw, \"DisTubeOptions.nsfw\");\n }\n if (typeof options.emitAddSongWhenCreatingQueue !== \"boolean\") {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n \"boolean\",\n options.emitAddSongWhenCreatingQueue,\n \"DisTubeOptions.emitAddSongWhenCreatingQueue\",\n );\n }\n if (typeof options.emitAddListWhenCreatingQueue !== \"boolean\") {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n \"boolean\",\n options.emitAddListWhenCreatingQueue,\n \"DisTubeOptions.emitAddListWhenCreatingQueue\",\n );\n }\n if (typeof options.streamType !== \"number\" || isNaN(options.streamType) || !StreamType[options.streamType]) {\n throw new DisTubeError(\"INVALID_TYPE\", \"StreamType\", options.streamType, \"DisTubeOptions.streamType\");\n }\n if (typeof options.directLink !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", options.directLink, \"DisTubeOptions.directLink\");\n }\n }\n}\n","import { FFmpeg } from \"prism-media\";\nimport { DisTubeError, isURL } from \"..\";\nimport { StreamType as DiscordVoiceStreamType } from \"@discordjs/voice\";\nimport type ytdl from \"@distube/ytdl-core\";\nimport type { StreamType } from \"..\";\n\ninterface StreamOptions {\n seek?: number;\n ffmpegArgs?: string[];\n isLive?: boolean;\n type?: StreamType;\n}\n\nexport const chooseBestVideoFormat = (formats: ytdl.videoFormat[], isLive = false) => {\n let filter = (format: ytdl.videoFormat) => format.hasAudio;\n if (isLive) filter = (format: ytdl.videoFormat) => format.hasAudio && format.isHLS;\n formats = formats\n .filter(filter)\n .sort((a, b) => Number(b.audioBitrate) - Number(a.audioBitrate) || Number(a.bitrate) - Number(b.bitrate));\n return formats.find(format => !format.hasVideo) || formats.sort((a, b) => Number(a.bitrate) - Number(b.bitrate))[0];\n};\n\n/**\n * Create a stream to play with {@link DisTubeVoice}\n * @private\n */\nexport class DisTubeStream {\n /**\n * Create a stream from ytdl video formats\n * @param {ytdl.videoFormat[]} formats ytdl video formats\n * @param {StreamOptions} options options\n * @returns {DisTubeStream}\n * @private\n */\n static YouTube(formats: ytdl.videoFormat[] | undefined, options: StreamOptions = {}): DisTubeStream {\n if (!formats || !formats.length) throw new DisTubeError(\"UNAVAILABLE_VIDEO\");\n if (!options || typeof options !== \"object\" || Array.isArray(options)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", options, \"options\");\n }\n const bestFormat = chooseBestVideoFormat(formats, options.isLive);\n if (!bestFormat) throw new DisTubeError(\"UNPLAYABLE_FORMATS\");\n return new DisTubeStream(bestFormat.url, options);\n }\n /**\n * Create a stream from a stream url\n * @param {string} url stream url\n * @param {StreamOptions} options options\n * @returns {DisTubeStream}\n * @private\n */\n static DirectLink(url: string, options: StreamOptions = {}): DisTubeStream {\n if (!options || typeof options !== \"object\" || Array.isArray(options)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", options, \"options\");\n }\n if (typeof url !== \"string\" || !isURL(url)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"an URL\", url);\n }\n return new DisTubeStream(url, options);\n }\n type: DiscordVoiceStreamType;\n stream: FFmpeg;\n url: string;\n /**\n * Create a DisTubeStream to play with {@link DisTubeVoice}\n * @param {string} url Stream URL\n * @param {StreamOptions} options Stream options\n * @private\n */\n constructor(url: string, options: StreamOptions) {\n /**\n * Stream URL\n * @type {string}\n */\n this.url = url;\n /**\n * Stream type\n * @type {DiscordVoice.StreamType}\n */\n this.type = !options.type ? DiscordVoiceStreamType.OggOpus : DiscordVoiceStreamType.Raw;\n const args = [\n \"-reconnect\",\n \"1\",\n \"-reconnect_streamed\",\n \"1\",\n \"-reconnect_delay_max\",\n \"5\",\n \"-i\",\n url,\n \"-analyzeduration\",\n \"0\",\n \"-loglevel\",\n \"0\",\n \"-ar\",\n \"48000\",\n \"-ac\",\n \"2\",\n \"-f\",\n ];\n if (!options.type) {\n args.push(\"opus\", \"-acodec\", \"libopus\");\n } else {\n args.push(\"s16le\");\n }\n if (typeof options.seek === \"number\" && options.seek > 0) {\n args.unshift(\"-ss\", options.seek.toString());\n }\n if (Array.isArray(options.ffmpegArgs)) {\n args.push(...options.ffmpegArgs);\n }\n /**\n * FFmpeg stream\n * @type {FFmpeg}\n */\n this.stream = new FFmpeg({ args, shell: false });\n }\n}\n","import { DisTubeBase, FilterManager } from \"../core\";\nimport { DisTubeError, RepeatMode, Song, TaskQueue, formatDuration } from \"..\";\nimport type { GuildTextBasedChannel, Snowflake } from \"discord.js\";\nimport type { DisTube, DisTubeVoice, DisTubeVoiceEvents } from \"..\";\n\n/**\n * Represents a queue.\n * @extends DisTubeBase\n */\nexport class Queue extends DisTubeBase {\n readonly id: Snowflake;\n voice: DisTubeVoice;\n songs: Song[];\n previousSongs: Song[];\n stopped: boolean;\n _next: boolean;\n _prev: boolean;\n playing: boolean;\n paused: boolean;\n repeatMode: RepeatMode;\n autoplay: boolean;\n #filters: FilterManager;\n beginTime: number;\n textChannel?: GuildTextBasedChannel;\n _emptyTimeout?: NodeJS.Timeout;\n _taskQueue: TaskQueue;\n _listeners?: DisTubeVoiceEvents;\n /**\n * Create a queue for the guild\n * @param {DisTube} distube DisTube\n * @param {DisTubeVoice} voice Voice connection\n * @param {Song|Song[]} song First song(s)\n * @param {Discord.BaseGuildTextChannel?} textChannel Default text channel\n */\n constructor(distube: DisTube, voice: DisTubeVoice, song: Song | Song[], textChannel?: GuildTextBasedChannel) {\n super(distube);\n /**\n * Voice connection of this queue.\n * @type {DisTubeVoice}\n */\n this.voice = voice;\n /**\n * Queue id (Guild id)\n * @type {Discord.Snowflake}\n */\n this.id = voice.id;\n /**\n * Get or set the stream volume. Default value: `50`.\n * @type {number}\n */\n this.volume = 50;\n /**\n * List of songs in the queue (The first one is the playing song)\n * @type {Array<Song>}\n */\n this.songs = Array.isArray(song) ? [...song] : [song];\n /**\n * List of the previous songs.\n * @type {Array<Song>}\n */\n this.previousSongs = [];\n /**\n * Whether stream is currently stopped.\n * @type {boolean}\n * @private\n */\n this.stopped = false;\n /**\n * Whether or not the last song was skipped to next song.\n * @type {boolean}\n * @private\n */\n this._next = false;\n /**\n * Whether or not the last song was skipped to previous song.\n * @type {boolean}\n * @private\n */\n this._prev = false;\n /**\n * Whether or not the stream is currently playing.\n * @type {boolean}\n */\n this.playing = true;\n /**\n * Whether or not the stream is currently paused.\n * @type {boolean}\n */\n this.paused = false;\n /**\n * Type of repeat mode (`0` is disabled, `1` is repeating a song, `2` is repeating all the queue).\n * Default value: `0` (disabled)\n * @type {RepeatMode}\n */\n this.repeatMode = RepeatMode.DISABLED;\n /**\n * Whether or not the autoplay mode is enabled.\n * Default value: `false`\n * @type {boolean}\n */\n this.autoplay = false;\n this.#filters = new FilterManager(this);\n /**\n * What time in the song to begin (in seconds).\n * @type {number}\n */\n this.beginTime = 0;\n /**\n * The text channel of the Queue. (Default: where the first command is called).\n * @type {Discord.TextChannel?}\n */\n this.textChannel = textChannel;\n /**\n * Timeout for checking empty channel\n * @type {*}\n * @private\n */\n this._emptyTimeout = undefined;\n /**\n * Task queuing system\n * @type {TaskQueue}\n * @private\n */\n this._taskQueue = new TaskQueue();\n /**\n * DisTubeVoice listener\n * @type {Object}\n * @private\n */\n this._listeners = undefined;\n }\n /**\n * The client user as a `GuildMember` of this queue's guild\n * @type {Discord.GuildMember?}\n */\n get clientMember() {\n return this.voice.channel.guild.members.me ?? undefined;\n }\n /**\n * The filter manager of the queue\n * @type {FilterManager}\n * @readonly\n */\n get filters() {\n return this.#filters;\n }\n /**\n * Formatted duration string.\n * @type {string}\n * @readonly\n */\n get formattedDuration() {\n return formatDuration(this.duration);\n }\n /**\n * Queue's duration.\n * @type {number}\n * @readonly\n */\n get duration() {\n return this.songs.length ? this.songs.reduce((prev, next) => prev + next.duration, 0) : 0;\n }\n /**\n * What time in the song is playing (in seconds).\n * @type {number}\n * @readonly\n */\n get currentTime() {\n return this.voice.playbackDuration + this.beginTime;\n }\n /**\n * Formatted {@link Queue#currentTime} string.\n * @type {string}\n * @readonly\n */\n get formattedCurrentTime() {\n return formatDuration(this.currentTime);\n }\n /**\n * The voice channel playing in.\n * @type {Discord.VoiceChannel|Discord.StageChannel|null}\n * @readonly\n */\n get voiceChannel() {\n return this.clientMember?.voice?.channel ?? null;\n }\n get volume() {\n return this.voice.volume;\n }\n set volume(value: number) {\n this.voice.volume = value;\n }\n /**\n * @private\n * Add a Song or an array of Song to the queue\n * @param {Song|Song[]} song Song to add\n * @param {number} [position=0] Position to add, <= 0 to add to the end of the queue\n * @throws {Error}\n * @returns {Queue} The guild queue\n */\n addToQueue(song: Song | Song[], position = 0): Queue {\n if (!song || (Array.isArray(song) && !song.length)) {\n throw new DisTubeError(\"INVALID_TYPE\", [\"Song\", \"Array<Song>\"], song, \"song\");\n }\n if (typeof position !== \"number\" || !Number.isInteger(position)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"integer\", position, \"position\");\n }\n if (position <= 0) {\n if (Array.isArray(song)) this.songs.push(...song);\n else this.songs.push(song);\n } else if (Array.isArray(song)) {\n this.songs.splice(position, 0, ...song);\n } else {\n this.songs.splice(position, 0, song);\n }\n if (Array.isArray(song)) song.map(s => delete s.formats);\n else delete song.formats;\n return this;\n }\n /**\n * Pause the guild stream\n * @returns {Queue} The guild queue\n */\n pause(): Queue {\n if (this.paused) throw new DisTubeError(\"PAUSED\");\n this.playing = false;\n this.paused = true;\n this.voice.pause();\n return this;\n }\n /**\n * Resume the guild stream\n * @returns {Queue} The guild queue\n */\n resume(): Queue {\n if (this.playing) throw new DisTubeError(\"RESUMED\");\n this.playing = true;\n this.paused = false;\n this.voice.unpause();\n return this;\n }\n /**\n * Set the guild stream's volume\n * @param {number} percent The percentage of volume you want to set\n * @returns {Queue} The guild queue\n */\n setVolume(percent: number): Queue {\n this.volume = percent;\n return this;\n }\n\n /**\n * Skip the playing song if there is a next song in the queue.\n * <info>If {@link Queue#autoplay} is `true` and there is no up next song,\n * DisTube will add and play a related song.</info>\n * @returns {Promise<Song>} The song will skip to\n * @throws {Error}\n */\n async skip(): Promise<Song> {\n await this._taskQueue.queuing();\n try {\n if (this.songs.length <= 1) {\n if (this.autoplay) await this.addRelatedSong();\n else throw new DisTubeError(\"NO_UP_NEXT\");\n }\n const song = this.songs[1];\n this._next = true;\n this.voice.stop();\n return song;\n } finally {\n this._taskQueue.resolve();\n }\n }\n\n /**\n * Play the previous song if exists\n * @returns {Promise<Song>} The guild queue\n * @throws {Error}\n */\n async previous(): Promise<Song> {\n await this._taskQueue.queuing();\n try {\n if (!this.options.savePreviousSongs) throw new DisTubeError(\"DISABLED_OPTION\", \"savePreviousSongs\");\n if (this.previousSongs?.length === 0 && this.repeatMode !== RepeatMode.QUEUE) {\n throw new DisTubeError(\"NO_PREVIOUS\");\n }\n const song =\n this.repeatMode === 2 ? this.songs[this.songs.length - 1] : this.previousSongs[this.previousSongs.length - 1];\n this._prev = true;\n this.voice.stop();\n return song;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Shuffle the queue's songs\n * @returns {Promise<Queue>} The guild queue\n */\n async shuffle(): Promise<Queue> {\n await this._taskQueue.queuing();\n try {\n const playing = this.songs.shift();\n if (playing === undefined) return this;\n for (let i = this.songs.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [this.songs[i], this.songs[j]] = [this.songs[j], this.songs[i]];\n }\n this.songs.unshift(playing);\n return this;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Jump to the song position in the queue.\n * The next one is 1, 2,...\n * The previous one is -1, -2,...\n * @param {number} position The song position to play\n * @returns {Promise<Song>} The new Song will be played\n * @throws {Error} if `num` is invalid number\n */\n async jump(position: number): Promise<Song> {\n await this._taskQueue.queuing();\n try {\n if (typeof position !== \"number\") throw new DisTubeError(\"INVALID_TYPE\", \"number\", position, \"position\");\n if (!position || position > this.songs.length || -position > this.previousSongs.length) {\n throw new DisTubeError(\"NO_SONG_POSITION\");\n }\n let nextSong: Song;\n if (position > 0) {\n const nextSongs = this.songs.splice(position - 1);\n if (this.options.savePreviousSongs) {\n this.previousSongs.push(...this.songs);\n } else {\n this.previousSongs.push(...this.songs.map(s => ({ id: s.id } as Song)));\n }\n this.songs = nextSongs;\n this._next = true;\n nextSong = nextSongs[1];\n } else if (!this.options.savePreviousSongs) {\n throw new DisTubeError(\"DISABLED_OPTION\", \"savePreviousSongs\");\n } else {\n this._prev = true;\n if (position !== -1) this.songs.unshift(...this.previousSongs.splice(position + 1));\n nextSong = this.previousSongs[this.previousSongs.length - 1];\n }\n this.voice.stop();\n return nextSong;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Set the repeat mode of the guild queue.\\\n * Toggle mode `(Disabled -> Song -> Queue -> Disabled ->...)` if `mode` is `undefined`\n * @param {RepeatMode?} [mode] The repeat modes (toggle if `undefined`)\n * @returns {RepeatMode} The new repeat mode\n */\n setRepeatMode(mode?: RepeatMode): RepeatMode {\n if (mode !== undefined && !Object.values(RepeatMode).includes(mode)) {\n throw new DisTubeError(\"INVALID_TYPE\", [\"RepeatMode\", \"undefined\"], mode, \"mode\");\n }\n if (mode === undefined) this.repeatMode = (this.repeatMode + 1) % 3;\n else if (this.repeatMode === mode) this.repeatMode = RepeatMode.DISABLED;\n else this.repeatMode = mode;\n return this.repeatMode;\n }\n /**\n * Set the playing time to another position\n * @param {number} time Time in seconds\n * @returns {Queue} The guild queue\n */\n seek(time: number): Queue {\n if (typeof time !== \"number\") throw new DisTubeError(\"INVALID_TYPE\", \"number\", time, \"time\");\n if (isNaN(time) || time < 0) throw new DisTubeError(\"NUMBER_COMPARE\", \"time\", \"bigger or equal to\", 0);\n this.beginTime = time;\n this.queues.playSong(this);\n return this;\n }\n /**\n * Add a related song of the playing song to the queue\n * @returns {Promise<Song>} The added song\n * @throws {Error}\n */\n async addRelatedSong(): Promise<Song> {\n if (!this.songs?.[0]) throw new DisTubeError(\"NO_PLAYING\");\n const related = this.songs[0].related.find(v => !this.previousSongs.map(s => s.id).includes(v.id));\n if (!related || !(related instanceof Song)) throw new DisTubeError(\"NO_RELATED\");\n const song = await this.handler.resolve(related, { member: this.clientMember, metadata: related.metadata });\n if (!(song instanceof Song)) throw new DisTubeError(\"CANNOT_PLAY_RELATED\");\n this.addToQueue(song);\n return song;\n }\n /**\n * Stop the guild stream and delete the queue\n */\n async stop() {\n await this._taskQueue.queuing();\n try {\n this.playing = false;\n this.paused = false;\n this.stopped = true;\n if (this.options.leaveOnStop) this.voice.leave();\n else this.voice.stop();\n this.remove();\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Remove the queue from the manager\n * (This does not leave the voice channel even if {@link DisTubeOptions|DisTubeOptions.leaveOnStop} is enabled)\n * @private\n */\n remove() {\n this.stopped = true;\n this.songs = [];\n this.previousSongs = [];\n if (this._listeners) {\n for (const event of Object.keys(this._listeners) as (keyof DisTubeVoiceEvents)[]) {\n this.voice.removeListener(event, this._listeners[event]);\n }\n }\n this.queues.remove(this.id);\n this.emit(\"deleteQueue\", this);\n }\n /**\n * Toggle autoplay mode\n * @returns {boolean} Autoplay mode state\n */\n toggleAutoplay(): boolean {\n this.autoplay = !this.autoplay;\n return this.autoplay;\n }\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\nimport type { Client, GuildTextBasedChannel } from \"discord.js\";\nimport type {\n Awaitable,\n DisTube,\n DisTubeEvents,\n DisTubeHandler,\n DisTubeVoiceManager,\n Options,\n PluginType,\n QueueManager,\n RelatedSong,\n} from \"..\";\n\n/**\n * DisTube Plugin\n * @abstract\n * @private\n */\nexport abstract class Plugin {\n abstract type: PluginType;\n distube!: DisTube;\n init(distube: DisTube) {\n /**\n * DisTube\n * @type {DisTube}\n */\n this.distube = distube;\n }\n /**\n * Type of the plugin\n * @name Plugin#type\n * @type {PluginType}\n */\n /**\n * Emit an event to the {@link DisTube} class\n * @param {string} eventName Event name\n * @param {...any} args arguments\n * @returns {boolean}\n */\n emit(eventName: keyof DisTubeEvents, ...args: any): boolean {\n return this.distube.emit(eventName, ...args);\n }\n /**\n * Emit error event to the {@link DisTube} class\n * @param {Error} error error\n * @param {Discord.BaseGuildTextChannel} [channel] Text channel where the error is encountered.\n */\n emitError(error: Error, channel?: GuildTextBasedChannel) {\n this.distube.emitError(error, channel);\n }\n /**\n * The queue manager\n * @type {QueueManager}\n * @readonly\n */\n get queues(): QueueManager {\n return this.distube.queues;\n }\n /**\n * The voice manager\n * @type {DisTubeVoiceManager}\n * @readonly\n */\n get voices(): DisTubeVoiceManager {\n return this.distube.voices;\n }\n /**\n * Discord.js client\n * @type {Discord.Client}\n * @readonly\n */\n get client(): Client {\n return this.distube.client;\n }\n /**\n * DisTube options\n * @type {DisTubeOptions}\n * @readonly\n */\n get options(): Options {\n return this.distube.options;\n }\n /**\n * DisTube handler\n * @type {DisTubeHandler}\n * @readonly\n */\n get handler(): DisTubeHandler {\n return this.distube.handler;\n }\n /**\n * Check if the string is working with this plugin\n * @param {string} _string Input string\n * @returns {boolean|Promise<boolean>}\n */\n validate(_string: string): Awaitable<boolean> {\n return false;\n }\n /**\n * Get the stream url from {@link Song#url}. Returns {@link Song#url} by default.\n * Not needed if the plugin plays song from YouTube.\n * @param {string} url Input url\n * @returns {string|Promise<string>}\n */\n getStreamURL(url: string): Awaitable<string> {\n return url;\n }\n /**\n * Get related songs from a supported url. {@link Song#member} should be `undefined`.\n * Not needed to add {@link Song#related} because it will be added with this function later.\n * @param {string} _url Input url\n * @returns {Song[]|Promise<Song[]>}\n */\n getRelatedSongs(_url: string): Awaitable<RelatedSong[]> {\n return [];\n }\n}\n","import { Plugin } from \".\";\nimport { PluginType } from \"..\";\nimport type { VoiceBasedChannel } from \"discord.js\";\nimport type { Awaitable, PlayOptions } from \"..\";\n\n/**\n * Custom Plugin\n * @extends Plugin\n * @abstract\n */\nexport abstract class CustomPlugin extends Plugin {\n readonly type = PluginType.CUSTOM;\n abstract play(voiceChannel: VoiceBasedChannel, song: string, options: PlayOptions): Awaitable<void>;\n}\n\n/**\n * This method will be executed if the url is validated.\n * @param {Discord.BaseGuildVoiceChannel} voiceChannel The voice channel will be joined\n * @param {string} song Validated `song`\n * @param {PlayOptions} [options] Optional options\n * @returns {Promise<void>}\n * @abstract\n * @method play\n * @memberof CustomPlugin#\n */\n\n/**\n * Check if the string is working with this plugin\n * @param {string} string String need to validate\n * @returns {boolean|Promise<boolean>}\n * @method validate\n * @memberof CustomPlugin#\n */\n","import { Plugin } from \".\";\nimport { PluginType } from \"..\";\nimport type { GuildMember } from \"discord.js\";\nimport type { Awaitable, Playlist, Song } from \"..\";\n\n/**\n * Extractor Plugin\n * @extends Plugin\n * @abstract\n */\nexport abstract class ExtractorPlugin extends Plugin {\n readonly type = PluginType.EXTRACTOR;\n abstract resolve<T = unknown>(\n url: string,\n options: { member?: GuildMember; metadata?: T },\n ): Awaitable<Song<T> | Playlist<T>>;\n}\n\n/**\n * Resolve the validated url to a {@link Song} or a {@link Playlist}.\n *\n * @param {string} url URL\n * @param {Object} [options] Optional options\n * @param {Discord.GuildMember} [options.member] Requested user\n * @param {*} [options.metadata] Metadata\n * @returns {Song|Playlist|Promise<Song|Playlist>}\n * @method resolve\n * @memberof ExtractorPlugin#\n * @abstract\n */\n\n/**\n * Check if the url is working with this plugin\n * @param {string} url Input url\n * @returns {boolean|Promise<boolean>}\n * @method validate\n * @memberof ExtractorPlugin#\n */\n","import { URL } from \"url\";\nimport { DisTubeError, DisTubeVoice, Queue } from \".\";\nimport { Constants, GatewayIntentBits, IntentsBitField, SnowflakeUtil } from \"discord.js\";\nimport type { GuildIdResolvable } from \".\";\nimport type {\n Client,\n ClientOptions,\n Guild,\n GuildMember,\n GuildTextBasedChannel,\n Message,\n Snowflake,\n VoiceBasedChannel,\n VoiceState,\n} from \"discord.js\";\n\nconst formatInt = (int: number) => (int < 10 ? `0${int}` : int);\n\n/**\n * Format duration to string\n * @param {number} sec Duration in seconds\n * @returns {string}\n */\nexport function formatDuration(sec: number): string {\n if (!sec || !Number(sec)) return \"00:00\";\n const seconds = Math.round(sec % 60);\n const minutes = Math.floor((sec % 3600) / 60);\n const hours = Math.floor(sec / 3600);\n if (hours > 0) return `${formatInt(hours)}:${formatInt(minutes)}:${formatInt(seconds)}`;\n if (minutes > 0) return `${formatInt(minutes)}:${formatInt(seconds)}`;\n return `00:${formatInt(seconds)}`;\n}\n/**\n * Convert formatted duration to seconds\n * @param {*} input Formatted duration string\n * @returns {number}\n */\nexport function toSecond(input: any): number {\n if (!input) return 0;\n if (typeof input !== \"string\") return Number(input) || 0;\n if (input.match(/:/g)) {\n const time = input.split(\":\").reverse();\n let s = 0;\n for (let i = 0; i < 3; i++) if (time[i]) s += Number(time[i].replace(/[^\\d.]+/g, \"\")) * Math.pow(60, i);\n if (time.length > 3) s += Number(time[3].replace(/[^\\d.]+/g, \"\")) * 24 * 60 * 60;\n return s;\n } else {\n return Number(input.replace(/[^\\d.]+/g, \"\")) || 0;\n }\n}\n/**\n * Parse number from input\n * @param {*} input Any\n * @returns {number}\n */\nexport function parseNumber(input: any): number {\n if (typeof input === \"string\") return Number(input.replace(/[^\\d.]+/g, \"\")) || 0;\n return Number(input) || 0;\n}\n/**\n * Check if the string is an URL\n * @param {string} input input\n * @returns {boolean}\n */\nexport function isURL(input: any): input is `http://${string}` | `https://${string}` {\n if (typeof input !== \"string\" || input.includes(\" \")) return false;\n try {\n const url = new URL(input);\n if (![\"https:\", \"http:\"].includes(url.protocol) || !url.host) return false;\n } catch {\n return false;\n }\n return true;\n}\n/**\n * Check if the Client has enough intents to using DisTube\n * @param {ClientOptions} options options\n */\nexport function checkIntents(options: ClientOptions): void {\n const intents = new IntentsBitField(options.intents);\n if (!intents.has(GatewayIntentBits.GuildVoiceStates)) throw new DisTubeError(\"MISSING_INTENTS\", \"GuildVoiceStates\");\n}\n\n/**\n * Check if the voice channel is empty\n * @param {Discord.VoiceState} voiceState voiceState\n * @returns {boolean}\n */\nexport function isVoiceChannelEmpty(voiceState: VoiceState): boolean {\n const guild = voiceState.guild;\n const clientId = voiceState.client.user?.id;\n if (!guild || !clientId) return false;\n const voiceChannel = guild.members.me?.voice?.channel;\n if (!voiceChannel) return false;\n const members = voiceChannel.members.filter(m => !m.user.bot);\n return !members.size;\n}\n\nexport function isSnowflake(id: any): id is Snowflake {\n try {\n return SnowflakeUtil.deconstruct(id).timestamp > SnowflakeUtil.epoch;\n } catch {\n return false;\n }\n}\n\nexport function isMemberInstance(member: any): member is GuildMember {\n return (\n !!member &&\n isSnowflake(member.id) &&\n isSnowflake(member.guild?.id) &&\n isSnowflake(member.user?.id) &&\n member.id === member.user.id\n );\n}\n\nexport function isTextChannelInstance(channel: any): channel is GuildTextBasedChannel {\n return (\n !!channel &&\n isSnowflake(channel.id) &&\n isSnowflake(channel.guildId) &&\n typeof channel.name === \"string\" &&\n Constants.TextBasedChannelTypes.includes(channel.type) &&\n typeof channel.nsfw === \"boolean\" &&\n \"messages\" in channel &&\n typeof channel.send === \"function\"\n );\n}\n\nexport function isMessageInstance(message: any): message is Message<true> {\n // Simple check for using distube normally\n return (\n !!message &&\n isSnowflake(message.id) &&\n isSnowflake(message.guildId) &&\n isMemberInstance(message.member) &&\n isTextChannelInstance(message.channel) &&\n Constants.NonSystemMessageTypes.includes(message.type) &&\n message.member.id === message.author?.id\n );\n}\n\nexport function isSupportedVoiceChannel(channel: any): channel is VoiceBasedChannel {\n return (\n !!channel &&\n isSnowflake(channel.id) &&\n isSnowflake(channel.guildId) &&\n Constants.VoiceBasedChannelTypes.includes(channel.type)\n );\n}\n\nexport function isGuildInstance(guild: any): guild is Guild {\n return !!guild && isSnowflake(guild.id) && isSnowflake(guild.ownerId) && typeof guild.name === \"string\";\n}\n\nexport function resolveGuildId(resolvable: GuildIdResolvable): Snowflake {\n let guildId: string | undefined;\n if (typeof resolvable === \"string\") {\n guildId = resolvable;\n } else if (isObject(resolvable)) {\n if (\"guildId\" in resolvable && resolvable.guildId) {\n guildId = resolvable.guildId;\n } else if (resolvable instanceof Queue || resolvable instanceof DisTubeVoice || isGuildInstance(resolvable)) {\n guildId = resolvable.id;\n } else if (\"guild\" in resolvable && isGuildInstance(resolvable.guild)) {\n guildId = resolvable.guild.id;\n }\n }\n if (!isSnowflake(guildId)) throw new DisTubeError(\"INVALID_TYPE\", \"GuildIdResolvable\", resolvable);\n return guildId;\n}\n\nexport function isClientInstance(client: any): client is Client {\n return !!client && typeof client.login === \"function\";\n}\n\nexport function checkInvalidKey(\n target: Record<string, any>,\n source: Record<string, any> | string[],\n sourceName: string,\n) {\n if (!isObject(target)) throw new DisTubeError(\"INVALID_TYPE\", \"object\", target, sourceName);\n const sourceKeys = Array.isArray(source) ? source : Object.keys(source);\n const invalidKey = Object.keys(target).find(key => !sourceKeys.includes(key));\n if (invalidKey) throw new DisTubeError(\"INVALID_KEY\", sourceName, invalidKey);\n}\n\nexport function isObject(obj: any): obj is object {\n return typeof obj === \"object\" && obj !== null && !Array.isArray(obj);\n}\n\nexport function isRecord<T = unknown>(obj: any): obj is Record<string, T> {\n return isObject(obj);\n}\n","import { request } from \"undici\";\nimport { ExtractorPlugin, Song } from \"..\";\nimport type { GuildMember } from \"discord.js\";\n\nexport class DirectLinkPlugin extends ExtractorPlugin {\n override async validate(url: string) {\n try {\n const headers = await request(url, { method: \"HEAD\" }).then(res => res.headers);\n const type = headers[\"content-type\"];\n\n if (type?.startsWith(\"audio\")) return true;\n } catch {}\n return false;\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async resolve(url: string, options: { member?: GuildMember; metadata?: any } = {}) {\n url = url.replace(/\\/+$/, \"\");\n return new Song(\n {\n name: url.substring(url.lastIndexOf(\"/\") + 1).replace(/((\\?|#).*)?$/, \"\") || url,\n url,\n },\n options,\n );\n }\n}\n","import ytsr from \"@distube/ytsr\";\nimport { TypedEmitter } from \"tiny-typed-emitter\";\nimport {\n DirectLinkPlugin,\n DisTubeError,\n DisTubeHandler,\n DisTubeVoiceManager,\n Options,\n Playlist,\n QueueManager,\n SearchResultPlaylist,\n SearchResultType,\n SearchResultVideo,\n Song,\n checkIntents,\n defaultFilters,\n isClientInstance,\n isMemberInstance,\n isMessageInstance,\n isObject,\n isSupportedVoiceChannel,\n isTextChannelInstance,\n isURL,\n} from \".\";\nimport type { Client, GuildTextBasedChannel, VoiceBasedChannel } from \"discord.js\";\nimport type {\n CustomPlaylistOptions,\n CustomPlugin,\n DisTubeEvents,\n DisTubeOptions,\n ExtractorPlugin,\n Filters,\n GuildIdResolvable,\n PlayOptions,\n Queue,\n SearchResult,\n} from \".\";\n\n// Cannot be `import` as it's not under TS root dir\n// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports\nexport const { version }: { version: string } = require(\"../package.json\");\n\n/**\n * DisTube class\n * @extends EventEmitter\n */\nexport class DisTube extends TypedEmitter<DisTubeEvents> {\n readonly handler: DisTubeHandler;\n readonly options: Options;\n readonly client: Client;\n readonly queues: QueueManager;\n readonly voices: DisTubeVoiceManager;\n readonly extractorPlugins: ExtractorPlugin[];\n readonly customPlugins: CustomPlugin[];\n readonly filters: Filters;\n /**\n * Create a new DisTube class.\n * @param {Discord.Client} client Discord.JS client\n * @param {DisTubeOptions} [otp] Custom DisTube options\n * @example\n * const Discord = require('discord.js'),\n * DisTube = require('distube'),\n * client = new Discord.Client();\n * // Create a new DisTube\n * const distube = new DisTube.default(client, { searchSongs: 10 });\n * // client.DisTube = distube // make it access easily\n * client.login(\"Your Discord Bot Token\")\n */\n constructor(client: Client, otp: DisTubeOptions = {}) {\n super();\n this.setMaxListeners(1);\n if (!isClientInstance(client)) throw new DisTubeError(\"INVALID_TYPE\", \"Discord.Client\", client, \"client\");\n /**\n * Discord.JS client\n * @type {Discord.Client}\n */\n this.client = client;\n checkIntents(client.options);\n /**\n * DisTube options\n * @type {DisTubeOptions}\n */\n this.options = new Options(otp);\n /**\n * Voice connections manager\n * @type {DisTubeVoiceManager}\n */\n this.voices = new DisTubeVoiceManager(this);\n /**\n * DisTube's Handler\n * @type {DisTubeHandler}\n * @private\n */\n this.handler = new DisTubeHandler(this);\n /**\n * Queues manager\n * @type {QueueManager}\n */\n this.queues = new QueueManager(this);\n /**\n * DisTube filters\n * @type {Filters}\n */\n this.filters = { ...defaultFilters, ...this.options.customFilters };\n // Default plugin\n if (this.options.directLink) this.options.plugins.push(new DirectLinkPlugin());\n this.options.plugins.map(p => p.init(this));\n /**\n * Extractor Plugins\n * @type {ExtractorPlugin[]}\n * @private\n */\n this.extractorPlugins = this.options.plugins.filter((p): p is ExtractorPlugin => p.type === \"extractor\");\n /**\n * Custom Plugins\n * @type {CustomPlugin[]}\n * @private\n */\n this.customPlugins = this.options.plugins.filter((p): p is CustomPlugin => p.type === \"custom\");\n }\n\n static get version() {\n return version;\n }\n\n /**\n * DisTube version\n * @type {string}\n */\n get version() {\n return version;\n }\n\n /**\n * Play / add a song or playlist from url. Search and play a song if it is not a valid url.\n *\n * @param {Discord.BaseGuildVoiceChannel} voiceChannel The channel will be joined if the bot isn't in any channels,\n * the bot will be moved to this channel if `options.move` is `true`\n * @param {string|Song|SearchResult|Playlist} song URL | Search string |\n * {@link Song} | {@link SearchResult} | {@link Playlist}\n * @param {PlayOptions} [options] Optional options\n * @throws {DisTubeError}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"play\")\n * distube.play(message.member.voice.channel, args.join(\" \"), {\n * member: message.member,\n * textChannel: message.channel,\n * message\n * });\n * });\n * @returns {Promise<void>}\n */\n async play(\n voiceChannel: VoiceBasedChannel,\n song: string | Song | SearchResult | Playlist,\n options: PlayOptions = {},\n ): Promise<void> {\n if (!isSupportedVoiceChannel(voiceChannel)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"BaseGuildVoiceChannel\", voiceChannel, \"voiceChannel\");\n }\n if (!isObject(options)) throw new DisTubeError(\"INVALID_TYPE\", \"object\", options, \"options\");\n\n const { textChannel, member, skip, message, metadata } = {\n member: voiceChannel.guild.members.me ?? undefined,\n textChannel: options?.message?.channel,\n skip: false,\n ...options,\n };\n const position = Number(options.position) || (skip ? 1 : 0);\n\n if (message && !isMessageInstance(message)) {\n throw new DisTubeError(\"INVALID_TYPE\", [\"Discord.Message\", \"a falsy value\"], message, \"options.message\");\n }\n if (textChannel && !isTextChannelInstance(textChannel)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"Discord.GuildTextBasedChannel\", textChannel, \"options.textChannel\");\n }\n if (member && !isMemberInstance(member)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"Discord.GuildMember\", member, \"options.member\");\n }\n const queue = this.getQueue(voiceChannel);\n const queuing = !!queue && !queue._taskQueue.hasResolveTask;\n if (queuing) await queue?._taskQueue.queuing(true);\n try {\n if (typeof song === \"string\") {\n for (const plugin of this.customPlugins) {\n if (await plugin.validate(song)) {\n await plugin.play(voiceChannel, song, options);\n return;\n }\n }\n }\n if (typeof song === \"string\" && !isURL(song)) {\n if (!message) {\n song = (await this.search(song, { limit: 1 }))[0];\n } else {\n const result = await this.handler.searchSong(message, song);\n if (!result) return;\n song = result;\n }\n }\n song = await this.handler.resolve(song, { member, metadata });\n if (song instanceof Playlist) {\n await this.handler.playPlaylist(voiceChannel, song, { textChannel, skip, position });\n } else {\n await this.handler.playSong(voiceChannel, song, { textChannel, skip, position });\n }\n } catch (e: any) {\n if (!(e instanceof DisTubeError)) {\n try {\n e.name = \"PlayError\";\n e.message = `${typeof song === \"string\" ? song : song.url}\\n${e.message}`;\n } catch {}\n }\n throw e;\n } finally {\n if (queuing) queue?._taskQueue.resolve();\n }\n }\n\n /**\n * Create a custom playlist\n * @returns {Promise<Playlist>}\n * @param {Array<string|Song|SearchResult>} songs Array of url, Song or SearchResult\n * @param {CustomPlaylistOptions} [options] Optional options\n * @example\n * const songs = [\"https://www.youtube.com/watch?v=xxx\", \"https://www.youtube.com/watch?v=yyy\"];\n * const playlist = await distube.createCustomPlaylist(songs, {\n * member: message.member,\n * properties: { name: \"My playlist name\", source: \"custom\" },\n * parallel: true\n * });\n * distube.play(voiceChannel, playlist, { ... });\n */\n async createCustomPlaylist(\n songs: (string | Song | SearchResult)[],\n options: CustomPlaylistOptions = {},\n ): Promise<Playlist> {\n const { member, properties, parallel, metadata } = { parallel: true, ...options };\n if (!Array.isArray(songs)) throw new DisTubeError(\"INVALID_TYPE\", \"Array\", songs, \"songs\");\n if (!songs.length) throw new DisTubeError(\"EMPTY_ARRAY\", \"songs\");\n const filteredSongs = songs.filter(\n song => song instanceof Song || isURL(song) || (typeof song !== \"string\" && song.type === SearchResultType.VIDEO),\n );\n if (!filteredSongs.length) throw new DisTubeError(\"NO_VALID_SONG\");\n if (member && !isMemberInstance(member)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"Discord.Member\", member, \"options.member\");\n }\n if (!filteredSongs.length) throw new DisTubeError(\"NO_VALID_SONG\");\n let resolvedSongs: Song[];\n if (parallel) {\n const promises = filteredSongs.map((song: string | Song | SearchResult) =>\n this.handler.resolve(song, { member, metadata }).catch(() => undefined),\n );\n resolvedSongs = (await Promise.all(promises)).filter((s: any): s is Song => !!s);\n } else {\n const resolved = [];\n for (const song of filteredSongs) {\n resolved.push(await this.handler.resolve(song, { member, metadata }).catch(() => undefined));\n }\n resolvedSongs = resolved.filter((s: any): s is Song => !!s);\n }\n return new Playlist(resolvedSongs, { member, properties, metadata });\n }\n\n search(\n string: string,\n options?: { type?: SearchResultType; limit?: number; safeSearch?: boolean; retried?: boolean },\n ): Promise<Array<SearchResult>>;\n search(\n string: string,\n options?: { type?: SearchResultType.VIDEO; limit?: number; safeSearch?: boolean; retried?: boolean },\n ): Promise<Array<SearchResultVideo>>;\n search(\n string: string,\n options: { type: SearchResultType.PLAYLIST; limit?: number; safeSearch?: boolean; retried?: boolean },\n ): Promise<Array<SearchResultPlaylist>>;\n /**\n * Search for a song. You can customize how user answers instead of send a number.\n * Then use {@link DisTube#play} to play it.\n *\n * @param {string} string The string search for\n * @param {Object} options Search options\n * @param {number} [options.limit=10] Limit the results\n * @param {SearchResultType} [options.type=SearchResultType.VIDEO] Type of results (`video` or `playlist`).\n * @param {boolean} [options.safeSearch=false] Whether or not use safe search (YouTube restricted mode)\n * @throws {Error}\n * @returns {Promise<Array<SearchResult>>} Array of results\n */\n async search(\n string: string,\n options: {\n type?: SearchResultType;\n limit?: number;\n safeSearch?: boolean;\n retried?: boolean;\n } = {},\n ): Promise<Array<SearchResult>> {\n const opts = { type: SearchResultType.VIDEO, limit: 10, safeSearch: false, ...options };\n if (typeof opts.type !== \"string\" || ![\"video\", \"playlist\"].includes(opts.type)) {\n throw new DisTubeError(\"INVALID_TYPE\", [\"video\", \"playlist\"], opts.type, \"options.type\");\n }\n if (typeof opts.limit !== \"number\") throw new DisTubeError(\"INVALID_TYPE\", \"number\", opts.limit, \"options.limit\");\n if (opts.limit < 1) throw new DisTubeError(\"NUMBER_COMPARE\", \"option.limit\", \"bigger or equal to\", 1);\n if (typeof opts.safeSearch !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", opts.safeSearch, \"options.safeSearch\");\n }\n\n try {\n const search = await ytsr(string, opts);\n const results = search.items.map(i => {\n if (i.type === \"video\") return new SearchResultVideo(i);\n return new SearchResultPlaylist(i as any);\n });\n if (results.length === 0) throw new DisTubeError(\"NO_RESULT\");\n return results;\n } catch (e) {\n if (options.retried) throw e;\n options.retried = true;\n return this.search(string, options);\n }\n }\n\n /**\n * Get the guild queue\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Queue?}\n * @throws {Error}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"queue\") {\n * const queue = distube.getQueue(message);\n * message.channel.send('Current queue:\\n' + queue.songs.map((song, id) =>\n * `**${id+1}**. [${song.name}](${song.url}) - \\`${song.formattedDuration}\\``\n * ).join(\"\\n\"));\n * }\n * });\n */\n getQueue(guild: GuildIdResolvable): Queue | undefined {\n return this.queues.get(guild);\n }\n\n /**\n * Pause the guild stream\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Queue} The guild queue\n * @throws {Error}\n */\n pause(guild: GuildIdResolvable): Queue {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.pause();\n }\n\n /**\n * Resume the guild stream\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Queue} The guild queue\n * @throws {Error}\n */\n resume(guild: GuildIdResolvable): Queue {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.resume();\n }\n\n /**\n * Stop the guild stream\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Promise<void>}\n * @throws {Error}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"stop\") {\n * distube.stop(message);\n * message.channel.send(\"Stopped the queue!\");\n * }\n * });\n */\n stop(guild: GuildIdResolvable): Promise<void> {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.stop();\n }\n\n /**\n * Set the guild stream's volume\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @param {number} percent The percentage of volume you want to set\n * @returns {Queue} The guild queue\n * @throws {Error}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"volume\")\n * distube.setVolume(message, Number(args[0]));\n * });\n */\n setVolume(guild: GuildIdResolvable, percent: number): Queue {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.setVolume(percent);\n }\n\n /**\n * Skip the playing song if there is a next song in the queue.\n * <info>If {@link Queue#autoplay} is `true` and there is no up next song,\n * DisTube will add and play a related song.</info>\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Promise<Song>} The new Song will be played\n * @throws {Error}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"skip\")\n * distube.skip(message);\n * });\n */\n skip(guild: GuildIdResolvable): Promise<Song> {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.skip();\n }\n\n /**\n * Play the previous song\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Promise<Song>} The new Song will be played\n * @throws {Error}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"previous\")\n * distube.previous(message);\n * });\n */\n previous(guild: GuildIdResolvable): Promise<Song> {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.previous();\n }\n\n /**\n * Shuffle the guild queue songs\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Promise<Queue>} The guild queue\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"shuffle\")\n * distube.shuffle(message);\n * });\n */\n shuffle(guild: GuildIdResolvable): Promise<Queue> {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.shuffle();\n }\n\n /**\n * Jump to the song number in the queue.\n * The next one is 1, 2,...\n * The previous one is -1, -2,...\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @param {number} num The song number to play\n * @returns {Promise<Song>} The new Song will be played\n * @throws {Error} if `num` is invalid number (0 < num < {@link Queue#songs}.length)\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"jump\")\n * distube.jump(message, parseInt(args[0]))\n * .catch(err => message.channel.send(\"Invalid song number.\"));\n * });\n */\n jump(guild: GuildIdResolvable, num: number): Promise<Song> {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.jump(num);\n }\n\n /**\n * Set the repeat mode of the guild queue.\\\n * Toggle mode `(Disabled -> Song -> Queue -> Disabled ->...)` if `mode` is `undefined`\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @param {RepeatMode?} [mode] The repeat modes (toggle if `undefined`)\n * @returns {RepeatMode} The new repeat mode\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"repeat\") {\n * let mode = distube.setRepeatMode(message, parseInt(args[0]));\n * mode = mode ? mode == 2 ? \"Repeat queue\" : \"Repeat song\" : \"Off\";\n * message.channel.send(\"Set repeat mode to `\" + mode + \"`\");\n * }\n * });\n * @example\n * const { RepeatMode } = require(\"distube\");\n * let mode;\n * switch(distube.setRepeatMode(message, parseInt(args[0]))) {\n * case RepeatMode.DISABLED:\n * mode = \"Off\";\n * break;\n * case RepeatMode.SONG:\n * mode = \"Repeat a song\";\n * break;\n * case RepeatMode.QUEUE:\n * mode = \"Repeat all queue\";\n * break;\n * }\n * message.channel.send(\"Set repeat mode to `\" + mode + \"`\");\n */\n setRepeatMode(guild: GuildIdResolvable, mode?: number): number {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.setRepeatMode(mode);\n }\n\n /**\n * Toggle autoplay mode\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {boolean} Autoplay mode state\n * @throws {Error}\n * @example\n * client.on('message', (message) => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command == \"autoplay\") {\n * const mode = distube.toggleAutoplay(message);\n * message.channel.send(\"Set autoplay mode to `\" + (mode ? \"On\" : \"Off\") + \"`\");\n * }\n * });\n */\n toggleAutoplay(guild: GuildIdResolvable): boolean {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n q.autoplay = !q.autoplay;\n return q.autoplay;\n }\n\n /**\n * Add related song to the queue\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @returns {Promise<Song>} The guild queue\n */\n addRelatedSong(guild: GuildIdResolvable): Promise<Song> {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.addRelatedSong();\n }\n\n /**\n * Set the playing time to another position\n * @param {GuildIdResolvable} guild The type can be resolved to give a {@link Queue}\n * @param {number} time Time in seconds\n * @returns {Queue} Seeked queue\n * @example\n * client.on('message', message => {\n * if (!message.content.startsWith(config.prefix)) return;\n * const args = message.content.slice(config.prefix.length).trim().split(/ +/g);\n * const command = args.shift();\n * if (command = 'seek')\n * distube.seek(message, Number(args[0]));\n * });\n */\n seek(guild: GuildIdResolvable, time: number): Queue {\n const q = this.getQueue(guild);\n if (!q) throw new DisTubeError(\"NO_QUEUE\");\n return q.seek(time);\n }\n\n /**\n * Emit error event\n * @param {Error} error error\n * @param {Discord.BaseGuildTextChannel} [channel] Text channel where the error is encountered.\n * @private\n */\n emitError(error: Error, channel?: GuildTextBasedChannel): void {\n if (this.listeners(\"error\").length) {\n this.emit(\"error\", channel, error);\n } else {\n /* eslint-disable no-console */\n console.error(error);\n console.warn(\"Unhandled 'error' event.\");\n console.warn(\n \"See: https://distube.js.org/#/docs/DisTube/stable/class/DisTube?scrollTo=e-error and https://nodejs.org/api/events.html#events_error_events\",\n );\n /* eslint-enable no-console */\n }\n }\n}\n\nexport default DisTube;\n\n/**\n * Emitted after DisTube add a new playlist to the playing {@link Queue}.\n *\n * @event DisTube#addList\n * @param {Queue} queue The guild queue\n * @param {Playlist} playlist Playlist info\n * @example\n * distube.on(\"addList\", (queue, playlist) => queue.textChannel.send(\n * `Added \\`${playlist.name}\\` playlist (${playlist.songs.length} songs) to the queue!`\n * ));\n */\n\n/**\n * Emitted after DisTube add a new song to the playing {@link Queue}.\n *\n * @event DisTube#addSong\n * @param {Queue} queue The guild queue\n * @param {Song} song Added song\n * @example\n * distube.on(\"addSong\", (queue, song) => queue.textChannel.send(\n * `Added ${song.name} - \\`${song.formattedDuration}\\` to the queue by ${song.user}.`\n * ));\n */\n\n/**\n * Emitted when there is no user in the voice channel,\n * {@link DisTubeOptions}.leaveOnEmpty is `true` and there is a playing queue.\n *\n * If there is no playing queue (stopped and {@link DisTubeOptions}.leaveOnStop is `false`),\n * it will leave the channel without emitting this event.\n * @event DisTube#empty\n * @param {Queue} queue The guild queue\n * @example\n * distube.on(\"empty\", queue => queue.textChannel.send(\"Channel is empty. Leaving the channel\"))\n */\n\n/**\n * Emitted when DisTube encounters an error while playing songs.\n *\n * @event DisTube#error\n * @param {Discord.BaseGuildTextChannel?} channel Text channel where the error is encountered.\n * @param {Error} error The error encountered\n * @example\n * distube.on('error', (channel, e) => {\n * if (channel) channel.send(`An error encountered: ${e}`)\n * else console.error(e)\n * })\n */\n\n/**\n * Emitted when there is no more song in the queue and {@link Queue#autoplay} is `false`.\n * DisTube will leave voice channel if {@link DisTubeOptions}.leaveOnFinish is `true`.\n *\n * @event DisTube#finish\n * @param {Queue} queue The guild queue\n * @example\n * distube.on(\"finish\", queue => queue.textChannel.send(\"No more song in queue\"));\n */\n\n/**\n * Emitted when DisTube initialize a queue to change queue default properties.\n *\n * @event DisTube#initQueue\n * @param {Queue} queue The guild queue\n * @example\n * distube.on(\"initQueue\", queue => {\n * queue.autoplay = false;\n * queue.volume = 100;\n * });\n */\n\n/**\n * Emitted when {@link Queue#autoplay} is `true`, {@link Queue#songs} is empty,\n * and DisTube cannot find related songs to play.\n *\n * @event DisTube#noRelated\n * @param {Queue} queue The guild queue\n * @example\n * distube.on(\"noRelated\", queue => queue.textChannel.send(\"Can't find related video to play.\"));\n */\n\n/**\n * Emitted when DisTube play a song.\n *\n * If {@link DisTubeOptions}.emitNewSongOnly is `true`,\n * this event is not emitted when looping a song or next song is the previous one.\n *\n * @event DisTube#playSong\n * @param {Queue} queue The guild queue\n * @param {Song} song Playing song\n * @example\n * distube.on(\"playSong\", (queue, song) => queue.textChannel.send(\n * `Playing \\`${song.name}\\` - \\`${song.formattedDuration}\\`\\nRequested by: ${song.user}`\n * ));\n */\n\n/**\n * Emitted when DisTube cannot find any results for the query.\n *\n * @event DisTube#searchNoResult\n * @param {Discord.Message} message The user message called play method\n * @param {string} query The search query\n * @example\n * distube.on(\"searchNoResult\", (message, query) => message.channel.send(`No result found for ${query}!`));\n */\n\n/**\n * Emitted when {@link DisTubeOptions|DisTubeOptions.searchSongs} bigger than 0,\n * and song param of {@link DisTube#play} is invalid url.\n * DisTube will wait for user's next message to choose a song manually.\n * <info>{@link https://support.google.com/youtube/answer/7354993|Safe search} is enabled\n * if {@link DisTubeOptions}.nsfw is disabled and the message's channel is not a nsfw channel.</info>\n *\n * @event DisTube#searchResult\n * @param {Discord.Message} message The user message called play method\n * @param {Array<SearchResult>} results Searched results\n * @param {string} query The search query\n * @example\n * // DisTubeOptions.searchSongs > 0\n * distube.on(\"searchResult\", (message, results) => {\n * message.channel.send(`**Choose an option from below**\\n${\n * results.map((song, i) => `**${i + 1}**. ${song.name} - \\`${song.formattedDuration}\\``).join(\"\\n\")\n * }\\n*Enter anything else or wait 60 seconds to cancel*`);\n * });\n */\n\n/**\n * Emitted when {@link DisTubeOptions|DisTubeOptions.searchSongs} bigger than 0,\n * and the search canceled due to {@link DisTubeOptions|DisTubeOptions.searchTimeout}.\n *\n * @event DisTube#searchCancel\n * @param {Discord.Message} message The user message called play method\n * @param {string} query The search query\n * @example\n * // DisTubeOptions.searchSongs > 0\n * distube.on(\"searchCancel\", (message) => message.channel.send(`Searching canceled`));\n */\n\n/**\n * Emitted when {@link DisTubeOptions|DisTubeOptions.searchSongs} bigger than 0,\n * and the search canceled due to user's next message is not a number or out of results range.\n *\n * @event DisTube#searchInvalidAnswer\n * @param {Discord.Message} message The user message called play method\n * @param {Discord.Message} answer The answered message of user\n * @param {string} query The search query\n * @example\n * // DisTubeOptions.searchSongs > 0\n * distube.on(\"searchInvalidAnswer\", (message) => message.channel.send(`You answered an invalid number!`));\n */\n\n/**\n * Emitted when {@link DisTubeOptions|DisTubeOptions.searchSongs} bigger than 0,\n * and after the user chose a search result to play.\n *\n * @event DisTube#searchDone\n * @param {Discord.Message} message The user message called play method\n * @param {Discord.Message} answer The answered message of user\n * @param {string} query The search query\n */\n\n/**\n * Emitted when the bot is disconnected to a voice channel.\n *\n * @event DisTube#disconnect\n * @param {Queue} queue The guild queue\n */\n\n/**\n * Emitted when a {@link Queue} is deleted with any reasons.\n *\n * @event DisTube#deleteQueue\n * @param {Queue} queue The guild queue\n */\n\n/**\n * Emitted when DisTube finished a song.\n *\n * @event DisTube#finishSong\n * @param {Queue} queue The guild queue\n * @param {Song} song Finished song\n */\n"],"mappings":"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","names":[]}