您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
IPFS gateway switcher for ofans.party.
当前为
// ==UserScript== // @name OFans.party IPFS Gateway Switcher // @namespace Violentmonkey Scripts // @description IPFS gateway switcher for ofans.party. // @match https://ofans.party/* // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @run-at document-start // @version 0.4 // @author sudorain // @noframes // ==/UserScript== // A (somewhat working) polyfill for beforescriptexecute event // https://github.com/jspenguin2017/Snippets/blob/master/onbeforescriptexecute.html (() => { "use strict"; const Event = class { constructor(script, target) { this.script = script; this.target = target; this._cancel = false; this._replace = null; this._stop = false; } preventDefault() { this._cancel = true; } stopPropagation() { this._stop = true; } replacePayload(payload) { this._replace = payload; } }; let callbacks = []; window.addBeforeScriptExecuteListener = (f) => { if (typeof f !== "function") { throw new Error("Event handler must be a function."); } callbacks.push(f); }; window.removeBeforeScriptExecuteListener = (f) => { let i = callbacks.length; while (i--) { if (callbacks[i] === f) { callbacks.splice(i, 1); } } }; const dispatch = (script, target) => { if (script.tagName !== "SCRIPT") { return; } const e = new Event(script, target); if (typeof window.onbeforescriptexecute === "function") { try { window.onbeforescriptexecute(e); } catch (err) { console.error(err); } } for (const func of callbacks) { if (e._stop) { break; } try { func(e); } catch (err) { console.error(err); } } if (e._cancel) { script.textContent = ""; script.remove(); } else if (typeof e._replace === "string") { script.textContent = e._replace; } }; const observer = new MutationObserver((mutations) => { for (const m of mutations) { for (const n of m.addedNodes) { dispatch(n, m.target); } } }); observer.observe(document, { childList: true, subtree: true, }); })(); (async () => { "use strict"; var loaded, regex_main_js, gateways_json, public_gateways, current_gateway, gallery_mode; loaded = false; regex_main_js = new RegExp(/main\.[a-z0-9]+\.chunk\.js/); // A site displaying public IPFS gateways and their online/offline status. // https://ipfs.github.io/public-gateway-checker/ gateways_json = "https://ipfs.github.io/public-gateway-checker/gateways.json"; public_gateways = await GM_getValue("public_gateways"); current_gateway = await GM_getValue("current_gateway"); gallery_mode = await GM_getValue("gallery_mode"); await GM_xmlhttpRequest({ method: "GET", url: gateways_json, onload: function (response) { public_gateways = response.responseText.replace(/:hash/g, ""); GM_setValue("public_gateways", public_gateways) } }); window.onbeforescriptexecute = (e) => { const script = e.script.outerHTML; if (regex_main_js.test(script) && !loaded && current_gateway) { const source = e.script.attributes.src.value; e.preventDefault(); e.stopPropagation(); GM_xmlhttpRequest({ method: "GET", url: source, onload: function (response) { loaded = !loaded let text = response.responseText.replace(/ipfsHost:"(.*?)"/g, `ipfsHost:"${current_gateway}"`); let newScript = createElement('script', text, { type: "text/javascript", id: "main" }); document.head.append(newScript); } }); } } document.addEventListener('DOMContentLoaded', function () { let css = ` .custom-scrollbar::-webkit-scrollbar { width: 5px; } .custom-scrollbar::-webkit-scrollbar-track { background: #dee2e6; } .custom-scrollbar::-webkit-scrollbar-thumb { background: #888; } .custom-scrollbar::-webkit-scrollbar-thumb:hover { background: #555; } `; let style = createElement('style', css); document.head.append(style); const gateways = JSON.parse(public_gateways) let wrapper = createElement('div', false, { class: "position-absolute fixed-bottom float-left text-monospace mb-3 ml-3", style: "width: fit-content;" }); let dropdown_group = createElement('div', false, { id: "switch", class: "btn-group dropup" }); let button = createElement('button', "Gateways ", { class: "btn btn-dark dropdown-toggle", "data-toggle": "dropdown", "aria-haspopup": "true", "aria-expanded": "false" }); let badge = createElement('span', gateways.length, { class: "badge badge-light" }); button.append(badge) dropdown_group.append(button) let dropdown_menu = createElement('div', false, { class: "dropdown-menu overflow-auto custom-scrollbar shadow-lg px-0 pt-0 pb-2 mb-3", style: "max-height: 388px" }); for (const [index, url] of gateways.entries()) { let current = current_gateway == url; let fancy_url = url.match(/(^https?:\/\/)(.*)/); let url_protocol = createElement('small', fancy_url[1], { class: `${current ? ' ' : ' text-black-50'}` }); let menu_item = createElement('button', fancy_url[2], { "data-value": url, class: `dropdown-item border-bottom button-switch ${current ? ' active' : ' text-dark'}`, type: "button" }); menu_item.prepend(url_protocol) if (current) { dropdown_menu.prepend(menu_item) } else { dropdown_menu.append(menu_item) } } let dafault_gateway = createElement('button', 'Default', { "data-value": '', class: `dropdown-item border-bottom border-top button-switch ${!current_gateway ? ' active' : ''}`, type: "button" }); dropdown_menu.prepend(dafault_gateway) let menu_header = createElement('h6', "Gateway Switcher", { class: "bg-light text-dark shadow-sm sticky-top dropdown-header border-bottom py-3 mb-2" }); let menu_checker = createElement('a', "Public Gateway Checker ", { class: "float-right text-success", href: "https://ipfs.github.io/public-gateway-checker/", target: "_blank" }); menu_header.append(menu_checker) dropdown_menu.prepend(menu_header) dropdown_group.append(dropdown_menu) wrapper.append(dropdown_group) document.body.append(wrapper) }); document.addEventListener("click", switchGateway); function switchGateway(e) { const class_list = e.target.classList; const data_set = e.target.dataset; if (class_list.contains('button-switch')) { const value = data_set.value; if (value) { GM_setValue("current_gateway", value) } else { GM_deleteValue("current_gateway") } location.reload(); } } function createElement(el, text, attrs) { let element = document.createElement(el); if (text) element.textContent = text; if (attrs) Object.keys(attrs).forEach(key => element.setAttribute(key, attrs[key])); return element; } })();