您需要先安装一个扩展,例如 篡改猴、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 // @grant unsafeWindow // @run-at document-start // @version 0.9 // @author sudorain // @noframes // ==/UserScript== // A (somewhat working) polyfill for beforescriptexecute event // https://github.com/jspenguin2017/Snippets/blob/master/onbeforescriptexecute.html (() => { 'use strict'; if (navigator.userAgent.indexOf("Chrome") !== -1) { 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, regex_ipfs, ipfs_replace, gateways_json, public_gateways, current_gateway, gallery_mode, posts_find, posts_replace; // 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') || false; loaded = false; regex_main_js = new RegExp(/main\.[a-z0-9]+\.chunk\.js/); regex_ipfs = new RegExp(/ipfsHost:"(.*?)"/g); ipfs_replace = `ipfsHost:"${current_gateway}"` posts_find = `Object(a.jsxs)("div",{className:"container",children:[o,this.state.posts&&this.state.posts.map((function(t,s){return r++,Object(a.jsxs)("div",{className:"row post",of_id:t.post_id,children:[r%15==0&&e.renderAd(),Object(a.jsxs)("div",{className:"col-lg-6 postText",children:[e.renderPostDate(t),Object(a.jsx)("br",{}),e.renderPostText(t)]}),Object(a.jsx)("div",{className:"col-lg-6",style:{textAlign:"center"},children:t.media&&t.media.map((function(t,s){return t.ipfs_media_hash?Object(a.jsx)("a",{href:e.state.ipfsHost+t.ipfs_media_hash,children:Object(a.jsx)("img",{src:e.state.ipfsHost+t.ipfs_thumb_hash,loading:"lazy",className:"mediaThumb"})},t.id.toString()):Object(a.jsx)("div",{style:{backgroundColor:"grey",height:"144px",width:"144px",margin:"0.5em",position:"relative"},title:"Importing...",children:Object(a.jsxs)("span",{style:{color:"white",fontSize:"2em",fontWeight:"bold",position:"absolute",top:"50%",left:"50%",margin:"-25px 0 0 -25px",height:"50px",width:"50px"},children:[" ",Object(a.jsx)(c.a,{icon:["fa","download"]})," "]})})}))})]},t.id.toString())}))]})` posts_replace = `Object(a.jsxs)("div",{className:"container",children:[o,Object(a.jsxs)("div",{className:"row row-cols-5 align-items-stretch no-gutters",children:[this.state.posts&&this.state.posts.map((function(t,s){return r++,t.media&&t.media.map((function(t,s){return t.ipfs_media_hash?Object(a.jsx)("div",{className:"col d-flex",children:Object(a.jsx)("div",{className:"d-flex justify-content-center align-items-center w-100 m-1 bg-light",style:{"min-height": "150px"},children:[Object(a.jsx)("span",{className:"position-absolute text-white fa fa-3x fa-fw fa-"+(t.type=="video"?"play-circle":t.type+" d-none"),style:{"text-shadow": "0 0 24px rgb(0 0 0 / 50%)"}}),Object(a.jsx)("a",{href:e.state.ipfsHost+t.ipfs_media_hash,target:"_blank",children:Object(a.jsx)("img",{src:e.state.ipfsHost+t.ipfs_thumb_hash,loading:"lazy",className:"img-fluid"})},t.id.toString())]})}):Object(a.jsx)("div",{className:"col d-flex",children:Object(a.jsx)("div",{className:"d-flex justify-content-center align-items-center w-100 m-1 bg-secondary",style:{"min-height": "150px"},title:"Importing...",children:Object(a.jsx)("span",{className:"text-white fa fa-3x fa-fw fa-download",style:{"text-shadow": "0 0 24px rgb(0 0 0 / 50%)"}})})})}))}))]})]})` await GM_xmlhttpRequest({ method: 'GET', url: gateways_json, onload: function (response) { public_gateways = response.responseText.replace(/:hash/g, ''); GM_setValue('public_gateways', public_gateways) } }); if (navigator.userAgent.indexOf("Chrome") !== -1) { window.onbeforescriptexecute = (e) => { const script = e.script.outerHTML; if (regex_main_js.test(script) && !loaded && (current_gateway || gallery_mode)) { const source = e.script.attributes.src.value; e.preventDefault() e.stopPropagation() modifyScript(source) } } } else if (navigator.userAgent.indexOf("Firefox") !== -1) { window.addEventListener('beforescriptexecute', function (e) { const source = e.target.src; if (regex_main_js.test(source) && !loaded && (current_gateway || gallery_mode)) { e.preventDefault() e.stopPropagation() modifyScript(source) } }) } 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); let gateways = JSON.parse(public_gateways) gateways.sort(function (gateway) { if (gateway === current_gateway) return -1; }); let party = createElement('div', { class: 'position-fixed fixed-bottom float-left text-monospace mb-3 ml-3', style: 'width: fit-content;width: -moz-fit-content;' }, createElement('div', { id: 'switch', class: 'btn-group dropup' }, createElement('button', { class: 'btn btn-dark dropdown-toggle', 'data-toggle': 'dropdown', 'aria-haspopup': 'true', 'aria-expanded': 'false', reference: 'parent' }, 'Gateways', createElement('span', { class: 'badge badge-light ml-2' }, gateways.length ) ), createElement('div', { class: 'dropdown-menu overflow-auto custom-scrollbar shadow-lg px-0 pt-0 pb-2 mb-3', style: 'max-height: 388px' }, createElement('h6', { class: 'bg-light text-dark shadow-sm sticky-top dropdown-header border-bottom py-3 mb-2' }, 'Gateway Switcher', createElement('a', { class: 'float-right text-success', href: 'https://ipfs.github.io/public-gateway-checker/', target: '_blank' }, 'Public Gateway Checker' ) ), createElement('button', { 'data-value': '', class: `dropdown-item border-bottom button-switch ${!current_gateway ? ' active' : ' text-dark'}`, type: 'button' }, 'Default' ), ...gateways.map((gateway, index) => { let current = current_gateway == gateway; let url = gateway.match(/(?<protocol>.*?:\/\/)(?<origin>.*)/); return createElement('button', { 'data-value': gateway, class: `dropdown-item border-bottom button-switch ${current ? ' active' : ' text-dark'}`, type: 'button' }, createElement('small', { class: `${current ? ' ' : ' text-black-50'}` }, url.groups.protocol ), url.groups.origin ) }) ) ), createElement('button', { class: `btn button-gallery ml-2 ${gallery_mode ? ' btn-info' : ' btn-dark'}` }, 'Gallery Mode', createElement('span', { class: 'badge badge-light ml-2' }, `${gallery_mode ? 'On' : 'Off'}` ) ) ); document.body.append(party) }); 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() } else if (class_list.contains('button-gallery')) { GM_setValue('gallery_mode', !gallery_mode) location.reload() } } function modifyScript(source) { GM_xmlhttpRequest({ method: 'GET', url: source, onload: async function (response) { loaded = !loaded var text = response.responseText text = text.replace(regex_ipfs, ipfs_replace) if (current_gateway) { text = text.replace(regex_ipfs, ipfs_replace) } if (gallery_mode) { text = text.replace(posts_find, posts_replace); } let newScript = createElement('script', { type: 'text/javascript', id: 'main' }, text); document.head.append(newScript); } }) } function createElement(type, attributes, ...children) { let element = document.createElement(type) Object.keys(attributes).forEach(key => element.setAttribute(key, attributes[key])) children.forEach(child => { if (typeof child === 'string' || typeof child === 'number') { element.appendChild(document.createTextNode(child)) } else { element.appendChild(child) } }) return element } })();