"use strict"; var _Queue_instances, _Queue_lastVolume, _Queue_destroyed, _Queue_watchDestroyed, _Queue_getBufferingTimeout; Object.defineProperty(exports, "__esModule", { value: true }); exports.Queue = void 0; const tslib_1 = require("tslib"); const discord_js_1 = require("discord.js"); const Track_1 = tslib_1.__importDefault(require("./Track")); const types_1 = require("../types/types"); const voice_1 = require("@discordjs/voice"); const play_dl_1 = tslib_1.__importDefault(require("play-dl")); const Util_1 = require("../utils/Util"); const AudioFilters_1 = tslib_1.__importDefault(require("../utils/AudioFilters")); const PlayerError_1 = require("./PlayerError"); const FFmpegStream_1 = require("../utils/FFmpegStream"); class Queue { /** * Queue constructor * @param {Player} player The player that instantiated this queue * @param {Guild} guild The guild that instantiated this queue * @param {PlayerOptions} [options] Player options for the queue */ constructor(player, guild, options = {}) { _Queue_instances.add(this); this.tracks = []; this.previousTracks = []; this.playing = false; this.metadata = null; this.repeatMode = 0; this.id = discord_js_1.SnowflakeUtil.generate().toString(); this._streamTime = 0; this._cooldownsTimeout = new discord_js_1.Collection(); this._activeFilters = []; // eslint-disable-line @typescript-eslint/no-explicit-any this._filtersUpdate = false; _Queue_lastVolume.set(this, 0); _Queue_destroyed.set(this, false); this.onBeforeCreateStream = null; /** * The player that instantiated this queue * @type {Player} * @readonly */ this.player = player; /** * The guild that instantiated this queue * @type {Guild} * @readonly */ this.guild = guild; /** * The player options for this queue * @type {PlayerOptions} */ this.options = {}; /** * Queue repeat mode * @type {QueueRepeatMode} * @name Queue#repeatMode */ /** * Queue metadata * @type {any} * @name Queue#metadata */ /** * Previous tracks * @type {Track[]} * @name Queue#previousTracks */ /** * Regular tracks * @type {Track[]} * @name Queue#tracks */ /** * The connection * @type {StreamDispatcher} * @name Queue#connection */ /** * The ID of this queue * @type {Snowflake} * @name Queue#id */ Object.assign(this.options, { leaveOnEnd: true, leaveOnStop: true, leaveOnEmpty: true, leaveOnEmptyCooldown: 1000, autoSelfDeaf: true, ytdlOptions: { highWaterMark: 1 << 25 }, initialVolume: 100, bufferingTimeout: 3000, spotifyBridge: true, disableVolume: false }, options); if ("onBeforeCreateStream" in this.options) this.onBeforeCreateStream = this.options.onBeforeCreateStream; this.player.emit("debug", this, `Queue initialized:\n\n${this.player.scanDeps()}`); } /** * Returns current track * @type {Track} */ get current() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; return this.connection.audioResource?.metadata ?? this.tracks[0]; } /** * If this queue is destroyed * @type {boolean} */ get destroyed() { return tslib_1.__classPrivateFieldGet(this, _Queue_destroyed, "f"); } /** * Returns current track * @returns {Track} */ nowPlaying() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; return this.current; } /** * Connects to a voice channel * @param {GuildChannelResolvable} channel The voice/stage channel * @returns {Promise} */ async connect(channel) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; const _channel = this.guild.channels.resolve(channel); if (![discord_js_1.ChannelType.GuildStageVoice, discord_js_1.ChannelType.GuildVoice].includes(_channel?.type)) throw new PlayerError_1.PlayerError(`Channel type must be GuildVoice or GuildStageVoice, got ${_channel?.type}!`, PlayerError_1.ErrorStatusCode.INVALID_ARG_TYPE); const connection = await this.player.voiceUtils.connect(_channel, { deaf: this.options.autoSelfDeaf }); this.connection = connection; if (_channel.type === discord_js_1.ChannelType.GuildStageVoice) { await _channel.guild.members.me.voice.setSuppressed(false).catch(async () => { return await _channel.guild.members.me.voice.setRequestToSpeak(true).catch(Util_1.Util.noop); }); } this.connection.on("error", (err) => { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this, false)) return; this.player.emit("connectionError", this, err); }); this.connection.on("debug", (msg) => { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this, false)) return; this.player.emit("debug", this, msg); }); this.player.emit("connectionCreate", this, this.connection); this.connection.on("start", (resource) => { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this, false)) return; this.playing = true; if (!this._filtersUpdate) this.player.emit("trackStart", this, resource?.metadata ?? this.current); this._filtersUpdate = false; }); this.connection.on("finish", async (resource) => { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this, false)) return; this.playing = false; if (this._filtersUpdate) return; this._streamTime = 0; if (resource?.metadata) this.previousTracks.push(resource.metadata); this.player.emit("trackEnd", this, resource.metadata); if (!this.tracks.length && this.repeatMode === types_1.QueueRepeatMode.OFF) { if (this.options.leaveOnEnd) this.destroy(); this.player.emit("queueEnd", this); } else if (!this.tracks.length && this.repeatMode === types_1.QueueRepeatMode.AUTOPLAY) { this._handleAutoplay(Util_1.Util.last(this.previousTracks)); } else { if (this.repeatMode === types_1.QueueRepeatMode.TRACK) return void this.play(Util_1.Util.last(this.previousTracks), { immediate: true }); if (this.repeatMode === types_1.QueueRepeatMode.QUEUE) this.tracks.push(Util_1.Util.last(this.previousTracks)); const nextTrack = this.tracks.shift(); this.play(nextTrack, { immediate: true }); return; } }); return this; } /** * Destroys this queue * @param {boolean} [disconnect=this.options.leaveOnStop] If it should leave on destroy * @returns {void} */ destroy(disconnect = this.options.leaveOnStop) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (this.connection) this.connection.end(); if (disconnect) this.connection?.disconnect(); this.player.queues.delete(this.guild.id); this.player.voiceUtils.cache.delete(this.guild.id); tslib_1.__classPrivateFieldSet(this, _Queue_destroyed, true, "f"); } /** * Skips current track * @returns {boolean} */ skip() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!this.connection) return false; this._filtersUpdate = false; this.connection.end(); return true; } /** * Adds single track to the queue * @param {Track} track The track to add * @returns {void} */ addTrack(track) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!(track instanceof Track_1.default)) throw new PlayerError_1.PlayerError("invalid track", PlayerError_1.ErrorStatusCode.INVALID_TRACK); this.tracks.push(track); this.player.emit("trackAdd", this, track); } /** * Adds multiple tracks to the queue * @param {Track[]} tracks Array of tracks to add */ addTracks(tracks) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!tracks.every((y) => y instanceof Track_1.default)) throw new PlayerError_1.PlayerError("invalid track", PlayerError_1.ErrorStatusCode.INVALID_TRACK); this.tracks.push(...tracks); this.player.emit("tracksAdd", this, tracks); } /** * Sets paused state * @param {boolean} paused The paused state * @returns {boolean} */ setPaused(paused) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!this.connection) return false; return paused ? this.connection.pause(true) : this.connection.resume(); } /** * Sets bitrate * @param {number|auto} bitrate bitrate to set * @returns {void} */ setBitrate(bitrate) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!this.connection?.audioResource?.encoder) return; if (bitrate === "auto") bitrate = this.connection.channel?.bitrate ?? 64000; this.connection.audioResource.encoder.setBitrate(bitrate); } /** * Sets volume * @param {number} amount The volume amount * @returns {boolean} */ setVolume(amount) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!this.connection) return false; tslib_1.__classPrivateFieldSet(this, _Queue_lastVolume, amount, "f"); this.options.initialVolume = amount; return this.connection.setVolume(amount); } /** * Sets repeat mode * @param {QueueRepeatMode} mode The repeat mode * @returns {boolean} */ setRepeatMode(mode) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (![types_1.QueueRepeatMode.OFF, types_1.QueueRepeatMode.QUEUE, types_1.QueueRepeatMode.TRACK, types_1.QueueRepeatMode.AUTOPLAY].includes(mode)) throw new PlayerError_1.PlayerError(`Unknown repeat mode "${mode}"!`, PlayerError_1.ErrorStatusCode.UNKNOWN_REPEAT_MODE); if (mode === this.repeatMode) return false; this.repeatMode = mode; return true; } /** * The current volume amount * @type {number} */ get volume() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!this.connection) return 100; return this.connection.volume; } set volume(amount) { this.setVolume(amount); } /** * The stream time of this queue * @type {number} */ get streamTime() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!this.connection) return 0; const playbackTime = this._streamTime + this.connection.streamTime; const NC = this._activeFilters.includes("nightcore") ? 1.25 : null; const VW = this._activeFilters.includes("vaporwave") ? 0.8 : null; if (NC && VW) return playbackTime * (NC + VW); return NC ? playbackTime * NC : VW ? playbackTime * VW : playbackTime; } set streamTime(time) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; this.seek(time); } /** * Returns enabled filters * @returns {AudioFilters} */ getFiltersEnabled() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; return AudioFilters_1.default.names.filter((x) => this._activeFilters.includes(x)); } /** * Returns disabled filters * @returns {AudioFilters} */ getFiltersDisabled() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; return AudioFilters_1.default.names.filter((x) => !this._activeFilters.includes(x)); } /** * Sets filters * @param {QueueFilters} filters Queue filters * @returns {Promise} */ async setFilters(filters) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!filters || !Object.keys(filters).length) { // reset filters const streamTime = this.streamTime; this._activeFilters = []; return await this.play(this.current, { immediate: true, filtersUpdate: true, seek: streamTime, encoderArgs: [] }); } const _filters = []; // eslint-disable-line @typescript-eslint/no-explicit-any for (const filter in filters) { if (filters[filter] === true) _filters.push(filter); } if (this._activeFilters.join("") === _filters.join("")) return; const newFilters = AudioFilters_1.default.create(_filters).trim(); const streamTime = this.streamTime; this._activeFilters = _filters; return await this.play(this.current, { immediate: true, filtersUpdate: true, seek: streamTime, encoderArgs: !_filters.length ? undefined : ["-af", newFilters] }); } /** * Seeks to the given time * @param {number} position The position * @returns {boolean} */ async seek(position) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!this.playing || !this.current) return false; if (position < 1) position = 0; if (position >= this.current.durationMS) return this.skip(); await this.play(this.current, { immediate: true, filtersUpdate: true, seek: position }); return true; } /** * Plays previous track * @returns {Promise} */ async back() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; const prev = this.previousTracks[this.previousTracks.length - 2]; // because last item is the current track if (!prev) throw new PlayerError_1.PlayerError("Could not find previous track", PlayerError_1.ErrorStatusCode.TRACK_NOT_FOUND); return await this.play(prev, { immediate: true }); } /** * Clear this queue */ clear() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; this.tracks = []; this.previousTracks = []; } /** * Stops the player * @returns {void} */ stop() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; return this.destroy(); } /** * Shuffles this queue * @returns {boolean} */ shuffle() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!this.tracks.length || this.tracks.length < 2) return false; for (let i = this.tracks.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [this.tracks[i], this.tracks[j]] = [this.tracks[j], this.tracks[i]]; } return true; } /** * Removes a track from the queue * @param {Track|string|number} track The track to remove * @returns {Track} */ remove(track) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; let trackFound = null; if (typeof track === "number") { trackFound = this.tracks[track]; if (trackFound) { this.tracks = this.tracks.filter((t) => t.id !== trackFound.id); } } else { trackFound = this.tracks.find((s) => s.id === (track instanceof Track_1.default ? track.id : track)); if (trackFound) { this.tracks = this.tracks.filter((s) => s.id !== trackFound.id); } } return trackFound; } /** * Returns the index of the specified track. If found, returns the track index else returns -1. * @param {number|Track|string} track The track * @returns {number} */ getTrackPosition(track) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (typeof track === "number") return this.tracks[track] != null ? track : -1; return this.tracks.findIndex((pred) => pred.id === (track instanceof Track_1.default ? track.id : track)); } /** * Jumps to particular track * @param {Track|number} track The track * @returns {void} */ jump(track) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; const foundTrack = this.remove(track); if (!foundTrack) throw new PlayerError_1.PlayerError("Track not found", PlayerError_1.ErrorStatusCode.TRACK_NOT_FOUND); this.tracks.splice(0, 0, foundTrack); return void this.skip(); } /** * Jumps to particular track, removing other tracks on the way * @param {Track|number} track The track * @returns {void} */ skipTo(track) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; const trackIndex = this.getTrackPosition(track); const removedTrack = this.remove(track); if (!removedTrack) throw new PlayerError_1.PlayerError("Track not found", PlayerError_1.ErrorStatusCode.TRACK_NOT_FOUND); this.tracks.splice(0, trackIndex, removedTrack); return void this.skip(); } /** * Inserts the given track to specified index * @param {Track} track The track to insert * @param {number} [index=0] The index where this track should be */ insert(track, index = 0) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!track || !(track instanceof Track_1.default)) throw new PlayerError_1.PlayerError("track must be the instance of Track", PlayerError_1.ErrorStatusCode.INVALID_TRACK); if (typeof index !== "number" || index < 0 || !Number.isFinite(index)) throw new PlayerError_1.PlayerError(`Invalid index "${index}"`, PlayerError_1.ErrorStatusCode.INVALID_ARG_TYPE); this.tracks.splice(index, 0, track); this.player.emit("trackAdd", this, track); } /** * @typedef {object} PlayerTimestamp * @property {string} current The current progress * @property {string} end The total time * @property {number} progress Progress in % */ /** * Returns player stream timestamp * @returns {PlayerTimestamp} */ getPlayerTimestamp() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; const currentStreamTime = this.streamTime; const totalTime = this.current.durationMS; const currentTimecode = Util_1.Util.buildTimeCode(Util_1.Util.parseMS(currentStreamTime)); const endTimecode = Util_1.Util.buildTimeCode(Util_1.Util.parseMS(totalTime)); return { current: currentTimecode, end: endTimecode, progress: Math.round((currentStreamTime / totalTime) * 100) }; } /** * Creates progress bar string * @param {PlayerProgressbarOptions} options The progress bar options * @returns {string} */ createProgressBar(options = { timecodes: true }) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; const length = typeof options.length === "number" ? (options.length <= 0 || options.length === Infinity ? 15 : options.length) : 15; const index = Math.round((this.streamTime / this.current.durationMS) * length); const indicator = typeof options.indicator === "string" && options.indicator.length > 0 ? options.indicator : "🔘"; const line = typeof options.line === "string" && options.line.length > 0 ? options.line : "▬"; if (index >= 1 && index <= length) { const bar = line.repeat(length - 1).split(""); bar.splice(index, 0, indicator); if (options.timecodes) { const timestamp = this.getPlayerTimestamp(); return `${timestamp.current} ┃ ${bar.join("")} ┃ ${timestamp.end}`; } else { return `${bar.join("")}`; } } else { if (options.timecodes) { const timestamp = this.getPlayerTimestamp(); return `${timestamp.current} ┃ ${indicator}${line.repeat(length - 1)} ┃ ${timestamp.end}`; } else { return `${indicator}${line.repeat(length - 1)}`; } } } /** * Total duration * @type {Number} */ get totalTime() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; return this.tracks.length > 0 ? this.tracks.map((t) => t.durationMS).reduce((p, c) => p + c) : 0; } /** * Play stream in a voice/stage channel * @param {Track} [src] The track to play (if empty, uses first track from the queue) * @param {PlayOptions} [options] The options * @returns {Promise} */ async play(src, options = {}) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this, false)) return; if (!this.connection || !this.connection.voiceConnection) throw new PlayerError_1.PlayerError("Voice connection is not available, use .connect()!", PlayerError_1.ErrorStatusCode.NO_CONNECTION); if (src && (this.playing || this.tracks.length) && !options.immediate) return this.addTrack(src); const track = options.filtersUpdate && !options.immediate ? src || this.current : src ?? this.tracks.shift(); if (!track) return; this.player.emit("debug", this, "Received play request"); if (!options.filtersUpdate) { this.previousTracks = this.previousTracks.filter((x) => x.id !== track.id); this.previousTracks.push(track); } let stream = null; const hasCustomDownloader = typeof this.onBeforeCreateStream === "function"; if (["youtube", "spotify"].includes(track.raw.source)) { let spotifyResolved = false; if (this.options.spotifyBridge && track.raw.source === "spotify" && !track.raw.engine) { track.raw.engine = await play_dl_1.default.search(`${track.author} ${track.title}`, { source: { youtube: "video" } }) .then(res => res[0].url) .catch(() => null); spotifyResolved = true; } const url = track.raw.source === "spotify" ? track.raw.engine : track.url; if (!url) return void this.play(this.tracks.shift(), { immediate: true }); if (hasCustomDownloader) { stream = (await this.onBeforeCreateStream(track, spotifyResolved ? "youtube" : track.raw.source, this)) || null; } if (!stream) { stream = (await play_dl_1.default.stream(url, { discordPlayerCompatibility: true })).stream; } } else { const arbitraryStream = (hasCustomDownloader && (await this.onBeforeCreateStream(track, track.raw.source || track.raw.engine, this))) || null; stream = arbitraryStream || (track.raw.source === "soundcloud" && typeof track.raw.engine?.downloadProgressive === "function") ? await track.raw.engine.downloadProgressive() : typeof track.raw.engine === "function" ? await track.raw.engine() : track.raw.engine; } const ffmpegStream = (0, FFmpegStream_1.createFFmpegStream)(stream, { encoderArgs: options.encoderArgs || [], seek: options.seek ? options.seek / 1000 : 0, fmt: "s16le" }).on("error", (err) => { if (!`${err}`.toLowerCase().includes("premature close")) this.player.emit("error", this, err); }); const resource = this.connection.createStream(ffmpegStream, { type: voice_1.StreamType.Raw, data: track, disableVolume: Boolean(this.options.disableVolume) }); if (options.seek) this._streamTime = options.seek; this._filtersUpdate = options.filtersUpdate; const volumeTransformer = resource.volume; if (volumeTransformer && typeof this.options.initialVolume === "number") Reflect.set(volumeTransformer, "volume", Math.pow(this.options.initialVolume / 100, 1.660964)); if (volumeTransformer?.hasSmoothness && typeof this.options.volumeSmoothness === "number") { if (typeof volumeTransformer.setSmoothness === "function") volumeTransformer.setSmoothness(this.options.volumeSmoothness || 0); } setTimeout(() => { this.connection.playStream(resource); }, tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_getBufferingTimeout).call(this)).unref(); } /** * Private method to handle autoplay * @param {Track} track The source track to find its similar track for autoplay * @returns {Promise} * @private */ async _handleAutoplay(track) { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!track || ![track.source, track.raw?.source].includes("youtube")) { if (this.options.leaveOnEnd) this.destroy(); return void this.player.emit("queueEnd", this); } const info = await play_dl_1.default.video_info(track.url) .catch(Util_1.Util.noop); if (!info) { if (this.options.leaveOnEnd) this.destroy(); return void this.player.emit("queueEnd", this); } const randomRelated = await play_dl_1.default.video_info(info.related_videos[0]); const nextTrack = new Track_1.default(this.player, { title: randomRelated.video_details.title, url: randomRelated.video_details.url, duration: randomRelated.video_details.durationRaw ? Util_1.Util.buildTimeCode(Util_1.Util.parseMS(randomRelated.video_details.durationInSec * 1000)) : "0:00", description: "", thumbnail: Util_1.Util.last(randomRelated.video_details.thumbnails).url, views: randomRelated.video_details.views, author: randomRelated.video_details.channel.name, requestedBy: track.requestedBy, source: "youtube" }); this.play(nextTrack, { immediate: true }); } *[(_Queue_lastVolume = new WeakMap(), _Queue_destroyed = new WeakMap(), _Queue_instances = new WeakSet(), Symbol.iterator)]() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; yield* this.tracks; } /** * JSON representation of this queue * @returns {object} */ toJSON() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; return { id: this.id, guild: this.guild.id, voiceChannel: this.connection?.channel?.id, options: this.options, tracks: this.tracks.map((m) => m.toJSON()) }; } /** * String representation of this queue * @returns {string} */ toString() { if (tslib_1.__classPrivateFieldGet(this, _Queue_instances, "m", _Queue_watchDestroyed).call(this)) return; if (!this.tracks.length) return "No songs available to display!"; return `**Upcoming Songs:**\n${this.tracks.map((m, i) => `${i + 1}. **${m.title}**`).join("\n")}`; } } exports.Queue = Queue; _Queue_watchDestroyed = function _Queue_watchDestroyed(emit = true) { if (tslib_1.__classPrivateFieldGet(this, _Queue_destroyed, "f")) { if (emit) this.player.emit("error", this, new PlayerError_1.PlayerError("Cannot use destroyed queue", PlayerError_1.ErrorStatusCode.DESTROYED_QUEUE)); return true; } return false; }, _Queue_getBufferingTimeout = function _Queue_getBufferingTimeout() { const timeout = this.options.bufferingTimeout; if (isNaN(timeout) || timeout < 0 || !Number.isFinite(timeout)) return 1000; return timeout; };