From f1c9f1cc6079d1728305f1c8f28447a50eb304d6 Mon Sep 17 00:00:00 2001 From: Delusoire Date: Mon, 19 Feb 2024 19:37:07 +0100 Subject: [PATCH 1/4] fix(wrapper): made profile menu button selector more precise (#2839) Co-authored-by: ririxi --- jsHelper/spicetifyWrapper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsHelper/spicetifyWrapper.js b/jsHelper/spicetifyWrapper.js index 7afe62d520..c2dd00d80b 100644 --- a/jsHelper/spicetifyWrapper.js +++ b/jsHelper/spicetifyWrapper.js @@ -1552,7 +1552,7 @@ Spicetify.ContextMenuV2 = (() => { })(); Spicetify.Menu = (() => { - const shouldAdd = (_, trigger, target) => trigger === "click" && target.closest(".main-topBar-container"); + const shouldAdd = (_, trigger, target) => trigger === "click" && target.getAttribute("data-testid")?.endsWith("user-widget-link"); class Item extends Spicetify.ContextMenuV2.Item { constructor(children, isEnabled, onClick, leadingIcon) { From 1205ea455a3d6322e5bd54dc97ea53bddd1516c4 Mon Sep 17 00:00:00 2001 From: ririxi Date: Tue, 20 Feb 2024 18:47:47 +0100 Subject: [PATCH 2/4] feat: add proxy for CosmosAsync calls (#2846) Co-authored-by: Delusoire --- jsHelper/spicetifyWrapper.js | 93 ++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/jsHelper/spicetifyWrapper.js b/jsHelper/spicetifyWrapper.js index c2dd00d80b..35f80f58cf 100644 --- a/jsHelper/spicetifyWrapper.js +++ b/jsHelper/spicetifyWrapper.js @@ -303,6 +303,99 @@ window.Spicetify = { Platform: {} }; +(function addProxyCosmos() { + if (!Spicetify.Player.origin?._cosmos) { + setTimeout(addProxyCosmos, 50); + return; + } + + const corsProxyURL = "https://cors-proxy.spicetify.app/"; + const allowedMethodsMap = { + get: "get", + post: "post", + del: "delete", + put: "put", + patch: "patch" + }; + const allowedMethodsSet = new Set(Object.keys(allowedMethodsMap)); + const internalEndpoints = new Set(["sp:", "wg:"]); + + const handler = { + // biome-ignore lint/complexity/useArrowFunction: + get: function (target, prop, receiver) { + const internalFetch = Reflect.get(target, prop, receiver); + + if (typeof internalFetch !== "function" || !allowedMethodsSet.has(prop) || Spicetify.Platform.version < "1.2.31") return internalFetch; + + // biome-ignore lint/complexity/useArrowFunction: + return async function (url, body) { + const urlObj = new URL(url); + + const isWebAPI = urlObj.hostname === "api.spotify.com"; + const isSpClientAPI = urlObj.hostname.includes("spotify.com") && urlObj.hostname.includes("spclient"); + const isInternalURL = internalEndpoints.has(urlObj.protocol); + // biome-ignore lint/style/noArguments: + if (isInternalURL) return internalFetch.apply(this, arguments); + + const shouldUseCORSProxy = !isWebAPI && !isSpClientAPI && !isInternalURL; + + const method = allowedMethodsMap[prop.toLowerCase()]; + const headers = { + "Content-Type": "application/json" + }; + + const options = { + method, + headers, + timeout: 1000 * 15 + }; + + function isJson(str) { + try { + JSON.parse(str); + } catch { + return false; + } + return true; + } + + let finalURL = urlObj.toString(); + if (body) { + if (method === "get") { + const params = new URLSearchParams(body); + finalURL += `?${params.toString()}`; + } else options.body = isJson ? JSON.stringify(body) : body; + } + if (shouldUseCORSProxy) finalURL = `${corsProxyURL}${finalURL}`; + + const Authorization = `Bearer ${Spicetify.Platform.AuthorizationAPI.getState().token.accessToken}`; + let injectedHeaders = {}; + if (isWebAPI) injectedHeaders = { Authorization }; + if (isSpClientAPI) { + injectedHeaders = { + Authorization, + "Spotify-App-Version": Spicetify.Platform.version, + "App-Platform": Spicetify.Platform.PlatformData.app_platform + }; + } + Object.assign(options.headers, injectedHeaders); + + try { + return fetch(finalURL, options).then(res => + res.json().catch(() => { + return { status: res.status }; + }) + ); + } catch (e) { + console.error(e); + } + }; + } + }; + + Spicetify.Player.origin._cosmos = new Proxy(Spicetify.Player.origin._cosmos, handler); +})(); + (function waitForPlatform() { if (!Spicetify._platform) { setTimeout(waitForPlatform, 50); From 5c542454656996d8d528889c92efe8cbeab952f8 Mon Sep 17 00:00:00 2001 From: ririxi Date: Tue, 20 Feb 2024 18:47:56 +0100 Subject: [PATCH 3/4] fix(wrapper/chunks): add failsafe for `1.2.31` (#2840) --- jsHelper/spicetifyWrapper.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/jsHelper/spicetifyWrapper.js b/jsHelper/spicetifyWrapper.js index 35f80f58cf..11e8240b0a 100644 --- a/jsHelper/spicetifyWrapper.js +++ b/jsHelper/spicetifyWrapper.js @@ -419,7 +419,11 @@ window.Spicetify = { } // Force all webpack modules to load const require = webpackChunkopen.push([[Symbol()], {}, re => re]); - const chunks = Object.entries(require.m); + const chunks = require.m ? Object.entries(require.m) : []; + if (!chunks) { + setTimeout(hotloadWebpackModules, 50); + return; + } const cache = Object.keys(require.m).map(id => require(id)); const modules = cache .filter(module => typeof module === "object") From 5f77de501800fcb56d4a533ed5bd59a92e6f6095 Mon Sep 17 00:00:00 2001 From: ririxi Date: Tue, 20 Feb 2024 20:04:58 +0100 Subject: [PATCH 4/4] fix: use different check for target in `shouldAdd` (#2853) --- jsHelper/spicetifyWrapper.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jsHelper/spicetifyWrapper.js b/jsHelper/spicetifyWrapper.js index 11e8240b0a..4d47811bd8 100644 --- a/jsHelper/spicetifyWrapper.js +++ b/jsHelper/spicetifyWrapper.js @@ -1649,7 +1649,8 @@ Spicetify.ContextMenuV2 = (() => { })(); Spicetify.Menu = (() => { - const shouldAdd = (_, trigger, target) => trigger === "click" && target.getAttribute("data-testid")?.endsWith("user-widget-link"); + const shouldAdd = (_, trigger, target) => + trigger === "click" && (target.classList.contains("main-userWidget-boxCondensed") || target.classList.contains("main-userWidget-box")); class Item extends Spicetify.ContextMenuV2.Item { constructor(children, isEnabled, onClick, leadingIcon) {