修复copymanga图片错误

处理图片资源加载失败时自动重新加载

当前为 2022-08-15 提交的版本,查看 最新版本

// ==UserScript==
// @name         修复copymanga图片错误
// @namespace    https://github.com/IronKinoko/userscripts/tree/master/packages/copymanga
// @version      1.2.3
// @license      MIT
// @description  处理图片资源加载失败时自动重新加载
// @author       IronKinoko
// @match        https://www.copymanga.org/*
// @match        https://www.copymanga.site/*
// @icon         https://www.google.com/s2/favicons?domain=www.copymanga.org
// @grant        none
// @noframes
// ==/UserScript==
(function () {
  'use strict';

  function s2d(string) {
    return new DOMParser().parseFromString(string, "text/html").body.firstChild;
  }
  function addErrorListener(img) {
    if (img.dataset.errorFix === "true")
      return;
    img.dataset.errorFix = "true";
    img.onerror = () => {
      const url = new URL(img.src);
      let v = parseInt(url.searchParams.get("v")) || 0;
      if (v > 5)
        return img.onerror = null;
      url.searchParams.set("v", ++v + "");
      img.src = url.toString();
      img.alt = "\u56FE\u7247\u52A0\u8F7D\u51FA\u9519";
    };
  }

  function sleep(time) {
    return new Promise((resolve) => {
      setTimeout(resolve, time);
    });
  }

  async function waitDOM(selector) {
    return new Promise((resolve, reject) => {
      const now = Date.now();
      function getDOM() {
        if (Date.now() - now > 5e3)
          reject();
        const dom = document.querySelector(selector);
        if (dom) {
          resolve(dom);
        } else {
          requestAnimationFrame(getDOM);
        }
      }
      getDOM();
    });
  }

  async function openControl() {
    const li = await waitDOM("li.comicContentPopupImageItem");
    li.dispatchEvent(fakeClickEvent());
    await sleep(0);
    li.dispatchEvent(fakeClickEvent());
  }
  function fakeClickEvent() {
    const { width, height } = document.body.getBoundingClientRect();
    return new MouseEvent("click", { clientX: width / 2, clientY: height / 2 });
  }
  async function currentPage() {
    try {
      if (!/h5\/comicContent\/.*/.test(location.href))
        return;
      const scrollHeight = document.scrollingElement.scrollTop;
      const list = await waitHasComicContent();
      let height = 0;
      for (let i = 0; i < list.length; i++) {
        const item = list[i];
        height += item.getBoundingClientRect().height;
        if (height > scrollHeight) {
          const dom = document.querySelector(".comicContentPopup .comicFixed");
          dom.textContent = dom.textContent.replace(/(.*)\//, `${i + 1}/`);
          break;
        }
      }
    } catch (e) {
    }
  }
  let trackId = { current: 0 };
  async function runH5main() {
    try {
      if (!/h5\/comicContent\/.*/.test(location.href))
        return;
      let runTrackId = ++trackId.current;
      const ulDom = await waitDOM(".comicContentPopupImageList");
      if (runTrackId !== trackId.current)
        return;
      const uuid = getComicId();
      const domUUID = ulDom.dataset.uuid;
      if (domUUID !== uuid) {
        ulDom.dataset.uuid = uuid;
      }
      injectFixImg$1();
      injectFastLoadImg$1();
      const main = ulDom.parentElement;
      main.style.position = "unset";
      main.style.overflowY = "unset";
      createNextPartDom();
    } catch (error) {
      throw error;
    }
  }
  let ob;
  async function createNextPartDom() {
    let nextPartDom = document.querySelector("#comicContentMain .next-part-btn");
    let nextButton = document.querySelector(".comicControlBottomTop > div:nth-child(3) > span");
    if (!nextPartDom) {
      if (!nextButton) {
        await openControl();
        nextButton = document.querySelector(".comicControlBottomTop > div:nth-child(3) > span");
      }
      nextPartDom = document.createElement("div");
      nextPartDom.className = "next-part-btn";
      nextPartDom.textContent = "\u4E0B\u4E00\u8BDD";
      nextPartDom.onclick = async (e) => {
        e.stopPropagation();
        nextButton && nextButton.click();
        document.scrollingElement.scrollTop = 0;
      };
      document.getElementById("comicContentMain").appendChild(nextPartDom);
    }
    nextPartDom.style.display = nextButton.parentElement.classList.contains("noneUuid") ? "none" : "block";
    let fixedNextBtn = document.querySelector(".next-part-btn-fixed");
    if (!fixedNextBtn) {
      fixedNextBtn = document.createElement("div");
      fixedNextBtn.className = "next-part-btn-fixed";
      fixedNextBtn.textContent = "\u4E0B\u4E00\u8BDD";
      fixedNextBtn.onclick = nextPartDom.onclick;
      document.body.appendChild(fixedNextBtn);
      ob = new IntersectionObserver((e) => {
        console.log(e);
        if (e[0].isIntersecting)
          fixedNextBtn == null ? void 0 : fixedNextBtn.classList.remove("hide");
        else
          fixedNextBtn == null ? void 0 : fixedNextBtn.classList.add("hide");
      }, { threshold: [0, 1], rootMargin: "0px 0px 1000px 0px" });
    }
    ob.observe(nextPartDom);
    fixedNextBtn.style.display = nextPartDom.style.display;
  }
  function getComicId() {
    const [, uuid] = location.href.match(/h5\/comicContent\/.*\/(.*)/);
    return uuid;
  }
  async function waitHasComicContent() {
    return document.querySelectorAll(".comicContentPopupImageItem");
  }
  async function addH5HistoryListener() {
    history.pushState = _historyWrap("pushState");
    history.replaceState = _historyWrap("replaceState");
    window.addEventListener("pushState", runH5main);
    window.addEventListener("replaceState", runH5main);
    window.addEventListener("popstate", runH5main);
    window.addEventListener("scroll", currentPage);
    runH5main();
  }
  const _historyWrap = function(type) {
    const orig = history[type];
    const e = new Event(type);
    return function() {
      const rv = orig.apply(this, arguments);
      window.dispatchEvent(e);
      return rv;
    };
  };
  async function injectFixImg$1() {
    const listDOM = await waitDOM(".comicContentPopupImageList");
    async function injectEvent() {
      const imgs = document.querySelectorAll("ul li img");
      imgs.forEach(addErrorListener);
    }
    const ob2 = new MutationObserver(injectEvent);
    ob2.observe(listDOM, { childList: true, subtree: true });
    injectEvent();
  }
  async function injectFastLoadImg$1() {
    const $list = await waitDOM(".comicContentPopupImageList");
    function fastLoad() {
      const $imgs = document.querySelectorAll("ul li img");
      $imgs.forEach(($img) => {
        if ($img.dataset.fastLoad === $img.dataset.src)
          return;
        $img.dataset.fastLoad = $img.dataset.src;
        $img.src = $img.dataset.src;
      });
    }
    const ob2 = new MutationObserver(fastLoad);
    ob2.observe($list, {
      childList: true,
      subtree: true,
      attributes: true,
      attributeFilter: ["data-src"]
    });
  }
  function h5() {
    addH5HistoryListener();
  }

  function replaceHeader() {
    const header = document.querySelector(".container.header-log .row");
    if (header) {
      header.style.flexWrap = "nowrap";
      header.querySelector("div:nth-child(6)").replaceWith(s2d(`<div class="col-1">
          <div class="log-txt">
            <a href="/web/person/shujia">\u6211\u7684\u4E66\u67B6</a>
            <div class="log-unboder"></div>
          </div>
        </div>`));
      header.querySelector("div:nth-child(7)").replaceWith(s2d(`<div class="col-1">
          <div class="log-txt">
            <a href="/web/person/liulan">\u6211\u7684\u6D4F\u89C8</a>
            <div class="log-unboder"></div>
          </div>
        </div>`));
      header.querySelector("div:nth-child(8)").className = "col";
      header.querySelector("div.col > div > div").style.justifyContent = "flex-end";
    }
  }
  async function injectFixImg() {
    const listDOM = await waitDOM("ul.comicContent-list");
    async function injectEvent() {
      const imgs = document.querySelectorAll("ul li img");
      imgs.forEach(addErrorListener);
    }
    const ob = new MutationObserver(injectEvent);
    ob.observe(listDOM, { childList: true, subtree: true });
    injectEvent();
  }
  async function injectFastLoadImg() {
    const $list = await waitDOM(".comicContent-list");
    function fastLoad() {
      const $imgs = $list.querySelectorAll("li img");
      $imgs.forEach(($img) => {
        if ($img.dataset.fastLoad === "true")
          return;
        $img.dataset.fastLoad = "true";
        $img.src = $img.dataset.src;
      });
    }
    const ob = new MutationObserver(fastLoad);
    ob.observe($list, { childList: true, subtree: true });
  }
  function pc() {
    if (/comic\/.*\/chapter/.test(location.href)) {
      injectFixImg();
      injectFastLoadImg();
    }
    replaceHeader();
  }

  var e=[],t=[];function n(n,r){if(n&&"undefined"!=typeof document){var a,s=!0===r.prepend?"prepend":"append",d=!0===r.singleTag,i="string"==typeof r.container?document.querySelector(r.container):document.getElementsByTagName("head")[0];if(d){var u=e.indexOf(i);-1===u&&(u=e.push(i)-1,t[u]={}),a=t[u]&&t[u][s]?t[u][s]:t[u][s]=c();}else a=c();65279===n.charCodeAt(0)&&(n=n.substring(1)),a.styleSheet?a.styleSheet.cssText+=n:a.appendChild(document.createTextNode(n));}function c(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),r.attributes)for(var t=Object.keys(r.attributes),n=0;n<t.length;n++)e.setAttribute(t[n],r.attributes[t[n]]);var a="prepend"===s?"afterbegin":"beforeend";return i.insertAdjacentElement(a,e),e}}

  var css = ".k-copymanga .next-part-btn {\n  height: 150px;\n  line-height: 50px;\n  text-align: center;\n  font-size: 16px;\n}\n.k-copymanga .next-part-btn-fixed {\n  position: fixed;\n  right: 0;\n  top: 25vh;\n  font-size: 16px;\n  background: white;\n  padding: 8px;\n  writing-mode: vertical-lr;\n  box-shadow: rgba(0, 0, 0, 0.2) -1px 1px 10px 0px;\n  transition: all 0.2s ease;\n  transform: translateX(0);\n  border-radius: 4px 0 0 4px;\n  opacity: 1;\n}\n.k-copymanga .next-part-btn-fixed.hide {\n  opacity: 0;\n  pointer-events: none;\n  transform: translateX(100%);\n}";
  n(css,{});

  document.body.classList.add("k-copymanga");
  if (location.pathname.startsWith("/h5")) {
    h5();
  } else {
    pc();
  }

})();