Skip to content

Instantly share code, notes, and snippets.

@superRaytin
Created May 12, 2025 09:29
Show Gist options
  • Select an option

  • Save superRaytin/07b509cb8cb2dd3a641712bb61d26202 to your computer and use it in GitHub Desktop.

Select an option

Save superRaytin/07b509cb8cb2dd3a641712bb61d26202 to your computer and use it in GitHub Desktop.
Local Resource Redirector | 本地资源代理重定向工具
// ==UserScript==
// @name Local Resource Redirector | 本地资源代理重定向工具
// @namespace https://github.com/superRaytin
// @version 1.0
// @description Redirect specified remote resources to local files for testing, debugging, and development use.
// @author superraytin
// @match *://*/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @run-at document-start
// ==/UserScript==
(function () {
"use strict";
let currentRules = GM_getValue("rules", []);
function getRedirectedUrl(originalUrl) {
for (const rule of currentRules) {
if (
rule.enabled &&
rule.url &&
rule.localPath &&
originalUrl.includes(rule.url)
) {
return rule.localPath;
}
}
return null;
}
// 拦截 fetch 请求
const originalFetch = window.fetch;
window.fetch = async (...args) => {
const redirected = getRedirectedUrl(args[0]);
if (redirected) args[0] = redirected;
return originalFetch(...args);
};
// 拦截 XHR 请求
const open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (method, url) {
const redirected = getRedirectedUrl(url);
if (redirected) arguments[1] = redirected;
return open.apply(this, arguments);
};
// 拦截 script 元素动态加载
const originalCreateElement = document.createElement;
document.createElement = function (tag) {
const el = originalCreateElement.call(document, tag);
if (tag.toLowerCase() === "script") {
Object.defineProperty(el, "src", {
set(val) {
const redirected = getRedirectedUrl(val);
el.setAttribute("src", redirected || val);
},
get() {
return el.getAttribute("src");
},
});
}
return el;
};
// 注册菜单命令打开配置界面
GM_registerMenuCommand("Configure Redirect Rules", openSettingsUI);
function openSettingsUI() {
const win = window.open("", "", "width=600,height=400");
win.document.write(`<html><head><title>Redirect Rules</title></head><body>
<h2>Redirect Rules (模糊匹配)</h2>
<table border="1" id="rulesTable" style="width:100%">
<tr><th>Enable</th><th>Match Substring (in remote URL)</th><th>Local Redirect URL</th><th>Delete</th></tr>
</table>
<button id="addRule">Add Rule</button>
<button id="applyRules">Apply Rules</button>
</body></html>`);
const table = win.document.getElementById("rulesTable");
function renderTable() {
Array.from(table.rows)
.slice(1)
.forEach((row) => row.remove());
currentRules.forEach((rule, index) => {
const row = table.insertRow();
const checkbox = win.document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = rule.enabled;
checkbox.onchange = () => {
currentRules[index].enabled = checkbox.checked;
};
const urlInput = win.document.createElement("input");
urlInput.type = "text";
urlInput.value = rule.url || "";
urlInput.style = "width:100%";
urlInput.oninput = () => {
currentRules[index].url = urlInput.value;
};
const pathInput = win.document.createElement("input");
pathInput.type = "text";
pathInput.value = rule.localPath || "";
pathInput.style = "width:100%";
pathInput.oninput = () => {
currentRules[index].localPath = pathInput.value;
};
const deleteBtn = win.document.createElement("button");
deleteBtn.textContent = "Delete";
deleteBtn.onclick = () => {
currentRules.splice(index, 1);
renderTable();
};
row.insertCell().appendChild(checkbox);
row.insertCell().appendChild(urlInput);
row.insertCell().appendChild(pathInput);
row.insertCell().appendChild(deleteBtn);
});
}
win.document.getElementById("addRule").onclick = () => {
currentRules.push({ enabled: true, url: "", localPath: "" });
renderTable();
};
win.document.getElementById("applyRules").onclick = () => {
const cleaned = currentRules.filter(
(r) => r.url?.trim() && r.localPath?.trim()
);
GM_setValue("rules", cleaned);
currentRules = cleaned;
win.alert("Rules applied. Reload the target page to take effect.");
renderTable();
};
renderTable();
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment