//META{"name":"SpotifyControls","authorId":"278543574059057154","invite":"Jx3TjNS","donate":"https://www.paypal.me/MircoWittrien","patreon":"https://www.patreon.com/MircoWittrien","website":"https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/SpotifyControls","source":"https://raw.githubusercontent.com/mwittrien/BetterDiscordAddons/master/Plugins/SpotifyControls/SpotifyControls.plugin.js"}*// var SpotifyControls = (_ => { var controls, lastSong, stopTime, updateInterval; const SpotifyControlsComponent = class SpotifyControls extends BdApi.React.Component { componentDidMount() { controls = this; } request(socket, device, type, song, data) { return new Promise(callback => { BDFDB.LibraryRequires.request({ url: `https://api.spotify.com/v1/me/player/${type}`, method: type == "next" || type == "previous" ? "POST" : "PUT", query: {device_id: device.id}, headers: { authorization: `Bearer ${socket.accessToken}` }, body: JSON.stringify(Object.assign({}, data)) }, (error, response, result) => { if (response.statusCode == 401) { BDFDB.LibraryModules.SpotifyUtils.getAccessToken(socket.accountId).then(promiseResult => { let newSocketDevice = BDFDB.LibraryModules.SpotifyTrackUtils.getActiveSocketAndDevice(); this.request(newSocketDevice.socket, newSocketDevice.device, type, song, data).then(_ => { callback(error, response, result); }); }); } else callback(error, response, result); }); }); } render() { let socketDevice = BDFDB.LibraryModules.SpotifyTrackUtils.getActiveSocketAndDevice(); if (this.props.song) { lastSong = this.props.song; stopTime = null; } else if (!stopTime && lastSong) stopTime = new Date(); return !socketDevice || !lastSong ? null : BDFDB.ReactUtils.createElement("div", { className: BDFDB.disCN._spotifycontrolscontainer, children: [ BDFDB.ReactUtils.createElement("div", { className: BDFDB.disCN._spotifycontrolscontainerinner, children: [ BDFDB.ReactUtils.createElement("img", { className: BDFDB.disCN._spotifycontrolscover, src: BDFDB.LibraryModules.AssetUtils.getAssetImage(lastSong.application_id, lastSong.assets.large_image, [128, 128]) }), BDFDB.ReactUtils.createElement("div", { className: BDFDB.disCN._spotifycontrolsdetails, children: [ BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextElement, { className: BDFDB.disCN._spotifycontrolssong, children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextScroller, { children: lastSong.details }) }), BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextElement, { className: BDFDB.disCNS.subtext + BDFDB.disCN._spotifycontrolsinterpret, color: BDFDB.LibraryComponents.TextElement.Colors.CUSTOM, size: BDFDB.LibraryComponents.TextElement.Sizes.SIZE_12, children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextScroller, { children: BDFDB.LanguageUtils.LanguageStringsFormat("USER_ACTIVITY_LISTENING_ARTISTS", lastSong.state) }) }) ] }), BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { text: socketDevice.device.is_restricted ? "Can not control Spotify while playing on restricted device" : null, tooltipConfig: {color: "red"}, children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { grow: 0, children: [ BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, { className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.accountinfobutton, !socketDevice.device.is_restricted ? BDFDB.disCN.accountinfobuttonenabled : BDFDB.disCN.accountinfobuttondisabled), style: {fontFamily: "glue1-spoticon"}, look: BDFDB.LibraryComponents.Button.Looks.BLANK, size: BDFDB.LibraryComponents.Button.Sizes.NONE, children: "", onClick: socketDevice.device.is_restricted ? _ => {} : _ => { this.request(socketDevice.socket, socketDevice.device, "previous"); } }), BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, { className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.accountinfobutton, !socketDevice.device.is_restricted ? BDFDB.disCN.accountinfobuttonenabled : BDFDB.disCN.accountinfobuttondisabled), style: {fontFamily: "glue1-spoticon"}, look: BDFDB.LibraryComponents.Button.Looks.BLANK, size: BDFDB.LibraryComponents.Button.Sizes.NONE, children: this.props.song ? "" : "", onClick: socketDevice.device.is_restricted ? _ => {} : _ => { if (this.props.song) this.request(socketDevice.socket, socketDevice.device, "pause"); else this.request(socketDevice.socket, socketDevice.device, "play", lastSong); } }), BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, { className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.accountinfobutton, !socketDevice.device.is_restricted ? BDFDB.disCN.accountinfobuttonenabled : BDFDB.disCN.accountinfobuttondisabled), style: {fontFamily: "glue1-spoticon"}, look: BDFDB.LibraryComponents.Button.Looks.BLANK, size: BDFDB.LibraryComponents.Button.Sizes.NONE, children: "", onClick: socketDevice.device.is_restricted ? _ => {} : _ => { this.request(socketDevice.socket, socketDevice.device, "next"); } }) ] }) }) ] }), BDFDB.ReactUtils.createElement(SpotifyControlsTimelineComponent, { song: lastSong, running: !!this.props.song }) ] }); } }; const SpotifyControlsTimelineComponent = class SpotifyControlsTimeline extends BdApi.React.Component { componentDidMount() { BDFDB.TimeUtils.clear(updateInterval); updateInterval = BDFDB.TimeUtils.interval(_ => { if (!this.updater || typeof this.updater.isMounted != "function" || !this.updater.isMounted(this)) BDFDB.TimeUtils.clear(updateInterval); else if (this.props.running) { let song = BDFDB.LibraryModules.SpotifyTrackUtils.getActivity(); if (!song) BDFDB.ReactUtils.forceUpdate(controls); else if (this.props.running) BDFDB.ReactUtils.forceUpdate(this); } }, 1000); } formatTime(time) { let seconds = Math.floor((time / 1000) % 60); let minutes = Math.floor((time / (1000 * 60)) % 60); let hours = Math.floor((time / (1000 * 60 * 60)) % 24); return `${hours > 0 ? hours + ":" : ""}${hours > 0 && minutes < 10 ? "0" + minutes : minutes}:${seconds < 10 ? "0" + seconds : seconds}` } render() { let maxTime = this.props.song.timestamps.end - this.props.song.timestamps.start; let currentTime = (!this.props.running && stopTime ? stopTime : new Date()) - this.props.song.timestamps.start; currentTime = currentTime > maxTime ? maxTime : currentTime; return BDFDB.ReactUtils.createElement("div", { className: BDFDB.disCN._spotifycontrolsbarcontainer, children: [ BDFDB.ReactUtils.createElement("div", { className: BDFDB.disCN._spotifycontrolsbar, children: BDFDB.ReactUtils.createElement("div", { className: BDFDB.disCN._spotifycontrolsbarfill, style: {width: `${currentTime / maxTime * 100}%`} }) }), BDFDB.ReactUtils.createElement("div", { className: BDFDB.disCN._spotifycontrolsbartext, children: [ BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextElement, { className: BDFDB.disCN.height12, size: BDFDB.LibraryComponents.TextElement.Sizes.SIZE_12, children: this.formatTime(currentTime) }), BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextElement, { className: BDFDB.disCN.height12, size: BDFDB.LibraryComponents.TextElement.Sizes.SIZE_12, children: this.formatTime(maxTime) }) ] }) ] }); } }; return class SpotifyControls { getName () {return "SpotifyControls";} getVersion () {return "1.0.4";} getAuthor () {return "DevilBro";} getDescription () {return "Adds a control panel to discord when listening to spotify.";} constructor () { this.changelog = { "fixed":[["Controls","Fixed an issue where the controls would stop working after some time"],["Resume","Playlists should no longer restart, when you resume a song"]] }; this.patchedModules = { after: { AnalyticsContext: "render" } }; } initConstructor () { this.css = ` @font-face { font-family: glue1-spoticon; src: url("https://mwittrien.github.io/BetterDiscordAddons/Plugins/SpotifyControls/res/spoticon.ttf") format("truetype"); font-weight: 400; font-style: normal } ${BDFDB.dotCN._spotifycontrolscontainer} { margin-bottom: 1px; border-bottom: 1px solid var(--background-modifier-accent); padding: 8px 8px 0 8px; } ${BDFDB.dotCN._spotifycontrolscontainerinner} { display: flex; align-items: center; font-size: 14px; } ${BDFDB.dotCN._spotifycontrolsbarcontainer} { margin: 4px 0; } ${BDFDB.dotCN._spotifycontrolsbar} { border-radius: 2px; background-color: rgba(79, 84, 92, 0.16); height: 4px; margin-bottom: 4px; } ${BDFDB.dotCN._spotifycontrolsbarfill} { border-radius: 2px; height: 100%; min-width: 4px; border-radius: 2px; background: var(--header-primary); } ${BDFDB.dotCN._spotifycontrolsbartext} { display: flex; align-items: center; justify-content: space-between; } ${BDFDB.dotCN._spotifycontrolscover} { display: block; width: 32px; height: 32px; margin-right: 8px; border-radius: 4px; object-fit: cover; } ${BDFDB.dotCN._spotifycontrolsdetails} { user-select: text; flex-grow: 1; margin-right: 4px; min-width: 0; } ${BDFDB.dotCN._spotifycontrolssong} { font-weight: 500; } ${BDFDB.dotCN._spotifycontrolsinterpret} { font-weight: 300; } ${BDFDB.dotCNS._spotifycontrolscontainer + BDFDB.dotCN.accountinfobuttondisabled}{ cursor: no-drop; } `; } getSettingsPanel () { if (!window.BDFDB || typeof BDFDB != "object" || !BDFDB.loaded || !this.started) return; } // Legacy load () {} start () { if (!window.BDFDB) window.BDFDB = {myPlugins:{}}; if (window.BDFDB && window.BDFDB.myPlugins && typeof window.BDFDB.myPlugins == "object") window.BDFDB.myPlugins[this.getName()] = this; let libraryScript = document.querySelector("head script#BDFDBLibraryScript"); if (!libraryScript || (performance.now() - libraryScript.getAttribute("date")) > 600000) { if (libraryScript) libraryScript.remove(); libraryScript = document.createElement("script"); libraryScript.setAttribute("id", "BDFDBLibraryScript"); libraryScript.setAttribute("type", "text/javascript"); libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.min.js"); libraryScript.setAttribute("date", performance.now()); libraryScript.addEventListener("load", _ => {this.initialize();}); document.head.appendChild(libraryScript); } else if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) this.initialize(); this.startTimeout = setTimeout(_ => { try {return this.initialize();} catch (err) {console.error(`%c[${this.getName()}]%c`, "color: #3a71c1; font-weight: 700;", "", "Fatal Error: Could not initiate plugin! " + err);} }, 30000); } initialize () { if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { if (this.started) return; BDFDB.PluginUtils.init(this); BDFDB.ModuleUtils.patch(this, BDFDB.LibraryModules.SpotifyTrackUtils, "getActivity", {after: e => { if (e.returnValue && e.returnValue.name == "Spotify") this.updatePlayer(e.returnValue); else if (!e.returnValue) this.updatePlayer(null); }}); BDFDB.ModuleUtils.patch(this, BDFDB.LibraryModules.SpotifyTrackUtils, "wasAutoPaused", {instead: e => { return false; }}); BDFDB.ModuleUtils.patch(this, BDFDB.LibraryModules.SpotifyUtils, "pause", {instead: e => { return false; }}); BDFDB.ModuleUtils.forceAllUpdates(this); } else { console.error(`%c[${this.getName()}]%c`, 'color: #3a71c1; font-weight: 700;', '', 'Fatal Error: Could not load BD functions!'); } } stop () { if (window.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) { this.stopping = true; BDFDB.ModuleUtils.forceAllUpdates(this); BDFDB.PluginUtils.clear(this); } } // Begin of own functions processAnalyticsContext (e) { if (typeof e.returnvalue.props.children == "function" && e.instance.props.section == BDFDB.DiscordConstants.AnalyticsSections.ACCOUNT_PANEL) { let renderChildren = e.returnvalue.props.children; e.returnvalue.props.children = (...args) => { return [ BDFDB.ReactUtils.createElement(SpotifyControlsComponent, { song: BDFDB.LibraryModules.SpotifyTrackUtils.getActivity() }), renderChildren(...args) ]; }; } } updatePlayer (song) { if (controls) { controls.props.song = song; BDFDB.ReactUtils.forceUpdate(controls); } } } })();