OFans.party IPFS Gateway Switcher

IPFS gateway switcher for ofans.party.

Versione datata 30/04/2021. Vedi la nuova versione l'ultima versione.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==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.6
// @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, regex_creator, api_posts, gateways_json, public_gateways, current_gateway, gallery_mode, creator, posts_find, posts_replace;

  loaded = false;
  regex_main_js = new RegExp(/main\.[a-z0-9]+\.chunk\.js/);
  regex_creator = new RegExp(/^https:\/\/ofans.party\/#\/creator\//);

  // 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";
  api_posts = "https://api.ofans.party/posts/";
  public_gateways = await GM_getValue("public_gateways");
  current_gateway = await GM_getValue("current_gateway");
  gallery_mode = await GM_getValue("gallery_mode") || false;

  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-center no-gutters bg-light",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",children:Object(a.jsx)("div",{className:"d-flex justify-content-center m-1",children: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",children:Object(a.jsx)("div",{className:"d-flex justify-content-center m-1",style:{backgroundColor:"grey",height:"150px",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"]})," "]})})})}))}))]})]})`

  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 || gallery_mode)) {
      const source = e.script.attributes.src.value;
      e.preventDefault();
      e.stopPropagation();
      GM_xmlhttpRequest({
        method: "GET",
        url: source,
        onload: async function (response) {
          loaded = !loaded

          var text = response.responseText
          if (current_gateway) {
            text = text.replace(/ipfsHost:"(.*?)"/g, `ipfsHost:"${current_gateway}"`)
          }
          if (gallery_mode) {
            text = text.replace(posts_find, posts_replace);
          }
          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-fixed 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 ml-1" });
    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)
    let button_gallery = createElement('button', `Gallery Mode`, { class: `btn button-gallery ml-2 ${gallery_mode ? ' btn-info' : ' btn-dark'}` });
    let gallery_status = createElement('span', `${gallery_mode ? 'On' : 'Off'}`, { class: "badge badge-light ml-1" });
    button_gallery.append(gallery_status)
    wrapper.append(button_gallery)
    document.body.append(wrapper)

    console.log(creator)

  });

  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();
    }
  }

  /*
  async function createGallery() {
    const loc = window.location.href
    if (regex_creator.test(loc)) {
      const id = loc.substring(loc.lastIndexOf('/') + 1)
      await GM_xmlhttpRequest({
        method: "GET",
        url: api_posts + id,
        onload: function (response) {
          let json = JSON.parse(response.responseText)
          creator = json.response
          let app = document.querySelectorAll('#root')[0];
          let container = document.querySelectorAll('.container')[0];
          let posts_container = createElement('div', false, { class: 'container' });
          let posts_row = createElement('div', false, { class: 'row row-cols-5 align-items-center no-gutters bg-light' });
          for (const [index, post] of creator.posts.entries()) {
            for (const media of post.media) {
              if (media.ipfs_media_hash) {
                let col = createElement('div', false, { class: 'col' });
                let item = createElement('div', false, { class: 'd-flex justify-content-center m-1' });
                let link = createElement('a', false, { href: current_gateway + media.ipfs_media_hash });
                let image = createElement('img', false, { src: current_gateway + media.ipfs_thumb_hash, loading: "lazy", class: 'img-fluid' });
                link.append(image)
                item.append(link)
                col.append(item)
                posts_row.append(col)
              }
            }
          }
          posts_container.append(posts_row)
          container.innerHTML = posts_row.outerHTML
          gallery_mode = true
        }
      });
    }
  }
  */

  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;
  }

})();