OFans.party IPFS Gateway Switcher

IPFS gateway switcher for ofans.party.

Versão de: 30/04/2021. Veja: a última versão.

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

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

})();