OFans.party IPFS Gateway Switcher

IPFS gateway switcher for ofans.party.

От 27.04.2021. Виж последната версия.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

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

})();