Greasy Fork

DM5动漫屋_日漫阅读辅助

DM5动漫屋_日漫瀑布流阅读连续载入图片(自用)。

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

// ==UserScript==
// @name               DM5動漫屋_日漫閱讀輔助
// @name:en            DM5 Read Helpr
// @name:zh-CN         DM5动漫屋_日漫阅读辅助
// @name:zh-TW         DM5動漫屋_日漫閱讀輔助
// @version            0.1
// @description        DM5動漫屋_日漫瀑布流閱讀連續載入圖片(自用)。
// @description:en     DM5 read infinite scroll
// @description:zh-CN  DM5动漫屋_日漫瀑布流阅读连续载入图片(自用)。
// @description:zh-TW  DM5動漫屋_日漫瀑布流閱讀連續載入圖片(自用)。
// @author             tony0809
// @match              *://www.dm5.com/*/
// @match              *://www.dm5.cn/*/
// @match              *://en.dm5.com/*/
// @match              *://tel.dm5.com/*/
// @match              *://www.1kkk.com/*/
// @icon               https://www.google.com/s2/favicons?sz=64&domain=dm5.com
// @grant              none
// @license            MIT
// @namespace          https://greasyfork.org/users/20361
// ==/UserScript==

(function() {
    'use strict';
    const options = { //true 開啟,false 關閉
        remove: [true, 3] //!!!不能小於2!!!閱讀載入超過n話時刪除前面話數的圖片。
    };
    const ge = e => document.querySelector(e);
    const gae = e => document.querySelectorAll(e);
    const gx = x => document.evaluate(x,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue;
    const gax = x => {
        let nodes = [];
        let results = document.evaluate(x, document, null, XPathResult.ANY_TYPE, null);
        let node;
        while (node = results.iterateNext()) {
            nodes.push(node)
        }
        return nodes
    };
    const runCode = code => new Function('return ' + code)();
    const addGlobalStyle = css => {
        let style = document.createElement('style');
        style.type = 'text/css';
        style.innerHTML = css;
        document.head.appendChild(style);
    };
    const css = `
a[href^='j'],
.chapterpager {
    display: none !important
}
#cp_img>img {
    width: auto !important;
    height: auto !important;
    max-width: 100% !important;
    display: block !important;
    margin: 0 auto !important
}
.chapterLoading {
    font-size: 20px;
    height: 80px;
    line-height: 32px;
    text-align: center;
}
.chapterTitle {
    width: auto;
    height: 30px;
    font-size: 26px;
    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;
}
    `;
    const addHistory = (title, url) => {
        history.pushState(null, title, url);
        document.title = title;
    };
    const addLoad = () => {
        let cl = document.createElement('div');
        cl.className = 'chapterLoading';
        cl.innerText = 'Loading...';
        ge('#cp_img').appendChild(cl);
    };
    const removeLoad = () => {
        ge('.chapterLoading').remove();
    };
    const addTitle = title => {
        let t = document.createElement('div');
        t.className = 'chapterTitle';
        t.innerText = title;
        let load = ge('.chapterLoading');
        load.parentNode.insertBefore(t, load);
    };
    const 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;
    };
    const fetchData = url => {
        fetch(url).then(res => res.text()).then(res => {
            let doc = parseHTML(res);
            addHistory(doc.title, url);
            let code = Array.from(doc.scripts).find(s=>s.innerHTML.search(/DM5_IMAGE_COUNT/)>-1).innerHTML;
            let script = document.createElement('script');
            script.type = 'text/javascript';
            script.innerHTML = code;
            ge('#cp_img').appendChild(script);
            insertData(doc);
        }).catch(error => {
            console.error(error);
            ge('.chapterLoading').innerText = '連線出錯,請返回頂部重新載入。';
        });
    };
    const insertData = d => {
        const getData = async (page) => {
            if (page > DM5_IMAGE_COUNT){
                addNextObserver();
                return;
            }
            if (!mkey) {
                var mkey = '';
            }
            let apiUrl = location.href + 'chapterfun.ashx' + `?cid=${DM5_CID}&page=${page}&key=${mkey}&language=1>k=6&_cid=${DM5_CID}&_mid=${DM5_MID}&_dt=${DM5_VIEWSIGN_DT}&_sign=${DM5_VIEWSIGN}`;
            let res = await fetch(apiUrl);
            let resText = await res.text();
            let imgSrc = await runCode(resText)[0];
            let img = new Image();
            img.src = imgSrc;
            ge('#cp_img').appendChild(img);
            page++;
            getData(page)
        };
        let load = ge('.chapterLoading');
        if (load) {
            const rgx = x => d.evaluate(x,d,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue;
            gax("//div[@class='container' and div[@id='chapterpager']]").forEach(e => {
                e.outerHTML = rgx("//div[@class='container' and div[@id='chapterpager']]").outerHTML;
            });
            ge('.rightToolBar').outerHTML = d.querySelector('.rightToolBar').outerHTML;
            let title = rgx("//span[@class='active right-arrow']").innerText.trim();
            addTitle(title);
            if (options.remove[0] && options.remove[1] > 1) {
                removeOldChapter();
            }
            setTimeout(() => {
                getData(1);
                removeLoad();
            }, 300);
        } else {
            document.body.style.overflow = 'scroll';
            ge('#cp_img').innerHTML = '';
            getData(1);
        }
    };
    const nextObserver = new IntersectionObserver((entries, observer) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                observer.unobserve(entry.target);
                let next = gx("//a[text()='下一章']");
                if (next) {
                    console.log('觸發載入下一話');
                    addLoad();
                    fetchData(next.href);
                }
            }
        });
    });
    const addNextObserver = () => {
        let lastImg = [...ge('#cp_img').querySelectorAll('img')].pop();
        nextObserver.observe(lastImg);
    };
    const removeOldChapter = () => {
        let titles = gae('.chapterTitle');
        if (titles.length > options.remove[1]) {
            titles[0].remove();
            let removes = gae('#cp_img>*');
            for (let i in removes) {
                if (/chapterTitle/.test(removes[i].className)) {
                    break;
                }
                removes[i].remove();
            }
        }
    };

    if(ge('#chapterpager')){
        addGlobalStyle(css);
        insertData();
    }

})();