Greasy Fork

Greasy Fork is available in English.

包子漫画阅读辅助

包子漫画阅读辅助,瀑布流阅读连续载入图片,在新分页打开漫画链接(自用)。

当前为 2023-03-04 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         包子漫畫閱讀輔助
// @name:zh-CN   包子漫画阅读辅助
// @version      1.3
// @description  包子漫畫閱讀輔助,瀑布流閱讀連續載入圖片,在新分頁打開漫畫鏈接(自用)。
// @description:zh-CN  包子漫画阅读辅助,瀑布流阅读连续载入图片,在新分页打开漫画链接(自用)。
// @author       tony0809
// @match        *://cn.baozimh.com/*
// @match        *://cn.webmota.com/*
// @match        *://tw.baozimh.com/*
// @match        *://tw.webmota.com/*
// @match        *://www.baozimh.com/*
// @match        *://www.webmota.com/*
// @match        *://cn.kukuc.co/*
// @match        *://tw.kukuc.co/*
// @match        *://www.kukuc.co/*
// @icon         https://www.baozimh.com/favicon.ico
// @grant        none
// @run-at       document-end
// @license GPL
// @namespace http://greasyfork.icu/users/20361
// ==/UserScript==

(() => {
    'use strict';
    const options = { //true 開啟,false 關閉
        oint: true, //在新分頁打開漫畫鏈接。
        aH: true, //載入下一話時添加瀏覽器歷史紀錄
        aO: true, //目錄頁自動展開全部章節。
        remove: [true, 2] //!!!不能小於2!!!閱讀載入超過n話時刪除前面話數的圖片。
    },
          ge = e => document.querySelector(e),
          gae = e => document.querySelectorAll(e),
          lp = location.pathname,
          classify = /^\/classify/.test(lp),
          list = /^\/list\/new/.test(lp),
          search = /^\/search\?/.test(lp),
          comic = /^\/comic\/[^.]+$/.test(lp),
          read = /^\/comic\/chapter\/[^.]+\.html$/.test(lp),
          addGlobalStyle = css => {
              let style = document.createElement('style');
              style.type = 'text/css';
              style.innerHTML = css;
              document.head.appendChild(style);
          },
          readCss = `
.goback {
    background: #fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAAXNSR0IArs4c6QAAAgpJREFUSEvtlD2IE0EYht9vJBeRQxIU5AoPCwsFGwsRrAQRzztRRFeEa6LsfiyBgJ2FrYWdSDjITH4uhYK4Ih74g4qFjSAWFoJYWCgKIigbVCSYzYxsGCXJ5ZLlDq6QTDPs9/M+H+/MDmGdFq0TB2PQqp0eW0fMfAUAKaUuAjBJvUxsneM4G7LZbBnAOSu+GIahFwRBOwksESiXy21MpVI3iehEt6gxZqnVap2t1+vNUbCRoEKhsLnZbC4R0UEr9tvuE3Z/lk6njxeLxe/DYENBrutuE0I8BLDXivwEcIqIjDHmDoBJG3+ltT5aqVS+rARbEeT7/g6t9RMAO23zNwBzSqkX8Tcz7wdwH8AWm38nhDhcKpXeD4INBPm+v0dr/RjAlG36SEQzUso33SKu6+4WQjwCsN3GPwM4opR63Q9bBvI87wAR3QOQtcVv2+32TLVa/TBoUmaeBhDDdtl8aIw5Vi6Xn3fX94CYeQ7ALQCbbNFLALNKqa/DDpqZtwJ4AGCfrfsF4IxSKra2s/6BPM+bJ6JFACmbexpF0clarfZj1NWN8/l8fjKKorsADtn6FhGdl1Je7wEx81UAF+KgMeZ2o9GYD4Lg71VOwoLjOBOZTOYGEZ3uiBNdk1J2NPutuwRgOgzDfNI/vn8C+4IsENEnKeXlZdYlGnkNRSNfhjVo97SOQat28v+z7g/utJ8bMvScRQAAAABJRU5ErkJggg==) no-repeat;
    background-position:center;
    opacity: 0.7;
    border-radius: 50%;
    position: fixed;
    z-index:999;
    bottom: 7px;
    left: 50%;
    margin-left: -16px;
    width: 36px;
    height: 36px;
}
.mobadsq {
    display: none !important
}
ul {
    margin-block-start: -2px !important;
    margin-block-end: 2px !important
}
.chapterLoading {
    font-size: 20px;
    height: 30px;
    line-height: 32px;
    text-align: center;
}
.chapterTitle {
    width: auto;
    height: 30px;
    font-size: 20px;
    font-family: Arial,sans-serif!important;
    line-height: 32px;
    text-align: center;
    margin: 10px 5px;
    border: 1px solid #e0e0e0;
    background-color: #f0f0f0;
    background: -webkit-gradient(linear, 0 0, 0 100%, from(#f9f9f9), to(#f0f0f0));
    background: -moz-linear-gradient(top, #f9f9f9, #f0f0f0);
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.6);
    border-radius: 5px;
}
    `,
          openInNewTab = () => gae('.comics-card a:not([target=_blank]),.bookshelf-items a:not(.remove-img):not([target=_blank])').forEach(a => {
              a.setAttribute('target', '_blank');
          }),
          addGoBack = () => {
              let goback = document.createElement('div');
              goback.className = 'goback';
              goback.setAttribute('title', '返回頂部');
              goback.addEventListener('click', () => {
                  window.scrollTo({
                      top: 0,
                      behavior: "smooth"
                  });
              });
              document.body.appendChild(goback);
          },
          removeAd = () => {
              let loop = setInterval(() => {
                  let ad = ge('#interstitial_fade');
                  if (ad) {
                      clearInterval(loop);
                      ad.remove();
                  }
              }, 100);
              setTimeout(() => {
                  if (loop) clearInterval(loop);
              }, 1e4);
              gae('.mobadsq').forEach(e => {
                  e.remove();
              });
          },
          addHistory = (title, url) => {
              history.pushState(null, title, url);
              document.title = title;
          },
          addLoad = () => {
              let cl = document.createElement('div');
              cl.className = 'chapterLoading';
              let li = new Image();
              li.className = 'loadingImg';
              li.src = '/_nuxt/img/loading.12fdcc4.gif';
              li.style.width = '50px';
              cl.appendChild(li);
              let lt = document.createElement('div');
              lt.className = 'loadingText';
              lt.innerText = 'Loading...';
              cl.appendChild(lt);
              ge('.comic-contain').appendChild(cl);
          },
          removeLoad = () => {
              ge('.chapterLoading').remove();
          },
          addTitle = title => {
              let t = document.createElement('div');
              t.className = 'chapterTitle';
              t.innerText = title;
              let load = ge('.chapterLoading');
              load.parentNode.insertBefore(t, load);
          },
          parseHTML = str => {
              let doc;
              try {
                  doc = new DOMParser().parseFromString(str, 'text/html');
              } catch (e) {}
              if (!doc) {
                  doc = document.implementation.createHTMLDocument('');
                  doc.documentElement.innerHTML = str;
              }
              return doc;
          },
          fetchData = url => {
              fetch(url).then(res => res.text()).then(res => {
                  let doc = parseHTML(res);
                  insertData(doc, url);
                  setTimeout(() => {
                      addNextObserver();
                  }, 1200);
              }).catch(() => {
                  ge('.loadingImg').style.display = 'none';
                  ge('.loadingText').innerText = '連線出錯請返回頂部重新載入';
              });
          },
          /*fetchData = url => {
              let xhr = new XMLHttpRequest();
              xhr.responseType = 'text';
              xhr.open('GET', url);
              xhr.timeout = 10000;
              xhr.onload = () => {
                  if (xhr.status == 200) {
                      let doc = parseHTML(xhr.responseText),
                          title = doc.title;
                      if (options.aH) {
                          addHistory(title, url);
                      }
                      insertData(doc, url);
                      setTimeout(() => {
                          addNextObserver();
                      }, 1200);
                  } else if (xhr.status > 400) {
                      ge('.chapterLoading').innerText = 'HTTP連線狀態碼:' + xhr.status + ',獲取過程中出錯。';
                  }
              };
              xhr.onerror = (e) => {
                  ge('.chapterLoading').innerText = '連線出錯,請重新載入。';
              }
              xhr.ontimeout = (e) => {
                  ge('.chapterLoading').innerText = '連線逾時,請重新載入。';
              };
              xhr.send();
          },*/
          insertData = (d, url) => {
              let F = new DocumentFragment(),
                  imgs = d.querySelectorAll('.comic-contain amp-img');
              imgs.forEach(e => {
                  let img = new Image();
                  img.className = 'comic-contain__item';
                  img.src = e.getAttribute('src');
                  F.appendChild(img);
              });
              let load = ge('.chapterLoading');
              if (load) {
                  const rge = e => d.querySelector(e);
                  let title = rge('span.title').innerText;
                  if (!/\/\d+_\d+_\d+\.html$/.test(url)) {//是下一話才添加標題分隔條,下一頁則不添加。
                      let docTitle = d.title;
                      if (options.aH) {
                          addHistory(docTitle, url);
                      }
                      addTitle(title);
                  }
                  if (options.remove[0] && options.remove[1] > 1) {
                      removesOldChapter();
                  }
                  setTimeout(() => {
                      load.parentNode.insertBefore(F, load);
                      ['.comic-chapter>.next_chapter', '.bottom-bar', 'span.title'].forEach(e => {
                          ge(e).outerHTML = rge(e).outerHTML; //替換元素
                      });
                      removeLoad();
                  }, 200);
              } else {
                  let E = ge('.comic-contain');
                  E.innerHTML = '';
                  E.appendChild(F);
              }
          },
          addNextObserver = () => {
              const getNext = () => {
                  let next = ge('#next-chapter');
                  if (next) {
                      //可能會遇到當前域名和下一頁鏈接的域名不同,導致發生跨域請求出錯的情況,需替換為當前域名。
                      let url = next.href;
                      const nh = next.host;
                      const lh = location.host;
                      if (nh !== lh) {
                          url = url.replace(nh, lh);
                      }
                      addLoad();
                      fetchData(url);
                  }
              };
              /*let imgs = ge('.comic-contain').querySelectorAll('img');
              let lastImg = [].slice.call(imgs).pop();*/
              let lastImg = [...ge('.comic-contain').querySelectorAll('img')].pop(), //用最後一張圖片作為觀察對象。
                  loadImg = new Image();
              loadImg.src = lastImg.src;
              loadImg.onload = () => {
                  //等待最後一張圖片載入完成再添加觀察,過早可能會連續觸發下一頁,導致圖片請求過度頻繁。
                  const observer = new IntersectionObserver((e, observer) => {
                      if (e[0].isIntersecting) {
                          observer.unobserve(lastImg);
                          getNext();
                      }
                  }).observe(lastImg);
              };
              loadImg.onerror = () => {
                  alert('可能圖片請求過於頻繁,觸發網站限制圖片403拒絕存取,也或許只是圖片404掛掉了,請自行確認。');
                  //圖片出錯則改用當前頁面的next元素做為觀察對象
                  let ele = ge('.comic-chapter>.next_chapter');
                  const observer = new IntersectionObserver((e, observer) => {
                      if (e[0].isIntersecting) {
                          observer.unobserve(ele);
                          getNext();
                      }
                  }).observe(ele);
              };
          },
          removesOldChapter = () => {
              let titles = gae('.chapterTitle');
              if (titles.length > options.remove[1]) {
                  titles[0].remove();
                  let removes = gae('.comic-contain>*');
                  for (let i in removes) {
                      if (/chapterTitle/.test(removes[i].className)) {
                          break
                      }
                      removes[i].remove();
                  }
              }
          };

    if (read) {
        removeAd();
        addGoBack();
        addGlobalStyle(readCss);
        insertData(document);
        addNextObserver();
    }

    if (options.oint && !read) {
        openInNewTab();
        new MutationObserver(() => {
            openInNewTab();
        }).observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    if (options.aO && comic) {
        window.onload = () => {
            let open = ge('#button_show_all_chatper:not([hidden])');
            if (open) open.click();
        };
    }

})();