@kattowo/distube 6.2.0 → 6.2.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.
- package/dist/index.d.mts +68 -1
- package/dist/index.d.ts +68 -1
- package/dist/index.js +61 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +61 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/constant.ts","../src/core/DisTubeBase.ts","../src/core/DisTubeHandler.ts","../src/struct/DisTubeError.ts","../src/util.ts","../src/core/DisTubeVoice.ts","../src/core/manager/BaseManager.ts","../src/core/manager/FilterManager.ts","../src/type.ts","../src/struct/TaskQueue.ts","../src/struct/Queue.ts","../src/struct/Playlist.ts","../src/struct/Song.ts","../src/core/DisTubeOptions.ts","../src/core/DisTubeStream.ts","../src/core/manager/DisTubeVoiceManager.ts","../src/core/manager/GuildIdManager.ts","../src/core/manager/QueueManager.ts","../src/core/StreamServer.ts","../src/DisTube.ts","../src/struct/SearchResult.ts","../src/struct/Plugin.ts","../src/struct/ExtractorPlugin.ts","../src/struct/PluginError.ts","../src/struct/InfoExtractorPlugin.ts","../src/struct/PlayableExtractorPlugin.ts"],"sourcesContent":["export * from \"./constant\";\nexport * from \"./core/DisTubeBase\";\nexport * from \"./core/DisTubeHandler\";\nexport * from \"./core/DisTubeOptions\";\nexport * from \"./core/DisTubeStream\";\nexport * from \"./core/DisTubeVoice\";\nexport * from \"./core/manager/BaseManager\";\nexport * from \"./core/manager/DisTubeVoiceManager\";\nexport * from \"./core/manager/FilterManager\";\nexport * from \"./core/manager/GuildIdManager\";\nexport * from \"./core/manager/QueueManager\";\nexport * from \"./core/StreamServer\";\nexport { DisTube, DisTube as default } from \"./DisTube\";\nexport * from \"./struct/DisTubeError\";\nexport * from \"./struct/ExtractorPlugin\";\nexport * from \"./struct/InfoExtractorPlugin\";\nexport * from \"./struct/PlayableExtractorPlugin\";\nexport * from \"./struct/Playlist\";\nexport * from \"./struct/Plugin\";\nexport * from \"./struct/PluginError\";\nexport * from \"./struct/Queue\";\nexport * from \"./struct/SearchResult\";\nexport * from \"./struct/Song\";\nexport * from \"./struct/TaskQueue\";\nexport * from \"./type\";\nexport * from \"./util\";\n","import type { DisTubeOptions, Filters } from \"./type\";\n\n/**\n * The version of DisTube.\n *\n * The placeholder is replaced by the real version at build time.\n */\nexport const version: string = \"6.2.0\";\n\n/**\n * The sample rate of the audio, in Hz.\n */\nexport const AUDIO_SAMPLE_RATE = 48000;\n/**\n * The number of channels of the audio.\n */\nexport const AUDIO_CHANNELS = 2;\n\n/**\n * Default volume percentage (0-100)\n */\nexport const DEFAULT_VOLUME = 50;\n\n/**\n * The timeout to join a voice channel, in milliseconds.\n */\nexport const JOIN_TIMEOUT_MS = 30_000;\n/**\n * The delay between two reconnection attempts, in milliseconds.\n */\nexport const RECONNECT_TIMEOUT_MS = 5_000;\n/**\n * The maximum number of reconnection attempts before giving up.\n */\nexport const RECONNECT_MAX_ATTEMPTS = 5;\n\n/**\n * Default time (in milliseconds) a track may stay in the \"buffering\" state\n * before it is considered stuck and gets skipped.\n */\nexport const STUCK_THRESHOLD_MS = 10_000;\n\n/**\n * The HTTP status codes that are followed as a redirection.\n */\nexport const HTTP_REDIRECT_CODES = new Set([301, 302, 303, 307, 308]);\n/**\n * The maximum number of redirections that are followed before giving up.\n */\nexport const MAX_REDIRECT_DEPTH = 5;\n\n/**\n * Default DisTube audio filters.\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\n/**\n * Default number of seconds remaining in the currently playing song before preloading starts.\n */\nexport const DEFAULT_PRELOAD_THRESHOLD_SECS = 15;\n\n/**\n * Default crossfade duration in seconds for a {@link Queue} (0 disables the crossfade).\n */\nexport const DEFAULT_CROSSFADE_DURATION_SECS = 0;\n/**\n * Maximum crossfade duration in seconds a {@link Queue} may request.\n */\nexport const MAX_CROSSFADE_DURATION_SECS = 12;\n/**\n * Default FFmpeg `acrossfade` fade curve of the crossfade transition.\n *\n * `qsin` is an equal-power curve: the two songs mix without the -3dB dip of a\n * linear (triangular) curve.\n */\nexport const DEFAULT_CROSSFADE_CURVE = \"qsin\";\n/**\n * Default number of seconds before the fade window when the merged crossfade\n * transition stream is spawned to warm up its buffers.\n */\nexport const DEFAULT_CROSSFADE_WARMUP_SECS = 5;\n/**\n * How far (in seconds) the playback position may drift from the expected\n * crossfade boundary before the transition is aborted and the regular\n * song-switch takes over.\n */\nexport const CROSSFADE_DRIFT_TOLERANCE_SECS = 0.75;\n\n/**\n * The default options of a {@link DisTube} instance.\n *\n * They are overridden by the options given to the constructor of\n * {@link DisTube}.\n */\nexport const defaultOptions = {\n plugins: [],\n emitNewSongOnly: false,\n savePreviousSongs: true,\n nsfw: false,\n emitAddSongWhenCreatingQueue: true,\n emitAddListWhenCreatingQueue: true,\n joinNewVoiceChannel: true,\n unhandledError: \"log\",\n stuckThreshold: STUCK_THRESHOLD_MS,\n preload: false,\n crossfade: {\n duration: DEFAULT_CROSSFADE_DURATION_SECS,\n curve: DEFAULT_CROSSFADE_CURVE,\n warmup: DEFAULT_CROSSFADE_WARMUP_SECS,\n },\n} satisfies DisTubeOptions;\n","import type { Client } from \"discord.js\";\nimport type { DisTube } from \"../DisTube\";\nimport type { Queue } from \"../struct/Queue\";\nimport type { Song } from \"../struct/Song\";\nimport type { DisTubeEvents, DisTubePlugin } from \"../type\";\nimport type { DisTubeHandler } from \"./DisTubeHandler\";\nimport type { Options } from \"./DisTubeOptions\";\nimport type { DisTubeVoiceManager } from \"./manager/DisTubeVoiceManager\";\nimport type { QueueManager } from \"./manager/QueueManager\";\n\n/**\n * The base class of every DisTube internal that needs a reference to the\n * {@link DisTube} instance.\n */\nexport abstract class DisTubeBase {\n /**\n * The DisTube instance this object belongs to.\n */\n distube: DisTube;\n /**\n * Create a new base object.\n * @param distube - The DisTube instance\n */\n constructor(distube: DisTube) {\n this.distube = distube;\n }\n /**\n * Emit the {@link DisTube} of this base\n * @param eventName - Event name\n * @param args - arguments\n * @returns `true` when the event had listeners, `false` otherwise\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\n * @param queue - The queue encountered the error\n * @param song - The playing song when encountered the error\n * @returns Nothing\n */\n emitError(error: Error, queue: Queue, song?: Song) {\n this.distube.emitError(error, queue, song);\n }\n /**\n * Emit debug event\n * @param message - debug message\n * @returns Nothing\n */\n debug(message: string) {\n this.distube.debug(message);\n }\n /**\n * The queue manager\n */\n get queues(): QueueManager {\n return this.distube.queues;\n }\n /**\n * The voice manager\n */\n get voices(): DisTubeVoiceManager {\n return this.distube.voices;\n }\n /**\n * Discord.js client\n */\n get client(): Client {\n return this.distube.client;\n }\n /**\n * DisTube options\n */\n get options(): Options {\n return this.distube.options;\n }\n /**\n * DisTube handler\n */\n get handler(): DisTubeHandler {\n return this.distube.handler;\n }\n /**\n * DisTube plugins\n */\n get plugins(): DisTubePlugin[] {\n return this.distube.plugins;\n }\n}\n","import { request } from \"undici\";\nimport { HTTP_REDIRECT_CODES, MAX_REDIRECT_DEPTH } from \"../constant\";\nimport { DisTubeError } from \"../struct/DisTubeError\";\nimport type { ExtractorPlugin } from \"../struct/ExtractorPlugin\";\nimport { Playlist } from \"../struct/Playlist\";\nimport { Song } from \"../struct/Song\";\nimport type { DisTubePlugin, ResolveOptions } from \"../type\";\nimport { PluginType } from \"../type\";\nimport { isURL } from \"../util\";\nimport { DisTubeBase } from \"./DisTubeBase\";\n\n/**\n * DisTube's Handler\n */\nexport class DisTubeHandler extends DisTubeBase {\n /**\n * Resolve a {@link Song} to a {@link Song}.\n * @param song - The song to resolve\n * @param options - Optional options\n * @returns The resolved song\n */\n resolve<T = unknown>(song: Song<T>, options?: Omit<ResolveOptions, \"metadata\">): Promise<Song<T>>;\n /**\n * Resolve a {@link Playlist} to a {@link Playlist}.\n * @param song - The playlist to resolve\n * @param options - Optional options\n * @returns The resolved playlist\n */\n resolve<T = unknown>(song: Playlist<T>, options?: Omit<ResolveOptions, \"metadata\">): Promise<Playlist<T>>;\n /**\n * Resolve a url or a search query to a {@link Song} or a {@link Playlist}.\n * @param song - The url or the search query to resolve\n * @param options - Optional options\n * @returns The resolved song or playlist\n */\n resolve<T = unknown>(song: string, options?: ResolveOptions<T>): Promise<Song<T> | Playlist<T>>;\n /**\n * Resolve a {@link Song} to a {@link Song}.\n * @param song - The song to resolve\n * @param options - Optional options\n * @returns The resolved song\n */\n resolve<T = unknown>(song: Song, options: ResolveOptions<T>): Promise<Song<T>>;\n /**\n * Resolve a {@link Playlist} to a {@link Playlist}.\n * @param song - The playlist to resolve\n * @param options - Optional options\n * @returns The resolved playlist\n */\n resolve<T = unknown>(song: Playlist, options: ResolveOptions<T>): Promise<Playlist<T>>;\n /**\n * Resolve a url or a supported object to a {@link Song} or {@link Playlist}\n * @throws {@link DisTubeError}\n * @param song - Resolvable input\n * @param options - Optional options\n * @returns Resolved\n * @example\n * ```ts\n * const song = await distube.handler.resolve(\"Never gonna give you up\");\n * ```\n */\n resolve(song: string | Song | Playlist, options?: ResolveOptions): Promise<Song | Playlist>;\n /**\n * Resolve a url or a supported object to a {@link Song} or {@link Playlist}\n * @throws {@link DisTubeError}\n * @param input - Resolvable input\n * @param options - Optional options\n * @returns Resolved\n */\n async resolve(input: string | Song | Playlist, options: ResolveOptions = {}): Promise<Song | Playlist> {\n if (input instanceof Song || input instanceof Playlist) {\n if (\"metadata\" in options) input.metadata = options.metadata;\n if (\"member\" in options) input.member = options.member;\n return input;\n }\n if (typeof input === \"string\") {\n if (isURL(input)) {\n const plugin =\n (await this._getPluginFromURL(input)) ||\n (await this._getPluginFromURL((input = await this.followRedirectLink(input))));\n if (!plugin) throw new DisTubeError(\"NOT_SUPPORTED_URL\");\n this.debug(`[${plugin.constructor.name}] Resolving from url: ${input}`);\n return plugin.resolve(input, options);\n }\n try {\n const song = await this.#searchSong(input, options);\n if (song) return song;\n } catch (e: unknown) {\n // Keep the original error as the cause so that it is not lost.\n const error = new DisTubeError(\"NO_RESULT\", input);\n error.cause = e;\n throw error;\n }\n }\n throw new DisTubeError(\"CANNOT_RESOLVE_SONG\", input);\n }\n\n /**\n * Find the plugin that supports the given url.\n * @param url - The url to check\n * @returns The plugin, or `null` when there is none\n */\n async _getPluginFromURL(url: string): Promise<DisTubePlugin | null> {\n for (const plugin of this.plugins) if (await plugin.validate(url)) return plugin;\n return null;\n }\n\n /**\n * Find the plugin that can handle the given song.\n * @param song - The song\n * @returns The plugin, or `null` when there is none\n */\n _getPluginFromSong(song: Song): Promise<DisTubePlugin | null>;\n /**\n * Find the plugin of the given type that can handle the given song.\n * @param song - The song\n * @param types - The types of the plugin to look for\n * @param validate - Whether the url of the song has to be validated\n * @returns The plugin, or `null` when there is none\n */\n _getPluginFromSong<T extends PluginType>(\n song: Song,\n types: T[],\n validate?: boolean,\n ): Promise<(DisTubePlugin & { type: T }) | null>;\n async _getPluginFromSong<T extends PluginType>(\n song: Song,\n types?: T[],\n validate = true,\n ): Promise<(DisTubePlugin & { type: T }) | null> {\n if (!types || types.includes(<T>song.plugin?.type)) return song.plugin as DisTubePlugin & { type: T };\n if (!song.url) return null;\n for (const plugin of this.plugins) {\n if ((!types || types.includes(<T>plugin?.type)) && (!validate || (await plugin.validate(song.url)))) {\n return plugin as DisTubePlugin & { type: T };\n }\n }\n return null;\n }\n\n async #searchSong(query: string, options: ResolveOptions = {}, getStreamURL = false): Promise<Song | null> {\n const source = options.source?.toLowerCase();\n const plugins = this.plugins.filter(\n (plugin): plugin is ExtractorPlugin =>\n plugin.type === PluginType.EXTRACTOR && (!source || plugin.identifiers.includes(source)),\n );\n if (!plugins.length) throw new DisTubeError(\"NO_EXTRACTOR_PLUGIN\");\n for (const plugin of plugins) {\n this.debug(`[${plugin.constructor.name}] Searching for song: ${query}`);\n const result = await plugin.searchSong(query, options);\n if (result) {\n if (getStreamURL && result.stream.playFromSource) result.stream.url = await plugin.getStreamURL(result);\n return result;\n }\n }\n return null;\n }\n\n /**\n * Get {@link Song}'s stream info and attach it to the song.\n * @param song - A Song\n * @returns A promise that resolves when the stream info is attached\n * @throws {@link DisTubeError} When no plugin supports the song, or when its\n * stream URL cannot be found\n */\n async attachStreamInfo(song: Song) {\n if (song.stream.playFromSource) {\n if (song.stream.url) return;\n this.debug(`[DisTubeHandler] Getting stream info: ${song}`);\n const plugin = await this._getPluginFromSong(song, [PluginType.EXTRACTOR, PluginType.PLAYABLE_EXTRACTOR]);\n if (!plugin) throw new DisTubeError(\"NOT_SUPPORTED_SONG\", song.toString());\n this.debug(`[${plugin.constructor.name}] Getting stream URL: ${song}`);\n song.stream.url = await plugin.getStreamURL(song);\n if (!song.stream.url) throw new DisTubeError(\"CANNOT_GET_STREAM_URL\", song.toString());\n } else {\n if (song.stream.song?.stream?.playFromSource && song.stream.song.stream.url) return;\n this.debug(`[DisTubeHandler] Getting stream info: ${song}`);\n // The song comes from a plugin that cannot play it: look for a playable\n // version of it with the other plugins.\n const source = song.plugin;\n const query = source\n ? await source.createSearchQuery(song)\n : `${song.name ?? \"\"} ${song.uploader?.name ?? \"\"}`.trim();\n if (!query) throw new DisTubeError(\"CANNOT_GET_SEARCH_QUERY\", song.toString());\n const altSong = await this.#findPlayableSong(query, song, source);\n song.stream.song = altSong;\n }\n }\n\n /**\n * Look for a playable version of a song with the plugins that can search.\n *\n * Every searchable plugin is tried, in the order they were registered, until\n * one of them has a result.\n * @param query - The search query\n * @param song - The song that cannot be played\n * @param source - The plugin that resolved the song\n * @returns The playable song\n */\n async #findPlayableSong(query: string, song: Song, source: DisTubePlugin | null): Promise<Song> {\n const options: ResolveOptions = { metadata: song.metadata, member: song.member };\n for (const plugin of this.plugins) {\n if (plugin === source) continue;\n // A plugin that cannot play its own songs cannot provide a playable\n // version of them either.\n if (plugin.playable === false) continue;\n const result = await plugin.searchSong(query, options);\n if (!result) continue;\n // The result has to be playable, otherwise the playback would fail later\n // with a confusing error.\n if (!result.stream.playFromSource) continue;\n this.debug(`[${plugin.constructor.name}] Found a playable version of \"${query}\"`);\n result.stream.url = await plugin.getStreamURL(result);\n return result;\n }\n throw new DisTubeError(\"NO_RESULT\", query);\n }\n\n /**\n * Follow the redirections of an url.\n * @param url - The url to follow\n * @param maxRedirect - The maximum number of redirections to follow\n * @returns The final url\n */\n async followRedirectLink(url: string, maxRedirect = MAX_REDIRECT_DEPTH): Promise<string> {\n if (maxRedirect === 0) return url;\n\n const res = await request(url, {\n method: \"HEAD\",\n headers: {\n \"user-agent\":\n \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) \" +\n \"Chrome/129.0.0.0 Safari/537.3\",\n },\n });\n\n if (HTTP_REDIRECT_CODES.has(res.statusCode ?? 200)) {\n let location = res.headers.location;\n if (typeof location !== \"string\") location = location?.[0] ?? url;\n return this.followRedirectLink(location, --maxRedirect);\n }\n\n return url;\n }\n}\n","import { inspect } from \"node:util\";\n\n/**\n * The table of the error messages of DisTube.\n *\n * Every entry is the message of one error code. A message can be a template\n * that receives the arguments of the error.\n */\nconst ERROR_MESSAGES = {\n /**\n * A value does not have the expected type.\n *\n * It is raised when an argument of a public method is not of the type that\n * the method expects, e.g. when a voice channel is not a voice channel.\n */\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 /**\n * A number is not in the expected range.\n *\n * It is raised when a numeric argument is out of the range that the method\n * accepts, e.g. a negative volume.\n */\n NUMBER_COMPARE: (name: string, expected: string, value: number) => `'${name}' must be ${expected} ${value}`,\n /**\n * An array is empty.\n *\n * It is raised when an argument that must hold at least one element is\n * empty, e.g. the songs of a custom playlist.\n */\n EMPTY_ARRAY: (name: string) => `'${name}' is an empty array`,\n /**\n * An array does not have any valid element.\n *\n * It is raised when every element of an array was filtered out, e.g. when\n * all the songs of an array are invalid.\n */\n EMPTY_FILTERED_ARRAY: (name: string, type: string) => `There is no valid '${type}' in the '${name}' array`,\n /**\n * A string is empty.\n *\n * It is raised when a string argument that must not be empty is empty.\n */\n EMPTY_STRING: (name: string) => `'${name}' string must not be empty`,\n /**\n * An object has a key that is not allowed.\n *\n * It is raised when an options object has a key that DisTube does not know,\n * e.g. `{ emitNewSong: true }` instead of `{ emitNewSongOnly: true }`.\n */\n INVALID_KEY: (obj: string, key: string) => `'${key}' does not need to be provided in ${obj}`,\n /**\n * A required key is missing.\n *\n * It is raised when an object does not have a key that DisTube needs.\n */\n MISSING_KEY: (obj: string, key: string) => `'${key}' needs to be provided in ${obj}`,\n /**\n * Several required keys are missing.\n *\n * It is raised when an object does not have the keys that DisTube needs.\n */\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 /**\n * The Discord.js client does not have the required intents.\n *\n * It is raised when the `GuildVoiceStates` intent is missing: DisTube\n * cannot work without it.\n */\n MISSING_INTENTS: (i: string) => `${i} intent must be provided for the Client`,\n /**\n * A DisTube option that is needed is disabled.\n *\n * It is raised when a feature cannot work because one of its options is\n * disabled, e.g. {@link Queue#previous} when\n * {@link DisTubeOptions.savePreviousSongs} is `false`.\n */\n DISABLED_OPTION: (o: string) => `DisTubeOptions.${o} is disabled`,\n /**\n * A DisTube option that must be disabled is enabled.\n *\n * It is raised when a feature cannot work because one of its options is\n * enabled.\n */\n ENABLED_OPTION: (o: string) => `DisTubeOptions.${o} is enabled`,\n\n /**\n * The user is not in any voice channel.\n *\n * It is raised when a command needs the voice channel of the user, but the\n * user is not connected to any voice channel.\n */\n NOT_IN_VOICE: \"User is not in any voice channel\",\n /**\n * The voice channel is full.\n *\n * It is raised when the bot cannot join a voice channel because it is\n * full.\n */\n VOICE_FULL: \"The voice channel is full\",\n /**\n * The guild already has a voice connection that DisTube does not manage.\n *\n * It is raised when DisTube cannot create a voice connection because\n * another one already exists in the guild.\n */\n VOICE_ALREADY_CREATED: \"This guild already has a voice connection which is not managed by DisTube\",\n /**\n * The voice connection could not be established in time.\n *\n * It is raised when the connection did not become ready before\n * {@link JOIN_TIMEOUT_MS}.\n */\n VOICE_CONNECT_FAILED: (s: number) => `Cannot connect to the voice channel after ${s} seconds`,\n /**\n * The bot does not have the permission to join the voice channel.\n *\n * It is raised when the bot cannot join a voice channel because of a missing\n * permission.\n */\n VOICE_MISSING_PERMS: \"I do not have permission to join this voice channel\",\n /**\n * The voice connection could not be restored.\n *\n * It is raised when every reconnection attempt of\n * {@link RECONNECT_MAX_ATTEMPTS} failed.\n */\n VOICE_RECONNECT_FAILED: \"Cannot reconnect to the voice channel\",\n /**\n * The voice channel belongs to another guild.\n *\n * It is raised when a voice connection is asked to join a voice channel of\n * another guild.\n */\n VOICE_DIFFERENT_GUILD: \"Cannot join a voice channel in a different guild\",\n /**\n * The voice channel belongs to another client.\n *\n * It is raised when a voice connection is asked to join a voice channel\n * that was created by another Discord.js client.\n */\n VOICE_DIFFERENT_CLIENT: \"Cannot join a voice channel created by a different client\",\n\n /**\n * The FFmpeg process exited with an unexpected code.\n *\n * It is raised when the FFmpeg process that decodes the audio exits with a\n * code that is neither `0` nor `255`.\n */\n FFMPEG_EXITED: (code: number) => `ffmpeg exited with code ${code}`,\n /**\n * FFmpeg is not installed at the given path.\n *\n * It is raised when the FFmpeg executable cannot be spawned, e.g. when\n * {@link DisTubeOptions.ffmpeg} points to a path that does not exist.\n */\n FFMPEG_NOT_INSTALLED: (path: string) => `ffmpeg is not installed at '${path}' path`,\n /**\n * No encryption library is available.\n *\n * It is raised when Discord cannot decrypt the audio: neither the\n * `aes-256-gcm` cipher of Node.js nor one of the supported third-party\n * encryption libraries is available.\n */\n ENCRYPTION_LIBRARIES_MISSING:\n \"Cannot play audio as no valid encryption package is installed and your node doesn't support aes-256-gcm.\\n\" +\n \"Please install @noble/ciphers, @stablelib/xchacha20poly1305, sodium-native or libsodium-wrappers.\",\n\n /**\n * The guild does not have a playing queue.\n *\n * It is raised when a queue operation is used in a guild that has no\n * {@link Queue}.\n */\n NO_QUEUE: \"There is no playing queue in this guild\",\n /**\n * The guild already has a queue.\n *\n * It is raised when a {@link Queue} is created for a guild that already\n * has one.\n */\n QUEUE_EXIST: \"This guild has a Queue already\",\n /**\n * The queue has been stopped already.\n *\n * It is raised when an operation needs a running queue, but the queue was\n * stopped.\n */\n QUEUE_STOPPED: \"The queue has been stopped already\",\n /**\n * The queue is already paused.\n *\n * It is raised when {@link Queue#pause} is used on a paused queue.\n */\n PAUSED: \"The queue has been paused already\",\n /**\n * The queue is already playing.\n *\n * It is raised when {@link Queue#resume} is used on a queue that is not\n * paused.\n */\n RESUMED: \"The queue has been playing already\",\n /**\n * The queue does not have any previous song.\n *\n * It is raised when {@link Queue#previous} is used on a queue without any\n * history.\n */\n NO_PREVIOUS: \"There is no previous song in this queue\",\n /**\n * The queue does not have any up next song.\n *\n * It is raised when a jump goes past the end of the queue while the\n * autoplay mode is disabled.\n */\n NO_UP_NEXT: \"There is no up next song\",\n /**\n * The queue does not have any song at the given position.\n *\n * It is raised when {@link Queue#jump} is used with a position that is out\n * of the bounds of the queue.\n */\n NO_SONG_POSITION: \"Does not have any song at this position\",\n /**\n * The queue does not have any playing song.\n *\n * It is raised when a related song is requested but the queue is empty.\n */\n NO_PLAYING_SONG: \"There is no playing song in the queue\",\n /**\n * The track is stuck and does not produce any audio.\n *\n * It is raised when a track stays in the \"buffering\" state for longer than\n * {@link DisTubeOptions.stuckThreshold} milliseconds. The queue skips it.\n */\n TRACK_STUCK: \"The track is stuck and not producing any audio\",\n /**\n * There is no extractor plugin.\n *\n * It is raised when a search is requested but no {@link ExtractorPlugin} is\n * registered in {@link DisTubeOptions.plugins}.\n */\n NO_EXTRACTOR_PLUGIN: \"There is no extractor plugin in the DisTubeOptions.plugins, please add one for searching songs\",\n /**\n * No related song could be found.\n *\n * It is raised when the autoplay mode is enabled and no plugin could find\n * a related song for the current one.\n */\n NO_RELATED: \"Cannot find any related songs\",\n /**\n * The related song cannot be played.\n *\n * It is raised when the related song of the autoplay mode cannot be\n * played.\n */\n CANNOT_PLAY_RELATED: \"Cannot play the related song\",\n /**\n * The video is unavailable.\n *\n * It is raised when the source of the song does not have the video anymore,\n * e.g. when it was removed or when it is private.\n */\n UNAVAILABLE_VIDEO: \"This video is unavailable\",\n /**\n * No playable format was found.\n *\n * It is raised when the source of the song does not have any format that\n * FFmpeg can play.\n */\n UNPLAYABLE_FORMATS: \"No playable format found\",\n /**\n * The content is age-restricted and cannot be played in this channel.\n *\n * It is raised when an age-restricted song is played in a non-NSFW channel\n * while {@link DisTubeOptions.nsfw} is `false`.\n */\n NON_NSFW: \"Cannot play age-restricted content in non-NSFW channel\",\n /**\n * The url is not supported.\n *\n * It is raised when no plugin of {@link DisTubeOptions.plugins} can handle\n * the url.\n */\n NOT_SUPPORTED_URL: \"This url is not supported\",\n /**\n * No plugin supports the song.\n *\n * It is raised when no plugin of {@link DisTubeOptions.plugins} can play\n * the song.\n */\n NOT_SUPPORTED_SONG: (song: string) => `There is no plugin supporting this song (${song})`,\n /**\n * The array does not have any valid song.\n *\n * It is raised when every element of the `songs` array of\n * {@link DisTube#createCustomPlaylist} is neither a {@link Song} nor a\n * valid url.\n */\n NO_VALID_SONG: \"'songs' array does not have any valid Song or url\",\n /**\n * The input cannot be resolved to a song or a playlist.\n *\n * It is raised when the input of {@link DisTubeHandler#resolve} is neither\n * a url, nor a {@link Song}, nor a {@link Playlist}.\n */\n CANNOT_RESOLVE_SONG: (t: any) => `Cannot resolve ${inspect(t)} to a Song`,\n /**\n * The stream url of the song cannot be found.\n *\n * It is raised when the plugin of the song does not return a stream url.\n */\n CANNOT_GET_STREAM_URL: (song: string) => `Cannot get stream url with this song (${song})`,\n /**\n * The search query of the song cannot be built.\n *\n * It is raised when the plugin of the song cannot build a query to look for\n * a playable version of it.\n */\n CANNOT_GET_SEARCH_QUERY: (song: string) => `Cannot get search query with this song (${song})`,\n /**\n * No song was found for the query.\n *\n * It is raised when no plugin of {@link DisTubeOptions.plugins} has any\n * result for the search query.\n */\n NO_RESULT: (query: string) => `Cannot find any song with this query (${query})`,\n /**\n * The song does not have any stream url.\n *\n * It is raised when a song is played while it does not have a stream url\n * attached to it.\n */\n NO_STREAM_URL: (song: string) => `No stream url attached (${song})`,\n\n /**\n * Every video of the playlist was filtered out.\n *\n * It is raised when a playlist does not have any valid video left, e.g.\n * because all of them were age-restricted and the channel is not NSFW.\n */\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 /**\n * The playlist does not have any valid video.\n *\n * It is raised when a playlist is empty.\n */\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 if (!haveCode(code)) return args[0];\n try {\n return parseMessage(ERROR_MESSAGES[code], ...args);\n } catch {\n // The error code needs more arguments than the ones that were given.\n return args[0] ?? code;\n }\n};\n\n/**\n * The error raised by DisTube.\n *\n * Every error of the library is a `DisTubeError`: it has a machine readable\n * `errorCode` and a human readable message that is built from the code.\n *\n * @example\n * ```ts\n * try {\n * await distube.play(channel, \"Never gonna give you up\");\n * } catch (error) {\n * if (error instanceof DisTubeError && error.errorCode === \"NO_RESULT\") {\n * // No song was found for the query.\n * }\n * }\n * ```\n */\nexport class DisTubeError<T extends string = any> extends Error {\n /**\n * The code of the error, e.g. `NO_RESULT`.\n */\n errorCode: string;\n /**\n * Create a DisTube error with a static error code.\n * @param code - The code of the error\n */\n constructor(code: T extends StaticErrorCode ? T : never);\n /**\n * Create a DisTube error with a templated error code.\n * @param code - The code of the error\n * @param args - The arguments of the message template of the code\n */\n constructor(code: T extends TemplateErrorCode ? T : never, ...args: Parameters<ErrorMessage[typeof code]>);\n /**\n * Create a DisTube error with a templated error code.\n * @param code - The code of the error\n * @param _ - Not used: it prevents this overload from being selected\n */\n constructor(code: TemplateErrorCode, _: never);\n /**\n * Create a DisTube error with a custom message.\n * @param code - The code of the error\n * @param message - The custom message of the error\n */\n constructor(code: T extends ErrorCode ? never : T, message: string);\n /**\n * Create a DisTube error.\n * @param code - The code of the error\n * @param args - The arguments of the message template of the code\n */\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 /**\n * Create a {@link DisTubeError} with a custom message.\n *\n * The default message of an error code is a generic template. Use this factory\n * when you need to tell the user what exactly went wrong, or when you want to\n * keep the original error as the `cause` of the error.\n *\n * It is polymorphic: calling it on a subclass creates an instance of that\n * subclass.\n *\n * @param code - The error code\n * @param message - The custom message\n * @param options - Optional options\n * @param options.cause - The original error that caused this one\n * @returns The created error\n */\n static withMessage<T extends string = any>(code: T, message: string, options?: { cause?: unknown }): DisTubeError<T> {\n // biome-ignore lint/complexity/noThisInStatic: the factory has to create an instance of the class it is called on\n const error = new (this as any)(code, message) as DisTubeError<T>;\n error.message = message;\n if (options && \"cause\" in options) error.cause = options.cause;\n return error;\n }\n\n /**\n * The name of the error, with its code.\n * @returns The name of the error, e.g. `DisTubeError [NO_RESULT]`\n */\n override get name() {\n return `DisTubeError [${this.errorCode}]`;\n }\n\n /**\n * The code of the error, e.g. `NO_RESULT`.\n *\n * It is an alias of {@link DisTubeError.errorCode}.\n * @returns The code of the error\n */\n get code() {\n return this.errorCode;\n }\n}\n","import { URL } from \"node:url\";\nimport type {\n Client,\n ClientOptions,\n Guild,\n GuildMember,\n GuildTextBasedChannel,\n Message,\n Snowflake,\n VoiceBasedChannel,\n VoiceState,\n} from \"discord.js\";\nimport { Constants, GatewayIntentBits, IntentsBitField, SnowflakeUtil } from \"discord.js\";\nimport { DisTubeVoice } from \"./core/DisTubeVoice\";\nimport { DisTubeError } from \"./struct/DisTubeError\";\nimport { Queue } from \"./struct/Queue\";\nimport type { GuildIdResolvable, UnhandledErrorBehavior } from \"./type\";\n\nconst formatInt = (int: number) => (int < 10 ? `0${int}` : int);\n\n/**\n * Format duration to string\n * @param sec - Duration in seconds\n * @returns The formatted duration, e.g. `01:23` or `01:02:03`\n */\nexport function formatDuration(sec: number): string {\n if (!sec || !Number(sec)) return \"00:00\";\n const seconds = Math.floor(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}\nconst SUPPORTED_PROTOCOL = [\"https:\", \"http:\", \"file:\"] as const;\n/**\n * Check if the string is an URL\n * @param input - input\n * @returns `true` when the input is an URL with a supported protocol\n */\nexport function isURL(input: any): input is `${(typeof SUPPORTED_PROTOCOL)[number]}//${string}` {\n if (typeof input !== \"string\" || input.includes(\" \")) return false;\n try {\n const url = new URL(input);\n if (!SUPPORTED_PROTOCOL.some(p => p === url.protocol)) 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 options - options\n * @returns Nothing\n * @throws {@link DisTubeError} When the `GuildVoiceStates` intent is missing\n */\nexport function checkIntents(options: ClientOptions): void {\n // The `instanceof` check is not used on purpose: a project can have more than\n // one copy of discord.js in its tree (a linked package, a monorepo, ...), and\n // the intents of the client would not be an instance of our own IntentsBitField.\n const intents = options.intents as unknown as { has?: (bit: number | bigint) => boolean };\n const hasVoiceStates =\n typeof intents?.has === \"function\"\n ? intents.has(GatewayIntentBits.GuildVoiceStates)\n : new IntentsBitField(options.intents as never).has(GatewayIntentBits.GuildVoiceStates);\n if (!hasVoiceStates) throw new DisTubeError(\"MISSING_INTENTS\", \"GuildVoiceStates\");\n}\n\n/**\n * Check if the voice channel is empty\n * @param voiceState - voiceState\n * @returns `true` when there is no human user in the voice channel of the state\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\n/**\n * Check if the value is a valid Discord snowflake.\n * @param id - The value to check\n * @returns `true` when the value is a valid snowflake\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\n/**\n * Check if the value is a Discord.js guild member.\n * @param member - The value to check\n * @returns `true` when the value looks like a guild member\n */\nexport function isMemberInstance(member: any): member is GuildMember {\n return (\n Boolean(member) &&\n isSnowflake(member.id) &&\n isSnowflake(member.guild?.id) &&\n isSnowflake(member.user?.id) &&\n member.id === member.user.id\n );\n}\n\n/**\n * Check if the value is a Discord.js guild text based channel.\n * @param channel - The value to check\n * @returns `true` when the value looks like a guild text based channel\n */\nexport function isTextChannelInstance(channel: any): channel is GuildTextBasedChannel {\n return (\n Boolean(channel) &&\n isSnowflake(channel.id) &&\n isSnowflake(channel.guildId || channel.guild?.id) &&\n Constants.TextBasedChannelTypes.includes(channel.type) &&\n typeof channel.send === \"function\" &&\n (typeof channel.nsfw === \"boolean\" || typeof channel.parent?.nsfw === \"boolean\")\n );\n}\n\n/**\n * Check if the value is a Discord.js message.\n * @param message - The value to check\n * @returns `true` when the value looks like a message\n */\nexport function isMessageInstance(message: any): message is Message<true> {\n // Simple check for using distube normally\n return (\n Boolean(message) &&\n isSnowflake(message.id) &&\n isSnowflake(message.guildId || message.guild?.id) &&\n isMemberInstance(message.member) &&\n isTextChannelInstance(message.channel) &&\n Constants.NonSystemMessageTypes.includes(message.type) &&\n message.member.id === message.author?.id\n );\n}\n\n/**\n * Check if the value is a Discord.js voice based channel.\n * @param channel - The value to check\n * @returns `true` when the value looks like a voice based channel\n */\nexport function isSupportedVoiceChannel(channel: any): channel is VoiceBasedChannel {\n return (\n Boolean(channel) &&\n isSnowflake(channel.id) &&\n isSnowflake(channel.guildId || channel.guild?.id) &&\n Constants.VoiceBasedChannelTypes.includes(channel.type)\n );\n}\n\n/**\n * Check if the value is a Discord.js guild.\n * @param guild - The value to check\n * @returns `true` when the value looks like a guild\n */\nexport function isGuildInstance(guild: any): guild is Guild {\n return Boolean(guild) && isSnowflake(guild.id) && isSnowflake(guild.ownerId) && typeof guild.name === \"string\";\n}\n\n/**\n * Resolve a guild id from anything that can be resolved to a guild id.\n * @param resolvable - The value to resolve\n * @returns The id of the guild\n * @throws {@link DisTubeError} When the value cannot be resolved to a guild id\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\n/**\n * Check if the value is a Discord.js client.\n * @param client - The value to check\n * @returns `true` when the value looks like a client\n */\nexport function isClientInstance(client: any): client is Client {\n return Boolean(client) && typeof client.login === \"function\";\n}\n\n/**\n * Check that an object does not have any key that is not in a source.\n * @param target - The object to check\n * @param source - The valid keys, or the object that holds them\n * @param sourceName - The name of the source, used in the error message\n * @returns Nothing\n * @throws {@link DisTubeError} When the target is not an object, or when it has\n * an invalid key\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 : objectKeys(source);\n const invalidKey = objectKeys(target).find(key => !sourceKeys.includes(key));\n if (invalidKey) throw new DisTubeError(\"INVALID_KEY\", sourceName, invalidKey);\n}\n\n/**\n * Check if the value is a plain object.\n * @param obj - The value to check\n * @returns `true` when the value is an object and not an array nor `null`\n */\nexport function isObject(obj: any): obj is object {\n return typeof obj === \"object\" && obj !== null && !Array.isArray(obj);\n}\n\n/**\n * The keys of a type, as an array.\n */\nexport type KeyOf<T> = T extends object ? (keyof T)[] : [];\n/**\n * Get the keys of an object.\n * @param obj - The object\n * @returns The keys of the object, or an empty array when it is not an object\n */\nexport function objectKeys<T>(obj: T): KeyOf<T> {\n if (!isObject(obj)) return [] as KeyOf<T>;\n return Object.keys(obj) as KeyOf<T>;\n}\n\n/**\n * Check if the channel is age-restricted.\n * @param channel - The channel to check\n * @returns `true` when the channel is a NSFW channel\n */\nexport function isNsfwChannel(channel?: GuildTextBasedChannel): boolean {\n if (!isTextChannelInstance(channel)) return false;\n if (channel.isThread()) return channel.parent?.nsfw ?? false;\n return channel.nsfw;\n}\n\n/**\n * The falsy values of JavaScript.\n */\nexport type Falsy = undefined | null | false | 0 | \"\";\n/**\n * Check if a value is not falsy.\n * @param x - The value to check\n * @returns `true` when the value is not falsy\n */\nexport const isTruthy = <T>(x: T | Falsy): x is T => Boolean(x);\n\n/**\n * Handle an error that was emitted through the special `\"error\"` event without\n * any listener.\n *\n * Node.js throws an `ERR_UNHANDLED_ERROR` in that situation, which crashes the\n * whole process. DisTube handles it gracefully instead.\n * @param error - The error\n * @param behavior - The behavior to apply. Defaults to `\"log\"`.\n * @returns Nothing\n * @throws The given error when the behavior is `\"throw\"`\n */\nexport function handleUnhandledError(error: Error, behavior: UnhandledErrorBehavior = \"log\"): void {\n if (behavior === \"throw\") throw error;\n if (behavior === \"ignore\") return;\n process.emitWarning(\n \"The 'error' event was emitted but there is no listener for it. \" +\n \"Add a listener with `distube.on(Events.ERROR, (error, queue, song) => { ... })` \" +\n \"to handle DisTube errors, or set `unhandledError` to 'throw' to restore the default behavior.\",\n {\n code: \"DIS_TUBE_UNHANDLED_ERROR\",\n detail: error?.stack ?? error?.message ?? String(error),\n },\n );\n}\n\n/**\n * Check that an encryption library is available.\n *\n * Discord encrypts the audio with DAVE, so a cipher is required to play it.\n * The `aes-256-gcm` cipher of Node.js is used when it is available, otherwise\n * one of the supported third-party libraries is used.\n * @returns `true` when an encryption library is available\n */\nexport const checkEncryptionLibraries = async () => {\n if (await import(\"node:crypto\").then(m => m.getCiphers().includes(\"aes-256-gcm\"))) return true;\n for (const lib of [\n \"@noble/ciphers\",\n \"@stablelib/xchacha20poly1305\",\n \"sodium-native\",\n \"sodium\",\n \"libsodium-wrappers\",\n \"tweetnacl\",\n ]) {\n try {\n await import(lib);\n return true;\n } catch {}\n }\n return false;\n};\n","import type { AudioPlayer, VoiceConnection } from \"@discordjs/voice\";\nimport {\n AudioPlayerStatus,\n createAudioPlayer,\n entersState,\n joinVoiceChannel,\n VoiceConnectionDisconnectReason,\n VoiceConnectionStatus,\n} from \"@discordjs/voice\";\nimport type { Snowflake, VoiceBasedChannel, VoiceState } from \"discord.js\";\nimport { Constants } from \"discord.js\";\nimport { TypedEmitter } from \"tiny-typed-emitter\";\nimport { JOIN_TIMEOUT_MS, RECONNECT_MAX_ATTEMPTS, RECONNECT_TIMEOUT_MS } from \"../constant\";\nimport { DisTubeError } from \"../struct/DisTubeError\";\nimport type { DisTubeVoiceEvents } from \"../type\";\nimport { checkEncryptionLibraries, handleUnhandledError, isSupportedVoiceChannel } from \"../util\";\nimport type { DisTubeStream } from \"./DisTubeStream\";\nimport type { DisTubeVoiceManager } from \"./manager/DisTubeVoiceManager\";\n\n/**\n * Create a voice connection to the voice channel\n */\nexport class DisTubeVoice extends TypedEmitter<DisTubeVoiceEvents> {\n /**\n * The id of the guild of this voice connection.\n */\n readonly id: Snowflake;\n /**\n * The voice manager that instantiated this connection.\n */\n readonly voices: DisTubeVoiceManager;\n /**\n * The audio player that plays the audio of this connection.\n */\n readonly audioPlayer: AudioPlayer;\n /**\n * The Discord.js voice connection.\n */\n connection!: VoiceConnection;\n /**\n * Whether or not an error was already emitted for the current stream.\n *\n * It prevents the same error from being emitted several times.\n */\n emittedError!: boolean;\n /**\n * Whether or not the voice connection has been disconnected.\n */\n isDisconnected = false;\n /**\n * The stream that is currently playing.\n */\n stream?: DisTubeStream;\n /**\n * The stream that was playing when the playback was paused.\n */\n pausingStream?: DisTubeStream;\n #channel!: VoiceBasedChannel;\n #volume = 100;\n /**\n * Timer used to detect a track that is stuck in the \"buffering\" state.\n */\n #stuckTimer?: NodeJS.Timeout;\n /**\n * Create a voice connection to the voice channel.\n * @param voiceManager - The voice manager of the DisTube instance\n * @param channel - The voice channel to join\n */\n constructor(voiceManager: DisTubeVoiceManager, channel: VoiceBasedChannel) {\n super();\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 this.#clearStuckTimer();\n if (oldState.status !== AudioPlayerStatus.Idle) this.emit(\"finish\");\n })\n .on(AudioPlayerStatus.Buffering, () => {\n this.#startStuckTimer();\n })\n .on(AudioPlayerStatus.Playing, () => {\n this.#clearStuckTimer();\n })\n .on(\"error\", (error: NodeJS.ErrnoException) => {\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 // User disconnect\n this.leave();\n } else if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {\n // Move to other channel\n entersState(this.connection, VoiceConnectionStatus.Connecting, RECONNECT_TIMEOUT_MS)\n .then(() => entersState(this.connection, VoiceConnectionStatus.Ready, RECONNECT_TIMEOUT_MS))\n .then(() => {\n const oldChannel = this.#channel;\n const currentChannel = this.channel;\n if (oldChannel && currentChannel && oldChannel.id !== currentChannel.id) {\n this.#channel = currentChannel;\n this.emit(\"channelChange\", oldChannel, currentChannel);\n }\n })\n .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 < RECONNECT_MAX_ATTEMPTS) {\n // Try to rejoin\n setTimeout(\n () => {\n this.connection.rejoin();\n },\n (this.connection.rejoinAttempts + 1) * RECONNECT_TIMEOUT_MS,\n ).unref();\n } else if (this.connection.state.status !== VoiceConnectionStatus.Destroyed) {\n // Leave after 5 attempts\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 /**\n * The voice channel id the bot is in\n */\n get channelId() {\n return this.connection?.joinConfig?.channelId ?? undefined;\n }\n /**\n * The voice channel the bot is in.\n *\n * Setting it moves the bot to another voice channel.\n */\n get channel() {\n if (!this.channelId) return this.#channel;\n if (this.#channel?.id === this.channelId) return this.#channel;\n const channel = this.voices.client.channels.cache.get(this.channelId);\n if (!channel) return this.#channel;\n for (const type of Constants.VoiceBasedChannelTypes) {\n if (channel.type === type) {\n this.#channel = channel;\n return channel;\n }\n }\n return this.#channel;\n }\n /**\n * Move the bot to another voice channel.\n * @param channel - The voice channel to join\n * @throws {@link DisTubeError} When the channel is invalid, when it belongs to\n * another guild or client, or when the bot cannot join it\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.channelId) return;\n if (!channel.joinable) {\n if (channel.full) throw new DisTubeError(\"VOICE_FULL\");\n else throw new DisTubeError(\"VOICE_MISSING_PERMS\");\n }\n const oldChannel = this.#channel;\n this.connection = this.#join(channel);\n this.#channel = channel;\n if (oldChannel && oldChannel.id !== channel.id) {\n this.emit(\"channelChange\", oldChannel, channel);\n }\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 // DAVE is the end-to-end encryption protocol used by Discord.\n // It is enabled explicitly so that a change of the upstream default\n // can never silently disable the encryption.\n daveEncryption: true,\n });\n }\n /**\n * Join a voice channel with this connection\n * @param channel - A voice channel\n * @returns The voice connection\n * @throws {@link DisTubeError} When the connection cannot be established\n */\n async join(channel?: VoiceBasedChannel): Promise<DisTubeVoice> {\n if (channel) this.channel = channel;\n try {\n await entersState(this.connection, VoiceConnectionStatus.Ready, JOIN_TIMEOUT_MS);\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\", JOIN_TIMEOUT_MS / 1000);\n }\n return this;\n }\n /**\n * Leave the voice channel of this connection\n * @param error - Optional, an error to emit with 'error' event.\n * @returns Nothing\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 force - If true, will force the {@link DisTubeVoice#audioPlayer} to enter the Idle state even\n * if the {@link DisTubeStream#audioResource} has silence padding frames.\n * @returns Nothing\n */\n stop(force = false) {\n this.audioPlayer.stop(force);\n }\n #streamErrorHandler?: (error: NodeJS.ErrnoException) => void;\n /**\n * Play a {@link DisTubeStream}\n * @param dtStream - DisTubeStream\n * @returns A promise that resolves when the stream is playing\n * @throws {@link DisTubeError} When no encryption library is available\n */\n async play(dtStream: DisTubeStream) {\n if (!(await checkEncryptionLibraries())) {\n dtStream.kill();\n throw new DisTubeError(\"ENCRYPTION_LIBRARIES_MISSING\");\n }\n this.emittedError = false;\n // Remove previous error listener to prevent memory leaks\n if (this.stream && this.#streamErrorHandler) {\n this.stream.off(\"error\", this.#streamErrorHandler);\n }\n this.#streamErrorHandler = (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 dtStream.on(\"error\", this.#streamErrorHandler);\n if (this.audioPlayer.state.status !== AudioPlayerStatus.Paused) {\n this.audioPlayer.play(dtStream.audioResource);\n this.stream?.kill();\n // A crossfade transition stream is already spawned (it warmed up its\n // buffers before the fade window began): only swap the resource.\n if (!dtStream.process) dtStream.spawn();\n } else if (!this.pausingStream) {\n this.pausingStream = this.stream;\n }\n this.stream = dtStream;\n this.volume = this.#volume;\n }\n /**\n * Set the volume percentage of the stream.\n * @param volume - The volume percentage, from `0` to `100`\n * @throws {@link DisTubeError} When the volume is not a number, or when it is\n * negative\n */\n set volume(volume: number) {\n if (typeof volume !== \"number\" || 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.stream?.setVolume((this.#volume / 100) ** (0.5 / Math.log10(2)));\n }\n /**\n * Get or set the volume percentage\n */\n get volume() {\n return this.#volume;\n }\n /**\n * Playback duration of the audio resource in seconds (time since playback started)\n */\n get playbackDuration() {\n return (this.stream?.audioResource?.playbackDuration ?? 0) / 1000;\n }\n /**\n * Current playback time in seconds, accounting for seek offset\n */\n get playbackTime() {\n return this.playbackDuration + (this.stream?.seekTime ?? 0);\n }\n /**\n * Pause the playback of the audio player.\n * @returns Nothing\n */\n pause() {\n this.audioPlayer.pause();\n }\n /**\n * Resume the playback of the audio player.\n *\n * The FFmpeg process is spawned again when the stream was killed while the\n * playback was paused.\n * @returns Nothing\n */\n unpause() {\n const state = this.audioPlayer.state;\n if (state.status !== AudioPlayerStatus.Paused) return;\n if (this.stream?.audioResource && state.resource !== this.stream.audioResource) {\n this.audioPlayer.play(this.stream.audioResource);\n this.stream.spawn();\n this.pausingStream?.kill();\n delete this.pausingStream;\n } else {\n this.audioPlayer.unpause();\n }\n }\n /**\n * Emit an event of the voice connection.\n *\n * The special `\"error\"` event never crashes the process when there is no\n * listener for it, even when the voice connection is used outside of a\n * {@link Queue}.\n * @param event - The event name\n * @param args - The event arguments\n * @returns `true` when the event had listeners, `false` otherwise\n */\n override emit<U extends keyof DisTubeVoiceEvents>(event: U, ...args: Parameters<DisTubeVoiceEvents[U]>): boolean {\n if (event === \"error\" && this.listenerCount(\"error\") === 0) {\n handleUnhandledError(args[0] as Error, this.voices.options?.unhandledError ?? \"log\");\n return false;\n }\n return super.emit(event, ...args);\n }\n\n /**\n * Start the timer that detects a track stuck in the \"buffering\" state.\n *\n * When the track does not start playing within\n * {@link DisTubeOptions.stuckThreshold} milliseconds, it is reported as an error\n * so that the queue can skip it.\n */\n #startStuckTimer() {\n const threshold = this.voices.options.stuckThreshold;\n if (typeof threshold !== \"number\" || threshold <= 0) return;\n this.#clearStuckTimer();\n this.#stuckTimer = setTimeout(() => {\n this.#stuckTimer = undefined;\n if (this.emittedError) return;\n this.emittedError = true;\n this.emit(\"error\", new DisTubeError(\"TRACK_STUCK\"));\n }, threshold);\n this.#stuckTimer.unref?.();\n }\n /**\n * Clear the stuck-track detection timer.\n */\n #clearStuckTimer() {\n if (!this.#stuckTimer) return;\n clearTimeout(this.#stuckTimer);\n this.#stuckTimer = undefined;\n }\n /**\n * Whether the bot is self-deafened\n */\n get selfDeaf(): boolean {\n return this.connection.joinConfig.selfDeaf;\n }\n /**\n * Whether the bot is self-muted\n */\n get selfMute(): boolean {\n return this.connection.joinConfig.selfMute;\n }\n /**\n * Self-deafens/undeafens the bot.\n * @param selfDeaf - Whether or not the bot should be self-deafened\n * @returns true if the voice state was successfully updated, otherwise false\n * @throws {@link DisTubeError} When the value is not a boolean\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 selfMute - Whether or not the bot should be self-muted\n * @returns true if the voice state was successfully updated, otherwise false\n * @throws {@link DisTubeError} When the value is not a boolean\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 */\n get voiceState(): VoiceState | undefined {\n return this.channel?.guild?.members?.me?.voice;\n }\n}\n","import { Collection } from \"discord.js\";\nimport { DisTubeBase } from \"../DisTubeBase\";\n\n/**\n * Manages the collection of a data model.\n */\nexport abstract class BaseManager<V> extends DisTubeBase {\n /**\n * The collection of items for this manager.\n */\n collection = new Collection<string, V>();\n /**\n * The size of the collection.\n */\n get size() {\n return this.collection.size;\n }\n}\n","import type { FFmpegArg as FFmpegArgsValue, Filter, FilterResolvable, Queue } from \"../..\";\nimport { DisTubeError, Events } from \"../..\";\nimport { BaseManager } from \"./BaseManager\";\n\n/**\n * Manage filters of a playing {@link Queue}\n */\nexport class FilterManager extends BaseManager<Filter> {\n /**\n * The queue to manage\n */\n queue: Queue;\n /**\n * Create a filter manager for a queue.\n * @param queue - The queue to manage\n */\n constructor(queue: Queue) {\n super(queue.distube);\n this.queue = queue;\n }\n\n #resolve(filter: FilterResolvable): Filter {\n if (typeof filter === \"object\" && typeof filter.name === \"string\" && typeof filter.value === \"string\") {\n return filter;\n }\n if (typeof filter === \"string\" && Object.hasOwn(this.distube.filters, filter)) {\n return {\n name: filter,\n value: this.distube.filters[filter],\n };\n }\n throw new DisTubeError(\"INVALID_TYPE\", \"FilterResolvable\", filter, \"filter\");\n }\n\n #apply(oldFilters: string[]) {\n this.queue._clearPreload?.();\n const newFilters = this.names;\n const changed = oldFilters.length !== newFilters.length || !oldFilters.every(f => newFilters.includes(f));\n if (changed) {\n this.emit(Events.CHANGE_FILTER, this.queue, newFilters, oldFilters);\n }\n // The FFmpeg audio filters are applied when the stream is created, so the\n // stream has to be restarted. The restart never interrupts the playback for\n // good: a failure keeps the current song in the queue.\n void this.queue._restartStream().catch((e: unknown) => {\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.queue.debug(`[${this.queue.id}] Failed to apply the filters: ${errorMessage}`);\n });\n }\n\n /**\n * Enable a filter or multiple filters to the manager\n * @param filterOrFilters - The filter or filters to enable\n * @param override - Wether or not override the applied filter with new filter value\n * @returns This manager, to allow chaining\n * @throws {@link DisTubeError} When a filter is not a valid {@link FilterResolvable}\n * @example\n * ```ts\n * queue.filters.add(\"bassboost\");\n * ```\n */\n add(filterOrFilters: FilterResolvable | FilterResolvable[], override = false) {\n const oldFilters = this.names;\n if (Array.isArray(filterOrFilters)) {\n for (const filter of filterOrFilters) {\n const ft = this.#resolve(filter);\n if (override || !this.has(ft)) this.collection.set(ft.name, ft);\n }\n } else {\n const ft = this.#resolve(filterOrFilters);\n if (override || !this.has(ft)) this.collection.set(ft.name, ft);\n }\n this.#apply(oldFilters);\n return this;\n }\n\n /**\n * Clear enabled filters of the manager\n * @returns This manager, to allow chaining\n */\n clear() {\n return this.set([]);\n }\n\n /**\n * Set the filters applied to the manager\n * @param filters - The filters to apply\n * @returns This manager, to allow chaining\n * @throws {@link DisTubeError} When the array is invalid, or when a filter is\n * not a valid {@link FilterResolvable}\n */\n set(filters: FilterResolvable[]) {\n if (!Array.isArray(filters)) throw new DisTubeError(\"INVALID_TYPE\", \"Array<FilterResolvable>\", filters, \"filters\");\n const oldFilters = this.names;\n this.collection.clear();\n for (const f of filters) {\n const filter = this.#resolve(f);\n this.collection.set(filter.name, filter);\n }\n this.#apply(oldFilters);\n return this;\n }\n\n #removeFn(f: FilterResolvable) {\n return this.collection.delete(this.#resolve(f).name);\n }\n\n /**\n * Disable a filter or multiple filters\n * @param filterOrFilters - The filter or filters to disable\n * @returns This manager, to allow chaining\n * @throws {@link DisTubeError} When a filter is not a valid {@link FilterResolvable}\n */\n remove(filterOrFilters: FilterResolvable | FilterResolvable[]) {\n const oldFilters = this.names;\n if (Array.isArray(filterOrFilters)) filterOrFilters.forEach(f => this.#removeFn(f));\n else this.#removeFn(filterOrFilters);\n this.#apply(oldFilters);\n return this;\n }\n\n /**\n * Check whether a filter enabled or not\n * @param filter - The filter to check\n * @returns `true` when the filter is enabled\n * @throws {@link DisTubeError} When the filter is not a valid {@link FilterResolvable}\n */\n has(filter: FilterResolvable) {\n return this.collection.has(typeof filter === \"string\" ? filter : this.#resolve(filter).name);\n }\n\n /**\n * Array of enabled filter names\n */\n get names(): string[] {\n return [...this.collection.keys()];\n }\n\n /**\n * Array of enabled filters\n */\n get values(): Filter[] {\n return [...this.collection.values()];\n }\n\n /**\n * The FFmpeg arguments of the enabled filters.\n *\n * It is the `af` output argument of the FFmpeg process.\n */\n get ffmpegArgs(): FFmpegArgsValue {\n return this.size ? { af: this.values.map(f => f.value).join(\",\") } : {};\n }\n\n /**\n * The names of the enabled filters, as a comma separated string.\n * @returns The names of the enabled filters\n */\n override toString() {\n return this.names.toString();\n }\n}\n","import type {\n Guild,\n GuildMember,\n GuildTextBasedChannel,\n Interaction,\n Message,\n Snowflake,\n VoiceBasedChannel,\n VoiceState,\n} from \"discord.js\";\nimport type {\n DisTubeError,\n DisTubeVoice,\n ExtractorPlugin,\n InfoExtractorPlugin,\n PlayableExtractorPlugin,\n Playlist,\n Queue,\n Song,\n} from \".\";\n\n/**\n * A value that can be awaited.\n *\n * It is used by every method of DisTube that can be implemented\n * synchronously or asynchronously: the plugin methods and the event\n * listeners.\n */\nexport type Awaitable<T = any> = T | PromiseLike<T>;\n\n/**\n * Behavior when the {@link Events.ERROR} event is emitted but nobody listens to it.\n * - `log` (default): the error is logged to the console instead of crashing the process\n * - `throw`: the error is re-thrown (Node.js default behavior)\n * - `ignore`: the error is silently discarded\n */\nexport type UnhandledErrorBehavior = \"log\" | \"throw\" | \"ignore\";\n\n/**\n * The events emitted by a {@link DisTube} instance.\n */\nexport enum Events {\n /**\n * Emitted when DisTube encounters an error while playing songs.\n *\n * It is the only special event: Node.js crashes the process when the\n * `\"error\"` event is emitted without any listener. DisTube handles it\n * gracefully instead, following {@link DisTubeOptions.unhandledError}.\n */\n ERROR = \"error\",\n /**\n * Emitted after a new playlist is added to a {@link Queue}.\n */\n ADD_LIST = \"addList\",\n /**\n * Emitted after a new song is added to a {@link Queue}.\n */\n ADD_SONG = \"addSong\",\n /**\n * Emitted when a song starts playing.\n */\n PLAY_SONG = \"playSong\",\n /**\n * Emitted when a song finished playing.\n */\n FINISH_SONG = \"finishSong\",\n /**\n * Emitted when a {@link Queue} runs out of songs to play.\n */\n EMPTY = \"empty\",\n /**\n * Emitted when a {@link Queue} is finished, and its autoplay mode is\n * disabled.\n */\n FINISH = \"finish\",\n /**\n * Emitted when a {@link Queue} is initialized, to change its default\n * properties.\n */\n INIT_QUEUE = \"initQueue\",\n /**\n * Emitted when the autoplay mode is enabled and no related song could be\n * found.\n */\n NO_RELATED = \"noRelated\",\n /**\n * Emitted when the bot is disconnected from a voice channel.\n */\n DISCONNECT = \"disconnect\",\n /**\n * Emitted when a {@link Queue} is deleted.\n */\n DELETE_QUEUE = \"deleteQueue\",\n /**\n * Emitted for logging FFmpeg debug information.\n */\n FFMPEG_DEBUG = \"ffmpegDebug\",\n /**\n * Emitted to provide debug information from DisTube's operation.\n */\n DEBUG = \"debug\",\n /**\n * Emitted when a guild stream is paused.\n */\n PAUSE_SONG = \"pauseSong\",\n /**\n * Emitted when a paused guild stream is resumed.\n */\n RESUME_SONG = \"resumeSong\",\n /**\n * Emitted when a guild stream is seeked to a new position.\n */\n SEEK_SONG = \"seekSong\",\n /**\n * Emitted when the volume of a guild stream is changed.\n */\n SET_VOLUME = \"setVolume\",\n /**\n * Emitted after the songs of a {@link Queue} have been shuffled.\n */\n SHUFFLE_QUEUE = \"shuffleQueue\",\n /**\n * Emitted when a song is skipped.\n */\n SKIP_SONG = \"skipSong\",\n /**\n * Emitted when the audio filters of a {@link Queue} are changed.\n */\n CHANGE_FILTER = \"changeFilter\",\n /**\n * Emitted when the bot is moved to another voice channel.\n */\n VOICE_CHANNEL_CHANGE = \"voiceChannelChange\",\n /**\n * Emitted when DisTube starts pre-buffering / pre-fetching the next song in a {@link Queue}.\n */\n PRELOAD_SONG = \"preloadSong\",\n /**\n * Emitted when the next song in a {@link Queue} has been pre-buffered and is ready.\n */\n PRELOADED_SONG = \"preloadedSong\",\n /**\n * Emitted when pre-buffering the next song in a {@link Queue} fails.\n */\n PRELOAD_ERROR = \"preloadError\",\n}\n\n/**\n * The arguments of every {@link Events} event.\n *\n * It is the source of truth of the signature of the event listeners:\n * @see {@link TypedDisTubeEvents}\n */\nexport type DisTubeEvents = {\n /**\n * Emitted after a new playlist is added to a {@link Queue}.\n */\n [Events.ADD_LIST]: [queue: Queue, playlist: Playlist];\n /**\n * Emitted after a new song is added to a {@link Queue}.\n */\n [Events.ADD_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when a {@link Queue} is deleted.\n */\n [Events.DELETE_QUEUE]: [queue: Queue];\n /**\n * Emitted when the bot is disconnected from a voice channel.\n */\n [Events.DISCONNECT]: [queue: Queue];\n /**\n * Emitted when a {@link Queue} runs out of songs to play.\n */\n [Events.EMPTY]: [queue: Queue];\n /**\n * Emitted when DisTube encounters an error while playing songs.\n */\n [Events.ERROR]: [error: Error, queue: Queue, song: Song | undefined];\n /**\n * Emitted for logging FFmpeg debug information.\n */\n [Events.FFMPEG_DEBUG]: [debug: string];\n /**\n * Emitted to provide debug information from DisTube's operation.\n */\n [Events.DEBUG]: [debug: string];\n /**\n * Emitted when a {@link Queue} is finished, and its autoplay mode is\n * disabled.\n */\n [Events.FINISH]: [queue: Queue];\n /**\n * Emitted when a song finished playing.\n */\n [Events.FINISH_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when a {@link Queue} is initialized.\n */\n [Events.INIT_QUEUE]: [queue: Queue];\n /**\n * Emitted when the autoplay mode is enabled and no related song could be\n * found.\n */\n [Events.NO_RELATED]: [queue: Queue, error: DisTubeError];\n /**\n * Emitted when a song starts playing.\n */\n [Events.PLAY_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when a guild stream is paused.\n */\n [Events.PAUSE_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when a paused guild stream is resumed.\n */\n [Events.RESUME_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when a guild stream is seeked to a new position.\n */\n [Events.SEEK_SONG]: [queue: Queue, song: Song, position: number];\n /**\n * Emitted when the volume of a guild stream is changed.\n */\n [Events.SET_VOLUME]: [queue: Queue, volume: number, oldVolume: number];\n /**\n * Emitted after the songs of a {@link Queue} have been shuffled.\n */\n [Events.SHUFFLE_QUEUE]: [queue: Queue, songs: Song[]];\n /**\n * Emitted when a song is skipped.\n */\n [Events.SKIP_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when the audio filters of a {@link Queue} are changed.\n */\n [Events.CHANGE_FILTER]: [queue: Queue, newFilters: string[], oldFilters: string[]];\n /**\n * Emitted when the bot is moved to another voice channel.\n */\n [Events.VOICE_CHANNEL_CHANGE]: [queue: Queue, oldChannel: VoiceBasedChannel, newChannel: VoiceBasedChannel];\n /**\n * Emitted when DisTube starts pre-buffering / pre-fetching the next song in a {@link Queue}.\n */\n [Events.PRELOAD_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when the next song in a {@link Queue} has been pre-buffered and is ready.\n */\n [Events.PRELOADED_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when pre-buffering the next song in a {@link Queue} fails.\n */\n [Events.PRELOAD_ERROR]: [queue: Queue, song: Song, error: Error];\n};\n\n/**\n * The typed event listeners of a {@link DisTube} instance.\n *\n * Every listener of an event receives the arguments of\n * {@link DisTubeEvents}, and can be synchronous or asynchronous.\n */\nexport type TypedDisTubeEvents = {\n [K in keyof DisTubeEvents]: (...args: DisTubeEvents[K]) => Awaitable;\n};\n\n/**\n * The events emitted by a {@link DisTubeVoice} instance.\n */\nexport type DisTubeVoiceEvents = {\n /**\n * Emitted when the voice connection is disconnected.\n * @param error - The error that caused the disconnection, when there is one.\n */\n disconnect: (error?: Error) => Awaitable;\n /**\n * Emitted when an error occurs while playing the audio.\n * @param error - The error\n */\n error: (error: Error) => Awaitable;\n /**\n * Emitted when the audio player becomes idle, i.e. the song is finished.\n */\n finish: () => Awaitable;\n /**\n * Emitted when the connection moves to another voice channel.\n * @param oldChannel - The previous voice channel\n * @param newChannel - The new voice channel\n */\n channelChange: (oldChannel: VoiceBasedChannel, newChannel: VoiceBasedChannel) => Awaitable;\n};\n\n/**\n * An FFmpeg audio filter object\n * ```ts\n * {\n * name: \"bassboost\",\n * value: \"bass=g=10\"\n * }\n * ```ts\n */\nexport interface Filter {\n /**\n * Name of the filter\n */\n name: string;\n /**\n * FFmpeg audio filter argument\n */\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 * @see {@link defaultFilters}\n * @see {@link DisTubeOptions|DisTubeOptions.customFilters}\n */\nexport type FilterResolvable = string | Filter;\n\n/**\n * FFmpeg Filters\n * ```ts\n * {\n * \"Filter Name\": \"Filter Value\",\n * \"bassboost\": \"bass=g=10\"\n * }\n * ```\n * @see {@link defaultFilters}\n */\nexport type Filters = Record<string, string>;\n\n/**\n * The validated {@link DisTubeOptions.preload} options of a {@link DisTube} instance.\n */\nexport type PreloadOptions = {\n /**\n * Whether or not preloading is enabled.\n */\n enabled: boolean;\n /**\n * The number of seconds remaining in the currently playing song before\n * preloading starts.\n */\n threshold: number;\n};\n\n/**\n * The validated {@link DisTubeOptions.crossfade} options of a {@link DisTube}\n * instance.\n */\nexport type CrossfadeOptions = {\n /**\n * The default crossfade duration (in seconds) applied to new queues. `0`\n * disables the crossfade. A {@link Queue} can override it at runtime through\n * its `crossfade` property.\n */\n duration: number;\n /**\n * The FFmpeg `acrossfade` fade curve applied to both sides of the transition.\n * @default \"qsin\" (equal-power)\n */\n curve: string;\n /**\n * How long (in seconds) before the fade window begins the merged transition\n * stream is spawned, so its buffers are warm and the fade starts on time.\n * @default 5\n */\n warmup: number;\n};\n\n/**\n * DisTube options\n */\nexport type DisTubeOptions = {\n /**\n * DisTube plugins.\n * The order of this effects the priority of the plugins when verifying the input.\n */\n plugins?: DisTubePlugin[];\n /**\n * Whether or not emitting {@link Events.PLAY_SONG} event when looping a song\n * or next song is the same as the previous one\n * @default false\n */\n emitNewSongOnly?: boolean;\n /**\n * Whether or not saving the previous songs of the queue and enable {@link\n * Queue#previous} method. Disable it may help to reduce the memory usage\n * @default true\n */\n savePreviousSongs?: boolean;\n /**\n * Override {@link defaultFilters} or add more ffmpeg filters\n */\n customFilters?: Filters;\n /**\n * Whether or not playing age-restricted content and disabling safe search in\n * non-NSFW channel\n * @default false\n */\n nsfw?: boolean;\n /**\n * Whether or not emitting `addSong` event when creating a new Queue\n * @default true\n */\n emitAddSongWhenCreatingQueue?: boolean;\n /**\n * Whether or not emitting `addList` event when creating a new Queue\n * @default true\n */\n emitAddListWhenCreatingQueue?: boolean;\n /**\n * Whether or not joining the new voice channel when using {@link DisTube#play}\n * method\n * @default true\n */\n joinNewVoiceChannel?: boolean;\n /**\n * Behavior when the {@link Events.ERROR} event is emitted but nobody listens to it.\n *\n * By default (`\"log\"`), the error is logged to the console instead of crashing the\n * process, which is the Node.js default behavior for the special `\"error\"` event.\n * @default \"log\"\n */\n unhandledError?: UnhandledErrorBehavior;\n /**\n * Time (in milliseconds) a track may stay in the \"buffering\" state before it is\n * considered stuck and gets skipped automatically.\n *\n * Set to `0` to disable the stuck-track detection.\n * @default 10000\n */\n stuckThreshold?: number;\n /**\n * Pre-fetch stream information and prepare the stream for the next song in\n * the queue before the current song finishes playing, to reduce the delay\n * between two songs.\n *\n * Can be a simple `boolean` to toggle it with the default threshold, or an\n * object to configure it:\n * - `enabled`: whether or not preloading is enabled (@default false)\n * - `threshold`: the number of seconds remaining in the currently playing\n * song before preloading starts (@default 15)\n * @default false\n */\n preload?:\n | boolean\n | {\n /**\n * Whether or not preloading is enabled.\n */\n enabled?: boolean;\n /**\n * The number of seconds remaining in the currently playing song before\n * preloading starts.\n */\n threshold?: number;\n };\n /**\n * Crossfade the end of the current song with the beginning of the next one,\n * instead of a hard switch between two streams.\n *\n * The transition is a single FFmpeg process that mixes both songs with an\n * `acrossfade` filter, so the fade is seamless (no gaps, no extra decode\n * round-trips). Because the fade length must be prepared in advance, the\n * next song's stream is resolved even when preloading is disabled.\n *\n * Can be an object to configure it:\n * - `duration`: the default crossfade duration in seconds for new queues\n * (@default 0). Each {@link Queue} can override it at runtime with its\n * `crossfade` property, which is what bots typically bind to a guild\n * setting.\n * - `curve`: the FFmpeg `acrossfade` fade curve (@default \"qsin\")\n * - `warmup`: seconds before the fade window when the transition stream is\n * spawned to warm up its buffers (@default 5)\n * @default { duration: 0, curve: \"qsin\", warmup: 5 }\n */\n crossfade?: {\n /**\n * The default crossfade duration (in seconds) for new queues (0 disables).\n */\n duration?: number;\n /**\n * The FFmpeg `acrossfade` fade curve applied to both songs.\n */\n curve?: string;\n /**\n * Seconds before the fade window when the transition stream is spawned.\n */\n warmup?: number;\n };\n /**\n * FFmpeg options\n */\n ffmpeg?: {\n /**\n * FFmpeg path\n */\n path?: string;\n /**\n * FFmpeg default arguments\n */\n args?: Partial<FFmpegArgs>;\n };\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\n * | BaseGuildVoiceChannel}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/BaseGuildTextChannel\n * | BaseGuildTextChannel}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/VoiceState |\n * VoiceState}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/GuildMember |\n * GuildMember}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/Interaction |\n * Interaction}\n * - A {@link DisTubeVoice}\n * - A {@link Queue}\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\n/**\n * The raw information of a song.\n *\n * It is the input of the {@link Song} constructor: a plugin builds it from\n * the data of its source.\n */\nexport interface SongInfo<T = unknown> {\n /**\n * The plugin that created this song, or `null` when it was created manually.\n */\n plugin: DisTubePlugin | null;\n /**\n * The identifier of the source of the song, e.g. `my-source`.\n */\n source: string;\n /**\n * Whether the song can be streamed directly from its source.\n *\n * When it is `false`, DisTube looks for a playable version of the song with\n * the other plugins.\n */\n playFromSource: boolean;\n /**\n * The identifier of the song in its source.\n */\n id: string;\n /**\n * The name of the song.\n */\n name?: string;\n /**\n * Whether the song is a live stream.\n */\n isLive?: boolean;\n /**\n * The duration of the song, in seconds.\n */\n duration?: number;\n /**\n * The URL of the song.\n */\n url?: string;\n /**\n * The URL of the thumbnail of the song.\n */\n thumbnail?: string;\n /**\n * The number of views of the song.\n */\n views?: number;\n /**\n * The number of likes of the song.\n */\n likes?: number;\n /**\n * The number of dislikes of the song.\n */\n dislikes?: number;\n /**\n * The number of reposts (shares) of the song.\n */\n reposts?: number;\n /**\n * The uploader (the author, the channel, ...) of the song.\n */\n uploader?: {\n /**\n * The name of the uploader.\n */\n name?: string;\n /**\n * The URL of the uploader.\n */\n url?: string;\n };\n /**\n * Whether the song is age-restricted.\n */\n ageRestricted?: boolean;\n /**\n * Source specific metadata of the song.\n *\n * It is used by the plugin that created the song to keep the data it needs to\n * play it (stream url, identifiers, ...). It is ignored when the song is\n * created with a `metadata` option.\n */\n metadata?: T;\n}\n\n/**\n * The raw information of a playlist.\n *\n * It is the input of the {@link Playlist} constructor: a plugin builds it from\n * the data of its source.\n */\nexport interface PlaylistInfo {\n /**\n * The identifier of the source of the playlist, e.g. `my-source`.\n */\n source: string;\n /**\n * The songs of the playlist.\n */\n songs: Song[];\n /**\n * The identifier of the playlist in its source.\n */\n id?: string;\n /**\n * The name of the playlist.\n */\n name?: string;\n /**\n * The URL of the playlist.\n */\n url?: string;\n /**\n * The URL of the thumbnail of the playlist.\n */\n thumbnail?: string;\n}\n\n/**\n * A song that is related to another song.\n *\n * It is the same as a {@link Song}, without the `related` property of the\n * previous versions of DisTube.\n */\nexport type RelatedSong = Omit<Song, \"related\">;\n\n/**\n * The options of the handler of a song or a playlist.\n */\nexport type PlayHandlerOptions = {\n /**\n * [Default: false] Skip the playing song (if exists) and play the added playlist\n * instantly\n */\n skip?: boolean;\n /**\n * [Default: 0] Position of the song/playlist to add to the queue, \\<= 0 to add to\n * the end of the queue\n */\n position?: number;\n /**\n * The default text channel of the queue\n */\n textChannel?: GuildTextBasedChannel;\n};\n\n/**\n * The options of a jump in the queue.\n */\nexport interface JumpOptions {\n /**\n * [Default: false] Whether or not skipped song(s) will be added to the end of the\n * queue\n */\n requeue?: boolean;\n}\n\n/**\n * The options of {@link DisTube#play}.\n */\nexport interface PlayOptions<T = unknown> extends PlayHandlerOptions, ResolveOptions<T> {\n /**\n * The message that triggered the command.\n *\n * It is used as the default {@link PlayHandlerOptions.textChannel} of the queue\n * when no `textChannel` is provided.\n */\n message?: Message;\n}\n\n/**\n * The kind of result a search is looking for.\n */\nexport enum SearchResultType {\n /**\n * A single track, i.e. a song.\n */\n TRACK = \"track\",\n /**\n * A video, i.e. a song with a video.\n */\n VIDEO = \"video\",\n /**\n * A playlist of songs.\n */\n PLAYLIST = \"playlist\",\n /**\n * An album of songs.\n */\n ALBUM = \"album\",\n /**\n * The songs of an artist.\n */\n ARTIST = \"artist\",\n}\n\n/**\n * The options of the resolution of a song or a playlist.\n */\nexport interface ResolveOptions<T = unknown> {\n /**\n * Requested user\n */\n member?: GuildMember;\n /**\n * Metadata\n */\n metadata?: T;\n /**\n * The source to resolve the input in.\n *\n * It matches the {@link Plugin.source} of a plugin, or one of its\n * {@link Plugin.aliases}. When it is not given, every plugin is used.\n */\n source?: string;\n}\n\n/**\n * Options of a search.\n */\nexport interface SearchOptions<T = unknown> extends ResolveOptions<T> {\n /**\n * [Default: 10] Maximum number of results.\n */\n limit?: number;\n /**\n * The kind of result the caller is looking for.\n */\n type?: SearchResultType;\n /**\n * Whether or not filtering the explicit content.\n */\n safeSearch?: boolean;\n}\n\n/**\n * The options of the resolution of a playlist.\n */\nexport interface ResolvePlaylistOptions<T = unknown> extends ResolveOptions<T> {\n /**\n * Source of the playlist\n */\n source?: string;\n}\n\n/**\n * The options of a custom playlist.\n */\nexport interface CustomPlaylistOptions {\n /**\n * A guild member creating the playlist\n */\n member?: GuildMember;\n /**\n * Whether or not fetch the songs in parallel\n */\n parallel?: boolean;\n /**\n * Metadata\n */\n metadata?: any;\n /**\n * Playlist name\n */\n name?: string;\n /**\n * Playlist source\n */\n source?: string;\n /**\n * Playlist url\n */\n url?: string;\n /**\n * Playlist thumbnail\n */\n thumbnail?: string;\n}\n\n/**\n * The repeat mode of a {@link Queue}\n */\nexport enum RepeatMode {\n /**\n * The queue plays every song once. `0`.\n */\n DISABLED,\n /**\n * The queue repeats the current song. `1`.\n */\n SONG,\n /**\n * The queue repeats the whole queue. `2`.\n */\n QUEUE,\n}\n\n/**\n * All available plugin types:\n */\nexport enum PluginType {\n /**\n * A plugin that extracts, searches and plays the songs of its source.\n * `\"extractor\"`: {@link ExtractorPlugin}\n */\n EXTRACTOR = \"extractor\",\n /**\n * A plugin that only extracts the info of the links of its source.\n * `\"info-extractor\"`: {@link InfoExtractorPlugin}\n */\n INFO_EXTRACTOR = \"info-extractor\",\n /**\n * A plugin that extracts and plays the songs of its source, but cannot\n * search for them. `\"playable-extractor\"`: {@link PlayableExtractorPlugin}\n */\n PLAYABLE_EXTRACTOR = \"playable-extractor\",\n}\n\n/**\n * Every kind of plugin DisTube can use.\n *\n * - {@link ExtractorPlugin}\n * - {@link InfoExtractorPlugin}\n * - {@link PlayableExtractorPlugin}\n */\nexport type DisTubePlugin = ExtractorPlugin | InfoExtractorPlugin | PlayableExtractorPlugin;\n\n/**\n * A FFmpeg argument.\n *\n * The value is the argument itself (`\"-1\"`), or an array of the values of a\n * repeatable argument (`[\"-1\", \"-2\"]`).\n */\nexport type FFmpegArg = Record<string, string | number | boolean | Array<string | null | undefined> | null | undefined>;\n\n/**\n * FFmpeg arguments for different use cases\n */\nexport type FFmpegArgs = {\n /**\n * The arguments that are applied to the FFmpeg process itself.\n */\n global: FFmpegArg;\n /**\n * The arguments that are applied to the input of the FFmpeg process.\n */\n input: FFmpegArg;\n /**\n * The arguments that are applied to the output of the FFmpeg process.\n *\n * The `af` argument is replaced by the filters of the {@link Queue}.\n */\n output: FFmpegArg;\n};\n\n/**\n * FFmpeg options\n */\nexport type FFmpegOptions = {\n /**\n * Path to the ffmpeg executable\n * @default \"ffmpeg\"\n */\n path: string;\n /**\n * Arguments\n */\n args: FFmpegArgs;\n};\n","class Task {\n resolve!: () => void;\n promise: Promise<void>;\n isPlay: boolean;\n constructor(isPlay: boolean) {\n this.isPlay = isPlay;\n this.promise = new Promise<void>(res => {\n this.resolve = res;\n });\n }\n}\n\n/**\n * Task queuing system\n *\n * It makes sure that the tasks of a {@link Queue} are processed one after the\n * other, instead of all at the same time.\n */\nexport class TaskQueue {\n /**\n * The task array\n */\n #tasks: Task[] = [];\n\n /**\n * Waits for last task finished and queues a new task\n * @param isPlay - Whether the task is a play task\n * @returns A promise that resolves when the last queued task is finished\n */\n queuing(isPlay = false): Promise<void> {\n const next = this.remaining ? this.#tasks[this.#tasks.length - 1].promise : Promise.resolve();\n this.#tasks.push(new Task(isPlay));\n return next;\n }\n\n /**\n * Removes the finished task and processes the next task\n * @returns Nothing\n */\n resolve(): void {\n this.#tasks.shift()?.resolve();\n }\n\n /**\n * The remaining number of tasks\n */\n get remaining(): number {\n return this.#tasks.length;\n }\n\n /**\n * Whether or not having a play task\n */\n get hasPlayTask(): boolean {\n return this.#tasks.some(t => t.isPlay);\n }\n}\n","import type { GuildTextBasedChannel, Snowflake } from \"discord.js\";\nimport { DEFAULT_VOLUME, MAX_CROSSFADE_DURATION_SECS } from \"../constant\";\nimport { DisTubeBase } from \"../core/DisTubeBase\";\nimport type { DisTubeStream } from \"../core/DisTubeStream\";\nimport type { DisTubeVoice } from \"../core/DisTubeVoice\";\nimport { FilterManager } from \"../core/manager/FilterManager\";\nimport type { DisTube } from \"../DisTube\";\nimport type { DisTubeVoiceEvents, FFmpegArgs, JumpOptions } from \"../type\";\nimport { Events, RepeatMode } from \"../type\";\nimport { formatDuration, objectKeys } from \"../util\";\nimport { DisTubeError } from \"./DisTubeError\";\nimport type { Song } from \"./Song\";\nimport { TaskQueue } from \"./TaskQueue\";\n\n/**\n * Represents a queue.\n */\nexport class Queue extends DisTubeBase {\n /**\n * Queue id (Guild id)\n */\n readonly id: Snowflake;\n /**\n * Voice connection of this queue.\n */\n voice: DisTubeVoice;\n /**\n * List of songs in the queue (The first one is the playing song)\n */\n songs: Song[];\n /**\n * List of the previous songs.\n */\n previousSongs: Song[];\n /**\n * Whether stream is currently stopped.\n */\n stopped: boolean;\n /**\n * Whether or not the stream is currently paused.\n *\n * It is also `true` once the queue has been stopped, so that `!queue.paused`\n * stays `false` as soon as the queue is not playing anymore.\n */\n paused: boolean;\n /**\n * Type of repeat mode (`0` is disabled, `1` is repeating a song, `2` is repeating\n * all the queue). Default value: `0` (disabled)\n */\n repeatMode: RepeatMode;\n /**\n * Whether or not the autoplay mode is enabled. Default value: `false`\n */\n autoplay: boolean;\n /**\n * FFmpeg arguments for the current queue. Default value is defined with {@link DisTubeOptions}.ffmpeg.args.\n * `af` output argument will be replaced with {@link Queue#filters} manager\n */\n ffmpegArgs: FFmpegArgs;\n /**\n * The text channel of the Queue. (Default: where the first command is called).\n */\n textChannel?: GuildTextBasedChannel;\n /**\n * What time in the song to begin (in seconds).\n * @internal\n */\n _beginTime: number;\n #filters: FilterManager;\n #initialized = false;\n /**\n * Whether or not the queue is being updated manually (skip, jump, previous)\n * @internal\n */\n _manualUpdate: boolean;\n /**\n * Task queuing system\n * @internal\n */\n _taskQueue: TaskQueue;\n /**\n * {@link DisTubeVoice} listener\n * @internal\n */\n _listeners?: DisTubeVoiceEvents;\n /**\n * Preload timer\n * @internal\n */\n _preloadTimeout?: NodeJS.Timeout;\n /**\n * Preloaded song\n * @internal\n */\n _preloadedSong?: Song;\n /**\n * Preloaded stream\n * @internal\n */\n _preloadedStream?: DisTubeStream;\n /**\n * In-flight preload task\n * @internal\n */\n _preloading?: Promise<void>;\n /**\n * Bumped whenever the preloaded state is invalidated, so an in-flight\n * preload task can detect that its result is no longer needed.\n * @internal\n */\n _preloadGeneration = 0;\n #crossfade: number;\n /**\n * Crossfade boundary timer\n * @internal\n */\n _crossfadeTimeout?: NodeJS.Timeout;\n /**\n * The merged transition stream that is warming up before the fade window\n * starts\n * @internal\n */\n _crossfadeWarmup?: DisTubeStream;\n /**\n * Clear any preloaded song and cancel pending preload timer.\n * @internal\n */\n _clearPreload() {\n this._crossfadeCancel();\n this._preloadGeneration++;\n if (this._preloadTimeout) {\n clearTimeout(this._preloadTimeout);\n this._preloadTimeout = undefined;\n }\n if (this._preloadedStream) {\n this._preloadedStream.kill();\n this._preloadedStream = undefined;\n }\n this._preloadedSong = undefined;\n }\n /**\n * Cancel a pending crossfade and kill its warming-up transition stream.\n * @internal\n */\n _crossfadeCancel() {\n if (this._crossfadeTimeout) {\n clearTimeout(this._crossfadeTimeout);\n this._crossfadeTimeout = undefined;\n }\n if (this._crossfadeWarmup) {\n this._crossfadeWarmup.kill();\n this._crossfadeWarmup = undefined;\n }\n }\n /**\n * Create a queue for the guild\n * @param distube - DisTube\n * @param voice - Voice connection\n * @param textChannel - Default text channel\n */\n constructor(distube: DisTube, voice: DisTubeVoice, textChannel?: GuildTextBasedChannel) {\n super(distube);\n this.voice = voice;\n this.id = voice.id;\n this.volume = DEFAULT_VOLUME;\n this.songs = [];\n this.previousSongs = [];\n this.stopped = false;\n this._manualUpdate = false;\n this.paused = false;\n this.repeatMode = RepeatMode.DISABLED;\n this.autoplay = false;\n this.#filters = new FilterManager(this);\n this._beginTime = 0;\n this.textChannel = textChannel;\n this._taskQueue = new TaskQueue();\n this._listeners = undefined;\n this.ffmpegArgs = {\n global: { ...this.options.ffmpeg.args.global },\n input: { ...this.options.ffmpeg.args.input },\n output: { ...this.options.ffmpeg.args.output },\n };\n // Defensive: mocked/embedded options may not carry the crossfade block.\n this.#crossfade = Number(this.options.crossfade?.duration) || 0;\n this.#initialized = true;\n }\n #addToPreviousSongs(songs: Song | Song[]) {\n if (Array.isArray(songs)) {\n if (this.options.savePreviousSongs) {\n this.previousSongs.push(...songs);\n } else {\n this.previousSongs.push(...songs.map(s => ({ id: s.id }) as Song));\n }\n } else if (this.options.savePreviousSongs) {\n this.previousSongs.push(songs);\n } else {\n this.previousSongs.push({ id: songs.id } as Song);\n }\n }\n #stop() {\n this._manualUpdate = true;\n this.voice.stop();\n }\n /**\n * The client user as a `GuildMember` of this queue's guild\n */\n get clientMember() {\n return this.voice.channel.guild.members.me ?? undefined;\n }\n /**\n * The filter manager of the queue\n */\n get filters() {\n return this.#filters;\n }\n /**\n * Whether or not the queue is still active.\n *\n * It is `false` only when the queue has been stopped. A paused queue is still\n * active.\n */\n get isActive(): boolean {\n return !this.stopped;\n }\n /**\n * Formatted duration string.\n */\n get formattedDuration() {\n return formatDuration(this.duration);\n }\n /**\n * Queue's duration.\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 */\n get currentTime() {\n return this.voice.playbackTime;\n }\n /**\n * The crossfade duration (in seconds) between this song and the next one.\n *\n * `0` (the default) disables the crossfade. Changing it takes effect for the\n * next transition; call {@link Queue#scheduleCrossfade} to re-arm the\n * transition for the currently playing song immediately.\n * @throws {@link DisTubeError} When the value is not a number between `0`\n * and the maximum crossfade duration\n */\n get crossfade(): number {\n return this.#crossfade;\n }\n set crossfade(value: number) {\n if (typeof value !== \"number\" || Number.isNaN(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", value, \"Queue.crossfade\");\n }\n if (value < 0) throw new DisTubeError(\"NUMBER_COMPARE\", \"Crossfade\", \"bigger or equal to\", 0);\n if (value > MAX_CROSSFADE_DURATION_SECS) {\n throw new DisTubeError(\"NUMBER_COMPARE\", \"Crossfade\", \"smaller or equal to\", MAX_CROSSFADE_DURATION_SECS);\n }\n this.#crossfade = value;\n }\n /**\n * Formatted {@link Queue#currentTime} string.\n */\n get formattedCurrentTime() {\n return formatDuration(this.currentTime);\n }\n /**\n * The voice channel playing in.\n */\n get voiceChannel() {\n return this.clientMember?.voice?.channel ?? null;\n }\n /**\n * Get or set the stream volume. Default value: `50`.\n */\n get volume() {\n return this.voice.volume;\n }\n /**\n * Set the stream volume.\n * @param value - The volume percentage, from `0` to `100`\n * @throws {@link DisTubeError} When the volume is not a number, or when it is\n * negative\n */\n set volume(value: number) {\n const oldVolume = this.voice.volume;\n this.voice.volume = value;\n if (this.#initialized && oldVolume !== value) {\n this.emit(Events.SET_VOLUME, this, value, oldVolume);\n }\n }\n /**\n * Add a song or a list of songs to the queue.\n * @throws {DisTubeError}\n * @param song - Song to add\n * @param position - Position to add, \\<= 0 to add to the end of the queue\n * @returns The guild queue\n * @example\n * ```ts\n * queue.addToQueue(song);\n * ```\n */\n addToQueue(song: Song | Song[], position = 0): Queue {\n if (this.stopped) throw new DisTubeError(\"QUEUE_STOPPED\");\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 this.queues?.schedulePreload?.(this);\n return this;\n }\n /**\n /**\n * Pause the guild stream\n * @returns The guild queue\n * @throws {@link DisTubeError} When the queue is already paused\n * @example\n * ```ts\n * await queue.pause();\n * ```\n */\n async pause(): Promise<Queue> {\n await this._taskQueue.queuing();\n try {\n if (this.paused) throw new DisTubeError(\"PAUSED\");\n this.paused = true;\n // A paused queue cannot know when the preloaded stream is still valid:\n // drop it and let resume() re-schedule a fresh preload.\n this._clearPreload();\n this.voice.pause();\n this.emit(Events.PAUSE_SONG, this, this.songs[0]);\n return this;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Resume the guild stream\n * @returns The guild queue\n * @throws {@link DisTubeError} When the queue is not paused\n * @example\n * ```ts\n * await queue.resume();\n * ```\n */\n async resume(): Promise<Queue> {\n await this._taskQueue.queuing();\n try {\n if (!this.paused) throw new DisTubeError(\"RESUMED\");\n this.paused = false;\n this.voice.unpause();\n this.emit(Events.RESUME_SONG, this, this.songs[0]);\n this.queues?.schedulePreload?.(this);\n this.queues?.scheduleCrossfade?.(this);\n return this;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Set the guild stream's volume\n * @param percent - The percentage of volume you want to set\n * @returns The guild queue\n * @throws {@link DisTubeError} When the volume is not a number, or when it is\n * negative\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. <info>If {@link\n * Queue#autoplay} is `true` and there is no up next song, DisTube will add and\n * play a related song.</info>\n * @param options - Skip options\n * @returns The song will skip to\n * @throws {@link DisTubeError} When there is no up next song, or when the\n * position is out of the bounds of the queue\n * @example\n * ```ts\n * await queue.skip();\n * ```\n */\n async skip(options?: JumpOptions): Promise<Song> {\n return this.jump(1, options);\n }\n\n /**\n * Play the previous song if exists\n * @returns The guild queue\n * @throws {@link DisTubeError} When {@link DisTubeOptions.savePreviousSongs} is\n * disabled, or when the queue does not have any previous song\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 const hasPrevious = this.previousSongs.length > 0;\n if (!hasPrevious && this.repeatMode !== RepeatMode.QUEUE) {\n throw new DisTubeError(\"NO_PREVIOUS\");\n }\n // In repeat-queue mode without any history, the last song of the queue is\n // replayed. It has to be removed from its position, otherwise it would be\n // queued twice.\n const song = hasPrevious ? this.previousSongs.pop() : this.songs.pop();\n if (!song) throw new DisTubeError(\"NO_PREVIOUS\");\n this.songs.unshift(song);\n this.#stop();\n return song;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Shuffle the queue's songs\n * @returns 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 this._clearPreload();\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 this.emit(Events.SHUFFLE_QUEUE, this, this.songs);\n this.queues?.schedulePreload?.(this);\n return this;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Jump to the song position in the queue. The next one is 1, 2,... The previous\n * one is -1, -2,...\n * if `num` is invalid number\n * @param position - The song position to play\n * @param options - Skip options\n * @returns The new Song will be played\n * @throws {@link DisTubeError} When the position is invalid, when there is no\n * up next song, or when {@link DisTubeOptions.savePreviousSongs} is disabled\n * and the jump is backwards\n */\n async jump(position: number, options?: JumpOptions): 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 if (position > 0) {\n if (position >= this.songs.length) {\n if (this.autoplay) {\n await this._addRelatedSong();\n } else {\n throw new DisTubeError(\"NO_UP_NEXT\");\n }\n }\n const skipped = this.songs.splice(0, position);\n if (options?.requeue) {\n this.songs.push(...skipped);\n } else {\n this.#addToPreviousSongs(skipped);\n }\n this.emit(Events.SKIP_SONG, this, skipped[0]);\n } else if (!this.options.savePreviousSongs) {\n throw new DisTubeError(\"DISABLED_OPTION\", \"savePreviousSongs\");\n } else {\n const skipped = this.previousSongs.splice(position);\n this.songs.unshift(...skipped);\n }\n this._clearPreload();\n this.#stop();\n return this.songs[0];\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 mode - The repeat modes (toggle if `undefined`)\n * @returns The new repeat mode\n * @throws {@link DisTubeError} When the mode is not a valid {@link RepeatMode}\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 time - Time in seconds\n * @returns The guild queue\n * @throws {@link DisTubeError} When the time is not a number, or when it is\n * negative\n * @example\n * ```ts\n * await queue.seek(60);\n * ```\n */\n async seek(time: number): Promise<Queue> {\n await this._taskQueue.queuing();\n try {\n if (typeof time !== \"number\") throw new DisTubeError(\"INVALID_TYPE\", \"number\", time, \"time\");\n if (Number.isNaN(time) || time < 0) throw new DisTubeError(\"NUMBER_COMPARE\", \"time\", \"bigger or equal to\", 0);\n this._clearPreload();\n this._beginTime = time;\n await this.play(false);\n this.emit(Events.SEEK_SONG, this, this.songs[0], time);\n return this;\n } finally {\n this._taskQueue.resolve();\n }\n }\n async #getRelatedSong(current: Song): Promise<Song[]> {\n const plugin = await this.handler._getPluginFromSong(current);\n if (plugin) return plugin.getRelatedSongs(current);\n return [];\n }\n /**\n * Internal implementation of addRelatedSong without task queue protection.\n * Used by methods that already hold the task queue lock.\n * @param song - The song to get related songs from. Defaults to the current playing song.\n * @returns A promise that resolves to the added song\n * @throws {@link DisTubeError} When the queue does not have any playing song,\n * or when no related song could be found\n * @internal\n */\n async _addRelatedSong(song?: Song): Promise<Song> {\n const current = song ?? this.songs?.[0];\n if (!current) throw new DisTubeError(\"NO_PLAYING_SONG\");\n const prevIds = this.previousSongs.map(p => p.id);\n const relatedSongs = (await this.#getRelatedSong(current)).filter(s => !prevIds.includes(s.id));\n this.debug(`[${this.id}] Getting related songs from: ${current}`);\n if (!relatedSongs.length && !current.stream.playFromSource) {\n const altSong = current.stream.song;\n if (altSong) relatedSongs.push(...(await this.#getRelatedSong(altSong)).filter(s => !prevIds.includes(s.id)));\n this.debug(`[${this.id}] Getting related songs from streamed song: ${altSong}`);\n }\n const nextSong = relatedSongs[0];\n if (!nextSong) throw new DisTubeError(\"NO_RELATED\");\n nextSong.metadata = current.metadata;\n nextSong.member = this.clientMember;\n this.addToQueue(nextSong);\n return nextSong;\n }\n /**\n * Add a related song of the playing song to the queue\n * @param song - The song to get related songs from. Defaults to the current playing song.\n * @returns The added song\n * @throws {@link DisTubeError} When the queue does not have any playing song,\n * or when no related song could be found\n */\n async addRelatedSong(song?: Song): Promise<Song> {\n await this._taskQueue.queuing();\n try {\n return await this._addRelatedSong(song);\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Stop the guild stream and delete the queue\n * @returns A promise that resolves when the queue is stopped\n */\n async stop() {\n await this._taskQueue.queuing();\n try {\n this.voice.stop();\n this.remove();\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Remove the queue from the manager\n * @returns Nothing\n */\n remove() {\n this._clearPreload();\n this.paused = true;\n this.stopped = true;\n this.songs = [];\n this.previousSongs = [];\n if (this._listeners) for (const event of objectKeys(this._listeners)) this.voice.off(event, this._listeners[event]);\n this.queues.remove(this.id);\n this.emit(Events.DELETE_QUEUE, this);\n }\n /**\n * Toggle autoplay mode\n * @returns Autoplay mode state\n */\n toggleAutoplay(): boolean {\n this.autoplay = !this.autoplay;\n return this.autoplay;\n }\n /**\n * Play the first song in the queue\n * @param emitPlaySong - Whether or not emit {@link Events.PLAY_SONG} event\n * @returns A promise that resolves when the song is playing\n * @throws {@link DisTubeError} When the queue has been stopped\n */\n play(emitPlaySong = true) {\n if (this.stopped) throw new DisTubeError(\"QUEUE_STOPPED\");\n return this.queues.playSong(this, emitPlaySong);\n }\n /**\n * Re-arm the crossfade into the next song for the currently playing one.\n *\n * Useful after changing {@link Queue#crossfade} while a song is playing: the\n * fade may still fit into the remaining time. This is called automatically\n * after every song switch.\n * @returns Nothing\n */\n scheduleCrossfade() {\n this.queues.scheduleCrossfade(this);\n }\n /**\n * Restart the current stream with the current FFmpeg arguments, keeping the\n * playback position.\n *\n * The FFmpeg audio filters are applied when the stream is created, so the stream\n * has to be recreated whenever the filters change.\n *\n * Unlike a regular playback error, a failure while restarting the stream does\n * **not** remove the current song from the queue.\n * @returns A promise that resolves when the stream is restarted\n * @internal\n */\n async _restartStream(): Promise<void> {\n await this._taskQueue.queuing(true);\n try {\n if (this.stopped || !this.songs.length) return;\n this._beginTime = this.currentTime;\n await this.queues.playSong(this, false, { keepSongOnError: true });\n } finally {\n this._taskQueue.resolve();\n }\n }\n}\n","import type { GuildMember } from \"discord.js\";\nimport type { PlaylistInfo, ResolveOptions } from \"../type\";\nimport { formatDuration, isMemberInstance } from \"../util\";\nimport { DisTubeError } from \"./DisTubeError\";\nimport type { Song } from \"./Song\";\n\n/**\n * Class representing a playlist.\n */\nexport class Playlist<T = unknown> implements PlaylistInfo {\n /**\n * Playlist source.\n */\n source: string;\n /**\n * Songs in the playlist.\n */\n songs: Song[];\n /**\n * Playlist ID.\n */\n id?: string;\n /**\n * Playlist name.\n */\n name?: string;\n /**\n * Playlist URL.\n */\n url?: string;\n /**\n * Playlist thumbnail.\n */\n thumbnail?: string;\n #metadata!: T;\n #member?: GuildMember;\n /**\n * Create a Playlist\n * @param playlist - Raw playlist info\n * @param options - Optional data\n * @param options.member - The user that requested the playlist\n * @param options.metadata - The metadata of the playlist\n * @throws {@link DisTubeError} When the playlist does not have any song\n */\n constructor(playlist: PlaylistInfo, { member, metadata }: ResolveOptions<T> = {}) {\n if (!Array.isArray(playlist.songs) || !playlist.songs.length) throw new DisTubeError(\"EMPTY_PLAYLIST\");\n\n this.source = playlist.source.toLowerCase();\n this.songs = playlist.songs;\n this.name = playlist.name;\n this.id = playlist.id;\n this.url = playlist.url;\n this.thumbnail = playlist.thumbnail;\n this.member = member;\n this.songs.forEach(s => (s.playlist = this));\n this.metadata = metadata as T;\n }\n\n /**\n * Playlist duration in second.\n */\n get duration() {\n return this.songs.reduce((prev, next) => prev + next.duration, 0);\n }\n\n /**\n * Formatted duration string `hh:mm:ss`.\n */\n get formattedDuration() {\n return formatDuration(this.duration);\n }\n\n /**\n * User requested.\n */\n get member() {\n return this.#member;\n }\n\n /**\n * Set the user that requested the playlist.\n *\n * The value is ignored when it is not a valid guild member.\n * @param member - The member\n */\n set member(member: GuildMember | undefined) {\n if (!isMemberInstance(member)) return;\n this.#member = member;\n this.songs.forEach(s => (s.member = this.member));\n }\n\n /**\n * User requested.\n */\n get user() {\n return this.member?.user;\n }\n\n /**\n * Optional metadata that can be used to identify the playlist.\n */\n get metadata() {\n return this.#metadata;\n }\n\n /**\n * Set the metadata of the playlist.\n *\n * The metadata of the songs is not changed when the metadata is `undefined`.\n * @param metadata - The metadata\n */\n set metadata(metadata: T) {\n this.#metadata = metadata;\n // Do not wipe the metadata of the songs when there is no metadata:\n // the songs may carry their own source specific metadata (stream url,\n // identifiers, ...) that the plugin needs to play them.\n if (metadata === undefined) return;\n this.songs.forEach(s => (s.metadata = metadata));\n }\n\n /**\n * The name of the playlist and the number of its songs.\n * @returns The string representation of the playlist\n */\n toString() {\n return `${this.name} (${this.songs.length} songs)`;\n }\n}\n","import type { GuildMember } from \"discord.js\";\nimport type { DisTubePlugin, ResolveOptions, SongInfo } from \"../type\";\nimport { formatDuration, isMemberInstance } from \"../util\";\nimport { DisTubeError } from \"./DisTubeError\";\nimport { Playlist } from \"./Playlist\";\n\n/**\n * Class representing a song.\n */\nexport class Song<T = unknown> {\n /**\n * The source of this song info\n */\n source: string;\n /**\n * Song ID.\n */\n id: string;\n /**\n * Song name.\n */\n name?: string;\n /**\n * Indicates if the song is an active live.\n */\n isLive?: boolean;\n /**\n * Song duration.\n */\n duration: number;\n /**\n * Formatted duration string (`hh:mm:ss`, `mm:ss` or `Live`).\n */\n formattedDuration: string;\n /**\n * Song URL.\n */\n url?: string;\n /**\n * Song thumbnail.\n */\n thumbnail?: string;\n /**\n * Song view count\n */\n views?: number;\n /**\n * Song like count\n */\n likes?: number;\n /**\n * Song dislike count\n */\n dislikes?: number;\n /**\n * Song repost (share) count\n */\n reposts?: number;\n /**\n * Song uploader\n */\n uploader: {\n /**\n * The name of the uploader.\n */\n name?: string;\n /**\n * The URL of the uploader.\n */\n url?: string;\n };\n /**\n * Whether or not an age-restricted content\n */\n ageRestricted?: boolean;\n /**\n * Stream info\n */\n stream:\n | {\n /**\n * The stream of this song will be played from source\n */\n playFromSource: true;\n /**\n * Stream URL of this song\n */\n url?: string;\n }\n | {\n /**\n * The stream of this song will be played from another song\n */\n playFromSource: false;\n /**\n * The song that this song will be played from\n */\n song?: Song<T>;\n };\n /**\n * The plugin that created this song\n */\n plugin: DisTubePlugin | null;\n #metadata!: T;\n #member?: GuildMember;\n #playlist?: Playlist;\n /**\n * Create a Song\n *\n * @param info - Raw song info\n * @param options - Optional data\n * @param options.member - The user that requested the song\n * @param options.metadata - The metadata of the song\n */\n constructor(info: SongInfo<T>, { member, metadata }: ResolveOptions<T> = {}) {\n this.source = info.source.toLowerCase();\n this.metadata = (metadata ?? info.metadata) as T;\n this.member = member;\n this.id = info.id;\n this.name = info.name;\n this.isLive = info.isLive;\n this.duration = this.isLive || !info.duration ? 0 : info.duration;\n this.formattedDuration = this.isLive ? \"Live\" : formatDuration(this.duration);\n this.url = info.url;\n this.thumbnail = info.thumbnail;\n this.views = info.views;\n this.likes = info.likes;\n this.dislikes = info.dislikes;\n this.reposts = info.reposts;\n this.uploader = {\n name: info.uploader?.name,\n url: info.uploader?.url,\n };\n this.ageRestricted = info.ageRestricted;\n // A plugin that cannot play its own songs never has a stream: its songs are\n // resolved to a playable version by another plugin.\n this.stream = { playFromSource: info.playFromSource && info.plugin?.playable !== false };\n this.plugin = info.plugin;\n }\n\n /**\n * The playlist this song belongs to\n */\n get playlist() {\n return this.#playlist;\n }\n\n /**\n * Set the playlist this song belongs to.\n * @param playlist - The playlist\n * @throws {@link DisTubeError} When the value is not a {@link Playlist}\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 to play this song.\n */\n get member() {\n return this.#member;\n }\n\n /**\n * Set the user that requested this song.\n *\n * The value is ignored when it is not a valid guild member.\n * @param member - The member\n */\n set member(member: GuildMember | undefined) {\n if (isMemberInstance(member)) this.#member = member;\n }\n\n /**\n * User requested to play this song.\n */\n get user() {\n return this.member?.user;\n }\n\n /**\n * Optional metadata that can be used to identify the song. This is attached by the\n * {@link DisTube#play} method.\n */\n get metadata() {\n return this.#metadata;\n }\n\n /**\n * Set the metadata of the song.\n * @param metadata - The metadata\n */\n set metadata(metadata: T) {\n this.#metadata = metadata;\n }\n\n /**\n * The name of the song, or its url, or its id.\n * @returns The string representation of the song\n */\n toString() {\n return this.name || this.url || this.id || \"Unknown\";\n }\n}\n","import {\n DEFAULT_CROSSFADE_CURVE,\n DEFAULT_CROSSFADE_DURATION_SECS,\n DEFAULT_CROSSFADE_WARMUP_SECS,\n DEFAULT_PRELOAD_THRESHOLD_SECS,\n defaultOptions,\n MAX_CROSSFADE_DURATION_SECS,\n} from \"../constant\";\nimport { DisTubeError } from \"../struct/DisTubeError\";\nimport type {\n CrossfadeOptions,\n DisTubeOptions,\n DisTubePlugin,\n FFmpegArgs,\n FFmpegOptions,\n Filters,\n PreloadOptions,\n UnhandledErrorBehavior,\n} from \"../type\";\nimport { checkInvalidKey } from \"../util\";\n\nconst UNHANDLED_ERROR_BEHAVIORS: readonly UnhandledErrorBehavior[] = [\"log\", \"throw\", \"ignore\"];\n\n/**\n * The validated options of a {@link DisTube} instance.\n *\n * Every option has a default value, and every option is validated when the\n * instance is created.\n */\nexport class Options {\n /**\n * The plugins of the DisTube instance.\n */\n plugins: DisTubePlugin[];\n /**\n * Whether or not the {@link Events.PLAY_SONG} event is emitted when looping a\n * song or when the next song is the same as the previous one.\n * @default false\n */\n emitNewSongOnly: boolean;\n /**\n * Whether or not the previous songs of a {@link Queue} are saved.\n * @default true\n */\n savePreviousSongs: boolean;\n /**\n * The custom FFmpeg audio filters, that override the {@link defaultFilters}.\n */\n customFilters?: Filters;\n /**\n * Whether or not age-restricted content can be played in a non-NSFW channel.\n * @default false\n */\n nsfw: boolean;\n /**\n * Whether or not the {@link Events.ADD_SONG} event is emitted when a new\n * {@link Queue} is created.\n * @default true\n */\n emitAddSongWhenCreatingQueue: boolean;\n /**\n * Whether or not the {@link Events.ADD_LIST} event is emitted when a new\n * {@link Queue} is created.\n * @default true\n */\n emitAddListWhenCreatingQueue: boolean;\n /**\n * Whether or not the bot joins the new voice channel when\n * {@link DisTube#play} is used.\n * @default true\n */\n joinNewVoiceChannel: boolean;\n /**\n * The behavior of the {@link Events.ERROR} event when it has no listener.\n * @default \"log\"\n */\n unhandledError: UnhandledErrorBehavior;\n /**\n * The time (in milliseconds) a track may stay in the \"buffering\" state before\n * it is considered stuck and gets skipped.\n *\n * Set to `0` to disable the stuck-track detection.\n * @default 10000\n */\n stuckThreshold: number;\n /**\n * The preload options of the DisTube instance.\n * @default { enabled: false, threshold: 15 }\n */\n preload: PreloadOptions;\n /**\n * The crossfade options of the DisTube instance.\n * @default { duration: 0, curve: \"qsin\", warmup: 5 }\n */\n crossfade: CrossfadeOptions;\n /**\n * The FFmpeg options of the DisTube instance.\n */\n ffmpeg: FFmpegOptions;\n /**\n * Create the options of a {@link DisTube} instance.\n * @param options - The options given by the user\n * @throws {@link DisTubeError} When an option has an invalid type, or when it\n * is not a known option\n */\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.savePreviousSongs = opts.savePreviousSongs;\n this.customFilters = opts.customFilters;\n this.nsfw = opts.nsfw;\n this.emitAddSongWhenCreatingQueue = opts.emitAddSongWhenCreatingQueue;\n this.emitAddListWhenCreatingQueue = opts.emitAddListWhenCreatingQueue;\n this.joinNewVoiceChannel = opts.joinNewVoiceChannel;\n this.unhandledError = opts.unhandledError;\n this.stuckThreshold = opts.stuckThreshold;\n this.preload = this.#preloadOption(opts.preload);\n this.crossfade = this.#crossfadeOption(opts.crossfade);\n this.ffmpeg = this.#ffmpegOption(options);\n checkInvalidKey(opts, this, \"DisTubeOptions\");\n this.#validateOptions();\n }\n\n #preloadOption(value: DisTubeOptions[\"preload\"]): PreloadOptions {\n if (value === undefined || value === false) {\n return { enabled: false, threshold: DEFAULT_PRELOAD_THRESHOLD_SECS };\n }\n if (value === true) {\n return { enabled: true, threshold: DEFAULT_PRELOAD_THRESHOLD_SECS };\n }\n if (typeof value !== \"object\" || Array.isArray(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", [\"boolean\", \"object\"], value, \"DisTubeOptions.preload\");\n }\n checkInvalidKey(value, [\"enabled\", \"threshold\"], \"DisTubeOptions.preload\");\n const { enabled, threshold } = value;\n if (enabled !== undefined && typeof enabled !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", enabled, \"DisTubeOptions.preload.enabled\");\n }\n if (threshold !== undefined && (typeof threshold !== \"number\" || Number.isNaN(threshold) || threshold < 0)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", threshold, \"DisTubeOptions.preload.threshold\");\n }\n return {\n enabled: enabled ?? false,\n threshold: threshold ?? DEFAULT_PRELOAD_THRESHOLD_SECS,\n };\n }\n\n #crossfadeOption(value: DisTubeOptions[\"crossfade\"]): CrossfadeOptions {\n if (value === undefined) {\n return {\n duration: DEFAULT_CROSSFADE_DURATION_SECS,\n curve: DEFAULT_CROSSFADE_CURVE,\n warmup: DEFAULT_CROSSFADE_WARMUP_SECS,\n };\n }\n if (typeof value !== \"object\" || Array.isArray(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", value, \"DisTubeOptions.crossfade\");\n }\n checkInvalidKey(value, [\"duration\", \"curve\", \"warmup\"], \"DisTubeOptions.crossfade\");\n const { duration, curve, warmup } = value;\n if (duration !== undefined && (typeof duration !== \"number\" || Number.isNaN(duration) || duration < 0)) {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n `number >= 0 (max ${MAX_CROSSFADE_DURATION_SECS})`,\n duration,\n \"DisTubeOptions.crossfade.duration\",\n );\n }\n if (duration !== undefined && duration > MAX_CROSSFADE_DURATION_SECS) {\n throw new DisTubeError(\n \"NUMBER_COMPARE\",\n \"Crossfade duration\",\n \"smaller or equal to\",\n MAX_CROSSFADE_DURATION_SECS,\n );\n }\n if (curve !== undefined && (typeof curve !== \"string\" || !curve)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"string\", curve, \"DisTubeOptions.crossfade.curve\");\n }\n if (warmup !== undefined && (typeof warmup !== \"number\" || Number.isNaN(warmup) || warmup < 0)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number >= 0\", warmup, \"DisTubeOptions.crossfade.warmup\");\n }\n return {\n duration: duration ?? DEFAULT_CROSSFADE_DURATION_SECS,\n curve: curve ?? DEFAULT_CROSSFADE_CURVE,\n warmup: warmup ?? DEFAULT_CROSSFADE_WARMUP_SECS,\n };\n }\n\n #validateOptions(options = this) {\n const booleanOptions = new Set([\n \"emitNewSongOnly\",\n \"savePreviousSongs\",\n \"joinNewVoiceChannel\",\n \"nsfw\",\n \"emitAddSongWhenCreatingQueue\",\n \"emitAddListWhenCreatingQueue\",\n ]);\n const numberOptions = new Set([\"stuckThreshold\"]);\n const stringOptions = new Set([\"unhandledError\"]);\n const objectOptions = new Set([\"customFilters\", \"ffmpeg\", \"preload\", \"crossfade\"]);\n const optionalOptions = new Set([\"customFilters\"]);\n\n for (const [key, value] of Object.entries(options)) {\n if (value === undefined && optionalOptions.has(key)) continue;\n if (key === \"plugins\" && !Array.isArray(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"Array<Plugin>\", value, `DisTubeOptions.${key}`);\n } else if (booleanOptions.has(key)) {\n if (typeof value !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", value, `DisTubeOptions.${key}`);\n }\n } else if (numberOptions.has(key)) {\n if (typeof value !== \"number\" || Number.isNaN(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", value, `DisTubeOptions.${key}`);\n }\n } else if (stringOptions.has(key)) {\n if (typeof value !== \"string\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"string\", value, `DisTubeOptions.${key}`);\n }\n if (!UNHANDLED_ERROR_BEHAVIORS.includes(value as UnhandledErrorBehavior)) {\n throw new DisTubeError(\"INVALID_TYPE\", UNHANDLED_ERROR_BEHAVIORS, value, `DisTubeOptions.${key}`);\n }\n } else if (objectOptions.has(key)) {\n // `preload` has already been fully validated and normalized in\n // #preloadOption, so a plain object check is enough here.\n if (typeof value !== \"object\" || Array.isArray(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", value, `DisTubeOptions.${key}`);\n }\n }\n }\n }\n\n #ffmpegOption(opts: DisTubeOptions) {\n const args: FFmpegArgs = { global: {}, input: {}, output: {} };\n if (opts.ffmpeg?.args) {\n if (opts.ffmpeg.args.global) args.global = opts.ffmpeg.args.global;\n if (opts.ffmpeg.args.input) args.input = opts.ffmpeg.args.input;\n if (opts.ffmpeg.args.output) args.output = opts.ffmpeg.args.output;\n }\n const path = opts.ffmpeg?.path ?? \"ffmpeg\";\n if (typeof path !== \"string\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"string\", path, \"DisTubeOptions.ffmpeg.path\");\n }\n for (const [key, value] of Object.entries(args)) {\n if (typeof value !== \"object\" || Array.isArray(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", value, `DisTubeOptions.ffmpeg.${key}`);\n }\n for (const [k, v] of Object.entries(value)) {\n if (\n typeof v !== \"string\" &&\n typeof v !== \"number\" &&\n typeof v !== \"boolean\" &&\n !Array.isArray(v) &&\n v !== null &&\n v !== undefined\n ) {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n [\"string\", \"number\", \"boolean\", \"Array<string | null | undefined>\", \"null\", \"undefined\"],\n v,\n `DisTubeOptions.ffmpeg.${key}.${k}`,\n );\n }\n }\n }\n return { path, args };\n }\n}\n","import type { ChildProcess } from \"node:child_process\";\nimport { spawn, spawnSync } from \"node:child_process\";\nimport type { TransformCallback } from \"node:stream\";\nimport { Transform } from \"node:stream\";\nimport type { AudioResource } from \"@discordjs/voice\";\nimport { createAudioResource, StreamType } from \"@discordjs/voice\";\nimport { TypedEmitter } from \"tiny-typed-emitter\";\nimport { AUDIO_CHANNELS, AUDIO_SAMPLE_RATE, DEFAULT_CROSSFADE_CURVE } from \"../constant\";\nimport type { DisTube } from \"../DisTube\";\nimport { DisTubeError } from \"../struct/DisTubeError\";\nimport type { Awaitable, FFmpegArg, FFmpegOptions } from \"../type\";\nimport { Events } from \"../type\";\n\n/**\n * Options for {@link DisTubeStream}\n */\nexport interface StreamOptions {\n /**\n * FFmpeg options\n */\n ffmpeg: FFmpegOptions;\n /**\n * Seek time (in seconds).\n * @default 0\n */\n seek?: number;\n /**\n * Crossfade transition options.\n *\n * When set, the stream mixes the primary URL (the song that is fading out,\n * seeked to its final `duration` seconds) and the secondary URL (the song\n * that is fading in) with an FFmpeg `acrossfade` filter graph, so the two\n * songs crossfade seamlessly in a single FFmpeg process.\n */\n crossfade?: CrossfadeStreamOptions;\n}\n\n/**\n * Options describing a crossfade transition stream\n */\nexport interface CrossfadeStreamOptions {\n /**\n * The fade duration in seconds.\n */\n duration: number;\n /**\n * The initial seek of the first (fading out) input, in seconds. It must be\n * the position where the fade window begins (`song duration - duration`).\n */\n primarySeek: number;\n /**\n * The stream URL of the second (fading in) input.\n */\n secondaryUrl: string;\n /**\n * The FFmpeg `acrossfade` fade curve of the first (fading out) input.\n * @default \"qsin\"\n */\n outCurve?: string;\n /**\n * The FFmpeg `acrossfade` fade curve of the second (fading in) input.\n * @default \"qsin\"\n */\n inCurve?: string;\n}\n\nlet checked = process.env.NODE_ENV === \"test\";\n/**\n * Check that FFmpeg is installed and can be spawned.\n *\n * The check is only done once: the result is cached.\n * @param distube - The DisTube instance\n * @returns Nothing\n * @throws {@link DisTubeError} When FFmpeg cannot be spawned\n */\nexport const checkFFmpeg = (distube: DisTube) => {\n if (checked) return;\n const path = distube.options.ffmpeg.path;\n const debug = (str: string) => distube.emit(Events.FFMPEG_DEBUG, str);\n try {\n debug(`[test] spawn ffmpeg at '${path}' path`);\n const process = spawnSync(path, [\"-h\"], {\n windowsHide: true,\n encoding: \"utf-8\",\n });\n if (process.error) throw process.error;\n if (process.stderr && !process.stdout) throw new Error(process.stderr);\n\n const result = process.output.join(\"\\n\");\n const version = /ffmpeg version (\\S+)/iu.exec(result)?.[1];\n if (!version) throw new Error(\"Invalid FFmpeg version\");\n debug(`[test] ffmpeg version: ${version}`);\n } catch (e: unknown) {\n const errorMessage = e instanceof Error ? (e.stack ?? e.message) : String(e);\n debug(`[test] failed to spawn ffmpeg at '${path}': ${errorMessage}`);\n throw new DisTubeError(\"FFMPEG_NOT_INSTALLED\", path);\n }\n checked = true;\n};\n\n/**\n * Create a stream to play with {@link DisTubeVoice}\n */\nexport class DisTubeStream extends TypedEmitter<{\n debug: (debug: string) => Awaitable;\n error: (error: Error) => Awaitable;\n}> {\n #ffmpegPath: string;\n #opts: string[];\n /**\n * The FFmpeg process that decodes the audio.\n *\n * It is `undefined` until {@link DisTubeStream#spawn} is called.\n */\n process?: ChildProcess;\n /**\n * The stream of the decoded audio, with the volume applied to it.\n */\n stream: VolumeTransformer;\n /**\n * The Discord.js audio resource that is played by the audio player.\n */\n audioResource: AudioResource;\n /**\n * The seek time in seconds that this stream started from\n */\n readonly seekTime: number;\n /**\n * Create a DisTubeStream to play with {@link DisTubeVoice}\n * @param url - Stream URL\n * @param options - Stream options\n */\n constructor(url: string, options: StreamOptions) {\n super();\n const { ffmpeg, seek, crossfade } = options;\n this.seekTime = typeof seek === \"number\" && seek > 0 ? seek : 0;\n this.#ffmpegPath = ffmpeg.path;\n this.#opts = crossfade ? this.#crossfadeArgs(url, ffmpeg, crossfade) : this.#singleInputArgs(url, ffmpeg, seek);\n\n this.stream = new VolumeTransformer();\n this.stream\n .on(\"close\", () => this.kill())\n .on(\"error\", err => {\n this.debug(`[stream] error: ${err.message}`);\n this.emit(\"error\", err);\n })\n .on(\"finish\", () => this.debug(\"[stream] log: stream finished\"));\n\n this.audioResource = createAudioResource(this.stream, {\n inputType: StreamType.Raw,\n inlineVolume: false,\n });\n }\n\n #flattenArgs(args: FFmpegArg): string[] {\n return Object.entries(args)\n .flatMap(([key, value]) =>\n Array.isArray(value)\n ? value.filter(Boolean).map(v => [`-${key}`, String(v)])\n : value == null || value === false\n ? []\n : [value === true ? `-${key}` : [`-${key}`, String(value)]],\n )\n .flat();\n }\n\n /**\n * Translate a `file:` URL into a local filesystem path that FFmpeg accepts.\n *\n * `file:///C:/x` loses its drive-letter leading slash on Windows (`C:/x`),\n * UNC shares keep their `//host` prefix, POSIX paths stay untouched, and\n * other protocols return `undefined`.\n */\n #localPath(url: string): string | undefined {\n const fileUrl = new URL(url);\n if (fileUrl.protocol !== \"file:\") return undefined;\n const pathname = decodeURIComponent(fileUrl.pathname);\n if (fileUrl.hostname) return `//${fileUrl.hostname}${pathname}`;\n return /^\\/[A-Za-z]:\\//.test(pathname) ? pathname.slice(1) : pathname;\n }\n\n #singleInputArgs(url: string, ffmpeg: FFmpegOptions, seek?: number): string[] {\n const opts: FFmpegArg = {\n reconnect: 1,\n reconnect_streamed: 1,\n reconnect_delay_max: 5,\n analyzeduration: 0,\n hide_banner: true,\n ...ffmpeg.args.global,\n ...ffmpeg.args.input,\n i: url,\n ar: AUDIO_SAMPLE_RATE,\n ac: AUDIO_CHANNELS,\n ...ffmpeg.args.output,\n f: \"s16le\",\n };\n\n if (typeof seek === \"number\" && seek > 0) opts.ss = seek.toString();\n\n const localPath = this.#localPath(url);\n if (localPath !== undefined) {\n opts.reconnect = null;\n opts.reconnect_streamed = null;\n opts.reconnect_delay_max = null;\n opts.i = localPath;\n }\n\n return [...this.#flattenArgs(opts), \"pipe:1\"];\n }\n\n /**\n * Build the arguments of a crossfade transition stream: a single FFmpeg\n * process with two inputs (the fading out song seeked to its final\n * `duration` seconds and the fading in song from its beginning) mixed by an\n * `acrossfade` filter graph.\n *\n * Both inputs are normalized (48kHz stereo s16) before the fade, and the\n * queue's `af` filter chain, when present, is folded into the filter complex\n * after the fade (FFmpeg cannot combine `-af` with `-filter_complex`).\n */\n #crossfadeArgs(url: string, ffmpeg: FFmpegOptions, crossfade: CrossfadeStreamOptions): string[] {\n const {\n duration,\n primarySeek,\n secondaryUrl,\n outCurve = DEFAULT_CROSSFADE_CURVE,\n inCurve = DEFAULT_CROSSFADE_CURVE,\n } = crossfade;\n // The `af` output argument cannot coexist with filter_complex: move it to\n // the end of the filter graph instead.\n const outputArgs: FFmpegArg = { ...ffmpeg.args.output };\n const extraFilters =\n typeof outputArgs.af === \"string\"\n ? outputArgs.af\n : Array.isArray(outputArgs.af)\n ? outputArgs.af.filter(Boolean).join(\",\")\n : undefined;\n delete outputArgs.af;\n\n const primaryOpts: FFmpegArg = {\n reconnect: 1,\n reconnect_streamed: 1,\n reconnect_delay_max: 5,\n analyzeduration: 0,\n hide_banner: true,\n ...ffmpeg.args.global,\n ...ffmpeg.args.input,\n ss: typeof primarySeek === \"number\" && primarySeek > 0 ? primarySeek.toString() : null,\n i: url,\n };\n const secondaryOpts: FFmpegArg = {\n reconnect: 1,\n reconnect_streamed: 1,\n reconnect_delay_max: 5,\n analyzeduration: 0,\n ...ffmpeg.args.input,\n i: secondaryUrl,\n };\n\n // File inputs need the reconnect flags dropped and a plain local path\n // (also for the fading-in input, not only the primary one).\n const primaryLocal = this.#localPath(url);\n if (primaryLocal !== undefined) {\n primaryOpts.reconnect = null;\n primaryOpts.reconnect_streamed = null;\n primaryOpts.reconnect_delay_max = null;\n primaryOpts.i = primaryLocal;\n }\n const secondaryLocal = this.#localPath(secondaryUrl);\n if (secondaryLocal !== undefined) {\n secondaryOpts.reconnect = null;\n secondaryOpts.reconnect_streamed = null;\n secondaryOpts.reconnect_delay_max = null;\n secondaryOpts.i = secondaryLocal;\n }\n\n const normalize = `aresample=${AUDIO_SAMPLE_RATE},aformat=sample_fmts=s16:channel_layouts=stereo`;\n const fade = `[a0][a1]acrossfade=d=${duration}:c1=${outCurve}:c2=${inCurve}[xf]`;\n const graph = [\n `[0:a]${normalize}[a0]`,\n `[1:a]${normalize}[a1]`,\n fade,\n ...(extraFilters ? [`[xf]${extraFilters}[aout]`] : []),\n ].join(\";\");\n\n const outputOpts: FFmpegArg = {\n ar: AUDIO_SAMPLE_RATE,\n ac: AUDIO_CHANNELS,\n ...outputArgs,\n filter_complex: graph,\n map: extraFilters ? \"[aout]\" : \"[xf]\",\n f: \"s16le\",\n };\n\n return [\n ...this.#flattenArgs(primaryOpts),\n ...this.#flattenArgs(secondaryOpts),\n ...this.#flattenArgs(outputOpts),\n \"pipe:1\",\n ];\n }\n\n /**\n * Spawn the FFmpeg process that decodes the audio.\n * @returns Nothing\n * @throws {Error} When the FFmpeg process cannot be created\n */\n spawn() {\n this.debug(`[process] spawn: ${this.#ffmpegPath} ${this.#opts.join(\" \")}`);\n this.process = spawn(this.#ffmpegPath, this.#opts, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n shell: false,\n windowsHide: true,\n })\n .on(\"error\", err => {\n this.debug(`[process] error: ${err.message}`);\n this.emit(\"error\", err);\n })\n .on(\"exit\", (code, signal) => {\n this.debug(`[process] exit: code=${code ?? \"unknown\"} signal=${signal ?? \"unknown\"}`);\n if (!code || [0, 255].includes(code)) return;\n this.debug(`[process] error: ffmpeg exited with code ${code}`);\n this.emit(\"error\", new DisTubeError(\"FFMPEG_EXITED\", code));\n });\n\n if (!this.process.stdout || !this.process.stderr) {\n this.kill();\n throw new Error(\"Failed to create ffmpeg process\");\n }\n\n this.process.stdout.pipe(this.stream);\n this.process.stderr.setEncoding(\"utf8\")?.on(\"data\", (data: string) => {\n const lines = data.split(/\\r\\n|\\r|\\n/u);\n for (const line of lines) {\n if (/^\\s*$/.test(line)) continue;\n this.debug(`[ffmpeg] log: ${line}`);\n }\n });\n }\n\n private debug(debug: string) {\n this.emit(\"debug\", debug);\n }\n\n /**\n * Set the volume of the stream.\n * @param volume - The volume of the stream, between `0` and `1`\n * @returns Nothing\n */\n setVolume(volume: number) {\n this.stream.vol = volume;\n }\n\n /**\n * Kill the FFmpeg process and destroy the stream.\n * @returns Nothing\n */\n kill() {\n if (!this.stream.destroyed) this.stream.destroy();\n if (this.process && !this.process.killed) this.process.kill(\"SIGKILL\");\n }\n}\n\n// Based on prism-media\nclass VolumeTransformer extends Transform {\n private buffer = Buffer.allocUnsafe(0);\n private readonly extrema = [-(2 ** (16 - 1)), 2 ** (16 - 1) - 1];\n vol = 1;\n\n override _transform(newChunk: Buffer, _encoding: BufferEncoding, done: TransformCallback): void {\n const { vol } = this;\n if (vol === 1) {\n this.push(newChunk);\n done();\n return;\n }\n\n const bytes = 2;\n const chunk = Buffer.concat([this.buffer, newChunk]);\n const readableLength = Math.floor(chunk.length / bytes) * bytes;\n\n for (let i = 0; i < readableLength; i += bytes) {\n const value = chunk.readInt16LE(i);\n const clampedValue = Math.min(this.extrema[1], Math.max(this.extrema[0], value * vol));\n chunk.writeInt16LE(clampedValue, i);\n }\n\n this.buffer = chunk.subarray(readableLength);\n this.push(chunk.subarray(0, readableLength));\n done();\n }\n}\n","import { getVoiceConnection, VoiceConnectionStatus } from \"@discordjs/voice\";\nimport type { VoiceBasedChannel } from \"discord.js\";\nimport type { GuildIdResolvable } from \"../..\";\nimport { DisTubeError, resolveGuildId } from \"../..\";\nimport { DisTubeVoice } from \"../DisTubeVoice\";\nimport { GuildIdManager } from \"./GuildIdManager\";\n\n/**\n * Manages voice connections\n */\nexport class DisTubeVoiceManager extends GuildIdManager<DisTubeVoice> {\n /**\n * Create a {@link DisTubeVoice} instance\n * @param channel - A voice channel to join\n * @returns The voice connection of the guild\n * @throws {@link DisTubeError} When the guild already has a voice connection\n * that is not managed by DisTube\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 if (\n getVoiceConnection(resolveGuildId(channel), this.client.user?.id) ||\n getVoiceConnection(resolveGuildId(channel))\n ) {\n throw new DisTubeError(\"VOICE_ALREADY_CREATED\");\n }\n return new DisTubeVoice(this, channel);\n }\n /**\n * Join a voice channel and wait until the connection is ready\n * @param channel - A voice channel to join\n * @returns The voice connection of the guild\n * @throws {@link DisTubeError} When the connection cannot be established\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 guild - Queue Resolvable\n * @returns Nothing\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 type { GuildIdResolvable } from \"../..\";\nimport { resolveGuildId } from \"../..\";\nimport { BaseManager } from \"./BaseManager\";\n\n/**\n * Manages the collection of a data model paired with a guild id.\n */\nexport abstract class GuildIdManager<V> extends BaseManager<V> {\n /**\n * Add an item to the collection.\n *\n * The item is not added when there is already one for the same guild.\n * @param idOrInstance - The guild id, or anything that can be resolved to a guild id\n * @param data - The item to add\n * @returns This manager, to allow chaining\n * @throws {@link DisTubeError} When the value cannot be resolved to a guild id\n */\n add(idOrInstance: GuildIdResolvable, data: V) {\n const id = resolveGuildId(idOrInstance);\n const existing = this.get(id);\n if (existing) return this;\n this.collection.set(id, data);\n return this;\n }\n /**\n * Get the item of a guild.\n * @param idOrInstance - The guild id, or anything that can be resolved to a guild id\n * @returns The item of the guild, or `undefined` when there is none\n * @throws {@link DisTubeError} When the value cannot be resolved to a guild id\n */\n get(idOrInstance: GuildIdResolvable): V | undefined {\n return this.collection.get(resolveGuildId(idOrInstance));\n }\n /**\n * Remove the item of a guild.\n * @param idOrInstance - The guild id, or anything that can be resolved to a guild id\n * @returns `true` when an item was removed, `false` otherwise\n * @throws {@link DisTubeError} When the value cannot be resolved to a guild id\n */\n remove(idOrInstance: GuildIdResolvable): boolean {\n return this.collection.delete(resolveGuildId(idOrInstance));\n }\n /**\n * Check whether a guild has an item.\n * @param idOrInstance - The guild id, or anything that can be resolved to a guild id\n * @returns `true` when there is an item for the guild\n * @throws {@link DisTubeError} When the value cannot be resolved to a guild id\n */\n has(idOrInstance: GuildIdResolvable): boolean {\n return this.collection.has(resolveGuildId(idOrInstance));\n }\n}\n","import type { GuildTextBasedChannel, VoiceBasedChannel } from \"discord.js\";\nimport type { Song } from \"../..\";\nimport {\n CROSSFADE_DRIFT_TOLERANCE_SECS,\n checkFFmpeg,\n DisTubeError,\n DisTubeStream,\n Events,\n objectKeys,\n Queue,\n RepeatMode,\n} from \"../..\";\nimport { GuildIdManager } from \"./GuildIdManager\";\n\n/**\n * Queue manager\n */\nexport class QueueManager extends GuildIdManager<Queue> {\n /**\n * Create a {@link Queue}\n * @param channel - A voice channel\n * @param textChannel - Default text channel\n * @returns The created queue\n * @throws {@link DisTubeError} When the guild already has a queue, or when\n * the voice channel cannot be joined\n */\n async create(channel: VoiceBasedChannel, textChannel?: GuildTextBasedChannel): Promise<Queue> {\n if (this.has(channel.guildId)) throw new DisTubeError(\"QUEUE_EXIST\");\n this.debug(`[QueueManager] Creating queue for guild: ${channel.guildId}`);\n const voice = this.voices.create(channel);\n const queue = new Queue(this.distube, voice, textChannel);\n await queue._taskQueue.queuing();\n try {\n checkFFmpeg(this.distube);\n this.debug(`[QueueManager] Joining voice channel: ${channel.id}`);\n await voice.join();\n this.#voiceEventHandler(queue);\n this.add(queue.id, queue);\n this.emit(Events.INIT_QUEUE, queue);\n return queue;\n } finally {\n queue._taskQueue.resolve();\n }\n }\n\n /**\n * Listen to DisTubeVoice events and handle the Queue\n * @param queue - Queue\n */\n #voiceEventHandler(queue: Queue) {\n queue._listeners = {\n disconnect: error => {\n queue.remove();\n this.emit(Events.DISCONNECT, queue);\n if (error) this.emitError(error, queue, queue.songs?.[0]);\n },\n error: error => void this.#handlePlayingError(queue, error),\n finish: () => void this.handleSongFinish(queue),\n channelChange: (oldChannel, newChannel) => {\n this.emit(Events.VOICE_CHANNEL_CHANGE, queue, oldChannel, newChannel);\n },\n };\n for (const event of objectKeys(queue._listeners)) {\n queue.voice.on(event, queue._listeners[event]);\n }\n }\n\n /**\n * Handle the queue when a Song finish\n * @param queue - queue\n * @returns A promise that resolves when the next song is playing\n */\n async handleSongFinish(queue: Queue): Promise<void> {\n if (queue._manualUpdate) {\n queue._manualUpdate = false;\n await this.playSong(queue);\n return;\n }\n this.debug(`[QueueManager] Handling song finish: ${queue.id}`);\n const song = queue.songs[0];\n this.emit(Events.FINISH_SONG, queue, song);\n await queue._taskQueue.queuing();\n try {\n if (queue.stopped) return;\n if (queue.repeatMode === RepeatMode.QUEUE) queue.songs.push(song);\n\n if (queue.repeatMode !== RepeatMode.SONG) {\n const prev = queue.songs.shift() as Song;\n if (this.options.savePreviousSongs) queue.previousSongs.push(prev);\n else queue.previousSongs.push({ id: prev.id } as Song);\n }\n\n if (queue.songs.length === 0 && queue.autoplay) {\n try {\n this.debug(`[QueueManager] Adding related song: ${queue.id}`);\n await queue._addRelatedSong(song);\n } catch (e: unknown) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[${queue.id}] Add related song error: ${errorMessage}`);\n if (e instanceof DisTubeError) {\n this.emit(Events.NO_RELATED, queue, e);\n } else {\n this.emit(Events.NO_RELATED, queue, new DisTubeError(\"NO_RELATED\"));\n }\n }\n }\n\n if (queue.songs.length === 0) {\n this.debug(`[${queue.id}] Queue is empty, stopping...`);\n this.emit(Events.EMPTY, queue);\n if (!queue.autoplay) this.emit(Events.FINISH, queue);\n queue.remove();\n return;\n }\n\n if (song !== queue.songs[0]) {\n const playedSong = song.stream.playFromSource ? song : song.stream.song;\n if (playedSong?.stream.playFromSource) delete playedSong.stream.url;\n }\n await this.playSong(queue, true);\n } finally {\n queue._taskQueue.resolve();\n }\n }\n\n /**\n * Handle error while playing\n * @param queue - queue\n * @param error - error\n */\n async #handlePlayingError(queue: Queue, error: Error) {\n const song = queue.songs.shift()!;\n try {\n error.name = \"PlayingError\";\n } catch {\n // Emit original error\n }\n this.debug(`[${queue.id}] Error while playing: ${error.stack || error.message}`);\n this.emitError(error, queue, song);\n if (queue.songs.length > 0) {\n this.debug(`[${queue.id}] Playing next song: ${queue.songs[0]}`);\n await this.playSong(queue);\n } else {\n this.debug(`[${queue.id}] Queue is empty, stopping...`);\n await queue.stop();\n }\n }\n\n /**\n * Play a song on voice connection with queue properties\n * @param queue - The guild queue to play\n * @param emitPlaySong - Whether or not emit {@link Events.PLAY_SONG} event\n * @param options - Optional options\n * @param options.keepSongOnError - Whether the current song has to stay in the\n * queue when the stream cannot be started\n * @returns A promise that resolves when the song is playing\n * @throws {@link DisTubeError} When the song does not have any stream URL\n */\n async playSong(queue: Queue, emitPlaySong = true, options?: { keepSongOnError?: boolean }) {\n if (!queue) return;\n if (queue.stopped || !queue.songs.length) {\n await queue.stop();\n return;\n }\n try {\n const song = queue.songs[0];\n let dtStream: DisTubeStream;\n\n if (queue._preloadedSong === song && queue._preloadedStream) {\n this.debug(`[${queue.id}] Using preloaded stream for: ${song}`);\n dtStream = queue._preloadedStream;\n queue._preloadedSong = undefined;\n queue._preloadedStream = undefined;\n } else {\n queue._clearPreload();\n this.debug(`[${queue.id}] Getting stream from: ${song}`);\n await this.handler.attachStreamInfo(song);\n const willPlaySong = song.stream.playFromSource ? song : song.stream.song;\n const stream = willPlaySong?.stream;\n if (!willPlaySong || !stream?.playFromSource || !stream.url) throw new DisTubeError(\"NO_STREAM_URL\", `${song}`);\n this.debug(`[${queue.id}] Creating DisTubeStream for: ${willPlaySong}`);\n const streamOptions = {\n ffmpeg: {\n path: this.options.ffmpeg.path,\n args: {\n global: { ...queue.ffmpegArgs.global },\n input: { ...queue.ffmpegArgs.input },\n output: { ...queue.ffmpegArgs.output, ...queue.filters.ffmpegArgs },\n },\n },\n seek: willPlaySong.duration ? queue._beginTime : undefined,\n };\n queue._beginTime = 0;\n dtStream = new DisTubeStream(stream.url, streamOptions);\n dtStream.on(\"debug\", data => this.emit(Events.FFMPEG_DEBUG, `[${queue.id}] ${data}`));\n }\n\n queue._beginTime = 0;\n this.debug(`[${queue.id}] Started playing: ${song}`);\n await queue.voice.play(dtStream);\n if (emitPlaySong) this.emit(Events.PLAY_SONG, queue, song);\n this.schedulePreload(queue);\n this.scheduleCrossfade(queue);\n } catch (e: unknown) {\n const error = e instanceof Error ? e : new Error(String(e));\n if (options?.keepSongOnError) {\n // The stream is only being restarted (e.g. after a filter change):\n // the current song must stay in the queue even if the restart failed.\n this.debug(`[${queue.id}] Error while restarting the stream: ${error.stack || error.message}`);\n this.emitError(error, queue, queue.songs[0]);\n return;\n }\n await this.#handlePlayingError(queue, error);\n }\n }\n\n /**\n * Schedule preloading the next song in the queue before the current song finishes.\n * @param queue - The guild queue\n */\n schedulePreload(queue: Queue) {\n if (!this.options.preload.enabled || queue.stopped || queue.paused) return;\n if (queue._preloadTimeout) {\n clearTimeout(queue._preloadTimeout);\n queue._preloadTimeout = undefined;\n }\n\n const currentSong = queue.songs[0];\n const nextSong = queue.songs[1];\n if (!currentSong || !nextSong) return;\n\n if (queue._preloadedSong === nextSong && queue._preloadedStream) return;\n\n const threshold = this.options.preload.threshold;\n const duration = currentSong.duration ?? 0;\n const currentTime = queue.currentTime;\n const remaining = duration > 0 && Number.isFinite(currentTime) ? duration - currentTime : 0;\n\n if (duration === 0 || remaining <= threshold) {\n void this.preloadNextSong(queue);\n } else {\n const delayMs = Math.max(0, (remaining - threshold) * 1000);\n queue._preloadTimeout = setTimeout(() => {\n queue._preloadTimeout = undefined;\n void this.preloadNextSong(queue);\n }, delayMs);\n queue._preloadTimeout.unref?.();\n }\n }\n\n /**\n * Preload the next song in the queue.\n * @param queue - The guild queue\n */\n async preloadNextSong(queue: Queue) {\n // Only one preload task may run at a time: playSong fires a preload\n // internally, and callers may request one concurrently as well.\n if (queue._preloading) return queue._preloading;\n const task = this.#preloadTask(queue);\n queue._preloading = task;\n try {\n await task;\n } finally {\n if (queue._preloading === task) queue._preloading = undefined;\n }\n }\n\n async #preloadTask(queue: Queue) {\n if (!this.options.preload.enabled || queue.stopped || queue.paused) return;\n const nextSong = queue.songs[1];\n if (!nextSong) return;\n if (queue._preloadedSong === nextSong && queue._preloadedStream) return;\n // The generation is bumped by _clearPreload(): when the preloaded state\n // is invalidated while this task is running, its result must be dropped.\n const generation = queue._preloadGeneration;\n\n this.debug(`[${queue.id}] Preloading next song: ${nextSong}`);\n this.emit(Events.PRELOAD_SONG, queue, nextSong);\n\n try {\n await this.handler.attachStreamInfo(nextSong);\n\n if (queue.stopped || queue.songs[1] !== nextSong || generation !== queue._preloadGeneration) return;\n\n const willPlaySong = nextSong.stream.playFromSource ? nextSong : nextSong.stream.song;\n const stream = willPlaySong?.stream;\n if (!willPlaySong || !stream?.playFromSource || !stream.url) {\n throw new DisTubeError(\"NO_STREAM_URL\", `${nextSong}`);\n }\n\n const streamOptions = {\n ffmpeg: {\n path: this.options.ffmpeg.path,\n args: {\n global: { ...queue.ffmpegArgs.global },\n input: { ...queue.ffmpegArgs.input },\n output: { ...queue.ffmpegArgs.output, ...queue.filters.ffmpegArgs },\n },\n },\n seek: undefined,\n };\n\n const dtStream = new DisTubeStream(stream.url, streamOptions);\n dtStream.on(\"debug\", data => this.emit(Events.FFMPEG_DEBUG, `[${queue.id}] [preload] ${data}`));\n\n if (queue.stopped || queue.songs[1] !== nextSong || generation !== queue._preloadGeneration) {\n dtStream.kill();\n return;\n }\n\n queue._preloadedSong = nextSong;\n queue._preloadedStream = dtStream;\n\n this.debug(`[${queue.id}] Successfully preloaded next song: ${nextSong}`);\n this.emit(Events.PRELOADED_SONG, queue, nextSong);\n } catch (e: unknown) {\n if (queue._preloadedSong === nextSong) {\n queue._preloadedSong = undefined;\n queue._preloadedStream?.kill();\n queue._preloadedStream = undefined;\n }\n const error = e instanceof Error ? e : new Error(String(e));\n this.debug(`[${queue.id}] Preload failed for ${nextSong}: ${error.message}`);\n this.emit(Events.PRELOAD_ERROR, queue, nextSong, error);\n }\n }\n\n /**\n * Schedule the crossfade into the next song: a single FFmpeg process mixes\n * the current song (seeked to its final fade window) with the next song, and\n * replaces the playback stream exactly when the fade window begins.\n *\n * Canceled automatically whenever the preloaded state is invalidated\n * (pause, seek, stop...), as both schedulers share the same generation.\n * @param queue - The guild queue\n */\n scheduleCrossfade(queue: Queue) {\n queue._crossfadeCancel();\n if (queue.stopped || queue.paused) return;\n const currentSong = queue.songs[0];\n if (!currentSong) return;\n const songDuration = currentSong.duration ?? 0;\n // Live songs have an unknown duration: they cannot be crossfaded.\n if (!songDuration || !Number.isFinite(songDuration)) return;\n const fade = Math.min(Number(queue.crossfade) || 0, songDuration);\n if (fade <= 0) return;\n const nextSong = queue.repeatMode === RepeatMode.SONG ? currentSong : queue.songs[1];\n if (!nextSong) return;\n const currentTime = queue.currentTime;\n if (!Number.isFinite(currentTime)) return;\n const remaining = songDuration - currentTime;\n if (remaining <= fade) return;\n const delayMs = Math.max(0, (remaining - fade - this.options.crossfade.warmup) * 1000);\n this.debug(\n `[${queue.id}] Scheduling crossfade (${fade}s fade) in ${(delayMs / 1000).toFixed(1)}s: ${currentSong} -> ${nextSong}`,\n );\n queue._crossfadeTimeout = setTimeout(() => {\n queue._crossfadeTimeout = undefined;\n void this.#crossfadeWarmupTask(queue);\n }, delayMs);\n queue._crossfadeTimeout.unref?.();\n }\n\n /**\n * Spawn the merged transition stream ahead of the fade window so both of\n * its inputs are buffered when the fade must start, then arm the boundary\n * timer that swaps the playback stream.\n */\n async #crossfadeWarmupTask(queue: Queue) {\n let transitionStream: DisTubeStream | undefined;\n try {\n if (queue.stopped || queue.paused) return;\n const song = queue.songs[0];\n const generation = queue._preloadGeneration;\n const repeatSong = queue.repeatMode === RepeatMode.SONG;\n const nextSong = repeatSong ? song : queue.songs[1];\n if (!song || !nextSong) return;\n const songDuration = song.duration ?? 0;\n const fade = Math.min(Number(queue.crossfade) || 0, songDuration);\n if (fade <= 0) return;\n const remaining = songDuration - queue.currentTime;\n if (remaining <= fade) return;\n if (!repeatSong) {\n // Resolve the next song's stream url if the preload has not done it\n // yet: the transition stream needs it before the fade starts.\n if (this.options.preload.enabled) await this.preloadNextSong(queue);\n else await this.handler.attachStreamInfo(nextSong);\n }\n if (queue.stopped || queue.paused || queue.songs[0] !== song || generation !== queue._preloadGeneration) return;\n if (repeatSong ? queue.songs[0] !== song : queue.songs[1] !== nextSong) return;\n\n const primary = song.stream.playFromSource ? song : song.stream.song;\n const secondary = repeatSong ? primary : nextSong.stream.playFromSource ? nextSong : nextSong.stream.song;\n if (!primary?.stream.playFromSource || !primary.stream.url) return;\n if (!secondary?.stream.playFromSource || !secondary.stream.url) return;\n\n this.debug(`[${queue.id}] Warming up crossfade stream: ${song} -> ${nextSong}`);\n transitionStream = new DisTubeStream(primary.stream.url, {\n ffmpeg: {\n path: this.options.ffmpeg.path,\n args: {\n global: { ...queue.ffmpegArgs.global },\n input: { ...queue.ffmpegArgs.input },\n output: { ...queue.ffmpegArgs.output, ...queue.filters.ffmpegArgs },\n },\n },\n crossfade: {\n duration: fade,\n primarySeek: Math.max(0, songDuration - fade),\n secondaryUrl: secondary.stream.url,\n inCurve: this.options.crossfade.curve,\n outCurve: this.options.crossfade.curve,\n },\n });\n transitionStream.on(\"debug\", data => this.emit(Events.FFMPEG_DEBUG, `[${queue.id}] [crossfade] ${data}`));\n\n if (queue.stopped || queue.paused || queue.songs[0] !== song || generation !== queue._preloadGeneration) {\n transitionStream.kill();\n return;\n }\n queue._crossfadeWarmup = transitionStream;\n // Pre-spawn: until the boundary, both inputs buffer into the stream so\n // the fade can begin without waiting for any network round-trip.\n transitionStream.spawn();\n\n const boundaryMs = Math.max(0, (remaining - fade) * 1000);\n queue._crossfadeTimeout = setTimeout(() => {\n queue._crossfadeTimeout = undefined;\n void this.#crossfadeSwapTask(queue, transitionStream!);\n }, boundaryMs);\n queue._crossfadeTimeout.unref?.();\n } catch (e: unknown) {\n // Crossfade is best-effort: fall back to the regular song transition.\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[${queue.id}] Crossfade warmup failed, using the regular transition: ${errorMessage}`);\n if (transitionStream) transitionStream.kill();\n }\n }\n\n /**\n * Swap the playing stream for the merged transition stream and update the\n * queue as if the current song had just finished.\n */\n async #crossfadeSwapTask(queue: Queue, transitionStream: DisTubeStream) {\n const abort = () => {\n if (queue._crossfadeWarmup === transitionStream) queue._crossfadeWarmup = undefined;\n transitionStream.kill();\n };\n try {\n if (queue.stopped || queue.paused || queue._crossfadeWarmup !== transitionStream) return abort();\n const song = queue.songs[0];\n if (!song) return abort();\n const songDuration = song.duration ?? 0;\n const fade = Math.min(Number(queue.crossfade) || 0, songDuration);\n if (fade <= 0) return abort();\n // The playback position must be inside the fade window: on drift, fall\n // back to the regular transition instead of miscalibrated audio.\n const drift = queue.currentTime - (songDuration - fade);\n if (Math.abs(drift) > CROSSFADE_DRIFT_TOLERANCE_SECS) {\n this.debug(`[${queue.id}] Crossfade aborted: playback drifted ${drift.toFixed(2)}s from the fade boundary`);\n return abort();\n }\n\n await queue._taskQueue.queuing();\n try {\n if (queue.stopped || queue.paused || queue.songs[0] !== song || queue._crossfadeWarmup !== transitionStream) {\n return abort();\n }\n this.debug(`[${queue.id}] Starting crossfade: ${song} -> ${queue.songs.length > 1 ? queue.songs[1] : song}`);\n await queue.voice.play(transitionStream);\n queue._crossfadeWarmup = undefined;\n\n // Update the queue exactly like a regular song finish.\n this.emit(Events.FINISH_SONG, queue, song);\n if (queue.repeatMode === RepeatMode.QUEUE) queue.songs.push(song);\n if (queue.repeatMode !== RepeatMode.SONG) {\n const prev = queue.songs.shift() as Song;\n if (this.options.savePreviousSongs) queue.previousSongs.push(prev);\n else queue.previousSongs.push({ id: prev.id } as Song);\n } else {\n // Repeat-song fades into a fresh playback of the same song: the\n // plain preloaded stream (if any) is replaced by the transition.\n }\n if (song !== queue.songs[0]) {\n const playedSong = song.stream.playFromSource ? song : song.stream.song;\n if (playedSong?.stream.playFromSource) delete playedSong.stream.url;\n }\n // The transition stream replaces whatever plain stream was preloaded\n // for the next song: its url is still resolved, so kill quietly.\n if (queue._preloadedStream) {\n queue._preloadedStream.kill();\n queue._preloadedStream = undefined;\n queue._preloadedSong = undefined;\n }\n this.emit(Events.PLAY_SONG, queue, queue.songs[0]);\n this.schedulePreload(queue);\n this.scheduleCrossfade(queue);\n } finally {\n queue._taskQueue.resolve();\n }\n } catch (e: unknown) {\n abort();\n // Keep the fallback predictable: the old song keeps playing and the\n // regular transition takes over when it ends.\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[${queue.id}] Crossfade swap failed, using the regular transition: ${errorMessage}`);\n }\n }\n}\n","import { randomBytes } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { Readable } from \"node:stream\";\n\n/**\n * A request of the stream server.\n */\nexport interface StreamRequest {\n /**\n * The path after the source, e.g. `v/abc123`.\n */\n path: string;\n /**\n * The parsed query parameters.\n */\n query: URLSearchParams;\n /**\n * The byte offset the client asked for, or `0`.\n */\n offset: number;\n /**\n * Aborted when the client disconnects.\n */\n signal: AbortSignal;\n /**\n * The raw request.\n */\n request: IncomingMessage;\n}\n\n/**\n * The response of a stream handler.\n */\nexport interface StreamResponse {\n /**\n * The audio bytes.\n */\n body: Readable | AsyncIterable<Uint8Array>;\n /**\n * The content type. Default: `application/octet-stream`.\n */\n contentType?: string;\n /**\n * The status code. Default: `200`.\n */\n status?: number;\n /**\n * The total size of the stream, when it is known.\n *\n * It is required to answer the range requests.\n */\n size?: number;\n /**\n * Extra headers.\n */\n headers?: Record<string, string | number>;\n}\n\n/**\n * The handler of a source.\n */\nexport type StreamHandler = (\n req: StreamRequest,\n) => Promise<StreamResponse | null | undefined> | StreamResponse | null | undefined;\n\n/**\n * A handle to release a resource.\n */\nexport interface Disposable {\n /**\n * Release the resource.\n * @returns Nothing\n */\n dispose(): void;\n}\n\n/**\n * Options of the stream server.\n */\nexport interface StreamServerOptions {\n /**\n * The port of the server. `0` (the default) lets the operating system pick a\n * free one, which is what a plugin should use: a fixed port makes the next\n * instance fail with `EADDRINUSE`.\n */\n port?: number;\n /**\n * The prefix of the URLs. A random one is generated by default, so the other\n * local processes cannot guess them.\n */\n prefix?: string;\n}\n\nconst parseRange = (header: string | undefined): number => {\n if (!header) return 0;\n const match = /^bytes=(\\d+)-/u.exec(header);\n return match ? Number(match[1]) : 0;\n};\n\n/**\n * A local HTTP server that the plugins use to stream the audio.\n *\n * Every plugin that cannot hand out a static URL to FFmpeg needs an HTTP\n * server: a source that has to be decrypted, captured or negotiated cannot be\n * fetched by FFmpeg directly. Instead of every plugin running its own server,\n * they register a handler on this one.\n *\n * The server is started on the first registration and it is closed by\n * {@link DisTube#destroy}.\n */\nexport class StreamServer {\n readonly #handlers = new Map<string, StreamHandler>();\n readonly #port: number;\n readonly #prefix: string;\n #server?: Server;\n #ready?: Promise<void>;\n #boundPort?: number;\n #closed = false;\n /**\n * Create a stream server.\n * @param options - Optional options\n */\n constructor({ port = 0, prefix }: StreamServerOptions = {}) {\n this.#port = port;\n this.#prefix = prefix ?? randomBytes(8).toString(\"hex\");\n }\n /**\n * The prefix of the URLs of the server.\n */\n get prefix(): string {\n return this.#prefix;\n }\n /**\n * The base URL of the server, e.g. `http://127.0.0.1:51234`.\n *\n * @throws When the server is not started yet.\n */\n get baseUrl(): string {\n if (!this.#boundPort) throw new Error(\"The stream server is not started yet.\");\n return `http://127.0.0.1:${this.#boundPort}`;\n }\n /**\n * Register a source.\n *\n * The handler is called for every request of that source. Return `null` to\n * answer a `404`.\n * @param source - The identifier of the source\n * @param handler - The handler of the source\n * @returns A handle to unregister the source\n * @example\n * ```ts\n * const disposable = distube.streams.register(\"my-source\", async req => ({\n * body: Readable.from(Buffer.from(\"audio\")),\n * contentType: \"audio/mpeg\",\n * }));\n * ```\n */\n register(source: string, handler: StreamHandler): Disposable {\n const key = source.toLowerCase();\n this.#handlers.set(key, handler);\n void this.#start();\n return {\n dispose: () => {\n if (this.#handlers.get(key) === handler) this.#handlers.delete(key);\n },\n };\n }\n /**\n * Build the URL of a stream.\n *\n * The server is started when it is not running yet.\n * @param source - The identifier of the source\n * @param path - The path after the source\n * @param query - The query parameters\n * @returns The URL of the stream\n * @example\n * ```ts\n * const url = await distube.streams.url(\"my-source\", \"abc123\", { token: \"secret\" });\n * ```\n */\n async url(source: string, path?: string, query?: Record<string, string | number | boolean>): Promise<string> {\n await this.#start();\n const url = new URL(`${this.baseUrl}/${this.#prefix}/${source.toLowerCase()}`);\n if (path) url.pathname = `${url.pathname}/${path.replace(/^\\/+/u, \"\")}`;\n for (const [key, value] of Object.entries(query ?? {})) url.searchParams.set(key, String(value));\n return url.toString();\n }\n /**\n * Close the server and release every handler.\n * @returns A promise that resolves when the server is closed\n */\n async close(): Promise<void> {\n this.#closed = true;\n this.#handlers.clear();\n const server = this.#server;\n this.#server = undefined;\n this.#ready = undefined;\n this.#boundPort = undefined;\n if (!server) return;\n await new Promise<void>(resolve => server.close(() => resolve()));\n }\n async #start(): Promise<void> {\n if (this.#closed) throw new Error(\"The stream server is closed.\");\n if (!this.#ready) {\n this.#ready = new Promise<void>((resolve, reject) => {\n const server = createServer((req, res) => void this.#handle(req, res));\n server.once(\"error\", reject);\n server.listen(this.#port, \"127.0.0.1\", () => {\n const address = server.address();\n this.#boundPort = typeof address === \"object\" && address ? address.port : this.#port;\n this.#server = server;\n // The server must not keep the process alive.\n server.unref?.();\n resolve();\n });\n });\n }\n return this.#ready;\n }\n async #handle(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const controller = new AbortController();\n req.on(\"close\", () => controller.abort());\n try {\n const requestUrl = new URL(req.url ?? \"/\", \"http://127.0.0.1\");\n const segments = requestUrl.pathname.split(\"/\").filter(Boolean);\n if (segments[0] !== this.#prefix) {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" }).end(\"Not Found\");\n return;\n }\n const handler = this.#handlers.get((segments[1] ?? \"\").toLowerCase());\n if (!handler) {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" }).end(\"Not Found\");\n return;\n }\n const result = await handler({\n path: segments.slice(2).join(\"/\"),\n query: requestUrl.searchParams,\n offset: parseRange(req.headers.range),\n signal: controller.signal,\n request: req,\n });\n if (!result) {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" }).end(\"Not Found\");\n return;\n }\n const headers: Record<string, string | number> = {\n \"Content-Type\": result.contentType ?? \"application/octet-stream\",\n ...result.headers,\n };\n if (result.size !== undefined) headers[\"Accept-Ranges\"] = \"bytes\";\n if (result.size !== undefined && result.size > 0) {\n const offset = Math.min(parseRange(req.headers.range), Math.max(result.size - 1, 0));\n if (offset > 0) {\n headers[\"Content-Range\"] = `bytes ${offset}-${result.size - 1}/${result.size}`;\n res.writeHead(206, headers);\n } else {\n res.writeHead(result.status ?? 200, headers);\n }\n } else {\n res.writeHead(result.status ?? 200, headers);\n }\n const body = result.body instanceof Readable ? result.body : Readable.from(result.body);\n body.on(\"error\", () => res.end());\n body.pipe(res);\n } catch {\n if (!res.headersSent) res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end();\n }\n }\n}\n","import type { Client, VoiceBasedChannel } from \"discord.js\";\nimport { TypedEmitter } from \"tiny-typed-emitter\";\nimport { defaultFilters, version } from \"./constant\";\nimport { DisTubeHandler } from \"./core/DisTubeHandler\";\nimport { Options } from \"./core/DisTubeOptions\";\nimport { DisTubeVoiceManager } from \"./core/manager/DisTubeVoiceManager\";\nimport { QueueManager } from \"./core/manager/QueueManager\";\nimport { StreamServer } from \"./core/StreamServer\";\nimport { DisTubeError } from \"./struct/DisTubeError\";\nimport type { ExtractorPlugin } from \"./struct/ExtractorPlugin\";\nimport { Playlist } from \"./struct/Playlist\";\nimport type { Queue } from \"./struct/Queue\";\nimport { SearchResult } from \"./struct/SearchResult\";\nimport { Song } from \"./struct/Song\";\nimport type {\n Awaitable,\n CustomPlaylistOptions,\n DisTubeOptions,\n DisTubePlugin,\n Filters,\n GuildIdResolvable,\n PlayOptions,\n SearchOptions,\n TypedDisTubeEvents,\n} from \"./type\";\nimport { Events } from \"./type\";\nimport {\n checkIntents,\n handleUnhandledError,\n isClientInstance,\n isMemberInstance,\n isMessageInstance,\n isNsfwChannel,\n isObject,\n isSupportedVoiceChannel,\n isTextChannelInstance,\n isURL,\n} from \"./util\";\n\n/**\n * DisTube class\n */\nexport class DisTube extends TypedEmitter<TypedDisTubeEvents> {\n /**\n * @event\n * Emitted after DisTube add a new playlist to the playing {@link Queue}.\n * @param queue - The guild queue\n * @param playlist - Playlist info\n */\n static readonly [Events.ADD_LIST]: (queue: Queue, playlist: Playlist) => Awaitable;\n /**\n * @event\n * Emitted after DisTube add a new song to the playing {@link Queue}.\n * @param queue - The guild queue\n * @param song - Added song\n */\n static readonly [Events.ADD_SONG]: (queue: Queue, song: Song) => Awaitable;\n /**\n * @event\n * Emitted when the {@link Queue} is deleted with any reasons.\n * @param queue - The guild queue\n */\n static readonly [Events.DELETE_QUEUE]: (queue: Queue) => Awaitable;\n /**\n * @event\n * Emitted when the bot is disconnected to a voice channel.\n * @param queue - The guild queue\n */\n static readonly [Events.DISCONNECT]: (queue: Queue) => Awaitable;\n /**\n * @event\n * Emitted when the {@link Queue} runs out of songs to play.\n * @param queue - The guild queue\n */\n static readonly [Events.EMPTY]: (queue: Queue) => Awaitable;\n /**\n * @event\n * Emitted when DisTube encounters an error while playing songs.\n * @param error - error\n * @param queue - The queue encountered the error\n * @param song - The playing song when encountered the error\n */\n static readonly [Events.ERROR]: (error: Error, queue: Queue, song?: Song) => Awaitable;\n /**\n * @event\n * Emitted for logging FFmpeg debug information.\n * @param debug - Debug message string.\n */\n static readonly [Events.FFMPEG_DEBUG]: (debug: string) => Awaitable;\n /**\n * @event\n * Emitted to provide debug information from DisTube's operation.\n * Useful for troubleshooting or logging purposes.\n *\n * @param debug - Debug message string.\n */\n static readonly [Events.DEBUG]: (debug: string) => Awaitable;\n /**\n * @event\n * Emitted when there is no more song in the queue and {@link Queue#autoplay} is `false`.\n * @param queue - The guild queue\n */\n static readonly [Events.FINISH]: (queue: Queue) => Awaitable;\n /**\n * @event\n * Emitted when DisTube finished a song.\n * @param queue - The guild queue\n * @param song - Finished song\n */\n static readonly [Events.FINISH_SONG]: (queue: Queue, song: Song) => Awaitable;\n /**\n * @event\n * Emitted when DisTube initialize a queue to change queue default properties.\n * @param queue - The guild queue\n */\n static readonly [Events.INIT_QUEUE]: (queue: Queue) => Awaitable;\n /**\n * @event\n * Emitted when {@link Queue#autoplay} is `true`, {@link Queue#songs} is empty, and\n * DisTube cannot find related songs to play.\n * @param queue - The guild queue\n * @param error - The error that occurred while looking for related songs\n */\n static readonly [Events.NO_RELATED]: (queue: Queue, error: DisTubeError) => Awaitable;\n /**\n * @event\n * Emitted when DisTube play a song.\n * If {@link DisTubeOptions}.emitNewSongOnly is `true`, this event is not emitted\n * when looping a song or next song is the previous one.\n * @param queue - The guild queue\n * @param song - Playing song\n */\n static readonly [Events.PLAY_SONG]: (queue: Queue, song: Song) => Awaitable;\n /**\n * DisTube internal handler\n */\n readonly handler: DisTubeHandler;\n /**\n * DisTube options\n */\n readonly options: Options;\n /**\n * Discord.js v14 client\n */\n readonly client: Client;\n /**\n * Queues manager\n */\n readonly queues: QueueManager;\n /**\n * DisTube voice connections manager\n */\n readonly voices: DisTubeVoiceManager;\n /**\n * DisTube plugins\n */\n readonly plugins: DisTubePlugin[];\n /**\n * The local HTTP server the plugins use to stream the audio.\n *\n * A plugin that cannot hand out a static URL to FFmpeg registers a handler on\n * it, instead of running its own server.\n */\n readonly streams: StreamServer;\n /**\n * DisTube ffmpeg audio filters\n */\n readonly filters: Filters;\n /**\n * Create a new DisTube class.\n * @throws {@link DisTubeError}\n * @param client - Discord.JS client\n * @param opts - Custom DisTube options\n * @example\n * ```ts\n * const distube = new DisTube(client, { nsfw: false });\n * ```\n */\n constructor(client: Client, opts: DisTubeOptions = {}) {\n super();\n // Do not limit the number of listeners: bots commonly register several\n // listeners for the same event (e.g. one per guild).\n this.setMaxListeners(0);\n if (!isClientInstance(client)) throw new DisTubeError(\"INVALID_TYPE\", \"Discord.Client\", client, \"client\");\n this.client = client;\n checkIntents(client.options);\n this.options = new Options(opts);\n this.voices = new DisTubeVoiceManager(this);\n this.handler = new DisTubeHandler(this);\n this.queues = new QueueManager(this);\n this.filters = { ...defaultFilters, ...this.options.customFilters };\n this.plugins = [...this.options.plugins];\n this.streams = new StreamServer();\n for (const p of this.plugins) {\n const result = p.init(this);\n // The plugins can do asynchronous work in their init. The rejection is\n // caught: an unhandled rejection would crash the whole process.\n if (result && typeof (result as Promise<void>).catch === \"function\") {\n (result as Promise<void>).catch((e: unknown) => {\n const error = e instanceof Error ? e : new Error(String(e));\n this.debug(`[DisTube] The plugin ${p.constructor.name} failed to initialize: ${error.message}`);\n process.emitWarning(`The plugin ${p.constructor.name} failed to initialize: ${error.message}`, {\n code: \"DIS_TUBE_PLUGIN_INIT_FAILED\",\n detail: error.stack ?? error.message,\n });\n });\n }\n }\n }\n\n /**\n * Create a DisTube instance and wait for the plugins to be initialized.\n *\n * Use it when a plugin does asynchronous work in its `init` method: the\n * constructor cannot await it.\n * @param client - The Discord.js client\n * @param opts - Optional options\n * @returns The DisTube instance\n * @example\n * ```ts\n * const distube = await DisTube.create(client, { plugins: [new MyPlugin()] });\n * ```\n */\n static async create(client: Client, opts: DisTubeOptions = {}): Promise<DisTube> {\n const distube = new DisTube(client, opts);\n await Promise.all(\n distube.plugins.map(async plugin => {\n try {\n await plugin.init(distube);\n } catch (e: unknown) {\n const error = e instanceof Error ? e : new Error(String(e));\n distube.debug(`[DisTube] The plugin ${plugin.constructor.name} failed to initialize: ${error.message}`);\n process.emitWarning(`The plugin ${plugin.constructor.name} failed to initialize: ${error.message}`, {\n code: \"DIS_TUBE_PLUGIN_INIT_FAILED\",\n detail: error.stack ?? error.message,\n });\n }\n }),\n );\n return distube;\n }\n\n /**\n * Emit an event of the DisTube instance.\n *\n * The special {@link Events.ERROR} event is handled differently than the other\n * events: Node.js throws an `ERR_UNHANDLED_ERROR` when the special `\"error\"`\n * event is emitted without any listener, which crashes the whole process.\n *\n * Instead of crashing, DisTube follows {@link DisTubeOptions.unhandledError}\n * (`\"log\"` by default).\n * @param event - The event name\n * @param args - The event arguments\n * @returns `true` when the event had listeners, `false` otherwise\n */\n override emit<U extends keyof TypedDisTubeEvents>(event: U, ...args: Parameters<TypedDisTubeEvents[U]>): boolean {\n if (event === Events.ERROR && this.listenerCount(Events.ERROR) === 0) {\n this.#handleUnhandledError(args[0] as Error);\n return false;\n }\n return super.emit(event, ...args);\n }\n\n /**\n * Handle an {@link Events.ERROR} event that has no listener.\n * @param error - The error\n */\n #handleUnhandledError(error: Error) {\n handleUnhandledError(error, this.options?.unhandledError ?? \"log\");\n }\n\n /**\n * DisTube version\n */\n static get version() {\n return version;\n }\n\n /**\n * DisTube version\n */\n get version() {\n return version;\n }\n\n /**\n * Play / add a song or playlist from url.\n * Search and play a song (with {@link ExtractorPlugin}) if it is not a valid url.\n * @throws {@link DisTubeError}\n * @param voiceChannel - The channel will be joined if the bot isn't in any channels, the bot will be\n * moved to this channel if {@link DisTubeOptions}.joinNewVoiceChannel is `true`\n * @param song - URL | Search string | {@link Song} | {@link Playlist}\n * @param options - Optional options\n * @returns A promise that resolves when the song is added to the queue\n * @example\n * ```ts\n * await distube.play(channel, \"Never gonna give you up\", { message });\n * ```\n */\n async play<T = unknown>(\n voiceChannel: VoiceBasedChannel,\n song: string | Song | Playlist,\n options: PlayOptions<T> = {},\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, source } = {\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\n const queue = this.getQueue(voiceChannel) || (await this.queues.create(voiceChannel, textChannel));\n await queue._taskQueue.queuing(true);\n try {\n this.debug(`[${queue.id}] Playing input: ${song}`);\n const resolved = await this.handler.resolve(song, { member, metadata, source });\n const isNsfw = isNsfwChannel(queue?.textChannel || textChannel);\n const isFirstSong = queue.songs.length === 0;\n if (resolved instanceof Playlist) {\n if (!this.options.nsfw && !isNsfw) {\n resolved.songs = resolved.songs.filter(s => !s.ageRestricted);\n if (!resolved.songs.length) throw new DisTubeError(\"EMPTY_FILTERED_PLAYLIST\");\n }\n if (!resolved.songs.length) throw new DisTubeError(\"EMPTY_PLAYLIST\");\n this.debug(`[${queue.id}] Adding playlist to queue: ${resolved.songs.length} songs`);\n queue.addToQueue(resolved.songs, position);\n if (!isFirstSong || this.options.emitAddListWhenCreatingQueue) this.emit(Events.ADD_LIST, queue, resolved);\n } else {\n if (!this.options.nsfw && resolved.ageRestricted && !isNsfwChannel(queue?.textChannel || textChannel)) {\n throw new DisTubeError(\"NON_NSFW\");\n }\n this.debug(`[${queue.id}] Adding song to queue: ${resolved.name || resolved.url || resolved.id || resolved}`);\n queue.addToQueue(resolved, position);\n if (!isFirstSong || this.options.emitAddSongWhenCreatingQueue) this.emit(Events.ADD_SONG, queue, resolved);\n }\n\n if (isFirstSong) await queue.play();\n else if (skip) await queue.skip();\n } catch (e: unknown) {\n if (!(e instanceof DisTubeError)) {\n const errorMessage = e instanceof Error ? (e.stack ?? e.message) : String(e);\n this.debug(`[${queue.id}] Unexpected error while playing song: ${errorMessage}`);\n if (e instanceof Error) {\n try {\n e.name = \"PlayError\";\n e.message = `${typeof song === \"string\" ? song : song.url}\\n${e.message}`;\n } catch {\n // Some errors have read-only properties, throw original error\n }\n }\n }\n throw e;\n } finally {\n if (!queue.songs.length && !queue._taskQueue.hasPlayTask) queue.remove();\n queue._taskQueue.resolve();\n }\n }\n\n /**\n * Create a custom playlist\n * @param songs - Array of url or Song\n * @param options - Optional options\n * @returns The created playlist\n * @throws {@link DisTubeError} When the array is empty, or when it does not\n * have any valid song\n */\n async createCustomPlaylist(\n songs: (string | Song)[],\n { member, parallel, metadata, name, source, url, thumbnail }: CustomPlaylistOptions = {},\n ): Promise<Playlist> {\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(song => song instanceof Song || isURL(song));\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 let resolvedSongs: Song[];\n if (parallel !== false) {\n const promises = filteredSongs.map((song: string | Song) =>\n this.handler.resolve(song, { member, metadata }).catch(() => undefined),\n );\n resolvedSongs = (await Promise.all(promises)).filter((s): s is Song => s instanceof Song);\n } else {\n resolvedSongs = [];\n for (const song of filteredSongs) {\n const resolved = await this.handler.resolve(song, { member, metadata }).catch(() => undefined);\n if (resolved instanceof Song) resolvedSongs.push(resolved);\n }\n }\n return new Playlist(\n {\n source: source || \"custom\",\n name,\n url,\n thumbnail: thumbnail || resolvedSongs.find(s => s.thumbnail)?.thumbnail,\n songs: resolvedSongs,\n },\n { member, metadata },\n );\n }\n\n /**\n * Get the guild queue\n * @param guild - The type can be resolved to give a {@link Queue}\n * @returns The queue of the guild, or `undefined` when there is none\n * @example\n * ```ts\n * const queue = distube.getQueue(guildId);\n * ```\n */\n getQueue(guild: GuildIdResolvable): Queue | undefined {\n return this.queues.get(guild);\n }\n\n /**\n * Get a plugin by the identifier of its source.\n *\n * It matches the {@link Plugin.source} of the plugin, or one of its\n * {@link Plugin.aliases}. The identifier of the class is used when the\n * plugin does not define a source (`MyPlugin` -> `myplugin`).\n * @param source - The identifier of the source\n * @returns The plugin, or `undefined` when there is none\n * @example\n * ```ts\n * const plugin = distube.getPlugin(\"myplugin\");\n * ```\n */\n getPlugin(source: string): DisTubePlugin | undefined {\n if (typeof source !== \"string\" || !source) return undefined;\n const identifier = source.toLowerCase();\n return this.plugins.find(plugin => plugin.identifiers.includes(identifier));\n }\n\n /**\n * Search for the songs of the plugins.\n *\n * The plugins are used in the order they were registered. When\n * {@link ResolveOptions.source} is given, only the matching plugin is used.\n * @param query - The search query\n * @param options - Optional options\n * @returns The result of the search\n * @example\n * ```ts\n * const result = await distube.search(\"Never gonna give you up\", { limit: 5 });\n * ```\n */\n async search<T = unknown>(query: string, options: SearchOptions<T> = {}): Promise<SearchResult<T>> {\n const limit = options.limit ?? 10;\n const plugins: DisTubePlugin[] = options.source\n ? [this.getPlugin(options.source)].filter((plugin): plugin is DisTubePlugin => Boolean(plugin))\n : this.plugins;\n\n const songs: Song<T>[] = [];\n const sources: string[] = [];\n let playlist: Playlist<T> | undefined;\n\n for (const plugin of plugins) {\n if (songs.length >= limit) break;\n const found = await plugin.search<T>(query, { ...options, limit: limit - songs.length });\n if (!found) continue;\n if (found.songs.length) {\n songs.push(...found.songs);\n sources.push(plugin.identifiers[0] ?? plugin.constructor.name);\n }\n playlist ??= found.playlist;\n }\n\n return new SearchResult<T>(query, {\n songs: songs.slice(0, limit),\n playlist,\n queryType: options.type,\n sources,\n });\n }\n\n /**\n /**\n /**\n /**\n * Emit error event\n * @param error - error\n * @param queue - The queue encountered the error\n * @param song - The playing song when encountered the error\n * @returns Nothing\n */\n emitError(error: Error, queue: Queue, song?: Song): void {\n this.emit(Events.ERROR, error, queue, song);\n }\n\n /**\n * Emit debug event\n * @param message - debug message\n * @returns Nothing\n */\n debug(message: string) {\n this.emit(Events.DEBUG, message);\n }\n\n /**\n * Destroy the DisTube instance.\n *\n * Stops every queue, leaves every voice channel, destroys every plugin and\n * removes every listener.\n * Call it before your Discord.js client is destroyed to release all resources.\n * @returns A promise that resolves when every resource is released\n * @example\n * ```ts\n * await distube.destroy();\n * ```\n */\n async destroy(): Promise<void> {\n this.debug(\"[DisTube] Destroying the DisTube instance...\");\n const queues = [...this.queues.collection.values()];\n for (const queue of queues) {\n try {\n await queue.stop();\n } catch (e: unknown) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[DisTube] Failed to stop the queue ${queue.id}: ${errorMessage}`);\n }\n }\n const voices = [...this.voices.collection.values()];\n for (const voice of voices) {\n try {\n voice.leave();\n } catch (e: unknown) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[DisTube] Failed to leave the voice connection ${voice.id}: ${errorMessage}`);\n }\n }\n for (const plugin of this.plugins) {\n try {\n await plugin.destroy();\n } catch (e: unknown) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[DisTube] Failed to destroy the plugin ${plugin.constructor.name}: ${errorMessage}`);\n }\n }\n await this.streams.close();\n this.removeAllListeners();\n }\n}\n\nexport default DisTube;\n","import { SearchResultType } from \"../type\";\nimport type { Playlist } from \"./Playlist\";\nimport type { Song } from \"./Song\";\n\n/**\n * The result of a search.\n *\n * It is the result type of every search, at the plugin level and at the\n * DisTube level.\n */\nexport class SearchResult<T = unknown> {\n /**\n * The query of the search.\n */\n readonly query: string;\n /**\n * The kind of result that was looked for.\n */\n readonly queryType: SearchResultType;\n /**\n * The songs that were found.\n */\n readonly songs: Song<T>[];\n /**\n * The playlist that was found, when the search returned one.\n */\n readonly playlist?: Playlist<T>;\n /**\n * The identifiers of the plugins that contributed to the result.\n */\n readonly sources: string[];\n /**\n * Create a search result.\n * @param query - The query of the search\n * @param options - Optional data\n * @param options.songs - The songs that were found\n * @param options.playlist - The playlist that was found\n * @param options.queryType - The kind of result that was looked for\n * @param options.sources - The identifiers of the plugins that contributed\n * to the result\n * @example\n * ```ts\n * const result = new SearchResult(\"Never gonna give you up\", { songs: [song] });\n * ```\n */\n constructor(\n query: string,\n {\n songs = [],\n playlist,\n queryType,\n sources = [],\n }: {\n songs?: Song<T>[];\n playlist?: Playlist<T>;\n queryType?: SearchResultType;\n sources?: string[];\n } = {},\n ) {\n this.query = query;\n this.songs = songs;\n this.playlist = playlist;\n this.queryType = queryType ?? SearchResultType.TRACK;\n this.sources = sources;\n }\n /**\n * Whether the search returned nothing.\n * @returns `true` when the result has neither songs nor a playlist\n */\n isEmpty(): boolean {\n return this.songs.length === 0 && !this.playlist;\n }\n /**\n * Whether the search returned songs.\n * @returns `true` when the result has at least one song\n */\n hasSongs(): boolean {\n return this.songs.length > 0;\n }\n /**\n * Whether the search returned a playlist.\n * @returns `true` when the result has a playlist\n */\n hasPlaylist(): boolean {\n return Boolean(this.playlist);\n }\n /**\n * A plain object representation of the result.\n * @returns The plain object representation of the result\n */\n toJSON(): object {\n return {\n query: this.query,\n queryType: this.queryType,\n sources: [...this.sources],\n songs: this.songs.map(song => ({\n id: song.id,\n name: song.name,\n url: song.url,\n duration: song.duration,\n formattedDuration: song.formattedDuration,\n thumbnail: song.thumbnail,\n source: song.source,\n uploader: song.uploader,\n })),\n playlist: this.playlist\n ? {\n id: this.playlist.id,\n name: this.playlist.name,\n url: this.playlist.url,\n thumbnail: this.playlist.thumbnail,\n songs: this.playlist.songs.length,\n }\n : undefined,\n };\n }\n}\n","import type { StreamServer } from \"../core/StreamServer\";\nimport type { DisTube } from \"../DisTube\";\nimport type { Awaitable, PluginType, ResolveOptions, SearchOptions } from \"../type\";\nimport { SearchResult } from \"./SearchResult\";\nimport type { Song } from \"./Song\";\n\n/**\n * DisTube Plugin\n */\nexport abstract class Plugin {\n /**\n * Type of the plugin\n */\n abstract readonly type: PluginType;\n /**\n * The identifier of the source of the plugin.\n *\n * It defaults to the name of the class, lowercased, without the `Plugin`\n * suffix (`MyPlugin` -> `myplugin`).\n *\n * It is used to route a search to a plugin, and to find a plugin with\n * {@link DisTube#getPlugin}.\n */\n readonly source?: string;\n /**\n * Additional identifiers of the source of the plugin, e.g. `[\"yt\"]`.\n */\n readonly aliases?: string[];\n /**\n * Whether the songs of this plugin can be played directly.\n *\n * When it is `false`, the songs of the plugin are resolved to a playable\n * version by another plugin. It defaults to `true`.\n */\n readonly playable?: boolean;\n /**\n * DisTube\n */\n distube!: DisTube;\n /**\n * Initialize the plugin.\n *\n * It can be asynchronous: use {@link DisTube.create} to wait for the\n * initialization of the plugins.\n * @param distube - The DisTube instance\n * @returns Nothing, or a promise that resolves when the plugin is initialized\n * @example\n * ```ts\n * override async init(distube: DisTube) {\n * this.client = await createSession();\n * }\n * ```\n */\n init(distube: DisTube): void | Promise<void> {\n this.distube = distube;\n }\n /**\n * Every identifier of this plugin: its {@link Plugin.source} and its\n * {@link Plugin.aliases}, lowercased.\n *\n * The static properties of the class are used when the instance ones are not\n * defined, so a plugin can declare them either way.\n */\n get identifiers(): string[] {\n const names = new Set<string>();\n const ctor = this.constructor as { source?: string; aliases?: string[] };\n const source = this.source ?? ctor.source ?? this.constructor.name.replace(/Plugin$/iu, \"\");\n if (source) names.add(source.toLowerCase());\n for (const alias of this.aliases ?? ctor.aliases ?? []) {\n if (typeof alias === \"string\" && alias) names.add(alias.toLowerCase());\n }\n return [...names];\n }\n /**\n * The local HTTP server of the DisTube instance.\n *\n * Register a handler on it when the plugin cannot hand out a static URL to\n * FFmpeg, instead of running its own server.\n */\n get streams(): StreamServer {\n return this.distube.streams;\n }\n /**\n * Search for a song of the source.\n *\n * Override it to enable the search of your source. It returns `null` by\n * default, because a source that cannot be searched does not have any result.\n * @param _query - Search query\n * @param _options - Optional options\n * @returns The song that was found, or `null`\n * @example\n * ```ts\n * override async searchSong(query: string): Promise<Song | null> {\n * return findSong(query);\n * }\n * ```\n */\n searchSong<T>(_query: string, _options: ResolveOptions<T>): Awaitable<Song<T> | null> {\n return null;\n }\n /**\n * Search for the songs of the source.\n *\n * The default implementation returns the single result of\n * {@link Plugin#searchSong}. Override it to return more results, or to return\n * a playlist.\n * @param query - Search query\n * @param options - Optional options\n * @returns The result of the search\n * @example\n * ```ts\n * const result = await plugin.search(\"Never gonna give you up\", { limit: 5 });\n * ```\n */\n async search<T>(query: string, options: SearchOptions<T> = {}): Promise<SearchResult<T>> {\n const song = await this.searchSong(query, options);\n return new SearchResult<T>(query, {\n songs: song ? [song] : [],\n queryType: options.type,\n });\n }\n /**\n * Create the query used to find a playable version of a song.\n *\n * It is used when the plugin cannot play the songs it resolves.\n * @param song - Input song\n * @returns The search query\n * @example\n * ```ts\n * override createSearchQuery(song: Song): string {\n * return `${song.name} ${song.uploader?.name}`;\n * }\n * ```\n */\n createSearchQuery<T>(song: Song<T>): Awaitable<string> {\n return `${song.name ?? \"\"} ${song.uploader?.name ?? \"\"}`.trim();\n }\n /**\n * Get related songs from a supported url.\n *\n * Override it to enable the autoplay for your source. Return an empty array\n * when your source does not have any related songs.\n * @param _song - Input song\n * @returns The related songs\n */\n getRelatedSongs(_song: Song): Awaitable<Song[]> {\n return [];\n }\n /**\n * Destroy the plugin.\n *\n * It is called when the {@link DisTube} instance is destroyed. Override it to\n * release every resource held by the plugin (HTTP servers, timers, browser\n * sessions, ...).\n * @returns Nothing, or a promise that resolves when the plugin is destroyed\n */\n destroy(): void | Promise<void> {\n // Nothing to destroy by default\n }\n}\n","import type { Awaitable, ResolveOptions } from \"../type\";\nimport { PluginType } from \"../type\";\nimport type { Playlist } from \"./Playlist\";\nimport { Plugin } from \"./Plugin\";\nimport type { Song } from \"./Song\";\n\n/**\n * This plugin can extract the info, search, and play a song directly from its source\n */\nexport abstract class ExtractorPlugin extends Plugin {\n /**\n * The type of the plugin.\n */\n override readonly type: PluginType = PluginType.EXTRACTOR;\n /**\n * Check if the url is working with this plugin\n * @param url - Input url\n * @returns `true` when the plugin can handle the url\n */\n abstract validate(url: string): Awaitable<boolean>;\n /**\n * Resolve the validated url to a {@link Song} or a {@link Playlist}.\n * @param url - URL\n * @param options - Optional options\n * @returns The resolved song or playlist\n */\n abstract resolve<T>(url: string, options: ResolveOptions<T>): Awaitable<Song<T> | Playlist<T>>;\n /**\n * Get the stream url from {@link Song#url}. Returns {@link Song#url} by default.\n * Not needed if the plugin plays the song itself.\n * @param song - Input song\n * @returns The url of the audio stream\n */\n abstract getStreamURL<T>(song: Song<T>): Awaitable<string>;\n}\n","import { DisTubeError } from \"./DisTubeError\";\n\n/**\n * The error codes a plugin can raise.\n */\nexport enum PluginErrorCode {\n /**\n * The URL is not supported by the plugin.\n */\n UNSUPPORTED_URL = \"UNSUPPORTED_URL\",\n /**\n * The song, the playlist or the album was not found.\n */\n NOT_FOUND = \"NOT_FOUND\",\n /**\n * The plugin could not get a playable stream for the song.\n */\n NO_STREAM = \"NO_STREAM\",\n /**\n * The source is temporarily unavailable: rate limit, server error or network\n * failure.\n */\n SOURCE_UNAVAILABLE = \"SOURCE_UNAVAILABLE\",\n /**\n * The content is age-restricted.\n */\n AGE_RESTRICTED = \"AGE_RESTRICTED\",\n}\n\nconst DEFAULT_MESSAGES: Record<PluginErrorCode, string> = {\n [PluginErrorCode.UNSUPPORTED_URL]: \"This URL is not supported by the plugin\",\n [PluginErrorCode.NOT_FOUND]: \"The song was not found\",\n [PluginErrorCode.NO_STREAM]: \"No playable stream was found for the song\",\n [PluginErrorCode.SOURCE_UNAVAILABLE]: \"The source is temporarily unavailable\",\n [PluginErrorCode.AGE_RESTRICTED]: \"The content is age-restricted\",\n};\n\n/**\n * The error raised by a plugin.\n *\n * It extends {@link DisTubeError}, so the code of the error is available with\n * `error.errorCode` and the error can be caught with `instanceof DisTubeError`.\n */\nexport class PluginError<T extends PluginErrorCode = PluginErrorCode> extends DisTubeError<T> {\n /**\n * Create a plugin error.\n * @param code - The error code\n * @param message - The message. It defaults to the one of the error code.\n * @param options - Optional options\n * @param options.cause - The original error that caused this one\n * @example\n * ```ts\n * throw new PluginError(PluginErrorCode.NOT_FOUND);\n * ```\n */\n constructor(code: T, message?: string, options?: { cause?: unknown }) {\n super(code, message ?? DEFAULT_MESSAGES[code]);\n if (options && \"cause\" in options) this.cause = options.cause;\n }\n /**\n * The name of the error, with its code.\n * @returns The name of the error, e.g. `PluginError [NOT_FOUND]`\n */\n override get name() {\n return `PluginError [${this.errorCode}]`;\n }\n}\n","import type { Awaitable, ResolveOptions } from \"../type\";\nimport { PluginType } from \"../type\";\nimport { ExtractorPlugin } from \"./ExtractorPlugin\";\nimport type { Playlist } from \"./Playlist\";\nimport { PluginError, PluginErrorCode } from \"./PluginError\";\nimport type { Song } from \"./Song\";\n\n/**\n * This plugin only can extract the info from supported links, but not play song directly from its source\n *\n * @deprecated Use {@link ExtractorPlugin} with `playable: false` instead.\n */\nexport abstract class InfoExtractorPlugin extends ExtractorPlugin {\n /**\n * The type of the plugin.\n */\n override readonly type: PluginType = PluginType.INFO_EXTRACTOR;\n /**\n * The songs of this plugin are resolved to a playable version by another\n * plugin.\n */\n override readonly playable = false;\n /**\n * Check if the url is working with this plugin\n * @param url - Input url\n * @returns `true` when the plugin can handle the url\n */\n abstract override validate(url: string): Awaitable<boolean>;\n /**\n * Resolve the validated url to a {@link Song} or a {@link Playlist}.\n * @param url - URL\n * @param options - Optional options\n * @returns The resolved song or playlist\n */\n abstract override resolve<T>(url: string, options: ResolveOptions<T>): Awaitable<Song<T> | Playlist<T>>;\n\n /**\n * Create a search query to be used in {@link ExtractorPlugin#searchSong}\n * @param song - Input song\n * @returns The search query\n */\n abstract override createSearchQuery<T>(song: Song<T>): Awaitable<string>;\n\n /**\n * This plugin cannot play the songs it resolves, so it never has a stream url.\n * @param _song - Input song\n * @returns Nothing: it always throws\n * @throws {@link PluginError} Always, with the code `NO_STREAM`\n */\n override async getStreamURL<T>(_song: Song<T>): Promise<string> {\n throw new PluginError(PluginErrorCode.NO_STREAM);\n }\n}\n","import type { Awaitable, ResolveOptions } from \"../type\";\nimport { PluginType } from \"../type\";\nimport { ExtractorPlugin } from \"./ExtractorPlugin\";\nimport type { Playlist } from \"./Playlist\";\nimport type { Song } from \"./Song\";\n\n/**\n * This plugin can extract and play song from supported links, but cannot search for songs from its source\n */\nexport abstract class PlayableExtractorPlugin extends ExtractorPlugin {\n /**\n * The type of the plugin.\n */\n override readonly type: PluginType = PluginType.PLAYABLE_EXTRACTOR;\n /**\n * Check if the url is working with this plugin\n * @param url - Input url\n * @returns `true` when the plugin can handle the url\n */\n abstract override validate(url: string): Awaitable<boolean>;\n /**\n * Resolve the validated url to a {@link Song} or a {@link Playlist}.\n * @param url - URL\n * @param options - Optional options\n * @returns The resolved song or playlist\n */\n abstract override resolve<T>(url: string, options: ResolveOptions<T>): Awaitable<Song<T> | Playlist<T>>;\n /**\n * Get the stream url from {@link Song#url}. Returns {@link Song#url} by default.\n * Not needed if the plugin plays the song itself.\n * @param song - Input song\n * @returns The url of the audio stream\n */\n abstract override getStreamURL<T>(song: Song<T>): Awaitable<string>;\n}\n"],"mappings":"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","names":["import_discord","import_discord","Events","SearchResultType","RepeatMode","PluginType","import_voice","import_tiny_typed_emitter","process","version","import_voice","import_node_stream","import_tiny_typed_emitter","PluginErrorCode"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constant.ts","../src/core/DisTubeBase.ts","../src/core/DisTubeHandler.ts","../src/struct/DisTubeError.ts","../src/util.ts","../src/core/DisTubeVoice.ts","../src/core/manager/BaseManager.ts","../src/core/manager/FilterManager.ts","../src/type.ts","../src/struct/TaskQueue.ts","../src/struct/Queue.ts","../src/struct/Playlist.ts","../src/struct/Song.ts","../src/core/DisTubeOptions.ts","../src/core/DisTubeStream.ts","../src/core/manager/DisTubeVoiceManager.ts","../src/core/manager/GuildIdManager.ts","../src/core/manager/QueueManager.ts","../src/core/StreamServer.ts","../src/DisTube.ts","../src/struct/SearchResult.ts","../src/struct/Plugin.ts","../src/struct/ExtractorPlugin.ts","../src/struct/PluginError.ts","../src/struct/InfoExtractorPlugin.ts","../src/struct/PlayableExtractorPlugin.ts"],"sourcesContent":["export * from \"./constant\";\nexport * from \"./core/DisTubeBase\";\nexport * from \"./core/DisTubeHandler\";\nexport * from \"./core/DisTubeOptions\";\nexport * from \"./core/DisTubeStream\";\nexport * from \"./core/DisTubeVoice\";\nexport * from \"./core/manager/BaseManager\";\nexport * from \"./core/manager/DisTubeVoiceManager\";\nexport * from \"./core/manager/FilterManager\";\nexport * from \"./core/manager/GuildIdManager\";\nexport * from \"./core/manager/QueueManager\";\nexport * from \"./core/StreamServer\";\nexport { DisTube, DisTube as default } from \"./DisTube\";\nexport * from \"./struct/DisTubeError\";\nexport * from \"./struct/ExtractorPlugin\";\nexport * from \"./struct/InfoExtractorPlugin\";\nexport * from \"./struct/PlayableExtractorPlugin\";\nexport * from \"./struct/Playlist\";\nexport * from \"./struct/Plugin\";\nexport * from \"./struct/PluginError\";\nexport * from \"./struct/Queue\";\nexport * from \"./struct/SearchResult\";\nexport * from \"./struct/Song\";\nexport * from \"./struct/TaskQueue\";\nexport * from \"./type\";\nexport * from \"./util\";\n","import type { DisTubeOptions, Filters } from \"./type\";\n\n/**\n * The version of DisTube.\n *\n * The placeholder is replaced by the real version at build time.\n */\nexport const version: string = \"6.2.2\";\n\n/**\n * The sample rate of the audio, in Hz.\n */\nexport const AUDIO_SAMPLE_RATE = 48000;\n/**\n * The number of channels of the audio.\n */\nexport const AUDIO_CHANNELS = 2;\n\n/**\n * Default volume percentage (0-100)\n */\nexport const DEFAULT_VOLUME = 50;\n\n/**\n * The timeout to join a voice channel, in milliseconds.\n */\nexport const JOIN_TIMEOUT_MS = 30_000;\n/**\n * The delay between two reconnection attempts, in milliseconds.\n */\nexport const RECONNECT_TIMEOUT_MS = 5_000;\n/**\n * The maximum number of reconnection attempts before giving up.\n */\nexport const RECONNECT_MAX_ATTEMPTS = 5;\n\n/**\n * Default time (in milliseconds) a track may stay in the \"buffering\" state\n * before it is considered stuck and gets skipped.\n */\nexport const STUCK_THRESHOLD_MS = 10_000;\n\n/**\n * The HTTP status codes that are followed as a redirection.\n */\nexport const HTTP_REDIRECT_CODES = new Set([301, 302, 303, 307, 308]);\n/**\n * The maximum number of redirections that are followed before giving up.\n */\nexport const MAX_REDIRECT_DEPTH = 5;\n\n/**\n * Default DisTube audio filters.\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\n/**\n * Default number of seconds remaining in the currently playing song before preloading starts.\n */\nexport const DEFAULT_PRELOAD_THRESHOLD_SECS = 15;\n\n/**\n * Default crossfade duration in seconds for a {@link Queue} (0 disables the crossfade).\n */\nexport const DEFAULT_CROSSFADE_DURATION_SECS = 0;\n/**\n * Maximum crossfade duration in seconds a {@link Queue} may request.\n */\nexport const MAX_CROSSFADE_DURATION_SECS = 12;\n/**\n * Default FFmpeg `acrossfade` fade curve of the crossfade transition.\n *\n * `qsin` is an equal-power curve: the two songs mix without the -3dB dip of a\n * linear (triangular) curve.\n */\nexport const DEFAULT_CROSSFADE_CURVE = \"qsin\";\n/**\n * Default number of seconds before the fade window when the merged crossfade\n * transition stream is spawned to warm up its buffers.\n */\nexport const DEFAULT_CROSSFADE_WARMUP_SECS = 5;\n/**\n * How far (in seconds) the playback position may drift from the expected\n * crossfade boundary before the transition is aborted and the regular\n * song-switch takes over.\n */\nexport const CROSSFADE_DRIFT_TOLERANCE_SECS = 0.75;\n\n/**\n * The default options of a {@link DisTube} instance.\n *\n * They are overridden by the options given to the constructor of\n * {@link DisTube}.\n */\nexport const defaultOptions = {\n plugins: [],\n emitNewSongOnly: false,\n savePreviousSongs: true,\n nsfw: false,\n emitAddSongWhenCreatingQueue: true,\n emitAddListWhenCreatingQueue: true,\n joinNewVoiceChannel: true,\n unhandledError: \"log\",\n stuckThreshold: STUCK_THRESHOLD_MS,\n preload: false,\n crossfade: {\n duration: DEFAULT_CROSSFADE_DURATION_SECS,\n curve: DEFAULT_CROSSFADE_CURVE,\n warmup: DEFAULT_CROSSFADE_WARMUP_SECS,\n },\n} satisfies DisTubeOptions;\n","import type { Client } from \"discord.js\";\nimport type { DisTube } from \"../DisTube\";\nimport type { Queue } from \"../struct/Queue\";\nimport type { Song } from \"../struct/Song\";\nimport type { DisTubeEvents, DisTubePlugin } from \"../type\";\nimport type { DisTubeHandler } from \"./DisTubeHandler\";\nimport type { Options } from \"./DisTubeOptions\";\nimport type { DisTubeVoiceManager } from \"./manager/DisTubeVoiceManager\";\nimport type { QueueManager } from \"./manager/QueueManager\";\n\n/**\n * The base class of every DisTube internal that needs a reference to the\n * {@link DisTube} instance.\n */\nexport abstract class DisTubeBase {\n /**\n * The DisTube instance this object belongs to.\n */\n distube: DisTube;\n /**\n * Create a new base object.\n * @param distube - The DisTube instance\n */\n constructor(distube: DisTube) {\n this.distube = distube;\n }\n /**\n * Emit the {@link DisTube} of this base\n * @param eventName - Event name\n * @param args - arguments\n * @returns `true` when the event had listeners, `false` otherwise\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\n * @param queue - The queue encountered the error\n * @param song - The playing song when encountered the error\n * @returns Nothing\n */\n emitError(error: Error, queue: Queue, song?: Song) {\n this.distube.emitError(error, queue, song);\n }\n /**\n * Emit debug event\n * @param message - debug message\n * @returns Nothing\n */\n debug(message: string) {\n this.distube.debug(message);\n }\n /**\n * The queue manager\n */\n get queues(): QueueManager {\n return this.distube.queues;\n }\n /**\n * The voice manager\n */\n get voices(): DisTubeVoiceManager {\n return this.distube.voices;\n }\n /**\n * Discord.js client\n */\n get client(): Client {\n return this.distube.client;\n }\n /**\n * DisTube options\n */\n get options(): Options {\n return this.distube.options;\n }\n /**\n * DisTube handler\n */\n get handler(): DisTubeHandler {\n return this.distube.handler;\n }\n /**\n * DisTube plugins\n */\n get plugins(): DisTubePlugin[] {\n return this.distube.plugins;\n }\n}\n","import { request } from \"undici\";\nimport { HTTP_REDIRECT_CODES, MAX_REDIRECT_DEPTH } from \"../constant\";\nimport { DisTubeError } from \"../struct/DisTubeError\";\nimport type { ExtractorPlugin } from \"../struct/ExtractorPlugin\";\nimport { Playlist } from \"../struct/Playlist\";\nimport { Song } from \"../struct/Song\";\nimport type { DisTubePlugin, ResolveOptions } from \"../type\";\nimport { PluginType } from \"../type\";\nimport { isURL } from \"../util\";\nimport { DisTubeBase } from \"./DisTubeBase\";\n\n/**\n * DisTube's Handler\n */\nexport class DisTubeHandler extends DisTubeBase {\n /**\n * Resolve a {@link Song} to a {@link Song}.\n * @param song - The song to resolve\n * @param options - Optional options\n * @returns The resolved song\n */\n resolve<T = unknown>(song: Song<T>, options?: Omit<ResolveOptions, \"metadata\">): Promise<Song<T>>;\n /**\n * Resolve a {@link Playlist} to a {@link Playlist}.\n * @param song - The playlist to resolve\n * @param options - Optional options\n * @returns The resolved playlist\n */\n resolve<T = unknown>(song: Playlist<T>, options?: Omit<ResolveOptions, \"metadata\">): Promise<Playlist<T>>;\n /**\n * Resolve a url or a search query to a {@link Song} or a {@link Playlist}.\n * @param song - The url or the search query to resolve\n * @param options - Optional options\n * @returns The resolved song or playlist\n */\n resolve<T = unknown>(song: string, options?: ResolveOptions<T>): Promise<Song<T> | Playlist<T>>;\n /**\n * Resolve a {@link Song} to a {@link Song}.\n * @param song - The song to resolve\n * @param options - Optional options\n * @returns The resolved song\n */\n resolve<T = unknown>(song: Song, options: ResolveOptions<T>): Promise<Song<T>>;\n /**\n * Resolve a {@link Playlist} to a {@link Playlist}.\n * @param song - The playlist to resolve\n * @param options - Optional options\n * @returns The resolved playlist\n */\n resolve<T = unknown>(song: Playlist, options: ResolveOptions<T>): Promise<Playlist<T>>;\n /**\n * Resolve a url or a supported object to a {@link Song} or {@link Playlist}\n * @throws {@link DisTubeError}\n * @param song - Resolvable input\n * @param options - Optional options\n * @returns Resolved\n * @example\n * ```ts\n * const song = await distube.handler.resolve(\"Never gonna give you up\");\n * ```\n */\n resolve(song: string | Song | Playlist, options?: ResolveOptions): Promise<Song | Playlist>;\n /**\n * Resolve a url or a supported object to a {@link Song} or {@link Playlist}\n * @throws {@link DisTubeError}\n * @param input - Resolvable input\n * @param options - Optional options\n * @returns Resolved\n */\n async resolve(input: string | Song | Playlist, options: ResolveOptions = {}): Promise<Song | Playlist> {\n if (input instanceof Song || input instanceof Playlist) {\n if (\"metadata\" in options) input.metadata = options.metadata;\n if (\"member\" in options) input.member = options.member;\n return input;\n }\n if (typeof input === \"string\") {\n if (isURL(input)) {\n const plugin =\n (await this._getPluginFromURL(input)) ||\n (await this._getPluginFromURL((input = await this.followRedirectLink(input))));\n if (!plugin) throw new DisTubeError(\"NOT_SUPPORTED_URL\");\n this.debug(`[${plugin.constructor.name}] Resolving from url: ${input}`);\n return plugin.resolve(input, options);\n }\n try {\n const song = await this.#searchSong(input, options);\n if (song) return song;\n } catch (e: unknown) {\n // Keep the original error as the cause so that it is not lost.\n const error = new DisTubeError(\"NO_RESULT\", input);\n error.cause = e;\n throw error;\n }\n }\n throw new DisTubeError(\"CANNOT_RESOLVE_SONG\", input);\n }\n\n /**\n * Find the plugin that supports the given url.\n * @param url - The url to check\n * @returns The plugin, or `null` when there is none\n */\n async _getPluginFromURL(url: string): Promise<DisTubePlugin | null> {\n for (const plugin of this.plugins) if (await plugin.validate(url)) return plugin;\n return null;\n }\n\n /**\n * Find the plugin that can handle the given song.\n * @param song - The song\n * @returns The plugin, or `null` when there is none\n */\n _getPluginFromSong(song: Song): Promise<DisTubePlugin | null>;\n /**\n * Find the plugin of the given type that can handle the given song.\n * @param song - The song\n * @param types - The types of the plugin to look for\n * @param validate - Whether the url of the song has to be validated\n * @returns The plugin, or `null` when there is none\n */\n _getPluginFromSong<T extends PluginType>(\n song: Song,\n types: T[],\n validate?: boolean,\n ): Promise<(DisTubePlugin & { type: T }) | null>;\n async _getPluginFromSong<T extends PluginType>(\n song: Song,\n types?: T[],\n validate = true,\n ): Promise<(DisTubePlugin & { type: T }) | null> {\n if (!types || types.includes(<T>song.plugin?.type)) return song.plugin as DisTubePlugin & { type: T };\n if (!song.url) return null;\n for (const plugin of this.plugins) {\n if ((!types || types.includes(<T>plugin?.type)) && (!validate || (await plugin.validate(song.url)))) {\n return plugin as DisTubePlugin & { type: T };\n }\n }\n return null;\n }\n\n async #searchSong(query: string, options: ResolveOptions = {}, getStreamURL = false): Promise<Song | null> {\n const source = options.source?.toLowerCase();\n const plugins = this.plugins.filter(\n (plugin): plugin is ExtractorPlugin =>\n plugin.type === PluginType.EXTRACTOR && (!source || plugin.identifiers.includes(source)),\n );\n if (!plugins.length) throw new DisTubeError(\"NO_EXTRACTOR_PLUGIN\");\n for (const plugin of plugins) {\n this.debug(`[${plugin.constructor.name}] Searching for song: ${query}`);\n const result = await plugin.searchSong(query, options);\n if (result) {\n if (getStreamURL && result.stream.playFromSource) result.stream.url = await plugin.getStreamURL(result);\n return result;\n }\n }\n return null;\n }\n\n /**\n * Get {@link Song}'s stream info and attach it to the song.\n * @param song - A Song\n * @returns A promise that resolves when the stream info is attached\n * @throws {@link DisTubeError} When no plugin supports the song, or when its\n * stream URL cannot be found\n */\n async attachStreamInfo(song: Song) {\n if (song.stream.playFromSource) {\n if (song.stream.url) return;\n this.debug(`[DisTubeHandler] Getting stream info: ${song}`);\n const plugin = await this._getPluginFromSong(song, [PluginType.EXTRACTOR, PluginType.PLAYABLE_EXTRACTOR]);\n if (!plugin) throw new DisTubeError(\"NOT_SUPPORTED_SONG\", song.toString());\n this.debug(`[${plugin.constructor.name}] Getting stream URL: ${song}`);\n song.stream.url = await plugin.getStreamURL(song);\n if (!song.stream.url) throw new DisTubeError(\"CANNOT_GET_STREAM_URL\", song.toString());\n } else {\n if (song.stream.song?.stream?.playFromSource && song.stream.song.stream.url) return;\n this.debug(`[DisTubeHandler] Getting stream info: ${song}`);\n // The song comes from a plugin that cannot play it: look for a playable\n // version of it with the other plugins.\n const source = song.plugin;\n const query = source\n ? await source.createSearchQuery(song)\n : `${song.name ?? \"\"} ${song.uploader?.name ?? \"\"}`.trim();\n if (!query) throw new DisTubeError(\"CANNOT_GET_SEARCH_QUERY\", song.toString());\n const altSong = await this.#findPlayableSong(query, song, source);\n song.stream.song = altSong;\n }\n }\n\n /**\n * Look for a playable version of a song with the plugins that can search.\n *\n * Every searchable plugin is tried, in the order they were registered, until\n * one of them has a result.\n * @param query - The search query\n * @param song - The song that cannot be played\n * @param source - The plugin that resolved the song\n * @returns The playable song\n */\n async #findPlayableSong(query: string, song: Song, source: DisTubePlugin | null): Promise<Song> {\n const options: ResolveOptions = { metadata: song.metadata, member: song.member };\n for (const plugin of this.plugins) {\n if (plugin === source) continue;\n // A plugin that cannot play its own songs cannot provide a playable\n // version of them either.\n if (plugin.playable === false) continue;\n const result = await plugin.searchSong(query, options);\n if (!result) continue;\n // The result has to be playable, otherwise the playback would fail later\n // with a confusing error.\n if (!result.stream.playFromSource) continue;\n this.debug(`[${plugin.constructor.name}] Found a playable version of \"${query}\"`);\n result.stream.url = await plugin.getStreamURL(result);\n return result;\n }\n throw new DisTubeError(\"NO_RESULT\", query);\n }\n\n /**\n * Follow the redirections of an url.\n * @param url - The url to follow\n * @param maxRedirect - The maximum number of redirections to follow\n * @returns The final url\n */\n async followRedirectLink(url: string, maxRedirect = MAX_REDIRECT_DEPTH): Promise<string> {\n if (maxRedirect === 0) return url;\n\n const res = await request(url, {\n method: \"HEAD\",\n headers: {\n \"user-agent\":\n \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) \" +\n \"Chrome/129.0.0.0 Safari/537.3\",\n },\n });\n\n if (HTTP_REDIRECT_CODES.has(res.statusCode ?? 200)) {\n let location = res.headers.location;\n if (typeof location !== \"string\") location = location?.[0] ?? url;\n return this.followRedirectLink(location, --maxRedirect);\n }\n\n return url;\n }\n}\n","import { inspect } from \"node:util\";\n\n/**\n * The table of the error messages of DisTube.\n *\n * Every entry is the message of one error code. A message can be a template\n * that receives the arguments of the error.\n */\nconst ERROR_MESSAGES = {\n /**\n * A value does not have the expected type.\n *\n * It is raised when an argument of a public method is not of the type that\n * the method expects, e.g. when a voice channel is not a voice channel.\n */\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 /**\n * A number is not in the expected range.\n *\n * It is raised when a numeric argument is out of the range that the method\n * accepts, e.g. a negative volume.\n */\n NUMBER_COMPARE: (name: string, expected: string, value: number) => `'${name}' must be ${expected} ${value}`,\n /**\n * An array is empty.\n *\n * It is raised when an argument that must hold at least one element is\n * empty, e.g. the songs of a custom playlist.\n */\n EMPTY_ARRAY: (name: string) => `'${name}' is an empty array`,\n /**\n * An array does not have any valid element.\n *\n * It is raised when every element of an array was filtered out, e.g. when\n * all the songs of an array are invalid.\n */\n EMPTY_FILTERED_ARRAY: (name: string, type: string) => `There is no valid '${type}' in the '${name}' array`,\n /**\n * A string is empty.\n *\n * It is raised when a string argument that must not be empty is empty.\n */\n EMPTY_STRING: (name: string) => `'${name}' string must not be empty`,\n /**\n * An object has a key that is not allowed.\n *\n * It is raised when an options object has a key that DisTube does not know,\n * e.g. `{ emitNewSong: true }` instead of `{ emitNewSongOnly: true }`.\n */\n INVALID_KEY: (obj: string, key: string) => `'${key}' does not need to be provided in ${obj}`,\n /**\n * A required key is missing.\n *\n * It is raised when an object does not have a key that DisTube needs.\n */\n MISSING_KEY: (obj: string, key: string) => `'${key}' needs to be provided in ${obj}`,\n /**\n * Several required keys are missing.\n *\n * It is raised when an object does not have the keys that DisTube needs.\n */\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 /**\n * The Discord.js client does not have the required intents.\n *\n * It is raised when the `GuildVoiceStates` intent is missing: DisTube\n * cannot work without it.\n */\n MISSING_INTENTS: (i: string) => `${i} intent must be provided for the Client`,\n /**\n * A DisTube option that is needed is disabled.\n *\n * It is raised when a feature cannot work because one of its options is\n * disabled, e.g. {@link Queue#previous} when\n * {@link DisTubeOptions.savePreviousSongs} is `false`.\n */\n DISABLED_OPTION: (o: string) => `DisTubeOptions.${o} is disabled`,\n /**\n * A DisTube option that must be disabled is enabled.\n *\n * It is raised when a feature cannot work because one of its options is\n * enabled.\n */\n ENABLED_OPTION: (o: string) => `DisTubeOptions.${o} is enabled`,\n\n /**\n * The user is not in any voice channel.\n *\n * It is raised when a command needs the voice channel of the user, but the\n * user is not connected to any voice channel.\n */\n NOT_IN_VOICE: \"User is not in any voice channel\",\n /**\n * The voice channel is full.\n *\n * It is raised when the bot cannot join a voice channel because it is\n * full.\n */\n VOICE_FULL: \"The voice channel is full\",\n /**\n * The guild already has a voice connection that DisTube does not manage.\n *\n * It is raised when DisTube cannot create a voice connection because\n * another one already exists in the guild.\n */\n VOICE_ALREADY_CREATED: \"This guild already has a voice connection which is not managed by DisTube\",\n /**\n * The voice connection could not be established in time.\n *\n * It is raised when the connection did not become ready before\n * {@link JOIN_TIMEOUT_MS}.\n */\n VOICE_CONNECT_FAILED: (s: number) => `Cannot connect to the voice channel after ${s} seconds`,\n /**\n * The bot does not have the permission to join the voice channel.\n *\n * It is raised when the bot cannot join a voice channel because of a missing\n * permission.\n */\n VOICE_MISSING_PERMS: \"I do not have permission to join this voice channel\",\n /**\n * The voice connection could not be restored.\n *\n * It is raised when every reconnection attempt of\n * {@link RECONNECT_MAX_ATTEMPTS} failed.\n */\n VOICE_RECONNECT_FAILED: \"Cannot reconnect to the voice channel\",\n /**\n * The voice channel belongs to another guild.\n *\n * It is raised when a voice connection is asked to join a voice channel of\n * another guild.\n */\n VOICE_DIFFERENT_GUILD: \"Cannot join a voice channel in a different guild\",\n /**\n * The voice channel belongs to another client.\n *\n * It is raised when a voice connection is asked to join a voice channel\n * that was created by another Discord.js client.\n */\n VOICE_DIFFERENT_CLIENT: \"Cannot join a voice channel created by a different client\",\n\n /**\n * The FFmpeg process exited with an unexpected code.\n *\n * It is raised when the FFmpeg process that decodes the audio exits with a\n * code that is neither `0` nor `255`.\n */\n FFMPEG_EXITED: (code: number) => `ffmpeg exited with code ${code}`,\n /**\n * FFmpeg is not installed at the given path.\n *\n * It is raised when the FFmpeg executable cannot be spawned, e.g. when\n * {@link DisTubeOptions.ffmpeg} points to a path that does not exist.\n */\n FFMPEG_NOT_INSTALLED: (path: string) => `ffmpeg is not installed at '${path}' path`,\n /**\n * No encryption library is available.\n *\n * It is raised when Discord cannot decrypt the audio: neither the\n * `aes-256-gcm` cipher of Node.js nor one of the supported third-party\n * encryption libraries is available.\n */\n ENCRYPTION_LIBRARIES_MISSING:\n \"Cannot play audio as no valid encryption package is installed and your node doesn't support aes-256-gcm.\\n\" +\n \"Please install @noble/ciphers, @stablelib/xchacha20poly1305, sodium-native or libsodium-wrappers.\",\n\n /**\n * The guild does not have a playing queue.\n *\n * It is raised when a queue operation is used in a guild that has no\n * {@link Queue}.\n */\n NO_QUEUE: \"There is no playing queue in this guild\",\n /**\n * The guild already has a queue.\n *\n * It is raised when a {@link Queue} is created for a guild that already\n * has one.\n */\n QUEUE_EXIST: \"This guild has a Queue already\",\n /**\n * The queue has been stopped already.\n *\n * It is raised when an operation needs a running queue, but the queue was\n * stopped.\n */\n QUEUE_STOPPED: \"The queue has been stopped already\",\n /**\n * The queue is already paused.\n *\n * It is raised when {@link Queue#pause} is used on a paused queue.\n */\n PAUSED: \"The queue has been paused already\",\n /**\n * The queue is already playing.\n *\n * It is raised when {@link Queue#resume} is used on a queue that is not\n * paused.\n */\n RESUMED: \"The queue has been playing already\",\n /**\n * The queue does not have any previous song.\n *\n * It is raised when {@link Queue#previous} is used on a queue without any\n * history.\n */\n NO_PREVIOUS: \"There is no previous song in this queue\",\n /**\n * The queue does not have any up next song.\n *\n * It is raised when a jump goes past the end of the queue while the\n * autoplay mode is disabled.\n */\n NO_UP_NEXT: \"There is no up next song\",\n /**\n * The queue does not have any song at the given position.\n *\n * It is raised when {@link Queue#jump} is used with a position that is out\n * of the bounds of the queue.\n */\n NO_SONG_POSITION: \"Does not have any song at this position\",\n /**\n * The queue does not have any playing song.\n *\n * It is raised when a related song is requested but the queue is empty.\n */\n NO_PLAYING_SONG: \"There is no playing song in the queue\",\n /**\n * The track is stuck and does not produce any audio.\n *\n * It is raised when a track stays in the \"buffering\" state for longer than\n * {@link DisTubeOptions.stuckThreshold} milliseconds. The queue skips it.\n */\n TRACK_STUCK: \"The track is stuck and not producing any audio\",\n /**\n * There is no extractor plugin.\n *\n * It is raised when a search is requested but no {@link ExtractorPlugin} is\n * registered in {@link DisTubeOptions.plugins}.\n */\n NO_EXTRACTOR_PLUGIN: \"There is no extractor plugin in the DisTubeOptions.plugins, please add one for searching songs\",\n /**\n * No related song could be found.\n *\n * It is raised when the autoplay mode is enabled and no plugin could find\n * a related song for the current one.\n */\n NO_RELATED: \"Cannot find any related songs\",\n /**\n * The related song cannot be played.\n *\n * It is raised when the related song of the autoplay mode cannot be\n * played.\n */\n CANNOT_PLAY_RELATED: \"Cannot play the related song\",\n /**\n * The video is unavailable.\n *\n * It is raised when the source of the song does not have the video anymore,\n * e.g. when it was removed or when it is private.\n */\n UNAVAILABLE_VIDEO: \"This video is unavailable\",\n /**\n * No playable format was found.\n *\n * It is raised when the source of the song does not have any format that\n * FFmpeg can play.\n */\n UNPLAYABLE_FORMATS: \"No playable format found\",\n /**\n * The content is age-restricted and cannot be played in this channel.\n *\n * It is raised when an age-restricted song is played in a non-NSFW channel\n * while {@link DisTubeOptions.nsfw} is `false`.\n */\n NON_NSFW: \"Cannot play age-restricted content in non-NSFW channel\",\n /**\n * The url is not supported.\n *\n * It is raised when no plugin of {@link DisTubeOptions.plugins} can handle\n * the url.\n */\n NOT_SUPPORTED_URL: \"This url is not supported\",\n /**\n * No plugin supports the song.\n *\n * It is raised when no plugin of {@link DisTubeOptions.plugins} can play\n * the song.\n */\n NOT_SUPPORTED_SONG: (song: string) => `There is no plugin supporting this song (${song})`,\n /**\n * The array does not have any valid song.\n *\n * It is raised when every element of the `songs` array of\n * {@link DisTube#createCustomPlaylist} is neither a {@link Song} nor a\n * valid url.\n */\n NO_VALID_SONG: \"'songs' array does not have any valid Song or url\",\n /**\n * The input cannot be resolved to a song or a playlist.\n *\n * It is raised when the input of {@link DisTubeHandler#resolve} is neither\n * a url, nor a {@link Song}, nor a {@link Playlist}.\n */\n CANNOT_RESOLVE_SONG: (t: any) => `Cannot resolve ${inspect(t)} to a Song`,\n /**\n * The stream url of the song cannot be found.\n *\n * It is raised when the plugin of the song does not return a stream url.\n */\n CANNOT_GET_STREAM_URL: (song: string) => `Cannot get stream url with this song (${song})`,\n /**\n * The search query of the song cannot be built.\n *\n * It is raised when the plugin of the song cannot build a query to look for\n * a playable version of it.\n */\n CANNOT_GET_SEARCH_QUERY: (song: string) => `Cannot get search query with this song (${song})`,\n /**\n * No song was found for the query.\n *\n * It is raised when no plugin of {@link DisTubeOptions.plugins} has any\n * result for the search query.\n */\n NO_RESULT: (query: string) => `Cannot find any song with this query (${query})`,\n /**\n * The song does not have any stream url.\n *\n * It is raised when a song is played while it does not have a stream url\n * attached to it.\n */\n NO_STREAM_URL: (song: string) => `No stream url attached (${song})`,\n\n /**\n * Every video of the playlist was filtered out.\n *\n * It is raised when a playlist does not have any valid video left, e.g.\n * because all of them were age-restricted and the channel is not NSFW.\n */\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 /**\n * The playlist does not have any valid video.\n *\n * It is raised when a playlist is empty.\n */\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 if (!haveCode(code)) return args[0];\n try {\n return parseMessage(ERROR_MESSAGES[code], ...args);\n } catch {\n // The error code needs more arguments than the ones that were given.\n return args[0] ?? code;\n }\n};\n\n/**\n * The error raised by DisTube.\n *\n * Every error of the library is a `DisTubeError`: it has a machine readable\n * `errorCode` and a human readable message that is built from the code.\n *\n * @example\n * ```ts\n * try {\n * await distube.play(channel, \"Never gonna give you up\");\n * } catch (error) {\n * if (error instanceof DisTubeError && error.errorCode === \"NO_RESULT\") {\n * // No song was found for the query.\n * }\n * }\n * ```\n */\nexport class DisTubeError<T extends string = any> extends Error {\n /**\n * The code of the error, e.g. `NO_RESULT`.\n */\n errorCode: string;\n /**\n * Create a DisTube error with a static error code.\n * @param code - The code of the error\n */\n constructor(code: T extends StaticErrorCode ? T : never);\n /**\n * Create a DisTube error with a templated error code.\n * @param code - The code of the error\n * @param args - The arguments of the message template of the code\n */\n constructor(code: T extends TemplateErrorCode ? T : never, ...args: Parameters<ErrorMessage[typeof code]>);\n /**\n * Create a DisTube error with a templated error code.\n * @param code - The code of the error\n * @param _ - Not used: it prevents this overload from being selected\n */\n constructor(code: TemplateErrorCode, _: never);\n /**\n * Create a DisTube error with a custom message.\n * @param code - The code of the error\n * @param message - The custom message of the error\n */\n constructor(code: T extends ErrorCode ? never : T, message: string);\n /**\n * Create a DisTube error.\n * @param code - The code of the error\n * @param args - The arguments of the message template of the code\n */\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 /**\n * Create a {@link DisTubeError} with a custom message.\n *\n * The default message of an error code is a generic template. Use this factory\n * when you need to tell the user what exactly went wrong, or when you want to\n * keep the original error as the `cause` of the error.\n *\n * It is polymorphic: calling it on a subclass creates an instance of that\n * subclass.\n *\n * @param code - The error code\n * @param message - The custom message\n * @param options - Optional options\n * @param options.cause - The original error that caused this one\n * @returns The created error\n */\n static withMessage<T extends string = any>(code: T, message: string, options?: { cause?: unknown }): DisTubeError<T> {\n // biome-ignore lint/complexity/noThisInStatic: the factory has to create an instance of the class it is called on\n const error = new (this as any)(code, message) as DisTubeError<T>;\n error.message = message;\n if (options && \"cause\" in options) error.cause = options.cause;\n return error;\n }\n\n /**\n * The name of the error, with its code.\n * @returns The name of the error, e.g. `DisTubeError [NO_RESULT]`\n */\n override get name() {\n return `DisTubeError [${this.errorCode}]`;\n }\n\n /**\n * The code of the error, e.g. `NO_RESULT`.\n *\n * It is an alias of {@link DisTubeError.errorCode}.\n * @returns The code of the error\n */\n get code() {\n return this.errorCode;\n }\n}\n","import { URL } from \"node:url\";\nimport type {\n Client,\n ClientOptions,\n Guild,\n GuildMember,\n GuildTextBasedChannel,\n Message,\n Snowflake,\n VoiceBasedChannel,\n VoiceState,\n} from \"discord.js\";\nimport { Constants, GatewayIntentBits, IntentsBitField, SnowflakeUtil } from \"discord.js\";\nimport { DisTubeVoice } from \"./core/DisTubeVoice\";\nimport { DisTubeError } from \"./struct/DisTubeError\";\nimport { Queue } from \"./struct/Queue\";\nimport type { GuildIdResolvable, UnhandledErrorBehavior } from \"./type\";\n\nconst formatInt = (int: number) => (int < 10 ? `0${int}` : int);\n\n/**\n * Format duration to string\n * @param sec - Duration in seconds\n * @returns The formatted duration, e.g. `01:23` or `01:02:03`\n */\nexport function formatDuration(sec: number): string {\n if (!sec || !Number(sec)) return \"00:00\";\n const seconds = Math.floor(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}\nconst SUPPORTED_PROTOCOL = [\"https:\", \"http:\", \"file:\"] as const;\n/**\n * Check if the string is an URL\n * @param input - input\n * @returns `true` when the input is an URL with a supported protocol\n */\nexport function isURL(input: any): input is `${(typeof SUPPORTED_PROTOCOL)[number]}//${string}` {\n if (typeof input !== \"string\" || input.includes(\" \")) return false;\n try {\n const url = new URL(input);\n if (!SUPPORTED_PROTOCOL.some(p => p === url.protocol)) 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 options - options\n * @returns Nothing\n * @throws {@link DisTubeError} When the `GuildVoiceStates` intent is missing\n */\nexport function checkIntents(options: ClientOptions): void {\n // The `instanceof` check is not used on purpose: a project can have more than\n // one copy of discord.js in its tree (a linked package, a monorepo, ...), and\n // the intents of the client would not be an instance of our own IntentsBitField.\n const intents = options.intents as unknown as { has?: (bit: number | bigint) => boolean };\n const hasVoiceStates =\n typeof intents?.has === \"function\"\n ? intents.has(GatewayIntentBits.GuildVoiceStates)\n : new IntentsBitField(options.intents as never).has(GatewayIntentBits.GuildVoiceStates);\n if (!hasVoiceStates) throw new DisTubeError(\"MISSING_INTENTS\", \"GuildVoiceStates\");\n}\n\n/**\n * Check if the voice channel is empty\n * @param voiceState - voiceState\n * @returns `true` when there is no human user in the voice channel of the state\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\n/**\n * Check if the value is a valid Discord snowflake.\n * @param id - The value to check\n * @returns `true` when the value is a valid snowflake\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\n/**\n * Check if the value is a Discord.js guild member.\n * @param member - The value to check\n * @returns `true` when the value looks like a guild member\n */\nexport function isMemberInstance(member: any): member is GuildMember {\n return (\n Boolean(member) &&\n isSnowflake(member.id) &&\n isSnowflake(member.guild?.id) &&\n isSnowflake(member.user?.id) &&\n member.id === member.user.id\n );\n}\n\n/**\n * Check if the value is a Discord.js guild text based channel.\n * @param channel - The value to check\n * @returns `true` when the value looks like a guild text based channel\n */\nexport function isTextChannelInstance(channel: any): channel is GuildTextBasedChannel {\n return (\n Boolean(channel) &&\n isSnowflake(channel.id) &&\n isSnowflake(channel.guildId || channel.guild?.id) &&\n Constants.TextBasedChannelTypes.includes(channel.type) &&\n typeof channel.send === \"function\" &&\n (typeof channel.nsfw === \"boolean\" || typeof channel.parent?.nsfw === \"boolean\")\n );\n}\n\n/**\n * Check if the value is a Discord.js message.\n * @param message - The value to check\n * @returns `true` when the value looks like a message\n */\nexport function isMessageInstance(message: any): message is Message<true> {\n // Simple check for using distube normally\n return (\n Boolean(message) &&\n isSnowflake(message.id) &&\n isSnowflake(message.guildId || message.guild?.id) &&\n isMemberInstance(message.member) &&\n isTextChannelInstance(message.channel) &&\n Constants.NonSystemMessageTypes.includes(message.type) &&\n message.member.id === message.author?.id\n );\n}\n\n/**\n * Check if the value is a Discord.js voice based channel.\n * @param channel - The value to check\n * @returns `true` when the value looks like a voice based channel\n */\nexport function isSupportedVoiceChannel(channel: any): channel is VoiceBasedChannel {\n return (\n Boolean(channel) &&\n isSnowflake(channel.id) &&\n isSnowflake(channel.guildId || channel.guild?.id) &&\n Constants.VoiceBasedChannelTypes.includes(channel.type)\n );\n}\n\n/**\n * Check if the value is a Discord.js guild.\n * @param guild - The value to check\n * @returns `true` when the value looks like a guild\n */\nexport function isGuildInstance(guild: any): guild is Guild {\n return Boolean(guild) && isSnowflake(guild.id) && isSnowflake(guild.ownerId) && typeof guild.name === \"string\";\n}\n\n/**\n * Resolve a guild id from anything that can be resolved to a guild id.\n * @param resolvable - The value to resolve\n * @returns The id of the guild\n * @throws {@link DisTubeError} When the value cannot be resolved to a guild id\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\n/**\n * Check if the value is a Discord.js client.\n * @param client - The value to check\n * @returns `true` when the value looks like a client\n */\nexport function isClientInstance(client: any): client is Client {\n return Boolean(client) && typeof client.login === \"function\";\n}\n\n/**\n * Check that an object does not have any key that is not in a source.\n * @param target - The object to check\n * @param source - The valid keys, or the object that holds them\n * @param sourceName - The name of the source, used in the error message\n * @returns Nothing\n * @throws {@link DisTubeError} When the target is not an object, or when it has\n * an invalid key\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 : objectKeys(source);\n const invalidKey = objectKeys(target).find(key => !sourceKeys.includes(key));\n if (invalidKey) throw new DisTubeError(\"INVALID_KEY\", sourceName, invalidKey);\n}\n\n/**\n * Check if the value is a plain object.\n * @param obj - The value to check\n * @returns `true` when the value is an object and not an array nor `null`\n */\nexport function isObject(obj: any): obj is object {\n return typeof obj === \"object\" && obj !== null && !Array.isArray(obj);\n}\n\n/**\n * The keys of a type, as an array.\n */\nexport type KeyOf<T> = T extends object ? (keyof T)[] : [];\n/**\n * Get the keys of an object.\n * @param obj - The object\n * @returns The keys of the object, or an empty array when it is not an object\n */\nexport function objectKeys<T>(obj: T): KeyOf<T> {\n if (!isObject(obj)) return [] as KeyOf<T>;\n return Object.keys(obj) as KeyOf<T>;\n}\n\n/**\n * Check if the channel is age-restricted.\n * @param channel - The channel to check\n * @returns `true` when the channel is a NSFW channel\n */\nexport function isNsfwChannel(channel?: GuildTextBasedChannel): boolean {\n if (!isTextChannelInstance(channel)) return false;\n if (channel.isThread()) return channel.parent?.nsfw ?? false;\n return channel.nsfw;\n}\n\n/**\n * The falsy values of JavaScript.\n */\nexport type Falsy = undefined | null | false | 0 | \"\";\n/**\n * Check if a value is not falsy.\n * @param x - The value to check\n * @returns `true` when the value is not falsy\n */\nexport const isTruthy = <T>(x: T | Falsy): x is T => Boolean(x);\n\n/**\n * Handle an error that was emitted through the special `\"error\"` event without\n * any listener.\n *\n * Node.js throws an `ERR_UNHANDLED_ERROR` in that situation, which crashes the\n * whole process. DisTube handles it gracefully instead.\n * @param error - The error\n * @param behavior - The behavior to apply. Defaults to `\"log\"`.\n * @returns Nothing\n * @throws The given error when the behavior is `\"throw\"`\n */\nexport function handleUnhandledError(error: Error, behavior: UnhandledErrorBehavior = \"log\"): void {\n if (behavior === \"throw\") throw error;\n if (behavior === \"ignore\") return;\n process.emitWarning(\n \"The 'error' event was emitted but there is no listener for it. \" +\n \"Add a listener with `distube.on(Events.ERROR, (error, queue, song) => { ... })` \" +\n \"to handle DisTube errors, or set `unhandledError` to 'throw' to restore the default behavior.\",\n {\n code: \"DIS_TUBE_UNHANDLED_ERROR\",\n detail: error?.stack ?? error?.message ?? String(error),\n },\n );\n}\n\n/**\n * Check that an encryption library is available.\n *\n * Discord encrypts the audio with DAVE, so a cipher is required to play it.\n * The `aes-256-gcm` cipher of Node.js is used when it is available, otherwise\n * one of the supported third-party libraries is used.\n * @returns `true` when an encryption library is available\n */\nexport const checkEncryptionLibraries = async () => {\n if (await import(\"node:crypto\").then(m => m.getCiphers().includes(\"aes-256-gcm\"))) return true;\n for (const lib of [\n \"@noble/ciphers\",\n \"@stablelib/xchacha20poly1305\",\n \"sodium-native\",\n \"sodium\",\n \"libsodium-wrappers\",\n \"tweetnacl\",\n ]) {\n try {\n await import(lib);\n return true;\n } catch {}\n }\n return false;\n};\n","import type { AudioPlayer, VoiceConnection } from \"@discordjs/voice\";\nimport {\n AudioPlayerStatus,\n createAudioPlayer,\n entersState,\n joinVoiceChannel,\n VoiceConnectionDisconnectReason,\n VoiceConnectionStatus,\n} from \"@discordjs/voice\";\nimport type { Snowflake, VoiceBasedChannel, VoiceState } from \"discord.js\";\nimport { Constants } from \"discord.js\";\nimport { TypedEmitter } from \"tiny-typed-emitter\";\nimport { JOIN_TIMEOUT_MS, RECONNECT_MAX_ATTEMPTS, RECONNECT_TIMEOUT_MS } from \"../constant\";\nimport { DisTubeError } from \"../struct/DisTubeError\";\nimport type { DisTubeVoiceEvents } from \"../type\";\nimport { checkEncryptionLibraries, handleUnhandledError, isSupportedVoiceChannel } from \"../util\";\nimport type { DisTubeStream } from \"./DisTubeStream\";\nimport type { DisTubeVoiceManager } from \"./manager/DisTubeVoiceManager\";\n\n/**\n * Create a voice connection to the voice channel\n */\nexport class DisTubeVoice extends TypedEmitter<DisTubeVoiceEvents> {\n /**\n * The id of the guild of this voice connection.\n */\n readonly id: Snowflake;\n /**\n * The voice manager that instantiated this connection.\n */\n readonly voices: DisTubeVoiceManager;\n /**\n * The audio player that plays the audio of this connection.\n */\n readonly audioPlayer: AudioPlayer;\n /**\n * The Discord.js voice connection.\n */\n connection!: VoiceConnection;\n /**\n * Whether or not an error was already emitted for the current stream.\n *\n * It prevents the same error from being emitted several times.\n */\n emittedError!: boolean;\n /**\n * Whether or not the voice connection has been disconnected.\n */\n isDisconnected = false;\n /**\n * The stream that is currently playing.\n */\n stream?: DisTubeStream;\n /**\n * The stream that was playing when the playback was paused.\n */\n pausingStream?: DisTubeStream;\n #channel!: VoiceBasedChannel;\n #volume = 100;\n /**\n * Timer used to detect a track that is stuck in the \"buffering\" state.\n */\n #stuckTimer?: NodeJS.Timeout;\n /**\n * Create a voice connection to the voice channel.\n * @param voiceManager - The voice manager of the DisTube instance\n * @param channel - The voice channel to join\n */\n constructor(voiceManager: DisTubeVoiceManager, channel: VoiceBasedChannel) {\n super();\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 this.#clearStuckTimer();\n if (oldState.status !== AudioPlayerStatus.Idle) this.emit(\"finish\");\n })\n .on(AudioPlayerStatus.Buffering, () => {\n this.#startStuckTimer();\n })\n .on(AudioPlayerStatus.Playing, () => {\n this.#clearStuckTimer();\n })\n .on(\"error\", (error: NodeJS.ErrnoException) => {\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 // User disconnect\n this.leave();\n } else if (newState.reason === VoiceConnectionDisconnectReason.WebSocketClose && newState.closeCode === 4014) {\n // Move to other channel\n entersState(this.connection, VoiceConnectionStatus.Connecting, RECONNECT_TIMEOUT_MS)\n .then(() => entersState(this.connection, VoiceConnectionStatus.Ready, RECONNECT_TIMEOUT_MS))\n .then(() => {\n const oldChannel = this.#channel;\n const currentChannel = this.channel;\n if (oldChannel && currentChannel && oldChannel.id !== currentChannel.id) {\n this.#channel = currentChannel;\n this.emit(\"channelChange\", oldChannel, currentChannel);\n }\n })\n .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 < RECONNECT_MAX_ATTEMPTS) {\n // Try to rejoin\n setTimeout(\n () => {\n this.connection.rejoin();\n },\n (this.connection.rejoinAttempts + 1) * RECONNECT_TIMEOUT_MS,\n ).unref();\n } else if (this.connection.state.status !== VoiceConnectionStatus.Destroyed) {\n // Leave after 5 attempts\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 /**\n * The voice channel id the bot is in\n */\n get channelId() {\n return this.connection?.joinConfig?.channelId ?? undefined;\n }\n /**\n * The voice channel the bot is in.\n *\n * Setting it moves the bot to another voice channel.\n */\n get channel() {\n if (!this.channelId) return this.#channel;\n if (this.#channel?.id === this.channelId) return this.#channel;\n const channel = this.voices.client.channels.cache.get(this.channelId);\n if (!channel) return this.#channel;\n for (const type of Constants.VoiceBasedChannelTypes) {\n if (channel.type === type) {\n this.#channel = channel;\n return channel;\n }\n }\n return this.#channel;\n }\n /**\n * Move the bot to another voice channel.\n * @param channel - The voice channel to join\n * @throws {@link DisTubeError} When the channel is invalid, when it belongs to\n * another guild or client, or when the bot cannot join it\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.channelId) return;\n if (!channel.joinable) {\n if (channel.full) throw new DisTubeError(\"VOICE_FULL\");\n else throw new DisTubeError(\"VOICE_MISSING_PERMS\");\n }\n const oldChannel = this.#channel;\n this.connection = this.#join(channel);\n this.#channel = channel;\n if (oldChannel && oldChannel.id !== channel.id) {\n this.emit(\"channelChange\", oldChannel, channel);\n }\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 // DAVE is the end-to-end encryption protocol used by Discord.\n // It is enabled explicitly so that a change of the upstream default\n // can never silently disable the encryption.\n daveEncryption: true,\n });\n }\n /**\n * Join a voice channel with this connection\n * @param channel - A voice channel\n * @returns The voice connection\n * @throws {@link DisTubeError} When the connection cannot be established\n */\n async join(channel?: VoiceBasedChannel): Promise<DisTubeVoice> {\n if (channel) this.channel = channel;\n try {\n await entersState(this.connection, VoiceConnectionStatus.Ready, JOIN_TIMEOUT_MS);\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\", JOIN_TIMEOUT_MS / 1000);\n }\n return this;\n }\n /**\n * Leave the voice channel of this connection\n * @param error - Optional, an error to emit with 'error' event.\n * @returns Nothing\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 force - If true, will force the {@link DisTubeVoice#audioPlayer} to enter the Idle state even\n * if the {@link DisTubeStream#audioResource} has silence padding frames.\n * @returns Nothing\n */\n stop(force = false) {\n this.audioPlayer.stop(force);\n }\n #streamErrorHandler?: (error: NodeJS.ErrnoException) => void;\n /**\n * Play a {@link DisTubeStream}\n * @param dtStream - DisTubeStream\n * @returns A promise that resolves when the stream is playing\n * @throws {@link DisTubeError} When no encryption library is available\n */\n async play(dtStream: DisTubeStream) {\n if (!(await checkEncryptionLibraries())) {\n dtStream.kill();\n throw new DisTubeError(\"ENCRYPTION_LIBRARIES_MISSING\");\n }\n this.emittedError = false;\n // Remove previous error listener to prevent memory leaks\n if (this.stream && this.#streamErrorHandler) {\n this.stream.off(\"error\", this.#streamErrorHandler);\n }\n this.#streamErrorHandler = (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 dtStream.on(\"error\", this.#streamErrorHandler);\n if (this.audioPlayer.state.status !== AudioPlayerStatus.Paused) {\n this.audioPlayer.play(dtStream.audioResource);\n this.stream?.kill();\n // A crossfade transition stream is already spawned (it warmed up its\n // buffers before the fade window began): only swap the resource.\n if (!dtStream.process) dtStream.spawn();\n } else if (!this.pausingStream) {\n this.pausingStream = this.stream;\n }\n this.stream = dtStream;\n this.volume = this.#volume;\n }\n /**\n * Set the volume percentage of the stream.\n * @param volume - The volume percentage, from `0` to `100`\n * @throws {@link DisTubeError} When the volume is not a number, or when it is\n * negative\n */\n set volume(volume: number) {\n if (typeof volume !== \"number\" || 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.stream?.setVolume((this.#volume / 100) ** (0.5 / Math.log10(2)));\n }\n /**\n * Get or set the volume percentage\n */\n get volume() {\n return this.#volume;\n }\n /**\n * Playback duration of the audio resource in seconds (time since playback started)\n */\n get playbackDuration() {\n return (this.stream?.audioResource?.playbackDuration ?? 0) / 1000;\n }\n /**\n * Current playback time in seconds, accounting for seek offset\n */\n get playbackTime() {\n return this.playbackDuration + (this.stream?.seekTime ?? 0);\n }\n /**\n * Pause the playback of the audio player.\n * @returns Nothing\n */\n pause() {\n this.audioPlayer.pause();\n }\n /**\n * Resume the playback of the audio player.\n *\n * The FFmpeg process is spawned again when the stream was killed while the\n * playback was paused.\n * @returns Nothing\n */\n unpause() {\n const state = this.audioPlayer.state;\n if (state.status !== AudioPlayerStatus.Paused) return;\n if (this.stream?.audioResource && state.resource !== this.stream.audioResource) {\n this.audioPlayer.play(this.stream.audioResource);\n this.stream.spawn();\n this.pausingStream?.kill();\n delete this.pausingStream;\n } else {\n this.audioPlayer.unpause();\n }\n }\n /**\n * Emit an event of the voice connection.\n *\n * The special `\"error\"` event never crashes the process when there is no\n * listener for it, even when the voice connection is used outside of a\n * {@link Queue}.\n * @param event - The event name\n * @param args - The event arguments\n * @returns `true` when the event had listeners, `false` otherwise\n */\n override emit<U extends keyof DisTubeVoiceEvents>(event: U, ...args: Parameters<DisTubeVoiceEvents[U]>): boolean {\n if (event === \"error\" && this.listenerCount(\"error\") === 0) {\n handleUnhandledError(args[0] as Error, this.voices.options?.unhandledError ?? \"log\");\n return false;\n }\n return super.emit(event, ...args);\n }\n\n /**\n * Start the timer that detects a track stuck in the \"buffering\" state.\n *\n * When the track does not start playing within\n * {@link DisTubeOptions.stuckThreshold} milliseconds, it is reported as an error\n * so that the queue can skip it.\n */\n #startStuckTimer() {\n const threshold = this.voices.options.stuckThreshold;\n if (typeof threshold !== \"number\" || threshold <= 0) return;\n this.#clearStuckTimer();\n this.#stuckTimer = setTimeout(() => {\n this.#stuckTimer = undefined;\n if (this.emittedError) return;\n this.emittedError = true;\n this.emit(\"error\", new DisTubeError(\"TRACK_STUCK\"));\n }, threshold);\n this.#stuckTimer.unref?.();\n }\n /**\n * Clear the stuck-track detection timer.\n */\n #clearStuckTimer() {\n if (!this.#stuckTimer) return;\n clearTimeout(this.#stuckTimer);\n this.#stuckTimer = undefined;\n }\n /**\n * Whether the bot is self-deafened\n */\n get selfDeaf(): boolean {\n return this.connection.joinConfig.selfDeaf;\n }\n /**\n * Whether the bot is self-muted\n */\n get selfMute(): boolean {\n return this.connection.joinConfig.selfMute;\n }\n /**\n * Self-deafens/undeafens the bot.\n * @param selfDeaf - Whether or not the bot should be self-deafened\n * @returns true if the voice state was successfully updated, otherwise false\n * @throws {@link DisTubeError} When the value is not a boolean\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 selfMute - Whether or not the bot should be self-muted\n * @returns true if the voice state was successfully updated, otherwise false\n * @throws {@link DisTubeError} When the value is not a boolean\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 */\n get voiceState(): VoiceState | undefined {\n return this.channel?.guild?.members?.me?.voice;\n }\n}\n","import { Collection } from \"discord.js\";\nimport { DisTubeBase } from \"../DisTubeBase\";\n\n/**\n * Manages the collection of a data model.\n */\nexport abstract class BaseManager<V> extends DisTubeBase {\n /**\n * The collection of items for this manager.\n */\n collection = new Collection<string, V>();\n /**\n * The size of the collection.\n */\n get size() {\n return this.collection.size;\n }\n}\n","import type { FFmpegArg as FFmpegArgsValue, Filter, FilterResolvable, Queue } from \"../..\";\nimport { DisTubeError, Events } from \"../..\";\nimport { BaseManager } from \"./BaseManager\";\n\n/**\n * Manage filters of a playing {@link Queue}\n */\nexport class FilterManager extends BaseManager<Filter> {\n /**\n * The queue to manage\n */\n queue: Queue;\n /**\n * Create a filter manager for a queue.\n * @param queue - The queue to manage\n */\n constructor(queue: Queue) {\n super(queue.distube);\n this.queue = queue;\n }\n\n #resolve(filter: FilterResolvable): Filter {\n if (typeof filter === \"object\" && typeof filter.name === \"string\" && typeof filter.value === \"string\") {\n return filter;\n }\n if (typeof filter === \"string\" && Object.hasOwn(this.distube.filters, filter)) {\n return {\n name: filter,\n value: this.distube.filters[filter],\n };\n }\n throw new DisTubeError(\"INVALID_TYPE\", \"FilterResolvable\", filter, \"filter\");\n }\n\n #apply(oldFilters: string[]) {\n this.queue._clearPreload?.();\n const newFilters = this.names;\n const changed = oldFilters.length !== newFilters.length || !oldFilters.every(f => newFilters.includes(f));\n if (changed) {\n this.emit(Events.CHANGE_FILTER, this.queue, newFilters, oldFilters);\n }\n // The FFmpeg audio filters are applied when the stream is created, so the\n // stream has to be restarted. The restart never interrupts the playback for\n // good: a failure keeps the current song in the queue.\n void this.queue._restartStream().catch((e: unknown) => {\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.queue.debug(`[${this.queue.id}] Failed to apply the filters: ${errorMessage}`);\n });\n }\n\n /**\n * Enable a filter or multiple filters to the manager\n * @param filterOrFilters - The filter or filters to enable\n * @param override - Wether or not override the applied filter with new filter value\n * @returns This manager, to allow chaining\n * @throws {@link DisTubeError} When a filter is not a valid {@link FilterResolvable}\n * @example\n * ```ts\n * queue.filters.add(\"bassboost\");\n * ```\n */\n add(filterOrFilters: FilterResolvable | FilterResolvable[], override = false) {\n const oldFilters = this.names;\n if (Array.isArray(filterOrFilters)) {\n for (const filter of filterOrFilters) {\n const ft = this.#resolve(filter);\n if (override || !this.has(ft)) this.collection.set(ft.name, ft);\n }\n } else {\n const ft = this.#resolve(filterOrFilters);\n if (override || !this.has(ft)) this.collection.set(ft.name, ft);\n }\n this.#apply(oldFilters);\n return this;\n }\n\n /**\n * Clear enabled filters of the manager\n * @returns This manager, to allow chaining\n */\n clear() {\n return this.set([]);\n }\n\n /**\n * Set the filters applied to the manager\n * @param filters - The filters to apply\n * @returns This manager, to allow chaining\n * @throws {@link DisTubeError} When the array is invalid, or when a filter is\n * not a valid {@link FilterResolvable}\n */\n set(filters: FilterResolvable[]) {\n if (!Array.isArray(filters)) throw new DisTubeError(\"INVALID_TYPE\", \"Array<FilterResolvable>\", filters, \"filters\");\n const oldFilters = this.names;\n this.collection.clear();\n for (const f of filters) {\n const filter = this.#resolve(f);\n this.collection.set(filter.name, filter);\n }\n this.#apply(oldFilters);\n return this;\n }\n\n #removeFn(f: FilterResolvable) {\n return this.collection.delete(this.#resolve(f).name);\n }\n\n /**\n * Disable a filter or multiple filters\n * @param filterOrFilters - The filter or filters to disable\n * @returns This manager, to allow chaining\n * @throws {@link DisTubeError} When a filter is not a valid {@link FilterResolvable}\n */\n remove(filterOrFilters: FilterResolvable | FilterResolvable[]) {\n const oldFilters = this.names;\n if (Array.isArray(filterOrFilters)) filterOrFilters.forEach(f => this.#removeFn(f));\n else this.#removeFn(filterOrFilters);\n this.#apply(oldFilters);\n return this;\n }\n\n /**\n * Check whether a filter enabled or not\n * @param filter - The filter to check\n * @returns `true` when the filter is enabled\n * @throws {@link DisTubeError} When the filter is not a valid {@link FilterResolvable}\n */\n has(filter: FilterResolvable) {\n return this.collection.has(typeof filter === \"string\" ? filter : this.#resolve(filter).name);\n }\n\n /**\n * Array of enabled filter names\n */\n get names(): string[] {\n return [...this.collection.keys()];\n }\n\n /**\n * Array of enabled filters\n */\n get values(): Filter[] {\n return [...this.collection.values()];\n }\n\n /**\n * The FFmpeg arguments of the enabled filters.\n *\n * It is the `af` output argument of the FFmpeg process.\n */\n get ffmpegArgs(): FFmpegArgsValue {\n return this.size ? { af: this.values.map(f => f.value).join(\",\") } : {};\n }\n\n /**\n * The names of the enabled filters, as a comma separated string.\n * @returns The names of the enabled filters\n */\n override toString() {\n return this.names.toString();\n }\n}\n","import type {\n Guild,\n GuildMember,\n GuildTextBasedChannel,\n Interaction,\n Message,\n Snowflake,\n VoiceBasedChannel,\n VoiceState,\n} from \"discord.js\";\nimport type {\n DisTubeError,\n DisTubeVoice,\n ExtractorPlugin,\n InfoExtractorPlugin,\n PlayableExtractorPlugin,\n Playlist,\n Queue,\n Song,\n} from \".\";\n\n/**\n * A value that can be awaited.\n *\n * It is used by every method of DisTube that can be implemented\n * synchronously or asynchronously: the plugin methods and the event\n * listeners.\n */\nexport type Awaitable<T = any> = T | PromiseLike<T>;\n\n/**\n * Behavior when the {@link Events.ERROR} event is emitted but nobody listens to it.\n * - `log` (default): the error is logged to the console instead of crashing the process\n * - `throw`: the error is re-thrown (Node.js default behavior)\n * - `ignore`: the error is silently discarded\n */\nexport type UnhandledErrorBehavior = \"log\" | \"throw\" | \"ignore\";\n\n/**\n * The events emitted by a {@link DisTube} instance.\n */\nexport enum Events {\n /**\n * Emitted when DisTube encounters an error while playing songs.\n *\n * It is the only special event: Node.js crashes the process when the\n * `\"error\"` event is emitted without any listener. DisTube handles it\n * gracefully instead, following {@link DisTubeOptions.unhandledError}.\n */\n ERROR = \"error\",\n /**\n * Emitted after a new playlist is added to a {@link Queue}.\n */\n ADD_LIST = \"addList\",\n /**\n * Emitted after a new song is added to a {@link Queue}.\n */\n ADD_SONG = \"addSong\",\n /**\n * Emitted when a song starts playing.\n */\n PLAY_SONG = \"playSong\",\n /**\n * Emitted when a song finished playing.\n */\n FINISH_SONG = \"finishSong\",\n /**\n * Emitted when a {@link Queue} runs out of songs to play.\n */\n EMPTY = \"empty\",\n /**\n * Emitted when a {@link Queue} is finished, and its autoplay mode is\n * disabled.\n */\n FINISH = \"finish\",\n /**\n * Emitted when a {@link Queue} is initialized, to change its default\n * properties.\n */\n INIT_QUEUE = \"initQueue\",\n /**\n * Emitted when the autoplay mode is enabled and no related song could be\n * found.\n */\n NO_RELATED = \"noRelated\",\n /**\n * Emitted when the bot is disconnected from a voice channel.\n */\n DISCONNECT = \"disconnect\",\n /**\n * Emitted when a {@link Queue} is deleted.\n */\n DELETE_QUEUE = \"deleteQueue\",\n /**\n * Emitted for logging FFmpeg debug information.\n */\n FFMPEG_DEBUG = \"ffmpegDebug\",\n /**\n * Emitted to provide debug information from DisTube's operation.\n */\n DEBUG = \"debug\",\n /**\n * Emitted when a guild stream is paused.\n */\n PAUSE_SONG = \"pauseSong\",\n /**\n * Emitted when a paused guild stream is resumed.\n */\n RESUME_SONG = \"resumeSong\",\n /**\n * Emitted when a guild stream is seeked to a new position.\n */\n SEEK_SONG = \"seekSong\",\n /**\n * Emitted when the volume of a guild stream is changed.\n */\n SET_VOLUME = \"setVolume\",\n /**\n * Emitted after the songs of a {@link Queue} have been shuffled.\n */\n SHUFFLE_QUEUE = \"shuffleQueue\",\n /**\n * Emitted when a song is skipped.\n */\n SKIP_SONG = \"skipSong\",\n /**\n * Emitted when the audio filters of a {@link Queue} are changed.\n */\n CHANGE_FILTER = \"changeFilter\",\n /**\n * Emitted when the bot is moved to another voice channel.\n */\n VOICE_CHANNEL_CHANGE = \"voiceChannelChange\",\n /**\n * Emitted when DisTube starts pre-buffering / pre-fetching the next song in a {@link Queue}.\n */\n PRELOAD_SONG = \"preloadSong\",\n /**\n * Emitted when the next song in a {@link Queue} has been pre-buffered and is ready.\n */\n PRELOADED_SONG = \"preloadedSong\",\n /**\n * Emitted when pre-buffering the next song in a {@link Queue} fails.\n */\n PRELOAD_ERROR = \"preloadError\",\n}\n\n/**\n * The arguments of every {@link Events} event.\n *\n * It is the source of truth of the signature of the event listeners:\n * @see {@link TypedDisTubeEvents}\n */\nexport type DisTubeEvents = {\n /**\n * Emitted after a new playlist is added to a {@link Queue}.\n */\n [Events.ADD_LIST]: [queue: Queue, playlist: Playlist];\n /**\n * Emitted after a new song is added to a {@link Queue}.\n */\n [Events.ADD_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when a {@link Queue} is deleted.\n */\n [Events.DELETE_QUEUE]: [queue: Queue];\n /**\n * Emitted when the bot is disconnected from a voice channel.\n */\n [Events.DISCONNECT]: [queue: Queue];\n /**\n * Emitted when a {@link Queue} runs out of songs to play.\n */\n [Events.EMPTY]: [queue: Queue];\n /**\n * Emitted when DisTube encounters an error while playing songs.\n */\n [Events.ERROR]: [error: Error, queue: Queue, song: Song | undefined];\n /**\n * Emitted for logging FFmpeg debug information.\n */\n [Events.FFMPEG_DEBUG]: [debug: string];\n /**\n * Emitted to provide debug information from DisTube's operation.\n */\n [Events.DEBUG]: [debug: string];\n /**\n * Emitted when a {@link Queue} is finished, and its autoplay mode is\n * disabled.\n */\n [Events.FINISH]: [queue: Queue];\n /**\n * Emitted when a song finished playing.\n */\n [Events.FINISH_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when a {@link Queue} is initialized.\n */\n [Events.INIT_QUEUE]: [queue: Queue];\n /**\n * Emitted when the autoplay mode is enabled and no related song could be\n * found.\n */\n [Events.NO_RELATED]: [queue: Queue, error: DisTubeError];\n /**\n * Emitted when a song starts playing.\n */\n [Events.PLAY_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when a guild stream is paused.\n */\n [Events.PAUSE_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when a paused guild stream is resumed.\n */\n [Events.RESUME_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when a guild stream is seeked to a new position.\n */\n [Events.SEEK_SONG]: [queue: Queue, song: Song, position: number];\n /**\n * Emitted when the volume of a guild stream is changed.\n */\n [Events.SET_VOLUME]: [queue: Queue, volume: number, oldVolume: number];\n /**\n * Emitted after the songs of a {@link Queue} have been shuffled.\n */\n [Events.SHUFFLE_QUEUE]: [queue: Queue, songs: Song[]];\n /**\n * Emitted when a song is skipped.\n */\n [Events.SKIP_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when the audio filters of a {@link Queue} are changed.\n */\n [Events.CHANGE_FILTER]: [queue: Queue, newFilters: string[], oldFilters: string[]];\n /**\n * Emitted when the bot is moved to another voice channel.\n */\n [Events.VOICE_CHANNEL_CHANGE]: [queue: Queue, oldChannel: VoiceBasedChannel, newChannel: VoiceBasedChannel];\n /**\n * Emitted when DisTube starts pre-buffering / pre-fetching the next song in a {@link Queue}.\n */\n [Events.PRELOAD_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when the next song in a {@link Queue} has been pre-buffered and is ready.\n */\n [Events.PRELOADED_SONG]: [queue: Queue, song: Song];\n /**\n * Emitted when pre-buffering the next song in a {@link Queue} fails.\n */\n [Events.PRELOAD_ERROR]: [queue: Queue, song: Song, error: Error];\n};\n\n/**\n * The typed event listeners of a {@link DisTube} instance.\n *\n * Every listener of an event receives the arguments of\n * {@link DisTubeEvents}, and can be synchronous or asynchronous.\n */\nexport type TypedDisTubeEvents = {\n [K in keyof DisTubeEvents]: (...args: DisTubeEvents[K]) => Awaitable;\n};\n\n/**\n * The events emitted by a {@link DisTubeVoice} instance.\n */\nexport type DisTubeVoiceEvents = {\n /**\n * Emitted when the voice connection is disconnected.\n * @param error - The error that caused the disconnection, when there is one.\n */\n disconnect: (error?: Error) => Awaitable;\n /**\n * Emitted when an error occurs while playing the audio.\n * @param error - The error\n */\n error: (error: Error) => Awaitable;\n /**\n * Emitted when the audio player becomes idle, i.e. the song is finished.\n */\n finish: () => Awaitable;\n /**\n * Emitted when the connection moves to another voice channel.\n * @param oldChannel - The previous voice channel\n * @param newChannel - The new voice channel\n */\n channelChange: (oldChannel: VoiceBasedChannel, newChannel: VoiceBasedChannel) => Awaitable;\n};\n\n/**\n * An FFmpeg audio filter object\n * ```ts\n * {\n * name: \"bassboost\",\n * value: \"bass=g=10\"\n * }\n * ```ts\n */\nexport interface Filter {\n /**\n * Name of the filter\n */\n name: string;\n /**\n * FFmpeg audio filter argument\n */\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 * @see {@link defaultFilters}\n * @see {@link DisTubeOptions|DisTubeOptions.customFilters}\n */\nexport type FilterResolvable = string | Filter;\n\n/**\n * FFmpeg Filters\n * ```ts\n * {\n * \"Filter Name\": \"Filter Value\",\n * \"bassboost\": \"bass=g=10\"\n * }\n * ```\n * @see {@link defaultFilters}\n */\nexport type Filters = Record<string, string>;\n\n/**\n * The validated {@link DisTubeOptions.preload} options of a {@link DisTube} instance.\n */\nexport type PreloadOptions = {\n /**\n * Whether or not preloading is enabled.\n */\n enabled: boolean;\n /**\n * The number of seconds remaining in the currently playing song before\n * preloading starts.\n */\n threshold: number;\n};\n\n/**\n * The validated {@link DisTubeOptions.crossfade} options of a {@link DisTube}\n * instance.\n */\nexport type CrossfadeOptions = {\n /**\n * The default crossfade duration (in seconds) applied to new queues. `0`\n * disables the crossfade. A {@link Queue} can override it at runtime through\n * its `crossfade` property.\n */\n duration: number;\n /**\n * The FFmpeg `acrossfade` fade curve applied to both sides of the transition.\n * @default \"qsin\" (equal-power)\n */\n curve: string;\n /**\n * How long (in seconds) before the fade window begins the merged transition\n * stream is spawned, so its buffers are warm and the fade starts on time.\n * @default 5\n */\n warmup: number;\n /**\n * Prepare the fading-out song's playback input for the crossfade FFmpeg\n * process. It is invoked right before the transition stream is spawned,\n * with the song's stream url and the position (in seconds, counted from the\n * beginning of the song) where the fade window begins.\n *\n * Streaming inputs that cannot fast-seek (for example HLS playlists) force\n * FFmpeg to re-download the whole stream and discard everything before the\n * seek position, which can miss the swap window on slow sources. The\n * adapter can return a replacement input that starts near the boundary —\n * a local playlist trimmed to the fade position, for example — along with\n * the seek offset inside it and its own FFmpeg input options. Return `null`\n * or `undefined` to use the url as-is.\n */\n preparePrimaryInput?: PrepareCrossfadeInput;\n};\n\n/**\n * The replacement input returned by {@link CrossfadeOptions.preparePrimaryInput}.\n */\nexport type PreparedCrossfadeInput = {\n /**\n * The replacement input url or path, for example a local playlist file\n * trimmed to start at the fade boundary.\n */\n url: string;\n /**\n * The initial seek of the replacement input, in seconds relative to it.\n * When omitted, the input is assumed to start exactly at the fade boundary.\n */\n seek?: number;\n /**\n * FFmpeg input options of the replacement input. They replace the default\n * input options, which are tuned for http(s) streaming urls.\n */\n inputArgs?: FFmpegArg;\n};\n\n/**\n * The {@link CrossfadeOptions.preparePrimaryInput} adapter type.\n */\nexport type PrepareCrossfadeInput = (\n url: string,\n boundary: { seek: number; song: Song },\n) => Awaitable<PreparedCrossfadeInput | null | undefined>;\n\n/**\n * DisTube options\n */\nexport type DisTubeOptions = {\n /**\n * DisTube plugins.\n * The order of this effects the priority of the plugins when verifying the input.\n */\n plugins?: DisTubePlugin[];\n /**\n * Whether or not emitting {@link Events.PLAY_SONG} event when looping a song\n * or next song is the same as the previous one\n * @default false\n */\n emitNewSongOnly?: boolean;\n /**\n * Whether or not saving the previous songs of the queue and enable {@link\n * Queue#previous} method. Disable it may help to reduce the memory usage\n * @default true\n */\n savePreviousSongs?: boolean;\n /**\n * Override {@link defaultFilters} or add more ffmpeg filters\n */\n customFilters?: Filters;\n /**\n * Whether or not playing age-restricted content and disabling safe search in\n * non-NSFW channel\n * @default false\n */\n nsfw?: boolean;\n /**\n * Whether or not emitting `addSong` event when creating a new Queue\n * @default true\n */\n emitAddSongWhenCreatingQueue?: boolean;\n /**\n * Whether or not emitting `addList` event when creating a new Queue\n * @default true\n */\n emitAddListWhenCreatingQueue?: boolean;\n /**\n * Whether or not joining the new voice channel when using {@link DisTube#play}\n * method\n * @default true\n */\n joinNewVoiceChannel?: boolean;\n /**\n * Behavior when the {@link Events.ERROR} event is emitted but nobody listens to it.\n *\n * By default (`\"log\"`), the error is logged to the console instead of crashing the\n * process, which is the Node.js default behavior for the special `\"error\"` event.\n * @default \"log\"\n */\n unhandledError?: UnhandledErrorBehavior;\n /**\n * Time (in milliseconds) a track may stay in the \"buffering\" state before it is\n * considered stuck and gets skipped automatically.\n *\n * Set to `0` to disable the stuck-track detection.\n * @default 10000\n */\n stuckThreshold?: number;\n /**\n * Pre-fetch stream information and prepare the stream for the next song in\n * the queue before the current song finishes playing, to reduce the delay\n * between two songs.\n *\n * Can be a simple `boolean` to toggle it with the default threshold, or an\n * object to configure it:\n * - `enabled`: whether or not preloading is enabled (@default false)\n * - `threshold`: the number of seconds remaining in the currently playing\n * song before preloading starts (@default 15)\n * @default false\n */\n preload?:\n | boolean\n | {\n /**\n * Whether or not preloading is enabled.\n */\n enabled?: boolean;\n /**\n * The number of seconds remaining in the currently playing song before\n * preloading starts.\n */\n threshold?: number;\n };\n /**\n * Crossfade the end of the current song with the beginning of the next one,\n * instead of a hard switch between two streams.\n *\n * The transition is a single FFmpeg process that mixes both songs with an\n * `acrossfade` filter, so the fade is seamless (no gaps, no extra decode\n * round-trips). Because the fade length must be prepared in advance, the\n * next song's stream is resolved even when preloading is disabled.\n *\n * Can be an object to configure it:\n * - `duration`: the default crossfade duration in seconds for new queues\n * (@default 0). Each {@link Queue} can override it at runtime with its\n * `crossfade` property, which is what bots typically bind to a guild\n * setting.\n * - `curve`: the FFmpeg `acrossfade` fade curve (@default \"qsin\")\n * - `warmup`: seconds before the fade window when the transition stream is\n * spawned to warm up its buffers (@default 5)\n * - `preparePrimaryInput`: an optional adapter preparing the fading-out\n * song's FFmpeg input before the transition stream is spawned. Useful for\n * streaming inputs that cannot fast-seek ({@link CrossfadeOptions.preparePrimaryInput}).\n * @default { duration: 0, curve: \"qsin\", warmup: 5 }\n */\n crossfade?: {\n /**\n * The default crossfade duration (in seconds) for new queues (0 disables).\n */\n duration?: number;\n /**\n * The FFmpeg `acrossfade` fade curve applied to both songs.\n */\n curve?: string;\n /**\n * Seconds before the fade window when the transition stream is spawned.\n */\n warmup?: number;\n /**\n * Optional adapter preparing the fading-out song's FFmpeg input\n * ({@link CrossfadeOptions.preparePrimaryInput}).\n */\n preparePrimaryInput?: PrepareCrossfadeInput;\n };\n /**\n * FFmpeg options\n */\n ffmpeg?: {\n /**\n * FFmpeg path\n */\n path?: string;\n /**\n * FFmpeg default arguments\n */\n args?: Partial<FFmpegArgs>;\n };\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\n * | BaseGuildVoiceChannel}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/BaseGuildTextChannel\n * | BaseGuildTextChannel}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/VoiceState |\n * VoiceState}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/GuildMember |\n * GuildMember}\n * - A {@link https://discord.js.org/#/docs/main/stable/class/Interaction |\n * Interaction}\n * - A {@link DisTubeVoice}\n * - A {@link Queue}\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\n/**\n * The raw information of a song.\n *\n * It is the input of the {@link Song} constructor: a plugin builds it from\n * the data of its source.\n */\nexport interface SongInfo<T = unknown> {\n /**\n * The plugin that created this song, or `null` when it was created manually.\n */\n plugin: DisTubePlugin | null;\n /**\n * The identifier of the source of the song, e.g. `my-source`.\n */\n source: string;\n /**\n * Whether the song can be streamed directly from its source.\n *\n * When it is `false`, DisTube looks for a playable version of the song with\n * the other plugins.\n */\n playFromSource: boolean;\n /**\n * The identifier of the song in its source.\n */\n id: string;\n /**\n * The name of the song.\n */\n name?: string;\n /**\n * Whether the song is a live stream.\n */\n isLive?: boolean;\n /**\n * The duration of the song, in seconds.\n */\n duration?: number;\n /**\n * The URL of the song.\n */\n url?: string;\n /**\n * The URL of the thumbnail of the song.\n */\n thumbnail?: string;\n /**\n * The number of views of the song.\n */\n views?: number;\n /**\n * The number of likes of the song.\n */\n likes?: number;\n /**\n * The number of dislikes of the song.\n */\n dislikes?: number;\n /**\n * The number of reposts (shares) of the song.\n */\n reposts?: number;\n /**\n * The uploader (the author, the channel, ...) of the song.\n */\n uploader?: {\n /**\n * The name of the uploader.\n */\n name?: string;\n /**\n * The URL of the uploader.\n */\n url?: string;\n };\n /**\n * Whether the song is age-restricted.\n */\n ageRestricted?: boolean;\n /**\n * Source specific metadata of the song.\n *\n * It is used by the plugin that created the song to keep the data it needs to\n * play it (stream url, identifiers, ...). It is ignored when the song is\n * created with a `metadata` option.\n */\n metadata?: T;\n}\n\n/**\n * The raw information of a playlist.\n *\n * It is the input of the {@link Playlist} constructor: a plugin builds it from\n * the data of its source.\n */\nexport interface PlaylistInfo {\n /**\n * The identifier of the source of the playlist, e.g. `my-source`.\n */\n source: string;\n /**\n * The songs of the playlist.\n */\n songs: Song[];\n /**\n * The identifier of the playlist in its source.\n */\n id?: string;\n /**\n * The name of the playlist.\n */\n name?: string;\n /**\n * The URL of the playlist.\n */\n url?: string;\n /**\n * The URL of the thumbnail of the playlist.\n */\n thumbnail?: string;\n}\n\n/**\n * A song that is related to another song.\n *\n * It is the same as a {@link Song}, without the `related` property of the\n * previous versions of DisTube.\n */\nexport type RelatedSong = Omit<Song, \"related\">;\n\n/**\n * The options of the handler of a song or a playlist.\n */\nexport type PlayHandlerOptions = {\n /**\n * [Default: false] Skip the playing song (if exists) and play the added playlist\n * instantly\n */\n skip?: boolean;\n /**\n * [Default: 0] Position of the song/playlist to add to the queue, \\<= 0 to add to\n * the end of the queue\n */\n position?: number;\n /**\n * The default text channel of the queue\n */\n textChannel?: GuildTextBasedChannel;\n};\n\n/**\n * The options of a jump in the queue.\n */\nexport interface JumpOptions {\n /**\n * [Default: false] Whether or not skipped song(s) will be added to the end of the\n * queue\n */\n requeue?: boolean;\n}\n\n/**\n * The options of {@link DisTube#play}.\n */\nexport interface PlayOptions<T = unknown> extends PlayHandlerOptions, ResolveOptions<T> {\n /**\n * The message that triggered the command.\n *\n * It is used as the default {@link PlayHandlerOptions.textChannel} of the queue\n * when no `textChannel` is provided.\n */\n message?: Message;\n}\n\n/**\n * The kind of result a search is looking for.\n */\nexport enum SearchResultType {\n /**\n * A single track, i.e. a song.\n */\n TRACK = \"track\",\n /**\n * A video, i.e. a song with a video.\n */\n VIDEO = \"video\",\n /**\n * A playlist of songs.\n */\n PLAYLIST = \"playlist\",\n /**\n * An album of songs.\n */\n ALBUM = \"album\",\n /**\n * The songs of an artist.\n */\n ARTIST = \"artist\",\n}\n\n/**\n * The options of the resolution of a song or a playlist.\n */\nexport interface ResolveOptions<T = unknown> {\n /**\n * Requested user\n */\n member?: GuildMember;\n /**\n * Metadata\n */\n metadata?: T;\n /**\n * The source to resolve the input in.\n *\n * It matches the {@link Plugin.source} of a plugin, or one of its\n * {@link Plugin.aliases}. When it is not given, every plugin is used.\n */\n source?: string;\n}\n\n/**\n * Options of a search.\n */\nexport interface SearchOptions<T = unknown> extends ResolveOptions<T> {\n /**\n * [Default: 10] Maximum number of results.\n */\n limit?: number;\n /**\n * The kind of result the caller is looking for.\n */\n type?: SearchResultType;\n /**\n * Whether or not filtering the explicit content.\n */\n safeSearch?: boolean;\n}\n\n/**\n * The options of the resolution of a playlist.\n */\nexport interface ResolvePlaylistOptions<T = unknown> extends ResolveOptions<T> {\n /**\n * Source of the playlist\n */\n source?: string;\n}\n\n/**\n * The options of a custom playlist.\n */\nexport interface CustomPlaylistOptions {\n /**\n * A guild member creating the playlist\n */\n member?: GuildMember;\n /**\n * Whether or not fetch the songs in parallel\n */\n parallel?: boolean;\n /**\n * Metadata\n */\n metadata?: any;\n /**\n * Playlist name\n */\n name?: string;\n /**\n * Playlist source\n */\n source?: string;\n /**\n * Playlist url\n */\n url?: string;\n /**\n * Playlist thumbnail\n */\n thumbnail?: string;\n}\n\n/**\n * The repeat mode of a {@link Queue}\n */\nexport enum RepeatMode {\n /**\n * The queue plays every song once. `0`.\n */\n DISABLED,\n /**\n * The queue repeats the current song. `1`.\n */\n SONG,\n /**\n * The queue repeats the whole queue. `2`.\n */\n QUEUE,\n}\n\n/**\n * All available plugin types:\n */\nexport enum PluginType {\n /**\n * A plugin that extracts, searches and plays the songs of its source.\n * `\"extractor\"`: {@link ExtractorPlugin}\n */\n EXTRACTOR = \"extractor\",\n /**\n * A plugin that only extracts the info of the links of its source.\n * `\"info-extractor\"`: {@link InfoExtractorPlugin}\n */\n INFO_EXTRACTOR = \"info-extractor\",\n /**\n * A plugin that extracts and plays the songs of its source, but cannot\n * search for them. `\"playable-extractor\"`: {@link PlayableExtractorPlugin}\n */\n PLAYABLE_EXTRACTOR = \"playable-extractor\",\n}\n\n/**\n * Every kind of plugin DisTube can use.\n *\n * - {@link ExtractorPlugin}\n * - {@link InfoExtractorPlugin}\n * - {@link PlayableExtractorPlugin}\n */\nexport type DisTubePlugin = ExtractorPlugin | InfoExtractorPlugin | PlayableExtractorPlugin;\n\n/**\n * A FFmpeg argument.\n *\n * The value is the argument itself (`\"-1\"`), or an array of the values of a\n * repeatable argument (`[\"-1\", \"-2\"]`).\n */\nexport type FFmpegArg = Record<string, string | number | boolean | Array<string | null | undefined> | null | undefined>;\n\n/**\n * FFmpeg arguments for different use cases\n */\nexport type FFmpegArgs = {\n /**\n * The arguments that are applied to the FFmpeg process itself.\n */\n global: FFmpegArg;\n /**\n * The arguments that are applied to the input of the FFmpeg process.\n */\n input: FFmpegArg;\n /**\n * The arguments that are applied to the output of the FFmpeg process.\n *\n * The `af` argument is replaced by the filters of the {@link Queue}.\n */\n output: FFmpegArg;\n};\n\n/**\n * FFmpeg options\n */\nexport type FFmpegOptions = {\n /**\n * Path to the ffmpeg executable\n * @default \"ffmpeg\"\n */\n path: string;\n /**\n * Arguments\n */\n args: FFmpegArgs;\n};\n","class Task {\n resolve!: () => void;\n promise: Promise<void>;\n isPlay: boolean;\n constructor(isPlay: boolean) {\n this.isPlay = isPlay;\n this.promise = new Promise<void>(res => {\n this.resolve = res;\n });\n }\n}\n\n/**\n * Task queuing system\n *\n * It makes sure that the tasks of a {@link Queue} are processed one after the\n * other, instead of all at the same time.\n */\nexport class TaskQueue {\n /**\n * The task array\n */\n #tasks: Task[] = [];\n\n /**\n * Waits for last task finished and queues a new task\n * @param isPlay - Whether the task is a play task\n * @returns A promise that resolves when the last queued task is finished\n */\n queuing(isPlay = false): Promise<void> {\n const next = this.remaining ? this.#tasks[this.#tasks.length - 1].promise : Promise.resolve();\n this.#tasks.push(new Task(isPlay));\n return next;\n }\n\n /**\n * Removes the finished task and processes the next task\n * @returns Nothing\n */\n resolve(): void {\n this.#tasks.shift()?.resolve();\n }\n\n /**\n * The remaining number of tasks\n */\n get remaining(): number {\n return this.#tasks.length;\n }\n\n /**\n * Whether or not having a play task\n */\n get hasPlayTask(): boolean {\n return this.#tasks.some(t => t.isPlay);\n }\n}\n","import type { GuildTextBasedChannel, Snowflake } from \"discord.js\";\nimport { DEFAULT_VOLUME, MAX_CROSSFADE_DURATION_SECS } from \"../constant\";\nimport { DisTubeBase } from \"../core/DisTubeBase\";\nimport type { DisTubeStream } from \"../core/DisTubeStream\";\nimport type { DisTubeVoice } from \"../core/DisTubeVoice\";\nimport { FilterManager } from \"../core/manager/FilterManager\";\nimport type { DisTube } from \"../DisTube\";\nimport type { DisTubeVoiceEvents, FFmpegArgs, JumpOptions } from \"../type\";\nimport { Events, RepeatMode } from \"../type\";\nimport { formatDuration, objectKeys } from \"../util\";\nimport { DisTubeError } from \"./DisTubeError\";\nimport type { Song } from \"./Song\";\nimport { TaskQueue } from \"./TaskQueue\";\n\n/**\n * Represents a queue.\n */\nexport class Queue extends DisTubeBase {\n /**\n * Queue id (Guild id)\n */\n readonly id: Snowflake;\n /**\n * Voice connection of this queue.\n */\n voice: DisTubeVoice;\n /**\n * List of songs in the queue (The first one is the playing song)\n */\n songs: Song[];\n /**\n * List of the previous songs.\n */\n previousSongs: Song[];\n /**\n * Whether stream is currently stopped.\n */\n stopped: boolean;\n /**\n * Whether or not the stream is currently paused.\n *\n * It is also `true` once the queue has been stopped, so that `!queue.paused`\n * stays `false` as soon as the queue is not playing anymore.\n */\n paused: boolean;\n /**\n * Type of repeat mode (`0` is disabled, `1` is repeating a song, `2` is repeating\n * all the queue). Default value: `0` (disabled)\n */\n repeatMode: RepeatMode;\n /**\n * Whether or not the autoplay mode is enabled. Default value: `false`\n */\n autoplay: boolean;\n /**\n * FFmpeg arguments for the current queue. Default value is defined with {@link DisTubeOptions}.ffmpeg.args.\n * `af` output argument will be replaced with {@link Queue#filters} manager\n */\n ffmpegArgs: FFmpegArgs;\n /**\n * The text channel of the Queue. (Default: where the first command is called).\n */\n textChannel?: GuildTextBasedChannel;\n /**\n * What time in the song to begin (in seconds).\n * @internal\n */\n _beginTime: number;\n #filters: FilterManager;\n #initialized = false;\n /**\n * Whether or not the queue is being updated manually (skip, jump, previous)\n * @internal\n */\n _manualUpdate: boolean;\n /**\n * Task queuing system\n * @internal\n */\n _taskQueue: TaskQueue;\n /**\n * {@link DisTubeVoice} listener\n * @internal\n */\n _listeners?: DisTubeVoiceEvents;\n /**\n * Preload timer\n * @internal\n */\n _preloadTimeout?: NodeJS.Timeout;\n /**\n * Preloaded song\n * @internal\n */\n _preloadedSong?: Song;\n /**\n * Preloaded stream\n * @internal\n */\n _preloadedStream?: DisTubeStream;\n /**\n * In-flight preload task\n * @internal\n */\n _preloading?: Promise<void>;\n /**\n * Bumped whenever the preloaded state is invalidated, so an in-flight\n * preload task can detect that its result is no longer needed.\n * @internal\n */\n _preloadGeneration = 0;\n #crossfade: number;\n /**\n * Crossfade boundary timer\n * @internal\n */\n _crossfadeTimeout?: NodeJS.Timeout;\n /**\n * The merged transition stream that is warming up before the fade window\n * starts\n * @internal\n */\n _crossfadeWarmup?: DisTubeStream;\n /**\n * Clear any preloaded song and cancel pending preload timer.\n * @internal\n */\n _clearPreload() {\n this._crossfadeCancel();\n this._preloadGeneration++;\n if (this._preloadTimeout) {\n clearTimeout(this._preloadTimeout);\n this._preloadTimeout = undefined;\n }\n if (this._preloadedStream) {\n this._preloadedStream.kill();\n this._preloadedStream = undefined;\n }\n this._preloadedSong = undefined;\n }\n /**\n * Cancel a pending crossfade and kill its warming-up transition stream.\n * @internal\n */\n _crossfadeCancel() {\n if (this._crossfadeTimeout) {\n clearTimeout(this._crossfadeTimeout);\n this._crossfadeTimeout = undefined;\n }\n if (this._crossfadeWarmup) {\n this._crossfadeWarmup.kill();\n this._crossfadeWarmup = undefined;\n }\n }\n /**\n * Create a queue for the guild\n * @param distube - DisTube\n * @param voice - Voice connection\n * @param textChannel - Default text channel\n */\n constructor(distube: DisTube, voice: DisTubeVoice, textChannel?: GuildTextBasedChannel) {\n super(distube);\n this.voice = voice;\n this.id = voice.id;\n this.volume = DEFAULT_VOLUME;\n this.songs = [];\n this.previousSongs = [];\n this.stopped = false;\n this._manualUpdate = false;\n this.paused = false;\n this.repeatMode = RepeatMode.DISABLED;\n this.autoplay = false;\n this.#filters = new FilterManager(this);\n this._beginTime = 0;\n this.textChannel = textChannel;\n this._taskQueue = new TaskQueue();\n this._listeners = undefined;\n this.ffmpegArgs = {\n global: { ...this.options.ffmpeg.args.global },\n input: { ...this.options.ffmpeg.args.input },\n output: { ...this.options.ffmpeg.args.output },\n };\n // Defensive: mocked/embedded options may not carry the crossfade block.\n this.#crossfade = Number(this.options.crossfade?.duration) || 0;\n this.#initialized = true;\n }\n #addToPreviousSongs(songs: Song | Song[]) {\n if (Array.isArray(songs)) {\n if (this.options.savePreviousSongs) {\n this.previousSongs.push(...songs);\n } else {\n this.previousSongs.push(...songs.map(s => ({ id: s.id }) as Song));\n }\n } else if (this.options.savePreviousSongs) {\n this.previousSongs.push(songs);\n } else {\n this.previousSongs.push({ id: songs.id } as Song);\n }\n }\n #stop() {\n this._manualUpdate = true;\n this.voice.stop();\n }\n /**\n * The client user as a `GuildMember` of this queue's guild\n */\n get clientMember() {\n return this.voice.channel.guild.members.me ?? undefined;\n }\n /**\n * The filter manager of the queue\n */\n get filters() {\n return this.#filters;\n }\n /**\n * Whether or not the queue is still active.\n *\n * It is `false` only when the queue has been stopped. A paused queue is still\n * active.\n */\n get isActive(): boolean {\n return !this.stopped;\n }\n /**\n * Formatted duration string.\n */\n get formattedDuration() {\n return formatDuration(this.duration);\n }\n /**\n * Queue's duration.\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 */\n get currentTime() {\n return this.voice.playbackTime;\n }\n /**\n * The crossfade duration (in seconds) between this song and the next one.\n *\n * `0` (the default) disables the crossfade. Changing it takes effect for the\n * next transition; call {@link Queue#scheduleCrossfade} to re-arm the\n * transition for the currently playing song immediately.\n * @throws {@link DisTubeError} When the value is not a number between `0`\n * and the maximum crossfade duration\n */\n get crossfade(): number {\n return this.#crossfade;\n }\n set crossfade(value: number) {\n if (typeof value !== \"number\" || Number.isNaN(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", value, \"Queue.crossfade\");\n }\n if (value < 0) throw new DisTubeError(\"NUMBER_COMPARE\", \"Crossfade\", \"bigger or equal to\", 0);\n if (value > MAX_CROSSFADE_DURATION_SECS) {\n throw new DisTubeError(\"NUMBER_COMPARE\", \"Crossfade\", \"smaller or equal to\", MAX_CROSSFADE_DURATION_SECS);\n }\n this.#crossfade = value;\n }\n /**\n * Formatted {@link Queue#currentTime} string.\n */\n get formattedCurrentTime() {\n return formatDuration(this.currentTime);\n }\n /**\n * The voice channel playing in.\n */\n get voiceChannel() {\n return this.clientMember?.voice?.channel ?? null;\n }\n /**\n * Get or set the stream volume. Default value: `50`.\n */\n get volume() {\n return this.voice.volume;\n }\n /**\n * Set the stream volume.\n * @param value - The volume percentage, from `0` to `100`\n * @throws {@link DisTubeError} When the volume is not a number, or when it is\n * negative\n */\n set volume(value: number) {\n const oldVolume = this.voice.volume;\n this.voice.volume = value;\n if (this.#initialized && oldVolume !== value) {\n this.emit(Events.SET_VOLUME, this, value, oldVolume);\n }\n }\n /**\n * Add a song or a list of songs to the queue.\n * @throws {DisTubeError}\n * @param song - Song to add\n * @param position - Position to add, \\<= 0 to add to the end of the queue\n * @returns The guild queue\n * @example\n * ```ts\n * queue.addToQueue(song);\n * ```\n */\n addToQueue(song: Song | Song[], position = 0): Queue {\n if (this.stopped) throw new DisTubeError(\"QUEUE_STOPPED\");\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 this.queues?.schedulePreload?.(this);\n return this;\n }\n /**\n /**\n * Pause the guild stream\n * @returns The guild queue\n * @throws {@link DisTubeError} When the queue is already paused\n * @example\n * ```ts\n * await queue.pause();\n * ```\n */\n async pause(): Promise<Queue> {\n await this._taskQueue.queuing();\n try {\n if (this.paused) throw new DisTubeError(\"PAUSED\");\n this.paused = true;\n // A paused queue cannot know when the preloaded stream is still valid:\n // drop it and let resume() re-schedule a fresh preload.\n this._clearPreload();\n this.voice.pause();\n this.emit(Events.PAUSE_SONG, this, this.songs[0]);\n return this;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Resume the guild stream\n * @returns The guild queue\n * @throws {@link DisTubeError} When the queue is not paused\n * @example\n * ```ts\n * await queue.resume();\n * ```\n */\n async resume(): Promise<Queue> {\n await this._taskQueue.queuing();\n try {\n if (!this.paused) throw new DisTubeError(\"RESUMED\");\n this.paused = false;\n this.voice.unpause();\n this.emit(Events.RESUME_SONG, this, this.songs[0]);\n this.queues?.schedulePreload?.(this);\n this.queues?.scheduleCrossfade?.(this);\n return this;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Set the guild stream's volume\n * @param percent - The percentage of volume you want to set\n * @returns The guild queue\n * @throws {@link DisTubeError} When the volume is not a number, or when it is\n * negative\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. <info>If {@link\n * Queue#autoplay} is `true` and there is no up next song, DisTube will add and\n * play a related song.</info>\n * @param options - Skip options\n * @returns The song will skip to\n * @throws {@link DisTubeError} When there is no up next song, or when the\n * position is out of the bounds of the queue\n * @example\n * ```ts\n * await queue.skip();\n * ```\n */\n async skip(options?: JumpOptions): Promise<Song> {\n return this.jump(1, options);\n }\n\n /**\n * Play the previous song if exists\n * @returns The guild queue\n * @throws {@link DisTubeError} When {@link DisTubeOptions.savePreviousSongs} is\n * disabled, or when the queue does not have any previous song\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 const hasPrevious = this.previousSongs.length > 0;\n if (!hasPrevious && this.repeatMode !== RepeatMode.QUEUE) {\n throw new DisTubeError(\"NO_PREVIOUS\");\n }\n // In repeat-queue mode without any history, the last song of the queue is\n // replayed. It has to be removed from its position, otherwise it would be\n // queued twice.\n const song = hasPrevious ? this.previousSongs.pop() : this.songs.pop();\n if (!song) throw new DisTubeError(\"NO_PREVIOUS\");\n this.songs.unshift(song);\n this.#stop();\n return song;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Shuffle the queue's songs\n * @returns 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 this._clearPreload();\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 this.emit(Events.SHUFFLE_QUEUE, this, this.songs);\n this.queues?.schedulePreload?.(this);\n return this;\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Jump to the song position in the queue. The next one is 1, 2,... The previous\n * one is -1, -2,...\n * if `num` is invalid number\n * @param position - The song position to play\n * @param options - Skip options\n * @returns The new Song will be played\n * @throws {@link DisTubeError} When the position is invalid, when there is no\n * up next song, or when {@link DisTubeOptions.savePreviousSongs} is disabled\n * and the jump is backwards\n */\n async jump(position: number, options?: JumpOptions): 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 if (position > 0) {\n if (position >= this.songs.length) {\n if (this.autoplay) {\n await this._addRelatedSong();\n } else {\n throw new DisTubeError(\"NO_UP_NEXT\");\n }\n }\n const skipped = this.songs.splice(0, position);\n if (options?.requeue) {\n this.songs.push(...skipped);\n } else {\n this.#addToPreviousSongs(skipped);\n }\n this.emit(Events.SKIP_SONG, this, skipped[0]);\n } else if (!this.options.savePreviousSongs) {\n throw new DisTubeError(\"DISABLED_OPTION\", \"savePreviousSongs\");\n } else {\n const skipped = this.previousSongs.splice(position);\n this.songs.unshift(...skipped);\n }\n this._clearPreload();\n this.#stop();\n return this.songs[0];\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 mode - The repeat modes (toggle if `undefined`)\n * @returns The new repeat mode\n * @throws {@link DisTubeError} When the mode is not a valid {@link RepeatMode}\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 time - Time in seconds\n * @returns The guild queue\n * @throws {@link DisTubeError} When the time is not a number, or when it is\n * negative\n * @example\n * ```ts\n * await queue.seek(60);\n * ```\n */\n async seek(time: number): Promise<Queue> {\n await this._taskQueue.queuing();\n try {\n if (typeof time !== \"number\") throw new DisTubeError(\"INVALID_TYPE\", \"number\", time, \"time\");\n if (Number.isNaN(time) || time < 0) throw new DisTubeError(\"NUMBER_COMPARE\", \"time\", \"bigger or equal to\", 0);\n this._clearPreload();\n this._beginTime = time;\n await this.play(false);\n this.emit(Events.SEEK_SONG, this, this.songs[0], time);\n return this;\n } finally {\n this._taskQueue.resolve();\n }\n }\n async #getRelatedSong(current: Song): Promise<Song[]> {\n const plugin = await this.handler._getPluginFromSong(current);\n if (plugin) return plugin.getRelatedSongs(current);\n return [];\n }\n /**\n * Internal implementation of addRelatedSong without task queue protection.\n * Used by methods that already hold the task queue lock.\n * @param song - The song to get related songs from. Defaults to the current playing song.\n * @returns A promise that resolves to the added song\n * @throws {@link DisTubeError} When the queue does not have any playing song,\n * or when no related song could be found\n * @internal\n */\n async _addRelatedSong(song?: Song): Promise<Song> {\n const current = song ?? this.songs?.[0];\n if (!current) throw new DisTubeError(\"NO_PLAYING_SONG\");\n const prevIds = this.previousSongs.map(p => p.id);\n const relatedSongs = (await this.#getRelatedSong(current)).filter(s => !prevIds.includes(s.id));\n this.debug(`[${this.id}] Getting related songs from: ${current}`);\n if (!relatedSongs.length && !current.stream.playFromSource) {\n const altSong = current.stream.song;\n if (altSong) relatedSongs.push(...(await this.#getRelatedSong(altSong)).filter(s => !prevIds.includes(s.id)));\n this.debug(`[${this.id}] Getting related songs from streamed song: ${altSong}`);\n }\n const nextSong = relatedSongs[0];\n if (!nextSong) throw new DisTubeError(\"NO_RELATED\");\n nextSong.metadata = current.metadata;\n nextSong.member = this.clientMember;\n this.addToQueue(nextSong);\n return nextSong;\n }\n /**\n * Add a related song of the playing song to the queue\n * @param song - The song to get related songs from. Defaults to the current playing song.\n * @returns The added song\n * @throws {@link DisTubeError} When the queue does not have any playing song,\n * or when no related song could be found\n */\n async addRelatedSong(song?: Song): Promise<Song> {\n await this._taskQueue.queuing();\n try {\n return await this._addRelatedSong(song);\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Stop the guild stream and delete the queue\n * @returns A promise that resolves when the queue is stopped\n */\n async stop() {\n await this._taskQueue.queuing();\n try {\n this.voice.stop();\n this.remove();\n } finally {\n this._taskQueue.resolve();\n }\n }\n /**\n * Remove the queue from the manager\n * @returns Nothing\n */\n remove() {\n this._clearPreload();\n this.paused = true;\n this.stopped = true;\n this.songs = [];\n this.previousSongs = [];\n if (this._listeners) for (const event of objectKeys(this._listeners)) this.voice.off(event, this._listeners[event]);\n this.queues.remove(this.id);\n this.emit(Events.DELETE_QUEUE, this);\n }\n /**\n * Toggle autoplay mode\n * @returns Autoplay mode state\n */\n toggleAutoplay(): boolean {\n this.autoplay = !this.autoplay;\n return this.autoplay;\n }\n /**\n * Play the first song in the queue\n * @param emitPlaySong - Whether or not emit {@link Events.PLAY_SONG} event\n * @returns A promise that resolves when the song is playing\n * @throws {@link DisTubeError} When the queue has been stopped\n */\n play(emitPlaySong = true) {\n if (this.stopped) throw new DisTubeError(\"QUEUE_STOPPED\");\n return this.queues.playSong(this, emitPlaySong);\n }\n /**\n * Re-arm the crossfade into the next song for the currently playing one.\n *\n * Useful after changing {@link Queue#crossfade} while a song is playing: the\n * fade may still fit into the remaining time. This is called automatically\n * after every song switch.\n * @returns Nothing\n */\n scheduleCrossfade() {\n this.queues.scheduleCrossfade(this);\n }\n /**\n * Restart the current stream with the current FFmpeg arguments, keeping the\n * playback position.\n *\n * The FFmpeg audio filters are applied when the stream is created, so the stream\n * has to be recreated whenever the filters change.\n *\n * Unlike a regular playback error, a failure while restarting the stream does\n * **not** remove the current song from the queue.\n * @returns A promise that resolves when the stream is restarted\n * @internal\n */\n async _restartStream(): Promise<void> {\n await this._taskQueue.queuing(true);\n try {\n if (this.stopped || !this.songs.length) return;\n this._beginTime = this.currentTime;\n await this.queues.playSong(this, false, { keepSongOnError: true });\n } finally {\n this._taskQueue.resolve();\n }\n }\n}\n","import type { GuildMember } from \"discord.js\";\nimport type { PlaylistInfo, ResolveOptions } from \"../type\";\nimport { formatDuration, isMemberInstance } from \"../util\";\nimport { DisTubeError } from \"./DisTubeError\";\nimport type { Song } from \"./Song\";\n\n/**\n * Class representing a playlist.\n */\nexport class Playlist<T = unknown> implements PlaylistInfo {\n /**\n * Playlist source.\n */\n source: string;\n /**\n * Songs in the playlist.\n */\n songs: Song[];\n /**\n * Playlist ID.\n */\n id?: string;\n /**\n * Playlist name.\n */\n name?: string;\n /**\n * Playlist URL.\n */\n url?: string;\n /**\n * Playlist thumbnail.\n */\n thumbnail?: string;\n #metadata!: T;\n #member?: GuildMember;\n /**\n * Create a Playlist\n * @param playlist - Raw playlist info\n * @param options - Optional data\n * @param options.member - The user that requested the playlist\n * @param options.metadata - The metadata of the playlist\n * @throws {@link DisTubeError} When the playlist does not have any song\n */\n constructor(playlist: PlaylistInfo, { member, metadata }: ResolveOptions<T> = {}) {\n if (!Array.isArray(playlist.songs) || !playlist.songs.length) throw new DisTubeError(\"EMPTY_PLAYLIST\");\n\n this.source = playlist.source.toLowerCase();\n this.songs = playlist.songs;\n this.name = playlist.name;\n this.id = playlist.id;\n this.url = playlist.url;\n this.thumbnail = playlist.thumbnail;\n this.member = member;\n this.songs.forEach(s => (s.playlist = this));\n this.metadata = metadata as T;\n }\n\n /**\n * Playlist duration in second.\n */\n get duration() {\n return this.songs.reduce((prev, next) => prev + next.duration, 0);\n }\n\n /**\n * Formatted duration string `hh:mm:ss`.\n */\n get formattedDuration() {\n return formatDuration(this.duration);\n }\n\n /**\n * User requested.\n */\n get member() {\n return this.#member;\n }\n\n /**\n * Set the user that requested the playlist.\n *\n * The value is ignored when it is not a valid guild member.\n * @param member - The member\n */\n set member(member: GuildMember | undefined) {\n if (!isMemberInstance(member)) return;\n this.#member = member;\n this.songs.forEach(s => (s.member = this.member));\n }\n\n /**\n * User requested.\n */\n get user() {\n return this.member?.user;\n }\n\n /**\n * Optional metadata that can be used to identify the playlist.\n */\n get metadata() {\n return this.#metadata;\n }\n\n /**\n * Set the metadata of the playlist.\n *\n * The metadata of the songs is not changed when the metadata is `undefined`.\n * @param metadata - The metadata\n */\n set metadata(metadata: T) {\n this.#metadata = metadata;\n // Do not wipe the metadata of the songs when there is no metadata:\n // the songs may carry their own source specific metadata (stream url,\n // identifiers, ...) that the plugin needs to play them.\n if (metadata === undefined) return;\n this.songs.forEach(s => (s.metadata = metadata));\n }\n\n /**\n * The name of the playlist and the number of its songs.\n * @returns The string representation of the playlist\n */\n toString() {\n return `${this.name} (${this.songs.length} songs)`;\n }\n}\n","import type { GuildMember } from \"discord.js\";\nimport type { DisTubePlugin, ResolveOptions, SongInfo } from \"../type\";\nimport { formatDuration, isMemberInstance } from \"../util\";\nimport { DisTubeError } from \"./DisTubeError\";\nimport { Playlist } from \"./Playlist\";\n\n/**\n * Class representing a song.\n */\nexport class Song<T = unknown> {\n /**\n * The source of this song info\n */\n source: string;\n /**\n * Song ID.\n */\n id: string;\n /**\n * Song name.\n */\n name?: string;\n /**\n * Indicates if the song is an active live.\n */\n isLive?: boolean;\n /**\n * Song duration.\n */\n duration: number;\n /**\n * Formatted duration string (`hh:mm:ss`, `mm:ss` or `Live`).\n */\n formattedDuration: string;\n /**\n * Song URL.\n */\n url?: string;\n /**\n * Song thumbnail.\n */\n thumbnail?: string;\n /**\n * Song view count\n */\n views?: number;\n /**\n * Song like count\n */\n likes?: number;\n /**\n * Song dislike count\n */\n dislikes?: number;\n /**\n * Song repost (share) count\n */\n reposts?: number;\n /**\n * Song uploader\n */\n uploader: {\n /**\n * The name of the uploader.\n */\n name?: string;\n /**\n * The URL of the uploader.\n */\n url?: string;\n };\n /**\n * Whether or not an age-restricted content\n */\n ageRestricted?: boolean;\n /**\n * Stream info\n */\n stream:\n | {\n /**\n * The stream of this song will be played from source\n */\n playFromSource: true;\n /**\n * Stream URL of this song\n */\n url?: string;\n }\n | {\n /**\n * The stream of this song will be played from another song\n */\n playFromSource: false;\n /**\n * The song that this song will be played from\n */\n song?: Song<T>;\n };\n /**\n * The plugin that created this song\n */\n plugin: DisTubePlugin | null;\n #metadata!: T;\n #member?: GuildMember;\n #playlist?: Playlist;\n /**\n * Create a Song\n *\n * @param info - Raw song info\n * @param options - Optional data\n * @param options.member - The user that requested the song\n * @param options.metadata - The metadata of the song\n */\n constructor(info: SongInfo<T>, { member, metadata }: ResolveOptions<T> = {}) {\n this.source = info.source.toLowerCase();\n this.metadata = (metadata ?? info.metadata) as T;\n this.member = member;\n this.id = info.id;\n this.name = info.name;\n this.isLive = info.isLive;\n this.duration = this.isLive || !info.duration ? 0 : info.duration;\n this.formattedDuration = this.isLive ? \"Live\" : formatDuration(this.duration);\n this.url = info.url;\n this.thumbnail = info.thumbnail;\n this.views = info.views;\n this.likes = info.likes;\n this.dislikes = info.dislikes;\n this.reposts = info.reposts;\n this.uploader = {\n name: info.uploader?.name,\n url: info.uploader?.url,\n };\n this.ageRestricted = info.ageRestricted;\n // A plugin that cannot play its own songs never has a stream: its songs are\n // resolved to a playable version by another plugin.\n this.stream = { playFromSource: info.playFromSource && info.plugin?.playable !== false };\n this.plugin = info.plugin;\n }\n\n /**\n * The playlist this song belongs to\n */\n get playlist() {\n return this.#playlist;\n }\n\n /**\n * Set the playlist this song belongs to.\n * @param playlist - The playlist\n * @throws {@link DisTubeError} When the value is not a {@link Playlist}\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 to play this song.\n */\n get member() {\n return this.#member;\n }\n\n /**\n * Set the user that requested this song.\n *\n * The value is ignored when it is not a valid guild member.\n * @param member - The member\n */\n set member(member: GuildMember | undefined) {\n if (isMemberInstance(member)) this.#member = member;\n }\n\n /**\n * User requested to play this song.\n */\n get user() {\n return this.member?.user;\n }\n\n /**\n * Optional metadata that can be used to identify the song. This is attached by the\n * {@link DisTube#play} method.\n */\n get metadata() {\n return this.#metadata;\n }\n\n /**\n * Set the metadata of the song.\n * @param metadata - The metadata\n */\n set metadata(metadata: T) {\n this.#metadata = metadata;\n }\n\n /**\n * The name of the song, or its url, or its id.\n * @returns The string representation of the song\n */\n toString() {\n return this.name || this.url || this.id || \"Unknown\";\n }\n}\n","import {\n DEFAULT_CROSSFADE_CURVE,\n DEFAULT_CROSSFADE_DURATION_SECS,\n DEFAULT_CROSSFADE_WARMUP_SECS,\n DEFAULT_PRELOAD_THRESHOLD_SECS,\n defaultOptions,\n MAX_CROSSFADE_DURATION_SECS,\n} from \"../constant\";\nimport { DisTubeError } from \"../struct/DisTubeError\";\nimport type {\n CrossfadeOptions,\n DisTubeOptions,\n DisTubePlugin,\n FFmpegArgs,\n FFmpegOptions,\n Filters,\n PreloadOptions,\n UnhandledErrorBehavior,\n} from \"../type\";\nimport { checkInvalidKey } from \"../util\";\n\nconst UNHANDLED_ERROR_BEHAVIORS: readonly UnhandledErrorBehavior[] = [\"log\", \"throw\", \"ignore\"];\n\n/**\n * The validated options of a {@link DisTube} instance.\n *\n * Every option has a default value, and every option is validated when the\n * instance is created.\n */\nexport class Options {\n /**\n * The plugins of the DisTube instance.\n */\n plugins: DisTubePlugin[];\n /**\n * Whether or not the {@link Events.PLAY_SONG} event is emitted when looping a\n * song or when the next song is the same as the previous one.\n * @default false\n */\n emitNewSongOnly: boolean;\n /**\n * Whether or not the previous songs of a {@link Queue} are saved.\n * @default true\n */\n savePreviousSongs: boolean;\n /**\n * The custom FFmpeg audio filters, that override the {@link defaultFilters}.\n */\n customFilters?: Filters;\n /**\n * Whether or not age-restricted content can be played in a non-NSFW channel.\n * @default false\n */\n nsfw: boolean;\n /**\n * Whether or not the {@link Events.ADD_SONG} event is emitted when a new\n * {@link Queue} is created.\n * @default true\n */\n emitAddSongWhenCreatingQueue: boolean;\n /**\n * Whether or not the {@link Events.ADD_LIST} event is emitted when a new\n * {@link Queue} is created.\n * @default true\n */\n emitAddListWhenCreatingQueue: boolean;\n /**\n * Whether or not the bot joins the new voice channel when\n * {@link DisTube#play} is used.\n * @default true\n */\n joinNewVoiceChannel: boolean;\n /**\n * The behavior of the {@link Events.ERROR} event when it has no listener.\n * @default \"log\"\n */\n unhandledError: UnhandledErrorBehavior;\n /**\n * The time (in milliseconds) a track may stay in the \"buffering\" state before\n * it is considered stuck and gets skipped.\n *\n * Set to `0` to disable the stuck-track detection.\n * @default 10000\n */\n stuckThreshold: number;\n /**\n * The preload options of the DisTube instance.\n * @default { enabled: false, threshold: 15 }\n */\n preload: PreloadOptions;\n /**\n * The crossfade options of the DisTube instance.\n * @default { duration: 0, curve: \"qsin\", warmup: 5 }\n */\n crossfade: CrossfadeOptions;\n /**\n * The FFmpeg options of the DisTube instance.\n */\n ffmpeg: FFmpegOptions;\n /**\n * Create the options of a {@link DisTube} instance.\n * @param options - The options given by the user\n * @throws {@link DisTubeError} When an option has an invalid type, or when it\n * is not a known option\n */\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.savePreviousSongs = opts.savePreviousSongs;\n this.customFilters = opts.customFilters;\n this.nsfw = opts.nsfw;\n this.emitAddSongWhenCreatingQueue = opts.emitAddSongWhenCreatingQueue;\n this.emitAddListWhenCreatingQueue = opts.emitAddListWhenCreatingQueue;\n this.joinNewVoiceChannel = opts.joinNewVoiceChannel;\n this.unhandledError = opts.unhandledError;\n this.stuckThreshold = opts.stuckThreshold;\n this.preload = this.#preloadOption(opts.preload);\n this.crossfade = this.#crossfadeOption(opts.crossfade);\n this.ffmpeg = this.#ffmpegOption(options);\n checkInvalidKey(opts, this, \"DisTubeOptions\");\n this.#validateOptions();\n }\n\n #preloadOption(value: DisTubeOptions[\"preload\"]): PreloadOptions {\n if (value === undefined || value === false) {\n return { enabled: false, threshold: DEFAULT_PRELOAD_THRESHOLD_SECS };\n }\n if (value === true) {\n return { enabled: true, threshold: DEFAULT_PRELOAD_THRESHOLD_SECS };\n }\n if (typeof value !== \"object\" || Array.isArray(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", [\"boolean\", \"object\"], value, \"DisTubeOptions.preload\");\n }\n checkInvalidKey(value, [\"enabled\", \"threshold\"], \"DisTubeOptions.preload\");\n const { enabled, threshold } = value;\n if (enabled !== undefined && typeof enabled !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", enabled, \"DisTubeOptions.preload.enabled\");\n }\n if (threshold !== undefined && (typeof threshold !== \"number\" || Number.isNaN(threshold) || threshold < 0)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", threshold, \"DisTubeOptions.preload.threshold\");\n }\n return {\n enabled: enabled ?? false,\n threshold: threshold ?? DEFAULT_PRELOAD_THRESHOLD_SECS,\n };\n }\n\n #crossfadeOption(value: DisTubeOptions[\"crossfade\"]): CrossfadeOptions {\n if (value === undefined) {\n return {\n duration: DEFAULT_CROSSFADE_DURATION_SECS,\n curve: DEFAULT_CROSSFADE_CURVE,\n warmup: DEFAULT_CROSSFADE_WARMUP_SECS,\n };\n }\n if (typeof value !== \"object\" || Array.isArray(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", value, \"DisTubeOptions.crossfade\");\n }\n checkInvalidKey(value, [\"duration\", \"curve\", \"warmup\", \"preparePrimaryInput\"], \"DisTubeOptions.crossfade\");\n const { duration, curve, warmup, preparePrimaryInput } = value;\n if (duration !== undefined && (typeof duration !== \"number\" || Number.isNaN(duration) || duration < 0)) {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n `number >= 0 (max ${MAX_CROSSFADE_DURATION_SECS})`,\n duration,\n \"DisTubeOptions.crossfade.duration\",\n );\n }\n if (duration !== undefined && duration > MAX_CROSSFADE_DURATION_SECS) {\n throw new DisTubeError(\n \"NUMBER_COMPARE\",\n \"Crossfade duration\",\n \"smaller or equal to\",\n MAX_CROSSFADE_DURATION_SECS,\n );\n }\n if (curve !== undefined && (typeof curve !== \"string\" || !curve)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"string\", curve, \"DisTubeOptions.crossfade.curve\");\n }\n if (warmup !== undefined && (typeof warmup !== \"number\" || Number.isNaN(warmup) || warmup < 0)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number >= 0\", warmup, \"DisTubeOptions.crossfade.warmup\");\n }\n if (preparePrimaryInput !== undefined && typeof preparePrimaryInput !== \"function\") {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n \"function\",\n preparePrimaryInput,\n \"DisTubeOptions.crossfade.preparePrimaryInput\",\n );\n }\n return {\n duration: duration ?? DEFAULT_CROSSFADE_DURATION_SECS,\n curve: curve ?? DEFAULT_CROSSFADE_CURVE,\n warmup: warmup ?? DEFAULT_CROSSFADE_WARMUP_SECS,\n preparePrimaryInput,\n };\n }\n\n #validateOptions(options = this) {\n const booleanOptions = new Set([\n \"emitNewSongOnly\",\n \"savePreviousSongs\",\n \"joinNewVoiceChannel\",\n \"nsfw\",\n \"emitAddSongWhenCreatingQueue\",\n \"emitAddListWhenCreatingQueue\",\n ]);\n const numberOptions = new Set([\"stuckThreshold\"]);\n const stringOptions = new Set([\"unhandledError\"]);\n const objectOptions = new Set([\"customFilters\", \"ffmpeg\", \"preload\", \"crossfade\"]);\n const optionalOptions = new Set([\"customFilters\"]);\n\n for (const [key, value] of Object.entries(options)) {\n if (value === undefined && optionalOptions.has(key)) continue;\n if (key === \"plugins\" && !Array.isArray(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"Array<Plugin>\", value, `DisTubeOptions.${key}`);\n } else if (booleanOptions.has(key)) {\n if (typeof value !== \"boolean\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"boolean\", value, `DisTubeOptions.${key}`);\n }\n } else if (numberOptions.has(key)) {\n if (typeof value !== \"number\" || Number.isNaN(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"number\", value, `DisTubeOptions.${key}`);\n }\n } else if (stringOptions.has(key)) {\n if (typeof value !== \"string\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"string\", value, `DisTubeOptions.${key}`);\n }\n if (!UNHANDLED_ERROR_BEHAVIORS.includes(value as UnhandledErrorBehavior)) {\n throw new DisTubeError(\"INVALID_TYPE\", UNHANDLED_ERROR_BEHAVIORS, value, `DisTubeOptions.${key}`);\n }\n } else if (objectOptions.has(key)) {\n // `preload` has already been fully validated and normalized in\n // #preloadOption, so a plain object check is enough here.\n if (typeof value !== \"object\" || Array.isArray(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", value, `DisTubeOptions.${key}`);\n }\n }\n }\n }\n\n #ffmpegOption(opts: DisTubeOptions) {\n const args: FFmpegArgs = { global: {}, input: {}, output: {} };\n if (opts.ffmpeg?.args) {\n if (opts.ffmpeg.args.global) args.global = opts.ffmpeg.args.global;\n if (opts.ffmpeg.args.input) args.input = opts.ffmpeg.args.input;\n if (opts.ffmpeg.args.output) args.output = opts.ffmpeg.args.output;\n }\n const path = opts.ffmpeg?.path ?? \"ffmpeg\";\n if (typeof path !== \"string\") {\n throw new DisTubeError(\"INVALID_TYPE\", \"string\", path, \"DisTubeOptions.ffmpeg.path\");\n }\n for (const [key, value] of Object.entries(args)) {\n if (typeof value !== \"object\" || Array.isArray(value)) {\n throw new DisTubeError(\"INVALID_TYPE\", \"object\", value, `DisTubeOptions.ffmpeg.${key}`);\n }\n for (const [k, v] of Object.entries(value)) {\n if (\n typeof v !== \"string\" &&\n typeof v !== \"number\" &&\n typeof v !== \"boolean\" &&\n !Array.isArray(v) &&\n v !== null &&\n v !== undefined\n ) {\n throw new DisTubeError(\n \"INVALID_TYPE\",\n [\"string\", \"number\", \"boolean\", \"Array<string | null | undefined>\", \"null\", \"undefined\"],\n v,\n `DisTubeOptions.ffmpeg.${key}.${k}`,\n );\n }\n }\n }\n return { path, args };\n }\n}\n","import type { ChildProcess } from \"node:child_process\";\nimport { spawn, spawnSync } from \"node:child_process\";\nimport type { TransformCallback } from \"node:stream\";\nimport { Transform } from \"node:stream\";\nimport type { AudioResource } from \"@discordjs/voice\";\nimport { createAudioResource, StreamType } from \"@discordjs/voice\";\nimport { TypedEmitter } from \"tiny-typed-emitter\";\nimport { AUDIO_CHANNELS, AUDIO_SAMPLE_RATE, DEFAULT_CROSSFADE_CURVE } from \"../constant\";\nimport type { DisTube } from \"../DisTube\";\nimport { DisTubeError } from \"../struct/DisTubeError\";\nimport type { Awaitable, FFmpegArg, FFmpegOptions } from \"../type\";\nimport { Events } from \"../type\";\n\n/**\n * Options for {@link DisTubeStream}\n */\nexport interface StreamOptions {\n /**\n * FFmpeg options\n */\n ffmpeg: FFmpegOptions;\n /**\n * Seek time (in seconds).\n * @default 0\n */\n seek?: number;\n /**\n * Crossfade transition options.\n *\n * When set, the stream mixes the primary URL (the song that is fading out,\n * seeked to its final `duration` seconds) and the secondary URL (the song\n * that is fading in) with an FFmpeg `acrossfade` filter graph, so the two\n * songs crossfade seamlessly in a single FFmpeg process.\n */\n crossfade?: CrossfadeStreamOptions;\n}\n\n/**\n * Options describing a crossfade transition stream\n */\nexport interface CrossfadeStreamOptions {\n /**\n * The fade duration in seconds.\n */\n duration: number;\n /**\n * The initial seek of the first (fading out) input, in seconds. It must be\n * the position where the fade window begins (`song duration - duration`).\n */\n primarySeek: number;\n /**\n * The stream URL of the second (fading in) input.\n */\n secondaryUrl: string;\n /**\n * The FFmpeg `acrossfade` fade curve of the first (fading out) input.\n * @default \"qsin\"\n */\n outCurve?: string;\n /**\n * The FFmpeg `acrossfade` fade curve of the second (fading in) input.\n * @default \"qsin\"\n */\n inCurve?: string;\n /**\n * FFmpeg input options of the first (fading out) input. When set, they\n * replace the default input options, which are tuned for http(s) streaming\n * urls. Use it for inputs that need different flags — a local playlist\n * file, for example, requires the `protocol_whitelist` option and no\n * reconnect flags.\n */\n primaryInputArgs?: FFmpegArg;\n}\n\nlet checked = process.env.NODE_ENV === \"test\";\n/**\n * Check that FFmpeg is installed and can be spawned.\n *\n * The check is only done once: the result is cached.\n * @param distube - The DisTube instance\n * @returns Nothing\n * @throws {@link DisTubeError} When FFmpeg cannot be spawned\n */\nexport const checkFFmpeg = (distube: DisTube) => {\n if (checked) return;\n const path = distube.options.ffmpeg.path;\n const debug = (str: string) => distube.emit(Events.FFMPEG_DEBUG, str);\n try {\n debug(`[test] spawn ffmpeg at '${path}' path`);\n const process = spawnSync(path, [\"-h\"], {\n windowsHide: true,\n encoding: \"utf-8\",\n });\n if (process.error) throw process.error;\n if (process.stderr && !process.stdout) throw new Error(process.stderr);\n\n const result = process.output.join(\"\\n\");\n const version = /ffmpeg version (\\S+)/iu.exec(result)?.[1];\n if (!version) throw new Error(\"Invalid FFmpeg version\");\n debug(`[test] ffmpeg version: ${version}`);\n } catch (e: unknown) {\n const errorMessage = e instanceof Error ? (e.stack ?? e.message) : String(e);\n debug(`[test] failed to spawn ffmpeg at '${path}': ${errorMessage}`);\n throw new DisTubeError(\"FFMPEG_NOT_INSTALLED\", path);\n }\n checked = true;\n};\n\n/**\n * Create a stream to play with {@link DisTubeVoice}\n */\nexport class DisTubeStream extends TypedEmitter<{\n debug: (debug: string) => Awaitable;\n error: (error: Error) => Awaitable;\n}> {\n #ffmpegPath: string;\n #opts: string[];\n /**\n * The FFmpeg process that decodes the audio.\n *\n * It is `undefined` until {@link DisTubeStream#spawn} is called.\n */\n process?: ChildProcess;\n /**\n * The stream of the decoded audio, with the volume applied to it.\n */\n stream: VolumeTransformer;\n /**\n * The Discord.js audio resource that is played by the audio player.\n */\n audioResource: AudioResource;\n /**\n * The seek time in seconds that this stream started from\n */\n readonly seekTime: number;\n /**\n * Whether FFmpeg has already produced audio that is waiting to be read.\n *\n * The stream is spawned ahead of the playback (crossfade warmup) and the\n * pipe backs up once its buffers are full, so this is `true` as soon as the\n * first frame exists. A stream that is still `false` at playback time would\n * leave the audio player buffering until FFmpeg catches up.\n */\n get hasBufferedAudio(): boolean {\n return this.stream.readableLength > 0;\n }\n /**\n * Create a DisTubeStream to play with {@link DisTubeVoice}\n * @param url - Stream URL\n * @param options - Stream options\n */\n constructor(url: string, options: StreamOptions) {\n super();\n const { ffmpeg, seek, crossfade } = options;\n this.seekTime = typeof seek === \"number\" && seek > 0 ? seek : 0;\n this.#ffmpegPath = ffmpeg.path;\n this.#opts = crossfade ? this.#crossfadeArgs(url, ffmpeg, crossfade) : this.#singleInputArgs(url, ffmpeg, seek);\n\n this.stream = new VolumeTransformer();\n this.stream\n .on(\"close\", () => this.kill())\n .on(\"error\", err => {\n this.debug(`[stream] error: ${err.message}`);\n this.emit(\"error\", err);\n })\n .on(\"finish\", () => this.debug(\"[stream] log: stream finished\"));\n\n this.audioResource = createAudioResource(this.stream, {\n inputType: StreamType.Raw,\n inlineVolume: false,\n });\n }\n\n #flattenArgs(args: FFmpegArg): string[] {\n return Object.entries(args)\n .flatMap(([key, value]) =>\n Array.isArray(value)\n ? value.filter(Boolean).map(v => [`-${key}`, String(v)])\n : value == null || value === false\n ? []\n : [value === true ? `-${key}` : [`-${key}`, String(value)]],\n )\n .flat();\n }\n\n /**\n * Translate a `file:` URL into a local filesystem path that FFmpeg accepts.\n *\n * `file:///C:/x` loses its drive-letter leading slash on Windows (`C:/x`),\n * UNC shares keep their `//host` prefix, POSIX paths stay untouched, and\n * other protocols return `undefined`.\n */\n #localPath(url: string): string | undefined {\n const fileUrl = new URL(url);\n if (fileUrl.protocol !== \"file:\") return undefined;\n const pathname = decodeURIComponent(fileUrl.pathname);\n if (fileUrl.hostname) return `//${fileUrl.hostname}${pathname}`;\n return /^\\/[A-Za-z]:\\//.test(pathname) ? pathname.slice(1) : pathname;\n }\n\n #singleInputArgs(url: string, ffmpeg: FFmpegOptions, seek?: number): string[] {\n const opts: FFmpegArg = {\n reconnect: 1,\n reconnect_streamed: 1,\n reconnect_delay_max: 5,\n analyzeduration: 0,\n hide_banner: true,\n ...ffmpeg.args.global,\n ...ffmpeg.args.input,\n i: url,\n ar: AUDIO_SAMPLE_RATE,\n ac: AUDIO_CHANNELS,\n ...ffmpeg.args.output,\n f: \"s16le\",\n };\n\n if (typeof seek === \"number\" && seek > 0) opts.ss = seek.toString();\n\n const localPath = this.#localPath(url);\n if (localPath !== undefined) {\n opts.reconnect = null;\n opts.reconnect_streamed = null;\n opts.reconnect_delay_max = null;\n opts.i = localPath;\n }\n\n return [...this.#flattenArgs(opts), \"pipe:1\"];\n }\n\n /**\n * Build the arguments of a crossfade transition stream: a single FFmpeg\n * process with two inputs (the fading out song seeked to its final\n * `duration` seconds and the fading in song from its beginning) mixed by an\n * `acrossfade` filter graph.\n *\n * Both inputs are normalized (48kHz stereo s16) before the fade, and the\n * queue's `af` filter chain, when present, is folded into the filter complex\n * after the fade (FFmpeg cannot combine `-af` with `-filter_complex`).\n */\n #crossfadeArgs(url: string, ffmpeg: FFmpegOptions, crossfade: CrossfadeStreamOptions): string[] {\n const {\n duration,\n primarySeek,\n secondaryUrl,\n outCurve = DEFAULT_CROSSFADE_CURVE,\n inCurve = DEFAULT_CROSSFADE_CURVE,\n } = crossfade;\n // The `af` output argument cannot coexist with filter_complex: move it to\n // the end of the filter graph instead.\n const outputArgs: FFmpegArg = { ...ffmpeg.args.output };\n const extraFilters =\n typeof outputArgs.af === \"string\"\n ? outputArgs.af\n : Array.isArray(outputArgs.af)\n ? outputArgs.af.filter(Boolean).join(\",\")\n : undefined;\n delete outputArgs.af;\n\n const primaryOpts: FFmpegArg = {\n hide_banner: true,\n ...ffmpeg.args.global,\n ...(crossfade.primaryInputArgs ?? {\n reconnect: 1,\n reconnect_streamed: 1,\n reconnect_delay_max: 5,\n analyzeduration: 0,\n ...ffmpeg.args.input,\n }),\n ss: typeof primarySeek === \"number\" && primarySeek > 0 ? primarySeek.toString() : null,\n i: url,\n };\n const secondaryOpts: FFmpegArg = {\n reconnect: 1,\n reconnect_streamed: 1,\n reconnect_delay_max: 5,\n analyzeduration: 0,\n ...ffmpeg.args.input,\n i: secondaryUrl,\n };\n\n // File inputs need the reconnect flags dropped and a plain local path\n // (also for the fading-in input, not only the primary one).\n const primaryLocal = this.#localPath(url);\n if (primaryLocal !== undefined) {\n primaryOpts.reconnect = null;\n primaryOpts.reconnect_streamed = null;\n primaryOpts.reconnect_delay_max = null;\n primaryOpts.i = primaryLocal;\n }\n const secondaryLocal = this.#localPath(secondaryUrl);\n if (secondaryLocal !== undefined) {\n secondaryOpts.reconnect = null;\n secondaryOpts.reconnect_streamed = null;\n secondaryOpts.reconnect_delay_max = null;\n secondaryOpts.i = secondaryLocal;\n }\n\n const normalize = `aresample=${AUDIO_SAMPLE_RATE},aformat=sample_fmts=s16:channel_layouts=stereo`;\n const fade = `[a0][a1]acrossfade=d=${duration}:c1=${outCurve}:c2=${inCurve}[xf]`;\n const graph = [\n `[0:a]${normalize}[a0]`,\n `[1:a]${normalize}[a1]`,\n fade,\n ...(extraFilters ? [`[xf]${extraFilters}[aout]`] : []),\n ].join(\";\");\n\n const outputOpts: FFmpegArg = {\n ar: AUDIO_SAMPLE_RATE,\n ac: AUDIO_CHANNELS,\n ...outputArgs,\n filter_complex: graph,\n map: extraFilters ? \"[aout]\" : \"[xf]\",\n f: \"s16le\",\n };\n\n return [\n ...this.#flattenArgs(primaryOpts),\n ...this.#flattenArgs(secondaryOpts),\n ...this.#flattenArgs(outputOpts),\n \"pipe:1\",\n ];\n }\n\n /**\n * Spawn the FFmpeg process that decodes the audio.\n * @returns Nothing\n * @throws {Error} When the FFmpeg process cannot be created\n */\n spawn() {\n this.debug(`[process] spawn: ${this.#ffmpegPath} ${this.#opts.join(\" \")}`);\n this.process = spawn(this.#ffmpegPath, this.#opts, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n shell: false,\n windowsHide: true,\n })\n .on(\"error\", err => {\n this.debug(`[process] error: ${err.message}`);\n this.emit(\"error\", err);\n })\n .on(\"exit\", (code, signal) => {\n this.debug(`[process] exit: code=${code ?? \"unknown\"} signal=${signal ?? \"unknown\"}`);\n if (!code || [0, 255].includes(code)) return;\n this.debug(`[process] error: ffmpeg exited with code ${code}`);\n this.emit(\"error\", new DisTubeError(\"FFMPEG_EXITED\", code));\n });\n\n if (!this.process.stdout || !this.process.stderr) {\n this.kill();\n throw new Error(\"Failed to create ffmpeg process\");\n }\n\n this.process.stdout.pipe(this.stream);\n this.process.stderr.setEncoding(\"utf8\")?.on(\"data\", (data: string) => {\n const lines = data.split(/\\r\\n|\\r|\\n/u);\n for (const line of lines) {\n if (/^\\s*$/.test(line)) continue;\n this.debug(`[ffmpeg] log: ${line}`);\n }\n });\n }\n\n private debug(debug: string) {\n this.emit(\"debug\", debug);\n }\n\n /**\n * Set the volume of the stream.\n * @param volume - The volume of the stream, between `0` and `1`\n * @returns Nothing\n */\n setVolume(volume: number) {\n this.stream.vol = volume;\n }\n\n /**\n * Kill the FFmpeg process and destroy the stream.\n * @returns Nothing\n */\n kill() {\n if (!this.stream.destroyed) this.stream.destroy();\n if (this.process && !this.process.killed) this.process.kill(\"SIGKILL\");\n }\n}\n\n// Based on prism-media\nclass VolumeTransformer extends Transform {\n private buffer = Buffer.allocUnsafe(0);\n private readonly extrema = [-(2 ** (16 - 1)), 2 ** (16 - 1) - 1];\n vol = 1;\n\n override _transform(newChunk: Buffer, _encoding: BufferEncoding, done: TransformCallback): void {\n const { vol } = this;\n if (vol === 1) {\n this.push(newChunk);\n done();\n return;\n }\n\n const bytes = 2;\n const chunk = Buffer.concat([this.buffer, newChunk]);\n const readableLength = Math.floor(chunk.length / bytes) * bytes;\n\n for (let i = 0; i < readableLength; i += bytes) {\n const value = chunk.readInt16LE(i);\n const clampedValue = Math.min(this.extrema[1], Math.max(this.extrema[0], value * vol));\n chunk.writeInt16LE(clampedValue, i);\n }\n\n this.buffer = chunk.subarray(readableLength);\n this.push(chunk.subarray(0, readableLength));\n done();\n }\n}\n","import { getVoiceConnection, VoiceConnectionStatus } from \"@discordjs/voice\";\nimport type { VoiceBasedChannel } from \"discord.js\";\nimport type { GuildIdResolvable } from \"../..\";\nimport { DisTubeError, resolveGuildId } from \"../..\";\nimport { DisTubeVoice } from \"../DisTubeVoice\";\nimport { GuildIdManager } from \"./GuildIdManager\";\n\n/**\n * Manages voice connections\n */\nexport class DisTubeVoiceManager extends GuildIdManager<DisTubeVoice> {\n /**\n * Create a {@link DisTubeVoice} instance\n * @param channel - A voice channel to join\n * @returns The voice connection of the guild\n * @throws {@link DisTubeError} When the guild already has a voice connection\n * that is not managed by DisTube\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 if (\n getVoiceConnection(resolveGuildId(channel), this.client.user?.id) ||\n getVoiceConnection(resolveGuildId(channel))\n ) {\n throw new DisTubeError(\"VOICE_ALREADY_CREATED\");\n }\n return new DisTubeVoice(this, channel);\n }\n /**\n * Join a voice channel and wait until the connection is ready\n * @param channel - A voice channel to join\n * @returns The voice connection of the guild\n * @throws {@link DisTubeError} When the connection cannot be established\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 guild - Queue Resolvable\n * @returns Nothing\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 type { GuildIdResolvable } from \"../..\";\nimport { resolveGuildId } from \"../..\";\nimport { BaseManager } from \"./BaseManager\";\n\n/**\n * Manages the collection of a data model paired with a guild id.\n */\nexport abstract class GuildIdManager<V> extends BaseManager<V> {\n /**\n * Add an item to the collection.\n *\n * The item is not added when there is already one for the same guild.\n * @param idOrInstance - The guild id, or anything that can be resolved to a guild id\n * @param data - The item to add\n * @returns This manager, to allow chaining\n * @throws {@link DisTubeError} When the value cannot be resolved to a guild id\n */\n add(idOrInstance: GuildIdResolvable, data: V) {\n const id = resolveGuildId(idOrInstance);\n const existing = this.get(id);\n if (existing) return this;\n this.collection.set(id, data);\n return this;\n }\n /**\n * Get the item of a guild.\n * @param idOrInstance - The guild id, or anything that can be resolved to a guild id\n * @returns The item of the guild, or `undefined` when there is none\n * @throws {@link DisTubeError} When the value cannot be resolved to a guild id\n */\n get(idOrInstance: GuildIdResolvable): V | undefined {\n return this.collection.get(resolveGuildId(idOrInstance));\n }\n /**\n * Remove the item of a guild.\n * @param idOrInstance - The guild id, or anything that can be resolved to a guild id\n * @returns `true` when an item was removed, `false` otherwise\n * @throws {@link DisTubeError} When the value cannot be resolved to a guild id\n */\n remove(idOrInstance: GuildIdResolvable): boolean {\n return this.collection.delete(resolveGuildId(idOrInstance));\n }\n /**\n * Check whether a guild has an item.\n * @param idOrInstance - The guild id, or anything that can be resolved to a guild id\n * @returns `true` when there is an item for the guild\n * @throws {@link DisTubeError} When the value cannot be resolved to a guild id\n */\n has(idOrInstance: GuildIdResolvable): boolean {\n return this.collection.has(resolveGuildId(idOrInstance));\n }\n}\n","import type { GuildTextBasedChannel, VoiceBasedChannel } from \"discord.js\";\nimport type { FFmpegArg, Song } from \"../..\";\nimport {\n CROSSFADE_DRIFT_TOLERANCE_SECS,\n checkFFmpeg,\n DisTubeError,\n DisTubeStream,\n Events,\n objectKeys,\n Queue,\n RepeatMode,\n} from \"../..\";\nimport { GuildIdManager } from \"./GuildIdManager\";\n\n/**\n * Queue manager\n */\nexport class QueueManager extends GuildIdManager<Queue> {\n /**\n * Create a {@link Queue}\n * @param channel - A voice channel\n * @param textChannel - Default text channel\n * @returns The created queue\n * @throws {@link DisTubeError} When the guild already has a queue, or when\n * the voice channel cannot be joined\n */\n async create(channel: VoiceBasedChannel, textChannel?: GuildTextBasedChannel): Promise<Queue> {\n if (this.has(channel.guildId)) throw new DisTubeError(\"QUEUE_EXIST\");\n this.debug(`[QueueManager] Creating queue for guild: ${channel.guildId}`);\n const voice = this.voices.create(channel);\n const queue = new Queue(this.distube, voice, textChannel);\n await queue._taskQueue.queuing();\n try {\n checkFFmpeg(this.distube);\n this.debug(`[QueueManager] Joining voice channel: ${channel.id}`);\n await voice.join();\n this.#voiceEventHandler(queue);\n this.add(queue.id, queue);\n this.emit(Events.INIT_QUEUE, queue);\n return queue;\n } finally {\n queue._taskQueue.resolve();\n }\n }\n\n /**\n * Listen to DisTubeVoice events and handle the Queue\n * @param queue - Queue\n */\n #voiceEventHandler(queue: Queue) {\n queue._listeners = {\n disconnect: error => {\n queue.remove();\n this.emit(Events.DISCONNECT, queue);\n if (error) this.emitError(error, queue, queue.songs?.[0]);\n },\n error: error => void this.#handlePlayingError(queue, error),\n finish: () => void this.handleSongFinish(queue),\n channelChange: (oldChannel, newChannel) => {\n this.emit(Events.VOICE_CHANNEL_CHANGE, queue, oldChannel, newChannel);\n },\n };\n for (const event of objectKeys(queue._listeners)) {\n queue.voice.on(event, queue._listeners[event]);\n }\n }\n\n /**\n * Handle the queue when a Song finish\n * @param queue - queue\n * @returns A promise that resolves when the next song is playing\n */\n async handleSongFinish(queue: Queue): Promise<void> {\n if (queue._manualUpdate) {\n queue._manualUpdate = false;\n await this.playSong(queue);\n return;\n }\n this.debug(`[QueueManager] Handling song finish: ${queue.id}`);\n const song = queue.songs[0];\n this.emit(Events.FINISH_SONG, queue, song);\n await queue._taskQueue.queuing();\n try {\n if (queue.stopped) return;\n if (queue.repeatMode === RepeatMode.QUEUE) queue.songs.push(song);\n\n if (queue.repeatMode !== RepeatMode.SONG) {\n const prev = queue.songs.shift() as Song;\n if (this.options.savePreviousSongs) queue.previousSongs.push(prev);\n else queue.previousSongs.push({ id: prev.id } as Song);\n }\n\n if (queue.songs.length === 0 && queue.autoplay) {\n try {\n this.debug(`[QueueManager] Adding related song: ${queue.id}`);\n await queue._addRelatedSong(song);\n } catch (e: unknown) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[${queue.id}] Add related song error: ${errorMessage}`);\n if (e instanceof DisTubeError) {\n this.emit(Events.NO_RELATED, queue, e);\n } else {\n this.emit(Events.NO_RELATED, queue, new DisTubeError(\"NO_RELATED\"));\n }\n }\n }\n\n if (queue.songs.length === 0) {\n this.debug(`[${queue.id}] Queue is empty, stopping...`);\n this.emit(Events.EMPTY, queue);\n if (!queue.autoplay) this.emit(Events.FINISH, queue);\n queue.remove();\n return;\n }\n\n if (song !== queue.songs[0]) {\n const playedSong = song.stream.playFromSource ? song : song.stream.song;\n if (playedSong?.stream.playFromSource) delete playedSong.stream.url;\n }\n await this.playSong(queue, true);\n } finally {\n queue._taskQueue.resolve();\n }\n }\n\n /**\n * Handle error while playing\n * @param queue - queue\n * @param error - error\n */\n async #handlePlayingError(queue: Queue, error: Error) {\n const song = queue.songs.shift()!;\n try {\n error.name = \"PlayingError\";\n } catch {\n // Emit original error\n }\n this.debug(`[${queue.id}] Error while playing: ${error.stack || error.message}`);\n this.emitError(error, queue, song);\n if (queue.songs.length > 0) {\n this.debug(`[${queue.id}] Playing next song: ${queue.songs[0]}`);\n await this.playSong(queue);\n } else {\n this.debug(`[${queue.id}] Queue is empty, stopping...`);\n await queue.stop();\n }\n }\n\n /**\n * Play a song on voice connection with queue properties\n * @param queue - The guild queue to play\n * @param emitPlaySong - Whether or not emit {@link Events.PLAY_SONG} event\n * @param options - Optional options\n * @param options.keepSongOnError - Whether the current song has to stay in the\n * queue when the stream cannot be started\n * @returns A promise that resolves when the song is playing\n * @throws {@link DisTubeError} When the song does not have any stream URL\n */\n async playSong(queue: Queue, emitPlaySong = true, options?: { keepSongOnError?: boolean }) {\n if (!queue) return;\n if (queue.stopped || !queue.songs.length) {\n await queue.stop();\n return;\n }\n try {\n const song = queue.songs[0];\n let dtStream: DisTubeStream;\n\n if (queue._preloadedSong === song && queue._preloadedStream) {\n this.debug(`[${queue.id}] Using preloaded stream for: ${song}`);\n dtStream = queue._preloadedStream;\n queue._preloadedSong = undefined;\n queue._preloadedStream = undefined;\n } else {\n queue._clearPreload();\n this.debug(`[${queue.id}] Getting stream from: ${song}`);\n await this.handler.attachStreamInfo(song);\n const willPlaySong = song.stream.playFromSource ? song : song.stream.song;\n const stream = willPlaySong?.stream;\n if (!willPlaySong || !stream?.playFromSource || !stream.url) throw new DisTubeError(\"NO_STREAM_URL\", `${song}`);\n this.debug(`[${queue.id}] Creating DisTubeStream for: ${willPlaySong}`);\n const streamOptions = {\n ffmpeg: {\n path: this.options.ffmpeg.path,\n args: {\n global: { ...queue.ffmpegArgs.global },\n input: { ...queue.ffmpegArgs.input },\n output: { ...queue.ffmpegArgs.output, ...queue.filters.ffmpegArgs },\n },\n },\n seek: willPlaySong.duration ? queue._beginTime : undefined,\n };\n queue._beginTime = 0;\n dtStream = new DisTubeStream(stream.url, streamOptions);\n dtStream.on(\"debug\", data => this.emit(Events.FFMPEG_DEBUG, `[${queue.id}] ${data}`));\n }\n\n queue._beginTime = 0;\n this.debug(`[${queue.id}] Started playing: ${song}`);\n await queue.voice.play(dtStream);\n if (emitPlaySong) this.emit(Events.PLAY_SONG, queue, song);\n this.schedulePreload(queue);\n this.scheduleCrossfade(queue);\n } catch (e: unknown) {\n const error = e instanceof Error ? e : new Error(String(e));\n if (options?.keepSongOnError) {\n // The stream is only being restarted (e.g. after a filter change):\n // the current song must stay in the queue even if the restart failed.\n this.debug(`[${queue.id}] Error while restarting the stream: ${error.stack || error.message}`);\n this.emitError(error, queue, queue.songs[0]);\n return;\n }\n await this.#handlePlayingError(queue, error);\n }\n }\n\n /**\n * Schedule preloading the next song in the queue before the current song finishes.\n * @param queue - The guild queue\n */\n schedulePreload(queue: Queue) {\n if (!this.options.preload.enabled || queue.stopped || queue.paused) return;\n if (queue._preloadTimeout) {\n clearTimeout(queue._preloadTimeout);\n queue._preloadTimeout = undefined;\n }\n\n const currentSong = queue.songs[0];\n const nextSong = queue.songs[1];\n if (!currentSong || !nextSong) return;\n\n if (queue._preloadedSong === nextSong && queue._preloadedStream) return;\n\n const threshold = this.options.preload.threshold;\n const duration = currentSong.duration ?? 0;\n const currentTime = queue.currentTime;\n const remaining = duration > 0 && Number.isFinite(currentTime) ? duration - currentTime : 0;\n\n if (duration === 0 || remaining <= threshold) {\n void this.preloadNextSong(queue);\n } else {\n const delayMs = Math.max(0, (remaining - threshold) * 1000);\n queue._preloadTimeout = setTimeout(() => {\n queue._preloadTimeout = undefined;\n void this.preloadNextSong(queue);\n }, delayMs);\n queue._preloadTimeout.unref?.();\n }\n }\n\n /**\n * Preload the next song in the queue.\n * @param queue - The guild queue\n */\n async preloadNextSong(queue: Queue) {\n // Only one preload task may run at a time: playSong fires a preload\n // internally, and callers may request one concurrently as well.\n if (queue._preloading) return queue._preloading;\n const task = this.#preloadTask(queue);\n queue._preloading = task;\n try {\n await task;\n } finally {\n if (queue._preloading === task) queue._preloading = undefined;\n }\n }\n\n async #preloadTask(queue: Queue) {\n if (!this.options.preload.enabled || queue.stopped || queue.paused) return;\n const nextSong = queue.songs[1];\n if (!nextSong) return;\n if (queue._preloadedSong === nextSong && queue._preloadedStream) return;\n // The generation is bumped by _clearPreload(): when the preloaded state\n // is invalidated while this task is running, its result must be dropped.\n const generation = queue._preloadGeneration;\n\n this.debug(`[${queue.id}] Preloading next song: ${nextSong}`);\n this.emit(Events.PRELOAD_SONG, queue, nextSong);\n\n try {\n await this.handler.attachStreamInfo(nextSong);\n\n if (queue.stopped || queue.songs[1] !== nextSong || generation !== queue._preloadGeneration) return;\n\n const willPlaySong = nextSong.stream.playFromSource ? nextSong : nextSong.stream.song;\n const stream = willPlaySong?.stream;\n if (!willPlaySong || !stream?.playFromSource || !stream.url) {\n throw new DisTubeError(\"NO_STREAM_URL\", `${nextSong}`);\n }\n\n const streamOptions = {\n ffmpeg: {\n path: this.options.ffmpeg.path,\n args: {\n global: { ...queue.ffmpegArgs.global },\n input: { ...queue.ffmpegArgs.input },\n output: { ...queue.ffmpegArgs.output, ...queue.filters.ffmpegArgs },\n },\n },\n seek: undefined,\n };\n\n const dtStream = new DisTubeStream(stream.url, streamOptions);\n dtStream.on(\"debug\", data => this.emit(Events.FFMPEG_DEBUG, `[${queue.id}] [preload] ${data}`));\n\n if (queue.stopped || queue.songs[1] !== nextSong || generation !== queue._preloadGeneration) {\n dtStream.kill();\n return;\n }\n\n queue._preloadedSong = nextSong;\n queue._preloadedStream = dtStream;\n\n this.debug(`[${queue.id}] Successfully preloaded next song: ${nextSong}`);\n this.emit(Events.PRELOADED_SONG, queue, nextSong);\n } catch (e: unknown) {\n if (queue._preloadedSong === nextSong) {\n queue._preloadedSong = undefined;\n queue._preloadedStream?.kill();\n queue._preloadedStream = undefined;\n }\n const error = e instanceof Error ? e : new Error(String(e));\n this.debug(`[${queue.id}] Preload failed for ${nextSong}: ${error.message}`);\n this.emit(Events.PRELOAD_ERROR, queue, nextSong, error);\n }\n }\n\n /**\n * Schedule the crossfade into the next song: a single FFmpeg process mixes\n * the current song (seeked to its final fade window) with the next song, and\n * replaces the playback stream exactly when the fade window begins.\n *\n * Canceled automatically whenever the preloaded state is invalidated\n * (pause, seek, stop...), as both schedulers share the same generation.\n * @param queue - The guild queue\n */\n scheduleCrossfade(queue: Queue) {\n queue._crossfadeCancel();\n if (queue.stopped || queue.paused) return;\n const currentSong = queue.songs[0];\n if (!currentSong) return;\n const songDuration = currentSong.duration ?? 0;\n // Live songs have an unknown duration: they cannot be crossfaded.\n if (!songDuration || !Number.isFinite(songDuration)) return;\n const fade = Math.min(Number(queue.crossfade) || 0, songDuration);\n if (fade <= 0) return;\n const nextSong = queue.repeatMode === RepeatMode.SONG ? currentSong : queue.songs[1];\n if (!nextSong) return;\n const currentTime = queue.currentTime;\n if (!Number.isFinite(currentTime)) return;\n const remaining = songDuration - currentTime;\n if (remaining <= fade) return;\n const delayMs = Math.max(0, (remaining - fade - this.options.crossfade.warmup) * 1000);\n this.debug(\n `[${queue.id}] Scheduling crossfade (${fade}s fade) in ${(delayMs / 1000).toFixed(1)}s: ${currentSong} -> ${nextSong}`,\n );\n queue._crossfadeTimeout = setTimeout(() => {\n queue._crossfadeTimeout = undefined;\n void this.#crossfadeWarmupTask(queue);\n }, delayMs);\n queue._crossfadeTimeout.unref?.();\n }\n\n /**\n * Spawn the merged transition stream ahead of the fade window so both of\n * its inputs are buffered when the fade must start, then arm the boundary\n * timer that swaps the playback stream.\n */\n async #crossfadeWarmupTask(queue: Queue) {\n let transitionStream: DisTubeStream | undefined;\n try {\n if (queue.stopped || queue.paused) return;\n const song = queue.songs[0];\n const generation = queue._preloadGeneration;\n const repeatSong = queue.repeatMode === RepeatMode.SONG;\n const nextSong = repeatSong ? song : queue.songs[1];\n if (!song || !nextSong) return;\n const songDuration = song.duration ?? 0;\n const fade = Math.min(Number(queue.crossfade) || 0, songDuration);\n if (fade <= 0) return;\n const remaining = songDuration - queue.currentTime;\n if (remaining <= fade) return;\n if (!repeatSong) {\n // Resolve the next song's stream url if the preload has not done it\n // yet: the transition stream needs it before the fade starts.\n if (this.options.preload.enabled) await this.preloadNextSong(queue);\n else await this.handler.attachStreamInfo(nextSong);\n }\n if (queue.stopped || queue.paused || queue.songs[0] !== song || generation !== queue._preloadGeneration) return;\n if (repeatSong ? queue.songs[0] !== song : queue.songs[1] !== nextSong) return;\n\n const primary = song.stream.playFromSource ? song : song.stream.song;\n const secondary = repeatSong ? primary : nextSong.stream.playFromSource ? nextSong : nextSong.stream.song;\n if (!primary?.stream.playFromSource || !primary.stream.url) return;\n if (!secondary?.stream.playFromSource || !secondary.stream.url) return;\n\n this.debug(`[${queue.id}] Warming up crossfade stream: ${song} -> ${nextSong}`);\n const boundarySeek = Math.max(0, songDuration - fade);\n let primaryUrl: string = primary.stream.url;\n let primarySeek = boundarySeek;\n let primaryInputArgs: FFmpegArg | undefined;\n const prepare = this.options.crossfade.preparePrimaryInput;\n if (prepare) {\n try {\n const prepared = await prepare(primary.stream.url, { seek: boundarySeek, song });\n if (prepared?.url) {\n primaryUrl = prepared.url;\n if (typeof prepared.seek === \"number\" && Number.isFinite(prepared.seek) && prepared.seek >= 0) {\n primarySeek = prepared.seek;\n }\n primaryInputArgs = prepared.inputArgs;\n this.debug(`[${queue.id}] Crossfade primary input prepared by the adapter`);\n }\n } catch (e: unknown) {\n // Best-effort: fall back to the original url when the adapter fails.\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[${queue.id}] Crossfade primary input preparation failed: ${errorMessage}`);\n }\n }\n transitionStream = new DisTubeStream(primaryUrl, {\n ffmpeg: {\n path: this.options.ffmpeg.path,\n args: {\n global: { ...queue.ffmpegArgs.global },\n input: { ...queue.ffmpegArgs.input },\n output: { ...queue.ffmpegArgs.output, ...queue.filters.ffmpegArgs },\n },\n },\n crossfade: {\n duration: fade,\n primarySeek,\n secondaryUrl: secondary.stream.url,\n inCurve: this.options.crossfade.curve,\n outCurve: this.options.crossfade.curve,\n primaryInputArgs,\n },\n });\n transitionStream.on(\"debug\", data => this.emit(Events.FFMPEG_DEBUG, `[${queue.id}] [crossfade] ${data}`));\n\n if (queue.stopped || queue.paused || queue.songs[0] !== song || generation !== queue._preloadGeneration) {\n transitionStream.kill();\n return;\n }\n queue._crossfadeWarmup = transitionStream;\n // Pre-spawn: until the boundary, both inputs buffer into the stream so\n // the fade can begin without waiting for any network round-trip.\n transitionStream.spawn();\n\n const boundaryMs = Math.max(0, (songDuration - queue.currentTime - fade) * 1000);\n queue._crossfadeTimeout = setTimeout(() => {\n queue._crossfadeTimeout = undefined;\n void this.#crossfadeSwapTask(queue, transitionStream!);\n }, boundaryMs);\n queue._crossfadeTimeout.unref?.();\n } catch (e: unknown) {\n // Crossfade is best-effort: fall back to the regular song transition.\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[${queue.id}] Crossfade warmup failed, using the regular transition: ${errorMessage}`);\n if (transitionStream) transitionStream.kill();\n }\n }\n\n /**\n * Swap the playing stream for the merged transition stream and update the\n * queue as if the current song had just finished.\n */\n async #crossfadeSwapTask(queue: Queue, transitionStream: DisTubeStream) {\n const abort = () => {\n if (queue._crossfadeWarmup === transitionStream) queue._crossfadeWarmup = undefined;\n transitionStream.kill();\n };\n try {\n if (queue.stopped || queue.paused || queue._crossfadeWarmup !== transitionStream) return abort();\n const song = queue.songs[0];\n if (!song) return abort();\n const songDuration = song.duration ?? 0;\n const fade = Math.min(Number(queue.crossfade) || 0, songDuration);\n if (fade <= 0) return abort();\n // The playback position must be inside the fade window: on drift, fall\n // back to the regular transition instead of miscalibrated audio.\n const drift = queue.currentTime - (songDuration - fade);\n if (Math.abs(drift) > CROSSFADE_DRIFT_TOLERANCE_SECS) {\n this.debug(`[${queue.id}] Crossfade aborted: playback drifted ${drift.toFixed(2)}s from the fade boundary`);\n return abort();\n }\n\n await queue._taskQueue.queuing();\n try {\n if (queue.stopped || queue.paused || queue.songs[0] !== song || queue._crossfadeWarmup !== transitionStream) {\n return abort();\n }\n // Swapping in a stream that has not produced its first frame yet would\n // leave the player buffering until FFmpeg catches up, and the stuck\n // watchdog would skip the song on slow sources. Falling back to the\n // regular transition keeps the playback alive instead.\n if (!transitionStream.hasBufferedAudio) {\n this.debug(`[${queue.id}] Crossfade aborted: the transition stream is not ready`);\n return abort();\n }\n this.debug(`[${queue.id}] Starting crossfade: ${song} -> ${queue.songs.length > 1 ? queue.songs[1] : song}`);\n await queue.voice.play(transitionStream);\n queue._crossfadeWarmup = undefined;\n\n // Update the queue exactly like a regular song finish.\n this.emit(Events.FINISH_SONG, queue, song);\n if (queue.repeatMode === RepeatMode.QUEUE) queue.songs.push(song);\n if (queue.repeatMode !== RepeatMode.SONG) {\n const prev = queue.songs.shift() as Song;\n if (this.options.savePreviousSongs) queue.previousSongs.push(prev);\n else queue.previousSongs.push({ id: prev.id } as Song);\n } else {\n // Repeat-song fades into a fresh playback of the same song: the\n // plain preloaded stream (if any) is replaced by the transition.\n }\n if (song !== queue.songs[0]) {\n const playedSong = song.stream.playFromSource ? song : song.stream.song;\n if (playedSong?.stream.playFromSource) delete playedSong.stream.url;\n }\n // The transition stream replaces whatever plain stream was preloaded\n // for the next song: its url is still resolved, so kill quietly.\n if (queue._preloadedStream) {\n queue._preloadedStream.kill();\n queue._preloadedStream = undefined;\n queue._preloadedSong = undefined;\n }\n this.emit(Events.PLAY_SONG, queue, queue.songs[0]);\n this.schedulePreload(queue);\n this.scheduleCrossfade(queue);\n } finally {\n queue._taskQueue.resolve();\n }\n } catch (e: unknown) {\n abort();\n // Keep the fallback predictable: the old song keeps playing and the\n // regular transition takes over when it ends.\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[${queue.id}] Crossfade swap failed, using the regular transition: ${errorMessage}`);\n }\n }\n}\n","import { randomBytes } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { Readable } from \"node:stream\";\n\n/**\n * A request of the stream server.\n */\nexport interface StreamRequest {\n /**\n * The path after the source, e.g. `v/abc123`.\n */\n path: string;\n /**\n * The parsed query parameters.\n */\n query: URLSearchParams;\n /**\n * The byte offset the client asked for, or `0`.\n */\n offset: number;\n /**\n * Aborted when the client disconnects.\n */\n signal: AbortSignal;\n /**\n * The raw request.\n */\n request: IncomingMessage;\n}\n\n/**\n * The response of a stream handler.\n */\nexport interface StreamResponse {\n /**\n * The audio bytes.\n */\n body: Readable | AsyncIterable<Uint8Array>;\n /**\n * The content type. Default: `application/octet-stream`.\n */\n contentType?: string;\n /**\n * The status code. Default: `200`.\n */\n status?: number;\n /**\n * The total size of the stream, when it is known.\n *\n * It is required to answer the range requests.\n */\n size?: number;\n /**\n * Extra headers.\n */\n headers?: Record<string, string | number>;\n}\n\n/**\n * The handler of a source.\n */\nexport type StreamHandler = (\n req: StreamRequest,\n) => Promise<StreamResponse | null | undefined> | StreamResponse | null | undefined;\n\n/**\n * A handle to release a resource.\n */\nexport interface Disposable {\n /**\n * Release the resource.\n * @returns Nothing\n */\n dispose(): void;\n}\n\n/**\n * Options of the stream server.\n */\nexport interface StreamServerOptions {\n /**\n * The port of the server. `0` (the default) lets the operating system pick a\n * free one, which is what a plugin should use: a fixed port makes the next\n * instance fail with `EADDRINUSE`.\n */\n port?: number;\n /**\n * The prefix of the URLs. A random one is generated by default, so the other\n * local processes cannot guess them.\n */\n prefix?: string;\n}\n\nconst parseRange = (header: string | undefined): number => {\n if (!header) return 0;\n const match = /^bytes=(\\d+)-/u.exec(header);\n return match ? Number(match[1]) : 0;\n};\n\n/**\n * A local HTTP server that the plugins use to stream the audio.\n *\n * Every plugin that cannot hand out a static URL to FFmpeg needs an HTTP\n * server: a source that has to be decrypted, captured or negotiated cannot be\n * fetched by FFmpeg directly. Instead of every plugin running its own server,\n * they register a handler on this one.\n *\n * The server is started on the first registration and it is closed by\n * {@link DisTube#destroy}.\n */\nexport class StreamServer {\n readonly #handlers = new Map<string, StreamHandler>();\n readonly #port: number;\n readonly #prefix: string;\n #server?: Server;\n #ready?: Promise<void>;\n #boundPort?: number;\n #closed = false;\n /**\n * Create a stream server.\n * @param options - Optional options\n */\n constructor({ port = 0, prefix }: StreamServerOptions = {}) {\n this.#port = port;\n this.#prefix = prefix ?? randomBytes(8).toString(\"hex\");\n }\n /**\n * The prefix of the URLs of the server.\n */\n get prefix(): string {\n return this.#prefix;\n }\n /**\n * The base URL of the server, e.g. `http://127.0.0.1:51234`.\n *\n * @throws When the server is not started yet.\n */\n get baseUrl(): string {\n if (!this.#boundPort) throw new Error(\"The stream server is not started yet.\");\n return `http://127.0.0.1:${this.#boundPort}`;\n }\n /**\n * Register a source.\n *\n * The handler is called for every request of that source. Return `null` to\n * answer a `404`.\n * @param source - The identifier of the source\n * @param handler - The handler of the source\n * @returns A handle to unregister the source\n * @example\n * ```ts\n * const disposable = distube.streams.register(\"my-source\", async req => ({\n * body: Readable.from(Buffer.from(\"audio\")),\n * contentType: \"audio/mpeg\",\n * }));\n * ```\n */\n register(source: string, handler: StreamHandler): Disposable {\n const key = source.toLowerCase();\n this.#handlers.set(key, handler);\n void this.#start();\n return {\n dispose: () => {\n if (this.#handlers.get(key) === handler) this.#handlers.delete(key);\n },\n };\n }\n /**\n * Build the URL of a stream.\n *\n * The server is started when it is not running yet.\n * @param source - The identifier of the source\n * @param path - The path after the source\n * @param query - The query parameters\n * @returns The URL of the stream\n * @example\n * ```ts\n * const url = await distube.streams.url(\"my-source\", \"abc123\", { token: \"secret\" });\n * ```\n */\n async url(source: string, path?: string, query?: Record<string, string | number | boolean>): Promise<string> {\n await this.#start();\n const url = new URL(`${this.baseUrl}/${this.#prefix}/${source.toLowerCase()}`);\n if (path) url.pathname = `${url.pathname}/${path.replace(/^\\/+/u, \"\")}`;\n for (const [key, value] of Object.entries(query ?? {})) url.searchParams.set(key, String(value));\n return url.toString();\n }\n /**\n * Close the server and release every handler.\n * @returns A promise that resolves when the server is closed\n */\n async close(): Promise<void> {\n this.#closed = true;\n this.#handlers.clear();\n const server = this.#server;\n this.#server = undefined;\n this.#ready = undefined;\n this.#boundPort = undefined;\n if (!server) return;\n await new Promise<void>(resolve => server.close(() => resolve()));\n }\n async #start(): Promise<void> {\n if (this.#closed) throw new Error(\"The stream server is closed.\");\n if (!this.#ready) {\n this.#ready = new Promise<void>((resolve, reject) => {\n const server = createServer((req, res) => void this.#handle(req, res));\n server.once(\"error\", reject);\n server.listen(this.#port, \"127.0.0.1\", () => {\n const address = server.address();\n this.#boundPort = typeof address === \"object\" && address ? address.port : this.#port;\n this.#server = server;\n // The server must not keep the process alive.\n server.unref?.();\n resolve();\n });\n });\n }\n return this.#ready;\n }\n async #handle(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const controller = new AbortController();\n req.on(\"close\", () => controller.abort());\n try {\n const requestUrl = new URL(req.url ?? \"/\", \"http://127.0.0.1\");\n const segments = requestUrl.pathname.split(\"/\").filter(Boolean);\n if (segments[0] !== this.#prefix) {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" }).end(\"Not Found\");\n return;\n }\n const handler = this.#handlers.get((segments[1] ?? \"\").toLowerCase());\n if (!handler) {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" }).end(\"Not Found\");\n return;\n }\n const result = await handler({\n path: segments.slice(2).join(\"/\"),\n query: requestUrl.searchParams,\n offset: parseRange(req.headers.range),\n signal: controller.signal,\n request: req,\n });\n if (!result) {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" }).end(\"Not Found\");\n return;\n }\n const headers: Record<string, string | number> = {\n \"Content-Type\": result.contentType ?? \"application/octet-stream\",\n ...result.headers,\n };\n if (result.size !== undefined) headers[\"Accept-Ranges\"] = \"bytes\";\n if (result.size !== undefined && result.size > 0) {\n const offset = Math.min(parseRange(req.headers.range), Math.max(result.size - 1, 0));\n if (offset > 0) {\n headers[\"Content-Range\"] = `bytes ${offset}-${result.size - 1}/${result.size}`;\n res.writeHead(206, headers);\n } else {\n res.writeHead(result.status ?? 200, headers);\n }\n } else {\n res.writeHead(result.status ?? 200, headers);\n }\n const body = result.body instanceof Readable ? result.body : Readable.from(result.body);\n body.on(\"error\", () => res.end());\n body.pipe(res);\n } catch {\n if (!res.headersSent) res.writeHead(500, { \"Content-Type\": \"text/plain\" });\n res.end();\n }\n }\n}\n","import type { Client, VoiceBasedChannel } from \"discord.js\";\nimport { TypedEmitter } from \"tiny-typed-emitter\";\nimport { defaultFilters, version } from \"./constant\";\nimport { DisTubeHandler } from \"./core/DisTubeHandler\";\nimport { Options } from \"./core/DisTubeOptions\";\nimport { DisTubeVoiceManager } from \"./core/manager/DisTubeVoiceManager\";\nimport { QueueManager } from \"./core/manager/QueueManager\";\nimport { StreamServer } from \"./core/StreamServer\";\nimport { DisTubeError } from \"./struct/DisTubeError\";\nimport type { ExtractorPlugin } from \"./struct/ExtractorPlugin\";\nimport { Playlist } from \"./struct/Playlist\";\nimport type { Queue } from \"./struct/Queue\";\nimport { SearchResult } from \"./struct/SearchResult\";\nimport { Song } from \"./struct/Song\";\nimport type {\n Awaitable,\n CustomPlaylistOptions,\n DisTubeOptions,\n DisTubePlugin,\n Filters,\n GuildIdResolvable,\n PlayOptions,\n SearchOptions,\n TypedDisTubeEvents,\n} from \"./type\";\nimport { Events } from \"./type\";\nimport {\n checkIntents,\n handleUnhandledError,\n isClientInstance,\n isMemberInstance,\n isMessageInstance,\n isNsfwChannel,\n isObject,\n isSupportedVoiceChannel,\n isTextChannelInstance,\n isURL,\n} from \"./util\";\n\n/**\n * DisTube class\n */\nexport class DisTube extends TypedEmitter<TypedDisTubeEvents> {\n /**\n * @event\n * Emitted after DisTube add a new playlist to the playing {@link Queue}.\n * @param queue - The guild queue\n * @param playlist - Playlist info\n */\n static readonly [Events.ADD_LIST]: (queue: Queue, playlist: Playlist) => Awaitable;\n /**\n * @event\n * Emitted after DisTube add a new song to the playing {@link Queue}.\n * @param queue - The guild queue\n * @param song - Added song\n */\n static readonly [Events.ADD_SONG]: (queue: Queue, song: Song) => Awaitable;\n /**\n * @event\n * Emitted when the {@link Queue} is deleted with any reasons.\n * @param queue - The guild queue\n */\n static readonly [Events.DELETE_QUEUE]: (queue: Queue) => Awaitable;\n /**\n * @event\n * Emitted when the bot is disconnected to a voice channel.\n * @param queue - The guild queue\n */\n static readonly [Events.DISCONNECT]: (queue: Queue) => Awaitable;\n /**\n * @event\n * Emitted when the {@link Queue} runs out of songs to play.\n * @param queue - The guild queue\n */\n static readonly [Events.EMPTY]: (queue: Queue) => Awaitable;\n /**\n * @event\n * Emitted when DisTube encounters an error while playing songs.\n * @param error - error\n * @param queue - The queue encountered the error\n * @param song - The playing song when encountered the error\n */\n static readonly [Events.ERROR]: (error: Error, queue: Queue, song?: Song) => Awaitable;\n /**\n * @event\n * Emitted for logging FFmpeg debug information.\n * @param debug - Debug message string.\n */\n static readonly [Events.FFMPEG_DEBUG]: (debug: string) => Awaitable;\n /**\n * @event\n * Emitted to provide debug information from DisTube's operation.\n * Useful for troubleshooting or logging purposes.\n *\n * @param debug - Debug message string.\n */\n static readonly [Events.DEBUG]: (debug: string) => Awaitable;\n /**\n * @event\n * Emitted when there is no more song in the queue and {@link Queue#autoplay} is `false`.\n * @param queue - The guild queue\n */\n static readonly [Events.FINISH]: (queue: Queue) => Awaitable;\n /**\n * @event\n * Emitted when DisTube finished a song.\n * @param queue - The guild queue\n * @param song - Finished song\n */\n static readonly [Events.FINISH_SONG]: (queue: Queue, song: Song) => Awaitable;\n /**\n * @event\n * Emitted when DisTube initialize a queue to change queue default properties.\n * @param queue - The guild queue\n */\n static readonly [Events.INIT_QUEUE]: (queue: Queue) => Awaitable;\n /**\n * @event\n * Emitted when {@link Queue#autoplay} is `true`, {@link Queue#songs} is empty, and\n * DisTube cannot find related songs to play.\n * @param queue - The guild queue\n * @param error - The error that occurred while looking for related songs\n */\n static readonly [Events.NO_RELATED]: (queue: Queue, error: DisTubeError) => Awaitable;\n /**\n * @event\n * Emitted when DisTube play a song.\n * If {@link DisTubeOptions}.emitNewSongOnly is `true`, this event is not emitted\n * when looping a song or next song is the previous one.\n * @param queue - The guild queue\n * @param song - Playing song\n */\n static readonly [Events.PLAY_SONG]: (queue: Queue, song: Song) => Awaitable;\n /**\n * DisTube internal handler\n */\n readonly handler: DisTubeHandler;\n /**\n * DisTube options\n */\n readonly options: Options;\n /**\n * Discord.js v14 client\n */\n readonly client: Client;\n /**\n * Queues manager\n */\n readonly queues: QueueManager;\n /**\n * DisTube voice connections manager\n */\n readonly voices: DisTubeVoiceManager;\n /**\n * DisTube plugins\n */\n readonly plugins: DisTubePlugin[];\n /**\n * The local HTTP server the plugins use to stream the audio.\n *\n * A plugin that cannot hand out a static URL to FFmpeg registers a handler on\n * it, instead of running its own server.\n */\n readonly streams: StreamServer;\n /**\n * DisTube ffmpeg audio filters\n */\n readonly filters: Filters;\n /**\n * Create a new DisTube class.\n * @throws {@link DisTubeError}\n * @param client - Discord.JS client\n * @param opts - Custom DisTube options\n * @example\n * ```ts\n * const distube = new DisTube(client, { nsfw: false });\n * ```\n */\n constructor(client: Client, opts: DisTubeOptions = {}) {\n super();\n // Do not limit the number of listeners: bots commonly register several\n // listeners for the same event (e.g. one per guild).\n this.setMaxListeners(0);\n if (!isClientInstance(client)) throw new DisTubeError(\"INVALID_TYPE\", \"Discord.Client\", client, \"client\");\n this.client = client;\n checkIntents(client.options);\n this.options = new Options(opts);\n this.voices = new DisTubeVoiceManager(this);\n this.handler = new DisTubeHandler(this);\n this.queues = new QueueManager(this);\n this.filters = { ...defaultFilters, ...this.options.customFilters };\n this.plugins = [...this.options.plugins];\n this.streams = new StreamServer();\n for (const p of this.plugins) {\n const result = p.init(this);\n // The plugins can do asynchronous work in their init. The rejection is\n // caught: an unhandled rejection would crash the whole process.\n if (result && typeof (result as Promise<void>).catch === \"function\") {\n (result as Promise<void>).catch((e: unknown) => {\n const error = e instanceof Error ? e : new Error(String(e));\n this.debug(`[DisTube] The plugin ${p.constructor.name} failed to initialize: ${error.message}`);\n process.emitWarning(`The plugin ${p.constructor.name} failed to initialize: ${error.message}`, {\n code: \"DIS_TUBE_PLUGIN_INIT_FAILED\",\n detail: error.stack ?? error.message,\n });\n });\n }\n }\n }\n\n /**\n * Create a DisTube instance and wait for the plugins to be initialized.\n *\n * Use it when a plugin does asynchronous work in its `init` method: the\n * constructor cannot await it.\n * @param client - The Discord.js client\n * @param opts - Optional options\n * @returns The DisTube instance\n * @example\n * ```ts\n * const distube = await DisTube.create(client, { plugins: [new MyPlugin()] });\n * ```\n */\n static async create(client: Client, opts: DisTubeOptions = {}): Promise<DisTube> {\n const distube = new DisTube(client, opts);\n await Promise.all(\n distube.plugins.map(async plugin => {\n try {\n await plugin.init(distube);\n } catch (e: unknown) {\n const error = e instanceof Error ? e : new Error(String(e));\n distube.debug(`[DisTube] The plugin ${plugin.constructor.name} failed to initialize: ${error.message}`);\n process.emitWarning(`The plugin ${plugin.constructor.name} failed to initialize: ${error.message}`, {\n code: \"DIS_TUBE_PLUGIN_INIT_FAILED\",\n detail: error.stack ?? error.message,\n });\n }\n }),\n );\n return distube;\n }\n\n /**\n * Emit an event of the DisTube instance.\n *\n * The special {@link Events.ERROR} event is handled differently than the other\n * events: Node.js throws an `ERR_UNHANDLED_ERROR` when the special `\"error\"`\n * event is emitted without any listener, which crashes the whole process.\n *\n * Instead of crashing, DisTube follows {@link DisTubeOptions.unhandledError}\n * (`\"log\"` by default).\n * @param event - The event name\n * @param args - The event arguments\n * @returns `true` when the event had listeners, `false` otherwise\n */\n override emit<U extends keyof TypedDisTubeEvents>(event: U, ...args: Parameters<TypedDisTubeEvents[U]>): boolean {\n if (event === Events.ERROR && this.listenerCount(Events.ERROR) === 0) {\n this.#handleUnhandledError(args[0] as Error);\n return false;\n }\n return super.emit(event, ...args);\n }\n\n /**\n * Handle an {@link Events.ERROR} event that has no listener.\n * @param error - The error\n */\n #handleUnhandledError(error: Error) {\n handleUnhandledError(error, this.options?.unhandledError ?? \"log\");\n }\n\n /**\n * DisTube version\n */\n static get version() {\n return version;\n }\n\n /**\n * DisTube version\n */\n get version() {\n return version;\n }\n\n /**\n * Play / add a song or playlist from url.\n * Search and play a song (with {@link ExtractorPlugin}) if it is not a valid url.\n * @throws {@link DisTubeError}\n * @param voiceChannel - The channel will be joined if the bot isn't in any channels, the bot will be\n * moved to this channel if {@link DisTubeOptions}.joinNewVoiceChannel is `true`\n * @param song - URL | Search string | {@link Song} | {@link Playlist}\n * @param options - Optional options\n * @returns A promise that resolves when the song is added to the queue\n * @example\n * ```ts\n * await distube.play(channel, \"Never gonna give you up\", { message });\n * ```\n */\n async play<T = unknown>(\n voiceChannel: VoiceBasedChannel,\n song: string | Song | Playlist,\n options: PlayOptions<T> = {},\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, source } = {\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\n const queue = this.getQueue(voiceChannel) || (await this.queues.create(voiceChannel, textChannel));\n await queue._taskQueue.queuing(true);\n try {\n this.debug(`[${queue.id}] Playing input: ${song}`);\n const resolved = await this.handler.resolve(song, { member, metadata, source });\n const isNsfw = isNsfwChannel(queue?.textChannel || textChannel);\n const isFirstSong = queue.songs.length === 0;\n if (resolved instanceof Playlist) {\n if (!this.options.nsfw && !isNsfw) {\n resolved.songs = resolved.songs.filter(s => !s.ageRestricted);\n if (!resolved.songs.length) throw new DisTubeError(\"EMPTY_FILTERED_PLAYLIST\");\n }\n if (!resolved.songs.length) throw new DisTubeError(\"EMPTY_PLAYLIST\");\n this.debug(`[${queue.id}] Adding playlist to queue: ${resolved.songs.length} songs`);\n queue.addToQueue(resolved.songs, position);\n if (!isFirstSong || this.options.emitAddListWhenCreatingQueue) this.emit(Events.ADD_LIST, queue, resolved);\n } else {\n if (!this.options.nsfw && resolved.ageRestricted && !isNsfwChannel(queue?.textChannel || textChannel)) {\n throw new DisTubeError(\"NON_NSFW\");\n }\n this.debug(`[${queue.id}] Adding song to queue: ${resolved.name || resolved.url || resolved.id || resolved}`);\n queue.addToQueue(resolved, position);\n if (!isFirstSong || this.options.emitAddSongWhenCreatingQueue) this.emit(Events.ADD_SONG, queue, resolved);\n }\n\n if (isFirstSong) await queue.play();\n else if (skip) await queue.skip();\n } catch (e: unknown) {\n if (!(e instanceof DisTubeError)) {\n const errorMessage = e instanceof Error ? (e.stack ?? e.message) : String(e);\n this.debug(`[${queue.id}] Unexpected error while playing song: ${errorMessage}`);\n if (e instanceof Error) {\n try {\n e.name = \"PlayError\";\n e.message = `${typeof song === \"string\" ? song : song.url}\\n${e.message}`;\n } catch {\n // Some errors have read-only properties, throw original error\n }\n }\n }\n throw e;\n } finally {\n if (!queue.songs.length && !queue._taskQueue.hasPlayTask) queue.remove();\n queue._taskQueue.resolve();\n }\n }\n\n /**\n * Create a custom playlist\n * @param songs - Array of url or Song\n * @param options - Optional options\n * @returns The created playlist\n * @throws {@link DisTubeError} When the array is empty, or when it does not\n * have any valid song\n */\n async createCustomPlaylist(\n songs: (string | Song)[],\n { member, parallel, metadata, name, source, url, thumbnail }: CustomPlaylistOptions = {},\n ): Promise<Playlist> {\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(song => song instanceof Song || isURL(song));\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 let resolvedSongs: Song[];\n if (parallel !== false) {\n const promises = filteredSongs.map((song: string | Song) =>\n this.handler.resolve(song, { member, metadata }).catch(() => undefined),\n );\n resolvedSongs = (await Promise.all(promises)).filter((s): s is Song => s instanceof Song);\n } else {\n resolvedSongs = [];\n for (const song of filteredSongs) {\n const resolved = await this.handler.resolve(song, { member, metadata }).catch(() => undefined);\n if (resolved instanceof Song) resolvedSongs.push(resolved);\n }\n }\n return new Playlist(\n {\n source: source || \"custom\",\n name,\n url,\n thumbnail: thumbnail || resolvedSongs.find(s => s.thumbnail)?.thumbnail,\n songs: resolvedSongs,\n },\n { member, metadata },\n );\n }\n\n /**\n * Get the guild queue\n * @param guild - The type can be resolved to give a {@link Queue}\n * @returns The queue of the guild, or `undefined` when there is none\n * @example\n * ```ts\n * const queue = distube.getQueue(guildId);\n * ```\n */\n getQueue(guild: GuildIdResolvable): Queue | undefined {\n return this.queues.get(guild);\n }\n\n /**\n * Get a plugin by the identifier of its source.\n *\n * It matches the {@link Plugin.source} of the plugin, or one of its\n * {@link Plugin.aliases}. The identifier of the class is used when the\n * plugin does not define a source (`MyPlugin` -> `myplugin`).\n * @param source - The identifier of the source\n * @returns The plugin, or `undefined` when there is none\n * @example\n * ```ts\n * const plugin = distube.getPlugin(\"myplugin\");\n * ```\n */\n getPlugin(source: string): DisTubePlugin | undefined {\n if (typeof source !== \"string\" || !source) return undefined;\n const identifier = source.toLowerCase();\n return this.plugins.find(plugin => plugin.identifiers.includes(identifier));\n }\n\n /**\n * Search for the songs of the plugins.\n *\n * The plugins are used in the order they were registered. When\n * {@link ResolveOptions.source} is given, only the matching plugin is used.\n * @param query - The search query\n * @param options - Optional options\n * @returns The result of the search\n * @example\n * ```ts\n * const result = await distube.search(\"Never gonna give you up\", { limit: 5 });\n * ```\n */\n async search<T = unknown>(query: string, options: SearchOptions<T> = {}): Promise<SearchResult<T>> {\n const limit = options.limit ?? 10;\n const plugins: DisTubePlugin[] = options.source\n ? [this.getPlugin(options.source)].filter((plugin): plugin is DisTubePlugin => Boolean(plugin))\n : this.plugins;\n\n const songs: Song<T>[] = [];\n const sources: string[] = [];\n let playlist: Playlist<T> | undefined;\n\n for (const plugin of plugins) {\n if (songs.length >= limit) break;\n const found = await plugin.search<T>(query, { ...options, limit: limit - songs.length });\n if (!found) continue;\n if (found.songs.length) {\n songs.push(...found.songs);\n sources.push(plugin.identifiers[0] ?? plugin.constructor.name);\n }\n playlist ??= found.playlist;\n }\n\n return new SearchResult<T>(query, {\n songs: songs.slice(0, limit),\n playlist,\n queryType: options.type,\n sources,\n });\n }\n\n /**\n /**\n /**\n /**\n * Emit error event\n * @param error - error\n * @param queue - The queue encountered the error\n * @param song - The playing song when encountered the error\n * @returns Nothing\n */\n emitError(error: Error, queue: Queue, song?: Song): void {\n this.emit(Events.ERROR, error, queue, song);\n }\n\n /**\n * Emit debug event\n * @param message - debug message\n * @returns Nothing\n */\n debug(message: string) {\n this.emit(Events.DEBUG, message);\n }\n\n /**\n * Destroy the DisTube instance.\n *\n * Stops every queue, leaves every voice channel, destroys every plugin and\n * removes every listener.\n * Call it before your Discord.js client is destroyed to release all resources.\n * @returns A promise that resolves when every resource is released\n * @example\n * ```ts\n * await distube.destroy();\n * ```\n */\n async destroy(): Promise<void> {\n this.debug(\"[DisTube] Destroying the DisTube instance...\");\n const queues = [...this.queues.collection.values()];\n for (const queue of queues) {\n try {\n await queue.stop();\n } catch (e: unknown) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[DisTube] Failed to stop the queue ${queue.id}: ${errorMessage}`);\n }\n }\n const voices = [...this.voices.collection.values()];\n for (const voice of voices) {\n try {\n voice.leave();\n } catch (e: unknown) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[DisTube] Failed to leave the voice connection ${voice.id}: ${errorMessage}`);\n }\n }\n for (const plugin of this.plugins) {\n try {\n await plugin.destroy();\n } catch (e: unknown) {\n const errorMessage = e instanceof Error ? e.message : String(e);\n this.debug(`[DisTube] Failed to destroy the plugin ${plugin.constructor.name}: ${errorMessage}`);\n }\n }\n await this.streams.close();\n this.removeAllListeners();\n }\n}\n\nexport default DisTube;\n","import { SearchResultType } from \"../type\";\nimport type { Playlist } from \"./Playlist\";\nimport type { Song } from \"./Song\";\n\n/**\n * The result of a search.\n *\n * It is the result type of every search, at the plugin level and at the\n * DisTube level.\n */\nexport class SearchResult<T = unknown> {\n /**\n * The query of the search.\n */\n readonly query: string;\n /**\n * The kind of result that was looked for.\n */\n readonly queryType: SearchResultType;\n /**\n * The songs that were found.\n */\n readonly songs: Song<T>[];\n /**\n * The playlist that was found, when the search returned one.\n */\n readonly playlist?: Playlist<T>;\n /**\n * The identifiers of the plugins that contributed to the result.\n */\n readonly sources: string[];\n /**\n * Create a search result.\n * @param query - The query of the search\n * @param options - Optional data\n * @param options.songs - The songs that were found\n * @param options.playlist - The playlist that was found\n * @param options.queryType - The kind of result that was looked for\n * @param options.sources - The identifiers of the plugins that contributed\n * to the result\n * @example\n * ```ts\n * const result = new SearchResult(\"Never gonna give you up\", { songs: [song] });\n * ```\n */\n constructor(\n query: string,\n {\n songs = [],\n playlist,\n queryType,\n sources = [],\n }: {\n songs?: Song<T>[];\n playlist?: Playlist<T>;\n queryType?: SearchResultType;\n sources?: string[];\n } = {},\n ) {\n this.query = query;\n this.songs = songs;\n this.playlist = playlist;\n this.queryType = queryType ?? SearchResultType.TRACK;\n this.sources = sources;\n }\n /**\n * Whether the search returned nothing.\n * @returns `true` when the result has neither songs nor a playlist\n */\n isEmpty(): boolean {\n return this.songs.length === 0 && !this.playlist;\n }\n /**\n * Whether the search returned songs.\n * @returns `true` when the result has at least one song\n */\n hasSongs(): boolean {\n return this.songs.length > 0;\n }\n /**\n * Whether the search returned a playlist.\n * @returns `true` when the result has a playlist\n */\n hasPlaylist(): boolean {\n return Boolean(this.playlist);\n }\n /**\n * A plain object representation of the result.\n * @returns The plain object representation of the result\n */\n toJSON(): object {\n return {\n query: this.query,\n queryType: this.queryType,\n sources: [...this.sources],\n songs: this.songs.map(song => ({\n id: song.id,\n name: song.name,\n url: song.url,\n duration: song.duration,\n formattedDuration: song.formattedDuration,\n thumbnail: song.thumbnail,\n source: song.source,\n uploader: song.uploader,\n })),\n playlist: this.playlist\n ? {\n id: this.playlist.id,\n name: this.playlist.name,\n url: this.playlist.url,\n thumbnail: this.playlist.thumbnail,\n songs: this.playlist.songs.length,\n }\n : undefined,\n };\n }\n}\n","import type { StreamServer } from \"../core/StreamServer\";\nimport type { DisTube } from \"../DisTube\";\nimport type { Awaitable, PluginType, ResolveOptions, SearchOptions } from \"../type\";\nimport { SearchResult } from \"./SearchResult\";\nimport type { Song } from \"./Song\";\n\n/**\n * DisTube Plugin\n */\nexport abstract class Plugin {\n /**\n * Type of the plugin\n */\n abstract readonly type: PluginType;\n /**\n * The identifier of the source of the plugin.\n *\n * It defaults to the name of the class, lowercased, without the `Plugin`\n * suffix (`MyPlugin` -> `myplugin`).\n *\n * It is used to route a search to a plugin, and to find a plugin with\n * {@link DisTube#getPlugin}.\n */\n readonly source?: string;\n /**\n * Additional identifiers of the source of the plugin, e.g. `[\"yt\"]`.\n */\n readonly aliases?: string[];\n /**\n * Whether the songs of this plugin can be played directly.\n *\n * When it is `false`, the songs of the plugin are resolved to a playable\n * version by another plugin. It defaults to `true`.\n */\n readonly playable?: boolean;\n /**\n * DisTube\n */\n distube!: DisTube;\n /**\n * Initialize the plugin.\n *\n * It can be asynchronous: use {@link DisTube.create} to wait for the\n * initialization of the plugins.\n * @param distube - The DisTube instance\n * @returns Nothing, or a promise that resolves when the plugin is initialized\n * @example\n * ```ts\n * override async init(distube: DisTube) {\n * this.client = await createSession();\n * }\n * ```\n */\n init(distube: DisTube): void | Promise<void> {\n this.distube = distube;\n }\n /**\n * Every identifier of this plugin: its {@link Plugin.source} and its\n * {@link Plugin.aliases}, lowercased.\n *\n * The static properties of the class are used when the instance ones are not\n * defined, so a plugin can declare them either way.\n */\n get identifiers(): string[] {\n const names = new Set<string>();\n const ctor = this.constructor as { source?: string; aliases?: string[] };\n const source = this.source ?? ctor.source ?? this.constructor.name.replace(/Plugin$/iu, \"\");\n if (source) names.add(source.toLowerCase());\n for (const alias of this.aliases ?? ctor.aliases ?? []) {\n if (typeof alias === \"string\" && alias) names.add(alias.toLowerCase());\n }\n return [...names];\n }\n /**\n * The local HTTP server of the DisTube instance.\n *\n * Register a handler on it when the plugin cannot hand out a static URL to\n * FFmpeg, instead of running its own server.\n */\n get streams(): StreamServer {\n return this.distube.streams;\n }\n /**\n * Search for a song of the source.\n *\n * Override it to enable the search of your source. It returns `null` by\n * default, because a source that cannot be searched does not have any result.\n * @param _query - Search query\n * @param _options - Optional options\n * @returns The song that was found, or `null`\n * @example\n * ```ts\n * override async searchSong(query: string): Promise<Song | null> {\n * return findSong(query);\n * }\n * ```\n */\n searchSong<T>(_query: string, _options: ResolveOptions<T>): Awaitable<Song<T> | null> {\n return null;\n }\n /**\n * Search for the songs of the source.\n *\n * The default implementation returns the single result of\n * {@link Plugin#searchSong}. Override it to return more results, or to return\n * a playlist.\n * @param query - Search query\n * @param options - Optional options\n * @returns The result of the search\n * @example\n * ```ts\n * const result = await plugin.search(\"Never gonna give you up\", { limit: 5 });\n * ```\n */\n async search<T>(query: string, options: SearchOptions<T> = {}): Promise<SearchResult<T>> {\n const song = await this.searchSong(query, options);\n return new SearchResult<T>(query, {\n songs: song ? [song] : [],\n queryType: options.type,\n });\n }\n /**\n * Create the query used to find a playable version of a song.\n *\n * It is used when the plugin cannot play the songs it resolves.\n * @param song - Input song\n * @returns The search query\n * @example\n * ```ts\n * override createSearchQuery(song: Song): string {\n * return `${song.name} ${song.uploader?.name}`;\n * }\n * ```\n */\n createSearchQuery<T>(song: Song<T>): Awaitable<string> {\n return `${song.name ?? \"\"} ${song.uploader?.name ?? \"\"}`.trim();\n }\n /**\n * Get related songs from a supported url.\n *\n * Override it to enable the autoplay for your source. Return an empty array\n * when your source does not have any related songs.\n * @param _song - Input song\n * @returns The related songs\n */\n getRelatedSongs(_song: Song): Awaitable<Song[]> {\n return [];\n }\n /**\n * Destroy the plugin.\n *\n * It is called when the {@link DisTube} instance is destroyed. Override it to\n * release every resource held by the plugin (HTTP servers, timers, browser\n * sessions, ...).\n * @returns Nothing, or a promise that resolves when the plugin is destroyed\n */\n destroy(): void | Promise<void> {\n // Nothing to destroy by default\n }\n}\n","import type { Awaitable, ResolveOptions } from \"../type\";\nimport { PluginType } from \"../type\";\nimport type { Playlist } from \"./Playlist\";\nimport { Plugin } from \"./Plugin\";\nimport type { Song } from \"./Song\";\n\n/**\n * This plugin can extract the info, search, and play a song directly from its source\n */\nexport abstract class ExtractorPlugin extends Plugin {\n /**\n * The type of the plugin.\n */\n override readonly type: PluginType = PluginType.EXTRACTOR;\n /**\n * Check if the url is working with this plugin\n * @param url - Input url\n * @returns `true` when the plugin can handle the url\n */\n abstract validate(url: string): Awaitable<boolean>;\n /**\n * Resolve the validated url to a {@link Song} or a {@link Playlist}.\n * @param url - URL\n * @param options - Optional options\n * @returns The resolved song or playlist\n */\n abstract resolve<T>(url: string, options: ResolveOptions<T>): Awaitable<Song<T> | Playlist<T>>;\n /**\n * Get the stream url from {@link Song#url}. Returns {@link Song#url} by default.\n * Not needed if the plugin plays the song itself.\n * @param song - Input song\n * @returns The url of the audio stream\n */\n abstract getStreamURL<T>(song: Song<T>): Awaitable<string>;\n}\n","import { DisTubeError } from \"./DisTubeError\";\n\n/**\n * The error codes a plugin can raise.\n */\nexport enum PluginErrorCode {\n /**\n * The URL is not supported by the plugin.\n */\n UNSUPPORTED_URL = \"UNSUPPORTED_URL\",\n /**\n * The song, the playlist or the album was not found.\n */\n NOT_FOUND = \"NOT_FOUND\",\n /**\n * The plugin could not get a playable stream for the song.\n */\n NO_STREAM = \"NO_STREAM\",\n /**\n * The source is temporarily unavailable: rate limit, server error or network\n * failure.\n */\n SOURCE_UNAVAILABLE = \"SOURCE_UNAVAILABLE\",\n /**\n * The content is age-restricted.\n */\n AGE_RESTRICTED = \"AGE_RESTRICTED\",\n}\n\nconst DEFAULT_MESSAGES: Record<PluginErrorCode, string> = {\n [PluginErrorCode.UNSUPPORTED_URL]: \"This URL is not supported by the plugin\",\n [PluginErrorCode.NOT_FOUND]: \"The song was not found\",\n [PluginErrorCode.NO_STREAM]: \"No playable stream was found for the song\",\n [PluginErrorCode.SOURCE_UNAVAILABLE]: \"The source is temporarily unavailable\",\n [PluginErrorCode.AGE_RESTRICTED]: \"The content is age-restricted\",\n};\n\n/**\n * The error raised by a plugin.\n *\n * It extends {@link DisTubeError}, so the code of the error is available with\n * `error.errorCode` and the error can be caught with `instanceof DisTubeError`.\n */\nexport class PluginError<T extends PluginErrorCode = PluginErrorCode> extends DisTubeError<T> {\n /**\n * Create a plugin error.\n * @param code - The error code\n * @param message - The message. It defaults to the one of the error code.\n * @param options - Optional options\n * @param options.cause - The original error that caused this one\n * @example\n * ```ts\n * throw new PluginError(PluginErrorCode.NOT_FOUND);\n * ```\n */\n constructor(code: T, message?: string, options?: { cause?: unknown }) {\n super(code, message ?? DEFAULT_MESSAGES[code]);\n if (options && \"cause\" in options) this.cause = options.cause;\n }\n /**\n * The name of the error, with its code.\n * @returns The name of the error, e.g. `PluginError [NOT_FOUND]`\n */\n override get name() {\n return `PluginError [${this.errorCode}]`;\n }\n}\n","import type { Awaitable, ResolveOptions } from \"../type\";\nimport { PluginType } from \"../type\";\nimport { ExtractorPlugin } from \"./ExtractorPlugin\";\nimport type { Playlist } from \"./Playlist\";\nimport { PluginError, PluginErrorCode } from \"./PluginError\";\nimport type { Song } from \"./Song\";\n\n/**\n * This plugin only can extract the info from supported links, but not play song directly from its source\n *\n * @deprecated Use {@link ExtractorPlugin} with `playable: false` instead.\n */\nexport abstract class InfoExtractorPlugin extends ExtractorPlugin {\n /**\n * The type of the plugin.\n */\n override readonly type: PluginType = PluginType.INFO_EXTRACTOR;\n /**\n * The songs of this plugin are resolved to a playable version by another\n * plugin.\n */\n override readonly playable = false;\n /**\n * Check if the url is working with this plugin\n * @param url - Input url\n * @returns `true` when the plugin can handle the url\n */\n abstract override validate(url: string): Awaitable<boolean>;\n /**\n * Resolve the validated url to a {@link Song} or a {@link Playlist}.\n * @param url - URL\n * @param options - Optional options\n * @returns The resolved song or playlist\n */\n abstract override resolve<T>(url: string, options: ResolveOptions<T>): Awaitable<Song<T> | Playlist<T>>;\n\n /**\n * Create a search query to be used in {@link ExtractorPlugin#searchSong}\n * @param song - Input song\n * @returns The search query\n */\n abstract override createSearchQuery<T>(song: Song<T>): Awaitable<string>;\n\n /**\n * This plugin cannot play the songs it resolves, so it never has a stream url.\n * @param _song - Input song\n * @returns Nothing: it always throws\n * @throws {@link PluginError} Always, with the code `NO_STREAM`\n */\n override async getStreamURL<T>(_song: Song<T>): Promise<string> {\n throw new PluginError(PluginErrorCode.NO_STREAM);\n }\n}\n","import type { Awaitable, ResolveOptions } from \"../type\";\nimport { PluginType } from \"../type\";\nimport { ExtractorPlugin } from \"./ExtractorPlugin\";\nimport type { Playlist } from \"./Playlist\";\nimport type { Song } from \"./Song\";\n\n/**\n * This plugin can extract and play song from supported links, but cannot search for songs from its source\n */\nexport abstract class PlayableExtractorPlugin extends ExtractorPlugin {\n /**\n * The type of the plugin.\n */\n override readonly type: PluginType = PluginType.PLAYABLE_EXTRACTOR;\n /**\n * Check if the url is working with this plugin\n * @param url - Input url\n * @returns `true` when the plugin can handle the url\n */\n abstract override validate(url: string): Awaitable<boolean>;\n /**\n * Resolve the validated url to a {@link Song} or a {@link Playlist}.\n * @param url - URL\n * @param options - Optional options\n * @returns The resolved song or playlist\n */\n abstract override resolve<T>(url: string, options: ResolveOptions<T>): Awaitable<Song<T> | Playlist<T>>;\n /**\n * Get the stream url from {@link Song#url}. Returns {@link Song#url} by default.\n * Not needed if the plugin plays the song itself.\n * @param song - Input song\n * @returns The url of the audio stream\n */\n abstract override getStreamURL<T>(song: Song<T>): Awaitable<string>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACOO,IAAM,UAAkB;AAKxB,IAAM,oBAAoB;AAI1B,IAAM,iBAAiB;AAKvB,IAAM,iBAAiB;AAKvB,IAAM,kBAAkB;AAIxB,IAAM,uBAAuB;AAI7B,IAAM,yBAAyB;AAM/B,IAAM,qBAAqB;AAK3B,IAAM,sBAAsB,oBAAI,IAAI,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG,CAAC;AAI7D,IAAM,qBAAqB;AAK3B,IAAM,iBAA0B;AAAA,EACrC,MAAM;AAAA,EACN,WAAW;AAAA,EACX,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,WAAW;AAAA,EACX,SAAS;AAAA,EACT,WAAW;AAAA,EACX,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AACV;AAKO,IAAM,iCAAiC;AAKvC,IAAM,kCAAkC;AAIxC,IAAM,8BAA8B;AAOpC,IAAM,0BAA0B;AAKhC,IAAM,gCAAgC;AAMtC,IAAM,iCAAiC;AAQvC,IAAM,iBAAiB;AAAA,EAC5B,SAAS,CAAC;AAAA,EACV,iBAAiB;AAAA,EACjB,mBAAmB;AAAA,EACnB,MAAM;AAAA,EACN,8BAA8B;AAAA,EAC9B,8BAA8B;AAAA,EAC9B,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,SAAS;AAAA,EACT,WAAW;AAAA,IACT,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AACF;;;AChHO,IAAe,cAAf,MAA2B;AAAA,EAdlC,OAckC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAIhC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,SAAkB;AAC5B,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KAAK,cAAmC,MAAoB;AAC1D,WAAO,KAAK,QAAQ,KAAK,WAAW,GAAG,IAAI;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,OAAc,OAAc,MAAa;AACjD,SAAK,QAAQ,UAAU,OAAO,OAAO,IAAI;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,SAAiB;AACrB,SAAK,QAAQ,MAAM,OAAO;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,SAAuB;AACzB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,SAA8B;AAChC,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,SAAiB;AACnB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,UAAmB;AACrB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,UAA0B;AAC5B,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,UAA2B;AAC7B,WAAO,KAAK,QAAQ;AAAA,EACtB;AACF;;;ACzFA,oBAAwB;;;ACAxB,uBAAwB;AAQxB,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrB,cAAc,wBAAC,UAA4D,KAAU,SACnF,YACE,MAAM,QAAQ,QAAQ,IAAI,SAAS,IAAI,OAAM,OAAO,MAAM,WAAW,IAAI,IAAI,CAAC,GAAI,EAAE,KAAK,MAAM,IAAI,IAAI,QAAQ,GACjH,GAAG,OAAO,SAAS,IAAI,MAAM,EAAE,iBAAa,0BAAQ,GAAG,CAAC,KAAK,OAAO,GAAG,KAH3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUd,gBAAgB,wBAAC,MAAc,UAAkB,UAAkB,IAAI,IAAI,aAAa,QAAQ,IAAI,KAAK,IAAzF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhB,aAAa,wBAAC,SAAiB,IAAI,IAAI,uBAA1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOb,sBAAsB,wBAAC,MAAc,SAAiB,sBAAsB,IAAI,aAAa,IAAI,WAA3E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMtB,cAAc,wBAAC,SAAiB,IAAI,IAAI,8BAA1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOd,aAAa,wBAAC,KAAa,QAAgB,IAAI,GAAG,qCAAqC,GAAG,IAA7E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMb,aAAa,wBAAC,KAAa,QAAgB,IAAI,GAAG,6BAA6B,GAAG,IAArE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMb,cAAc,wBAAC,KAAa,KAAe,QACzC,GAAG,IAAI,IAAI,OAAK,IAAI,CAAC,GAAG,EAAE,KAAK,MAAM,UAAU,MAAM,CAAC,2BAA2B,GAAG,IADxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASd,iBAAiB,wBAAC,MAAc,GAAG,CAAC,2CAAnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjB,iBAAiB,wBAAC,MAAc,kBAAkB,CAAC,gBAAlC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,gBAAgB,wBAAC,MAAc,kBAAkB,CAAC,eAAlC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOd,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOZ,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOvB,sBAAsB,wBAAC,MAAc,6CAA6C,CAAC,YAA7D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOtB,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrB,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOxB,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOvB,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQxB,eAAe,wBAAC,SAAiB,2BAA2B,IAAI,IAAjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOf,sBAAsB,wBAAC,SAAiB,+BAA+B,IAAI,UAArD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQtB,8BACE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASF,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOV,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOb,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMf,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOR,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOb,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOZ,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlB,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOjB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOb,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrB,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOZ,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrB,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnB,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOpB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOV,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnB,oBAAoB,wBAAC,SAAiB,4CAA4C,IAAI,KAAlE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQpB,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOf,qBAAqB,wBAAC,MAAW,sBAAkB,0BAAQ,CAAC,CAAC,cAAxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMrB,uBAAuB,wBAAC,SAAiB,yCAAyC,IAAI,KAA/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOvB,yBAAyB,wBAAC,SAAiB,2CAA2C,IAAI,KAAjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOzB,WAAW,wBAAC,UAAkB,yCAAyC,KAAK,KAAjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOX,eAAe,wBAAC,SAAiB,2BAA2B,IAAI,KAAjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQf,yBACE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOF,gBAAgB;AAClB;AAOA,IAAM,WAAW,wBAAC,SAAoC,OAAO,KAAK,cAAc,EAAE,SAAS,IAAI,GAA9E;AACjB,IAAM,eAAe,wBAAC,MAAwC,SAAe,OAAO,MAAM,WAAW,IAAI,EAAE,GAAG,IAAI,GAA7F;AACrB,IAAM,kBAAkB,wBAAC,SAAiB,SAAsB;AAC9D,MAAI,CAAC,SAAS,IAAI,EAAG,QAAO,KAAK,CAAC;AAClC,MAAI;AACF,WAAO,aAAa,eAAe,IAAI,GAAG,GAAG,IAAI;AAAA,EACnD,QAAQ;AAEN,WAAO,KAAK,CAAC,KAAK;AAAA,EACpB;AACF,GARwB;AA2BjB,IAAM,eAAN,MAAM,sBAA6C,MAAM;AAAA,EAtYhE,OAsYgE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAI9D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6BA,YAAY,SAAiB,MAAW;AACtC,UAAM,gBAAgB,MAAM,GAAG,IAAI,CAAC;AAEpC,SAAK,YAAY;AACjB,QAAI,MAAM,kBAAmB,OAAM,kBAAkB,MAAM,aAAY;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,OAAO,YAAoC,MAAS,SAAiB,SAAgD;AAEnH,UAAM,QAAQ,IAAK,KAAa,MAAM,OAAO;AAC7C,UAAM,UAAU;AAChB,QAAI,WAAW,WAAW,QAAS,OAAM,QAAQ,QAAQ;AACzD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAa,OAAO;AAClB,WAAO,iBAAiB,KAAK,SAAS;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,OAAO;AACT,WAAO,KAAK;AAAA,EACd;AACF;;;ACvdA,sBAAoB;AAYpB,IAAAA,kBAA6E;;;ACX7E,mBAOO;AAEP,qBAA0B;AAC1B,gCAA6B;AAWtB,IAAM,eAAN,cAA2B,uCAAiC;AAAA,EAtBnE,OAsBmE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAIxD;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA;AAAA;AAAA,EAIA,iBAAiB;AAAA;AAAA;AAAA;AAAA,EAIjB;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA,EACA;AAAA,EACA,UAAU;AAAA;AAAA;AAAA;AAAA,EAIV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,cAAmC,SAA4B;AACzE,UAAM;AACN,SAAK,SAAS;AACd,SAAK,KAAK,QAAQ;AAClB,SAAK,UAAU;AACf,SAAK,OAAO,IAAI,KAAK,IAAI,IAAI;AAC7B,SAAK,kBAAc,gCAAkB,EAClC,GAAG,+BAAkB,MAAM,cAAY;AACtC,WAAK,iBAAiB;AACtB,UAAI,SAAS,WAAW,+BAAkB,KAAM,MAAK,KAAK,QAAQ;AAAA,IACpE,CAAC,EACA,GAAG,+BAAkB,WAAW,MAAM;AACrC,WAAK,iBAAiB;AAAA,IACxB,CAAC,EACA,GAAG,+BAAkB,SAAS,MAAM;AACnC,WAAK,iBAAiB;AAAA,IACxB,CAAC,EACA,GAAG,SAAS,CAAC,UAAiC;AAC7C,UAAI,KAAK,aAAc;AACvB,WAAK,eAAe;AACpB,WAAK,KAAK,SAAS,KAAK;AAAA,IAC1B,CAAC;AACH,SAAK,WACF,GAAG,mCAAsB,cAAc,CAAC,GAAG,aAAa;AACvD,UAAI,SAAS,WAAW,6CAAgC,QAAQ;AAE9D,aAAK,MAAM;AAAA,MACb,WAAW,SAAS,WAAW,6CAAgC,kBAAkB,SAAS,cAAc,MAAM;AAE5G,sCAAY,KAAK,YAAY,mCAAsB,YAAY,oBAAoB,EAChF,KAAK,UAAM,0BAAY,KAAK,YAAY,mCAAsB,OAAO,oBAAoB,CAAC,EAC1F,KAAK,MAAM;AACV,gBAAM,aAAa,KAAK;AACxB,gBAAM,iBAAiB,KAAK;AAC5B,cAAI,cAAc,kBAAkB,WAAW,OAAO,eAAe,IAAI;AACvE,iBAAK,WAAW;AAChB,iBAAK,KAAK,iBAAiB,YAAY,cAAc;AAAA,UACvD;AAAA,QACF,CAAC,EACA,MAAM,MAAM;AACX,cACE,CAAC,CAAC,mCAAsB,OAAO,mCAAsB,UAAU,EAAE,SAAS,KAAK,WAAW,MAAM,MAAM,GACtG;AACA,iBAAK,MAAM;AAAA,UACb;AAAA,QACF,CAAC;AAAA,MACL,WAAW,KAAK,WAAW,iBAAiB,wBAAwB;AAElE;AAAA,UACE,MAAM;AACJ,iBAAK,WAAW,OAAO;AAAA,UACzB;AAAA,WACC,KAAK,WAAW,iBAAiB,KAAK;AAAA,QACzC,EAAE,MAAM;AAAA,MACV,WAAW,KAAK,WAAW,MAAM,WAAW,mCAAsB,WAAW;AAE3E,aAAK,MAAM,IAAI,aAAa,wBAAwB,CAAC;AAAA,MACvD;AAAA,IACF,CAAC,EACA,GAAG,mCAAsB,WAAW,MAAM;AACzC,WAAK,MAAM;AAAA,IACb,CAAC,EACA,GAAG,SAAS,MAAM,MAAS;AAC9B,SAAK,WAAW,UAAU,KAAK,WAAW;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,YAAY;AACd,WAAO,KAAK,YAAY,YAAY,aAAa;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,UAAU;AACZ,QAAI,CAAC,KAAK,UAAW,QAAO,KAAK;AACjC,QAAI,KAAK,UAAU,OAAO,KAAK,UAAW,QAAO,KAAK;AACtD,UAAM,UAAU,KAAK,OAAO,OAAO,SAAS,MAAM,IAAI,KAAK,SAAS;AACpE,QAAI,CAAC,QAAS,QAAO,KAAK;AAC1B,eAAW,QAAQ,yBAAU,wBAAwB;AACnD,UAAI,QAAQ,SAAS,MAAM;AACzB,aAAK,WAAW;AAChB,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,QAAQ,SAA4B;AACtC,QAAI,CAAC,wBAAwB,OAAO,GAAG;AACrC,YAAM,IAAI,aAAa,gBAAgB,yBAAyB,SAAS,sBAAsB;AAAA,IACjG;AACA,QAAI,QAAQ,YAAY,KAAK,GAAI,OAAM,IAAI,aAAa,uBAAuB;AAC/E,QAAI,QAAQ,OAAO,MAAM,OAAO,KAAK,OAAO,OAAO,MAAM,GAAI,OAAM,IAAI,aAAa,wBAAwB;AAC5G,QAAI,QAAQ,OAAO,KAAK,UAAW;AACnC,QAAI,CAAC,QAAQ,UAAU;AACrB,UAAI,QAAQ,KAAM,OAAM,IAAI,aAAa,YAAY;AAAA,UAChD,OAAM,IAAI,aAAa,qBAAqB;AAAA,IACnD;AACA,UAAM,aAAa,KAAK;AACxB,SAAK,aAAa,KAAK,MAAM,OAAO;AACpC,SAAK,WAAW;AAChB,QAAI,cAAc,WAAW,OAAO,QAAQ,IAAI;AAC9C,WAAK,KAAK,iBAAiB,YAAY,OAAO;AAAA,IAChD;AAAA,EACF;AAAA,EACA,MAAM,SAA4B;AAChC,eAAO,+BAAiB;AAAA,MACtB,WAAW,QAAQ;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,gBAAgB,QAAQ,MAAM;AAAA,MAC9B,OAAO,QAAQ,OAAO,MAAM;AAAA;AAAA;AAAA;AAAA,MAI5B,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAK,SAAoD;AAC7D,QAAI,QAAS,MAAK,UAAU;AAC5B,QAAI;AACF,gBAAM,0BAAY,KAAK,YAAY,mCAAsB,OAAO,eAAe;AAAA,IACjF,QAAQ;AACN,UAAI,KAAK,WAAW,MAAM,WAAW,mCAAsB,MAAO,QAAO;AACzE,UAAI,KAAK,WAAW,MAAM,WAAW,mCAAsB,UAAW,MAAK,WAAW,QAAQ;AAC9F,WAAK,OAAO,OAAO,KAAK,EAAE;AAC1B,YAAM,IAAI,aAAa,wBAAwB,kBAAkB,GAAI;AAAA,IACvE;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAe;AACnB,SAAK,KAAK,IAAI;AACd,QAAI,CAAC,KAAK,gBAAgB;AACxB,WAAK,KAAK,cAAc,KAAK;AAC7B,WAAK,iBAAiB;AAAA,IACxB;AACA,QAAI,KAAK,WAAW,MAAM,WAAW,mCAAsB,UAAW,MAAK,WAAW,QAAQ;AAC9F,SAAK,OAAO,OAAO,KAAK,EAAE;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KAAK,QAAQ,OAAO;AAClB,SAAK,YAAY,KAAK,KAAK;AAAA,EAC7B;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAK,UAAyB;AAClC,QAAI,CAAE,MAAM,yBAAyB,GAAI;AACvC,eAAS,KAAK;AACd,YAAM,IAAI,aAAa,8BAA8B;AAAA,IACvD;AACA,SAAK,eAAe;AAEpB,QAAI,KAAK,UAAU,KAAK,qBAAqB;AAC3C,WAAK,OAAO,IAAI,SAAS,KAAK,mBAAmB;AAAA,IACnD;AACA,SAAK,sBAAsB,CAAC,UAAiC;AAC3D,UAAI,KAAK,gBAAgB,MAAM,SAAS,6BAA8B;AACtE,WAAK,eAAe;AACpB,WAAK,KAAK,SAAS,KAAK;AAAA,IAC1B;AACA,aAAS,GAAG,SAAS,KAAK,mBAAmB;AAC7C,QAAI,KAAK,YAAY,MAAM,WAAW,+BAAkB,QAAQ;AAC9D,WAAK,YAAY,KAAK,SAAS,aAAa;AAC5C,WAAK,QAAQ,KAAK;AAGlB,UAAI,CAAC,SAAS,QAAS,UAAS,MAAM;AAAA,IACxC,WAAW,CAAC,KAAK,eAAe;AAC9B,WAAK,gBAAgB,KAAK;AAAA,IAC5B;AACA,SAAK,SAAS;AACd,SAAK,SAAS,KAAK;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,OAAO,QAAgB;AACzB,QAAI,OAAO,WAAW,YAAY,OAAO,MAAM,MAAM,GAAG;AACtD,YAAM,IAAI,aAAa,gBAAgB,UAAU,QAAQ,QAAQ;AAAA,IACnE;AACA,QAAI,SAAS,GAAG;AACd,YAAM,IAAI,aAAa,kBAAkB,UAAU,sBAAsB,CAAC;AAAA,IAC5E;AACA,SAAK,UAAU;AACf,SAAK,QAAQ,WAAW,KAAK,UAAU,SAAS,MAAM,KAAK,MAAM,CAAC,EAAE;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,SAAS;AACX,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,mBAAmB;AACrB,YAAQ,KAAK,QAAQ,eAAe,oBAAoB,KAAK;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,eAAe;AACjB,WAAO,KAAK,oBAAoB,KAAK,QAAQ,YAAY;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ;AACN,SAAK,YAAY,MAAM;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU;AACR,UAAM,QAAQ,KAAK,YAAY;AAC/B,QAAI,MAAM,WAAW,+BAAkB,OAAQ;AAC/C,QAAI,KAAK,QAAQ,iBAAiB,MAAM,aAAa,KAAK,OAAO,eAAe;AAC9E,WAAK,YAAY,KAAK,KAAK,OAAO,aAAa;AAC/C,WAAK,OAAO,MAAM;AAClB,WAAK,eAAe,KAAK;AACzB,aAAO,KAAK;AAAA,IACd,OAAO;AACL,WAAK,YAAY,QAAQ;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWS,KAAyC,UAAa,MAAkD;AAC/G,QAAI,UAAU,WAAW,KAAK,cAAc,OAAO,MAAM,GAAG;AAC1D,2BAAqB,KAAK,CAAC,GAAY,KAAK,OAAO,SAAS,kBAAkB,KAAK;AACnF,aAAO;AAAA,IACT;AACA,WAAO,MAAM,KAAK,OAAO,GAAG,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,mBAAmB;AACjB,UAAM,YAAY,KAAK,OAAO,QAAQ;AACtC,QAAI,OAAO,cAAc,YAAY,aAAa,EAAG;AACrD,SAAK,iBAAiB;AACtB,SAAK,cAAc,WAAW,MAAM;AAClC,WAAK,cAAc;AACnB,UAAI,KAAK,aAAc;AACvB,WAAK,eAAe;AACpB,WAAK,KAAK,SAAS,IAAI,aAAa,aAAa,CAAC;AAAA,IACpD,GAAG,SAAS;AACZ,SAAK,YAAY,QAAQ;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAIA,mBAAmB;AACjB,QAAI,CAAC,KAAK,YAAa;AACvB,iBAAa,KAAK,WAAW;AAC7B,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,WAAoB;AACtB,WAAO,KAAK,WAAW,WAAW;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,WAAoB;AACtB,WAAO,KAAK,WAAW,WAAW;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,UAA4B;AACtC,QAAI,OAAO,aAAa,WAAW;AACjC,YAAM,IAAI,aAAa,gBAAgB,WAAW,UAAU,UAAU;AAAA,IACxE;AACA,WAAO,KAAK,WAAW,OAAO;AAAA,MAC5B,GAAG,KAAK,WAAW;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,UAA4B;AACtC,QAAI,OAAO,aAAa,WAAW;AACjC,YAAM,IAAI,aAAa,gBAAgB,WAAW,UAAU,UAAU;AAAA,IACxE;AACA,WAAO,KAAK,WAAW,OAAO;AAAA,MAC5B,GAAG,KAAK,WAAW;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,aAAqC;AACvC,WAAO,KAAK,SAAS,OAAO,SAAS,IAAI;AAAA,EAC3C;AACF;;;ACtaA,IAAAC,kBAA2B;AAMpB,IAAe,cAAf,cAAsC,YAAY;AAAA,EANzD,OAMyD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAIvD,aAAa,IAAI,2BAAsB;AAAA;AAAA;AAAA;AAAA,EAIvC,IAAI,OAAO;AACT,WAAO,KAAK,WAAW;AAAA,EACzB;AACF;;;ACVO,IAAM,gBAAN,cAA4B,YAAoB;AAAA,EAPvD,OAOuD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAIrD;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,OAAc;AACxB,UAAM,MAAM,OAAO;AACnB,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,SAAS,QAAkC;AACzC,QAAI,OAAO,WAAW,YAAY,OAAO,OAAO,SAAS,YAAY,OAAO,OAAO,UAAU,UAAU;AACrG,aAAO;AAAA,IACT;AACA,QAAI,OAAO,WAAW,YAAY,OAAO,OAAO,KAAK,QAAQ,SAAS,MAAM,GAAG;AAC7E,aAAO;AAAA,QACL,MAAM;AAAA,QACN,OAAO,KAAK,QAAQ,QAAQ,MAAM;AAAA,MACpC;AAAA,IACF;AACA,UAAM,IAAI,aAAa,gBAAgB,oBAAoB,QAAQ,QAAQ;AAAA,EAC7E;AAAA,EAEA,OAAO,YAAsB;AAC3B,SAAK,MAAM,gBAAgB;AAC3B,UAAM,aAAa,KAAK;AACxB,UAAM,UAAU,WAAW,WAAW,WAAW,UAAU,CAAC,WAAW,MAAM,OAAK,WAAW,SAAS,CAAC,CAAC;AACxG,QAAI,SAAS;AACX,WAAK,yCAA2B,KAAK,OAAO,YAAY,UAAU;AAAA,IACpE;AAIA,SAAK,KAAK,MAAM,eAAe,EAAE,MAAM,CAAC,MAAe;AACrD,YAAM,eAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAC9D,WAAK,MAAM,MAAM,IAAI,KAAK,MAAM,EAAE,kCAAkC,YAAY,EAAE;AAAA,IACpF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,IAAI,iBAAwD,WAAW,OAAO;AAC5E,UAAM,aAAa,KAAK;AACxB,QAAI,MAAM,QAAQ,eAAe,GAAG;AAClC,iBAAW,UAAU,iBAAiB;AACpC,cAAM,KAAK,KAAK,SAAS,MAAM;AAC/B,YAAI,YAAY,CAAC,KAAK,IAAI,EAAE,EAAG,MAAK,WAAW,IAAI,GAAG,MAAM,EAAE;AAAA,MAChE;AAAA,IACF,OAAO;AACL,YAAM,KAAK,KAAK,SAAS,eAAe;AACxC,UAAI,YAAY,CAAC,KAAK,IAAI,EAAE,EAAG,MAAK,WAAW,IAAI,GAAG,MAAM,EAAE;AAAA,IAChE;AACA,SAAK,OAAO,UAAU;AACtB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ;AACN,WAAO,KAAK,IAAI,CAAC,CAAC;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAI,SAA6B;AAC/B,QAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,OAAM,IAAI,aAAa,gBAAgB,2BAA2B,SAAS,SAAS;AACjH,UAAM,aAAa,KAAK;AACxB,SAAK,WAAW,MAAM;AACtB,eAAW,KAAK,SAAS;AACvB,YAAM,SAAS,KAAK,SAAS,CAAC;AAC9B,WAAK,WAAW,IAAI,OAAO,MAAM,MAAM;AAAA,IACzC;AACA,SAAK,OAAO,UAAU;AACtB,WAAO;AAAA,EACT;AAAA,EAEA,UAAU,GAAqB;AAC7B,WAAO,KAAK,WAAW,OAAO,KAAK,SAAS,CAAC,EAAE,IAAI;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,iBAAwD;AAC7D,UAAM,aAAa,KAAK;AACxB,QAAI,MAAM,QAAQ,eAAe,EAAG,iBAAgB,QAAQ,OAAK,KAAK,UAAU,CAAC,CAAC;AAAA,QAC7E,MAAK,UAAU,eAAe;AACnC,SAAK,OAAO,UAAU;AACtB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,QAA0B;AAC5B,WAAO,KAAK,WAAW,IAAI,OAAO,WAAW,WAAW,SAAS,KAAK,SAAS,MAAM,EAAE,IAAI;AAAA,EAC7F;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,QAAkB;AACpB,WAAO,CAAC,GAAG,KAAK,WAAW,KAAK,CAAC;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAmB;AACrB,WAAO,CAAC,GAAG,KAAK,WAAW,OAAO,CAAC;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,aAA8B;AAChC,WAAO,KAAK,OAAO,EAAE,IAAI,KAAK,OAAO,IAAI,OAAK,EAAE,KAAK,EAAE,KAAK,GAAG,EAAE,IAAI,CAAC;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMS,WAAW;AAClB,WAAO,KAAK,MAAM,SAAS;AAAA,EAC7B;AACF;;;ACxHO,IAAK,SAAL,kBAAKC,YAAL;AAQL,EAAAA,QAAA,WAAQ;AAIR,EAAAA,QAAA,cAAW;AAIX,EAAAA,QAAA,cAAW;AAIX,EAAAA,QAAA,eAAY;AAIZ,EAAAA,QAAA,iBAAc;AAId,EAAAA,QAAA,WAAQ;AAKR,EAAAA,QAAA,YAAS;AAKT,EAAAA,QAAA,gBAAa;AAKb,EAAAA,QAAA,gBAAa;AAIb,EAAAA,QAAA,gBAAa;AAIb,EAAAA,QAAA,kBAAe;AAIf,EAAAA,QAAA,kBAAe;AAIf,EAAAA,QAAA,WAAQ;AAIR,EAAAA,QAAA,gBAAa;AAIb,EAAAA,QAAA,iBAAc;AAId,EAAAA,QAAA,eAAY;AAIZ,EAAAA,QAAA,gBAAa;AAIb,EAAAA,QAAA,mBAAgB;AAIhB,EAAAA,QAAA,eAAY;AAIZ,EAAAA,QAAA,mBAAgB;AAIhB,EAAAA,QAAA,0BAAuB;AAIvB,EAAAA,QAAA,kBAAe;AAIf,EAAAA,QAAA,oBAAiB;AAIjB,EAAAA,QAAA,mBAAgB;AAvGN,SAAAA;AAAA,GAAA;AAqtBL,IAAK,mBAAL,kBAAKC,sBAAL;AAIL,EAAAA,kBAAA,WAAQ;AAIR,EAAAA,kBAAA,WAAQ;AAIR,EAAAA,kBAAA,cAAW;AAIX,EAAAA,kBAAA,WAAQ;AAIR,EAAAA,kBAAA,YAAS;AApBC,SAAAA;AAAA,GAAA;AA6GL,IAAK,aAAL,kBAAKC,gBAAL;AAIL,EAAAA,wBAAA;AAIA,EAAAA,wBAAA;AAIA,EAAAA,wBAAA;AAZU,SAAAA;AAAA,GAAA;AAkBL,IAAK,aAAL,kBAAKC,gBAAL;AAKL,EAAAA,YAAA,eAAY;AAKZ,EAAAA,YAAA,oBAAiB;AAKjB,EAAAA,YAAA,wBAAqB;AAfX,SAAAA;AAAA,GAAA;;;AC73BZ,IAAM,OAAN,MAAW;AAAA,EAAX,OAAW;AAAA;AAAA;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY,QAAiB;AAC3B,SAAK,SAAS;AACd,SAAK,UAAU,IAAI,QAAc,SAAO;AACtC,WAAK,UAAU;AAAA,IACjB,CAAC;AAAA,EACH;AACF;AAQO,IAAM,YAAN,MAAgB;AAAA,EAlBvB,OAkBuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAIrB,SAAiB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOlB,QAAQ,SAAS,OAAsB;AACrC,UAAM,OAAO,KAAK,YAAY,KAAK,OAAO,KAAK,OAAO,SAAS,CAAC,EAAE,UAAU,QAAQ,QAAQ;AAC5F,SAAK,OAAO,KAAK,IAAI,KAAK,MAAM,CAAC;AACjC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAgB;AACd,SAAK,OAAO,MAAM,GAAG,QAAQ;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,YAAoB;AACtB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,cAAuB;AACzB,WAAO,KAAK,OAAO,KAAK,OAAK,EAAE,MAAM;AAAA,EACvC;AACF;;;ACvCO,IAAM,QAAN,cAAoB,YAAY;AAAA,EAjBvC,OAiBuC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAI5B;AAAA;AAAA;AAAA;AAAA,EAIT;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA,EACA;AAAA,EACA,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA,EAKf;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,qBAAqB;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB;AACd,SAAK,iBAAiB;AACtB,SAAK;AACL,QAAI,KAAK,iBAAiB;AACxB,mBAAa,KAAK,eAAe;AACjC,WAAK,kBAAkB;AAAA,IACzB;AACA,QAAI,KAAK,kBAAkB;AACzB,WAAK,iBAAiB,KAAK;AAC3B,WAAK,mBAAmB;AAAA,IAC1B;AACA,SAAK,iBAAiB;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB;AACjB,QAAI,KAAK,mBAAmB;AAC1B,mBAAa,KAAK,iBAAiB;AACnC,WAAK,oBAAoB;AAAA,IAC3B;AACA,QAAI,KAAK,kBAAkB;AACzB,WAAK,iBAAiB,KAAK;AAC3B,WAAK,mBAAmB;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,SAAkB,OAAqB,aAAqC;AACtF,UAAM,OAAO;AACb,SAAK,QAAQ;AACb,SAAK,KAAK,MAAM;AAChB,SAAK,SAAS;AACd,SAAK,QAAQ,CAAC;AACd,SAAK,gBAAgB,CAAC;AACtB,SAAK,UAAU;AACf,SAAK,gBAAgB;AACrB,SAAK,SAAS;AACd,SAAK;AACL,SAAK,WAAW;AAChB,SAAK,WAAW,IAAI,cAAc,IAAI;AACtC,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,SAAK,aAAa,IAAI,UAAU;AAChC,SAAK,aAAa;AAClB,SAAK,aAAa;AAAA,MAChB,QAAQ,EAAE,GAAG,KAAK,QAAQ,OAAO,KAAK,OAAO;AAAA,MAC7C,OAAO,EAAE,GAAG,KAAK,QAAQ,OAAO,KAAK,MAAM;AAAA,MAC3C,QAAQ,EAAE,GAAG,KAAK,QAAQ,OAAO,KAAK,OAAO;AAAA,IAC/C;AAEA,SAAK,aAAa,OAAO,KAAK,QAAQ,WAAW,QAAQ,KAAK;AAC9D,SAAK,eAAe;AAAA,EACtB;AAAA,EACA,oBAAoB,OAAsB;AACxC,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,UAAI,KAAK,QAAQ,mBAAmB;AAClC,aAAK,cAAc,KAAK,GAAG,KAAK;AAAA,MAClC,OAAO;AACL,aAAK,cAAc,KAAK,GAAG,MAAM,IAAI,QAAM,EAAE,IAAI,EAAE,GAAG,EAAU,CAAC;AAAA,MACnE;AAAA,IACF,WAAW,KAAK,QAAQ,mBAAmB;AACzC,WAAK,cAAc,KAAK,KAAK;AAAA,IAC/B,OAAO;AACL,WAAK,cAAc,KAAK,EAAE,IAAI,MAAM,GAAG,CAAS;AAAA,IAClD;AAAA,EACF;AAAA,EACA,QAAQ;AACN,SAAK,gBAAgB;AACrB,SAAK,MAAM,KAAK;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,eAAe;AACjB,WAAO,KAAK,MAAM,QAAQ,MAAM,QAAQ,MAAM;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,UAAU;AACZ,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,WAAoB;AACtB,WAAO,CAAC,KAAK;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,oBAAoB;AACtB,WAAO,eAAe,KAAK,QAAQ;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,WAAW;AACb,WAAO,KAAK,MAAM,SAAS,KAAK,MAAM,OAAO,CAAC,MAAM,SAAS,OAAO,KAAK,UAAU,CAAC,IAAI;AAAA,EAC1F;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,cAAc;AAChB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,IAAI,YAAoB;AACtB,WAAO,KAAK;AAAA,EACd;AAAA,EACA,IAAI,UAAU,OAAe;AAC3B,QAAI,OAAO,UAAU,YAAY,OAAO,MAAM,KAAK,GAAG;AACpD,YAAM,IAAI,aAAa,gBAAgB,UAAU,OAAO,iBAAiB;AAAA,IAC3E;AACA,QAAI,QAAQ,EAAG,OAAM,IAAI,aAAa,kBAAkB,aAAa,sBAAsB,CAAC;AAC5F,QAAI,QAAQ,6BAA6B;AACvC,YAAM,IAAI,aAAa,kBAAkB,aAAa,uBAAuB,2BAA2B;AAAA,IAC1G;AACA,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,uBAAuB;AACzB,WAAO,eAAe,KAAK,WAAW;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,eAAe;AACjB,WAAO,KAAK,cAAc,OAAO,WAAW;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,SAAS;AACX,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,OAAO,OAAe;AACxB,UAAM,YAAY,KAAK,MAAM;AAC7B,SAAK,MAAM,SAAS;AACpB,QAAI,KAAK,gBAAgB,cAAc,OAAO;AAC5C,WAAK,mCAAwB,MAAM,OAAO,SAAS;AAAA,IACrD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,WAAW,MAAqB,WAAW,GAAU;AACnD,QAAI,KAAK,QAAS,OAAM,IAAI,aAAa,eAAe;AACxD,QAAI,CAAC,QAAS,MAAM,QAAQ,IAAI,KAAK,CAAC,KAAK,QAAS;AAClD,YAAM,IAAI,aAAa,gBAAgB,CAAC,QAAQ,aAAa,GAAG,MAAM,MAAM;AAAA,IAC9E;AACA,QAAI,OAAO,aAAa,YAAY,CAAC,OAAO,UAAU,QAAQ,GAAG;AAC/D,YAAM,IAAI,aAAa,gBAAgB,WAAW,UAAU,UAAU;AAAA,IACxE;AACA,QAAI,YAAY,GAAG;AACjB,UAAI,MAAM,QAAQ,IAAI,EAAG,MAAK,MAAM,KAAK,GAAG,IAAI;AAAA,UAC3C,MAAK,MAAM,KAAK,IAAI;AAAA,IAC3B,WAAW,MAAM,QAAQ,IAAI,GAAG;AAC9B,WAAK,MAAM,OAAO,UAAU,GAAG,GAAG,IAAI;AAAA,IACxC,OAAO;AACL,WAAK,MAAM,OAAO,UAAU,GAAG,IAAI;AAAA,IACrC;AACA,SAAK,QAAQ,kBAAkB,IAAI;AACnC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,QAAwB;AAC5B,UAAM,KAAK,WAAW,QAAQ;AAC9B,QAAI;AACF,UAAI,KAAK,OAAQ,OAAM,IAAI,aAAa,QAAQ;AAChD,WAAK,SAAS;AAGd,WAAK,cAAc;AACnB,WAAK,MAAM,MAAM;AACjB,WAAK,mCAAwB,MAAM,KAAK,MAAM,CAAC,CAAC;AAChD,aAAO;AAAA,IACT,UAAE;AACA,WAAK,WAAW,QAAQ;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,SAAyB;AAC7B,UAAM,KAAK,WAAW,QAAQ;AAC9B,QAAI;AACF,UAAI,CAAC,KAAK,OAAQ,OAAM,IAAI,aAAa,SAAS;AAClD,WAAK,SAAS;AACd,WAAK,MAAM,QAAQ;AACnB,WAAK,qCAAyB,MAAM,KAAK,MAAM,CAAC,CAAC;AACjD,WAAK,QAAQ,kBAAkB,IAAI;AACnC,WAAK,QAAQ,oBAAoB,IAAI;AACrC,aAAO;AAAA,IACT,UAAE;AACA,WAAK,WAAW,QAAQ;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,SAAwB;AAChC,SAAK,SAAS;AACd,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,KAAK,SAAsC;AAC/C,WAAO,KAAK,KAAK,GAAG,OAAO;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,WAA0B;AAC9B,UAAM,KAAK,WAAW,QAAQ;AAC9B,QAAI;AACF,UAAI,CAAC,KAAK,QAAQ,kBAAmB,OAAM,IAAI,aAAa,mBAAmB,mBAAmB;AAClG,YAAM,cAAc,KAAK,cAAc,SAAS;AAChD,UAAI,CAAC,eAAe,KAAK,8BAAiC;AACxD,cAAM,IAAI,aAAa,aAAa;AAAA,MACtC;AAIA,YAAM,OAAO,cAAc,KAAK,cAAc,IAAI,IAAI,KAAK,MAAM,IAAI;AACrE,UAAI,CAAC,KAAM,OAAM,IAAI,aAAa,aAAa;AAC/C,WAAK,MAAM,QAAQ,IAAI;AACvB,WAAK,MAAM;AACX,aAAO;AAAA,IACT,UAAE;AACA,WAAK,WAAW,QAAQ;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAA0B;AAC9B,UAAM,KAAK,WAAW,QAAQ;AAC9B,QAAI;AACF,YAAM,UAAU,KAAK,MAAM,MAAM;AACjC,UAAI,YAAY,OAAW,QAAO;AAClC,WAAK,cAAc;AACnB,eAAS,IAAI,KAAK,MAAM,SAAS,GAAG,IAAI,GAAG,KAAK;AAC9C,cAAM,IAAI,KAAK,MAAM,KAAK,OAAO,KAAK,IAAI,EAAE;AAC5C,SAAC,KAAK,MAAM,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;AAAA,MAChE;AACA,WAAK,MAAM,QAAQ,OAAO;AAC1B,WAAK,yCAA2B,MAAM,KAAK,KAAK;AAChD,WAAK,QAAQ,kBAAkB,IAAI;AACnC,aAAO;AAAA,IACT,UAAE;AACA,WAAK,WAAW,QAAQ;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,KAAK,UAAkB,SAAsC;AACjE,UAAM,KAAK,WAAW,QAAQ;AAC9B,QAAI;AACF,UAAI,OAAO,aAAa,SAAU,OAAM,IAAI,aAAa,gBAAgB,UAAU,UAAU,UAAU;AACvG,UAAI,CAAC,YAAY,WAAW,KAAK,MAAM,UAAU,CAAC,WAAW,KAAK,cAAc,QAAQ;AACtF,cAAM,IAAI,aAAa,kBAAkB;AAAA,MAC3C;AACA,UAAI,WAAW,GAAG;AAChB,YAAI,YAAY,KAAK,MAAM,QAAQ;AACjC,cAAI,KAAK,UAAU;AACjB,kBAAM,KAAK,gBAAgB;AAAA,UAC7B,OAAO;AACL,kBAAM,IAAI,aAAa,YAAY;AAAA,UACrC;AAAA,QACF;AACA,cAAM,UAAU,KAAK,MAAM,OAAO,GAAG,QAAQ;AAC7C,YAAI,SAAS,SAAS;AACpB,eAAK,MAAM,KAAK,GAAG,OAAO;AAAA,QAC5B,OAAO;AACL,eAAK,oBAAoB,OAAO;AAAA,QAClC;AACA,aAAK,iCAAuB,MAAM,QAAQ,CAAC,CAAC;AAAA,MAC9C,WAAW,CAAC,KAAK,QAAQ,mBAAmB;AAC1C,cAAM,IAAI,aAAa,mBAAmB,mBAAmB;AAAA,MAC/D,OAAO;AACL,cAAM,UAAU,KAAK,cAAc,OAAO,QAAQ;AAClD,aAAK,MAAM,QAAQ,GAAG,OAAO;AAAA,MAC/B;AACA,WAAK,cAAc;AACnB,WAAK,MAAM;AACX,aAAO,KAAK,MAAM,CAAC;AAAA,IACrB,UAAE;AACA,WAAK,WAAW,QAAQ;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAc,MAA+B;AAC3C,QAAI,SAAS,UAAa,CAAC,OAAO,OAAO,UAAU,EAAE,SAAS,IAAI,GAAG;AACnE,YAAM,IAAI,aAAa,gBAAgB,CAAC,cAAc,WAAW,GAAG,MAAM,MAAM;AAAA,IAClF;AACA,QAAI,SAAS,OAAW,MAAK,cAAc,KAAK,aAAa,KAAK;AAAA,aACzD,KAAK,eAAe,KAAM,MAAK;AAAA,QACnC,MAAK,aAAa;AACvB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,KAAK,MAA8B;AACvC,UAAM,KAAK,WAAW,QAAQ;AAC9B,QAAI;AACF,UAAI,OAAO,SAAS,SAAU,OAAM,IAAI,aAAa,gBAAgB,UAAU,MAAM,MAAM;AAC3F,UAAI,OAAO,MAAM,IAAI,KAAK,OAAO,EAAG,OAAM,IAAI,aAAa,kBAAkB,QAAQ,sBAAsB,CAAC;AAC5G,WAAK,cAAc;AACnB,WAAK,aAAa;AAClB,YAAM,KAAK,KAAK,KAAK;AACrB,WAAK,iCAAuB,MAAM,KAAK,MAAM,CAAC,GAAG,IAAI;AACrD,aAAO;AAAA,IACT,UAAE;AACA,WAAK,WAAW,QAAQ;AAAA,IAC1B;AAAA,EACF;AAAA,EACA,MAAM,gBAAgB,SAAgC;AACpD,UAAM,SAAS,MAAM,KAAK,QAAQ,mBAAmB,OAAO;AAC5D,QAAI,OAAQ,QAAO,OAAO,gBAAgB,OAAO;AACjD,WAAO,CAAC;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,gBAAgB,MAA4B;AAChD,UAAM,UAAU,QAAQ,KAAK,QAAQ,CAAC;AACtC,QAAI,CAAC,QAAS,OAAM,IAAI,aAAa,iBAAiB;AACtD,UAAM,UAAU,KAAK,cAAc,IAAI,OAAK,EAAE,EAAE;AAChD,UAAM,gBAAgB,MAAM,KAAK,gBAAgB,OAAO,GAAG,OAAO,OAAK,CAAC,QAAQ,SAAS,EAAE,EAAE,CAAC;AAC9F,SAAK,MAAM,IAAI,KAAK,EAAE,iCAAiC,OAAO,EAAE;AAChE,QAAI,CAAC,aAAa,UAAU,CAAC,QAAQ,OAAO,gBAAgB;AAC1D,YAAM,UAAU,QAAQ,OAAO;AAC/B,UAAI,QAAS,cAAa,KAAK,IAAI,MAAM,KAAK,gBAAgB,OAAO,GAAG,OAAO,OAAK,CAAC,QAAQ,SAAS,EAAE,EAAE,CAAC,CAAC;AAC5G,WAAK,MAAM,IAAI,KAAK,EAAE,+CAA+C,OAAO,EAAE;AAAA,IAChF;AACA,UAAM,WAAW,aAAa,CAAC;AAC/B,QAAI,CAAC,SAAU,OAAM,IAAI,aAAa,YAAY;AAClD,aAAS,WAAW,QAAQ;AAC5B,aAAS,SAAS,KAAK;AACvB,SAAK,WAAW,QAAQ;AACxB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,eAAe,MAA4B;AAC/C,UAAM,KAAK,WAAW,QAAQ;AAC9B,QAAI;AACF,aAAO,MAAM,KAAK,gBAAgB,IAAI;AAAA,IACxC,UAAE;AACA,WAAK,WAAW,QAAQ;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO;AACX,UAAM,KAAK,WAAW,QAAQ;AAC9B,QAAI;AACF,WAAK,MAAM,KAAK;AAChB,WAAK,OAAO;AAAA,IACd,UAAE;AACA,WAAK,WAAW,QAAQ;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS;AACP,SAAK,cAAc;AACnB,SAAK,SAAS;AACd,SAAK,UAAU;AACf,SAAK,QAAQ,CAAC;AACd,SAAK,gBAAgB,CAAC;AACtB,QAAI,KAAK,WAAY,YAAW,SAAS,WAAW,KAAK,UAAU,EAAG,MAAK,MAAM,IAAI,OAAO,KAAK,WAAW,KAAK,CAAC;AAClH,SAAK,OAAO,OAAO,KAAK,EAAE;AAC1B,SAAK,uCAA0B,IAAI;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,iBAA0B;AACxB,SAAK,WAAW,CAAC,KAAK;AACtB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KAAK,eAAe,MAAM;AACxB,QAAI,KAAK,QAAS,OAAM,IAAI,aAAa,eAAe;AACxD,WAAO,KAAK,OAAO,SAAS,MAAM,YAAY;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,oBAAoB;AAClB,SAAK,OAAO,kBAAkB,IAAI;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,iBAAgC;AACpC,UAAM,KAAK,WAAW,QAAQ,IAAI;AAClC,QAAI;AACF,UAAI,KAAK,WAAW,CAAC,KAAK,MAAM,OAAQ;AACxC,WAAK,aAAa,KAAK;AACvB,YAAM,KAAK,OAAO,SAAS,MAAM,OAAO,EAAE,iBAAiB,KAAK,CAAC;AAAA,IACnE,UAAE;AACA,WAAK,WAAW,QAAQ;AAAA,IAC1B;AAAA,EACF;AACF;;;ANpoBA,IAAM,YAAY,wBAAC,QAAiB,MAAM,KAAK,IAAI,GAAG,KAAK,KAAzC;AAOX,SAAS,eAAe,KAAqB;AAClD,MAAI,CAAC,OAAO,CAAC,OAAO,GAAG,EAAG,QAAO;AACjC,QAAM,UAAU,KAAK,MAAM,MAAM,EAAE;AACnC,QAAM,UAAU,KAAK,MAAO,MAAM,OAAQ,EAAE;AAC5C,QAAM,QAAQ,KAAK,MAAM,MAAM,IAAI;AACnC,MAAI,QAAQ,EAAG,QAAO,GAAG,UAAU,KAAK,CAAC,IAAI,UAAU,OAAO,CAAC,IAAI,UAAU,OAAO,CAAC;AACrF,MAAI,UAAU,EAAG,QAAO,GAAG,UAAU,OAAO,CAAC,IAAI,UAAU,OAAO,CAAC;AACnE,SAAO,MAAM,UAAU,OAAO,CAAC;AACjC;AARgB;AAShB,IAAM,qBAAqB,CAAC,UAAU,SAAS,OAAO;AAM/C,SAAS,MAAM,OAA0E;AAC9F,MAAI,OAAO,UAAU,YAAY,MAAM,SAAS,GAAG,EAAG,QAAO;AAC7D,MAAI;AACF,UAAM,MAAM,IAAI,oBAAI,KAAK;AACzB,QAAI,CAAC,mBAAmB,KAAK,OAAK,MAAM,IAAI,QAAQ,EAAG,QAAO;AAAA,EAChE,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;AATgB;AAgBT,SAAS,aAAa,SAA8B;AAIzD,QAAM,UAAU,QAAQ;AACxB,QAAM,iBACJ,OAAO,SAAS,QAAQ,aACpB,QAAQ,IAAI,kCAAkB,gBAAgB,IAC9C,IAAI,gCAAgB,QAAQ,OAAgB,EAAE,IAAI,kCAAkB,gBAAgB;AAC1F,MAAI,CAAC,eAAgB,OAAM,IAAI,aAAa,mBAAmB,kBAAkB;AACnF;AAVgB;AAiBT,SAAS,oBAAoB,YAAiC;AACnE,QAAM,QAAQ,WAAW;AACzB,QAAM,WAAW,WAAW,OAAO,MAAM;AACzC,MAAI,CAAC,SAAS,CAAC,SAAU,QAAO;AAChC,QAAM,eAAe,MAAM,QAAQ,IAAI,OAAO;AAC9C,MAAI,CAAC,aAAc,QAAO;AAC1B,QAAM,UAAU,aAAa,QAAQ,OAAO,OAAK,CAAC,EAAE,KAAK,GAAG;AAC5D,SAAO,CAAC,QAAQ;AAClB;AARgB;AAeT,SAAS,YAAY,IAA0B;AACpD,MAAI;AACF,WAAO,8BAAc,YAAY,EAAE,EAAE,YAAY,8BAAc;AAAA,EACjE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AANgB;AAaT,SAAS,iBAAiB,QAAoC;AACnE,SACE,QAAQ,MAAM,KACd,YAAY,OAAO,EAAE,KACrB,YAAY,OAAO,OAAO,EAAE,KAC5B,YAAY,OAAO,MAAM,EAAE,KAC3B,OAAO,OAAO,OAAO,KAAK;AAE9B;AARgB;AAeT,SAAS,sBAAsB,SAAgD;AACpF,SACE,QAAQ,OAAO,KACf,YAAY,QAAQ,EAAE,KACtB,YAAY,QAAQ,WAAW,QAAQ,OAAO,EAAE,KAChD,0BAAU,sBAAsB,SAAS,QAAQ,IAAI,KACrD,OAAO,QAAQ,SAAS,eACvB,OAAO,QAAQ,SAAS,aAAa,OAAO,QAAQ,QAAQ,SAAS;AAE1E;AATgB;AAgBT,SAAS,kBAAkB,SAAwC;AAExE,SACE,QAAQ,OAAO,KACf,YAAY,QAAQ,EAAE,KACtB,YAAY,QAAQ,WAAW,QAAQ,OAAO,EAAE,KAChD,iBAAiB,QAAQ,MAAM,KAC/B,sBAAsB,QAAQ,OAAO,KACrC,0BAAU,sBAAsB,SAAS,QAAQ,IAAI,KACrD,QAAQ,OAAO,OAAO,QAAQ,QAAQ;AAE1C;AAXgB;AAkBT,SAAS,wBAAwB,SAA4C;AAClF,SACE,QAAQ,OAAO,KACf,YAAY,QAAQ,EAAE,KACtB,YAAY,QAAQ,WAAW,QAAQ,OAAO,EAAE,KAChD,0BAAU,uBAAuB,SAAS,QAAQ,IAAI;AAE1D;AAPgB;AAcT,SAAS,gBAAgB,OAA4B;AAC1D,SAAO,QAAQ,KAAK,KAAK,YAAY,MAAM,EAAE,KAAK,YAAY,MAAM,OAAO,KAAK,OAAO,MAAM,SAAS;AACxG;AAFgB;AAUT,SAAS,eAAe,YAA0C;AACvE,MAAI;AACJ,MAAI,OAAO,eAAe,UAAU;AAClC,cAAU;AAAA,EACZ,WAAW,SAAS,UAAU,GAAG;AAC/B,QAAI,aAAa,cAAc,WAAW,SAAS;AACjD,gBAAU,WAAW;AAAA,IACvB,WAAW,sBAAsB,SAAS,sBAAsB,gBAAgB,gBAAgB,UAAU,GAAG;AAC3G,gBAAU,WAAW;AAAA,IACvB,WAAW,WAAW,cAAc,gBAAgB,WAAW,KAAK,GAAG;AACrE,gBAAU,WAAW,MAAM;AAAA,IAC7B;AAAA,EACF;AACA,MAAI,CAAC,YAAY,OAAO,EAAG,OAAM,IAAI,aAAa,gBAAgB,qBAAqB,UAAU;AACjG,SAAO;AACT;AAfgB;AAsBT,SAAS,iBAAiB,QAA+B;AAC9D,SAAO,QAAQ,MAAM,KAAK,OAAO,OAAO,UAAU;AACpD;AAFgB;AAaT,SAAS,gBACd,QACA,QACA,YACA;AACA,MAAI,CAAC,SAAS,MAAM,EAAG,OAAM,IAAI,aAAa,gBAAgB,UAAU,QAAQ,UAAU;AAC1F,QAAM,aAAa,MAAM,QAAQ,MAAM,IAAI,SAAS,WAAW,MAAM;AACrE,QAAM,aAAa,WAAW,MAAM,EAAE,KAAK,SAAO,CAAC,WAAW,SAAS,GAAG,CAAC;AAC3E,MAAI,WAAY,OAAM,IAAI,aAAa,eAAe,YAAY,UAAU;AAC9E;AATgB;AAgBT,SAAS,SAAS,KAAyB;AAChD,SAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,CAAC,MAAM,QAAQ,GAAG;AACtE;AAFgB;AAaT,SAAS,WAAc,KAAkB;AAC9C,MAAI,CAAC,SAAS,GAAG,EAAG,QAAO,CAAC;AAC5B,SAAO,OAAO,KAAK,GAAG;AACxB;AAHgB;AAUT,SAAS,cAAc,SAA0C;AACtE,MAAI,CAAC,sBAAsB,OAAO,EAAG,QAAO;AAC5C,MAAI,QAAQ,SAAS,EAAG,QAAO,QAAQ,QAAQ,QAAQ;AACvD,SAAO,QAAQ;AACjB;AAJgB;AAeT,IAAM,WAAW,wBAAI,MAAyB,QAAQ,CAAC,GAAtC;AAajB,SAAS,qBAAqB,OAAc,WAAmC,OAAa;AACjG,MAAI,aAAa,QAAS,OAAM;AAChC,MAAI,aAAa,SAAU;AAC3B,UAAQ;AAAA,IACN;AAAA,IAGA;AAAA,MACE,MAAM;AAAA,MACN,QAAQ,OAAO,SAAS,OAAO,WAAW,OAAO,KAAK;AAAA,IACxD;AAAA,EACF;AACF;AAZgB;AAsBT,IAAM,2BAA2B,mCAAY;AAClD,MAAI,MAAM,OAAO,QAAa,EAAE,KAAK,OAAK,EAAE,WAAW,EAAE,SAAS,aAAa,CAAC,EAAG,QAAO;AAC1F,aAAW,OAAO;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAG;AACD,QAAI;AACF,YAAM,OAAO;AACb,aAAO;AAAA,IACT,QAAQ;AAAA,IAAC;AAAA,EACX;AACA,SAAO;AACT,GAhBwC;;;AOjSjC,IAAM,WAAN,MAAoD;AAAA,EAT3D,OAS2D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAIzD;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YAAY,UAAwB,EAAE,QAAQ,SAAS,IAAuB,CAAC,GAAG;AAChF,QAAI,CAAC,MAAM,QAAQ,SAAS,KAAK,KAAK,CAAC,SAAS,MAAM,OAAQ,OAAM,IAAI,aAAa,gBAAgB;AAErG,SAAK,SAAS,SAAS,OAAO,YAAY;AAC1C,SAAK,QAAQ,SAAS;AACtB,SAAK,OAAO,SAAS;AACrB,SAAK,KAAK,SAAS;AACnB,SAAK,MAAM,SAAS;AACpB,SAAK,YAAY,SAAS;AAC1B,SAAK,SAAS;AACd,SAAK,MAAM,QAAQ,OAAM,EAAE,WAAW,IAAK;AAC3C,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,WAAW;AACb,WAAO,KAAK,MAAM,OAAO,CAAC,MAAM,SAAS,OAAO,KAAK,UAAU,CAAC;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,oBAAoB;AACtB,WAAO,eAAe,KAAK,QAAQ;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAS;AACX,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,OAAO,QAAiC;AAC1C,QAAI,CAAC,iBAAiB,MAAM,EAAG;AAC/B,SAAK,UAAU;AACf,SAAK,MAAM,QAAQ,OAAM,EAAE,SAAS,KAAK,MAAO;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAO;AACT,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,WAAW;AACb,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,SAAS,UAAa;AACxB,SAAK,YAAY;AAIjB,QAAI,aAAa,OAAW;AAC5B,SAAK,MAAM,QAAQ,OAAM,EAAE,WAAW,QAAS;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW;AACT,WAAO,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,MAAM;AAAA,EAC3C;AACF;;;ACtHO,IAAM,OAAN,MAAwB;AAAA,EAT/B,OAS+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAI7B;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAaA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAwBA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YAAY,MAAmB,EAAE,QAAQ,SAAS,IAAuB,CAAC,GAAG;AAC3E,SAAK,SAAS,KAAK,OAAO,YAAY;AACtC,SAAK,WAAY,YAAY,KAAK;AAClC,SAAK,SAAS;AACd,SAAK,KAAK,KAAK;AACf,SAAK,OAAO,KAAK;AACjB,SAAK,SAAS,KAAK;AACnB,SAAK,WAAW,KAAK,UAAU,CAAC,KAAK,WAAW,IAAI,KAAK;AACzD,SAAK,oBAAoB,KAAK,SAAS,SAAS,eAAe,KAAK,QAAQ;AAC5E,SAAK,MAAM,KAAK;AAChB,SAAK,YAAY,KAAK;AACtB,SAAK,QAAQ,KAAK;AAClB,SAAK,QAAQ,KAAK;AAClB,SAAK,WAAW,KAAK;AACrB,SAAK,UAAU,KAAK;AACpB,SAAK,WAAW;AAAA,MACd,MAAM,KAAK,UAAU;AAAA,MACrB,KAAK,KAAK,UAAU;AAAA,IACtB;AACA,SAAK,gBAAgB,KAAK;AAG1B,SAAK,SAAS,EAAE,gBAAgB,KAAK,kBAAkB,KAAK,QAAQ,aAAa,MAAM;AACvF,SAAK,SAAS,KAAK;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,WAAW;AACb,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,SAAS,UAAgC;AAC3C,QAAI,EAAE,oBAAoB,UAAW,OAAM,IAAI,aAAa,gBAAgB,YAAY,UAAU,eAAe;AACjH,SAAK,YAAY;AACjB,SAAK,SAAS,SAAS;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAS;AACX,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,OAAO,QAAiC;AAC1C,QAAI,iBAAiB,MAAM,EAAG,MAAK,UAAU;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAO;AACT,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,WAAW;AACb,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,SAAS,UAAa;AACxB,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW;AACT,WAAO,KAAK,QAAQ,KAAK,OAAO,KAAK,MAAM;AAAA,EAC7C;AACF;;;AV/LO,IAAM,iBAAN,cAA6B,YAAY;AAAA,EAdhD,OAcgD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuD9C,MAAM,QAAQ,OAAiC,UAA0B,CAAC,GAA6B;AACrG,QAAI,iBAAiB,QAAQ,iBAAiB,UAAU;AACtD,UAAI,cAAc,QAAS,OAAM,WAAW,QAAQ;AACpD,UAAI,YAAY,QAAS,OAAM,SAAS,QAAQ;AAChD,aAAO;AAAA,IACT;AACA,QAAI,OAAO,UAAU,UAAU;AAC7B,UAAI,MAAM,KAAK,GAAG;AAChB,cAAM,SACH,MAAM,KAAK,kBAAkB,KAAK,KAClC,MAAM,KAAK,kBAAmB,QAAQ,MAAM,KAAK,mBAAmB,KAAK,CAAE;AAC9E,YAAI,CAAC,OAAQ,OAAM,IAAI,aAAa,mBAAmB;AACvD,aAAK,MAAM,IAAI,OAAO,YAAY,IAAI,yBAAyB,KAAK,EAAE;AACtE,eAAO,OAAO,QAAQ,OAAO,OAAO;AAAA,MACtC;AACA,UAAI;AACF,cAAM,OAAO,MAAM,KAAK,YAAY,OAAO,OAAO;AAClD,YAAI,KAAM,QAAO;AAAA,MACnB,SAAS,GAAY;AAEnB,cAAM,QAAQ,IAAI,aAAa,aAAa,KAAK;AACjD,cAAM,QAAQ;AACd,cAAM;AAAA,MACR;AAAA,IACF;AACA,UAAM,IAAI,aAAa,uBAAuB,KAAK;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,kBAAkB,KAA4C;AAClE,eAAW,UAAU,KAAK,QAAS,KAAI,MAAM,OAAO,SAAS,GAAG,EAAG,QAAO;AAC1E,WAAO;AAAA,EACT;AAAA,EAoBA,MAAM,mBACJ,MACA,OACA,WAAW,MACoC;AAC/C,QAAI,CAAC,SAAS,MAAM,SAAY,KAAK,QAAQ,IAAI,EAAG,QAAO,KAAK;AAChE,QAAI,CAAC,KAAK,IAAK,QAAO;AACtB,eAAW,UAAU,KAAK,SAAS;AACjC,WAAK,CAAC,SAAS,MAAM,SAAY,QAAQ,IAAI,OAAO,CAAC,YAAa,MAAM,OAAO,SAAS,KAAK,GAAG,IAAK;AACnG,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,YAAY,OAAe,UAA0B,CAAC,GAAG,eAAe,OAA6B;AACzG,UAAM,SAAS,QAAQ,QAAQ,YAAY;AAC3C,UAAM,UAAU,KAAK,QAAQ;AAAA,MAC3B,CAAC,WACC,OAAO,yCAAkC,CAAC,UAAU,OAAO,YAAY,SAAS,MAAM;AAAA,IAC1F;AACA,QAAI,CAAC,QAAQ,OAAQ,OAAM,IAAI,aAAa,qBAAqB;AACjE,eAAW,UAAU,SAAS;AAC5B,WAAK,MAAM,IAAI,OAAO,YAAY,IAAI,yBAAyB,KAAK,EAAE;AACtE,YAAM,SAAS,MAAM,OAAO,WAAW,OAAO,OAAO;AACrD,UAAI,QAAQ;AACV,YAAI,gBAAgB,OAAO,OAAO,eAAgB,QAAO,OAAO,MAAM,MAAM,OAAO,aAAa,MAAM;AACtG,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,iBAAiB,MAAY;AACjC,QAAI,KAAK,OAAO,gBAAgB;AAC9B,UAAI,KAAK,OAAO,IAAK;AACrB,WAAK,MAAM,yCAAyC,IAAI,EAAE;AAC1D,YAAM,SAAS,MAAM,KAAK,mBAAmB,MAAM,2EAAoD,CAAC;AACxG,UAAI,CAAC,OAAQ,OAAM,IAAI,aAAa,sBAAsB,KAAK,SAAS,CAAC;AACzE,WAAK,MAAM,IAAI,OAAO,YAAY,IAAI,yBAAyB,IAAI,EAAE;AACrE,WAAK,OAAO,MAAM,MAAM,OAAO,aAAa,IAAI;AAChD,UAAI,CAAC,KAAK,OAAO,IAAK,OAAM,IAAI,aAAa,yBAAyB,KAAK,SAAS,CAAC;AAAA,IACvF,OAAO;AACL,UAAI,KAAK,OAAO,MAAM,QAAQ,kBAAkB,KAAK,OAAO,KAAK,OAAO,IAAK;AAC7E,WAAK,MAAM,yCAAyC,IAAI,EAAE;AAG1D,YAAM,SAAS,KAAK;AACpB,YAAM,QAAQ,SACV,MAAM,OAAO,kBAAkB,IAAI,IACnC,GAAG,KAAK,QAAQ,EAAE,IAAI,KAAK,UAAU,QAAQ,EAAE,GAAG,KAAK;AAC3D,UAAI,CAAC,MAAO,OAAM,IAAI,aAAa,2BAA2B,KAAK,SAAS,CAAC;AAC7E,YAAM,UAAU,MAAM,KAAK,kBAAkB,OAAO,MAAM,MAAM;AAChE,WAAK,OAAO,OAAO;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,kBAAkB,OAAe,MAAY,QAA6C;AAC9F,UAAM,UAA0B,EAAE,UAAU,KAAK,UAAU,QAAQ,KAAK,OAAO;AAC/E,eAAW,UAAU,KAAK,SAAS;AACjC,UAAI,WAAW,OAAQ;AAGvB,UAAI,OAAO,aAAa,MAAO;AAC/B,YAAM,SAAS,MAAM,OAAO,WAAW,OAAO,OAAO;AACrD,UAAI,CAAC,OAAQ;AAGb,UAAI,CAAC,OAAO,OAAO,eAAgB;AACnC,WAAK,MAAM,IAAI,OAAO,YAAY,IAAI,kCAAkC,KAAK,GAAG;AAChF,aAAO,OAAO,MAAM,MAAM,OAAO,aAAa,MAAM;AACpD,aAAO;AAAA,IACT;AACA,UAAM,IAAI,aAAa,aAAa,KAAK;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,mBAAmB,KAAa,cAAc,oBAAqC;AACvF,QAAI,gBAAgB,EAAG,QAAO;AAE9B,UAAM,MAAM,UAAM,uBAAQ,KAAK;AAAA,MAC7B,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,cACE;AAAA,MAEJ;AAAA,IACF,CAAC;AAED,QAAI,oBAAoB,IAAI,IAAI,cAAc,GAAG,GAAG;AAClD,UAAI,WAAW,IAAI,QAAQ;AAC3B,UAAI,OAAO,aAAa,SAAU,YAAW,WAAW,CAAC,KAAK;AAC9D,aAAO,KAAK,mBAAmB,UAAU,EAAE,WAAW;AAAA,IACxD;AAEA,WAAO;AAAA,EACT;AACF;;;AW/NA,IAAM,4BAA+D,CAAC,OAAO,SAAS,QAAQ;AAQvF,IAAM,UAAN,MAAc;AAAA,EA7BrB,OA6BqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAInB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,SAAyB;AACnC,QAAI,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACzD,YAAM,IAAI,aAAa,gBAAgB,UAAU,SAAS,gBAAgB;AAAA,IAC5E;AACA,UAAM,OAAO,EAAE,GAAG,gBAAgB,GAAG,QAAQ;AAC7C,SAAK,UAAU,KAAK;AACpB,SAAK,kBAAkB,KAAK;AAC5B,SAAK,oBAAoB,KAAK;AAC9B,SAAK,gBAAgB,KAAK;AAC1B,SAAK,OAAO,KAAK;AACjB,SAAK,+BAA+B,KAAK;AACzC,SAAK,+BAA+B,KAAK;AACzC,SAAK,sBAAsB,KAAK;AAChC,SAAK,iBAAiB,KAAK;AAC3B,SAAK,iBAAiB,KAAK;AAC3B,SAAK,UAAU,KAAK,eAAe,KAAK,OAAO;AAC/C,SAAK,YAAY,KAAK,iBAAiB,KAAK,SAAS;AACrD,SAAK,SAAS,KAAK,cAAc,OAAO;AACxC,oBAAgB,MAAM,MAAM,gBAAgB;AAC5C,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,eAAe,OAAkD;AAC/D,QAAI,UAAU,UAAa,UAAU,OAAO;AAC1C,aAAO,EAAE,SAAS,OAAO,WAAW,+BAA+B;AAAA,IACrE;AACA,QAAI,UAAU,MAAM;AAClB,aAAO,EAAE,SAAS,MAAM,WAAW,+BAA+B;AAAA,IACpE;AACA,QAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AACrD,YAAM,IAAI,aAAa,gBAAgB,CAAC,WAAW,QAAQ,GAAG,OAAO,wBAAwB;AAAA,IAC/F;AACA,oBAAgB,OAAO,CAAC,WAAW,WAAW,GAAG,wBAAwB;AACzE,UAAM,EAAE,SAAS,UAAU,IAAI;AAC/B,QAAI,YAAY,UAAa,OAAO,YAAY,WAAW;AACzD,YAAM,IAAI,aAAa,gBAAgB,WAAW,SAAS,gCAAgC;AAAA,IAC7F;AACA,QAAI,cAAc,WAAc,OAAO,cAAc,YAAY,OAAO,MAAM,SAAS,KAAK,YAAY,IAAI;AAC1G,YAAM,IAAI,aAAa,gBAAgB,UAAU,WAAW,kCAAkC;AAAA,IAChG;AACA,WAAO;AAAA,MACL,SAAS,WAAW;AAAA,MACpB,WAAW,aAAa;AAAA,IAC1B;AAAA,EACF;AAAA,EAEA,iBAAiB,OAAsD;AACrE,QAAI,UAAU,QAAW;AACvB,aAAO;AAAA,QACL,UAAU;AAAA,QACV,OAAO;AAAA,QACP,QAAQ;AAAA,MACV;AAAA,IACF;AACA,QAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AACrD,YAAM,IAAI,aAAa,gBAAgB,UAAU,OAAO,0BAA0B;AAAA,IACpF;AACA,oBAAgB,OAAO,CAAC,YAAY,SAAS,UAAU,qBAAqB,GAAG,0BAA0B;AACzG,UAAM,EAAE,UAAU,OAAO,QAAQ,oBAAoB,IAAI;AACzD,QAAI,aAAa,WAAc,OAAO,aAAa,YAAY,OAAO,MAAM,QAAQ,KAAK,WAAW,IAAI;AACtG,YAAM,IAAI;AAAA,QACR;AAAA,QACA,oBAAoB,2BAA2B;AAAA,QAC/C;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,QAAI,aAAa,UAAa,WAAW,6BAA6B;AACpE,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,QAAI,UAAU,WAAc,OAAO,UAAU,YAAY,CAAC,QAAQ;AAChE,YAAM,IAAI,aAAa,gBAAgB,UAAU,OAAO,gCAAgC;AAAA,IAC1F;AACA,QAAI,WAAW,WAAc,OAAO,WAAW,YAAY,OAAO,MAAM,MAAM,KAAK,SAAS,IAAI;AAC9F,YAAM,IAAI,aAAa,gBAAgB,eAAe,QAAQ,iCAAiC;AAAA,IACjG;AACA,QAAI,wBAAwB,UAAa,OAAO,wBAAwB,YAAY;AAClF,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,MACL,UAAU,YAAY;AAAA,MACtB,OAAO,SAAS;AAAA,MAChB,QAAQ,UAAU;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,iBAAiB,UAAU,MAAM;AAC/B,UAAM,iBAAiB,oBAAI,IAAI;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,UAAM,gBAAgB,oBAAI,IAAI,CAAC,gBAAgB,CAAC;AAChD,UAAM,gBAAgB,oBAAI,IAAI,CAAC,gBAAgB,CAAC;AAChD,UAAM,gBAAgB,oBAAI,IAAI,CAAC,iBAAiB,UAAU,WAAW,WAAW,CAAC;AACjF,UAAM,kBAAkB,oBAAI,IAAI,CAAC,eAAe,CAAC;AAEjD,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,UAAI,UAAU,UAAa,gBAAgB,IAAI,GAAG,EAAG;AACrD,UAAI,QAAQ,aAAa,CAAC,MAAM,QAAQ,KAAK,GAAG;AAC9C,cAAM,IAAI,aAAa,gBAAgB,iBAAiB,OAAO,kBAAkB,GAAG,EAAE;AAAA,MACxF,WAAW,eAAe,IAAI,GAAG,GAAG;AAClC,YAAI,OAAO,UAAU,WAAW;AAC9B,gBAAM,IAAI,aAAa,gBAAgB,WAAW,OAAO,kBAAkB,GAAG,EAAE;AAAA,QAClF;AAAA,MACF,WAAW,cAAc,IAAI,GAAG,GAAG;AACjC,YAAI,OAAO,UAAU,YAAY,OAAO,MAAM,KAAK,GAAG;AACpD,gBAAM,IAAI,aAAa,gBAAgB,UAAU,OAAO,kBAAkB,GAAG,EAAE;AAAA,QACjF;AAAA,MACF,WAAW,cAAc,IAAI,GAAG,GAAG;AACjC,YAAI,OAAO,UAAU,UAAU;AAC7B,gBAAM,IAAI,aAAa,gBAAgB,UAAU,OAAO,kBAAkB,GAAG,EAAE;AAAA,QACjF;AACA,YAAI,CAAC,0BAA0B,SAAS,KAA+B,GAAG;AACxE,gBAAM,IAAI,aAAa,gBAAgB,2BAA2B,OAAO,kBAAkB,GAAG,EAAE;AAAA,QAClG;AAAA,MACF,WAAW,cAAc,IAAI,GAAG,GAAG;AAGjC,YAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AACrD,gBAAM,IAAI,aAAa,gBAAgB,UAAU,OAAO,kBAAkB,GAAG,EAAE;AAAA,QACjF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,cAAc,MAAsB;AAClC,UAAM,OAAmB,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,GAAG,QAAQ,CAAC,EAAE;AAC7D,QAAI,KAAK,QAAQ,MAAM;AACrB,UAAI,KAAK,OAAO,KAAK,OAAQ,MAAK,SAAS,KAAK,OAAO,KAAK;AAC5D,UAAI,KAAK,OAAO,KAAK,MAAO,MAAK,QAAQ,KAAK,OAAO,KAAK;AAC1D,UAAI,KAAK,OAAO,KAAK,OAAQ,MAAK,SAAS,KAAK,OAAO,KAAK;AAAA,IAC9D;AACA,UAAM,OAAO,KAAK,QAAQ,QAAQ;AAClC,QAAI,OAAO,SAAS,UAAU;AAC5B,YAAM,IAAI,aAAa,gBAAgB,UAAU,MAAM,4BAA4B;AAAA,IACrF;AACA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,UAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AACrD,cAAM,IAAI,aAAa,gBAAgB,UAAU,OAAO,yBAAyB,GAAG,EAAE;AAAA,MACxF;AACA,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1C,YACE,OAAO,MAAM,YACb,OAAO,MAAM,YACb,OAAO,MAAM,aACb,CAAC,MAAM,QAAQ,CAAC,KAChB,MAAM,QACN,MAAM,QACN;AACA,gBAAM,IAAI;AAAA,YACR;AAAA,YACA,CAAC,UAAU,UAAU,WAAW,oCAAoC,QAAQ,WAAW;AAAA,YACvF;AAAA,YACA,yBAAyB,GAAG,IAAI,CAAC;AAAA,UACnC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO,EAAE,MAAM,KAAK;AAAA,EACtB;AACF;;;ACvRA,gCAAiC;AAEjC,yBAA0B;AAE1B,IAAAC,gBAAgD;AAChD,IAAAC,6BAA6B;AAoE7B,IAAI,UAAU,QAAQ,IAAI,aAAa;AAShC,IAAM,cAAc,wBAAC,YAAqB;AAC/C,MAAI,QAAS;AACb,QAAM,OAAO,QAAQ,QAAQ,OAAO;AACpC,QAAM,QAAQ,wBAAC,QAAgB,QAAQ,uCAA0B,GAAG,GAAtD;AACd,MAAI;AACF,UAAM,2BAA2B,IAAI,QAAQ;AAC7C,UAAMC,eAAU,qCAAU,MAAM,CAAC,IAAI,GAAG;AAAA,MACtC,aAAa;AAAA,MACb,UAAU;AAAA,IACZ,CAAC;AACD,QAAIA,SAAQ,MAAO,OAAMA,SAAQ;AACjC,QAAIA,SAAQ,UAAU,CAACA,SAAQ,OAAQ,OAAM,IAAI,MAAMA,SAAQ,MAAM;AAErE,UAAM,SAASA,SAAQ,OAAO,KAAK,IAAI;AACvC,UAAMC,WAAU,yBAAyB,KAAK,MAAM,IAAI,CAAC;AACzD,QAAI,CAACA,SAAS,OAAM,IAAI,MAAM,wBAAwB;AACtD,UAAM,0BAA0BA,QAAO,EAAE;AAAA,EAC3C,SAAS,GAAY;AACnB,UAAM,eAAe,aAAa,QAAS,EAAE,SAAS,EAAE,UAAW,OAAO,CAAC;AAC3E,UAAM,qCAAqC,IAAI,MAAM,YAAY,EAAE;AACnE,UAAM,IAAI,aAAa,wBAAwB,IAAI;AAAA,EACrD;AACA,YAAU;AACZ,GAvB2B;AA4BpB,IAAM,gBAAN,cAA4B,wCAGhC;AAAA,EAlHH,OAkHG;AAAA;AAAA;AAAA,EACD;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAST,IAAI,mBAA4B;AAC9B,WAAO,KAAK,OAAO,iBAAiB;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,KAAa,SAAwB;AAC/C,UAAM;AACN,UAAM,EAAE,QAAQ,MAAM,UAAU,IAAI;AACpC,SAAK,WAAW,OAAO,SAAS,YAAY,OAAO,IAAI,OAAO;AAC9D,SAAK,cAAc,OAAO;AAC1B,SAAK,QAAQ,YAAY,KAAK,eAAe,KAAK,QAAQ,SAAS,IAAI,KAAK,iBAAiB,KAAK,QAAQ,IAAI;AAE9G,SAAK,SAAS,IAAI,kBAAkB;AACpC,SAAK,OACF,GAAG,SAAS,MAAM,KAAK,KAAK,CAAC,EAC7B,GAAG,SAAS,SAAO;AAClB,WAAK,MAAM,mBAAmB,IAAI,OAAO,EAAE;AAC3C,WAAK,KAAK,SAAS,GAAG;AAAA,IACxB,CAAC,EACA,GAAG,UAAU,MAAM,KAAK,MAAM,+BAA+B,CAAC;AAEjE,SAAK,oBAAgB,mCAAoB,KAAK,QAAQ;AAAA,MACpD,WAAW,yBAAW;AAAA,MACtB,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEA,aAAa,MAA2B;AACtC,WAAO,OAAO,QAAQ,IAAI,EACvB;AAAA,MAAQ,CAAC,CAAC,KAAK,KAAK,MACnB,MAAM,QAAQ,KAAK,IACf,MAAM,OAAO,OAAO,EAAE,IAAI,OAAK,CAAC,IAAI,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,IACrD,SAAS,QAAQ,UAAU,QACzB,CAAC,IACD,CAAC,UAAU,OAAO,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,OAAO,KAAK,CAAC,CAAC;AAAA,IAChE,EACC,KAAK;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,WAAW,KAAiC;AAC1C,UAAM,UAAU,IAAI,IAAI,GAAG;AAC3B,QAAI,QAAQ,aAAa,QAAS,QAAO;AACzC,UAAM,WAAW,mBAAmB,QAAQ,QAAQ;AACpD,QAAI,QAAQ,SAAU,QAAO,KAAK,QAAQ,QAAQ,GAAG,QAAQ;AAC7D,WAAO,iBAAiB,KAAK,QAAQ,IAAI,SAAS,MAAM,CAAC,IAAI;AAAA,EAC/D;AAAA,EAEA,iBAAiB,KAAa,QAAuB,MAAyB;AAC5E,UAAM,OAAkB;AAAA,MACtB,WAAW;AAAA,MACX,oBAAoB;AAAA,MACpB,qBAAqB;AAAA,MACrB,iBAAiB;AAAA,MACjB,aAAa;AAAA,MACb,GAAG,OAAO,KAAK;AAAA,MACf,GAAG,OAAO,KAAK;AAAA,MACf,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,GAAG,OAAO,KAAK;AAAA,MACf,GAAG;AAAA,IACL;AAEA,QAAI,OAAO,SAAS,YAAY,OAAO,EAAG,MAAK,KAAK,KAAK,SAAS;AAElE,UAAM,YAAY,KAAK,WAAW,GAAG;AACrC,QAAI,cAAc,QAAW;AAC3B,WAAK,YAAY;AACjB,WAAK,qBAAqB;AAC1B,WAAK,sBAAsB;AAC3B,WAAK,IAAI;AAAA,IACX;AAEA,WAAO,CAAC,GAAG,KAAK,aAAa,IAAI,GAAG,QAAQ;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,eAAe,KAAa,QAAuB,WAA6C;AAC9F,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,UAAU;AAAA,IACZ,IAAI;AAGJ,UAAM,aAAwB,EAAE,GAAG,OAAO,KAAK,OAAO;AACtD,UAAM,eACJ,OAAO,WAAW,OAAO,WACrB,WAAW,KACX,MAAM,QAAQ,WAAW,EAAE,IACzB,WAAW,GAAG,OAAO,OAAO,EAAE,KAAK,GAAG,IACtC;AACR,WAAO,WAAW;AAElB,UAAM,cAAyB;AAAA,MAC7B,aAAa;AAAA,MACb,GAAG,OAAO,KAAK;AAAA,MACf,GAAI,UAAU,oBAAoB;AAAA,QAChC,WAAW;AAAA,QACX,oBAAoB;AAAA,QACpB,qBAAqB;AAAA,QACrB,iBAAiB;AAAA,QACjB,GAAG,OAAO,KAAK;AAAA,MACjB;AAAA,MACA,IAAI,OAAO,gBAAgB,YAAY,cAAc,IAAI,YAAY,SAAS,IAAI;AAAA,MAClF,GAAG;AAAA,IACL;AACA,UAAM,gBAA2B;AAAA,MAC/B,WAAW;AAAA,MACX,oBAAoB;AAAA,MACpB,qBAAqB;AAAA,MACrB,iBAAiB;AAAA,MACjB,GAAG,OAAO,KAAK;AAAA,MACf,GAAG;AAAA,IACL;AAIA,UAAM,eAAe,KAAK,WAAW,GAAG;AACxC,QAAI,iBAAiB,QAAW;AAC9B,kBAAY,YAAY;AACxB,kBAAY,qBAAqB;AACjC,kBAAY,sBAAsB;AAClC,kBAAY,IAAI;AAAA,IAClB;AACA,UAAM,iBAAiB,KAAK,WAAW,YAAY;AACnD,QAAI,mBAAmB,QAAW;AAChC,oBAAc,YAAY;AAC1B,oBAAc,qBAAqB;AACnC,oBAAc,sBAAsB;AACpC,oBAAc,IAAI;AAAA,IACpB;AAEA,UAAM,YAAY,aAAa,iBAAiB;AAChD,UAAM,OAAO,wBAAwB,QAAQ,OAAO,QAAQ,OAAO,OAAO;AAC1E,UAAM,QAAQ;AAAA,MACZ,QAAQ,SAAS;AAAA,MACjB,QAAQ,SAAS;AAAA,MACjB;AAAA,MACA,GAAI,eAAe,CAAC,OAAO,YAAY,QAAQ,IAAI,CAAC;AAAA,IACtD,EAAE,KAAK,GAAG;AAEV,UAAM,aAAwB;AAAA,MAC5B,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,GAAG;AAAA,MACH,gBAAgB;AAAA,MAChB,KAAK,eAAe,WAAW;AAAA,MAC/B,GAAG;AAAA,IACL;AAEA,WAAO;AAAA,MACL,GAAG,KAAK,aAAa,WAAW;AAAA,MAChC,GAAG,KAAK,aAAa,aAAa;AAAA,MAClC,GAAG,KAAK,aAAa,UAAU;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAQ;AACN,SAAK,MAAM,oBAAoB,KAAK,WAAW,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC,EAAE;AACzE,SAAK,cAAU,iCAAM,KAAK,aAAa,KAAK,OAAO;AAAA,MACjD,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAChC,OAAO;AAAA,MACP,aAAa;AAAA,IACf,CAAC,EACE,GAAG,SAAS,SAAO;AAClB,WAAK,MAAM,oBAAoB,IAAI,OAAO,EAAE;AAC5C,WAAK,KAAK,SAAS,GAAG;AAAA,IACxB,CAAC,EACA,GAAG,QAAQ,CAAC,MAAM,WAAW;AAC5B,WAAK,MAAM,wBAAwB,QAAQ,SAAS,WAAW,UAAU,SAAS,EAAE;AACpF,UAAI,CAAC,QAAQ,CAAC,GAAG,GAAG,EAAE,SAAS,IAAI,EAAG;AACtC,WAAK,MAAM,4CAA4C,IAAI,EAAE;AAC7D,WAAK,KAAK,SAAS,IAAI,aAAa,iBAAiB,IAAI,CAAC;AAAA,IAC5D,CAAC;AAEH,QAAI,CAAC,KAAK,QAAQ,UAAU,CAAC,KAAK,QAAQ,QAAQ;AAChD,WAAK,KAAK;AACV,YAAM,IAAI,MAAM,iCAAiC;AAAA,IACnD;AAEA,SAAK,QAAQ,OAAO,KAAK,KAAK,MAAM;AACpC,SAAK,QAAQ,OAAO,YAAY,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAiB;AACpE,YAAM,QAAQ,KAAK,MAAM,aAAa;AACtC,iBAAW,QAAQ,OAAO;AACxB,YAAI,QAAQ,KAAK,IAAI,EAAG;AACxB,aAAK,MAAM,iBAAiB,IAAI,EAAE;AAAA,MACpC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,MAAM,OAAe;AAC3B,SAAK,KAAK,SAAS,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAU,QAAgB;AACxB,SAAK,OAAO,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO;AACL,QAAI,CAAC,KAAK,OAAO,UAAW,MAAK,OAAO,QAAQ;AAChD,QAAI,KAAK,WAAW,CAAC,KAAK,QAAQ,OAAQ,MAAK,QAAQ,KAAK,SAAS;AAAA,EACvE;AACF;AAGA,IAAM,oBAAN,cAAgC,6BAAU;AAAA,EAjY1C,OAiY0C;AAAA;AAAA;AAAA,EAChC,SAAS,OAAO,YAAY,CAAC;AAAA,EACpB,UAAU,CAAC,EAAE,MAAM,KAAK,KAAK,MAAM,KAAK,KAAK,CAAC;AAAA,EAC/D,MAAM;AAAA,EAEG,WAAW,UAAkB,WAA2B,MAA+B;AAC9F,UAAM,EAAE,IAAI,IAAI;AAChB,QAAI,QAAQ,GAAG;AACb,WAAK,KAAK,QAAQ;AAClB,WAAK;AACL;AAAA,IACF;AAEA,UAAM,QAAQ;AACd,UAAM,QAAQ,OAAO,OAAO,CAAC,KAAK,QAAQ,QAAQ,CAAC;AACnD,UAAM,iBAAiB,KAAK,MAAM,MAAM,SAAS,KAAK,IAAI;AAE1D,aAAS,IAAI,GAAG,IAAI,gBAAgB,KAAK,OAAO;AAC9C,YAAM,QAAQ,MAAM,YAAY,CAAC;AACjC,YAAM,eAAe,KAAK,IAAI,KAAK,QAAQ,CAAC,GAAG,KAAK,IAAI,KAAK,QAAQ,CAAC,GAAG,QAAQ,GAAG,CAAC;AACrF,YAAM,aAAa,cAAc,CAAC;AAAA,IACpC;AAEA,SAAK,SAAS,MAAM,SAAS,cAAc;AAC3C,SAAK,KAAK,MAAM,SAAS,GAAG,cAAc,CAAC;AAC3C,SAAK;AAAA,EACP;AACF;;;AC5ZA,IAAAC,gBAA0D;;;ACOnD,IAAe,iBAAf,cAAyC,YAAe;AAAA,EAP/D,OAO+D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAU7D,IAAI,cAAiC,MAAS;AAC5C,UAAM,KAAK,eAAe,YAAY;AACtC,UAAM,WAAW,KAAK,IAAI,EAAE;AAC5B,QAAI,SAAU,QAAO;AACrB,SAAK,WAAW,IAAI,IAAI,IAAI;AAC5B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,cAAgD;AAClD,WAAO,KAAK,WAAW,IAAI,eAAe,YAAY,CAAC;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,cAA0C;AAC/C,WAAO,KAAK,WAAW,OAAO,eAAe,YAAY,CAAC;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,cAA0C;AAC5C,WAAO,KAAK,WAAW,IAAI,eAAe,YAAY,CAAC;AAAA,EACzD;AACF;;;ADzCO,IAAM,sBAAN,cAAkC,eAA6B;AAAA,EAVtE,OAUsE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQpE,OAAO,SAA0C;AAC/C,UAAM,WAAW,KAAK,IAAI,QAAQ,OAAO;AACzC,QAAI,UAAU;AACZ,eAAS,UAAU;AACnB,aAAO;AAAA,IACT;AACA,YACE,kCAAmB,eAAe,OAAO,GAAG,KAAK,OAAO,MAAM,EAAE,SAChE,kCAAmB,eAAe,OAAO,CAAC,GAC1C;AACA,YAAM,IAAI,aAAa,uBAAuB;AAAA,IAChD;AACA,WAAO,IAAI,aAAa,MAAM,OAAO;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,KAAK,SAAmD;AACtD,UAAM,WAAW,KAAK,IAAI,QAAQ,OAAO;AACzC,QAAI,SAAU,QAAO,SAAS,KAAK,OAAO;AAC1C,WAAO,KAAK,OAAO,OAAO,EAAE,KAAK;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAA0B;AAC9B,UAAM,QAAQ,KAAK,IAAI,KAAK;AAC5B,QAAI,OAAO;AACT,YAAM,MAAM;AAAA,IACd,OAAO;AACL,YAAM,iBACJ,kCAAmB,eAAe,KAAK,GAAG,KAAK,OAAO,MAAM,EAAE,SAAK,kCAAmB,eAAe,KAAK,CAAC;AAC7G,UAAI,cAAc,WAAW,MAAM,WAAW,oCAAsB,WAAW;AAC7E,mBAAW,QAAQ;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AACF;;;AE3CO,IAAM,eAAN,cAA2B,eAAsB;AAAA,EAjBxD,OAiBwD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAStD,MAAM,OAAO,SAA4B,aAAqD;AAC5F,QAAI,KAAK,IAAI,QAAQ,OAAO,EAAG,OAAM,IAAI,aAAa,aAAa;AACnE,SAAK,MAAM,4CAA4C,QAAQ,OAAO,EAAE;AACxE,UAAM,QAAQ,KAAK,OAAO,OAAO,OAAO;AACxC,UAAM,QAAQ,IAAI,MAAM,KAAK,SAAS,OAAO,WAAW;AACxD,UAAM,MAAM,WAAW,QAAQ;AAC/B,QAAI;AACF,kBAAY,KAAK,OAAO;AACxB,WAAK,MAAM,yCAAyC,QAAQ,EAAE,EAAE;AAChE,YAAM,MAAM,KAAK;AACjB,WAAK,mBAAmB,KAAK;AAC7B,WAAK,IAAI,MAAM,IAAI,KAAK;AACxB,WAAK,mCAAwB,KAAK;AAClC,aAAO;AAAA,IACT,UAAE;AACA,YAAM,WAAW,QAAQ;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAmB,OAAc;AAC/B,UAAM,aAAa;AAAA,MACjB,YAAY,kCAAS;AACnB,cAAM,OAAO;AACb,aAAK,oCAAwB,KAAK;AAClC,YAAI,MAAO,MAAK,UAAU,OAAO,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA,MAC1D,GAJY;AAAA,MAKZ,OAAO,kCAAS,KAAK,KAAK,oBAAoB,OAAO,KAAK,GAAnD;AAAA,MACP,QAAQ,6BAAM,KAAK,KAAK,iBAAiB,KAAK,GAAtC;AAAA,MACR,eAAe,wBAAC,YAAY,eAAe;AACzC,aAAK,sDAAkC,OAAO,YAAY,UAAU;AAAA,MACtE,GAFe;AAAA,IAGjB;AACA,eAAW,SAAS,WAAW,MAAM,UAAU,GAAG;AAChD,YAAM,MAAM,GAAG,OAAO,MAAM,WAAW,KAAK,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBAAiB,OAA6B;AAClD,QAAI,MAAM,eAAe;AACvB,YAAM,gBAAgB;AACtB,YAAM,KAAK,SAAS,KAAK;AACzB;AAAA,IACF;AACA,SAAK,MAAM,wCAAwC,MAAM,EAAE,EAAE;AAC7D,UAAM,OAAO,MAAM,MAAM,CAAC;AAC1B,SAAK,qCAAyB,OAAO,IAAI;AACzC,UAAM,MAAM,WAAW,QAAQ;AAC/B,QAAI;AACF,UAAI,MAAM,QAAS;AACnB,UAAI,MAAM,6BAAiC,OAAM,MAAM,KAAK,IAAI;AAEhE,UAAI,MAAM,6BAAgC;AACxC,cAAM,OAAO,MAAM,MAAM,MAAM;AAC/B,YAAI,KAAK,QAAQ,kBAAmB,OAAM,cAAc,KAAK,IAAI;AAAA,YAC5D,OAAM,cAAc,KAAK,EAAE,IAAI,KAAK,GAAG,CAAS;AAAA,MACvD;AAEA,UAAI,MAAM,MAAM,WAAW,KAAK,MAAM,UAAU;AAC9C,YAAI;AACF,eAAK,MAAM,uCAAuC,MAAM,EAAE,EAAE;AAC5D,gBAAM,MAAM,gBAAgB,IAAI;AAAA,QAClC,SAAS,GAAY;AACnB,gBAAM,eAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAC9D,eAAK,MAAM,IAAI,MAAM,EAAE,6BAA6B,YAAY,EAAE;AAClE,cAAI,aAAa,cAAc;AAC7B,iBAAK,mCAAwB,OAAO,CAAC;AAAA,UACvC,OAAO;AACL,iBAAK,mCAAwB,OAAO,IAAI,aAAa,YAAY,CAAC;AAAA,UACpE;AAAA,QACF;AAAA,MACF;AAEA,UAAI,MAAM,MAAM,WAAW,GAAG;AAC5B,aAAK,MAAM,IAAI,MAAM,EAAE,+BAA+B;AACtD,aAAK,0BAAmB,KAAK;AAC7B,YAAI,CAAC,MAAM,SAAU,MAAK,4BAAoB,KAAK;AACnD,cAAM,OAAO;AACb;AAAA,MACF;AAEA,UAAI,SAAS,MAAM,MAAM,CAAC,GAAG;AAC3B,cAAM,aAAa,KAAK,OAAO,iBAAiB,OAAO,KAAK,OAAO;AACnE,YAAI,YAAY,OAAO,eAAgB,QAAO,WAAW,OAAO;AAAA,MAClE;AACA,YAAM,KAAK,SAAS,OAAO,IAAI;AAAA,IACjC,UAAE;AACA,YAAM,WAAW,QAAQ;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,oBAAoB,OAAc,OAAc;AACpD,UAAM,OAAO,MAAM,MAAM,MAAM;AAC/B,QAAI;AACF,YAAM,OAAO;AAAA,IACf,QAAQ;AAAA,IAER;AACA,SAAK,MAAM,IAAI,MAAM,EAAE,0BAA0B,MAAM,SAAS,MAAM,OAAO,EAAE;AAC/E,SAAK,UAAU,OAAO,OAAO,IAAI;AACjC,QAAI,MAAM,MAAM,SAAS,GAAG;AAC1B,WAAK,MAAM,IAAI,MAAM,EAAE,wBAAwB,MAAM,MAAM,CAAC,CAAC,EAAE;AAC/D,YAAM,KAAK,SAAS,KAAK;AAAA,IAC3B,OAAO;AACL,WAAK,MAAM,IAAI,MAAM,EAAE,+BAA+B;AACtD,YAAM,MAAM,KAAK;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,SAAS,OAAc,eAAe,MAAM,SAAyC;AACzF,QAAI,CAAC,MAAO;AACZ,QAAI,MAAM,WAAW,CAAC,MAAM,MAAM,QAAQ;AACxC,YAAM,MAAM,KAAK;AACjB;AAAA,IACF;AACA,QAAI;AACF,YAAM,OAAO,MAAM,MAAM,CAAC;AAC1B,UAAI;AAEJ,UAAI,MAAM,mBAAmB,QAAQ,MAAM,kBAAkB;AAC3D,aAAK,MAAM,IAAI,MAAM,EAAE,iCAAiC,IAAI,EAAE;AAC9D,mBAAW,MAAM;AACjB,cAAM,iBAAiB;AACvB,cAAM,mBAAmB;AAAA,MAC3B,OAAO;AACL,cAAM,cAAc;AACpB,aAAK,MAAM,IAAI,MAAM,EAAE,0BAA0B,IAAI,EAAE;AACvD,cAAM,KAAK,QAAQ,iBAAiB,IAAI;AACxC,cAAM,eAAe,KAAK,OAAO,iBAAiB,OAAO,KAAK,OAAO;AACrE,cAAM,SAAS,cAAc;AAC7B,YAAI,CAAC,gBAAgB,CAAC,QAAQ,kBAAkB,CAAC,OAAO,IAAK,OAAM,IAAI,aAAa,iBAAiB,GAAG,IAAI,EAAE;AAC9G,aAAK,MAAM,IAAI,MAAM,EAAE,iCAAiC,YAAY,EAAE;AACtE,cAAM,gBAAgB;AAAA,UACpB,QAAQ;AAAA,YACN,MAAM,KAAK,QAAQ,OAAO;AAAA,YAC1B,MAAM;AAAA,cACJ,QAAQ,EAAE,GAAG,MAAM,WAAW,OAAO;AAAA,cACrC,OAAO,EAAE,GAAG,MAAM,WAAW,MAAM;AAAA,cACnC,QAAQ,EAAE,GAAG,MAAM,WAAW,QAAQ,GAAG,MAAM,QAAQ,WAAW;AAAA,YACpE;AAAA,UACF;AAAA,UACA,MAAM,aAAa,WAAW,MAAM,aAAa;AAAA,QACnD;AACA,cAAM,aAAa;AACnB,mBAAW,IAAI,cAAc,OAAO,KAAK,aAAa;AACtD,iBAAS,GAAG,SAAS,UAAQ,KAAK,uCAA0B,IAAI,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;AAAA,MACtF;AAEA,YAAM,aAAa;AACnB,WAAK,MAAM,IAAI,MAAM,EAAE,sBAAsB,IAAI,EAAE;AACnD,YAAM,MAAM,MAAM,KAAK,QAAQ;AAC/B,UAAI,aAAc,MAAK,iCAAuB,OAAO,IAAI;AACzD,WAAK,gBAAgB,KAAK;AAC1B,WAAK,kBAAkB,KAAK;AAAA,IAC9B,SAAS,GAAY;AACnB,YAAM,QAAQ,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC;AAC1D,UAAI,SAAS,iBAAiB;AAG5B,aAAK,MAAM,IAAI,MAAM,EAAE,wCAAwC,MAAM,SAAS,MAAM,OAAO,EAAE;AAC7F,aAAK,UAAU,OAAO,OAAO,MAAM,MAAM,CAAC,CAAC;AAC3C;AAAA,MACF;AACA,YAAM,KAAK,oBAAoB,OAAO,KAAK;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,OAAc;AAC5B,QAAI,CAAC,KAAK,QAAQ,QAAQ,WAAW,MAAM,WAAW,MAAM,OAAQ;AACpE,QAAI,MAAM,iBAAiB;AACzB,mBAAa,MAAM,eAAe;AAClC,YAAM,kBAAkB;AAAA,IAC1B;AAEA,UAAM,cAAc,MAAM,MAAM,CAAC;AACjC,UAAM,WAAW,MAAM,MAAM,CAAC;AAC9B,QAAI,CAAC,eAAe,CAAC,SAAU;AAE/B,QAAI,MAAM,mBAAmB,YAAY,MAAM,iBAAkB;AAEjE,UAAM,YAAY,KAAK,QAAQ,QAAQ;AACvC,UAAM,WAAW,YAAY,YAAY;AACzC,UAAM,cAAc,MAAM;AAC1B,UAAM,YAAY,WAAW,KAAK,OAAO,SAAS,WAAW,IAAI,WAAW,cAAc;AAE1F,QAAI,aAAa,KAAK,aAAa,WAAW;AAC5C,WAAK,KAAK,gBAAgB,KAAK;AAAA,IACjC,OAAO;AACL,YAAM,UAAU,KAAK,IAAI,IAAI,YAAY,aAAa,GAAI;AAC1D,YAAM,kBAAkB,WAAW,MAAM;AACvC,cAAM,kBAAkB;AACxB,aAAK,KAAK,gBAAgB,KAAK;AAAA,MACjC,GAAG,OAAO;AACV,YAAM,gBAAgB,QAAQ;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAgB,OAAc;AAGlC,QAAI,MAAM,YAAa,QAAO,MAAM;AACpC,UAAM,OAAO,KAAK,aAAa,KAAK;AACpC,UAAM,cAAc;AACpB,QAAI;AACF,YAAM;AAAA,IACR,UAAE;AACA,UAAI,MAAM,gBAAgB,KAAM,OAAM,cAAc;AAAA,IACtD;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,OAAc;AAC/B,QAAI,CAAC,KAAK,QAAQ,QAAQ,WAAW,MAAM,WAAW,MAAM,OAAQ;AACpE,UAAM,WAAW,MAAM,MAAM,CAAC;AAC9B,QAAI,CAAC,SAAU;AACf,QAAI,MAAM,mBAAmB,YAAY,MAAM,iBAAkB;AAGjE,UAAM,aAAa,MAAM;AAEzB,SAAK,MAAM,IAAI,MAAM,EAAE,2BAA2B,QAAQ,EAAE;AAC5D,SAAK,uCAA0B,OAAO,QAAQ;AAE9C,QAAI;AACF,YAAM,KAAK,QAAQ,iBAAiB,QAAQ;AAE5C,UAAI,MAAM,WAAW,MAAM,MAAM,CAAC,MAAM,YAAY,eAAe,MAAM,mBAAoB;AAE7F,YAAM,eAAe,SAAS,OAAO,iBAAiB,WAAW,SAAS,OAAO;AACjF,YAAM,SAAS,cAAc;AAC7B,UAAI,CAAC,gBAAgB,CAAC,QAAQ,kBAAkB,CAAC,OAAO,KAAK;AAC3D,cAAM,IAAI,aAAa,iBAAiB,GAAG,QAAQ,EAAE;AAAA,MACvD;AAEA,YAAM,gBAAgB;AAAA,QACpB,QAAQ;AAAA,UACN,MAAM,KAAK,QAAQ,OAAO;AAAA,UAC1B,MAAM;AAAA,YACJ,QAAQ,EAAE,GAAG,MAAM,WAAW,OAAO;AAAA,YACrC,OAAO,EAAE,GAAG,MAAM,WAAW,MAAM;AAAA,YACnC,QAAQ,EAAE,GAAG,MAAM,WAAW,QAAQ,GAAG,MAAM,QAAQ,WAAW;AAAA,UACpE;AAAA,QACF;AAAA,QACA,MAAM;AAAA,MACR;AAEA,YAAM,WAAW,IAAI,cAAc,OAAO,KAAK,aAAa;AAC5D,eAAS,GAAG,SAAS,UAAQ,KAAK,uCAA0B,IAAI,MAAM,EAAE,eAAe,IAAI,EAAE,CAAC;AAE9F,UAAI,MAAM,WAAW,MAAM,MAAM,CAAC,MAAM,YAAY,eAAe,MAAM,oBAAoB;AAC3F,iBAAS,KAAK;AACd;AAAA,MACF;AAEA,YAAM,iBAAiB;AACvB,YAAM,mBAAmB;AAEzB,WAAK,MAAM,IAAI,MAAM,EAAE,uCAAuC,QAAQ,EAAE;AACxE,WAAK,2CAA4B,OAAO,QAAQ;AAAA,IAClD,SAAS,GAAY;AACnB,UAAI,MAAM,mBAAmB,UAAU;AACrC,cAAM,iBAAiB;AACvB,cAAM,kBAAkB,KAAK;AAC7B,cAAM,mBAAmB;AAAA,MAC3B;AACA,YAAM,QAAQ,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC;AAC1D,WAAK,MAAM,IAAI,MAAM,EAAE,wBAAwB,QAAQ,KAAK,MAAM,OAAO,EAAE;AAC3E,WAAK,yCAA2B,OAAO,UAAU,KAAK;AAAA,IACxD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,kBAAkB,OAAc;AAC9B,UAAM,iBAAiB;AACvB,QAAI,MAAM,WAAW,MAAM,OAAQ;AACnC,UAAM,cAAc,MAAM,MAAM,CAAC;AACjC,QAAI,CAAC,YAAa;AAClB,UAAM,eAAe,YAAY,YAAY;AAE7C,QAAI,CAAC,gBAAgB,CAAC,OAAO,SAAS,YAAY,EAAG;AACrD,UAAM,OAAO,KAAK,IAAI,OAAO,MAAM,SAAS,KAAK,GAAG,YAAY;AAChE,QAAI,QAAQ,EAAG;AACf,UAAM,WAAW,MAAM,8BAAiC,cAAc,MAAM,MAAM,CAAC;AACnF,QAAI,CAAC,SAAU;AACf,UAAM,cAAc,MAAM;AAC1B,QAAI,CAAC,OAAO,SAAS,WAAW,EAAG;AACnC,UAAM,YAAY,eAAe;AACjC,QAAI,aAAa,KAAM;AACvB,UAAM,UAAU,KAAK,IAAI,IAAI,YAAY,OAAO,KAAK,QAAQ,UAAU,UAAU,GAAI;AACrF,SAAK;AAAA,MACH,IAAI,MAAM,EAAE,2BAA2B,IAAI,eAAe,UAAU,KAAM,QAAQ,CAAC,CAAC,MAAM,WAAW,OAAO,QAAQ;AAAA,IACtH;AACA,UAAM,oBAAoB,WAAW,MAAM;AACzC,YAAM,oBAAoB;AAC1B,WAAK,KAAK,qBAAqB,KAAK;AAAA,IACtC,GAAG,OAAO;AACV,UAAM,kBAAkB,QAAQ;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,qBAAqB,OAAc;AACvC,QAAI;AACJ,QAAI;AACF,UAAI,MAAM,WAAW,MAAM,OAAQ;AACnC,YAAM,OAAO,MAAM,MAAM,CAAC;AAC1B,YAAM,aAAa,MAAM;AACzB,YAAM,aAAa,MAAM;AACzB,YAAM,WAAW,aAAa,OAAO,MAAM,MAAM,CAAC;AAClD,UAAI,CAAC,QAAQ,CAAC,SAAU;AACxB,YAAM,eAAe,KAAK,YAAY;AACtC,YAAM,OAAO,KAAK,IAAI,OAAO,MAAM,SAAS,KAAK,GAAG,YAAY;AAChE,UAAI,QAAQ,EAAG;AACf,YAAM,YAAY,eAAe,MAAM;AACvC,UAAI,aAAa,KAAM;AACvB,UAAI,CAAC,YAAY;AAGf,YAAI,KAAK,QAAQ,QAAQ,QAAS,OAAM,KAAK,gBAAgB,KAAK;AAAA,YAC7D,OAAM,KAAK,QAAQ,iBAAiB,QAAQ;AAAA,MACnD;AACA,UAAI,MAAM,WAAW,MAAM,UAAU,MAAM,MAAM,CAAC,MAAM,QAAQ,eAAe,MAAM,mBAAoB;AACzG,UAAI,aAAa,MAAM,MAAM,CAAC,MAAM,OAAO,MAAM,MAAM,CAAC,MAAM,SAAU;AAExE,YAAM,UAAU,KAAK,OAAO,iBAAiB,OAAO,KAAK,OAAO;AAChE,YAAM,YAAY,aAAa,UAAU,SAAS,OAAO,iBAAiB,WAAW,SAAS,OAAO;AACrG,UAAI,CAAC,SAAS,OAAO,kBAAkB,CAAC,QAAQ,OAAO,IAAK;AAC5D,UAAI,CAAC,WAAW,OAAO,kBAAkB,CAAC,UAAU,OAAO,IAAK;AAEhE,WAAK,MAAM,IAAI,MAAM,EAAE,kCAAkC,IAAI,OAAO,QAAQ,EAAE;AAC9E,YAAM,eAAe,KAAK,IAAI,GAAG,eAAe,IAAI;AACpD,UAAI,aAAqB,QAAQ,OAAO;AACxC,UAAI,cAAc;AAClB,UAAI;AACJ,YAAM,UAAU,KAAK,QAAQ,UAAU;AACvC,UAAI,SAAS;AACX,YAAI;AACF,gBAAM,WAAW,MAAM,QAAQ,QAAQ,OAAO,KAAK,EAAE,MAAM,cAAc,KAAK,CAAC;AAC/E,cAAI,UAAU,KAAK;AACjB,yBAAa,SAAS;AACtB,gBAAI,OAAO,SAAS,SAAS,YAAY,OAAO,SAAS,SAAS,IAAI,KAAK,SAAS,QAAQ,GAAG;AAC7F,4BAAc,SAAS;AAAA,YACzB;AACA,+BAAmB,SAAS;AAC5B,iBAAK,MAAM,IAAI,MAAM,EAAE,mDAAmD;AAAA,UAC5E;AAAA,QACF,SAAS,GAAY;AAEnB,gBAAM,eAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAC9D,eAAK,MAAM,IAAI,MAAM,EAAE,iDAAiD,YAAY,EAAE;AAAA,QACxF;AAAA,MACF;AACA,yBAAmB,IAAI,cAAc,YAAY;AAAA,QAC/C,QAAQ;AAAA,UACN,MAAM,KAAK,QAAQ,OAAO;AAAA,UAC1B,MAAM;AAAA,YACJ,QAAQ,EAAE,GAAG,MAAM,WAAW,OAAO;AAAA,YACrC,OAAO,EAAE,GAAG,MAAM,WAAW,MAAM;AAAA,YACnC,QAAQ,EAAE,GAAG,MAAM,WAAW,QAAQ,GAAG,MAAM,QAAQ,WAAW;AAAA,UACpE;AAAA,QACF;AAAA,QACA,WAAW;AAAA,UACT,UAAU;AAAA,UACV;AAAA,UACA,cAAc,UAAU,OAAO;AAAA,UAC/B,SAAS,KAAK,QAAQ,UAAU;AAAA,UAChC,UAAU,KAAK,QAAQ,UAAU;AAAA,UACjC;AAAA,QACF;AAAA,MACF,CAAC;AACD,uBAAiB,GAAG,SAAS,UAAQ,KAAK,uCAA0B,IAAI,MAAM,EAAE,iBAAiB,IAAI,EAAE,CAAC;AAExG,UAAI,MAAM,WAAW,MAAM,UAAU,MAAM,MAAM,CAAC,MAAM,QAAQ,eAAe,MAAM,oBAAoB;AACvG,yBAAiB,KAAK;AACtB;AAAA,MACF;AACA,YAAM,mBAAmB;AAGzB,uBAAiB,MAAM;AAEvB,YAAM,aAAa,KAAK,IAAI,IAAI,eAAe,MAAM,cAAc,QAAQ,GAAI;AAC/E,YAAM,oBAAoB,WAAW,MAAM;AACzC,cAAM,oBAAoB;AAC1B,aAAK,KAAK,mBAAmB,OAAO,gBAAiB;AAAA,MACvD,GAAG,UAAU;AACb,YAAM,kBAAkB,QAAQ;AAAA,IAClC,SAAS,GAAY;AAEnB,YAAM,eAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAC9D,WAAK,MAAM,IAAI,MAAM,EAAE,4DAA4D,YAAY,EAAE;AACjG,UAAI,iBAAkB,kBAAiB,KAAK;AAAA,IAC9C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,mBAAmB,OAAc,kBAAiC;AACtE,UAAM,QAAQ,6BAAM;AAClB,UAAI,MAAM,qBAAqB,iBAAkB,OAAM,mBAAmB;AAC1E,uBAAiB,KAAK;AAAA,IACxB,GAHc;AAId,QAAI;AACF,UAAI,MAAM,WAAW,MAAM,UAAU,MAAM,qBAAqB,iBAAkB,QAAO,MAAM;AAC/F,YAAM,OAAO,MAAM,MAAM,CAAC;AAC1B,UAAI,CAAC,KAAM,QAAO,MAAM;AACxB,YAAM,eAAe,KAAK,YAAY;AACtC,YAAM,OAAO,KAAK,IAAI,OAAO,MAAM,SAAS,KAAK,GAAG,YAAY;AAChE,UAAI,QAAQ,EAAG,QAAO,MAAM;AAG5B,YAAM,QAAQ,MAAM,eAAe,eAAe;AAClD,UAAI,KAAK,IAAI,KAAK,IAAI,gCAAgC;AACpD,aAAK,MAAM,IAAI,MAAM,EAAE,yCAAyC,MAAM,QAAQ,CAAC,CAAC,0BAA0B;AAC1G,eAAO,MAAM;AAAA,MACf;AAEA,YAAM,MAAM,WAAW,QAAQ;AAC/B,UAAI;AACF,YAAI,MAAM,WAAW,MAAM,UAAU,MAAM,MAAM,CAAC,MAAM,QAAQ,MAAM,qBAAqB,kBAAkB;AAC3G,iBAAO,MAAM;AAAA,QACf;AAKA,YAAI,CAAC,iBAAiB,kBAAkB;AACtC,eAAK,MAAM,IAAI,MAAM,EAAE,yDAAyD;AAChF,iBAAO,MAAM;AAAA,QACf;AACA,aAAK,MAAM,IAAI,MAAM,EAAE,yBAAyB,IAAI,OAAO,MAAM,MAAM,SAAS,IAAI,MAAM,MAAM,CAAC,IAAI,IAAI,EAAE;AAC3G,cAAM,MAAM,MAAM,KAAK,gBAAgB;AACvC,cAAM,mBAAmB;AAGzB,aAAK,qCAAyB,OAAO,IAAI;AACzC,YAAI,MAAM,6BAAiC,OAAM,MAAM,KAAK,IAAI;AAChE,YAAI,MAAM,6BAAgC;AACxC,gBAAM,OAAO,MAAM,MAAM,MAAM;AAC/B,cAAI,KAAK,QAAQ,kBAAmB,OAAM,cAAc,KAAK,IAAI;AAAA,cAC5D,OAAM,cAAc,KAAK,EAAE,IAAI,KAAK,GAAG,CAAS;AAAA,QACvD,OAAO;AAAA,QAGP;AACA,YAAI,SAAS,MAAM,MAAM,CAAC,GAAG;AAC3B,gBAAM,aAAa,KAAK,OAAO,iBAAiB,OAAO,KAAK,OAAO;AACnE,cAAI,YAAY,OAAO,eAAgB,QAAO,WAAW,OAAO;AAAA,QAClE;AAGA,YAAI,MAAM,kBAAkB;AAC1B,gBAAM,iBAAiB,KAAK;AAC5B,gBAAM,mBAAmB;AACzB,gBAAM,iBAAiB;AAAA,QACzB;AACA,aAAK,iCAAuB,OAAO,MAAM,MAAM,CAAC,CAAC;AACjD,aAAK,gBAAgB,KAAK;AAC1B,aAAK,kBAAkB,KAAK;AAAA,MAC9B,UAAE;AACA,cAAM,WAAW,QAAQ;AAAA,MAC3B;AAAA,IACF,SAAS,GAAY;AACnB,YAAM;AAGN,YAAM,eAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAC9D,WAAK,MAAM,IAAI,MAAM,EAAE,0DAA0D,YAAY,EAAE;AAAA,IACjG;AAAA,EACF;AACF;;;AC3hBA,yBAA4B;AAC5B,uBAAqF;AACrF,IAAAC,sBAAyB;AA2FzB,IAAM,aAAa,wBAAC,WAAuC;AACzD,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,QAAQ,iBAAiB,KAAK,MAAM;AAC1C,SAAO,QAAQ,OAAO,MAAM,CAAC,CAAC,IAAI;AACpC,GAJmB;AAiBZ,IAAM,eAAN,MAAmB;AAAA,EA9G1B,OA8G0B;AAAA;AAAA;AAAA,EACf,YAAY,oBAAI,IAA2B;AAAA,EAC3C;AAAA,EACA;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,EAKV,YAAY,EAAE,OAAO,GAAG,OAAO,IAAyB,CAAC,GAAG;AAC1D,SAAK,QAAQ;AACb,SAAK,UAAU,cAAU,gCAAY,CAAC,EAAE,SAAS,KAAK;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAIA,IAAI,SAAiB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,UAAkB;AACpB,QAAI,CAAC,KAAK,WAAY,OAAM,IAAI,MAAM,uCAAuC;AAC7E,WAAO,oBAAoB,KAAK,UAAU;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,SAAS,QAAgB,SAAoC;AAC3D,UAAM,MAAM,OAAO,YAAY;AAC/B,SAAK,UAAU,IAAI,KAAK,OAAO;AAC/B,SAAK,KAAK,OAAO;AACjB,WAAO;AAAA,MACL,SAAS,6BAAM;AACb,YAAI,KAAK,UAAU,IAAI,GAAG,MAAM,QAAS,MAAK,UAAU,OAAO,GAAG;AAAA,MACpE,GAFS;AAAA,IAGX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,IAAI,QAAgB,MAAe,OAAoE;AAC3G,UAAM,KAAK,OAAO;AAClB,UAAM,MAAM,IAAI,IAAI,GAAG,KAAK,OAAO,IAAI,KAAK,OAAO,IAAI,OAAO,YAAY,CAAC,EAAE;AAC7E,QAAI,KAAM,KAAI,WAAW,GAAG,IAAI,QAAQ,IAAI,KAAK,QAAQ,SAAS,EAAE,CAAC;AACrE,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,SAAS,CAAC,CAAC,EAAG,KAAI,aAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAC/F,WAAO,IAAI,SAAS;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAC3B,SAAK,UAAU;AACf,SAAK,UAAU,MAAM;AACrB,UAAM,SAAS,KAAK;AACpB,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,aAAa;AAClB,QAAI,CAAC,OAAQ;AACb,UAAM,IAAI,QAAc,aAAW,OAAO,MAAM,MAAM,QAAQ,CAAC,CAAC;AAAA,EAClE;AAAA,EACA,MAAM,SAAwB;AAC5B,QAAI,KAAK,QAAS,OAAM,IAAI,MAAM,8BAA8B;AAChE,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,IAAI,QAAc,CAAC,SAAS,WAAW;AACnD,cAAM,aAAS,+BAAa,CAAC,KAAK,QAAQ,KAAK,KAAK,QAAQ,KAAK,GAAG,CAAC;AACrE,eAAO,KAAK,SAAS,MAAM;AAC3B,eAAO,OAAO,KAAK,OAAO,aAAa,MAAM;AAC3C,gBAAM,UAAU,OAAO,QAAQ;AAC/B,eAAK,aAAa,OAAO,YAAY,YAAY,UAAU,QAAQ,OAAO,KAAK;AAC/E,eAAK,UAAU;AAEf,iBAAO,QAAQ;AACf,kBAAQ;AAAA,QACV,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EACA,MAAM,QAAQ,KAAsB,KAAoC;AACtE,UAAM,aAAa,IAAI,gBAAgB;AACvC,QAAI,GAAG,SAAS,MAAM,WAAW,MAAM,CAAC;AACxC,QAAI;AACF,YAAM,aAAa,IAAI,IAAI,IAAI,OAAO,KAAK,kBAAkB;AAC7D,YAAM,WAAW,WAAW,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AAC9D,UAAI,SAAS,CAAC,MAAM,KAAK,SAAS;AAChC,YAAI,UAAU,KAAK,EAAE,gBAAgB,aAAa,CAAC,EAAE,IAAI,WAAW;AACpE;AAAA,MACF;AACA,YAAM,UAAU,KAAK,UAAU,KAAK,SAAS,CAAC,KAAK,IAAI,YAAY,CAAC;AACpE,UAAI,CAAC,SAAS;AACZ,YAAI,UAAU,KAAK,EAAE,gBAAgB,aAAa,CAAC,EAAE,IAAI,WAAW;AACpE;AAAA,MACF;AACA,YAAM,SAAS,MAAM,QAAQ;AAAA,QAC3B,MAAM,SAAS,MAAM,CAAC,EAAE,KAAK,GAAG;AAAA,QAChC,OAAO,WAAW;AAAA,QAClB,QAAQ,WAAW,IAAI,QAAQ,KAAK;AAAA,QACpC,QAAQ,WAAW;AAAA,QACnB,SAAS;AAAA,MACX,CAAC;AACD,UAAI,CAAC,QAAQ;AACX,YAAI,UAAU,KAAK,EAAE,gBAAgB,aAAa,CAAC,EAAE,IAAI,WAAW;AACpE;AAAA,MACF;AACA,YAAM,UAA2C;AAAA,QAC/C,gBAAgB,OAAO,eAAe;AAAA,QACtC,GAAG,OAAO;AAAA,MACZ;AACA,UAAI,OAAO,SAAS,OAAW,SAAQ,eAAe,IAAI;AAC1D,UAAI,OAAO,SAAS,UAAa,OAAO,OAAO,GAAG;AAChD,cAAM,SAAS,KAAK,IAAI,WAAW,IAAI,QAAQ,KAAK,GAAG,KAAK,IAAI,OAAO,OAAO,GAAG,CAAC,CAAC;AACnF,YAAI,SAAS,GAAG;AACd,kBAAQ,eAAe,IAAI,SAAS,MAAM,IAAI,OAAO,OAAO,CAAC,IAAI,OAAO,IAAI;AAC5E,cAAI,UAAU,KAAK,OAAO;AAAA,QAC5B,OAAO;AACL,cAAI,UAAU,OAAO,UAAU,KAAK,OAAO;AAAA,QAC7C;AAAA,MACF,OAAO;AACL,YAAI,UAAU,OAAO,UAAU,KAAK,OAAO;AAAA,MAC7C;AACA,YAAM,OAAO,OAAO,gBAAgB,+BAAW,OAAO,OAAO,6BAAS,KAAK,OAAO,IAAI;AACtF,WAAK,GAAG,SAAS,MAAM,IAAI,IAAI,CAAC;AAChC,WAAK,KAAK,GAAG;AAAA,IACf,QAAQ;AACN,UAAI,CAAC,IAAI,YAAa,KAAI,UAAU,KAAK,EAAE,gBAAgB,aAAa,CAAC;AACzE,UAAI,IAAI;AAAA,IACV;AAAA,EACF;AACF;;;AC5QA,IAAAC,6BAA6B;;;ACStB,IAAM,eAAN,MAAgC;AAAA,EAVvC,OAUuC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAI5B;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeT,YACE,OACA;AAAA,IACE,QAAQ,CAAC;AAAA,IACT;AAAA,IACA;AAAA,IACA,UAAU,CAAC;AAAA,EACb,IAKI,CAAC,GACL;AACA,SAAK,QAAQ;AACb,SAAK,QAAQ;AACb,SAAK,WAAW;AAChB,SAAK,YAAY;AACjB,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,UAAmB;AACjB,WAAO,KAAK,MAAM,WAAW,KAAK,CAAC,KAAK;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,WAAoB;AAClB,WAAO,KAAK,MAAM,SAAS;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,WAAO,QAAQ,KAAK,QAAQ;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,SAAiB;AACf,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK;AAAA,MAChB,SAAS,CAAC,GAAG,KAAK,OAAO;AAAA,MACzB,OAAO,KAAK,MAAM,IAAI,WAAS;AAAA,QAC7B,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,KAAK,KAAK;AAAA,QACV,UAAU,KAAK;AAAA,QACf,mBAAmB,KAAK;AAAA,QACxB,WAAW,KAAK;AAAA,QAChB,QAAQ,KAAK;AAAA,QACb,UAAU,KAAK;AAAA,MACjB,EAAE;AAAA,MACF,UAAU,KAAK,WACX;AAAA,QACE,IAAI,KAAK,SAAS;AAAA,QAClB,MAAM,KAAK,SAAS;AAAA,QACpB,KAAK,KAAK,SAAS;AAAA,QACnB,WAAW,KAAK,SAAS;AAAA,QACzB,OAAO,KAAK,SAAS,MAAM;AAAA,MAC7B,IACA;AAAA,IACN;AAAA,EACF;AACF;;;AD1EO,IAAM,UAAN,MAAM,iBAAgB,wCAAiC;AAAA,EA1C9D,OA0C8D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO5D,gCAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhC,gCAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhC,wCAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMpC,qCAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlC,2BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ7B,2BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM7B,wCAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQpC,2BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM7B,6BAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO9B,sCAAmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMnC,oCAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQlC,oCAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASlC,kCAAiC;AAAA;AAAA;AAAA;AAAA,EAIxB;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWT,YAAY,QAAgB,OAAuB,CAAC,GAAG;AACrD,UAAM;AAGN,SAAK,gBAAgB,CAAC;AACtB,QAAI,CAAC,iBAAiB,MAAM,EAAG,OAAM,IAAI,aAAa,gBAAgB,kBAAkB,QAAQ,QAAQ;AACxG,SAAK,SAAS;AACd,iBAAa,OAAO,OAAO;AAC3B,SAAK,UAAU,IAAI,QAAQ,IAAI;AAC/B,SAAK,SAAS,IAAI,oBAAoB,IAAI;AAC1C,SAAK,UAAU,IAAI,eAAe,IAAI;AACtC,SAAK,SAAS,IAAI,aAAa,IAAI;AACnC,SAAK,UAAU,EAAE,GAAG,gBAAgB,GAAG,KAAK,QAAQ,cAAc;AAClE,SAAK,UAAU,CAAC,GAAG,KAAK,QAAQ,OAAO;AACvC,SAAK,UAAU,IAAI,aAAa;AAChC,eAAW,KAAK,KAAK,SAAS;AAC5B,YAAM,SAAS,EAAE,KAAK,IAAI;AAG1B,UAAI,UAAU,OAAQ,OAAyB,UAAU,YAAY;AACnE,QAAC,OAAyB,MAAM,CAAC,MAAe;AAC9C,gBAAM,QAAQ,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC;AAC1D,eAAK,MAAM,wBAAwB,EAAE,YAAY,IAAI,0BAA0B,MAAM,OAAO,EAAE;AAC9F,kBAAQ,YAAY,cAAc,EAAE,YAAY,IAAI,0BAA0B,MAAM,OAAO,IAAI;AAAA,YAC7F,MAAM;AAAA,YACN,QAAQ,MAAM,SAAS,MAAM;AAAA,UAC/B,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,aAAa,OAAO,QAAgB,OAAuB,CAAC,GAAqB;AAC/E,UAAM,UAAU,IAAI,SAAQ,QAAQ,IAAI;AACxC,UAAM,QAAQ;AAAA,MACZ,QAAQ,QAAQ,IAAI,OAAM,WAAU;AAClC,YAAI;AACF,gBAAM,OAAO,KAAK,OAAO;AAAA,QAC3B,SAAS,GAAY;AACnB,gBAAM,QAAQ,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC;AAC1D,kBAAQ,MAAM,wBAAwB,OAAO,YAAY,IAAI,0BAA0B,MAAM,OAAO,EAAE;AACtG,kBAAQ,YAAY,cAAc,OAAO,YAAY,IAAI,0BAA0B,MAAM,OAAO,IAAI;AAAA,YAClG,MAAM;AAAA,YACN,QAAQ,MAAM,SAAS,MAAM;AAAA,UAC/B,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeS,KAAyC,UAAa,MAAkD;AAC/G,QAAI,iCAA0B,KAAK,iCAA0B,MAAM,GAAG;AACpE,WAAK,sBAAsB,KAAK,CAAC,CAAU;AAC3C,aAAO;AAAA,IACT;AACA,WAAO,MAAM,KAAK,OAAO,GAAG,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,sBAAsB,OAAc;AAClC,yBAAqB,OAAO,KAAK,SAAS,kBAAkB,KAAK;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,UAAU;AACnB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,UAAU;AACZ,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,KACJ,cACA,MACA,UAA0B,CAAC,GACZ;AACf,QAAI,CAAC,wBAAwB,YAAY,GAAG;AAC1C,YAAM,IAAI,aAAa,gBAAgB,yBAAyB,cAAc,cAAc;AAAA,IAC9F;AACA,QAAI,CAAC,SAAS,OAAO,EAAG,OAAM,IAAI,aAAa,gBAAgB,UAAU,SAAS,SAAS;AAE3F,UAAM,EAAE,aAAa,QAAQ,MAAM,SAAS,UAAU,OAAO,IAAI;AAAA,MAC/D,QAAQ,aAAa,MAAM,QAAQ,MAAM;AAAA,MACzC,aAAa,SAAS,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN,GAAG;AAAA,IACL;AACA,UAAM,WAAW,OAAO,QAAQ,QAAQ,MAAM,OAAO,IAAI;AAEzD,QAAI,WAAW,CAAC,kBAAkB,OAAO,GAAG;AAC1C,YAAM,IAAI,aAAa,gBAAgB,CAAC,mBAAmB,eAAe,GAAG,SAAS,iBAAiB;AAAA,IACzG;AACA,QAAI,eAAe,CAAC,sBAAsB,WAAW,GAAG;AACtD,YAAM,IAAI,aAAa,gBAAgB,iCAAiC,aAAa,qBAAqB;AAAA,IAC5G;AACA,QAAI,UAAU,CAAC,iBAAiB,MAAM,GAAG;AACvC,YAAM,IAAI,aAAa,gBAAgB,uBAAuB,QAAQ,gBAAgB;AAAA,IACxF;AAEA,UAAM,QAAQ,KAAK,SAAS,YAAY,KAAM,MAAM,KAAK,OAAO,OAAO,cAAc,WAAW;AAChG,UAAM,MAAM,WAAW,QAAQ,IAAI;AACnC,QAAI;AACF,WAAK,MAAM,IAAI,MAAM,EAAE,oBAAoB,IAAI,EAAE;AACjD,YAAM,WAAW,MAAM,KAAK,QAAQ,QAAQ,MAAM,EAAE,QAAQ,UAAU,OAAO,CAAC;AAC9E,YAAM,SAAS,cAAc,OAAO,eAAe,WAAW;AAC9D,YAAM,cAAc,MAAM,MAAM,WAAW;AAC3C,UAAI,oBAAoB,UAAU;AAChC,YAAI,CAAC,KAAK,QAAQ,QAAQ,CAAC,QAAQ;AACjC,mBAAS,QAAQ,SAAS,MAAM,OAAO,OAAK,CAAC,EAAE,aAAa;AAC5D,cAAI,CAAC,SAAS,MAAM,OAAQ,OAAM,IAAI,aAAa,yBAAyB;AAAA,QAC9E;AACA,YAAI,CAAC,SAAS,MAAM,OAAQ,OAAM,IAAI,aAAa,gBAAgB;AACnE,aAAK,MAAM,IAAI,MAAM,EAAE,+BAA+B,SAAS,MAAM,MAAM,QAAQ;AACnF,cAAM,WAAW,SAAS,OAAO,QAAQ;AACzC,YAAI,CAAC,eAAe,KAAK,QAAQ,6BAA8B,MAAK,+BAAsB,OAAO,QAAQ;AAAA,MAC3G,OAAO;AACL,YAAI,CAAC,KAAK,QAAQ,QAAQ,SAAS,iBAAiB,CAAC,cAAc,OAAO,eAAe,WAAW,GAAG;AACrG,gBAAM,IAAI,aAAa,UAAU;AAAA,QACnC;AACA,aAAK,MAAM,IAAI,MAAM,EAAE,2BAA2B,SAAS,QAAQ,SAAS,OAAO,SAAS,MAAM,QAAQ,EAAE;AAC5G,cAAM,WAAW,UAAU,QAAQ;AACnC,YAAI,CAAC,eAAe,KAAK,QAAQ,6BAA8B,MAAK,+BAAsB,OAAO,QAAQ;AAAA,MAC3G;AAEA,UAAI,YAAa,OAAM,MAAM,KAAK;AAAA,eACzB,KAAM,OAAM,MAAM,KAAK;AAAA,IAClC,SAAS,GAAY;AACnB,UAAI,EAAE,aAAa,eAAe;AAChC,cAAM,eAAe,aAAa,QAAS,EAAE,SAAS,EAAE,UAAW,OAAO,CAAC;AAC3E,aAAK,MAAM,IAAI,MAAM,EAAE,0CAA0C,YAAY,EAAE;AAC/E,YAAI,aAAa,OAAO;AACtB,cAAI;AACF,cAAE,OAAO;AACT,cAAE,UAAU,GAAG,OAAO,SAAS,WAAW,OAAO,KAAK,GAAG;AAAA,EAAK,EAAE,OAAO;AAAA,UACzE,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AACA,YAAM;AAAA,IACR,UAAE;AACA,UAAI,CAAC,MAAM,MAAM,UAAU,CAAC,MAAM,WAAW,YAAa,OAAM,OAAO;AACvE,YAAM,WAAW,QAAQ;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,qBACJ,OACA,EAAE,QAAQ,UAAU,UAAU,MAAM,QAAQ,KAAK,UAAU,IAA2B,CAAC,GACpE;AACnB,QAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,OAAM,IAAI,aAAa,gBAAgB,SAAS,OAAO,OAAO;AACzF,QAAI,CAAC,MAAM,OAAQ,OAAM,IAAI,aAAa,eAAe,OAAO;AAChE,UAAM,gBAAgB,MAAM,OAAO,UAAQ,gBAAgB,QAAQ,MAAM,IAAI,CAAC;AAC9E,QAAI,CAAC,cAAc,OAAQ,OAAM,IAAI,aAAa,eAAe;AACjE,QAAI,UAAU,CAAC,iBAAiB,MAAM,GAAG;AACvC,YAAM,IAAI,aAAa,gBAAgB,kBAAkB,QAAQ,gBAAgB;AAAA,IACnF;AACA,QAAI;AACJ,QAAI,aAAa,OAAO;AACtB,YAAM,WAAW,cAAc;AAAA,QAAI,CAAC,SAClC,KAAK,QAAQ,QAAQ,MAAM,EAAE,QAAQ,SAAS,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,MACxE;AACA,uBAAiB,MAAM,QAAQ,IAAI,QAAQ,GAAG,OAAO,CAAC,MAAiB,aAAa,IAAI;AAAA,IAC1F,OAAO;AACL,sBAAgB,CAAC;AACjB,iBAAW,QAAQ,eAAe;AAChC,cAAM,WAAW,MAAM,KAAK,QAAQ,QAAQ,MAAM,EAAE,QAAQ,SAAS,CAAC,EAAE,MAAM,MAAM,MAAS;AAC7F,YAAI,oBAAoB,KAAM,eAAc,KAAK,QAAQ;AAAA,MAC3D;AAAA,IACF;AACA,WAAO,IAAI;AAAA,MACT;AAAA,QACE,QAAQ,UAAU;AAAA,QAClB;AAAA,QACA;AAAA,QACA,WAAW,aAAa,cAAc,KAAK,OAAK,EAAE,SAAS,GAAG;AAAA,QAC9D,OAAO;AAAA,MACT;AAAA,MACA,EAAE,QAAQ,SAAS;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,SAAS,OAA6C;AACpD,WAAO,KAAK,OAAO,IAAI,KAAK;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,UAAU,QAA2C;AACnD,QAAI,OAAO,WAAW,YAAY,CAAC,OAAQ,QAAO;AAClD,UAAM,aAAa,OAAO,YAAY;AACtC,WAAO,KAAK,QAAQ,KAAK,YAAU,OAAO,YAAY,SAAS,UAAU,CAAC;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,OAAoB,OAAe,UAA4B,CAAC,GAA6B;AACjG,UAAM,QAAQ,QAAQ,SAAS;AAC/B,UAAM,UAA2B,QAAQ,SACrC,CAAC,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,OAAO,CAAC,WAAoC,QAAQ,MAAM,CAAC,IAC5F,KAAK;AAET,UAAM,QAAmB,CAAC;AAC1B,UAAM,UAAoB,CAAC;AAC3B,QAAI;AAEJ,eAAW,UAAU,SAAS;AAC5B,UAAI,MAAM,UAAU,MAAO;AAC3B,YAAM,QAAQ,MAAM,OAAO,OAAU,OAAO,EAAE,GAAG,SAAS,OAAO,QAAQ,MAAM,OAAO,CAAC;AACvF,UAAI,CAAC,MAAO;AACZ,UAAI,MAAM,MAAM,QAAQ;AACtB,cAAM,KAAK,GAAG,MAAM,KAAK;AACzB,gBAAQ,KAAK,OAAO,YAAY,CAAC,KAAK,OAAO,YAAY,IAAI;AAAA,MAC/D;AACA,mBAAa,MAAM;AAAA,IACrB;AAEA,WAAO,IAAI,aAAgB,OAAO;AAAA,MAChC,OAAO,MAAM,MAAM,GAAG,KAAK;AAAA,MAC3B;AAAA,MACA,WAAW,QAAQ;AAAA,MACnB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,UAAU,OAAc,OAAc,MAAmB;AACvD,SAAK,0BAAmB,OAAO,OAAO,IAAI;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,SAAiB;AACrB,SAAK,0BAAmB,OAAO;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,UAAyB;AAC7B,SAAK,MAAM,8CAA8C;AACzD,UAAM,SAAS,CAAC,GAAG,KAAK,OAAO,WAAW,OAAO,CAAC;AAClD,eAAW,SAAS,QAAQ;AAC1B,UAAI;AACF,cAAM,MAAM,KAAK;AAAA,MACnB,SAAS,GAAY;AACnB,cAAM,eAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAC9D,aAAK,MAAM,sCAAsC,MAAM,EAAE,KAAK,YAAY,EAAE;AAAA,MAC9E;AAAA,IACF;AACA,UAAM,SAAS,CAAC,GAAG,KAAK,OAAO,WAAW,OAAO,CAAC;AAClD,eAAW,SAAS,QAAQ;AAC1B,UAAI;AACF,cAAM,MAAM;AAAA,MACd,SAAS,GAAY;AACnB,cAAM,eAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAC9D,aAAK,MAAM,kDAAkD,MAAM,EAAE,KAAK,YAAY,EAAE;AAAA,MAC1F;AAAA,IACF;AACA,eAAW,UAAU,KAAK,SAAS;AACjC,UAAI;AACF,cAAM,OAAO,QAAQ;AAAA,MACvB,SAAS,GAAY;AACnB,cAAM,eAAe,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAC9D,aAAK,MAAM,0CAA0C,OAAO,YAAY,IAAI,KAAK,YAAY,EAAE;AAAA,MACjG;AAAA,IACF;AACA,UAAM,KAAK,QAAQ,MAAM;AACzB,SAAK,mBAAmB;AAAA,EAC1B;AACF;;;AEriBO,IAAe,SAAf,MAAsB;AAAA,EAT7B,OAS6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAclB;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA;AAAA;AAAA;AAAA,EAIT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,KAAK,SAAwC;AAC3C,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,cAAwB;AAC1B,UAAM,QAAQ,oBAAI,IAAY;AAC9B,UAAM,OAAO,KAAK;AAClB,UAAM,SAAS,KAAK,UAAU,KAAK,UAAU,KAAK,YAAY,KAAK,QAAQ,aAAa,EAAE;AAC1F,QAAI,OAAQ,OAAM,IAAI,OAAO,YAAY,CAAC;AAC1C,eAAW,SAAS,KAAK,WAAW,KAAK,WAAW,CAAC,GAAG;AACtD,UAAI,OAAO,UAAU,YAAY,MAAO,OAAM,IAAI,MAAM,YAAY,CAAC;AAAA,IACvE;AACA,WAAO,CAAC,GAAG,KAAK;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,UAAwB;AAC1B,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,WAAc,QAAgB,UAAwD;AACpF,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,OAAU,OAAe,UAA4B,CAAC,GAA6B;AACvF,UAAM,OAAO,MAAM,KAAK,WAAW,OAAO,OAAO;AACjD,WAAO,IAAI,aAAgB,OAAO;AAAA,MAChC,OAAO,OAAO,CAAC,IAAI,IAAI,CAAC;AAAA,MACxB,WAAW,QAAQ;AAAA,IACrB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,kBAAqB,MAAkC;AACrD,WAAO,GAAG,KAAK,QAAQ,EAAE,IAAI,KAAK,UAAU,QAAQ,EAAE,GAAG,KAAK;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,gBAAgB,OAAgC;AAC9C,WAAO,CAAC;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,UAAgC;AAAA,EAEhC;AACF;;;ACtJO,IAAe,kBAAf,cAAuC,OAAO;AAAA,EATrD,OASqD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAIjC;AAqBpB;;;AC7BO,IAAK,kBAAL,kBAAKC,qBAAL;AAIL,EAAAA,iBAAA,qBAAkB;AAIlB,EAAAA,iBAAA,eAAY;AAIZ,EAAAA,iBAAA,eAAY;AAKZ,EAAAA,iBAAA,wBAAqB;AAIrB,EAAAA,iBAAA,oBAAiB;AArBP,SAAAA;AAAA,GAAA;AAwBZ,IAAM,mBAAoD;AAAA,EACxD,CAAC,uCAA+B,GAAG;AAAA,EACnC,CAAC,2BAAyB,GAAG;AAAA,EAC7B,CAAC,2BAAyB,GAAG;AAAA,EAC7B,CAAC,6CAAkC,GAAG;AAAA,EACtC,CAAC,qCAA8B,GAAG;AACpC;AAQO,IAAM,cAAN,cAAuE,aAAgB;AAAA,EA3C9F,OA2C8F;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAY5F,YAAY,MAAS,SAAkB,SAA+B;AACpE,UAAM,MAAM,WAAW,iBAAiB,IAAI,CAAC;AAC7C,QAAI,WAAW,WAAW,QAAS,MAAK,QAAQ,QAAQ;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,IAAa,OAAO;AAClB,WAAO,gBAAgB,KAAK,SAAS;AAAA,EACvC;AACF;;;ACtDO,IAAe,sBAAf,cAA2C,gBAAgB;AAAA,EAZlE,OAYkE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAI9C;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4B7B,MAAe,aAAgB,OAAiC;AAC9D,UAAM,IAAI,uCAAqC;AAAA,EACjD;AACF;;;AC3CO,IAAe,0BAAf,cAA+C,gBAAgB;AAAA,EATtE,OASsE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAIlD;AAqBpB;","names":["import_discord","import_discord","Events","SearchResultType","RepeatMode","PluginType","import_voice","import_tiny_typed_emitter","process","version","import_voice","import_node_stream","import_tiny_typed_emitter","PluginErrorCode"]}
|