diff --git a/README.md b/README.md index 01fde19..cc6f704 100644 --- a/README.md +++ b/README.md @@ -504,3 +504,34 @@ if(previousTrack) { - *This is technically better than skipping to a track but i wanted to point it out.* - You can play with clientTrack like this: `player.play({ clientTrack: searchResult.tracks[0] })` - You can play with just track like this: `player.play({ track: { encoded: "base64string..." }, requester: interaction.user })` + + +## **Version 2.3.1** + +- Fixed Export, where types of Manager weren't exported correctly +- Fixed Dist Folder containing old, left over not needed files + +## **Version 2.3.2** +- Added Missing function calls for the QueueWatcher of tracksRemoved within the queue.remove() function: +- Added new DestroyReasons: + - TrackStuckMaxTracksErroredPerTime + - TrackErrorMaxTracksErroredPerTime +- Added new Prevention Systems for CrashbackLoop recognitions: + - `this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime`: + - object: `{ threshold: number, maxAmount: number }` (set threshold to 0 or maxAmount to -1 to disable) + - Default: `{ threshold: 10_000, maxAmount: 3 }` + - If there are trackError or trackStuck Events > maxAmount within the given treshhold, the player will be destroyed prevent more errors and thus potential ratelimits. + - `this.NodeManager.LavalinkManager.options.playerOptions.minAutoPlayMs`: + - number: `10_000` (default) + - If there is an AutoplayFunction, and it get's executed before that threshold, than it won't trigger the autoplay function again. *(this is ignored for when the player is skipped)* + - This prevents autoplays from happeneing on a crashbackloop + - Set to `0` to disable +- **Added new Event "debug":** + - `LavalinkManager#debug(event:DebugEvents, data:{ state: "log" | "warn" | "error", message:string, functionLayer:string, error?:Error })` + - This function Event will emit, when the following option is set to **` true `**: `LavalinkManager.options.advancedOptions.enableDebugEvents` + - You can use the **` DebugEvents `** Enum to listen to specific events and only show those you care + - You can filter for the **` data.state `** to only show the certain log-level state + - The **` functionLayer `** string will show you where the debug event was triggered from + - The **` message `** string will show what is debugged + - The **` error `** object will show you the error that happened, if there was one. + - *This took quite some time to code, and i am sure there are still many logs you might want, feel free to open an issue or commit with an PR, if you think something is missing!* diff --git a/package.json b/package.json index 3d89f12..768e012 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lavalink-client", - "version": "2.3.1", + "version": "2.3.2", "description": "Easy, flexible and feature-rich lavalink@v4 Client. Both for Beginners and Proficients.", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", diff --git a/src/structures/Constants.ts b/src/structures/Constants.ts index 42a09e8..6923232 100644 --- a/src/structures/Constants.ts +++ b/src/structures/Constants.ts @@ -1,5 +1,58 @@ import type { AudioOutputs, ChannelMixFilter, EQBand } from "./Types/Filters"; +export enum DebugEvents { + SetSponsorBlock = "SetSponsorBlock", + DeleteSponsorBlock = "DeleteSponsorBlock", + TrackEndReplaced = "TrackEndReplaced", + + AutoplayNoSongsAdded = "AutoplayNoSongsAdded", + AutoplayThresholdSpamLimiter = "AutoplayThresholdSpamLimiter", + TriggerQueueEmptyInterval = "TriggerQueueEmptyInterval", + QueueEnded = "QueueEnded", + TrackStartNewSongsOnly = "TrackStartNewSongsOnly", + TrackStartNoTrack = "TrackStartNoTrack", + + ResumingFetchingError = "ResumingFetchingError", + + PlayerUpdateNoPlayer = "PlayerUpdateNoPlayer", + PlayerUpdateFilterFixApply = "PlayerUpdateFilterFixApply", + PlayerUpdateSuccess = "PlayerUpdateSuccess", + + HeartBeatTriggered = "HeartBeatTriggered", + NoSocketOnDestroy = "NoSocketOnDestroy", + SocketTerminateHeartBeatTimeout = "SocketTerminateHeartBeatTimeout", + + TryingConnectWhileConnected = "TryingConnectWhileConnected", + + LavaSearchNothingFound = "LavaSearchNothingFound", + SearchNothingFound = "SearchNothingFound", + + ValidatingBlacklistLinks = "ValidatingBlacklistLinks", + ValidatingWhitelistLinks = "ValidatingWhitelistLinks", + + TrackErrorMaxTracksErroredPerTime = "TrackErrorMaxTracksErroredPerTime", + TrackStuckMaxTracksErroredPerTime = "TrackStuckMaxTracksErroredPerTime", + + PlayerDestroyingSomewhereElse = "PlayerDestroyingSomewhereElse", + PlayerCreateNodeNotFound = "PlayerCreateNodeNotFound", + PlayerPlayQueueEmptyTimeoutClear = "PlayerPlayQueueEmptyTimeoutClear", + PlayerPlayWithTrackReplace = "PlayerPlayWithTrackReplace", + PlayerPlayUnresolvedTrack = "PlayerPlayUnresolvedTrack", + PlayerPlayUnresolvedTrackFailed = "PlayerPlayUnresolvedTrackFailed", + PlayerVolumeAsFilter = "PlayerVolumeAsFilter", + BandcampSearchLokalEngine = "BandcampSearchLokalEngine", + PlayerChangeNode = "PlayerChangeNode", + + BuildTrackError = "BuildTrackError", + TransformRequesterFunctionFailed = "TransformRequesterFunctionFailed", + GetClosestTrackFailed = "GetClosestTrackFailed", + PlayerDeleteInsteadOfDestroy = "PlayerDeleteInsteadOfDestroy", + FailedToConnectToNodes = "FailedToConnectToNodes", + NoAudioDebug = "NoAudioDebug", + PlayerAutoReconnect = "PlayerAutoReconnect" +} + + export enum DestroyReasons { QueueEmpty = "QueueEmpty", NodeDestroy = "NodeDestroy", @@ -10,7 +63,10 @@ export enum DestroyReasons { PlayerReconnectFail = "PlayerReconnectFail", ChannelDeleted = "ChannelDeleted", DisconnectAllNodes = "DisconnectAllNodes", - ReconnectAllNodes = "ReconnectAllNodes" + ReconnectAllNodes = "ReconnectAllNodes", + + TrackErrorMaxTracksErroredPerTime = "TrackErrorMaxTracksErroredPerTime", + TrackStuckMaxTracksErroredPerTime = "TrackStuckMaxTracksErroredPerTime", }; diff --git a/src/structures/LavalinkManager.ts b/src/structures/LavalinkManager.ts index a754eb9..c1836ff 100644 --- a/src/structures/LavalinkManager.ts +++ b/src/structures/LavalinkManager.ts @@ -1,6 +1,6 @@ import { EventEmitter } from "events"; -import { DestroyReasons } from "./Constants"; +import { DebugEvents, DestroyReasons } from "./Constants"; import { NodeManager } from "./NodeManager"; import { Player } from "./Player"; import { DefaultQueueStore } from "./Queue"; @@ -104,9 +104,15 @@ export class LavalinkManager extends EventEmitter { volumeDecrementer: options?.playerOptions?.volumeDecrementer ?? 1, requesterTransformer: options?.playerOptions?.requesterTransformer ?? null, useUnresolvedData: options?.playerOptions?.useUnresolvedData ?? false, + minAutoPlayMs: options?.playerOptions?.minAutoPlayMs ?? 10_000, + maxErrorsPerTime: { + threshold: options?.playerOptions?.maxErrorsPerTime?.threshold ?? 35_000, + maxAmount: options?.playerOptions?.maxErrorsPerTime?.maxAmount ?? 3 + } }, linksWhitelist: options?.linksWhitelist ?? [], linksBlacklist: options?.linksBlacklist ?? [], + linksAllowed: options?.linksAllowed ?? true, autoSkip: options?.autoSkip ?? true, autoSkipOnResolveError: options?.autoSkipOnResolveError ?? true, emitNewSongsOnly: options?.emitNewSongsOnly ?? false, @@ -116,6 +122,7 @@ export class LavalinkManager extends EventEmitter { queueStore: options?.queueOptions?.queueStore ?? new DefaultQueueStore(), }, advancedOptions: { + enableDebugEvents: options?.advancedOptions?.enableDebugEvents ?? false, maxFilterFixDuration: options?.advancedOptions?.maxFilterFixDuration ?? 600_000, debugOptions: { logCustomSearches: options?.advancedOptions?.debugOptions?.logCustomSearches ?? false, @@ -327,7 +334,13 @@ export class LavalinkManager extends EventEmitter { // oldPlayer.connected is operational. you could also do oldPlayer.voice?.token if (oldPlayer.voiceChannelId === "string" && oldPlayer.connected && !oldPlayer.get("internal_destroywithoutdisconnect")) { if (!this.options?.advancedOptions?.debugOptions?.playerDestroy?.dontThrowError) throw new Error(`Use Player#destroy() not LavalinkManager#deletePlayer() to stop the Player ${JSON.stringify(oldPlayer.toJSON?.())}`) - else console.error("Use Player#destroy() not LavalinkManager#deletePlayer() to stop the Player", oldPlayer.toJSON?.()) + else if(this.options?.advancedOptions?.enableDebugEvents) { + this.emit("debug", DebugEvents.PlayerDeleteInsteadOfDestroy, { + state: "warn", + message: "Use Player#destroy() not LavalinkManager#deletePlayer() to stop the Player", + functionLayer: "LavalinkManager > deletePlayer()", + }) + } } return this.players.delete(guildId); } @@ -380,7 +393,13 @@ export class LavalinkManager extends EventEmitter { } } if (success > 0) this.initiated = true; - else console.error("Could not connect to at least 1 Node"); + else if(this.options?.advancedOptions?.enableDebugEvents) { + this.emit("debug", DebugEvents.FailedToConnectToNodes, { + state: "error", + message: "Failed to connect to at least 1 Node", + functionLayer: "LavalinkManager > init()", + }) + } return this; } @@ -401,11 +420,25 @@ export class LavalinkManager extends EventEmitter { */ public async sendRawData(data: VoicePacket | VoiceServer | VoiceState | ChannelDeletePacket): Promise { if (!this.initiated) { + if(this.options?.advancedOptions?.enableDebugEvents) { + this.emit("debug", DebugEvents.NoAudioDebug, { + state: "log", + message: "Manager is not initated yet", + functionLayer: "LavalinkManager > sendRawData()", + }) + } if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, manager is not initated yet"); return; } if (!("t" in data)) { + if(this.options?.advancedOptions?.enableDebugEvents) { + this.emit("debug", DebugEvents.NoAudioDebug, { + state: "error", + message: "No 't' in payload-data of the raw event:", + functionLayer: "LavalinkManager > sendRawData()", + }) + } if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no 't' in payload-data of the raw event:", data); return; } @@ -422,20 +455,48 @@ export class LavalinkManager extends EventEmitter { if (["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"].includes(data.t)) { const update = ("d" in data ? data.d : data) as VoiceServer | VoiceState; if (!update) { + if(this.options?.advancedOptions?.enableDebugEvents) { + this.emit("debug", DebugEvents.NoAudioDebug, { + state: "warn", + message: `No Update data found in payload :: ${JSON.stringify(data, null, 2)}`, + functionLayer: "LavalinkManager > sendRawData()", + }) + } if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no update data found in payload:", data); return; } if (!("token" in update) && !("session_id" in update)) { + if(this.options?.advancedOptions?.enableDebugEvents) { + this.emit("debug", DebugEvents.NoAudioDebug, { + state: "error", + message: `No 'token' nor 'session_id' found in payload :: ${JSON.stringify(data, null, 2)}`, + functionLayer: "LavalinkManager > sendRawData()", + }) + } if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, no 'token' nor 'session_id' found in payload:", data); return; } const player = this.getPlayer(update.guild_id) as Player; if (!player) { + if(this.options?.advancedOptions?.enableDebugEvents) { + this.emit("debug", DebugEvents.NoAudioDebug, { + state: "warn", + message: `No Lavalink Player found via key: 'guild_id' of update-data :: ${JSON.stringify(update, null, 2)}`, + functionLayer: "LavalinkManager > sendRawData()", + }) + } if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, No Lavalink Player found via key: 'guild_id' of update-data:", update); return; } if (player.get("internal_destroystatus") === true) { + if(this.options?.advancedOptions?.enableDebugEvents) { + this.emit("debug", DebugEvents.NoAudioDebug, { + state: "warn", + message: `Player is in a destroying state. can't signal the voice states`, + functionLayer: "LavalinkManager > sendRawData()", + }) + } if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Player is in a destroying state. can't signal the voice states") return; } @@ -452,12 +513,24 @@ export class LavalinkManager extends EventEmitter { } } }); + if(this.options?.advancedOptions?.enableDebugEvents) { + this.emit("debug", DebugEvents.NoAudioDebug, { + state: "log", + message: `Sent updatePlayer for voice token session :: ${JSON.stringify({ voice: { token: update.token, endpoint: update.endpoint, sessionId: player.voice?.sessionId, }, update }, null, 2)}`, + functionLayer: "LavalinkManager > sendRawData()", + }) + } if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, Sent updatePlayer for voice token session", { voice: { token: update.token, endpoint: update.endpoint, sessionId: player.voice?.sessionId, } }); return } /* voice state update */ if (update.user_id !== this.options?.client.id) { + this.emit("debug", DebugEvents.NoAudioDebug, { + state: "warn", + message: `voice update user is not equal to provided client id of the LavalinkManager.options.client.id :: user: "${update.user_id}" manager client id: "${this.options?.client.id}"`, + functionLayer: "LavalinkManager > sendRawData()", + }) if (this.options?.advancedOptions?.debugOptions?.noAudio === true) console.debug("Lavalink-Client-Debug | NO-AUDIO [::] sendRawData function, voice update user is not equal to provided client id of the manageroptions#client#id", "user:", update.user_id, "manager client id:", this.options?.client.id); return; } @@ -476,7 +549,13 @@ export class LavalinkManager extends EventEmitter { if (this.options?.playerOptions?.onDisconnect?.autoReconnect === true) { try { const positionPrevios = player.position; - console.debug("Auto reconnect", positionPrevios, player.lastPosition); + + this.emit("debug", DebugEvents.PlayerAutoReconnect, { + state: "log", + message: `Auto reconnecting player because LavalinkManager.options.playerOptions.onDisconnect.autoReconnect is true`, + functionLayer: "LavalinkManager > sendRawData()", + }) + await player.connect(); // replay the current playing stream await player.play({ diff --git a/src/structures/Node.ts b/src/structures/Node.ts index 22ad3ed..3f5a22d 100644 --- a/src/structures/Node.ts +++ b/src/structures/Node.ts @@ -1,7 +1,7 @@ import { isAbsolute } from "path"; import WebSocket from "ws"; -import { DestroyReasons, validSponsorBlocks } from "./Constants"; +import { DebugEvents, DestroyReasons, validSponsorBlocks } from "./Constants"; import { NodeSymbol, queueTrackEnd } from "./Utils"; import type { Player } from "./Player"; @@ -218,12 +218,14 @@ export class LavalinkNode { let uri = `/loadtracks?identifier=`; if(/^https?:\/\//.test(Query.query) || ["http", "https", "link", "uri"].includes(Query.source)) { // if it's a link simply encode it - uri += encodeURIComponent(Query.query); + const url = encodeURIComponent(Query.query); + uri += url; } else { // if not make a query out of it if(Query.source !== "local") uri += `${Query.source}:`; // only add the query source string if it's not a local track if(Query.source === "ftts") uri += `//${encodeURIComponent(Query.query)}`; else uri += encodeURIComponent(Query.query); } + const res = await this.request(uri, (options) => { if(typeof query === "object" && typeof query.extraQueryUrlParams?.size === "number" && query.extraQueryUrlParams?.size > 0) { options.extraQueryUrlParams = query.extraQueryUrlParams; @@ -237,7 +239,16 @@ export class LavalinkNode { // transform the data which can be Error, Track or Track[] to enfore [Track] const resTracks = res.loadType === "playlist" ? res.data?.tracks : res.loadType === "track" ? [res.data] : res.loadType === "search" ? Array.isArray(res.data) ? res.data : [res.data] : []; - if(throwOnEmpty === true && (res.loadType === "empty" || !resTracks.length)) throw new Error("Nothing found"); + if(throwOnEmpty === true && (res.loadType === "empty" || !resTracks.length)) { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.SearchNothingFound, { + state: "warn", + message: `Search found nothing for Request: "${Query.source ? `${Query.source}:` : ""}${Query.query}"`, + functionLayer: "(LavalinkNode > node | player) > search()", + }); + } + throw new Error("Nothing found"); + } return { loadType: res.loadType, @@ -284,7 +295,16 @@ export class LavalinkNode { const res = (request.status === 204 ? { } : await request.json()) as LavaSearchResponse; - if(throwOnEmpty === true && !Object.entries(res).flat().filter(Boolean).length) throw new Error("Nothing found"); + if(throwOnEmpty === true && !Object.entries(res).flat().filter(Boolean).length) { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.LavaSearchNothingFound, { + state: "warn", + message: `LavaSearch found nothing for Request: "${Query.source ? `${Query.source}:` : ""}${Query.query}"`, + functionLayer: "(LavalinkNode > node | player) > lavaSearch()", + }); + } + throw new Error("Nothing found"); + } return { tracks: res.tracks?.map(v => this.NodeManager.LavalinkManager.utils.buildTrack(v, requestUser)) || [], @@ -310,6 +330,7 @@ export class LavalinkNode { public async updatePlayer(data: PlayerUpdateInfo) { if (!this.sessionId) throw new Error("The Lavalink Node is either not ready, or not up to date!"); this.syncPlayerData(data); + const res = await this.request(`/sessions/${this.sessionId}/players/${data.guildId}`, r => { r.method = "PATCH"; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion @@ -324,6 +345,14 @@ export class LavalinkNode { } }) as LavalinkPlayer; + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.PlayerUpdateSuccess, { + state: "log", + message: `Player get's updated with following payload :: ${JSON.stringify(data.playerOptions, null, 3)}`, + functionLayer: "LavalinkNode > node > updatePlayer()", + }); + } + return this.syncPlayerData({}, res), res; } @@ -358,7 +387,16 @@ export class LavalinkNode { * ``` */ public connect(sessionId?:string): void { - if (this.connected) return; + if (this.connected) { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.TryingConnectWhileConnected, { + state: "warn", + message: `Tryed to connect to node, but it's already connected!`, + functionLayer: "LavalinkNode > node > connect()", + }); + } + return; + } const headers = { Authorization: this.options.authorization, @@ -381,9 +419,33 @@ export class LavalinkNode { private heartBeat() { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.HeartBeatTriggered, { + state: "log", + message: `Node Socket Heartbeat triggered, resetting old Timeout to 65000ms (should happen every 60s due to /stats event)`, + functionLayer: "LavalinkNode > nodeEvent > stats > heartBeat()", + }); + } + if(this.pingTimeout) clearTimeout(this.pingTimeout); this.pingTimeout = setTimeout(() => { - if(!this.socket) return console.error("Node-Ping-Acknowledge-Timeout - Socket not available - maybe reconnecting?"); + if(!this.socket) { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.NoSocketOnDestroy, { + state: "error", + message: `Heartbeat registered a disconnect, but socket didn't exist therefore can't terminate`, + functionLayer: "LavalinkNode > nodeEvent > stats > heartBeat() > timeoutHit", + }); + } + return; + } + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.SocketTerminateHeartBeatTimeout, { + state: "warn", + message: `Heartbeat registered a disconnect, because timeout wasn't resetted in time. Terminating Web-Socket`, + functionLayer: "LavalinkNode > nodeEvent > stats > heartBeat() > timeoutHit", + }); + } this.isAlive = false; this.socket.terminate(); }, 65_000); // the stats endpoint get's sent every 60s. se wee add a 5s buffer to make sure we don't miss any stats message @@ -874,7 +936,16 @@ export class LavalinkNode { break; case "playerUpdate": { const player = this.NodeManager.LavalinkManager.getPlayer(payload.guildId); - if (!player) return; + if (!player) { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.PlayerUpdateNoPlayer, { + state: "error", + message: `PlayerUpdate Event Triggered, but no player found of payload.guildId: ${payload.guildId}`, + functionLayer: "LavalinkNode > nodeEvent > playerUpdate", + }); + } + return; + } const oldPlayer = player?.toJSON(); @@ -887,6 +958,15 @@ export class LavalinkNode { if(player.filterManager.filterUpdatedState === true && ((player.queue.current?.info?.duration || 0) <= (player.LavalinkManager.options.advancedOptions.maxFilterFixDuration || 600_000) || isAbsolute(player.queue.current?.info?.uri))) { player.filterManager.filterUpdatedState = false; + + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.PlayerUpdateFilterFixApply, { + state: "log", + message: `Fixing FilterState on "${player.guildId}" because player.options.instaUpdateFiltersFix === true`, + functionLayer: "LavalinkNode > nodeEvent > playerUpdate", + }); + } + await player.seek(player.position) } this.NodeManager.LavalinkManager.emit("playerUpdate", oldPlayer, player); @@ -901,7 +981,14 @@ export class LavalinkNode { try { this.NodeManager.emit("resumed", this, payload, await this.fetchAllPlayers()) } catch (e) { - console.error("Failed to fetch players for resumed event, falling back without players array", e); + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.ResumingFetchingError, { + state: "error", + message: `Failed to fetch players for resumed event, falling back without players array`, + error: e, + functionLayer: "LavalinkNode > nodeEvent > resumed", + }); + } this.NodeManager.emit("resumed", this, payload, []) } } @@ -946,10 +1033,30 @@ export class LavalinkNode { player.playing = true; player.paused = false; // don't emit the event if previous track == new track aka track loop - if(this.NodeManager.LavalinkManager.options?.emitNewSongsOnly === true && player.queue.previous[0]?.info?.identifier === track?.info?.identifier) return; + if(this.NodeManager.LavalinkManager.options?.emitNewSongsOnly === true && player.queue.previous[0]?.info?.identifier === track?.info?.identifier) { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.TrackStartNewSongsOnly, { + state: "log", + message: `TrackStart not Emitting, because playing the previous song again.`, + functionLayer: "LavalinkNode > trackStart()", + }); + } + return; + } if(!player.queue.current) { player.queue.current = await this.getTrackOfPayload(payload); - if(player.queue.current) await player.queue.utils.save(); + if(player.queue.current) { + await player.queue.utils.save(); + } + else { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.TrackStartNoTrack, { + state: "warn", + message: `Trackstart emitted but there is no track on player.queue.current, trying to get the track of the payload failed too.`, + functionLayer: "LavalinkNode > trackStart()", + }); + } + } } return this.NodeManager.LavalinkManager.emit("trackStart", player, player.queue.current, payload); } @@ -959,6 +1066,13 @@ export class LavalinkNode { const trackToUse = track || await this.getTrackOfPayload(payload); // If a track was forcibly played if (payload.reason === "replaced") { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.TrackEndReplaced, { + state: "warn", + message: `TrackEnd Event does not handle any playback, because the track was replaced.`, + functionLayer: "LavalinkNode > trackEnd()", + }); + } return this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload); } // If there are no songs in the queue @@ -980,9 +1094,9 @@ export class LavalinkNode { if (player.queue.previous.length > player.queue.options.maxPreviousTracks) player.queue.previous.splice(player.queue.options.maxPreviousTracks, player.queue.previous.length); await player.queue.utils.save(); } - player.set("internal_skipped", false); // if no track available, end queue if (!player.queue.current) return this.queueEnd(player, trackToUse, payload); + player.set("internal_skipped", false); // fire event this.NodeManager.LavalinkManager.emit("trackEnd", player, trackToUse, payload); // play track if autoSkip is true @@ -991,13 +1105,30 @@ export class LavalinkNode { /** @private util function for handling trackStuck event */ private async trackStuck(player: Player, track: Track, payload: TrackStuckEvent) { + if(this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.threshold > 0 && this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.maxAmount >= 0) { + const oldTimestamps = (player.get("internal_erroredTracksTimestamps") as number[] || []) + .filter(v => Date.now() - v < this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.threshold); + player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]); + if(oldTimestamps.length > this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.maxAmount) { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.TrackStuckMaxTracksErroredPerTime, { + state: "log", + message: `trackStuck Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`, + functionLayer: "LavalinkNode > trackStuck()", + }); + } + return player.destroy(DestroyReasons.TrackStuckMaxTracksErroredPerTime); + } + } this.NodeManager.LavalinkManager.emit("trackStuck", player, track || await this.getTrackOfPayload(payload), payload); // If there are no songs in the queue if (!player.queue.tracks.length && (player.repeatMode === "off" || player.get("internal_stopPlaying"))) return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload); // remove the current track, and enqueue the next one await queueTrackEnd(player); // if no track available, end queue - if (!player.queue.current) return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload); + if (!player.queue.current) { + return this.queueEnd(player, track || await this.getTrackOfPayload(payload), payload); + } // play track if autoSkip is true return (this.NodeManager.LavalinkManager.options.autoSkip && player.queue.current) && player.play({ noReplace: true }); } @@ -1008,6 +1139,22 @@ export class LavalinkNode { track: Track, payload: TrackExceptionEvent ) { + if(this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.threshold > 0 && this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.maxAmount >= 0) { + const oldTimestamps = (player.get("internal_erroredTracksTimestamps") as number[] || []) + .filter(v => Date.now() - v < this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.threshold); + player.set("internal_erroredTracksTimestamps", [...oldTimestamps, Date.now()]); + if(oldTimestamps.length > this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.maxAmount) { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.TrackErrorMaxTracksErroredPerTime, { + state: "log", + message: `TrackError Event was triggered too often within a given threshold (LavalinkManager.options.playerOptions.maxErrorsPerTime). Threshold: "${this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.threshold}ms", maxAmount: "${this.NodeManager.LavalinkManager.options.playerOptions.maxErrorsPerTime?.maxAmount}"`, + functionLayer: "LavalinkNode > trackError()", + }); + } + return player.destroy(DestroyReasons.TrackErrorMaxTracksErroredPerTime); + } + } + this.NodeManager.LavalinkManager.emit("trackError", player, track || await this.getTrackOfPayload(payload), payload); return; // get's handled by trackEnd // If there are no songs in the queue @@ -1094,6 +1241,15 @@ export class LavalinkNode { r.headers = { Authorization: this.options.authorization, 'Content-Type': 'application/json' } r.body = JSON.stringify(segments.map(v => v.toLowerCase())); }); + + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.SetSponsorBlock, { + state: "log", + message: `SponsorBlock was set for Player: ${player.guildId} to: ${segments.map(v => `'${v.toLowerCase()}'`).join(", ")}`, + functionLayer: "LavalinkNode > setSponsorBlock()", + }); + } + return; } @@ -1115,6 +1271,14 @@ export class LavalinkNode { await this.request(`/sessions/${this.sessionId}/players/${player.guildId}/sponsorblock/categories`, (r) => { r.method = "DELETE"; }); + + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.DeleteSponsorBlock, { + state: "log", + message: `SponsorBlock was deleted for Player: ${player.guildId}`, + functionLayer: "LavalinkNode > deleteSponsorBlock()", + }); + } return; } @@ -1125,15 +1289,45 @@ export class LavalinkNode { player.playing = false; player.set("internal_stopPlaying", undefined); + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.QueueEnded, { + state: "log", + message: `Queue Ended because no more Tracks were in the Queue, due to EventName: "${payload.type}"`, + functionLayer: "LavalinkNode > queueEnd()", + }); + } + if(typeof this.NodeManager.LavalinkManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction === "function" && typeof player.get("internal_autoplayStopPlaying") === "undefined") { - await this.NodeManager.LavalinkManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction(player, track); - if(player.queue.tracks.length > 0) await queueTrackEnd(player); - if(player.queue.current) { - if(payload.type === "TrackEndEvent") this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload); - return player.play({ noReplace: true, paused: false }); + const previousAutoplayTime = player.get("internal_previousautoplay") as number; + const duration = previousAutoplayTime ? Date.now() - previousAutoplayTime : 0; + if((duration && duration > this.NodeManager.LavalinkManager.options.playerOptions.minAutoPlayMs) || !!player.get("internal_skipped")) { + await this.NodeManager.LavalinkManager.options?.playerOptions?.onEmptyQueue?.autoPlayFunction(player, track); + player.set("internal_previousautoplay", Date.now()); + if(player.queue.tracks.length > 0) await queueTrackEnd(player); + else if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.AutoplayNoSongsAdded, { + state: "warn", + message: `Autoplay was triggered but no songs were added to the queue.`, + functionLayer: "LavalinkNode > queueEnd() > autoplayFunction", + }); + } + if(player.queue.current) { + if(payload.type === "TrackEndEvent") this.NodeManager.LavalinkManager.emit("trackEnd", player, track, payload); + return player.play({ noReplace: true, paused: false }); + } + } else { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.AutoplayThresholdSpamLimiter, { + state: "warn", + message: `Autoplay was triggered after the previousautoplay too early. Threshold is: ${this.NodeManager.LavalinkManager.options.playerOptions.minAutoPlayMs}ms and the Duration was ${duration}ms`, + functionLayer: "LavalinkNode > queueEnd() > autoplayFunction", + }); + } } } - player.set("internal_autoplayStopPlaying", undefined); + + player.set("internal_skipped", false); + player.set("internal_autoplayStopPlaying", Date.now()); if (track && !track?.pluginInfo?.clientData?.previousTrack) { // If there was a current Track already and repeatmode === true, add it to the queue. player.queue.previous.unshift(track); @@ -1148,6 +1342,13 @@ export class LavalinkNode { if(typeof this.NodeManager.LavalinkManager.options.playerOptions?.onEmptyQueue?.destroyAfterMs === "number" && !isNaN(this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs) && this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs >= 0) { if(this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs === 0) return player.destroy(DestroyReasons.QueueEmpty); else { + if(this.NodeManager.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.NodeManager.LavalinkManager.emit("debug", DebugEvents.TriggerQueueEmptyInterval, { + state: "log", + message: `Trigger Queue Empty Interval was Triggered because playerOptions.onEmptyQueue.destroyAfterMs is set to ${this.NodeManager.LavalinkManager.options.playerOptions.onEmptyQueue?.destroyAfterMs}ms`, + functionLayer: "LavalinkNode > queueEnd() > destroyAfterMs", + }); + } if(player.get("internal_queueempty")) { clearTimeout(player.get("internal_queueempty")); player.set("internal_queueempty", undefined); diff --git a/src/structures/Player.ts b/src/structures/Player.ts index e94adb9..c1bbf69 100644 --- a/src/structures/Player.ts +++ b/src/structures/Player.ts @@ -1,10 +1,11 @@ +import { DebugEvents } from "./Constants"; import { bandCampSearch } from "./CustomSearches/BandCampSearch"; import { FilterManager } from "./Filters"; import { Queue, QueueSaver } from "./Queue"; import { queueTrackEnd } from "./Utils"; -import type { Track, UnresolvedTrack } from "./Types/Track"; import type { DestroyReasons } from "./Constants"; +import type { Track, UnresolvedTrack } from "./Types/Track"; import type { LavalinkNode } from "./Node"; import type { SponsorBlockSegment } from "./Types/Node"; import type { anyObject, LavalinkPlayOptions, PlayerJson, PlayerOptions, PlayOptions, RepeatMode } from "./Types/Player"; @@ -87,9 +88,20 @@ export class Player { this.voiceChannelId = this.options.voiceChannelId; this.textChannelId = this.options.textChannelId || null; - this.node = typeof this.options.node === "string" ? this.LavalinkManager.nodeManager.nodes.get(this.options.node) : this.options.node; + + this.node = typeof this.options.node === "string" + ? this.LavalinkManager.nodeManager.nodes.get(this.options.node) + : this.options.node; if (!this.node || typeof this.node.request !== "function") { + if(typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager.emit("debug", DebugEvents.PlayerCreateNodeNotFound, { + state: "warn", + message: `Player was created with provided node Id: ${this.options.node}, but no node with that Id was found.`, + functionLayer: "Player > constructor()", + }); + } + const least = this.LavalinkManager.nodeManager.leastUsedNodes(); this.node = least.filter(v => options.vcRegion ? v.options?.regions?.includes(options.vcRegion) : true)[0] || least[0] || null; } @@ -152,6 +164,13 @@ export class Player { */ async play(options: Partial = {}) { if (this.get("internal_queueempty")) { + if(typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayQueueEmptyTimeoutClear, { + state: "log", + message: `Player was called to play something, while there was a queueEmpty Timeout set, clearing the timeout.`, + functionLayer: "Player > play()", + }); + } clearTimeout(this.get("internal_queueempty")); this.set("internal_queueempty", undefined); } @@ -195,6 +214,13 @@ export class Player { requester: this.LavalinkManager.utils.getTransformedRequester(options?.track?.requester || {}) as anyObject }; + if(typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayWithTrackReplace, { + state: "log", + message: `Player was called to play something, with a specific track provided. Replacing the current Track and resolving the track on trackStart Event.`, + functionLayer: "Player > play()", + }); + } return this.node.updatePlayer({ guildId: this.guildId, @@ -214,12 +240,29 @@ export class Player { if (!this.queue.current && this.queue.tracks.length) await queueTrackEnd(this); if (this.queue.current && this.LavalinkManager.utils.isUnresolvedTrack(this.queue.current)) { + if(typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayUnresolvedTrack, { + state: "log", + message: `Player Play was called, current Queue Song is unresolved, resolving the track.`, + functionLayer: "Player > play()", + }); + } + try { // resolve the unresolved track await (this.queue.current as unknown as UnresolvedTrack).resolve(this); if (typeof options.track?.userData === "object" && this.queue.current) this.queue.current.userData = { ...(this.queue.current?.userData || {}), ...(options.track?.userData || {}) }; } catch (error) { + if(typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager.emit("debug", DebugEvents.PlayerPlayUnresolvedTrackFailed, { + state: "error", + error: error, + message: `Player Play was called, current Queue Song is unresolved, but couldn't resolve it`, + functionLayer: "Player > play() > resolve currentTrack", + }); + } + this.LavalinkManager.emit("trackError", this, this.queue.current, error); if (options && "clientTrack" in options) delete options.clientTrack; @@ -292,6 +335,13 @@ export class Player { const now = performance.now(); if (this.LavalinkManager.options.playerOptions.applyVolumeAsFilter) { + if(typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager.emit("debug", DebugEvents.PlayerVolumeAsFilter, { + state: "log", + message: `Player Volume was set as a Filter, because LavalinkManager option "playerOptions.applyVolumeAsFilter" is true`, + functionLayer: "Player > setVolume()", + }); + } await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { filters: { volume: this.lavalinkVolume / 100 } } }); } else { await this.node.updatePlayer({ guildId: this.guildId, playerOptions: { volume: this.lavalinkVolume } }); @@ -336,7 +386,16 @@ export class Player { async search(query: SearchQuery, requestUser: unknown, throwOnEmpty: boolean = false) { const Query = this.LavalinkManager.utils.transformQuery(query); - if (["bcsearch", "bandcamp"].includes(Query.source) && !this.node.info.sourceManagers.includes("bandcamp")) return await bandCampSearch(this, Query.query, requestUser); + if (["bcsearch", "bandcamp"].includes(Query.source) && !this.node.info.sourceManagers.includes("bandcamp")) { + if(typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager.emit("debug", DebugEvents.BandcampSearchLokalEngine, { + state: "log", + message: `Player.search was called with a Bandcamp Query, but no bandcamp search was enabled on lavalink, searching with the custom Search Engine.`, + functionLayer: "Player > search()", + }); + } + return await bandCampSearch(this, Query.query, requestUser); + } return this.node.search(Query, requestUser, throwOnEmpty); } @@ -399,7 +458,7 @@ export class Player { if (!["off", "track", "queue"].includes(repeatMode)) throw new RangeError("Repeatmode must be either 'off', 'track', or 'queue'"); this.repeatMode = repeatMode; return this; - }1 + } /** * Skip the current song, or a specific amount of songs @@ -522,6 +581,15 @@ export class Player { public async destroy(reason?: DestroyReasons | string, disconnect: boolean = true) { // [disconnect -> queue destroy -> cache delete -> lavalink destroy -> event emit] if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog) console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Destroy-Reason: ${String(reason)}`); if (this.get("internal_destroystatus") === true) { + + if(this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager.emit("debug", DebugEvents.PlayerDestroyingSomewhereElse, { + state: "warn", + message: `Player is already destroying somewhere else..`, + functionLayer: "Player > destroy()", + }); + } + if (this.LavalinkManager.options.advancedOptions?.debugOptions.playerDestroy.debugLog) console.log(`Lavalink-Client-Debug | PlayerDestroy [::] destroy Function, [guildId ${this.guildId}] - Already destroying somewhere else..`); return; } @@ -552,14 +620,26 @@ export class Player { const updateNode = typeof newNode === "string" ? this.LavalinkManager.nodeManager.nodes.get(newNode) : newNode; if (!updateNode) throw new Error("Could not find the new Node"); + if(typeof this.options.node === "string" && this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager.emit("debug", DebugEvents.PlayerChangeNode, { + state: "log", + message: `Player.changeNode() was executed, trying to change from "${this.node.id}" to "${updateNode.id}"`, + functionLayer: "Player > changeNode()", + }); + } + const data = this.toJSON(); + const currentTrack = this.queue.current; + await this.node.destroyPlayer(this.guildId); this.node = updateNode; const now = performance.now(); + await this.connect(); + await this.node.updatePlayer({ guildId: this.guildId, noReplace: false, @@ -568,9 +648,7 @@ export class Player { volume: Math.round(Math.max(Math.min(data.volume, 1000), 0)), paused: data.paused, filters: { ...data.filters, equalizer: data.equalizer }, - voice: this.voice, - track: this.queue.current ?? undefined - // track: this.queue.current, + track: currentTrack ?? undefined }, }); diff --git a/src/structures/Queue.ts b/src/structures/Queue.ts index 41e3f80..6295425 100644 --- a/src/structures/Queue.ts +++ b/src/structures/Queue.ts @@ -303,11 +303,15 @@ export class Queue { * ``` */ public async remove(removeQueryTrack: T): Promise<{ removed: (Track | UnresolvedTrack)[] } | null> { + const oldStored = typeof this.queueChanges?.tracksRemoved === "function" ? this.utils.toJSON() : null; if (typeof removeQueryTrack === "number") { const toRemove = this.tracks[removeQueryTrack]; if (!toRemove) return null; const removed = this.tracks.splice(removeQueryTrack, 1); + // Log if available + if (typeof this.queueChanges?.tracksRemoved === "function") try { this.queueChanges.tracksRemoved(this.guildId, removed, removeQueryTrack, oldStored, this.utils.toJSON()) } catch (e) { /* */ } + await this.utils.save(); return { removed } @@ -317,9 +321,15 @@ export class Queue { if (removeQueryTrack.every(v => typeof v === "number")) { const removed = []; for (const i of removeQueryTrack) { - if (this.tracks[i]) removed.push(...this.tracks.splice(i, 1)) + if (this.tracks[i]) { + removed.push(...this.tracks.splice(i, 1)) + } } if (!removed.length) return null; + + // Log if available + if (typeof this.queueChanges?.tracksRemoved === "function") try { this.queueChanges.tracksRemoved(this.guildId, removed, removeQueryTrack as number[], oldStored, this.utils.toJSON()) } catch (e) { /* */ } + await this.utils.save(); return { removed }; @@ -342,8 +352,12 @@ export class Queue { const removed = []; for (const { i } of tracksToRemove) { - if (this.tracks[i]) removed.push(...this.tracks.splice(i, 1)) + if (this.tracks[i]) { + removed.push(...this.tracks.splice(i, 1)) + } } + // Log if available + if (typeof this.queueChanges?.tracksRemoved === "function") try { this.queueChanges.tracksRemoved(this.guildId, removed, tracksToRemove.map(v => v.i), oldStored, this.utils.toJSON()) } catch (e) { /* */ } await this.utils.save(); @@ -361,6 +375,9 @@ export class Queue { if (toRemove < 0) return null; const removed = this.tracks.splice(toRemove, 1); + // Log if available + if (typeof this.queueChanges?.tracksRemoved === "function") try { this.queueChanges.tracksRemoved(this.guildId, removed, toRemove, oldStored, this.utils.toJSON()) } catch (e) { /* */ } + await this.utils.save(); return { removed }; diff --git a/src/structures/Types/Manager.ts b/src/structures/Types/Manager.ts index 38ffc37..f0be1a4 100644 --- a/src/structures/Types/Manager.ts +++ b/src/structures/Types/Manager.ts @@ -1,3 +1,5 @@ +import type { DebugEvents } from "../Constants"; + import type { Player } from "../Player"; import type { LavalinkNodeOptions } from "./Node"; import type { DestroyReasonsType, PlayerJson } from "./Player"; @@ -107,6 +109,15 @@ export interface LavalinkManagerEvents { * @event Manager#trackError */ "ChaptersLoaded": (player: Player, track: Track | UnresolvedTrack | null, payload: SponsorBlockChaptersLoaded) => void; + + /** + * Lavalink-Client Debug Event + * Emitted for several erros, and logs within lavalink-client, if managerOptions.advancedOptions.enableDebugEvents is true + * Useful for debugging the lavalink-client + * + * @event Manager#debug + */ + "debug": (eventKey: DebugEvents, eventData: { message: string, state: "log" | "warn" | "error", error?: Error|string, functionLayer: string }) => void; } /** * The Bot client Options needed for the manager @@ -139,6 +150,15 @@ export interface ManagerPlayerOptions { /** Instantly destroy player (overrides autoReconnect) | Don't provide == disable feature*/ destroyPlayer?: boolean; }; + /** Minimum time to play the song before autoPlayFunction is executed (prevents error spamming) Set to 0 to disable it @default 10000 */ + minAutoPlayMs?: number; + /** Allows you to declare how many tracks are allowed to error/stuck within a time-frame before player is destroyed @default "{threshold: 35000, maxAmount: 3 }" */ + maxErrorsPerTime?: { + /** The threshold time to count errors (recommended is 35s) */ + threshold: number; + /** The max amount of errors within the threshold time which are allowed before destroying the player (when errors > maxAmount -> player.destroy()) */ + maxAmount: number; + }; /* What the Player should do, when the queue gets empty */ onEmptyQueue?: { /** Get's executed onEmptyQueue -> You can do any track queue previous transformations, if you add a track to the queue -> it will play it, if not queueEnd will execute! */ @@ -178,6 +198,8 @@ export interface ManagerOptions { advancedOptions?: { /** Max duration for that the filter fix duration works (in ms) - default is 8mins */ maxFilterFixDuration?: number, + /** Enable Debug event */ + enableDebugEvents?: boolean; /** optional */ debugOptions?: { /** For logging custom searches */ diff --git a/src/structures/Types/Queue.ts b/src/structures/Types/Queue.ts index 99f19af..61513ff 100644 --- a/src/structures/Types/Queue.ts +++ b/src/structures/Types/Queue.ts @@ -33,7 +33,7 @@ export interface QueueChangesWatcher { /** get a Value (MUST RETURN UNPARSED!) */ tracksAdd: (guildId: string, tracks: (Track | UnresolvedTrack)[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue) => void; /** Set a value inside a guildId (MUST BE UNPARSED) */ - tracksRemoved: (guildId: string, tracks: (Track | UnresolvedTrack)[], position: number, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue) => void; + tracksRemoved: (guildId: string, tracks: (Track | UnresolvedTrack)[], position: number | number[], oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue) => void; /** Set a value inside a guildId (MUST BE UNPARSED) */ shuffled: (guildId: string, oldStoredQueue: StoredQueue, newStoredQueue: StoredQueue) => void; } diff --git a/src/structures/Utils.ts b/src/structures/Utils.ts index 0166eac..9b191e3 100644 --- a/src/structures/Utils.ts +++ b/src/structures/Utils.ts @@ -3,6 +3,7 @@ import { URL } from "node:url"; import { isRegExp } from "node:util/types"; +import { DebugEvents } from "./Constants"; import { DefaultSources, LavalinkPlugins, SourceLinksRegexes } from "./LavalinkManagerStatics"; import type { LavalinkNodeOptions } from "./Types/Node"; @@ -90,6 +91,14 @@ export class ManagerUtils { Object.defineProperty(r, TrackSymbol, { configurable: true, value: true }); return r; } catch (error) { + if(this.LavalinkManager?.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager?.emit("debug", DebugEvents.BuildTrackError, { + error: error, + functionLayer: "ManagerUtils > buildTrack()", + message: "Error while building track", + state: "error", + }); + } throw new RangeError(`Argument "data" is not a valid track: ${error.message}`); } } @@ -127,6 +136,7 @@ export class ManagerUtils { Object.defineProperty(unresolvedTrack, UnresolvedTrackSymbol, { configurable: true, value: true }); return unresolvedTrack as UnresolvedTrack; } + /** * Validate if a data is equal to a node * @param data @@ -147,7 +157,14 @@ export class ManagerUtils { ? this.LavalinkManager?.options?.playerOptions?.requesterTransformer(requester) : requester; } catch (e) { - console.error("errored while transforming requester:", e); + if(this.LavalinkManager?.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager?.emit("debug", DebugEvents.TransformRequesterFunctionFailed, { + error: e, + functionLayer: "ManagerUtils > getTransformedRequester()", + message: "Your custom transformRequesterFunction failed to execute, please check your function for errors.", + state: "error", + }); + } return requester; } } @@ -200,7 +217,19 @@ export class ManagerUtils { } async getClosestTrack(data: UnresolvedTrack, player: Player): Promise { - return getClosestTrack(data, player); + try { + return getClosestTrack(data, player); + } catch (e) { + if(this.LavalinkManager?.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager?.emit("debug", DebugEvents.GetClosestTrackFailed, { + error: e, + functionLayer: "ManagerUtils > getClosestTrack()", + message: "Failed to resolve track because the getClosestTrack function failed.", + state: "error", + }); + } + throw e; + } } @@ -208,56 +237,77 @@ export class ManagerUtils { if (!node.info) throw new Error("No Lavalink Node was provided"); if (!node.info.sourceManagers?.length) throw new Error("Lavalink Node, has no sourceManagers enabled"); - if (sourceString === "speak" && queryString.length > 100) - // checks for blacklisted links / domains / queries - if (this.LavalinkManager.options?.linksBlacklist?.length > 0 && this.LavalinkManager.options?.linksBlacklist.some(v => (typeof v === "string" && (queryString.toLowerCase().includes(v.toLowerCase()) || v.toLowerCase().includes(queryString.toLowerCase()))) || isRegExp(v) && v.test(queryString))) { + if(!queryString.trim().length) throw new Error(`Query string is empty, please provide a valid query string.`) + + if (sourceString === "speak" && queryString.length > 100) throw new Error(`Query is speak, which is limited to 100 characters.`) + + // checks for blacklisted links / domains / queries + if (this.LavalinkManager.options?.linksBlacklist?.length > 0) { + if(this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager.emit("debug", DebugEvents.ValidatingBlacklistLinks, { + state: "log", + message: `Validating Query against LavalinkManager.options.linksBlacklist, query: "${queryString}"`, + functionLayer: "(LavalinkNode > node | player) > search() > validateQueryString()", + }); + } + if(this.LavalinkManager.options?.linksBlacklist.some(v => (typeof v === "string" && (queryString.toLowerCase().includes(v.toLowerCase()) || v.toLowerCase().includes(queryString.toLowerCase()))) || isRegExp(v) && v.test(queryString))) { throw new Error(`Query string contains a link / word which is blacklisted.`) } + } if (!/^https?:\/\//.test(queryString)) return; else if (this.LavalinkManager.options?.linksAllowed === false) throw new Error("Using links to make a request is not allowed.") // checks for if the query is whitelisted (should only work for links, so it skips the check for no link queries) - if (this.LavalinkManager.options?.linksWhitelist?.length > 0 && !this.LavalinkManager.options?.linksWhitelist.some(v => (typeof v === "string" && (queryString.toLowerCase().includes(v.toLowerCase()) || v.toLowerCase().includes(queryString.toLowerCase()))) || isRegExp(v) && v.test(queryString))) { - throw new Error(`Query string contains a link / word which isn't whitelisted.`) + if (this.LavalinkManager.options?.linksWhitelist?.length > 0) { + if(this.LavalinkManager.options?.advancedOptions?.enableDebugEvents) { + this.LavalinkManager.emit("debug", DebugEvents.ValidatingWhitelistLinks, { + state: "log", + message: `Link was provided to the Query, validating against LavalinkManager.options.linksWhitelist, query: "${queryString}"`, + functionLayer: "(LavalinkNode > node | player) > search() > validateQueryString()", + }); + } + if(!this.LavalinkManager.options?.linksWhitelist.some(v => (typeof v === "string" && (queryString.toLowerCase().includes(v.toLowerCase()) || v.toLowerCase().includes(queryString.toLowerCase()))) || isRegExp(v) && v.test(queryString))) { + throw new Error(`Query string contains a link / word which isn't whitelisted.`) + } } // missing links: beam.pro local getyarn.io clypit pornhub reddit ocreamix soundgasm if ((SourceLinksRegexes.YoutubeMusicRegex.test(queryString) || SourceLinksRegexes.YoutubeRegex.test(queryString)) && !node.info?.sourceManagers?.includes("youtube")) { - throw new Error("Lavalink Node has not 'youtube' enabled"); + throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'youtube' enabled"); } if ((SourceLinksRegexes.SoundCloudMobileRegex.test(queryString) || SourceLinksRegexes.SoundCloudRegex.test(queryString)) && !node.info?.sourceManagers?.includes("soundcloud")) { - throw new Error("Lavalink Node has not 'soundcloud' enabled"); + throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'soundcloud' enabled"); } if (SourceLinksRegexes.bandcamp.test(queryString) && !node.info?.sourceManagers?.includes("bandcamp")) { - throw new Error("Lavalink Node has not 'bandcamp' enabled (introduced with lavaplayer 2.2.0 or lavalink 4.0.6)"); + throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'bandcamp' enabled (introduced with lavaplayer 2.2.0 or lavalink 4.0.6)"); } if (SourceLinksRegexes.TwitchTv.test(queryString) && !node.info?.sourceManagers?.includes("twitch")) { - throw new Error("Lavalink Node has not 'twitch' enabled"); + throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'twitch' enabled"); } if (SourceLinksRegexes.vimeo.test(queryString) && !node.info?.sourceManagers?.includes("vimeo")) { - throw new Error("Lavalink Node has not 'vimeo' enabled"); + throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'vimeo' enabled"); } if (SourceLinksRegexes.tiktok.test(queryString) && !node.info?.sourceManagers?.includes("tiktok")) { - throw new Error("Lavalink Node has not 'tiktok' enabled"); + throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'tiktok' enabled"); } if (SourceLinksRegexes.mixcloud.test(queryString) && !node.info?.sourceManagers?.includes("mixcloud")) { - throw new Error("Lavalink Node has not 'mixcloud' enabled"); + throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'mixcloud' enabled"); } if (SourceLinksRegexes.AllSpotifyRegex.test(queryString) && !node.info?.sourceManagers?.includes("spotify")) { - throw new Error("Lavalink Node has not 'spotify' enabled"); + throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'spotify' enabled"); } if (SourceLinksRegexes.appleMusic.test(queryString) && !node.info?.sourceManagers?.includes("applemusic")) { - throw new Error("Lavalink Node has not 'applemusic' enabled"); + throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'applemusic' enabled"); } if (SourceLinksRegexes.AllDeezerRegex.test(queryString) && !node.info?.sourceManagers?.includes("deezer")) { - throw new Error("Lavalink Node has not 'deezer' enabled"); + throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'deezer' enabled"); } if (SourceLinksRegexes.AllDeezerRegex.test(queryString) && node.info?.sourceManagers?.includes("deezer") && !node.info?.sourceManagers?.includes("http")) { - throw new Error("Lavalink Node has not 'http' enabled, which is required to have 'deezer' to work"); + throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'http' enabled, which is required to have 'deezer' to work"); } if (SourceLinksRegexes.musicYandex.test(queryString) && !node.info?.sourceManagers?.includes("yandexmusic")) { - throw new Error("Lavalink Node has not 'yandexmusic' enabled"); + throw new Error("Query / Link Provided for this Source but Lavalink Node has not 'yandexmusic' enabled"); } return; } diff --git a/testBot/commands/play.ts b/testBot/commands/play.ts index 4060aac..c49d9b0 100644 --- a/testBot/commands/play.ts +++ b/testBot/commands/play.ts @@ -25,19 +25,19 @@ export default { .addStringOption(o => o.setName("query").setDescription("What to play?").setAutocomplete(true).setRequired(true)), execute: async (client, interaction) => { if(!interaction.guildId) return; - + const vcId = (interaction.member as GuildMember)?.voice?.channelId; if(!vcId) return interaction.reply({ ephemeral: true, content: `Join a voice Channel` }); const vc = (interaction.member as GuildMember)?.voice?.channel as VoiceChannel; if(!vc.joinable || !vc.speakable) return interaction.reply({ ephemeral: true, content: "I am not able to join your channel / speak in there." }); - + const src = (interaction.options as CommandInteractionOptionResolver).getString("source") as SearchPlatform|undefined; const query = (interaction.options as CommandInteractionOptionResolver).getString("query") as string; - + if(query === "nothing_found") return interaction.reply({ content: `No Tracks found`, ephemeral: true }); if(query === "join_vc") return interaction.reply({ content: `You joined a VC, but redo the Command please.`, ephemeral: true }); - + const fromAutoComplete = (Number(query.replace("autocomplete_", "")) >= 0 && autocompleteMap.has(`${interaction.user.id}_res`)) && autocompleteMap.get(`${interaction.user.id}_res`); if(autocompleteMap.has(`${interaction.user.id}_res`)) { if(autocompleteMap.has(`${interaction.user.id}_timeout`)) clearTimeout(autocompleteMap.get(`${interaction.user.id}_timeout`)); @@ -46,10 +46,10 @@ export default { } const player = client.lavalink.getPlayer(interaction.guildId) || await client.lavalink.createPlayer({ - guildId: interaction.guildId, - voiceChannelId: vcId, - textChannelId: interaction.channelId, - selfDeaf: true, + guildId: interaction.guildId, + voiceChannelId: vcId, + textChannelId: interaction.channelId, + selfDeaf: true, selfMute: false, volume: client.defaultVolume, // default volume instaUpdateFiltersFix: true, // optional @@ -57,22 +57,22 @@ export default { // node: "YOUR_NODE_ID", // vcRegion: (interaction.member as GuildMember)?.voice.channel?.rtcRegion! }); - + const connected = player.connected; if(!connected) await player.connect(); if(player.voiceChannelId !== vcId) return interaction.reply({ ephemeral: true, content: "You need to be in my Voice Channel" }); - + const response = (fromAutoComplete || await player.search({ query: query, source: src }, interaction.user)) as SearchResult; if(!response || !response.tracks?.length) return interaction.reply({ content: `No Tracks found`, ephemeral: true }); await player.queue.add(response.loadType === "playlist" ? response.tracks : response.tracks[fromAutoComplete ? Number(query.replace("autocomplete_", "")) : 0]); await interaction.reply({ - content: response.loadType === "playlist" - ? `✅ Added [${response.tracks.length}] Tracks${response.playlist?.title ? ` - from the ${response.pluginInfo.type || "Playlist"} ${response.playlist.uri ? `[\`${response.playlist.title}\`](<${response.playlist.uri}>)` : `\`${response.playlist.title}\``}` : ""} at \`#${player.queue.tracks.length-response.tracks.length}\`` - : `✅ Added [\`${response.tracks[0].info.title}\`](<${response.tracks[0].info.uri}>) by \`${response.tracks[0].info.author}\` at \`#${player.queue.tracks.length}\`` + content: response.loadType === "playlist" + ? `✅ Added [${response.tracks.length}] Tracks${response.playlist?.title ? ` - from the ${response.pluginInfo.type || "Playlist"} ${response.playlist.uri ? `[\`${response.playlist.title}\`](<${response.playlist.uri}>)` : `\`${response.playlist.title}\``}` : ""} at \`#${player.queue.tracks.length-response.tracks.length}\`` + : `✅ Added [\`${response.tracks[0].info.title}\`](<${response.tracks[0].info.uri}>) by \`${response.tracks[0].info.author}\` at \`#${player.queue.tracks.length}\`` }); if(!player.playing) await player.play(connected ? { volume: client.defaultVolume, paused: false } : undefined); @@ -92,8 +92,10 @@ export default { if(player.voiceChannelId !== vcId) return interaction.respond([{ name: `You need to be in my Voice Channel`, value: "join_vc" }]); + if(!focussedQuery.trim().length) return await interaction.respond([{ name: `No Tracks found (enter a query)`, value: "nothing_found" }]); + const res = await player.search({ query: focussedQuery, source: interaction.options.getString("source") as SearchPlatform }, interaction.user) as SearchResult; - + if(!res.tracks.length) return await interaction.respond([{ name: `No Tracks found`, value: "nothing_found" }]); // handle the res if(autocompleteMap.has(`${interaction.user.id}_timeout`)) clearTimeout(autocompleteMap.get(`${interaction.user.id}_timeout`)); @@ -103,9 +105,9 @@ export default { autocompleteMap.delete(`${interaction.user.id}_timeout`); }, 25000)); await interaction.respond( - res.loadType === "playlist" ? + res.loadType === "playlist" ? [{ name: `Playlist [${res.tracks.length} Tracks] - ${res.playlist?.title}`, value: `autocomplete_0`}] : res.tracks.map((t:Track, i) => ({ name: `[${formatMS_HHMMSS(t.info.duration)}] ${t.info.title} (by ${t.info.author || "Unknown-Author"})`.substring(0, 100), value: `autocomplete_${i}` })).slice(0, 25) ); } -} as Command; \ No newline at end of file +} as Command; diff --git a/testBot/index.ts b/testBot/index.ts index ede078e..e36d4ce 100644 --- a/testBot/index.ts +++ b/testBot/index.ts @@ -74,6 +74,11 @@ console.log(LavalinkNodesOfEnv); // you can then provide the result of here in L username: "TESTBOT" }, playerOptions: { + maxErrorsPerTime: { + threshold: 10_000, + maxAmount: 3 + }, + minAutoPlayMs: 10_000, applyVolumeAsFilter: false, clientBasedPositionUpdateInterval: 50, // in ms to up-calc player.position defaultSearchPlatform: "ytmsearch", @@ -94,15 +99,16 @@ console.log(LavalinkNodesOfEnv); // you can then provide the result of here in L queueStore: new myCustomStore(client.redis), queueChangesWatcher: new myCustomWatcher(client) }, - linksBlacklist: [], + linksBlacklist: ["porn", "youtube.com", "youtu.be"], linksWhitelist: [], advancedOptions: { + enableDebugEvents: true, maxFilterFixDuration: 600_000, // only allow instafixfilterupdate for tracks sub 10mins debugOptions: { - noAudio: true, + noAudio: false, playerDestroy: { - dontThrowError: true, - debugLog: true + dontThrowError: false, + debugLog: false } } } diff --git a/testBot/lavalinkEvents/Player.ts b/testBot/lavalinkEvents/Player.ts index c100ba9..7b6d8cf 100644 --- a/testBot/lavalinkEvents/Player.ts +++ b/testBot/lavalinkEvents/Player.ts @@ -1,5 +1,6 @@ import { EmbedBuilder, TextChannel } from "discord.js"; +import { DebugEvents } from "../../src"; import { BotClient, CustomRequester } from "../types/Client"; import { formatMS_HHMMSS } from "../Utils/Time"; @@ -28,7 +29,19 @@ export function PlayerEvents(client:BotClient) { console.log(player.guildId, " :: Player moved from Voice Channel :: ", oldVoiceChannelId, " :: To ::", newVoiceChannelId); }).on("playerSocketClosed", (player, payload) => { console.log(player.guildId, " :: Player socket got closed from lavalink :: ", payload); - }) + }).on("debug", (eventKey, eventData) => { + // skip specific log + if(eventKey === DebugEvents.NoAudioDebug && eventData.message === "Manager is not initated yet") return; + // skip specific event log of a log-level-state "log" + if(eventKey === DebugEvents.PlayerUpdateSuccess && eventData.state === "log") return; + + console.group("Lavalink-Client-Debug:"); + console.log("-".repeat(20)); + console.debug(`[${eventKey}]`); + console.debug(eventData) + console.log("-".repeat(20)); + console.groupEnd(); + }); /** * Queue/Track Events diff --git a/testBot/playerData.json b/testBot/playerData.json deleted file mode 100644 index 3da73e2..0000000 --- a/testBot/playerData.json +++ /dev/null @@ -1 +0,0 @@ -{"1180208273958375524":"{\"guildId\":\"1180208273958375524\",\"options\":{\"guildId\":\"1180208273958375524\",\"voiceChannelId\":\"1192564843912372265\",\"textChannelId\":\"1279572486832394271\",\"selfDeaf\":true,\"selfMute\":false,\"volume\":100,\"node\":\"testnode\",\"applyVolumeAsFilter\":false,\"instaUpdateFiltersFix\":true},\"voiceChannelId\":\"1192564843912372265\",\"textChannelId\":\"1279572486832394271\",\"position\":0,\"lastPosition\":0,\"lastPositionChange\":1725722701527,\"volume\":100,\"lavalinkVolume\":75,\"repeatMode\":\"off\",\"paused\":false,\"playing\":true,\"createdTimeStamp\":1725722693027,\"filters\":{},\"equalizer\":[],\"nodeId\":\"testnode\",\"nodeSessionId\":\"rbgzmack60hqpxp5\",\"ping\":{\"lavalink\":32,\"ws\":0},\"queue\":{\"current\":{\"encoded\":\"QAABzgMAC0NvdW50IG9uIE1lAApCcnVubyBNYXJzAAAAAAADA10AFjdsMXF2eFdqeGNLcEI5UEN0QnVUYlUAAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL3RyYWNrLzdsMXF2eFdqeGNLcEI5UEN0QnVUYlUBAEBodHRwczovL2kuc2Nkbi5jby9pbWFnZS9hYjY3NjE2ZDAwMDBiMjczZjZiNTVjYTkzYmQzMzIxMTIyN2I1MDJiAQAMVVNFRTExMDAwMTY4AAdzcG90aWZ5AQAURG9vLVdvcHMgJiBIb29saWdhbnMBADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vYWxidW0vMXV5ZjNsMmQ0WFl3aUVxQWI3dDdmWAEANmh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hcnRpc3QvMGR1NWNFVmg1eVRLOVFKemU4ekEwQwABAGtodHRwczovL3Auc2Nkbi5jby9tcDMtcHJldmlldy81MjVjM2M3N2E4YTM3OWM5YjY4NTllY2EzYjNlYzU0YmVhMzBlZjViP2NpZD1kY2ViYjlmOTg5ZmI0ODlhODlmYmMzMmU0NDM3YTgxMgAAAAAAAAAAAA==\",\"info\":{\"identifier\":\"7l1qvxWjxcKpB9PCtBuTbU\",\"title\":\"Count on Me\",\"author\":\"Bruno Mars\",\"duration\":197469,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273f6b55ca93bd33211227b502b\",\"uri\":\"https://open.spotify.com/track/7l1qvxWjxcKpB9PCtBuTbU\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USEE11000168\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/7l1qvxWjxcKpB9PCtBuTbU\",\"albumUrl\":\"https://open.spotify.com/album/1uyf3l2d4XYwiEqAb7t7fX\",\"albumName\":\"Doo-Wops & Hooligans\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/525c3c77a8a379c9b6859eca3b3ec54bea30ef5b?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"previous\":[{\"encoded\":\"QAAB1gMAE1RhbGtpbmcgdG8gdGhlIE1vb24ACkJydW5vIE1hcnMAAAAAAANTCgAWMTYxRG5MV3N4MWkzdTFKVDA1bHpxVQABADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vdHJhY2svMTYxRG5MV3N4MWkzdTFKVDA1bHpxVQEAQGh0dHBzOi8vaS5zY2RuLmNvL2ltYWdlL2FiNjc2MTZkMDAwMGIyNzNmNmI1NWNhOTNiZDMzMjExMjI3YjUwMmIBAAxVU0FUMjEwMDE5ODUAB3Nwb3RpZnkBABREb28tV29wcyAmIEhvb2xpZ2FucwEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hbGJ1bS8xdXlmM2wyZDRYWXdpRXFBYjd0N2ZYAQA2aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FydGlzdC8wZHU1Y0VWaDV5VEs5UUp6ZTh6QTBDAAEAa2h0dHBzOi8vcC5zY2RuLmNvL21wMy1wcmV2aWV3LzZmZWJhMWI0MTI1MzBhYjBkOWRkMWY4NDkxODBmMDM5ODMxYWNjNDI/Y2lkPWRjZWJiOWY5ODlmYjQ4OWE4OWZiYzMyZTQ0MzdhODEyAAAAAAAAAzFE\",\"info\":{\"identifier\":\"161DnLWsx1i3u1JT05lzqU\",\"title\":\"Talking to the Moon\",\"author\":\"Bruno Mars\",\"duration\":217881,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273f6b55ca93bd33211227b502b\",\"uri\":\"https://open.spotify.com/track/161DnLWsx1i3u1JT05lzqU\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21001985\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/161DnLWsx1i3u1JT05lzqU\",\"albumUrl\":\"https://open.spotify.com/album/1uyf3l2d4XYwiEqAb7t7fX\",\"albumName\":\"Doo-Wops & Hooligans\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/6feba1b412530ab0d9dd1f849180f039831acc42?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAABzAMACU1hcnJ5IFlvdQAKQnJ1bm8gTWFycwAAAAAAA4MwABYyMlBNZnZkejM1ZkZLWW5KeU1uMDc3AAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay8yMlBNZnZkejM1ZkZLWW5KeU1uMDc3AQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3M2Y2YjU1Y2E5M2JkMzMyMTEyMjdiNTAyYgEADFVTQVQyMTAwMTg4NwAHc3BvdGlmeQEAFERvby1Xb3BzICYgSG9vbGlnYW5zAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzF1eWYzbDJkNFhZd2lFcUFiN3Q3ZlgBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvNjc0N2EzNjc0ZWMwYjI0YWI5MDY3OTcyYmIxOTI5MWMzMDQ4YThkMj9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"22PMfvdz35fFKYnJyMn077\",\"title\":\"Marry You\",\"author\":\"Bruno Mars\",\"duration\":230192,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273f6b55ca93bd33211227b502b\",\"uri\":\"https://open.spotify.com/track/22PMfvdz35fFKYnJyMn077\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21001887\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/22PMfvdz35fFKYnJyMn077\",\"albumUrl\":\"https://open.spotify.com/album/1uyf3l2d4XYwiEqAb7t7fX\",\"albumName\":\"Doo-Wops & Hooligans\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/6747a3674ec0b24ab9067972bb19291c3048a8d2?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB0AMADVRoZSBMYXp5IFNvbmcACkJydW5vIE1hcnMAAAAAAALitQAWMUV4ZlBaRWlhaHFoTHlhamh5YkZlUwABADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vdHJhY2svMUV4ZlBaRWlhaHFoTHlhamh5YkZlUwEAQGh0dHBzOi8vaS5zY2RuLmNvL2ltYWdlL2FiNjc2MTZkMDAwMGIyNzNmNmI1NWNhOTNiZDMzMjExMjI3YjUwMmIBAAxVU0FUMjEwMDE4ODYAB3Nwb3RpZnkBABREb28tV29wcyAmIEhvb2xpZ2FucwEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hbGJ1bS8xdXlmM2wyZDRYWXdpRXFBYjd0N2ZYAQA2aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FydGlzdC8wZHU1Y0VWaDV5VEs5UUp6ZTh6QTBDAAEAa2h0dHBzOi8vcC5zY2RuLmNvL21wMy1wcmV2aWV3LzhhNmNkNjY3OWZjMmEzODhiOTg5YTA5YjU3MTE5NDcyM2Q0NWNiNzE/Y2lkPWRjZWJiOWY5ODlmYjQ4OWE4OWZiYzMyZTQ0MzdhODEyAAAAAAAAAAAA\",\"info\":{\"identifier\":\"1ExfPZEiahqhLyajhybFeS\",\"title\":\"The Lazy Song\",\"author\":\"Bruno Mars\",\"duration\":189109,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273f6b55ca93bd33211227b502b\",\"uri\":\"https://open.spotify.com/track/1ExfPZEiahqhLyajhybFeS\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21001886\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/1ExfPZEiahqhLyajhybFeS\",\"albumUrl\":\"https://open.spotify.com/album/1uyf3l2d4XYwiEqAb7t7fX\",\"albumName\":\"Doo-Wops & Hooligans\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/8a6cd6679fc2a388b989a09b571194723d45cb71?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAABygMAB0dyZW5hZGUACkJydW5vIE1hcnMAAAAAAANjiwAWMnRKdWxVWUxES09nOVhydFZrTWdjSgABADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vdHJhY2svMnRKdWxVWUxES09nOVhydFZrTWdjSgEAQGh0dHBzOi8vaS5zY2RuLmNvL2ltYWdlL2FiNjc2MTZkMDAwMGIyNzNmNmI1NWNhOTNiZDMzMjExMjI3YjUwMmIBAAxVU0FUMjEwMDE4ODMAB3Nwb3RpZnkBABREb28tV29wcyAmIEhvb2xpZ2FucwEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hbGJ1bS8xdXlmM2wyZDRYWXdpRXFBYjd0N2ZYAQA2aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FydGlzdC8wZHU1Y0VWaDV5VEs5UUp6ZTh6QTBDAAEAa2h0dHBzOi8vcC5zY2RuLmNvL21wMy1wcmV2aWV3LzUyMjFiZTU5MmM4MzJlMTQ1MDZmNjMwNGZmMWRlYjZjNTJhZTNmZWU/Y2lkPWRjZWJiOWY5ODlmYjQ4OWE4OWZiYzMyZTQ0MzdhODEyAAAAAAAAAAAA\",\"info\":{\"identifier\":\"2tJulUYLDKOg9XrtVkMgcJ\",\"title\":\"Grenade\",\"author\":\"Bruno Mars\",\"duration\":222091,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273f6b55ca93bd33211227b502b\",\"uri\":\"https://open.spotify.com/track/2tJulUYLDKOg9XrtVkMgcJ\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21001883\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/2tJulUYLDKOg9XrtVkMgcJ\",\"albumUrl\":\"https://open.spotify.com/album/1uyf3l2d4XYwiEqAb7t7fX\",\"albumName\":\"Doo-Wops & Hooligans\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/5221be592c832e14506f6304ff1deb6c52ae3fee?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB/AMACVRoZSBTcGFyawAKS2FiaW4gQ3JldwAAAAAAAjpQAAoyODM1NDIxODgyAAEAI2h0dHBzOi8vZGVlemVyLmNvbS90cmFjay8yODM1NDIxODgyAQBpaHR0cHM6Ly9lLWNkbnMtaW1hZ2VzLmR6Y2RuLm5ldC9pbWFnZXMvY292ZXIvNTMxY2UxNTU5MWZlMWNjYmZhMzMxYjdhOTY1NDk1ZWQvMTAwMHgxMDAwLTAwMDAwMC04MC0wLTAuanBnAQAMSUVBQ0oyNDAwMDY4AAZkZWV6ZXIBAAlUaGUgU3BhcmsBACZodHRwczovL3d3dy5kZWV6ZXIuY29tL2FsYnVtLzU5Nzc2NzA1MgEAJmh0dHBzOi8vd3d3LmRlZXplci5jb20vYXJ0aXN0Lzg3MjI1NjkyAQBqaHR0cHM6Ly9lLWNkbnMtaW1hZ2VzLmR6Y2RuLm5ldC9pbWFnZXMvYXJ0aXN0LzljODRjYjNjODk1YjBmMDdjNTRlYWYyYzI2MTU3NjIxLzEwMDB4MTAwMC0wMDAwMDAtODAtMC0wLmpwZwEAT2h0dHBzOi8vY2RuLXByZXZpZXctYi5kemNkbi5uZXQvc3RyZWFtL2MtYmEwNTA1ZWY0ZjE0MjI5NTUwYzQ0YzUyODcyYjQ2YTYtMS5tcDMAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"2835421882\",\"title\":\"The Spark\",\"author\":\"Kabin Crew\",\"duration\":146000,\"artworkUrl\":\"https://e-cdns-images.dzcdn.net/images/cover/531ce15591fe1ccbfa331b7a965495ed/1000x1000-000000-80-0-0.jpg\",\"uri\":\"https://deezer.com/track/2835421882\",\"sourceName\":\"deezer\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"IEACJ2400068\"},\"userData\":{},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://deezer.com/track/2835421882\",\"albumUrl\":\"https://www.deezer.com/album/597767052\",\"albumName\":\"The Spark\",\"previewUrl\":\"https://cdn-preview-b.dzcdn.net/stream/c-ba0505ef4f14229550c44c52872b46a6-1.mp3\",\"isPreview\":false,\"artistUrl\":\"https://www.deezer.com/artist/87225692\",\"artistArtworkUrl\":\"https://e-cdns-images.dzcdn.net/images/artist/9c84cb3c895b0f07c54eaf2c26157621/1000x1000-000000-80-0-0.jpg\"},\"requester\":{\"id\":\"1069185336913170503\",\"username\":\"Mivator - Private (Testing)\",\"bot\":true,\"system\":false,\"flags\":0,\"globalName\":null,\"discriminator\":\"6286\",\"avatar\":\"23f8f7b506aec78c52cc0cc44678f6a7\",\"avatarDecoration\":null,\"verified\":true,\"mfaEnabled\":true,\"shards\":\"auto\"}}],\"tracks\":[{\"encoded\":\"QAAB1QMAFExvY2tlZCBvdXQgb2YgSGVhdmVuAApCcnVubyBNYXJzAAAAAAADkAYAFjN3M3k4S1BUZk5lT0tQaXFVVGFrQmgAAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL3RyYWNrLzN3M3k4S1BUZk5lT0tQaXFVVGFrQmgBAEBodHRwczovL2kuc2Nkbi5jby9pbWFnZS9hYjY3NjE2ZDAwMDBiMjczOTI2ZjQzZTdjY2U1NzFlNjI3MjBmZDQ2AQAMVVNBVDIxMjAzMjg3AAdzcG90aWZ5AQASVW5vcnRob2RveCBKdWtlYm94AQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzU4dWZwUXNKMURTNWtxNGhoelFEaUkBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvNWEwMzE4ZTZjNDM5NjQ3ODZkMjJiOTQzMWFmMzU0OTBlOTZjZmYzZD9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"3w3y8KPTfNeOKPiqUTakBh\",\"title\":\"Locked out of Heaven\",\"author\":\"Bruno Mars\",\"duration\":233478,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273926f43e7cce571e62720fd46\",\"uri\":\"https://open.spotify.com/track/3w3y8KPTfNeOKPiqUTakBh\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21203287\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/3w3y8KPTfNeOKPiqUTakBh\",\"albumUrl\":\"https://open.spotify.com/album/58ufpQsJ1DS5kq4hhzQDiI\",\"albumName\":\"Unorthodox Jukebox\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/5a0318e6c43964786d22b9431af35490e96cff3d?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAByQMACFRyZWFzdXJlAApCcnVubyBNYXJzAAAAAAACuYAAFjU1aDd2SmNoaWJMZFVreGRsWDNmSzcAAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL3RyYWNrLzU1aDd2SmNoaWJMZFVreGRsWDNmSzcBAEBodHRwczovL2kuc2Nkbi5jby9pbWFnZS9hYjY3NjE2ZDAwMDBiMjczOTI2ZjQzZTdjY2U1NzFlNjI3MjBmZDQ2AQAMVVNBVDIxMjA2OTA5AAdzcG90aWZ5AQASVW5vcnRob2RveCBKdWtlYm94AQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzU4dWZwUXNKMURTNWtxNGhoelFEaUkBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvMjI2NWM1YjE2YjJlMTlmNjVkYTA0NWRmNDFjZjJiNGI4ZmQ2NmVhMz9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"55h7vJchibLdUkxdlX3fK7\",\"title\":\"Treasure\",\"author\":\"Bruno Mars\",\"duration\":178560,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273926f43e7cce571e62720fd46\",\"uri\":\"https://open.spotify.com/track/55h7vJchibLdUkxdlX3fK7\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21206909\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/55h7vJchibLdUkxdlX3fK7\",\"albumUrl\":\"https://open.spotify.com/album/58ufpQsJ1DS5kq4hhzQDiI\",\"albumName\":\"Unorthodox Jukebox\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/2265c5b16b2e19f65da045df41cf2b4b8fd66ea3?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB1AMAE1doZW4gSSBXYXMgWW91ciBNYW4ACkJydW5vIE1hcnMAAAAAAANDQgAWMG5KVzAxVDdYdHZJTHhRZ0M1SjdXaAABADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vdHJhY2svMG5KVzAxVDdYdHZJTHhRZ0M1SjdXaAEAQGh0dHBzOi8vaS5zY2RuLmNvL2ltYWdlL2FiNjc2MTZkMDAwMGIyNzM5MjZmNDNlN2NjZTU3MWU2MjcyMGZkNDYBAAxVU0FUMjEyMDY3MDEAB3Nwb3RpZnkBABJVbm9ydGhvZG94IEp1a2Vib3gBADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vYWxidW0vNTh1ZnBRc0oxRFM1a3E0aGh6UURpSQEANmh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hcnRpc3QvMGR1NWNFVmg1eVRLOVFKemU4ekEwQwABAGtodHRwczovL3Auc2Nkbi5jby9tcDMtcHJldmlldy8xNTlmYzA1NTg0MjE3YmFhOTk1ODFjNDgyMWY1MmQwNDY3MGRiNmIyP2NpZD1kY2ViYjlmOTg5ZmI0ODlhODlmYmMzMmU0NDM3YTgxMgAAAAAAAAAAAA==\",\"info\":{\"identifier\":\"0nJW01T7XtvILxQgC5J7Wh\",\"title\":\"When I Was Your Man\",\"author\":\"Bruno Mars\",\"duration\":213826,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273926f43e7cce571e62720fd46\",\"uri\":\"https://open.spotify.com/track/0nJW01T7XtvILxQgC5J7Wh\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21206701\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/0nJW01T7XtvILxQgC5J7Wh\",\"albumUrl\":\"https://open.spotify.com/album/58ufpQsJ1DS5kq4hhzQDiI\",\"albumName\":\"Unorthodox Jukebox\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/159fc05584217baa99581c4821f52d04670db6b2?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB7QMAHkJpbGxpb25haXJlIChmZWF0LiBCcnVubyBNYXJzKQAMVHJhdmllIE1jQ295AAAAAAADONgAFjJNOVVMbVF3VGFUR21BZFhhWHBmejUAAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL3RyYWNrLzJNOVVMbVF3VGFUR21BZFhhWHBmejUBAEBodHRwczovL2kuc2Nkbi5jby9pbWFnZS9hYjY3NjE2ZDAwMDBiMjczMzdjZTNkZDIwYzIzMThlMTNjNjYwOGVkAQAMVVNBVDIxMDAwMjU3AAdzcG90aWZ5AQAeQmlsbGlvbmFpcmUgKGZlYXQuIEJydW5vIE1hcnMpAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzFQcnV3R3ZRRGZnaDZDVFNGV1BOdG4BADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzdvOU5sN0sxQWw2Tk5BSFg2am42aUcAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvMDJmNDE4NDMzMDhlNzU1MDMxNjFjZmNlMjgxMTQ5MDJiOWUwNzJmYT9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"2M9ULmQwTaTGmAdXaXpfz5\",\"title\":\"Billionaire (feat. Bruno Mars)\",\"author\":\"Travie McCoy\",\"duration\":211160,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b27337ce3dd20c2318e13c6608ed\",\"uri\":\"https://open.spotify.com/track/2M9ULmQwTaTGmAdXaXpfz5\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21000257\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/2M9ULmQwTaTGmAdXaXpfz5\",\"albumUrl\":\"https://open.spotify.com/album/1PruwGvQDfgh6CTSFWPNtn\",\"albumName\":\"Billionaire (feat. Bruno Mars)\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/02f41843308e75503161cfce28114902b9e072fa?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/7o9Nl7K1Al6NNAHX6jn6iG\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAABygMAElRoYXQncyBXaGF0IEkgTGlrZQAKQnJ1bm8gTWFycwAAAAAAAydlABYwS0trSk5mR3loa1E1YUZvZ3hRQVBVAAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay8wS0trSk5mR3loa1E1YUZvZ3hRQVBVAQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3MzIzMjcxMWY3ZDY2YTFlMTllODllMjhjNQEADFVTQVQyMTYwMjk0OAAHc3BvdGlmeQEACTI0SyBNYWdpYwEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hbGJ1bS80UGdsZVIwOUpWbm0zelkxZlczWEJBAQA2aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FydGlzdC8wZHU1Y0VWaDV5VEs5UUp6ZTh6QTBDAAEAa2h0dHBzOi8vcC5zY2RuLmNvL21wMy1wcmV2aWV3LzkzMDQ2ZTk4N2Q4YzViZmRiZWVhMjc2OGFjMWE4ZWNlYTE3YmQ3ZTA/Y2lkPWRjZWJiOWY5ODlmYjQ4OWE4OWZiYzMyZTQ0MzdhODEyAAAAAAAAAAAA\",\"info\":{\"identifier\":\"0KKkJNfGyhkQ5aFogxQAPU\",\"title\":\"That's What I Like\",\"author\":\"Bruno Mars\",\"duration\":206693,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273232711f7d66a1e19e89e28c5\",\"uri\":\"https://open.spotify.com/track/0KKkJNfGyhkQ5aFogxQAPU\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21602948\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/0KKkJNfGyhkQ5aFogxQAPU\",\"albumUrl\":\"https://open.spotify.com/album/4PgleR09JVnm3zY1fW3XBA\",\"albumName\":\"24K Magic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/93046e987d8c5bfdbeea2768ac1a8ecea17bd7e0?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB9gMAIU5vdGhpbicgb24gWW91IChmZWF0LiBCcnVubyBNYXJzKQAFQi5vLkIAAAAAAAQYIAAWNTlkTHRHQlMyNng3a2MwckhiYVBycQABADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vdHJhY2svNTlkTHRHQlMyNng3a2MwckhiYVBycQEAQGh0dHBzOi8vaS5zY2RuLmNvL2ltYWdlL2FiNjc2MTZkMDAwMGIyNzM0ODRkMTIxZjBlMmQyY2FmODdkNWQxMGIBAAxVU0FUMjA5MDQwMzMAB3Nwb3RpZnkBACtCLm8uQiBQcmVzZW50czogVGhlIEFkdmVudHVyZXMgb2YgQm9iYnkgUmF5AQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzdhcExQWVQ4c3pWMUlxVHh5VlN5NVABADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzVuZGtLM2RwWkxLdEJrbEtqeE5Rd1QAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvMmJhOGExNGIzMTFjMWY0YWQ0NDZiOTRiNzFkYTNmNTA3ZDU1NTE5Mz9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"59dLtGBS26x7kc0rHbaPrq\",\"title\":\"Nothin' on You (feat. Bruno Mars)\",\"author\":\"B.o.B\",\"duration\":268320,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273484d121f0e2d2caf87d5d10b\",\"uri\":\"https://open.spotify.com/track/59dLtGBS26x7kc0rHbaPrq\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT20904033\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/59dLtGBS26x7kc0rHbaPrq\",\"albumUrl\":\"https://open.spotify.com/album/7apLPYT8szV1IqTxyVSy5P\",\"albumName\":\"B.o.B Presents: The Adventures of Bobby Ray\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/2ba8a14b311c1f4ad446b94b71da3f507d555193?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/5ndkK3dpZLKtBklKjxNQwT\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB1QMAE0xlYXZlIFRoZSBEb29yIE9wZW4ACkJydW5vIE1hcnMAAAAAAAOxsAAWN01BaWJjVGxpNElpc0N0YkhLckdNaAABADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vdHJhY2svN01BaWJjVGxpNElpc0N0YkhLckdNaAEAQGh0dHBzOi8vaS5zY2RuLmNvL2ltYWdlL2FiNjc2MTZkMDAwMGIyNzM2ZjllNmFiYmQ2ZmE0M2FjM2NkYmVlZTABAAxVU0FUMjIxMDA5MDYAB3Nwb3RpZnkBABNMZWF2ZSBUaGUgRG9vciBPcGVuAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzdkZlBxWGNrNkJCOXdwVGhyVllCc3MBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvMmYwNjM4NDEwMWFkMWE1YWE2YjAyZjZmYzI0YjU5Nzg5YzJhYjU0ZD9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"7MAibcTli4IisCtbHKrGMh\",\"title\":\"Leave The Door Open\",\"author\":\"Bruno Mars\",\"duration\":242096,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b2736f9e6abbd6fa43ac3cdbeee0\",\"uri\":\"https://open.spotify.com/track/7MAibcTli4IisCtbHKrGMh\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22100906\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/7MAibcTli4IisCtbHKrGMh\",\"albumUrl\":\"https://open.spotify.com/album/7dfPqXck6BB9wpThrVYBss\",\"albumName\":\"Leave The Door Open\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/2f06384101ad1a5aa6b02f6fc24b59789c2ab54d?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB/AMAM0FmdGVyIExhc3QgTmlnaHQgKHdpdGggVGh1bmRlcmNhdCAmIEJvb3RzeSBDb2xsaW5zKQAKQnJ1bm8gTWFycwAAAAAAA85kABYzamlLVU1YcXdFb2RCN2dWdjFSTVpVAAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay8zamlLVU1YcXdFb2RCN2dWdjFSTVpVAQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3M2ZjZjc1ZWFkOGEzMmFjMDAyMGQyY2U4NgEADFVTQVQyMjEwMzEwMwAHc3BvdGlmeQEAGkFuIEV2ZW5pbmcgV2l0aCBTaWxrIFNvbmljAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzFZZ2VrSkpURXVlV0RhTXI3QllxUGsBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvM2U4NWNlYzJjNTlkZTQ2Njg5YTdjYTA4MzkzNDJkOTdkM2FlZjAwOD9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"3jiKUMXqwEodB7gVv1RMZU\",\"title\":\"After Last Night (with Thundercat & Bootsy Collins)\",\"author\":\"Bruno Mars\",\"duration\":249444,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/3jiKUMXqwEodB7gVv1RMZU\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22103103\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/3jiKUMXqwEodB7gVv1RMZU\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/3e85cec2c59de46689a7ca0839342d97d3aef008?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB3gMAFVNtb2tpbiBPdXQgVGhlIFdpbmRvdwAKQnJ1bm8gTWFycwAAAAAAAwNCABYzeFZaWWtjdVdhbEd1ZGVLbDg2MXdiAAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay8zeFZaWWtjdVdhbEd1ZGVLbDg2MXdiAQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3M2ZjZjc1ZWFkOGEzMmFjMDAyMGQyY2U4NgEADFVTQVQyMjEwNTk1MgAHc3BvdGlmeQEAGkFuIEV2ZW5pbmcgV2l0aCBTaWxrIFNvbmljAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzFZZ2VrSkpURXVlV0RhTXI3QllxUGsBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvMDM5ODVlYTBmNWI1MzY2MGMzNTI3NzM4NzViYTUxNTk1MzNmZTY5Mj9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"3xVZYkcuWalGudeKl861wb\",\"title\":\"Smokin Out The Window\",\"author\":\"Bruno Mars\",\"duration\":197442,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/3xVZYkcuWalGudeKl861wb\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22105952\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/3xVZYkcuWalGudeKl861wb\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/03985ea0f5b53660c352773875ba5159533fe692?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB1wMADlB1dCBPbiBBIFNtaWxlAApCcnVubyBNYXJzAAAAAAAD5d8AFjVmN1VKQ01yQTFWUkx2YlBycTFoMEcAAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL3RyYWNrLzVmN1VKQ01yQTFWUkx2YlBycTFoMEcBAEBodHRwczovL2kuc2Nkbi5jby9pbWFnZS9hYjY3NjE2ZDAwMDBiMjczZmNmNzVlYWQ4YTMyYWMwMDIwZDJjZTg2AQAMVVNBVDIyMTA2MTkzAAdzcG90aWZ5AQAaQW4gRXZlbmluZyBXaXRoIFNpbGsgU29uaWMBADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vYWxidW0vMVlnZWtKSlRFdWVXRGFNcjdCWXFQawEANmh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hcnRpc3QvMGR1NWNFVmg1eVRLOVFKemU4ekEwQwABAGtodHRwczovL3Auc2Nkbi5jby9tcDMtcHJldmlldy9jNWY0YzUxYmFmOWVhNjM3YmI1ODllNmU4NDdlNGEzOGE3MjczMjFiP2NpZD1kY2ViYjlmOTg5ZmI0ODlhODlmYmMzMmU0NDM3YTgxMgAAAAAAAAAAAA==\",\"info\":{\"identifier\":\"5f7UJCMrA1VRLvbPrq1h0G\",\"title\":\"Put On A Smile\",\"author\":\"Bruno Mars\",\"duration\":255455,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/5f7UJCMrA1VRLvbPrq1h0G\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22106193\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/5f7UJCMrA1VRLvbPrq1h0G\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/c5f4c51baf9ea637bb589e6e847e4a38a727321b?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAABzAMAAzc3NwAKQnJ1bm8gTWFycwAAAAAAAoSIABY2N0JPak84QkVTWFlOVTVFNnFEY1V2AAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay82N0JPak84QkVTWFlOVTVFNnFEY1V2AQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3M2ZjZjc1ZWFkOGEzMmFjMDAyMGQyY2U4NgEADFVTQVQyMjEwNjU5MAAHc3BvdGlmeQEAGkFuIEV2ZW5pbmcgV2l0aCBTaWxrIFNvbmljAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzFZZ2VrSkpURXVlV0RhTXI3QllxUGsBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvZTk5NDM1NzcyYmRiY2ViNDU0NDc5ZDhjYWIwMDNiZTQyYWE5Y2FmMz9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"67BOjO8BESXYNU5E6qDcUv\",\"title\":\"777\",\"author\":\"Bruno Mars\",\"duration\":165000,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/67BOjO8BESXYNU5E6qDcUv\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22106590\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/67BOjO8BESXYNU5E6qDcUv\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/e99435772bdbceb454479d8cab003be42aa9caf3?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAABzgMABVNrYXRlAApCcnVubyBNYXJzAAAAAAADGXIAFjdqdkNlV09TbkpzMk4zc3Bxb2JXbk8AAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL3RyYWNrLzdqdkNlV09TbkpzMk4zc3Bxb2JXbk8BAEBodHRwczovL2kuc2Nkbi5jby9pbWFnZS9hYjY3NjE2ZDAwMDBiMjczZmNmNzVlYWQ4YTMyYWMwMDIwZDJjZTg2AQAMVVNBVDIyMTA0MjIyAAdzcG90aWZ5AQAaQW4gRXZlbmluZyBXaXRoIFNpbGsgU29uaWMBADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vYWxidW0vMVlnZWtKSlRFdWVXRGFNcjdCWXFQawEANmh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hcnRpc3QvMGR1NWNFVmg1eVRLOVFKemU4ekEwQwABAGtodHRwczovL3Auc2Nkbi5jby9tcDMtcHJldmlldy8zZTkzY2JlYzZlYjY4NDcxYjFjMDI3YmQwNTcxNzVjZGI3NTkwZGZjP2NpZD1kY2ViYjlmOTg5ZmI0ODlhODlmYmMzMmU0NDM3YTgxMgAAAAAAAAAAAA==\",\"info\":{\"identifier\":\"7jvCeWOSnJs2N3spqobWnO\",\"title\":\"Skate\",\"author\":\"Bruno Mars\",\"duration\":203122,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/7jvCeWOSnJs2N3spqobWnO\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22104222\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/7jvCeWOSnJs2N3spqobWnO\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/3e93cbec6eb68471b1c027bd057175cdb7590dfc?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB1QMADExvdmUncyBUcmFpbgAKQnJ1bm8gTWFycwAAAAAABK9GABYySlVRN21WMUFIazJvd1hMeWRtTjRaAAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay8ySlVRN21WMUFIazJvd1hMeWRtTjRaAQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3M2ZjZjc1ZWFkOGEzMmFjMDAyMGQyY2U4NgEADFVTQVQyMjIwMDk2NgAHc3BvdGlmeQEAGkFuIEV2ZW5pbmcgV2l0aCBTaWxrIFNvbmljAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzFZZ2VrSkpURXVlV0RhTXI3QllxUGsBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvOTA3ODMyNWEwNWMwZmU2YmI5ZTcyMDg5ODQ0MjczYTdmMzc2ZjMzMD9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"2JUQ7mV1AHk2owXLydmN4Z\",\"title\":\"Love's Train\",\"author\":\"Bruno Mars\",\"duration\":307014,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/2JUQ7mV1AHk2owXLydmN4Z\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22200966\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/2JUQ7mV1AHk2owXLydmN4Z\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/9078325a05c0fe6bb9e72089844273a7f376f330?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB0gMACUJsYXN0IE9mZgAKQnJ1bm8gTWFycwAAAAAABFjGABYya3BvUmVOM01ZN0kwdFNGOTAybjB6AAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay8ya3BvUmVOM01ZN0kwdFNGOTAybjB6AQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3M2ZjZjc1ZWFkOGEzMmFjMDAyMGQyY2U4NgEADFVTQVQyMjEwNjE5NQAHc3BvdGlmeQEAGkFuIEV2ZW5pbmcgV2l0aCBTaWxrIFNvbmljAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzFZZ2VrSkpURXVlV0RhTXI3QllxUGsBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvOTBlN2EwMzU5ZGRlYzAyZTI3NmExZDdiYTVlNDE0NTdlYjdlYjZjZT9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"2kpoReN3MY7I0tSF902n0z\",\"title\":\"Blast Off\",\"author\":\"Bruno Mars\",\"duration\":284870,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/2kpoReN3MY7I0tSF902n0z\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22106195\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/2kpoReN3MY7I0tSF902n0z\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/90e7a0359ddec02e276a1d7ba5e41457eb7eb6ce?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}}]}}"} \ No newline at end of file diff --git a/testBot/queueData.json b/testBot/queueData.json deleted file mode 100644 index e84bb0a..0000000 --- a/testBot/queueData.json +++ /dev/null @@ -1 +0,0 @@ -{"lavalinkqueue_1180208273958375524":"{\"current\":{\"encoded\":\"QAABzgMAC0NvdW50IG9uIE1lAApCcnVubyBNYXJzAAAAAAADA10AFjdsMXF2eFdqeGNLcEI5UEN0QnVUYlUAAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL3RyYWNrLzdsMXF2eFdqeGNLcEI5UEN0QnVUYlUBAEBodHRwczovL2kuc2Nkbi5jby9pbWFnZS9hYjY3NjE2ZDAwMDBiMjczZjZiNTVjYTkzYmQzMzIxMTIyN2I1MDJiAQAMVVNFRTExMDAwMTY4AAdzcG90aWZ5AQAURG9vLVdvcHMgJiBIb29saWdhbnMBADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vYWxidW0vMXV5ZjNsMmQ0WFl3aUVxQWI3dDdmWAEANmh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hcnRpc3QvMGR1NWNFVmg1eVRLOVFKemU4ekEwQwABAGtodHRwczovL3Auc2Nkbi5jby9tcDMtcHJldmlldy81MjVjM2M3N2E4YTM3OWM5YjY4NTllY2EzYjNlYzU0YmVhMzBlZjViP2NpZD1kY2ViYjlmOTg5ZmI0ODlhODlmYmMzMmU0NDM3YTgxMgAAAAAAAAAAAA==\",\"info\":{\"identifier\":\"7l1qvxWjxcKpB9PCtBuTbU\",\"title\":\"Count on Me\",\"author\":\"Bruno Mars\",\"duration\":197469,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273f6b55ca93bd33211227b502b\",\"uri\":\"https://open.spotify.com/track/7l1qvxWjxcKpB9PCtBuTbU\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USEE11000168\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/7l1qvxWjxcKpB9PCtBuTbU\",\"albumUrl\":\"https://open.spotify.com/album/1uyf3l2d4XYwiEqAb7t7fX\",\"albumName\":\"Doo-Wops & Hooligans\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/525c3c77a8a379c9b6859eca3b3ec54bea30ef5b?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"previous\":[{\"encoded\":\"QAAB1gMAE1RhbGtpbmcgdG8gdGhlIE1vb24ACkJydW5vIE1hcnMAAAAAAANTCgAWMTYxRG5MV3N4MWkzdTFKVDA1bHpxVQABADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vdHJhY2svMTYxRG5MV3N4MWkzdTFKVDA1bHpxVQEAQGh0dHBzOi8vaS5zY2RuLmNvL2ltYWdlL2FiNjc2MTZkMDAwMGIyNzNmNmI1NWNhOTNiZDMzMjExMjI3YjUwMmIBAAxVU0FUMjEwMDE5ODUAB3Nwb3RpZnkBABREb28tV29wcyAmIEhvb2xpZ2FucwEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hbGJ1bS8xdXlmM2wyZDRYWXdpRXFBYjd0N2ZYAQA2aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FydGlzdC8wZHU1Y0VWaDV5VEs5UUp6ZTh6QTBDAAEAa2h0dHBzOi8vcC5zY2RuLmNvL21wMy1wcmV2aWV3LzZmZWJhMWI0MTI1MzBhYjBkOWRkMWY4NDkxODBmMDM5ODMxYWNjNDI/Y2lkPWRjZWJiOWY5ODlmYjQ4OWE4OWZiYzMyZTQ0MzdhODEyAAAAAAAAAzFE\",\"info\":{\"identifier\":\"161DnLWsx1i3u1JT05lzqU\",\"title\":\"Talking to the Moon\",\"author\":\"Bruno Mars\",\"duration\":217881,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273f6b55ca93bd33211227b502b\",\"uri\":\"https://open.spotify.com/track/161DnLWsx1i3u1JT05lzqU\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21001985\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/161DnLWsx1i3u1JT05lzqU\",\"albumUrl\":\"https://open.spotify.com/album/1uyf3l2d4XYwiEqAb7t7fX\",\"albumName\":\"Doo-Wops & Hooligans\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/6feba1b412530ab0d9dd1f849180f039831acc42?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAABzAMACU1hcnJ5IFlvdQAKQnJ1bm8gTWFycwAAAAAAA4MwABYyMlBNZnZkejM1ZkZLWW5KeU1uMDc3AAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay8yMlBNZnZkejM1ZkZLWW5KeU1uMDc3AQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3M2Y2YjU1Y2E5M2JkMzMyMTEyMjdiNTAyYgEADFVTQVQyMTAwMTg4NwAHc3BvdGlmeQEAFERvby1Xb3BzICYgSG9vbGlnYW5zAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzF1eWYzbDJkNFhZd2lFcUFiN3Q3ZlgBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvNjc0N2EzNjc0ZWMwYjI0YWI5MDY3OTcyYmIxOTI5MWMzMDQ4YThkMj9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"22PMfvdz35fFKYnJyMn077\",\"title\":\"Marry You\",\"author\":\"Bruno Mars\",\"duration\":230192,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273f6b55ca93bd33211227b502b\",\"uri\":\"https://open.spotify.com/track/22PMfvdz35fFKYnJyMn077\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21001887\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/22PMfvdz35fFKYnJyMn077\",\"albumUrl\":\"https://open.spotify.com/album/1uyf3l2d4XYwiEqAb7t7fX\",\"albumName\":\"Doo-Wops & Hooligans\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/6747a3674ec0b24ab9067972bb19291c3048a8d2?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB0AMADVRoZSBMYXp5IFNvbmcACkJydW5vIE1hcnMAAAAAAALitQAWMUV4ZlBaRWlhaHFoTHlhamh5YkZlUwABADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vdHJhY2svMUV4ZlBaRWlhaHFoTHlhamh5YkZlUwEAQGh0dHBzOi8vaS5zY2RuLmNvL2ltYWdlL2FiNjc2MTZkMDAwMGIyNzNmNmI1NWNhOTNiZDMzMjExMjI3YjUwMmIBAAxVU0FUMjEwMDE4ODYAB3Nwb3RpZnkBABREb28tV29wcyAmIEhvb2xpZ2FucwEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hbGJ1bS8xdXlmM2wyZDRYWXdpRXFBYjd0N2ZYAQA2aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FydGlzdC8wZHU1Y0VWaDV5VEs5UUp6ZTh6QTBDAAEAa2h0dHBzOi8vcC5zY2RuLmNvL21wMy1wcmV2aWV3LzhhNmNkNjY3OWZjMmEzODhiOTg5YTA5YjU3MTE5NDcyM2Q0NWNiNzE/Y2lkPWRjZWJiOWY5ODlmYjQ4OWE4OWZiYzMyZTQ0MzdhODEyAAAAAAAAAAAA\",\"info\":{\"identifier\":\"1ExfPZEiahqhLyajhybFeS\",\"title\":\"The Lazy Song\",\"author\":\"Bruno Mars\",\"duration\":189109,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273f6b55ca93bd33211227b502b\",\"uri\":\"https://open.spotify.com/track/1ExfPZEiahqhLyajhybFeS\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21001886\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/1ExfPZEiahqhLyajhybFeS\",\"albumUrl\":\"https://open.spotify.com/album/1uyf3l2d4XYwiEqAb7t7fX\",\"albumName\":\"Doo-Wops & Hooligans\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/8a6cd6679fc2a388b989a09b571194723d45cb71?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAABygMAB0dyZW5hZGUACkJydW5vIE1hcnMAAAAAAANjiwAWMnRKdWxVWUxES09nOVhydFZrTWdjSgABADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vdHJhY2svMnRKdWxVWUxES09nOVhydFZrTWdjSgEAQGh0dHBzOi8vaS5zY2RuLmNvL2ltYWdlL2FiNjc2MTZkMDAwMGIyNzNmNmI1NWNhOTNiZDMzMjExMjI3YjUwMmIBAAxVU0FUMjEwMDE4ODMAB3Nwb3RpZnkBABREb28tV29wcyAmIEhvb2xpZ2FucwEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hbGJ1bS8xdXlmM2wyZDRYWXdpRXFBYjd0N2ZYAQA2aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FydGlzdC8wZHU1Y0VWaDV5VEs5UUp6ZTh6QTBDAAEAa2h0dHBzOi8vcC5zY2RuLmNvL21wMy1wcmV2aWV3LzUyMjFiZTU5MmM4MzJlMTQ1MDZmNjMwNGZmMWRlYjZjNTJhZTNmZWU/Y2lkPWRjZWJiOWY5ODlmYjQ4OWE4OWZiYzMyZTQ0MzdhODEyAAAAAAAAAAAA\",\"info\":{\"identifier\":\"2tJulUYLDKOg9XrtVkMgcJ\",\"title\":\"Grenade\",\"author\":\"Bruno Mars\",\"duration\":222091,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273f6b55ca93bd33211227b502b\",\"uri\":\"https://open.spotify.com/track/2tJulUYLDKOg9XrtVkMgcJ\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21001883\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/2tJulUYLDKOg9XrtVkMgcJ\",\"albumUrl\":\"https://open.spotify.com/album/1uyf3l2d4XYwiEqAb7t7fX\",\"albumName\":\"Doo-Wops & Hooligans\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/5221be592c832e14506f6304ff1deb6c52ae3fee?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB/AMACVRoZSBTcGFyawAKS2FiaW4gQ3JldwAAAAAAAjpQAAoyODM1NDIxODgyAAEAI2h0dHBzOi8vZGVlemVyLmNvbS90cmFjay8yODM1NDIxODgyAQBpaHR0cHM6Ly9lLWNkbnMtaW1hZ2VzLmR6Y2RuLm5ldC9pbWFnZXMvY292ZXIvNTMxY2UxNTU5MWZlMWNjYmZhMzMxYjdhOTY1NDk1ZWQvMTAwMHgxMDAwLTAwMDAwMC04MC0wLTAuanBnAQAMSUVBQ0oyNDAwMDY4AAZkZWV6ZXIBAAlUaGUgU3BhcmsBACZodHRwczovL3d3dy5kZWV6ZXIuY29tL2FsYnVtLzU5Nzc2NzA1MgEAJmh0dHBzOi8vd3d3LmRlZXplci5jb20vYXJ0aXN0Lzg3MjI1NjkyAQBqaHR0cHM6Ly9lLWNkbnMtaW1hZ2VzLmR6Y2RuLm5ldC9pbWFnZXMvYXJ0aXN0LzljODRjYjNjODk1YjBmMDdjNTRlYWYyYzI2MTU3NjIxLzEwMDB4MTAwMC0wMDAwMDAtODAtMC0wLmpwZwEAT2h0dHBzOi8vY2RuLXByZXZpZXctYi5kemNkbi5uZXQvc3RyZWFtL2MtYmEwNTA1ZWY0ZjE0MjI5NTUwYzQ0YzUyODcyYjQ2YTYtMS5tcDMAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"2835421882\",\"title\":\"The Spark\",\"author\":\"Kabin Crew\",\"duration\":146000,\"artworkUrl\":\"https://e-cdns-images.dzcdn.net/images/cover/531ce15591fe1ccbfa331b7a965495ed/1000x1000-000000-80-0-0.jpg\",\"uri\":\"https://deezer.com/track/2835421882\",\"sourceName\":\"deezer\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"IEACJ2400068\"},\"userData\":{},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://deezer.com/track/2835421882\",\"albumUrl\":\"https://www.deezer.com/album/597767052\",\"albumName\":\"The Spark\",\"previewUrl\":\"https://cdn-preview-b.dzcdn.net/stream/c-ba0505ef4f14229550c44c52872b46a6-1.mp3\",\"isPreview\":false,\"artistUrl\":\"https://www.deezer.com/artist/87225692\",\"artistArtworkUrl\":\"https://e-cdns-images.dzcdn.net/images/artist/9c84cb3c895b0f07c54eaf2c26157621/1000x1000-000000-80-0-0.jpg\"},\"requester\":{\"id\":\"1069185336913170503\",\"username\":\"Mivator - Private (Testing)\",\"bot\":true,\"system\":false,\"flags\":0,\"globalName\":null,\"discriminator\":\"6286\",\"avatar\":\"23f8f7b506aec78c52cc0cc44678f6a7\",\"avatarDecoration\":null,\"verified\":true,\"mfaEnabled\":true,\"shards\":\"auto\"}}],\"tracks\":[{\"encoded\":\"QAAB1QMAFExvY2tlZCBvdXQgb2YgSGVhdmVuAApCcnVubyBNYXJzAAAAAAADkAYAFjN3M3k4S1BUZk5lT0tQaXFVVGFrQmgAAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL3RyYWNrLzN3M3k4S1BUZk5lT0tQaXFVVGFrQmgBAEBodHRwczovL2kuc2Nkbi5jby9pbWFnZS9hYjY3NjE2ZDAwMDBiMjczOTI2ZjQzZTdjY2U1NzFlNjI3MjBmZDQ2AQAMVVNBVDIxMjAzMjg3AAdzcG90aWZ5AQASVW5vcnRob2RveCBKdWtlYm94AQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzU4dWZwUXNKMURTNWtxNGhoelFEaUkBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvNWEwMzE4ZTZjNDM5NjQ3ODZkMjJiOTQzMWFmMzU0OTBlOTZjZmYzZD9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"3w3y8KPTfNeOKPiqUTakBh\",\"title\":\"Locked out of Heaven\",\"author\":\"Bruno Mars\",\"duration\":233478,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273926f43e7cce571e62720fd46\",\"uri\":\"https://open.spotify.com/track/3w3y8KPTfNeOKPiqUTakBh\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21203287\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/3w3y8KPTfNeOKPiqUTakBh\",\"albumUrl\":\"https://open.spotify.com/album/58ufpQsJ1DS5kq4hhzQDiI\",\"albumName\":\"Unorthodox Jukebox\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/5a0318e6c43964786d22b9431af35490e96cff3d?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAByQMACFRyZWFzdXJlAApCcnVubyBNYXJzAAAAAAACuYAAFjU1aDd2SmNoaWJMZFVreGRsWDNmSzcAAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL3RyYWNrLzU1aDd2SmNoaWJMZFVreGRsWDNmSzcBAEBodHRwczovL2kuc2Nkbi5jby9pbWFnZS9hYjY3NjE2ZDAwMDBiMjczOTI2ZjQzZTdjY2U1NzFlNjI3MjBmZDQ2AQAMVVNBVDIxMjA2OTA5AAdzcG90aWZ5AQASVW5vcnRob2RveCBKdWtlYm94AQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzU4dWZwUXNKMURTNWtxNGhoelFEaUkBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvMjI2NWM1YjE2YjJlMTlmNjVkYTA0NWRmNDFjZjJiNGI4ZmQ2NmVhMz9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"55h7vJchibLdUkxdlX3fK7\",\"title\":\"Treasure\",\"author\":\"Bruno Mars\",\"duration\":178560,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273926f43e7cce571e62720fd46\",\"uri\":\"https://open.spotify.com/track/55h7vJchibLdUkxdlX3fK7\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21206909\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/55h7vJchibLdUkxdlX3fK7\",\"albumUrl\":\"https://open.spotify.com/album/58ufpQsJ1DS5kq4hhzQDiI\",\"albumName\":\"Unorthodox Jukebox\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/2265c5b16b2e19f65da045df41cf2b4b8fd66ea3?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB1AMAE1doZW4gSSBXYXMgWW91ciBNYW4ACkJydW5vIE1hcnMAAAAAAANDQgAWMG5KVzAxVDdYdHZJTHhRZ0M1SjdXaAABADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vdHJhY2svMG5KVzAxVDdYdHZJTHhRZ0M1SjdXaAEAQGh0dHBzOi8vaS5zY2RuLmNvL2ltYWdlL2FiNjc2MTZkMDAwMGIyNzM5MjZmNDNlN2NjZTU3MWU2MjcyMGZkNDYBAAxVU0FUMjEyMDY3MDEAB3Nwb3RpZnkBABJVbm9ydGhvZG94IEp1a2Vib3gBADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vYWxidW0vNTh1ZnBRc0oxRFM1a3E0aGh6UURpSQEANmh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hcnRpc3QvMGR1NWNFVmg1eVRLOVFKemU4ekEwQwABAGtodHRwczovL3Auc2Nkbi5jby9tcDMtcHJldmlldy8xNTlmYzA1NTg0MjE3YmFhOTk1ODFjNDgyMWY1MmQwNDY3MGRiNmIyP2NpZD1kY2ViYjlmOTg5ZmI0ODlhODlmYmMzMmU0NDM3YTgxMgAAAAAAAAAAAA==\",\"info\":{\"identifier\":\"0nJW01T7XtvILxQgC5J7Wh\",\"title\":\"When I Was Your Man\",\"author\":\"Bruno Mars\",\"duration\":213826,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273926f43e7cce571e62720fd46\",\"uri\":\"https://open.spotify.com/track/0nJW01T7XtvILxQgC5J7Wh\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21206701\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/0nJW01T7XtvILxQgC5J7Wh\",\"albumUrl\":\"https://open.spotify.com/album/58ufpQsJ1DS5kq4hhzQDiI\",\"albumName\":\"Unorthodox Jukebox\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/159fc05584217baa99581c4821f52d04670db6b2?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB7QMAHkJpbGxpb25haXJlIChmZWF0LiBCcnVubyBNYXJzKQAMVHJhdmllIE1jQ295AAAAAAADONgAFjJNOVVMbVF3VGFUR21BZFhhWHBmejUAAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL3RyYWNrLzJNOVVMbVF3VGFUR21BZFhhWHBmejUBAEBodHRwczovL2kuc2Nkbi5jby9pbWFnZS9hYjY3NjE2ZDAwMDBiMjczMzdjZTNkZDIwYzIzMThlMTNjNjYwOGVkAQAMVVNBVDIxMDAwMjU3AAdzcG90aWZ5AQAeQmlsbGlvbmFpcmUgKGZlYXQuIEJydW5vIE1hcnMpAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzFQcnV3R3ZRRGZnaDZDVFNGV1BOdG4BADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzdvOU5sN0sxQWw2Tk5BSFg2am42aUcAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvMDJmNDE4NDMzMDhlNzU1MDMxNjFjZmNlMjgxMTQ5MDJiOWUwNzJmYT9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"2M9ULmQwTaTGmAdXaXpfz5\",\"title\":\"Billionaire (feat. Bruno Mars)\",\"author\":\"Travie McCoy\",\"duration\":211160,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b27337ce3dd20c2318e13c6608ed\",\"uri\":\"https://open.spotify.com/track/2M9ULmQwTaTGmAdXaXpfz5\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21000257\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/2M9ULmQwTaTGmAdXaXpfz5\",\"albumUrl\":\"https://open.spotify.com/album/1PruwGvQDfgh6CTSFWPNtn\",\"albumName\":\"Billionaire (feat. Bruno Mars)\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/02f41843308e75503161cfce28114902b9e072fa?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/7o9Nl7K1Al6NNAHX6jn6iG\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAABygMAElRoYXQncyBXaGF0IEkgTGlrZQAKQnJ1bm8gTWFycwAAAAAAAydlABYwS0trSk5mR3loa1E1YUZvZ3hRQVBVAAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay8wS0trSk5mR3loa1E1YUZvZ3hRQVBVAQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3MzIzMjcxMWY3ZDY2YTFlMTllODllMjhjNQEADFVTQVQyMTYwMjk0OAAHc3BvdGlmeQEACTI0SyBNYWdpYwEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hbGJ1bS80UGdsZVIwOUpWbm0zelkxZlczWEJBAQA2aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FydGlzdC8wZHU1Y0VWaDV5VEs5UUp6ZTh6QTBDAAEAa2h0dHBzOi8vcC5zY2RuLmNvL21wMy1wcmV2aWV3LzkzMDQ2ZTk4N2Q4YzViZmRiZWVhMjc2OGFjMWE4ZWNlYTE3YmQ3ZTA/Y2lkPWRjZWJiOWY5ODlmYjQ4OWE4OWZiYzMyZTQ0MzdhODEyAAAAAAAAAAAA\",\"info\":{\"identifier\":\"0KKkJNfGyhkQ5aFogxQAPU\",\"title\":\"That's What I Like\",\"author\":\"Bruno Mars\",\"duration\":206693,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273232711f7d66a1e19e89e28c5\",\"uri\":\"https://open.spotify.com/track/0KKkJNfGyhkQ5aFogxQAPU\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT21602948\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/0KKkJNfGyhkQ5aFogxQAPU\",\"albumUrl\":\"https://open.spotify.com/album/4PgleR09JVnm3zY1fW3XBA\",\"albumName\":\"24K Magic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/93046e987d8c5bfdbeea2768ac1a8ecea17bd7e0?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB9gMAIU5vdGhpbicgb24gWW91IChmZWF0LiBCcnVubyBNYXJzKQAFQi5vLkIAAAAAAAQYIAAWNTlkTHRHQlMyNng3a2MwckhiYVBycQABADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vdHJhY2svNTlkTHRHQlMyNng3a2MwckhiYVBycQEAQGh0dHBzOi8vaS5zY2RuLmNvL2ltYWdlL2FiNjc2MTZkMDAwMGIyNzM0ODRkMTIxZjBlMmQyY2FmODdkNWQxMGIBAAxVU0FUMjA5MDQwMzMAB3Nwb3RpZnkBACtCLm8uQiBQcmVzZW50czogVGhlIEFkdmVudHVyZXMgb2YgQm9iYnkgUmF5AQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzdhcExQWVQ4c3pWMUlxVHh5VlN5NVABADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzVuZGtLM2RwWkxLdEJrbEtqeE5Rd1QAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvMmJhOGExNGIzMTFjMWY0YWQ0NDZiOTRiNzFkYTNmNTA3ZDU1NTE5Mz9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"59dLtGBS26x7kc0rHbaPrq\",\"title\":\"Nothin' on You (feat. Bruno Mars)\",\"author\":\"B.o.B\",\"duration\":268320,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273484d121f0e2d2caf87d5d10b\",\"uri\":\"https://open.spotify.com/track/59dLtGBS26x7kc0rHbaPrq\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT20904033\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/59dLtGBS26x7kc0rHbaPrq\",\"albumUrl\":\"https://open.spotify.com/album/7apLPYT8szV1IqTxyVSy5P\",\"albumName\":\"B.o.B Presents: The Adventures of Bobby Ray\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/2ba8a14b311c1f4ad446b94b71da3f507d555193?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/5ndkK3dpZLKtBklKjxNQwT\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB1QMAE0xlYXZlIFRoZSBEb29yIE9wZW4ACkJydW5vIE1hcnMAAAAAAAOxsAAWN01BaWJjVGxpNElpc0N0YkhLckdNaAABADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vdHJhY2svN01BaWJjVGxpNElpc0N0YkhLckdNaAEAQGh0dHBzOi8vaS5zY2RuLmNvL2ltYWdlL2FiNjc2MTZkMDAwMGIyNzM2ZjllNmFiYmQ2ZmE0M2FjM2NkYmVlZTABAAxVU0FUMjIxMDA5MDYAB3Nwb3RpZnkBABNMZWF2ZSBUaGUgRG9vciBPcGVuAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzdkZlBxWGNrNkJCOXdwVGhyVllCc3MBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvMmYwNjM4NDEwMWFkMWE1YWE2YjAyZjZmYzI0YjU5Nzg5YzJhYjU0ZD9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"7MAibcTli4IisCtbHKrGMh\",\"title\":\"Leave The Door Open\",\"author\":\"Bruno Mars\",\"duration\":242096,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b2736f9e6abbd6fa43ac3cdbeee0\",\"uri\":\"https://open.spotify.com/track/7MAibcTli4IisCtbHKrGMh\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22100906\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/7MAibcTli4IisCtbHKrGMh\",\"albumUrl\":\"https://open.spotify.com/album/7dfPqXck6BB9wpThrVYBss\",\"albumName\":\"Leave The Door Open\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/2f06384101ad1a5aa6b02f6fc24b59789c2ab54d?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB/AMAM0FmdGVyIExhc3QgTmlnaHQgKHdpdGggVGh1bmRlcmNhdCAmIEJvb3RzeSBDb2xsaW5zKQAKQnJ1bm8gTWFycwAAAAAAA85kABYzamlLVU1YcXdFb2RCN2dWdjFSTVpVAAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay8zamlLVU1YcXdFb2RCN2dWdjFSTVpVAQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3M2ZjZjc1ZWFkOGEzMmFjMDAyMGQyY2U4NgEADFVTQVQyMjEwMzEwMwAHc3BvdGlmeQEAGkFuIEV2ZW5pbmcgV2l0aCBTaWxrIFNvbmljAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzFZZ2VrSkpURXVlV0RhTXI3QllxUGsBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvM2U4NWNlYzJjNTlkZTQ2Njg5YTdjYTA4MzkzNDJkOTdkM2FlZjAwOD9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"3jiKUMXqwEodB7gVv1RMZU\",\"title\":\"After Last Night (with Thundercat & Bootsy Collins)\",\"author\":\"Bruno Mars\",\"duration\":249444,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/3jiKUMXqwEodB7gVv1RMZU\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22103103\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/3jiKUMXqwEodB7gVv1RMZU\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/3e85cec2c59de46689a7ca0839342d97d3aef008?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB3gMAFVNtb2tpbiBPdXQgVGhlIFdpbmRvdwAKQnJ1bm8gTWFycwAAAAAAAwNCABYzeFZaWWtjdVdhbEd1ZGVLbDg2MXdiAAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay8zeFZaWWtjdVdhbEd1ZGVLbDg2MXdiAQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3M2ZjZjc1ZWFkOGEzMmFjMDAyMGQyY2U4NgEADFVTQVQyMjEwNTk1MgAHc3BvdGlmeQEAGkFuIEV2ZW5pbmcgV2l0aCBTaWxrIFNvbmljAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzFZZ2VrSkpURXVlV0RhTXI3QllxUGsBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvMDM5ODVlYTBmNWI1MzY2MGMzNTI3NzM4NzViYTUxNTk1MzNmZTY5Mj9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"3xVZYkcuWalGudeKl861wb\",\"title\":\"Smokin Out The Window\",\"author\":\"Bruno Mars\",\"duration\":197442,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/3xVZYkcuWalGudeKl861wb\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22105952\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/3xVZYkcuWalGudeKl861wb\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/03985ea0f5b53660c352773875ba5159533fe692?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB1wMADlB1dCBPbiBBIFNtaWxlAApCcnVubyBNYXJzAAAAAAAD5d8AFjVmN1VKQ01yQTFWUkx2YlBycTFoMEcAAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL3RyYWNrLzVmN1VKQ01yQTFWUkx2YlBycTFoMEcBAEBodHRwczovL2kuc2Nkbi5jby9pbWFnZS9hYjY3NjE2ZDAwMDBiMjczZmNmNzVlYWQ4YTMyYWMwMDIwZDJjZTg2AQAMVVNBVDIyMTA2MTkzAAdzcG90aWZ5AQAaQW4gRXZlbmluZyBXaXRoIFNpbGsgU29uaWMBADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vYWxidW0vMVlnZWtKSlRFdWVXRGFNcjdCWXFQawEANmh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hcnRpc3QvMGR1NWNFVmg1eVRLOVFKemU4ekEwQwABAGtodHRwczovL3Auc2Nkbi5jby9tcDMtcHJldmlldy9jNWY0YzUxYmFmOWVhNjM3YmI1ODllNmU4NDdlNGEzOGE3MjczMjFiP2NpZD1kY2ViYjlmOTg5ZmI0ODlhODlmYmMzMmU0NDM3YTgxMgAAAAAAAAAAAA==\",\"info\":{\"identifier\":\"5f7UJCMrA1VRLvbPrq1h0G\",\"title\":\"Put On A Smile\",\"author\":\"Bruno Mars\",\"duration\":255455,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/5f7UJCMrA1VRLvbPrq1h0G\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22106193\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/5f7UJCMrA1VRLvbPrq1h0G\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/c5f4c51baf9ea637bb589e6e847e4a38a727321b?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAABzAMAAzc3NwAKQnJ1bm8gTWFycwAAAAAAAoSIABY2N0JPak84QkVTWFlOVTVFNnFEY1V2AAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay82N0JPak84QkVTWFlOVTVFNnFEY1V2AQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3M2ZjZjc1ZWFkOGEzMmFjMDAyMGQyY2U4NgEADFVTQVQyMjEwNjU5MAAHc3BvdGlmeQEAGkFuIEV2ZW5pbmcgV2l0aCBTaWxrIFNvbmljAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzFZZ2VrSkpURXVlV0RhTXI3QllxUGsBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvZTk5NDM1NzcyYmRiY2ViNDU0NDc5ZDhjYWIwMDNiZTQyYWE5Y2FmMz9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"67BOjO8BESXYNU5E6qDcUv\",\"title\":\"777\",\"author\":\"Bruno Mars\",\"duration\":165000,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/67BOjO8BESXYNU5E6qDcUv\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22106590\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/67BOjO8BESXYNU5E6qDcUv\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/e99435772bdbceb454479d8cab003be42aa9caf3?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAABzgMABVNrYXRlAApCcnVubyBNYXJzAAAAAAADGXIAFjdqdkNlV09TbkpzMk4zc3Bxb2JXbk8AAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL3RyYWNrLzdqdkNlV09TbkpzMk4zc3Bxb2JXbk8BAEBodHRwczovL2kuc2Nkbi5jby9pbWFnZS9hYjY3NjE2ZDAwMDBiMjczZmNmNzVlYWQ4YTMyYWMwMDIwZDJjZTg2AQAMVVNBVDIyMTA0MjIyAAdzcG90aWZ5AQAaQW4gRXZlbmluZyBXaXRoIFNpbGsgU29uaWMBADVodHRwczovL29wZW4uc3BvdGlmeS5jb20vYWxidW0vMVlnZWtKSlRFdWVXRGFNcjdCWXFQawEANmh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS9hcnRpc3QvMGR1NWNFVmg1eVRLOVFKemU4ekEwQwABAGtodHRwczovL3Auc2Nkbi5jby9tcDMtcHJldmlldy8zZTkzY2JlYzZlYjY4NDcxYjFjMDI3YmQwNTcxNzVjZGI3NTkwZGZjP2NpZD1kY2ViYjlmOTg5ZmI0ODlhODlmYmMzMmU0NDM3YTgxMgAAAAAAAAAAAA==\",\"info\":{\"identifier\":\"7jvCeWOSnJs2N3spqobWnO\",\"title\":\"Skate\",\"author\":\"Bruno Mars\",\"duration\":203122,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/7jvCeWOSnJs2N3spqobWnO\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22104222\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/7jvCeWOSnJs2N3spqobWnO\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/3e93cbec6eb68471b1c027bd057175cdb7590dfc?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB1QMADExvdmUncyBUcmFpbgAKQnJ1bm8gTWFycwAAAAAABK9GABYySlVRN21WMUFIazJvd1hMeWRtTjRaAAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay8ySlVRN21WMUFIazJvd1hMeWRtTjRaAQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3M2ZjZjc1ZWFkOGEzMmFjMDAyMGQyY2U4NgEADFVTQVQyMjIwMDk2NgAHc3BvdGlmeQEAGkFuIEV2ZW5pbmcgV2l0aCBTaWxrIFNvbmljAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzFZZ2VrSkpURXVlV0RhTXI3QllxUGsBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvOTA3ODMyNWEwNWMwZmU2YmI5ZTcyMDg5ODQ0MjczYTdmMzc2ZjMzMD9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"2JUQ7mV1AHk2owXLydmN4Z\",\"title\":\"Love's Train\",\"author\":\"Bruno Mars\",\"duration\":307014,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/2JUQ7mV1AHk2owXLydmN4Z\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22200966\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/2JUQ7mV1AHk2owXLydmN4Z\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/9078325a05c0fe6bb9e72089844273a7f376f330?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},{\"encoded\":\"QAAB0gMACUJsYXN0IE9mZgAKQnJ1bm8gTWFycwAAAAAABFjGABYya3BvUmVOM01ZN0kwdFNGOTAybjB6AAEANWh0dHBzOi8vb3Blbi5zcG90aWZ5LmNvbS90cmFjay8ya3BvUmVOM01ZN0kwdFNGOTAybjB6AQBAaHR0cHM6Ly9pLnNjZG4uY28vaW1hZ2UvYWI2NzYxNmQwMDAwYjI3M2ZjZjc1ZWFkOGEzMmFjMDAyMGQyY2U4NgEADFVTQVQyMjEwNjE5NQAHc3BvdGlmeQEAGkFuIEV2ZW5pbmcgV2l0aCBTaWxrIFNvbmljAQA1aHR0cHM6Ly9vcGVuLnNwb3RpZnkuY29tL2FsYnVtLzFZZ2VrSkpURXVlV0RhTXI3QllxUGsBADZodHRwczovL29wZW4uc3BvdGlmeS5jb20vYXJ0aXN0LzBkdTVjRVZoNXlUSzlRSnplOHpBMEMAAQBraHR0cHM6Ly9wLnNjZG4uY28vbXAzLXByZXZpZXcvOTBlN2EwMzU5ZGRlYzAyZTI3NmExZDdiYTVlNDE0NTdlYjdlYjZjZT9jaWQ9ZGNlYmI5Zjk4OWZiNDg5YTg5ZmJjMzJlNDQzN2E4MTIAAAAAAAAAAAA=\",\"info\":{\"identifier\":\"2kpoReN3MY7I0tSF902n0z\",\"title\":\"Blast Off\",\"author\":\"Bruno Mars\",\"duration\":284870,\"artworkUrl\":\"https://i.scdn.co/image/ab67616d0000b273fcf75ead8a32ac0020d2ce86\",\"uri\":\"https://open.spotify.com/track/2kpoReN3MY7I0tSF902n0z\",\"sourceName\":\"spotify\",\"isSeekable\":true,\"isStream\":false,\"isrc\":\"USAT22106195\"},\"userData\":{\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}},\"pluginInfo\":{\"clientData\":{},\"save_uri\":\"https://open.spotify.com/track/2kpoReN3MY7I0tSF902n0z\",\"albumUrl\":\"https://open.spotify.com/album/1YgekJJTEueWDaMr7BYqPk\",\"albumName\":\"An Evening With Silk Sonic\",\"previewUrl\":\"https://p.scdn.co/mp3-preview/90e7a0359ddec02e276a1d7ba5e41457eb7eb6ce?cid=dcebb9f989fb489a89fbc32e4437a812\",\"isPreview\":false,\"artistUrl\":\"https://open.spotify.com/artist/0du5cEVh5yTK9QJze8zA0C\",\"artistArtworkUrl\":null,\"isLocal\":false},\"requester\":{\"id\":\"498094279793704991\",\"username\":\"chrissy8283\",\"avatar\":\"https://cdn.discordapp.com/avatars/498094279793704991/bed8376ade07deb31d379358b30097b3.webp\"}}]}"} \ No newline at end of file