Greasy Fork

看漫画手机版阅读辅助

看漫画手机版阅读辅助,瀑布流阅读连续载入图片,自动点击载入更多,在新分页打开漫画链接(自用)。

目前为 2023-03-15 提交的版本。查看 最新版本

// ==UserScript==
// @name         看漫畫手機版閱讀輔助
// @name:zh-CN   看漫画手机版阅读辅助
// @version      1.4.3
// @description  看漫畫手機版閱讀輔助,瀑布流閱讀連續載入圖片,自動點擊載入更多,在新分頁打開漫畫鏈接(自用)。
// @description:zh-CN  看漫画手机版阅读辅助,瀑布流阅读连续载入图片,自动点击载入更多,在新分页打开漫画链接(自用)。
// @author       tony0809
// @match        *://m.manhuagui.com/*
// @icon         https://www.google.com/s2/favicons?domain=m.manhuagui.com
// @grant        none
// @run-at       document-end
// @license GPL
// @namespace https://greasyfork.org/users/20361
// ==/UserScript==

(() => {
    'use strict';
    const options = { //true 開啟,false 關閉
        lM: true, //最近更新、漫畫大全、排行榜、書架,自動點擊載入更多。
        oint: true, //在新分頁打開漫畫鏈接。
        aH: true, //載入下一話時添加瀏覽器歷史紀錄。
        remove: [true, 4] //!!!不能小於2!!!閱讀載入超過n話時刪除前面話數的圖片。
    },
          ge = e => document.querySelector(e),
          gae = e => document.querySelectorAll(e),
          runCode = code => new Function('return ' + code)(),
          lp = location.pathname,
          update = /^\/update\/$/.test(lp),
          list = /^\/list\//.test(lp),
          rank = /^\/rank\/$/.test(lp),
          search = /^\/s\/[^.]+\.html$/.test(lp),
          read = /^\/comic\/\d+\/\d+\.html$/.test(lp),
          chapter = /^\/comic\/\d+\/$/.test(lp),
          user = /^\/user\/book\//.test(lp),
          addGlobalStyle = css => {
              let style = document.createElement('style');
              style.type = 'text/css';
              style.innerHTML = css;
              document.head.appendChild(style);
          },
          css = `
.goback {
    background: url(/images/bg_main.png) -258px -80px no-repeat;
    position: fixed;
    left: 50%;
    margin-left: -20px;
    bottom: 0px;
    width: 40px;
    height: 40px;
}
.action-list li {
    width: 50% !important
}
#action>ul>li:nth-child(n+2):nth-child(-n+3),
.manga-page,
.clickforceads {
    display: none !important
}
.manga-box img {
    border-top: 0px !important;
    border-bottom: 0px !important
}
.loading {
    font-size: 20px;
    font-family: Arial,sans-serif!important;
    height: 32px;
    line-height: 30px;
    border: none!important;
}
.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;
}
    `;
    addGlobalStyle(css);
    const openInNewTab = () => gae('#topSlider a:not([target=_blank]),.main-list a:not([target=_blank]),.cont-list a: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);
              const goBackOpacity = () => {
                  let dd = document.documentElement,
                      gb = ge('.goback'),
                      scrollTotal = dd.scrollHeight - dd.clientHeight;
                  if ((dd.scrollTop / scrollTotal) > 0.8) {
                      gb.style.opacity = 0.7;
                  } else {
                      gb.style.opacity = 0.2;
                  }
              };
              document.addEventListener('scroll', goBackOpacity);
          },
          autoLoadMore = () => {
              let loadMore = ge('#more:not([style*=none])>.more-go');
              new IntersectionObserver(entries => {
                  if (entries[0].isIntersecting) {
                      loadMore.click();
                  }
              }).observe(loadMore);
          },
          addHistory = (title, url) => {
              history.pushState(null, title, url);
              document.title = title;
          },
          addLoad = () => {
              let load = document.createElement('p');
              load.className = 'loading';
              load.innerText = 'Loading...';
              ge('#manga').appendChild(load);
          },
          removeLoad = () => {
              ge('.loading').remove();
          },
          addTitle = title => {
              let t = document.createElement('div');
              t.className = 'chapterTitle';
              t.innerText = title;
              let load = ge('.loading');
              load.parentNode.insertBefore(t, load);
          },
          insertData = d => {
              const code = Array.from(d.scripts).find(s => s.innerHTML.search(/x6c/) > -1).innerHTML.trim().slice(26),
                    jsonData = JSON.parse(runCode(code).slice(11, -12)),
                    hostArray = ['i', 'eu', 'us'],
                    getRandom = max => Math.floor(Math.random() * Math.floor(max)),
                    randomHost = () => {
                        let choose = getRandom(hostArray.length);
                        let rValue = hostArray[choose];
                        return rValue;
                    },
                    imagesObserver = new IntersectionObserver((entries, observer) => {
                        entries.forEach(entry => {
                            if (entry.isIntersecting) {
                                observer.unobserve(entry.target);
                                let realSrc = entry.target.dataset.src;
                                if (realSrc) {
                                    entry.target.src = realSrc;
                                    entry.target.removeAttribute('data-src');
                                }
                                let nE = entry.target.nextElementSibling;
                                if (nE && nE.tagName == 'IMG' && nE.dataset.src) {
                                    nE.src = nE.dataset.src;
                                    nE.removeAttribute('data-src');
                                }
                            }
                        });
                    }),
                    F = new DocumentFragment();
              jsonData.images.forEach(e => {
                  let domain = location.protocol + "//" + randomHost() + ".hamreus.com";
                  let img = new Image();
                  img.src = 'data:image/png;base64,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';
                  img.dataset.src = `${domain+e}?e=${jsonData.sl.e}&m=${jsonData.sl.m}`;
                  imagesObserver.observe(img);
                  F.appendChild(img);
              });
              let load = ge('.loading');
              if (load) {
                  let title = d.querySelector('#mangaTitle').innerHTML.replace(/<.+>\s?/g, '');
                  addTitle(title);
                  if (options.remove[0] && options.remove[1] > 1) {
                      removeOldChapter();
                  }
                  setTimeout(() => {
                      load.parentNode.insertBefore(F, load);
                      removeLoad();
                  }, 300);
              } else {
                  let E = ge('#manga');
                  E.innerHTML = '';
                  E.appendChild(F);
              }
              let curl = lp.replace(/\d+\.html$/, ''),
                  next = ge("a[data-action='chapter.next']"),
                  prev = ge("a[data-action='chapter.prev']");
              if (jsonData.nextId == 0) {
                  next.href = curl;
                  next.innerText = '返回目录';
              } else {
                  next.href = curl + jsonData.nextId + '.html';
              }
              if (jsonData.prevId > 0) {
                  prev.href = curl + jsonData.prevId + '.html';
              }
          },
          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),
                      title = doc.title;
                  if (options.aH) {
                      addHistory(title, url);
                  }
                  insertData(doc);
                  setTimeout(() => {
                      addNextObserver();
                  }, 1300);
              }).catch((err) => {
                  console.log('出錯鏈接:' + url, err);
                  ge('.loading').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);
                    let title = doc.title;
                    if (options.aH) {
                        addHistory(title, url);
                    }
                    insertData(doc);
                    setTimeout(() => {
                        addNextObserver();
                    }, 1200);
                } else if (xhr.status > 400) {
                    console.log('HTTP連線狀態碼:' + xhr.status + '\n鏈接:' + url);
                    ge('.loading').innerText = 'HTTP連線狀態碼:' + xhr.status + ',獲取過程中出錯。';
                }
            };
            xhr.ontimeout = (e) => {
                console.log(e);
                ge('.loading').innerText = '連線逾時,請返回頂部重新載入。';
            };
            xhr.onerror = (e) => {
                console.log(e);
                ge('.loading').innerText = '連線出錯,請返回頂部重新載入。';
            }
            xhr.send();
        },*/
          addNextObserver = () => {
              //let imgChild = ge('#manga>img:nth-last-child(1)');
              let lastImg = [...ge('#manga').querySelectorAll('img')].pop(); //用最後一張圖片作為觀察對象。
              new IntersectionObserver((entries, observer) => {
                  if (entries[0].isIntersecting) {
                      observer.unobserve(lastImg);
                      let next = ge("a[data-action='chapter.next'][href$=html]");
                      if (next) {
                          console.log('觸發載入下一話');
                          addLoad();
                          fetchData(next.href);
                      }
                  }
              }).observe(lastImg);
          },
          removeOldChapter = () => {
              let titles = gae('.chapterTitle');
              if (titles.length > options.remove[1]) {
                  titles[0].remove();
                  let removes = gae('#manga>*');
                  for (let i in removes) {
                      if (/chapterTitle/.test(removes[i].className)) {
                          break;
                      }
                      removes[i].remove();
                  }
              }
          };

    if (read) {
        addGoBack();
        let loop = setInterval(() => {
            let set = ge('#manga img');
            if (set) {
                clearInterval(loop);
                insertData(document);
                addNextObserver();
            }
        }, 100);
    }

    if (options.oint && !read && !chapter) {
        openInNewTab();
        console.log('看漫画在新分頁打開漫畫鏈接');
        new MutationObserver(() => {
            openInNewTab();
        }).observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    if (options.lM && (update || user || list || rank || search)) {
        autoLoadMore();
    }

})();