// ==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 // @downloadURL none // ==/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(); } })();