// ==UserScript== // @name SpotiKitMobileDesktop - no more updates // @namespace https://github.com/Myst1cX/SpotiKit // @version 7.3.1.fork // @description SpotiKit — Mobile‑like layout for Spotify Web. Floating player, bottom nav, library overlay, and more. // @author kitbodega, Myst1cX (fork) // @icon https://i.ibb.co/YF1nLPfK/2eca7229-ca6a-4ad6-8653-b80a6a0f8586.png // @match https://open.spotify.com/* // @match https://www.spotify.com/*/account/* // @match https://www.spotify.com/*/premium/* // @match https://www.spotify.com/*/duo/* // @match https://www.spotify.com/*/student/* // @match https://www.spotify.com/*/family/* // @match https://payments.spotify.com/* // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_getValue // @run-at document-start // @homepageURL https://github.com/Myst1cX/SpotiKit // @supportURL https://github.com/Myst1cX/SpotiKit/issues // @updateURL https://raw.githubusercontent.com/Myst1cX/SpotiKit/main/SpotiKitMobileDesktop.user.js // @downloadURL https://raw.githubusercontent.com/Myst1cX/SpotiKit/main/SpotiKitMobileDesktop.user.js // ==/UserScript== // THIS WAS THE INITIAL FORK. THERE WILL BE NO MORE UPDATES. // USE: https://github.com/Myst1cX/spotifuck-userscript/raw/main/spotifuck-mobile.user.js // RESOLVED (7.3.1.fork, Myst1cX) // First batch: // Added a browser-side equivalent of Spotifuck's ForceEnglish // The userscript version forces English on open.spotify.com by overriding navigator.language/languages, // stripping a non-English /intl-xx/ locale prefix from the URL if present, // and flipping the account-level language setting at open.spotify.com/preferences to English via a hidden iframe when needed, // then verifying it stuck before reloading the page automatically. // Second batch: // Restored version 7.3's visual premium spoof & payment page blockers: // the PINK/GREEN constants, the REPLACE text-swap map, and the run() function - renamed to runPremium() to avoid clashes - that elabels // "Free" text as "Premium," hides upgrade/install-app prompts, and redirects away from the premium/duo/student/family/payments pages // Restored the @match lines for www.spotify.com/*/account,premium,duo,student,family/* and payments.spotify.com/* // Third batch: // Restricted the mobile bottom nav bar (Home/Search/Library) and its CSS to only load on open.spotify.com, // so it stops appearing on other spotify.com pages like the account/premium sections. // Fourth batch: // a) Fixed forceEnglish() to also redirect www.spotify.com off non-English region path segments (e.g. /mx/ -> /us/), // matching the fix already present on open.spotify.com. Previously only the open.spotify.com /intl-xx/ prefix was // stripped, so www.spotify.com account/premium pages could still render in a non-English region path. // b) Removed the old Spanish-language selectors/regex left over from before forceEnglish reliably forced English: // the "obtener|conseguir" and "explorar|ver|planes" branches of the button-relabeling regexes, the Spanish // "Planes Premium" XPath/aria-label selectors, the "abrir en...|instalar|descargar..." branch of the // desktop-app-hiding regex, and the Spanish "Descarga canciones..." string match. // c) Reworked runPremium()'s text-swap pass so it no longer does a blind full document.body walk on a timer. // It's now MutationObserver-driven: scanText()/applyReplacements() only re-scan nodes that actually changed, // batched and debounced (400ms) via handlePremiumMutations(), falling back to a full-body scan only if more // than 20 nodes changed in one batch. Every swap is now logged (selector, before/after text, times applied) // via logChange(), viewable through a new "Show everything replaced so far" userscript menu command. // d) Added two independent userscript-manager menu toggles (via GM_registerMenuCommand + GM_setValue/GM_getValue), // since the spoof behaves differently depending on which site it's touching: // 1. "Visual Premium Spoof (open.spotify.com)" - the in-player text/badge relabeling and account widgets // that render inside the web player. // 2. "Visual Premium Spoof (www.spotify.com)" - the account site (spotify.com /premium, /duo, /student, // /family, purchase pages) and the payments.spotify.com (plan payment blockers/redirects). // Each toggle is independent, persists via GM storage, and reloads the page to apply. Both are enabled by default. // Added the matching @grant lines (GM_registerMenuCommand, GM_setValue, GM_getValue) needed for the above. (function() { 'use strict'; const PINK = '#FFD2D7'; const GREEN = '#1ed760'; // --- Per-site visual premium spoof toggles (Fourth batch) --- const SPOOF_OPEN_KEY = 'spotikitPremSpoofOpen'; const SPOOF_WWW_KEY = 'spotikitPremSpoofWWW'; const HOST_IS_OPEN = location.hostname === 'open.spotify.com'; const HOST_IS_WWW = location.hostname === 'www.spotify.com' || location.hostname === 'payments.spotify.com'; function getFlag(key) { try { return typeof GM_getValue === 'function' ? GM_getValue(key, true) : true; } catch (e) { return true; } } function setFlag(key, val) { try { if (typeof GM_setValue === 'function') GM_setValue(key, val); } catch (e) {} } function premiumSpoofEnabledHere() { if (HOST_IS_OPEN) return getFlag(SPOOF_OPEN_KEY); if (HOST_IS_WWW) return getFlag(SPOOF_WWW_KEY); return false; } if (typeof GM_registerMenuCommand === 'function') { GM_registerMenuCommand( (getFlag(SPOOF_OPEN_KEY) ? '\u2705' : '\u274c') + ' Visual Premium Spoof (open.spotify.com)', () => { setFlag(SPOOF_OPEN_KEY, !getFlag(SPOOF_OPEN_KEY)); location.reload(); } ); GM_registerMenuCommand( (getFlag(SPOOF_WWW_KEY) ? '\u2705' : '\u274c') + ' Visual Premium Spoof (www.spotify.com)', () => { setFlag(SPOOF_WWW_KEY, !getFlag(SPOOF_WWW_KEY)); location.reload(); } ); } function forceEnglish() { try { Object.defineProperty(navigator, 'language', { get: () => 'en-US', configurable: true }); Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'], configurable: true }); } catch (e) {} if (location.hostname === 'www.spotify.com') { const ENGLISH_REGIONS = ['us', 'gb', 'ca', 'au', 'ie', 'nz']; const wm = location.pathname.match(/^\/([a-z]{2})(\/.*)?$/i); if (wm && !ENGLISH_REGIONS.includes(wm[1].toLowerCase())) { location.replace(location.origin + '/us' + (wm[2] || '/') + location.search + location.hash); return; } } const m = location.pathname.match(/^\/intl-([a-z]{2})(\/.*)?$/i); if (m && m[1].toLowerCase() !== 'en') { location.replace(location.origin + (m[2] || '/') + location.search + location.hash); return; } forceEnglishAccountSetting(); } function forceEnglishAccountSetting() { const PENDING_KEY = 'spotikitEnglishFlipPending'; const ATTEMPTS_KEY = 'spotikitEnglishFlipAttempts'; const MAX_ATTEMPTS = 3; if (window.top !== window.self) return; const verifying = localStorage.getItem(PENDING_KEY) === 'true'; if (verifying) localStorage.removeItem(PENDING_KEY); const withPreferencesDoc = (callback) => { let settled = false; const fire = (doc, cleanup) => { if (settled) return; settled = true; callback(doc, cleanup); }; if (location.pathname.startsWith('/preferences')) { fire(document, () => {}); return; } const iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = 'https://open.spotify.com/preferences'; (document.documentElement || document.body).appendChild(iframe); let removed = false; const cleanup = () => { if (removed) return; removed = true; iframe.remove(); }; iframe.addEventListener('load', () => { try { fire(iframe.contentDocument, cleanup); } catch (e) { cleanup(); fire(null, cleanup); } }); setTimeout(() => { cleanup(); fire(null, cleanup); }, 15000); }; const giveUp = () => {}; const attemptFlip = () => { withPreferencesDoc((doc, cleanup) => { if (!doc) { cleanup(); giveUp(); return; } applyEnglishToLanguageSelect(doc, (result) => { if (!result.found) { cleanup(); giveUp(); return; } if (!result.changed) { cleanup(); localStorage.removeItem(ATTEMPTS_KEY); return; } localStorage.setItem(PENDING_KEY, 'true'); setTimeout(() => { cleanup(); location.reload(); }, 1000); }); }); }; if (!verifying) { attemptFlip(); return; } withPreferencesDoc((doc, cleanup) => { if (!doc) { cleanup(); giveUp(); return; } applyEnglishToLanguageSelect(doc, (result) => { cleanup(); if (result.found && result.value === 'en') { localStorage.removeItem(ATTEMPTS_KEY); return; } if (!result.found) { giveUp(); return; } const attempts = parseInt(localStorage.getItem(ATTEMPTS_KEY) || '0', 10) + 1; if (attempts >= MAX_ATTEMPTS) { giveUp(); return; } localStorage.setItem(ATTEMPTS_KEY, String(attempts)); attemptFlip(); }, { readOnly: true }); }); } function applyEnglishToLanguageSelect(doc, onDone, { readOnly = false } = {}) { let settled = false; const resolve = (result) => { if (settled) return; settled = true; onDone(result); }; const trySelect = () => { const select = doc.getElementById('desktop.settings.selectLanguage'); if (!select) return false; if (readOnly || select.value === 'en') { resolve({ found: true, value: select.value, changed: false }); return true; } const win = doc.defaultView || window; const nativeSetter = Object.getOwnPropertyDescriptor(win.HTMLSelectElement.prototype, 'value').set; nativeSetter.call(select, 'en'); select.dispatchEvent(new Event('change', { bubbles: true })); resolve({ found: true, value: 'en', changed: true }); return true; }; if (trySelect()) return; const win = doc.defaultView || window; const startObserving = () => { if (trySelect()) return; const observer = new win.MutationObserver(() => { if (trySelect()) observer.disconnect(); }); observer.observe(doc.body, { childList: true, subtree: true }); setTimeout(() => { observer.disconnect(); resolve({ found: false, value: null, changed: false }); }, 12000); }; if (doc.body) { startObserving(); } else { doc.addEventListener('DOMContentLoaded', startObserving, { once: true }); } } forceEnglish(); let ulFlag = false; let ffDone = false; let pfint = null; let sidebarOverlayActive = false; const cache = { leftSidebar: null, rootContainer: null, bottomNav: null }; function getLeftSidebar() { if (!cache.leftSidebar || !document.contains(cache.leftSidebar)) { cache.leftSidebar = document.querySelector('#Desktop_LeftSidebar_Id'); } return cache.leftSidebar; } function getRootContainer() { if (!cache.rootContainer || !document.contains(cache.rootContainer)) { cache.rootContainer = document.querySelector('.Root__top-container') || document.querySelector('div[data-testid=root]'); } return cache.rootContainer; } window.switchLs = function(forceCollapse = false) { const leftSidebar = getLeftSidebar(); if (!leftSidebar) return; const rootContainer = getRootContainer(); if (forceCollapse || sidebarOverlayActive) { delete leftSidebar.dataset.overlay; sidebarOverlayActive = false; if (rootContainer) { rootContainer.style.removeProperty('--left-sidebar-width'); rootContainer.style.removeProperty('--nav-bar-width'); } setTimeout(() => { window.dispatchEvent(new Event('resize')); }, 50); } else { leftSidebar.dataset.overlay = 'true'; sidebarOverlayActive = true; if (rootContainer) { rootContainer.style.setProperty('--left-sidebar-width', window.innerWidth + 'px'); rootContainer.style.setProperty('--nav-bar-width', window.innerWidth + 'px'); } const expandBtn = leftSidebar.querySelector( 'button[aria-label*="Expand Your Library"], ' + 'button[aria-label*="Expandir Tu biblioteca"], ' + 'button[aria-label*="Expandir tu biblioteca"]' ); if (expandBtn) { expandBtn.click(); } const headerH1 = leftSidebar.querySelector('header>div>div:first-child h1'); if (headerH1) { const lang = document.documentElement.lang || ''; headerH1.textContent = lang.startsWith('es') ? 'Tu biblioteca' : 'Your library'; } setTimeout(() => { const list = leftSidebar.querySelector('[role="list"],[role="grid"],div[class*="view-container"]'); if (list) { list.scrollBy(0, 1); list.scrollBy(0, -1); } window.dispatchEvent(new Event('resize')); }, 100); } updateActiveTab(); }; window.firstFuck = function() { if (pfint) clearInterval(pfint); pfint = setInterval(() => { const playBtn = document.querySelector('aside button[data-testid=control-button-playpause]:not(.fuckd)'); if (playBtn) { playBtn.classList.add('fuckd'); window.pBtn = playBtn; if (!ffDone) { ffDone = true; clearInterval(pfint); addCSSJSHack(); } } }, 5000); }; window.addCSSJSHack = function() { const setupLibraryButton = () => { const libBtn = document.querySelector('#Desktop_LeftSidebar_Id header button[aria-label*="Your Library"]:not(.fuckd)'); if (libBtn && !libBtn.classList.contains('fuckd')) { window.lBtn = libBtn; libBtn.classList.add('fuckd', 'lbtn'); libBtn.style.padding = '0'; libBtn.style.height = '20px'; libBtn.addEventListener('click', function() { setTimeout(() => switchLs(), 0); }); if (libBtn.getAttribute('aria-label') === 'Collapse Your Library') { libBtn.click(); } } }; const setupLibraryGrid = () => { const libGrid = document.querySelector('#Desktop_LeftSidebar_Id div[role=grid]:not(.fuckd)'); if (libGrid) { libGrid.classList.add('fuckd'); libGrid.addEventListener('click', (event) => { let target = event.target; let isFolder = false; for (let i = 0; i < 5 && target; i++) { const ariaLabelledBy = target.getAttribute('aria-labelledby'); if (ariaLabelledBy && ariaLabelledBy.includes(':folder:')) { isFolder = true; break; } const ariaDescribedBy = target.getAttribute('aria-describedby'); if (ariaDescribedBy && ariaDescribedBy.includes(':folder:')) { isFolder = true; break; } target = target.parentElement; } if (!isFolder) { setTimeout(() => { switchLs(true); }, 150); } }); } }; const setupSearchInput = () => { const searchInput = document.querySelector('input[data-testid=search-input]:not(.fuckd)'); if (searchInput) { searchInput.classList.add('fuckd'); searchInput.addEventListener('focus', () => { const npBar = document.querySelector('aside[data-testid=now-playing-bar]'); if (npBar) npBar.style.display = 'none'; }); searchInput.addEventListener('blur', () => { const npBar = document.querySelector('aside[data-testid=now-playing-bar]'); if (npBar) npBar.style.display = 'flex'; }); } }; setupLibraryButton(); setupLibraryGrid(); setupSearchInput(); setupPlayerToggle(); setTimeout(() => { setupLibraryButton(); setupLibraryGrid(); setupSearchInput(); setupPlayerToggle(); }, 2000); }; function setupPlayerToggle() { const player = document.querySelector('aside[data-testid=now-playing-bar]:not(.fuckd)'); if (!player || player.querySelector('#sp-player-toggle')) return; player.classList.add('fuckd'); const btn = document.createElement('button'); btn.id = 'sp-player-toggle'; btn.textContent = '\u25BC'; player.appendChild(btn); btn.addEventListener('click', function(e) { e.stopPropagation(); player.classList.toggle('minimized'); btn.textContent = player.classList.contains('minimized') ? '\u25B2' : '\u25BC'; }); } function injectMobileCSS() { const style = document.createElement('style'); style.textContent = ` body{min-width:100%!important;min-height:100%!important;padding-bottom:56px!important} body,div[data-testid=root],.Root__top-container,.Root__now-playing-bar{background:transparent!important} aside[data-testid=now-playing-bar]>div,.Root__now-playing-bar>div,.Root__now-playing-bar{background:transparent!important} .os-scrollbar{--os-size:6px!important} .contentSpacing{padding:0} div[data-testid=root]{--panel-gap:0!important;--content-spacing:10px} #main+div,#main+div>div{overflow:hidden!important;width:auto} #main+div>div>div>div:nth-child(2)>div{width:100vw!important} div[data-encore-id=banner], #global-nav-bar>div:first-of-type, #global-nav-bar a[href="/download"], button[data-testid=fullscreen-mode-button], div.main-view-container__mh-footer-container, button[data-testid=upgrade-button], a[href="/download"], button[aria-label="Expandir la vista Estás escuchando"], button[aria-label="Ocultar la vista Estás escuchando"] {display:none!important} #global-nav-bar{display:none!important} body.sp-search #global-nav-bar{display:flex!important} #global-nav-bar button[data-testid=home-button], #global-nav-bar a[aria-label*="Home"], #global-nav-bar a[aria-label*="Inicio"]{display:none!important} #sp-bottom-nav{ position:fixed; bottom:0; left:0; right:0; height:56px; background:transparent!important; background-image:linear-gradient(to top,rgba(0,0,0,1) 0%,rgba(0,0,0,0.85) 40%,rgba(0,0,0,0.5) 75%,rgba(0,0,0,0) 100%)!important; border:none!important; box-shadow:none!important; display:flex; align-items:center; justify-content:space-around; z-index:9999; padding:0 8px; pointer-events:none; will-change:transform } #sp-bottom-nav button{ flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px; background:none!important; border:none; color:#b3b3b3; cursor:pointer; padding:4px 0; transition:color 0.15s; height:100%; pointer-events:auto } #sp-bottom-nav button.active{color:#fff} #sp-bottom-nav button svg{width:24px;height:24px;fill:currentColor} #sp-bottom-nav button span{font-size:10px;letter-spacing:0.5px} aside[data-testid=now-playing-bar]{ min-width:calc(100% - 16px)!important; margin:0 8px!important; position:fixed!important; box-shadow:0 -4px 30px rgba(0,0,0,0.5)!important; background:rgba(40,8,8,0.65)!important; backdrop-filter:blur(20px)!important; -webkit-backdrop-filter:blur(20px)!important; border:1px solid rgba(255,255,255,0.06)!important; bottom:64px!important; z-index:30!important; border-radius:16px!important; transition:transform 0.3s cubic-bezier(0.4,0,0.2,1),height 0.3s cubic-bezier(0.4,0,0.2,1)!important; overflow:hidden!important; will-change:transform } aside[data-testid=now-playing-bar].minimized{ height:72px!important; min-height:72px!important; max-height:72px!important; border-radius:14px!important; background:rgba(40,8,8,0.85)!important; padding:0!important } aside[data-testid=now-playing-bar].minimized div[data-testid=general-controls], aside[data-testid=now-playing-bar].minimized [data-testid=progress-bar], aside[data-testid=now-playing-bar].minimized [role=progressbar], aside[data-testid=now-playing-bar].minimized [data-testid=playback-position], aside[data-testid=now-playing-bar].minimized [data-testid=playback-duration], aside[data-testid=now-playing-bar].minimized [data-testid=playback-progressbar], aside[data-testid=now-playing-bar].minimized button[aria-label*="Previous"], aside[data-testid=now-playing-bar].minimized button[aria-label*="Next"], aside[data-testid=now-playing-bar].minimized button[aria-label*="Skip"], aside[data-testid=now-playing-bar].minimized button[aria-label*="Aleatorio"], aside[data-testid=now-playing-bar].minimized button[aria-label*="repeat"], aside[data-testid=now-playing-bar].minimized button[aria-label*="Repetir"], aside[data-testid=now-playing-bar].minimized button[data-testid="lyrics-button"], aside[data-testid=now-playing-bar].minimized button[data-testid="control-button-queue"], aside[data-testid=now-playing-bar].minimized button[data-testid="pip-toggle-button"], aside[data-testid=now-playing-bar].minimized button[data-testid="fullscreen-mode-button"], aside[data-testid=now-playing-bar].minimized button[aria-label*="Conectar"], aside[data-testid=now-playing-bar].minimized button[aria-label*="conectar"], aside[data-testid=now-playing-bar].minimized button[aria-label*="device"], aside[data-testid=now-playing-bar].minimized [data-testid="volume-bar"], aside[data-testid=now-playing-bar].minimized div[data-testid=now-playing-widget]>div:last-child, aside[data-testid=now-playing-bar].minimized>div:first-child>div:last-child{ display:none!important } aside[data-testid=now-playing-bar].minimized>div:first-child{ flex-direction:row!important; align-items:center!important; gap:10px!important; padding:8px 44px 8px 8px!important; height:100%!important } aside[data-testid=now-playing-bar].minimized div[data-testid=now-playing-widget]{ flex:1!important; min-width:0!important; flex-direction:row!important; align-items:center!important; gap:12px!important; height:100%!important } aside[data-testid=now-playing-bar].minimized div[data-testid=now-playing-widget]>div:first-child{ width:56px!important; height:56px!important; min-width:56px!important; border-radius:6px!important; overflow:hidden!important } aside[data-testid=now-playing-bar].minimized div[data-testid=now-playing-widget]>div:first-child img{ width:100%!important; height:100%!important; border-radius:6px!important } aside[data-testid=now-playing-bar].minimized div[data-testid=now-playing-widget]>div:nth-child(2){ overflow:hidden!important; max-width:50vw!important; display:flex!important; flex-direction:column!important; justify-content:center!important; gap:2px!important } aside[data-testid=now-playing-bar].minimized div[data-testid=now-playing-widget]>div:nth-child(2) a, aside[data-testid=now-playing-bar].minimized div[data-testid=now-playing-widget]>div:nth-child(2) span{ white-space:nowrap!important; overflow:hidden!important; text-overflow:ellipsis!important; max-width:100%!important; font-size:14px!important; line-height:1.3!important } aside[data-testid=now-playing-bar].minimized div[data-testid=now-playing-widget]>div:nth-child(2)>div:last-child span{ font-size:12px!important; opacity:0.75!important } aside[data-testid=now-playing-bar].minimized div[data-testid=player-controls]{ width:auto!important; margin:0!important; flex:none!important; height:100%!important; display:flex!important; align-items:center!important } aside[data-testid=now-playing-bar].minimized div[data-testid=player-controls]>div{ min-height:0!important; margin:0!important } aside[data-testid=now-playing-bar].minimized div[data-testid=player-controls] button[data-testid=control-button-playpause]{ transform:scale(1.15)!important; margin:0 6px!important } #sp-player-toggle{ position:absolute; right:10px; top:50%; transform:translateY(-50%); background:rgba(255,255,255,0.1); border:1px solid rgba(255,255,255,0.08); color:#fff; width:28px; height:28px; border-radius:50%; cursor:pointer; z-index:5; font-size:11px; line-height:1; display:flex; align-items:center; justify-content:center; padding:0; opacity:0.7; transition:opacity 0.2s } #sp-player-toggle:hover{opacity:1;background:rgba(255,255,255,0.2)} aside[data-testid=now-playing-bar] button[aria-label*="scroll"], aside[data-testid=now-playing-bar] button[aria-label*="info"], aside[data-testid=now-playing-bar] [class*="chevron"], aside[data-testid=now-playing-bar] [class*="Chevron"], aside[data-testid=now-playing-bar] button[aria-label*="Play from"], aside[data-testid=now-playing-bar] button[aria-label*="Queue"]{display:none!important} aside[data-testid=now-playing-bar]:not(.minimized)>div:first-child{ flex-direction:column!important; height:auto!important; padding:8px 8px 6px!important } aside[data-testid=now-playing-bar]>div>div{width:100%!important} aside[data-testid=now-playing-bar]:not(.minimized)>div>div:last-child>div{min-height:28px;margin:3px 6px} aside[data-testid=now-playing-bar]:not(.minimized)>div>div:last-child button{transform:scale(1.1);margin:0 4px} aside[data-testid=now-playing-bar]:not(.minimized) div[data-testid=general-controls]{margin:6px 0 8px!important} aside[data-testid=now-playing-bar]:not(.minimized) div[data-testid=general-controls] button{transform:scale(1.2)!important;margin:0 6px!important} aside[data-testid=now-playing-bar]:not(.minimized) div[data-testid=player-controls]{margin:2px 0!important} aside[data-testid=now-playing-bar]:not(.minimized) div[data-testid=now-playing-widget]{justify-content:center;overflow:hidden} aside[data-testid=now-playing-bar]:not(.minimized) div[data-testid=now-playing-widget]>div:last-child>button{transform:scale(1.15)} aside[data-testid=now-playing-bar]:not(.minimized) div[data-testid=now-playing-widget]>div:nth-child(2){display:flex!important;overflow:hidden!important} aside[data-testid=now-playing-bar]:not(.minimized) div[data-testid=now-playing-widget]>div:nth-child(2) span{font-size:13px!important;height:20px!important;margin:0!important} aside[data-testid=now-playing-bar]:not(.minimized) div[data-testid=now-playing-widget]>div:nth-child(2)>div{min-width:auto;max-width:66%} aside[data-testid=now-playing-bar]:not(.minimized)>div:first-child>div:last-child{ display:flex!important; flex-direction:row!important; align-items:center!important; justify-content:center!important; gap:2px!important; padding:4px 0!important } aside[data-testid=now-playing-bar]:not(.minimized)>div:first-child>div:last-child button{transform:scale(0.85)!important} aside[data-testid=now-playing-bar]:not(.minimized)>div:first-child>div:last-child [data-testid=volume-bar]{max-width:100px!important} input[data-testid="search-input"], input[aria-label="¿Qué quieres reproducir?"], input[aria-label="What do you want to play?"]{display:none!important} body.sp-search input[data-testid="search-input"], body.sp-search input[aria-label="¿Qué quieres reproducir?"], body.sp-search input[aria-label="What do you want to play?"]{display:flex!important} body.sp-collection main>section>div:first-child{height:auto!important;min-height:auto!important;padding:10px} form[role=search]{z-index:10;max-width:88%} #Desktop_LeftSidebar_Id{ width:0!important; min-width:0!important; overflow:hidden!important; display:none!important } #Desktop_LeftSidebar_Id[data-overlay="true"]{ display:flex!important; position:fixed!important; top:0!important; left:0!important; width:100vw!important; min-width:100vw!important; max-width:100vw!important; height:calc(100vh - 56px)!important; z-index:999!important; background:#121212!important; flex-direction:column!important; overflow:hidden!important } #Desktop_LeftSidebar_Id[data-overlay="true"]>*{ width:100vw!important; min-width:100vw!important; max-width:100vw!important } #Desktop_LeftSidebar_Id[data-overlay="true"] .YourLibraryX, #Desktop_LeftSidebar_Id[data-overlay="true"] [class*="YourLibraryX"]{ width:100vw!important; min-width:100vw!important; max-width:100vw!important; background:transparent!important; height:100%!important } #Desktop_LeftSidebar_Id[data-overlay="true"] nav{width:100vw!important;max-width:100vw!important} #Desktop_LeftSidebar_Id[data-overlay="true"] header button[aria-label*="Create"]{ position:absolute!important; top:14px!important; right:14px!important; width:36px!important; height:36px!important } #Desktop_LeftSidebar_Id[data-overlay="true"] button[aria-label*="Collapse Your Library"], #Desktop_LeftSidebar_Id[data-overlay="true"] button[aria-label*="Expand Your Library"], #Desktop_LeftSidebar_Id[data-overlay="true"] button[aria-label*="Comprimir"], #Desktop_LeftSidebar_Id[data-overlay="true"] button[aria-label*="Expandir"]{display:none!important} #Desktop_LeftSidebar_Id[data-overlay="true"] [data-testid="resize-bar"], #Desktop_LeftSidebar_Id[data-overlay="true"] [class*="ResizeBar"], #Desktop_LeftSidebar_Id[data-overlay="true"] [class*="resize-bar"], #Desktop_LeftSidebar_Id[data-overlay="true"] [class*="Resizer"]{ display:none!important; width:0!important; pointer-events:none!important } [data-testid="resize-bar"],[class*="ResizeBar"]{display:none!important} #Desktop_LeftSidebar_Id[data-overlay="true"] [data-overlayscrollbars-viewport], #Desktop_LeftSidebar_Id[data-overlay="true"] [class*="os-viewport"], #Desktop_LeftSidebar_Id[data-overlay="true"] div[role="grid"], #Desktop_LeftSidebar_Id[data-overlay="true"] [data-testid="LibraryRoot"]{padding-bottom:80px!important} #Desktop_LeftSidebar_Id>nav>div{min-height:48px;border-radius:25px} .YourLibraryX{background:var(--background-elevated-base)!important} .YourLibraryX header{padding:14px} #main-view,div[data-testid=main-view],.Root__main-view, #main-view+div,#main-view+div>div,#main-view+div>div>div, div[data-testid=root]>div:first-child>div:first-child{margin-left:0!important;padding-left:0!important} section[data-testid=artist-page]>div>div:first-child:not([data-encore-id]){height:25vh} div[data-testid=tracklist-row]{padding:0 10px 0 0;grid-gap:0} div[data-testid=tracklist-row] button:not([data-testid=add-to-playlist-button]){transform:scale(1.3)!important;opacity:0.6!important} div[data-testid=tracklist-row] button:hover{color:#2d6!important} div[data-testid=tracklist-row]>div:first-child>div:first-child{height:24px;min-height:24px;min-width:24px;margin:0 8px!important} [aria-colcount="3"] div[data-testid=tracklist-row]{grid-template-columns:[index] var(--tracklist-index-column-width,40px) [first] minmax(120px,var(--col1,4fr)) [last] minmax(82px,var(--col2,1fr))!important} [aria-colcount="4"] div[data-testid=tracklist-row]{grid-template-columns:[index] var(--tracklist-index-column-width,40px) [first] minmax(120px,var(--col1,4fr)) [var1] minmax(120px,var(--col2,2fr)) [last] minmax(82px,var(--col3,1fr))!important} [aria-colcount="5"] div[data-testid=tracklist-row]{grid-template-columns:[index] var(--tracklist-index-column-width,40px) [first] minmax(120px,var(--col1,6fr)) [var1] minmax(120px,var(--col2,4fr)) [var2] minmax(120px,var(--col3,3fr)) [last] minmax(82px,var(--col4,1fr))!important} section[data-testid=home-page] .contentSpacing{padding:0 10px!important;overflow:hidden} div[data-testid=grid-container]{margin-inline:0!important;column-gap:0!important;overflow:hidden!important} div[data-testid=action-bar-row],div[data-testid=topbar-content]{padding:5px 10px} div[data-testid=track-list]>div:first-child,div[data-testid=playlist-tracklist]>div:first-child{margin:0!important;padding:0!important} main>section:not([data-testid=artist-page])>div:first-child{height:auto!important;min-height:auto!important;padding:10px} main>section h1.encore-text-headline-large{font-size:22px!important} section[data-testid=artist-page] span.encore-text-headline-large{font-size:26px!important} section[data-testid=artist-page] div[data-testid=grid-container] h2,section[data-testid=artist-page] section[data-testid=component-shelf]{padding:0 10px} .Root__top-container{grid-template-columns:auto 1fr auto!important} #Desktop_PanelContainer_Id{display:flex!important;flex-direction:column!important;overflow-y:auto!important} div.IPnR0MPdiJw3m3C8.rd25SoWs7Y4T40c7, button[aria-label="Comprimir Tu biblioteca"], button[aria-label="Collapse Your library"]{display:none!important} button[data-testid="npv-artist-bio-button"],.tDBAoTKiCjMk1wxv{display:none!important;height:0px!important} .qy8cKKS5c5Y24cTG{display:none!important} .lhB5KQbFP8BJIgvI{flex:1!important;overflow-y:auto!important} ul.oPf3qKGRkUM3T0bK{display:block!important;overflow-y:auto!important} `; document.head.appendChild(style); } const FALLBACK_SVGS = { home: '', search: '', library: '' }; function createBottomNav() { if (document.getElementById('sp-bottom-nav')) return; const nav = document.createElement('div'); nav.id = 'sp-bottom-nav'; cache.bottomNav = nav; const tabs = [ { name: 'home', label: 'Home' }, { name: 'search', label: 'Search' }, { name: 'library', label: 'Library' } ]; const frag = document.createDocumentFragment(); tabs.forEach(({ name, label }) => { const btn = document.createElement('button'); btn.dataset.tab = name; btn.innerHTML = `${FALLBACK_SVGS[name]}${label}`; btn.addEventListener('click', () => handleTabClick(name)); frag.appendChild(btn); }); nav.appendChild(frag); document.body.appendChild(nav); updateActiveTab(); } function handleTabClick(name) { const currentPath = location.pathname; if (name === 'library') { if (sidebarOverlayActive) { switchLs(true); } else { switchLs(); } return; } if (sidebarOverlayActive) switchLs(true); if (name === 'search') { if (!currentPath.startsWith('/search')) { history.pushState(null, '', '/search'); window.dispatchEvent(new PopStateEvent('popstate')); } return; } if (name === 'home') { if (currentPath !== '/') { history.pushState(null, '', '/'); window.dispatchEvent(new PopStateEvent('popstate')); } return; } } let lastActiveTab = null; function updateActiveTab() { const path = location.pathname; let active = null; if (sidebarOverlayActive) active = 'library'; else if (path === '/' || path === '/home') active = 'home'; else if (path.startsWith('/search')) active = 'search'; else if (path.startsWith('/collection')) active = 'library'; if (active === lastActiveTab) return; lastActiveTab = active; const nav = cache.bottomNav || document.getElementById('sp-bottom-nav'); if (!nav) return; const buttons = nav.children; for (let i = 0; i < buttons.length; i++) { const btn = buttons[i]; btn.classList.toggle('active', btn.dataset.tab === active); } } let lastBodyClass = ''; function updateBodyClass() { const path = location.pathname; let cls = ''; if (path === '/' || path === '/home') cls = 'sp-home'; else if (path.startsWith('/search')) cls = 'sp-search'; else if (path.startsWith('/collection')) cls = 'sp-collection'; else if (path.startsWith('/playlist')) cls = 'sp-playlist'; else if (path.startsWith('/album')) cls = 'sp-album'; else if (path.startsWith('/artist')) cls = 'sp-artist'; else if (path.startsWith('/track')) cls = 'sp-track'; if (cls === lastBodyClass) return; if (lastBodyClass) document.body.classList.remove(lastBodyClass); if (cls) document.body.classList.add(cls); lastBodyClass = cls; } let lastPath = ''; function onLocationChange() { if (location.pathname === lastPath) return; lastPath = location.pathname; updateBodyClass(); updateActiveTab(); } function hookHistory() { const origPush = history.pushState; const origReplace = history.replaceState; history.pushState = function() { origPush.apply(this, arguments); onLocationChange(); }; history.replaceState = function() { origReplace.apply(this, arguments); onLocationChange(); }; window.addEventListener('popstate', onLocationChange); } const IS_OPEN_SPOTIFY = window.location.hostname === 'open.spotify.com'; if (IS_OPEN_SPOTIFY) { injectMobileCSS(); const waitForBody = setInterval(() => { if (document.body) { clearInterval(waitForBody); lastPath = location.pathname; updateBodyClass(); createBottomNav(); firstFuck(); hookHistory(); } }, 100); } GM_addStyle(` .__sp_curr { display:inline-block; background:#535353; color:#fff; font-size:11px; font-weight:700; padding:3px 8px; border-radius:3px; text-transform:uppercase; letter-spacing:.4px; } `); const REPLACE = { "Spotify Free": "Premium Individual", "1 Free account": "1 Premium account", "1 free account": "1 Premium account", "Music with ads": "Listen to music ad-free", "Music listening with ad breaks": "Listen to music ad-free", "Shuffle play": "Play any song", "Songs play in shuffle": "Play any song", "Online only": "Download for offline listening", "Streaming only": "Download for offline listening", "No downloads": "Download for offline listening", "Basic audio quality": "Very high audio quality", "Normal audio quality": "Very high audio quality", "Limited skips": "Unlimited skips", "Free plan": "Premium Individual", }; const replacementLog = new Map(); function logChange(selector, from, to) { const key = `${selector}\u0000${from}\u0000${to}`; const existing = replacementLog.get(key); if (existing) existing.times_applied++; else replacementLog.set(key, { selector, old_text: from, new_text: to, times_applied: 1 }); } function printReplacementLog() { if (replacementLog.size === 0) { console.log('[SpotiKit] Nothing has been replaced yet.'); return; } console.log(`[SpotiKit] ${replacementLog.size} distinct change(s) made so far:`); console.table(Array.from(replacementLog.values())); } function applyReplacements(node) { let v = node.nodeValue; if (v == null) return; let c = false; for (const [from, to] of Object.entries(REPLACE)) { if (v.includes(from)) { v = v.replaceAll(from, to); c = true; logChange('(page text)', from, to); } } if (c) node.nodeValue = v; } function scanText(root) { if (!root) return; const w = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false); let n; while (n = w.nextNode()) applyReplacements(n); } function runPremium() { document.querySelectorAll('.encore-text-title-medium, [class*="title-medium"]').forEach(el => { if ((el.textContent || '').trim() === 'Premium Individual') { el.style.color = window.location.href.includes('/subscription/manage/') ? '#000' : PINK; const parent = el.closest('[class*="Hjkjj"], [class*="hjkjj"]'); if (parent) { parent.style.background = PINK; parent.style.color = '#000'; } } }); const planCard = document.querySelector('[data-testid="plan-card"]'); if (planCard && !planCard.querySelector('.__sp_logo')) { planCard.style.position = 'relative'; const logo = document.createElement('span'); logo.className = '__sp_logo'; logo.style.cssText = 'position:absolute;top:8px;right:8px;width:24px;height:24px;z-index:10;pointer-events:none;display:flex;align-items:center;justify-content:center;background:#FFD2D7;border-radius:50%;font-size:12px;font-weight:700;color:#000;'; logo.textContent = 'SP'; planCard.appendChild(logo); const msg = document.createElement('p'); msg.textContent = 'Your Premium Individual NEVER expires. Dont pay Spotify, fuck their monopoly!'; msg.style.cssText = 'color:#B3B3B3;font-size:14px;margin:8px 0;text-align:left;line-height:1.4;padding:0 4px;'; const btnRow = planCard.querySelector('[class*="dCZPlm"]'); if (btnRow) btnRow.parentNode.insertBefore(msg, btnRow); } document.querySelectorAll('h1, h2, h3, h4, strong, span, div[class*="plan"], div[class*="Plan"]').forEach(el => { const t = (el.textContent || '').trim(); if (t === 'Free' || t === 'Spotify Free' || t === 'Free plan') { logChange('h1,h2,h3,h4,strong,span,div[class*="plan"]', t, 'Premium Individual'); el.textContent = 'Premium Individual'; el.style.color = PINK; el.style.fontWeight = '700'; } }); document.querySelectorAll('a, button, [role="button"]').forEach(el => { const orig = (el.innerText || el.textContent || '').trim(); const t = orig.toLowerCase(); if (/^(get|buy|join)\s*premium/.test(t)) { logChange('a, button, [role="button"]', orig, 'DONT JOIN PREMIUM'); el.textContent = 'DONT JOIN PREMIUM'; el.style.cssText += `background:${PINK}!important;color:#000!important;border:none!important;border-radius:20px!important;font-weight:700!important;pointer-events:none!important;cursor:default!important;`; el.onclick = e => { e.preventDefault(); e.stopPropagation(); }; } if (/^(explore|view)\s*plans/.test(t)) { logChange('a, button, [role="button"]', orig, 'Manage plan'); el.textContent = 'Manage plan'; el.style.cssText += `background:transparent!important;color:#fff!important;border:1px solid #727272!important;border-radius:20px!important;font-weight:700!important;pointer-events:none!important;cursor:default!important;`; el.onclick = e => { e.preventDefault(); e.stopPropagation(); }; } if (/^try/.test(t) && !el.dataset.spDone) { logChange('a, button, [role="button"]', orig, '(hidden)'); el.style.display = 'none'; el.dataset.spDone = '1'; } }); document.querySelectorAll('[class*="badge"], [class*="Badge"]').forEach(el => { if (/^free$/i.test(el.textContent.trim())) { el.textContent = 'PREMIUM'; el.style.background = PINK; el.style.color = '#000'; } }); document.querySelectorAll('table').forEach(tbl => { tbl.querySelectorAll('td, th').forEach(cell => { const t = cell.textContent.trim().toLowerCase(); if (!t || t === '\u2014' || t === '-' || t === 'no' || /free/.test(t)) { logChange('table td, th', t || '(empty)', '\u2713'); cell.innerHTML = `\u2713`; } }); }); document.querySelectorAll('span[data-encore-id="text"]').forEach(el => { const t = el.textContent.trim(); if (t === 'Download for offline listening') { logChange('span[data-encore-id="text"]', t, 'Spotify wont fuck you'); el.textContent = 'Spotify wont fuck you'; } }); const upgradeBtn = document.querySelector('[data-testid="upgrade-button"]:not([data-sp-done])'); if (upgradeBtn) { logChange('[data-testid="upgrade-button"]', upgradeBtn.textContent.trim(), '(hidden)'); upgradeBtn.style.display = 'none'; upgradeBtn.dataset.spDone = '1'; } const installBtn = document.querySelector('a[href="/download"]:not([data-sp-done])'); if (installBtn) { logChange('a[href="/download"]', 'install app link', '(hidden)'); installBtn.style.display = 'none'; installBtn.dataset.spDone = '1'; } const premiumMenu = document.querySelector('a[href*="premium/?ref=web_loggedin_upgrade_menu"]:not([data-sp-done])'); if (premiumMenu) { logChange('a[href*="premium/?ref=web_loggedin_upgrade_menu"]', premiumMenu.textContent.trim(), '(hidden)'); premiumMenu.style.display = 'none'; premiumMenu.dataset.spDone = '1'; } const planesXpath = document.evaluate( '//a[text()="Premium Plans"] | //span[text()="Premium Plans"] | //div[text()="Premium Plans"]', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null ); for (let i = 0; i < planesXpath.snapshotLength; i++) { const n = planesXpath.snapshotItem(i); if (n && n.nodeType === 1 && !n.dataset.spDone) { logChange('(xpath) Premium Plans text', n.textContent.trim(), '(hidden)'); n.style.display = 'none'; n.dataset.spDone = '1'; } } document.querySelectorAll('[aria-label*="Premium Plans"], [data-ga-action="premium"], [data-ga-category="menu"] a, a[href*="/premium/"]').forEach(el => { if (el.dataset.spDone) return; const t = el.textContent.trim(); if (t === 'Premium Plans') { logChange('[aria-label*="Premium Plans"] / [data-ga-action="premium"] / a[href*="/premium/"]', t, '(hidden)'); el.style.display = 'none'; el.dataset.spDone = '1'; } }); const DESKTOP_SELECTORS = [ '[data-testid="open-in-app-button"]', '[data-testid="install-app-button"]', '[data-testid="download-button"]', '[aria-label*="open in app"]', '[aria-label*="install app"]', '[aria-label*="download app"]', '[class*="open-in-app"]', '[class*="install-app"]', '[class*="get-the-app"]', '[class*="view-in-app"]', '[class*="desktop-app"]', ]; DESKTOP_SELECTORS.forEach(sel => { document.querySelectorAll(sel).forEach(el => el.style.display = 'none'); }); document.querySelectorAll('a, button, [role="button"]').forEach(el => { const t = (el.textContent || '').trim().toLowerCase(); if (/open (in|the) (app|desktop|spotify)|install|download (the )?app|get the app|launch|listen in app|listen on desktop|use (the )?(app|desktop)/.test(t)) { el.style.display = 'none'; } }); const premiumBanner = document.querySelector('[data-testid="compact-banner"]'); if (premiumBanner) { const wrapper = premiumBanner.closest('[class*="dad329a7"]'); if (wrapper) { wrapper.style.width = '100%'; } premiumBanner.style.cssText += ` display:flex !important; flex-direction:row !important; background:#2A2A2A !important; cursor:default !important; padding:0 !important; border-radius:8px !important; overflow:hidden !important; min-width:unset !important; width:100% !important; `; const left = document.createElement('div'); left.style.cssText = 'flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;row-gap:var(--encore-spacing-tighter-2);padding:var(--encore-spacing-looser) var(--encore-spacing-tighter-2);cursor:pointer;'; const pencilSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); pencilSvg.setAttribute('viewBox', '0 0 16 16'); pencilSvg.setAttribute('role', 'img'); pencilSvg.setAttribute('aria-hidden', 'true'); pencilSvg.style.cssText = 'width:var(--encore-graphic-size-decorative-base);height:var(--encore-graphic-size-decorative-base);'; pencilSvg.innerHTML = ``; const leftText = document.createElement('span'); leftText.className = 'e-10561-text encore-text-body-small-bold'; leftText.style.cssText = 'color:var(--text-base);text-align:center;'; leftText.textContent = 'Edit profile'; left.appendChild(pencilSvg); left.appendChild(leftText); left.onclick = e => { e.stopPropagation(); window.location.href = 'https://www.spotify.com/us/account/profile/'; }; const right = document.createElement('div'); right.style.cssText = 'flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;row-gap:var(--encore-spacing-tighter-2);padding:var(--encore-spacing-looser) var(--encore-spacing-tighter-2);cursor:pointer;border-left:1px solid #404040;'; const cardSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); cardSvg.setAttribute('viewBox', '0 0 16 16'); cardSvg.setAttribute('role', 'img'); cardSvg.setAttribute('aria-hidden', 'true'); cardSvg.style.cssText = 'width:var(--encore-graphic-size-decorative-base);height:var(--encore-graphic-size-decorative-base);'; cardSvg.innerHTML = ``; const rightText = document.createElement('span'); rightText.className = 'e-10561-text encore-text-body-small-bold'; rightText.style.cssText = 'color:var(--text-base);text-align:center;'; rightText.textContent = 'Payment method'; right.appendChild(cardSvg); right.appendChild(rightText); right.onclick = e => { e.stopPropagation(); window.location.href = 'https://www.spotify.com/us/account/saved-payment-cards/'; }; premiumBanner.innerHTML = ''; premiumBanner.appendChild(left); premiumBanner.appendChild(right); } if (/\/premium\/|\/duo\/|\/student\/|\/family\//.test(window.location.href) && !document.querySelector('.__sp_premium_done')) { window.location.replace('https://open.spotify.com/'); } if (window.location.hostname === 'payments.spotify.com' && !document.querySelector('.__sp_pay_done')) { window.location.replace('https://open.spotify.com/'); } } // Single gated entry point: both the timed passes below and the mutation // observer funnel through this so premiumSpoofEnabledHere() is the one // switch that turns the whole spoof pass on/off for the current host. function premiumPass(changedRoot) { if (!premiumSpoofEnabledHere()) return; if (changedRoot) scanText(changedRoot); else scanText(document.body); runPremium(); } setTimeout(() => premiumPass(document.body), 300); setTimeout(() => premiumPass(document.body), 2000); let premTimer; let pendingNodes = new Set(); let pendingTextNodes = new Set(); let premiumObserver = null; function handlePremiumMutations(mutations) { if (!premiumSpoofEnabledHere()) return; for (const m of mutations) { if (m.type === 'childList') { m.addedNodes.forEach(node => { if (node.nodeType === 1) pendingNodes.add(node); }); } else if (m.type === 'characterData') { pendingTextNodes.add(m.target); } } clearTimeout(premTimer); premTimer = setTimeout(() => { if (pendingNodes.size > 0 && pendingNodes.size <= 20) { pendingNodes.forEach(node => scanText(node)); } else if (pendingNodes.size > 20) { scanText(document.body); } pendingNodes.clear(); pendingTextNodes.forEach(node => applyReplacements(node)); pendingTextNodes.clear(); runPremium(); }, 400); } function startPremiumObserver() { if (premiumObserver) premiumObserver.disconnect(); premiumObserver = new MutationObserver(handlePremiumMutations); premiumObserver.observe(document.body, { childList: true, subtree: true, characterData: true, }); } if (document.body) { startPremiumObserver(); } else { document.addEventListener('DOMContentLoaded', startPremiumObserver, { once: true }); } if (typeof GM_registerMenuCommand === 'function') { GM_registerMenuCommand('\ud83d\udccb Show everything replaced so far (console)', () => { printReplacementLog(); alert('Current text replacements have been logged to the console. Open DevTools (Press F12 or Right click and Inspect), then select the Logs tab under Console to view it.'); }); } })();