您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Lists ALL releases at the artist page, not just hand picked ones by deezer.
// ==UserScript== // @name Deezer List All Releases // @description Lists ALL releases at the artist page, not just hand picked ones by deezer. // @author bertigert // @version 1.0.2 // @icon https://www.google.com/s2/favicons?sz=64&domain=deezer.com // @namespace Violentmonkey Scripts // @match https://www.deezer.com/* // @grant none // ==/UserScript== (function() { class Logger { static PREFIX = "[Display All Songs]"; constructor(do_debug) { this.do_debug = do_debug; } log(...args) { console.log(Logger.PREFIX, ...args); } warn(...args) { console.warn(Logger.PREFIX, ...args); } error(...args) { console.error(Logger.PREFIX, ...args); } debug(...args) { if (this.do_debug) console.debug(Logger.PREFIX, ...args); } } class Hooks { static HOOK_INDEXES = Object.freeze({ FETCH: 0, ALL: 1 }); // we use this approach to unhook to avoid unhooking hooks created after our hooks static is_hooked = [false]; static hook_fetch() { const orig_fetch = window.fetch; async function hooked_fetch(...args) { if (!Hooks.is_hooked[Hooks.HOOK_INDEXES.FETCH]) return orig_fetch.apply(this, args); try { if (args.length !== 2 || args[0] !== "https://pipe.deezer.com/api" || args[1].method !== "POST" || typeof args[1].body !== "string" ) { return orig_fetch.apply(this, args); } const operation_name = args[1].body.match(/"operationName":\s*"(.*?)"/); if (operation_name && operation_name[1] === "ArtistDiscographyByType") { // logger.debug('Caught original artist page fetch call'); args[1].body = args[1].body.replace(/"subType":\s*"(.*?)"/, '"subType": null') .replace(/"mode":\s*"(.*?)"/, '"mode": "ALL"'); } return orig_fetch.apply(this, args); } catch (e) { logger.error("Error in fetch hook:", e); return orig_fetch.apply(this, args); } } // only change the function which gets called, not the attributes of the original fetch function Object.setPrototypeOf(hooked_fetch, orig_fetch); Object.getOwnPropertyNames(orig_fetch).forEach(prop => { try { hooked_fetch[prop] = orig_fetch[prop]; } catch (e) {} }); window.fetch = hooked_fetch; window.fetch._modified_by_display_all_songs = true; } static ensure_hooks() { if (!window.fetch._modified_by_display_all_songs) { Hooks.hook_fetch(); } } static toggle_hooks(enabled, ...args) { for (const arg of args) { switch (arg) { case Hooks.HOOK_INDEXES.ALL: Hooks.is_hooked.fill(enabled); return; case Hooks.HOOK_INDEXES.FETCH: Hooks.is_hooked[arg] = enabled; break; } } } } const logger = new Logger(false); function artist_main() { logger.debug("Enabling hooks for artist page"); Hooks.toggle_hooks(true, Hooks.HOOK_INDEXES.ALL); } function cleanup() { logger.debug("Disabling hooks"); Hooks.toggle_hooks(false, Hooks.HOOK_INDEXES.ALL); } window.history.pushState = new Proxy(window.history.pushState, { apply: (target, thisArg, argArray) => { if (location.href.includes("/artist/")) { artist_main(); } else { cleanup(); } return target.apply(thisArg, argArray); }, }); window.addEventListener("popstate", (e) => { if (location.href.includes("/artist/")) { artist_main(); } else { cleanup(); } }); logger.log("Initializing"); Hooks.hook_fetch(); setTimeout(Hooks.ensure_hooks, 5000); if (location.href.includes("/artist/")) { artist_main(); } })();