// ==UserScript== // @name osu! Beatmap Download Link Replacer // @namespace http://tampermonkey.net/ // @version 1.1 // @description 将 osu!direct 谱面页面的 supporter 链接替换为osu://dl/[id] (方便lazer用户下载谱面,stable用户仍需开通supporter才能在游戏内使用osu!direct) // @author theinspired with 豆包 // @match https://osu.ppy.sh/* // @grant none // @license MIT // @run-at document-start // ==/UserScript== (function() { 'use strict'; // 1. 从URL中提取beatmapset ID function getBeatmapSetId() { const regex = /https:\/\/osu\.ppy\.sh\/beatmapsets\/(\d+)/; const match = window.location.href.match(regex); if (!match || !match[1]) { console.error("无法从URL中提取beatmapset ID"); return null; } return match[1]; } // 2. 替换页面中的support链接(核心逻辑) function replaceSupportLinks() { const beatmapId = getBeatmapSetId(); if (!beatmapId) return; const targetLink = `osu://dl/${beatmapId}`; const originalLink = "https://osu.ppy.sh/home/support"; // 查找并替换所有相关链接 const links = document.querySelectorAll(`a[href*="${originalLink}"]`); links.forEach(link => { link.href = targetLink; console.log(`已替换链接: ${originalLink} -> ${targetLink}`); }); } // 3. 监听页面动态加载的元素 function setupMutationObserver() { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.addedNodes.length > 0) { replaceSupportLinks(); } }); }); observer.observe(document.body, { childList: true, subtree: true }); return observer; } // 4. 监听URL变化(解决SPA跳转问题) function setupUrlChangeListener() { // 保存当前URL,用于对比变化 let currentUrl = window.location.href; // 监听popstate事件(浏览器前进/后退) window.addEventListener('popstate', () => { if (window.location.href !== currentUrl) { currentUrl = window.location.href; setTimeout(replaceSupportLinks, 100); // 延迟确保DOM已更新 } }); // 重写pushState和replaceState(SPA跳转核心) const originalPushState = history.pushState; const originalReplaceState = history.replaceState; history.pushState = function(...args) { originalPushState.apply(this, args); currentUrl = window.location.href; setTimeout(replaceSupportLinks, 100); }; history.replaceState = function(...args) { originalReplaceState.apply(this, args); currentUrl = window.location.href; setTimeout(replaceSupportLinks, 100); }; } // 初始化 window.addEventListener('DOMContentLoaded', () => { replaceSupportLinks(); // 首次加载执行 setupMutationObserver(); // 监听动态元素 setupUrlChangeListener(); // 监听URL变化 }); })();