mirror of
https://github.com/SpotX-Official/SpotX.git
synced 2026-06-14 03:16:33 +10:00
fix(js-helper): ignore empty bearer and remove local version fallback
- wait for a non-empty bearer token before starting and stop capture after 5 empty attempts or 30s - use the worker latest endpoint as the final fallback and stop when no remote version is available
This commit is contained in:
+64
-40
@@ -2,12 +2,11 @@
|
|||||||
if (window.oneTime) return;
|
if (window.oneTime) return;
|
||||||
window.oneTime = true;
|
window.oneTime = true;
|
||||||
|
|
||||||
const REPORT_BASE_URL = "https://spotify-ingest-admin.amd64fox1.workers.dev";
|
const WORKER_BASE_URL = "https://spotify-ingest-admin.amd64fox1.workers.dev";
|
||||||
const SCRIPT_VERSION = "1.1.0";
|
const SCRIPT_VERSION = "1.2.0";
|
||||||
|
|
||||||
const SOURCE_LABELS = {
|
const SOURCE_LABELS = {
|
||||||
REMOTE: "latest.json",
|
REMOTE: "latest.json",
|
||||||
LOCAL: "window",
|
|
||||||
FIXED: "fixed-version"
|
FIXED: "fixed-version"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -56,19 +55,25 @@
|
|||||||
? [String(window.__spotifyLatestUrl).trim()]
|
? [String(window.__spotifyLatestUrl).trim()]
|
||||||
: [
|
: [
|
||||||
"https://raw.githubusercontent.com/LoaderSpot/table/refs/heads/main/latest.json",
|
"https://raw.githubusercontent.com/LoaderSpot/table/refs/heads/main/latest.json",
|
||||||
"https://raw.githack.com/LoaderSpot/table/main/latest.json"
|
"https://raw.githack.com/LoaderSpot/table/main/latest.json",
|
||||||
|
`${WORKER_BASE_URL}/api/client/latest`
|
||||||
],
|
],
|
||||||
updateUrl: "https://spclient.wg.spotify.com/desktop-update/v2/update",
|
updateUrl: "https://spclient.wg.spotify.com/desktop-update/v2/update",
|
||||||
reportEndpoint: `${REPORT_BASE_URL}/api/client/report`,
|
reportEndpoint: `${WORKER_BASE_URL}/api/client/report`,
|
||||||
errorEndpoint: `${REPORT_BASE_URL}/api/client/error`,
|
errorEndpoint: `${WORKER_BASE_URL}/api/client/error`,
|
||||||
reportTimeoutMs: 15000,
|
reportTimeoutMs: 15000,
|
||||||
versionTimeoutMs: 10000,
|
versionTimeoutMs: 10000,
|
||||||
desktopUpdateTimeoutMs: 8000,
|
desktopUpdateTimeoutMs: 8000,
|
||||||
desktopUpdateMaxRetries: 1
|
desktopUpdateMaxRetries: 1,
|
||||||
|
tokenCaptureMaxAttempts: 5,
|
||||||
|
tokenCaptureTimeoutMs: 30000
|
||||||
};
|
};
|
||||||
|
|
||||||
const originalFetch = window.fetch;
|
const originalFetch = window.fetch;
|
||||||
let runStarted = false;
|
let runStarted = false;
|
||||||
|
let tokenCaptureStopped = false;
|
||||||
|
let tokenCaptureAttempts = 0;
|
||||||
|
let tokenCaptureTimeoutId = 0;
|
||||||
|
|
||||||
const SPOTIFY_VERSION_RE = /Spotify\/(\d+\.\d+\.\d+\.\d+)/;
|
const SPOTIFY_VERSION_RE = /Spotify\/(\d+\.\d+\.\d+\.\d+)/;
|
||||||
|
|
||||||
@@ -88,24 +93,6 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLocalSpotifyVersion() {
|
|
||||||
const versionSources = readVersionSourceSnapshot();
|
|
||||||
const sources = [
|
|
||||||
versionSources.clientInformationAppVersion,
|
|
||||||
versionSources.userAgent,
|
|
||||||
versionSources.navigatorAppVersion
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const source of sources) {
|
|
||||||
const version = String(source || "").match(SPOTIFY_VERSION_RE)?.[1];
|
|
||||||
if (version) {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
function readClientVersionSources() {
|
function readClientVersionSources() {
|
||||||
const versionSources = readVersionSourceSnapshot();
|
const versionSources = readVersionSourceSnapshot();
|
||||||
|
|
||||||
@@ -195,12 +182,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const localVersion = getLocalSpotifyVersion();
|
|
||||||
return {
|
return {
|
||||||
shortVersion: localVersion,
|
shortVersion: "",
|
||||||
fullVersion: "",
|
fullVersion: "",
|
||||||
spotifyAppVersion: buildSpotifyAppVersion(localVersion, SOURCE_LABELS.LOCAL),
|
spotifyAppVersion: "",
|
||||||
sourceLabel: SOURCE_LABELS.LOCAL,
|
sourceLabel: "",
|
||||||
remoteVersionFailed: true,
|
remoteVersionFailed: true,
|
||||||
remoteShortVersion: "",
|
remoteShortVersion: "",
|
||||||
remoteFullVersion: ""
|
remoteFullVersion: ""
|
||||||
@@ -905,24 +891,62 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractBearerToken(authorization) {
|
||||||
|
const match = String(authorization || "").match(/^Bearer\s+(.+)$/i);
|
||||||
|
if (!match) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return String(match[1] || "").trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopTokenCapture(reason) {
|
||||||
|
if (tokenCaptureStopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenCaptureStopped = true;
|
||||||
|
window.fetch = originalFetch;
|
||||||
|
if (tokenCaptureTimeoutId) {
|
||||||
|
clearTimeout(tokenCaptureTimeoutId);
|
||||||
|
tokenCaptureTimeoutId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reason === "max_attempts") {
|
||||||
|
console.warn(`Spotify token capture stopped after ${CONFIG.tokenCaptureMaxAttempts} empty bearer attempts.`);
|
||||||
|
} else if (reason === "timeout") {
|
||||||
|
console.warn(`Spotify token capture stopped after ${CONFIG.tokenCaptureTimeoutMs}ms timeout.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenCaptureTimeoutId = setTimeout(() => {
|
||||||
|
if (!runStarted) {
|
||||||
|
stopTokenCapture("timeout");
|
||||||
|
}
|
||||||
|
}, CONFIG.tokenCaptureTimeoutMs);
|
||||||
|
|
||||||
window.fetch = async function (...args) {
|
window.fetch = async function (...args) {
|
||||||
const [input, init] = args;
|
const [input, init] = args;
|
||||||
const headers = init?.headers || (input instanceof Request ? input.headers : null);
|
const headers = init?.headers || (input instanceof Request ? input.headers : null);
|
||||||
const authorization = getHeaderValue(headers, "authorization");
|
const authorization = getHeaderValue(headers, "authorization");
|
||||||
|
|
||||||
if (!runStarted && isSpotifyAuthorizedRequest(getRequestUrl(input), authorization)) {
|
if (!runStarted && !tokenCaptureStopped && isSpotifyAuthorizedRequest(getRequestUrl(input), authorization)) {
|
||||||
runStarted = true;
|
tokenCaptureAttempts += 1;
|
||||||
window.fetch = originalFetch;
|
const token = extractBearerToken(authorization);
|
||||||
|
if (token) {
|
||||||
|
runStarted = true;
|
||||||
|
stopTokenCapture("success");
|
||||||
|
|
||||||
const token = String(authorization).replace(/^Bearer\s+/i, "");
|
void runOnce(token).catch((error) => {
|
||||||
void runOnce(token).catch((error) => {
|
const state = createState(token);
|
||||||
const state = createState(token);
|
sendError(state, "uncaught", {
|
||||||
sendError(state, "uncaught", {
|
phase: "uncaught_runOnce",
|
||||||
phase: "uncaught_runOnce",
|
message: error?.message || String(error),
|
||||||
message: error?.message || String(error),
|
stack: error?.stack || ""
|
||||||
stack: error?.stack || ""
|
});
|
||||||
});
|
});
|
||||||
});
|
} else if (tokenCaptureAttempts >= CONFIG.tokenCaptureMaxAttempts) {
|
||||||
|
stopTokenCapture("max_attempts");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return originalFetch.apply(this, args);
|
return originalFetch.apply(this, args);
|
||||||
|
|||||||
Reference in New Issue
Block a user