您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Manage allowed sites dynamically and reference this in other scripts.
当前为
此脚本不应直接安装,它是供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://updategreasyfork.deno.dev/scripts/526770/1585264/Site%20Filter%20%28Protocol-Independent%29.js
// ==UserScript== // @name Site Filter (Protocol-Independent) // @namespace http://tampermonkey.net/ // @version 2.5 // @description Manage allowed sites dynamically and reference this in other scripts. // @author blvdmd // @match *://*/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant GM_download // @run-at document-start // ==/UserScript== (function () { 'use strict'; const USE_EMOJI_FOR_STATUS = true; // Configurable flag to use emoji for true/false status const SHOW_STATUS_ONLY_IF_TRUE = true; // Configurable flag to show status only if any value is true // ✅ Wait for `SCRIPT_STORAGE_KEY` to be set function waitForScriptStorageKey(maxWait = 1000) { return new Promise(resolve => { const startTime = Date.now(); const interval = setInterval(() => { if (typeof window.SCRIPT_STORAGE_KEY !== 'undefined') { clearInterval(interval); resolve(window.SCRIPT_STORAGE_KEY); } else if (Date.now() - startTime > maxWait) { clearInterval(interval); console.error("🚨 SCRIPT_STORAGE_KEY is not set! Make sure your script sets it **before** @require."); resolve(null); } }, 50); }); } (async function initialize() { async function waitForDocumentReady() { if (document.readyState === "complete") return; return new Promise(resolve => { window.addEventListener("load", resolve, { once: true }); }); } // ✅ Wait for the script storage key const key = await waitForScriptStorageKey(); if (!key) return; // ✅ Ensure the document is fully loaded before setting `shouldRunOnThisSite` await waitForDocumentReady(); const STORAGE_KEY = `additionalSites_${key}`; function getDefaultList() { return typeof window.GET_DEFAULT_LIST === "function" ? window.GET_DEFAULT_LIST() : []; } function normalizeUrl(url) { if (typeof url !== 'string') { url = String(url); } return url.replace(/^https?:\/\//, ''); } let additionalSites = GM_getValue(STORAGE_KEY, []); let mergedSites = [...new Set([...getDefaultList(), ...additionalSites])].map(item => { if (typeof item === 'string') { return { pattern: normalizeUrl(item), preProcessingRequired: false, postProcessingRequired: false }; } return { ...item, pattern: normalizeUrl(item.pattern) }; }); GM_registerMenuCommand("➕ Add Current Site to Include List", addCurrentSiteMenu); GM_registerMenuCommand("📜 View Included Sites", viewIncludedSites); GM_registerMenuCommand("🗑️ Delete Specific Entries", deleteEntries); GM_registerMenuCommand("✏️ Edit an Entry", editEntry); GM_registerMenuCommand("🚨 Clear All Entries", clearAllEntries); GM_registerMenuCommand("📤 Export Site List as JSON", exportAdditionalSites); GM_registerMenuCommand("📥 Import Site List from JSON", importAdditionalSites); async function shouldRunOnThisSite() { const currentFullPath = normalizeUrl(`${window.top.location.href}`); return mergedSites.some(item => wildcardToRegex(normalizeUrl(item.pattern)).test(currentFullPath)); } function wildcardToRegex(pattern) { return new RegExp("^" + pattern .replace(/[-[\]{}()+^$|#\s]/g, '\\$&') .replace(/\./g, '\\.') .replace(/\?/g, '\\?') .replace(/\*/g, '.*') + "$"); } function addCurrentSiteMenu() { const currentHost = window.top.location.hostname; // Use window.top to get the top-level hostname const currentPath = window.top.location.pathname; // Use window.top to get the top-level pathname const domainParts = currentHost.split('.'); const baseDomain = domainParts.length > 2 ? domainParts.slice(-2).join('.') : domainParts.join('.'); const secondLevelDomain = domainParts.length > 2 ? domainParts.slice(-2, -1)[0] : domainParts[0]; const options = [ { name: `Preferred Domain Match (*${secondLevelDomain}.*)`, pattern: `*${secondLevelDomain}.*` }, { name: `Base Hostname (*.${baseDomain}*)`, pattern: `*.${baseDomain}*` }, { name: `Base Domain (*.${secondLevelDomain}.*)`, pattern: `*.${secondLevelDomain}.*` }, { name: `Host Contains (*${secondLevelDomain}*)`, pattern: `*${secondLevelDomain}*` }, { name: `Exact Path (${currentHost}${currentPath})`, pattern: normalizeUrl(`${window.top.location.href}`) }, { name: "Custom Wildcard Pattern", pattern: normalizeUrl(`${window.top.location.href}`) } ]; const userChoice = prompt( "Select an option to add the site:\n" + options.map((opt, index) => `${index + 1}. ${opt.name}`).join("\n") + "\nEnter a number or cancel." ); if (!userChoice) return; const selectedIndex = parseInt(userChoice, 10) - 1; if (selectedIndex >= 0 && selectedIndex < options.length) { let pattern = normalizeUrl(options[selectedIndex].pattern); if (options[selectedIndex].name === "Custom Wildcard Pattern") { pattern = normalizeUrl(prompt("Edit custom wildcard pattern:", pattern)); if (!pattern.trim()) return alert("Invalid pattern. Operation canceled."); } const preProcessingRequired = prompt("Is pre-processing required? (y/n)", "n").toLowerCase() === 'y'; const postProcessingRequired = prompt("Is post-processing required? (y/n)", "n").toLowerCase() === 'y'; const onDemandFloatingButtonRequired = prompt("Is on-demand floating button required? (y/n)", "n").toLowerCase() === 'y'; const backgroundChangeObserverRequired = prompt("Is background change observer required? (y/n)", "n").toLowerCase() === 'y'; const entry = { pattern, preProcessingRequired, postProcessingRequired, onDemandFloatingButtonRequired, backgroundChangeObserverRequired }; if (!additionalSites.some(item => item.pattern === pattern)) { additionalSites.push(entry); GM_setValue(STORAGE_KEY, additionalSites); mergedSites = [...new Set([...getDefaultList(), ...additionalSites])].map(item => { if (typeof item === 'string') { return { pattern: normalizeUrl(item), preProcessingRequired: false, postProcessingRequired: false, onDemandFloatingButtonRequired: false, backgroundChangeObserverRequired: false }; } return { ...item, pattern: normalizeUrl(item.pattern), onDemandFloatingButtonRequired: item.onDemandFloatingButtonRequired || false, backgroundChangeObserverRequired: item.backgroundChangeObserverRequired || false }; }); alert(`✅ Added site with pattern: ${pattern}`); } else { alert(`⚠️ Pattern "${pattern}" is already in the list.`); } } } function viewIncludedSites() { const siteList = additionalSites.map(item => { const status = formatStatus(item.preProcessingRequired, item.postProcessingRequired, item.onDemandFloatingButtonRequired, item.backgroundChangeObserverRequired); return `${item.pattern}${status ? ` (${status})` : ''}`; }).join("\n"); alert(`🔍 Included Sites:\n${siteList || "No sites added yet."}`); } function deleteEntries() { if (additionalSites.length === 0) return alert("⚠️ No user-defined entries to delete."); const userChoice = prompt("Select entries to delete (comma-separated numbers):\n" + additionalSites.map((item, index) => `${index + 1}. ${item.pattern}`).join("\n")); if (!userChoice) return; const indicesToRemove = userChoice.split(',').map(num => parseInt(num.trim(), 10) - 1); additionalSites = additionalSites.filter((_, index) => !indicesToRemove.includes(index)); GM_setValue(STORAGE_KEY, additionalSites); mergedSites = [...new Set([...getDefaultList(), ...additionalSites])].map(item => { if (typeof item === 'string') { return { pattern: normalizeUrl(item), preProcessingRequired: false, postProcessingRequired: false }; } return { ...item, pattern: normalizeUrl(item.pattern) }; }); alert("✅ Selected entries have been deleted."); } function editEntry() { if (additionalSites.length === 0) return alert("⚠️ No user-defined entries to edit."); const userChoice = prompt("Select an entry to edit:\n" + additionalSites.map((item, index) => { const status = formatStatus(item.preProcessingRequired, item.postProcessingRequired, item.onDemandFloatingButtonRequired, item.backgroundChangeObserverRequired); return `${index + 1}. ${item.pattern}${status ? ` (${status})` : ''}`; }).join("\n")); if (!userChoice) return; const selectedIndex = parseInt(userChoice, 10) - 1; if (selectedIndex < 0 || selectedIndex >= additionalSites.length) return alert("❌ Invalid selection."); const entry = additionalSites[selectedIndex]; const newPattern = normalizeUrl(prompt("Edit the pattern:", entry.pattern)); if (!newPattern || !newPattern.trim()) return; const preProcessingRequired = prompt("Is pre-processing required? (y/n)", entry.preProcessingRequired ? "y" : "n").toLowerCase() === 'y'; const postProcessingRequired = prompt("Is post-processing required? (y/n)", entry.postProcessingRequired ? "y" : "n").toLowerCase() === 'y'; const onDemandFloatingButtonRequired = prompt("Is on-demand floating button required? (y/n)", entry.onDemandFloatingButtonRequired ? "y" : "n").toLowerCase() === 'y'; const backgroundChangeObserverRequired = prompt("Is background change observer required? (y/n)", entry.backgroundChangeObserverRequired ? "y" : "n").toLowerCase() === 'y'; entry.pattern = newPattern.trim(); entry.preProcessingRequired = preProcessingRequired; entry.postProcessingRequired = postProcessingRequired; entry.onDemandFloatingButtonRequired = onDemandFloatingButtonRequired; entry.backgroundChangeObserverRequired = backgroundChangeObserverRequired; GM_setValue(STORAGE_KEY, additionalSites); mergedSites = [...new Set([...getDefaultList(), ...additionalSites])].map(item => { if (typeof item === 'string') { return { pattern: normalizeUrl(item), preProcessingRequired: false, postProcessingRequired: false, onDemandFloatingButtonRequired: false, backgroundChangeObserverRequired: false }; } return { ...item, pattern: normalizeUrl(item.pattern), onDemandFloatingButtonRequired: item.onDemandFloatingButtonRequired || false, backgroundChangeObserverRequired: item.backgroundChangeObserverRequired || false }; }); alert("✅ Entry updated."); } function clearAllEntries() { if (additionalSites.length === 0) return alert("⚠️ No user-defined entries to clear."); if (confirm(`🚨 You have ${additionalSites.length} entries. Clear all?`)) { additionalSites = []; GM_setValue(STORAGE_KEY, additionalSites); mergedSites = [...getDefaultList()].map(item => { if (typeof item === 'string') { return { pattern: normalizeUrl(item), preProcessingRequired: false, postProcessingRequired: false }; } return { ...item, pattern: normalizeUrl(item.pattern) }; }); alert("✅ All user-defined entries cleared."); } } // function exportAdditionalSites() { // GM_download("data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(additionalSites, null, 2)), "additionalSites_backup.json"); // alert("📤 Additional sites exported as JSON."); // } function exportAdditionalSites() { const data = JSON.stringify(additionalSites, null, 2); const blob = new Blob([data], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'additionalSites_backup.json'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); alert("📤 Additional sites exported as JSON."); } // function importAdditionalSites() { // const input = document.createElement("input"); // input.type = "file"; // input.accept = ".json"; // input.onchange = event => { // const reader = new FileReader(); // reader.onload = e => { // additionalSites = JSON.parse(e.target.result); // GM_setValue(STORAGE_KEY, additionalSites); // mergedSites = [...new Set([...getDefaultList(), ...additionalSites])].map(item => { // if (typeof item === 'string') { // return { pattern: normalizeUrl(item), preProcessingRequired: false, postProcessingRequired: false }; // } // return { ...item, pattern: normalizeUrl(item.pattern) }; // }); // alert("📥 Sites imported successfully."); // }; // reader.readAsText(event.target.files[0]); // }; // input.click(); // } function importAdditionalSites() { const input = document.createElement('input'); input.type = 'file'; input.accept = '.json'; input.style.display = 'none'; input.onchange = event => { const reader = new FileReader(); reader.onload = e => { try { const importedData = JSON.parse(e.target.result); if (Array.isArray(importedData)) { additionalSites = importedData.map(item => { if (typeof item === 'string') { return normalizeUrl(item); } else if (typeof item === 'object' && item.pattern) { return { ...item, pattern: normalizeUrl(item.pattern) }; } throw new Error('Invalid data format'); }); GM_setValue(STORAGE_KEY, additionalSites); mergedSites = [...new Set([...getDefaultList(), ...additionalSites])].map(item => { if (typeof item === 'string') { return normalizeUrl(item); } return { ...item, pattern: normalizeUrl(item.pattern) }; }); alert('📥 Sites imported successfully.'); } else { throw new Error('Invalid data format'); } } catch (error) { alert('❌ Failed to import sites: ' + error.message); } }; reader.readAsText(event.target.files[0]); }; document.body.appendChild(input); input.click(); document.body.removeChild(input); } function formatStatus(preProcessingRequired, postProcessingRequired, onDemandFloatingButtonRequired, backgroundChangeObserverRequired) { if (SHOW_STATUS_ONLY_IF_TRUE && !preProcessingRequired && !postProcessingRequired && !onDemandFloatingButtonRequired && !backgroundChangeObserverRequired) { return ''; } const preStatus = USE_EMOJI_FOR_STATUS ? (preProcessingRequired ? '✅' : '✖️') : (preProcessingRequired ? 'true' : 'false'); const postStatus = USE_EMOJI_FOR_STATUS ? (postProcessingRequired ? '✅' : '✖️') : (postProcessingRequired ? 'true' : 'false'); const floatingButtonStatus = USE_EMOJI_FOR_STATUS ? (onDemandFloatingButtonRequired ? '✅' : '✖️') : (onDemandFloatingButtonRequired ? 'true' : 'false'); const backgroundObserverStatus = USE_EMOJI_FOR_STATUS ? (backgroundChangeObserverRequired ? '✅' : '✖️') : (backgroundChangeObserverRequired ? 'true' : 'false'); return `Pre: ${preStatus}, Post: ${postStatus}, Floating Button: ${floatingButtonStatus}, Background Observer: ${backgroundObserverStatus}`; } window.shouldRunOnThisSite = shouldRunOnThisSite; window.isPreProcessingRequired = function() { const currentFullPath = normalizeUrl(`${window.top.location.href}`); const entry = mergedSites.find(item => wildcardToRegex(normalizeUrl(item.pattern)).test(currentFullPath)); return entry ? entry.preProcessingRequired : false; }; window.isPostProcessingRequired = function() { const currentFullPath = normalizeUrl(`${window.top.location.href}`); const entry = mergedSites.find(item => wildcardToRegex(normalizeUrl(item.pattern)).test(currentFullPath)); return entry ? entry.postProcessingRequired : false; }; // Expose isOnDemandFloatingButtonRequired window.isOnDemandFloatingButtonRequired = function() { const currentFullPath = normalizeUrl(`${window.top.location.href}`); const entry = mergedSites.find(item => wildcardToRegex(normalizeUrl(item.pattern)).test(currentFullPath)); return entry ? entry.onDemandFloatingButtonRequired : false; }; // Expose isBackgroundChangeObserverRequired window.isBackgroundChangeObserverRequired = function() { const currentFullPath = normalizeUrl(`${window.top.location.href}`); const entry = mergedSites.find(item => wildcardToRegex(normalizeUrl(item.pattern)).test(currentFullPath)); return entry ? entry.backgroundChangeObserverRequired : false; }; })(); })(); //To use this in another script use @require // // @run-at document-end // // ==/UserScript== // window.SCRIPT_STORAGE_KEY = "magnetLinkHashChecker"; // UNIQUE STORAGE KEY // window.GET_DEFAULT_LIST = function() { // return [ // { pattern: "*1337x.*", preProcessingRequired: false, postProcessingRequired: false, onDemandFloatingButtonRequired: false, backgroundChangeObserverRequired: false }, // { pattern: "*yts.*", preProcessingRequired: true, postProcessingRequired: true, onDemandFloatingButtonRequired: false, backgroundChangeObserverRequired: false }, // { pattern: "*torrentgalaxy.*", preProcessingRequired: false, postProcessingRequired: true, onDemandFloatingButtonRequired: false, backgroundChangeObserverRequired: false }, // { pattern: "*bitsearch.*", preProcessingRequired: false, postProcessingRequired: false, onDemandFloatingButtonRequired: false, backgroundChangeObserverRequired: false }, // { pattern: "*thepiratebay.*", preProcessingRequired: false, postProcessingRequired: false, onDemandFloatingButtonRequired: false, backgroundChangeObserverRequired: false }, // { pattern: "*ext.*", preProcessingRequired: false, postProcessingRequired: false, onDemandFloatingButtonRequired: false, backgroundChangeObserverRequired: false } // ]; // }; // (async function () { // 'use strict'; // // ✅ Wait until `shouldRunOnThisSite` is available // while (typeof shouldRunOnThisSite === 'undefined') { // await new Promise(resolve => setTimeout(resolve, 50)); // } // if (!(await shouldRunOnThisSite())) return; // //alert("running"); // console.log("Pre-Customization enabled for this site: " + isPreProcessingRequired() ); // console.log("Post-Customization enabled for this site: " + isPostProcessingRequired() ); // const OFFCLOUD_CACHE_API_URL = 'https://offcloud.com/api/cache';