Greasy Fork

增強漫畫櫃

漫畫櫃自動隐藏頂部元素、中鍵捲動頁面、圖片高寬調整、自動切換上下一章、更改cookie、簡易觸控手勢、Backspace及觸控下滑在漫畫頁面時回目錄,在目錄時回進入目錄之前

// ==UserScript==
// @name 增強漫畫櫃
// @namespace http://tampermonkey.net/
// @version 1.4
// @description 漫畫櫃自動隐藏頂部元素、中鍵捲動頁面、圖片高寬調整、自動切換上下一章、更改cookie、簡易觸控手勢、Backspace及觸控下滑在漫畫頁面時回目錄,在目錄時回進入目錄之前
// @license MIT
// @match *://www.manhuagui.com/*
// @run-at document-end
// @grant none
// ==/UserScript==

(function($) {
    'use strict';

    // 禁用 tbBox.live
    function disableTbBoxLive() {
        $('#tbBox').off && $('#tbBox').off();
        $('#tbBox').die && $('#tbBox').die();
    }

    $(document).ready(disableTbBoxLive);

    new MutationObserver(() => {
        $('#tbBox').length && disableTbBoxLive();
    }).observe(document.body, { childList: true, subtree: true });
})(window.jQuery);

(function() {
    'use strict';

    // 滑鼠中鍵捲動頁面(優化版)
    let isMiddleButtonPressed = false;
    let [lastX, lastY] = [0, 0];

    document.addEventListener('mousedown', e => {
        if (e.button === 1) {
            isMiddleButtonPressed = true;
            document.body.style.cursor = 'grab';
            [lastX, lastY] = [e.clientX, e.clientY];
            e.preventDefault();
        }
    });

    document.addEventListener('mouseup', e => {
        if (e.button === 1) {
            isMiddleButtonPressed = false;
            document.body.style.cursor = 'default';
        }
    });

    document.addEventListener('mousemove', e => {
        if (isMiddleButtonPressed) {
            const deltaX = e.clientX - lastX;
            const deltaY = e.clientY - lastY;
            window.scrollBy(-deltaX * 1.5, -deltaY * 4); // 調整滑動速度
            [lastX, lastY] = [e.clientX, e.clientY];
        }
    });
const url = window.location.href;
if (url.includes('html')&&url.includes('/comic/')) {
    //改變css style
    const style = document.createElement('style');
    style.textContent = `
        html {
            overflow: overlay;
        }
        .notice-bar .notice{
            width:initial;
            float: initial;
        }
        .w998, .w728, .w980, .chapter, .chapter-list, .latest-list, .latest-list ul, .contList, .book-list ul, .cmt-cont, .cover-list, .tbCenter {
            width:100%;
        }
        .w860 {
            float:left;
        }
        .tbCenter {
            border:0px;
            background-color: transparent;
        }
        .footer-cont {
            width:100%;
            padding: 0;
        }
        .sub-btn {
            width:980px;
            margin:0px auto;
        }
    `;
    document.head.appendChild(style);
    // 隱藏頁面元素
    const elementsToHide = ['.header-inner', '.title', '.main-btn', '.w980.clearfix.sub-btn'];
    const header = document.querySelector('.header');
    const headerHeight = '50px';

    if (header) {
        Object.assign(header.style, {
            position: 'absolute', top: '0', left: '0', width: '100%', height: headerHeight,
            display: 'block', opacity: '0', zIndex: '1', marginBottom: '0'
        });

        [...elementsToHide, '.header'].forEach(selector => {
            const el = document.querySelector(selector);
            el && el.addEventListener('mouseover', () => toggleHeaderVisibility(true));
            el && el.addEventListener('mouseout', () => toggleHeaderVisibility(false));
        });

        // 頁面載入時先隱藏元素
        elementsToHide.forEach(selector => {
            const el = document.querySelector(selector);
            el && (el.style.display = 'none');
        });
    }

    function toggleHeaderVisibility(show) {
        header.style.opacity = show ? '1' : '0';
        elementsToHide.forEach(selector => {
            const el = document.querySelector(selector);
            el && (el.style.display = show ? 'block' : 'none');
        });
        header.style.height = show ? '34px' : headerHeight;
        header.style.position= show ? 'relative' : 'absolute';
    }

    // 動態改變圖片大小
    function resizeImage() {
        const img = document.getElementById('mangaFile');
        const images = document.querySelectorAll('#mangaMoreBox img');
        if (!img || !img.complete) return;

        const [windowHeight, windowWidth] = [window.innerHeight, window.innerWidth];
        const adjustedWidth = (windowHeight / img.naturalHeight) * img.naturalWidth;
        if (img.naturalHeight > img.naturalWidth && windowHeight > 1.5*windowWidth) {
            // 圖片高度大於圖片寬度且視窗寬度大於1.5倍視窗高度
            img.style.width = `${windowWidth}px`;
            img.style.height = 'auto';
/*          let style = document.getElementById('mangaStyle');

            if (!style) {
                style = document.createElement('style');
                style.id = 'mangaStyle';
            document.head.appendChild(style);
            }
            style.textContent = `
                #mangaMoreBox img {
                    width: ${windowWidth}px;
                    height: auto;
                }
            `;*/

            // 設定下拉模式的mangaMoreBox
            images.forEach(img => {
                img.style.width = `${windowWidth}px`;
                img.style.height = 'auto';
            });
            document.body.style.width = `${windowWidth}px`;
            header.style.width = '100%';
//        } else if (img.naturalHeight > windowHeight && adjustedWidth > windowWidth) {
            // 高度大於視窗高度且調整過圖片寬度大於視窗寬度,將圖片高度設為視窗高度且header, .main-nav .main-bar為調整過寬度
//            img.style.height = `${windowHeight}px`;
//            img.style.width = 'auto';
//            document.body.style.width = `${adjustedWidth}px`;
//            header.style.width = `${adjustedWidth}px`;
        } else if (pVars.curFunc==3) {
            // 下拉模式
            if (img.naturalWidth > windowWidth || windowHeight > 1.5*windowWidth) {
                img.style.width = `${windowWidth}px`;
            } else {
                img.style.width = 'auto';
            }
            img.style.height = 'auto';
            // 設定下拉模式的mangaMoreBox
            images.forEach(img => {
                if (img.naturalWidth > windowWidth || windowHeight > 1.5*windowWidth) {
                    img.style.width = `${windowWidth}px`;
                } else {
                    img.style.width = 'auto';
                }
                img.style.height = 'auto';
            });
        } else if (img.naturalHeight > 2.5*img.naturalWidth) {
            // 條漫為auto
            img.style.height = 'auto';
            img.style.width = 'auto';
            document.body.style.width = '100%';
            header.style.width = `100%`;
        } else if (img.naturalHeight > windowHeight || img.naturalHeight > img.naturalWidth || adjustedWidth < windowWidth) {
            // 圖片高度大於視窗高度和圖片寬度,將圖片高度設為視窗高度
            img.style.height = `${windowHeight}px`;
            img.style.width = 'auto';
            document.body.style.width = '100%';
            header.style.width = `100%`;
        } else if (img.naturalWidth > windowWidth) {
            // 圖片寬度度大於視窗寬度,將header, .main-nav .main-bar為圖片寬度
            img.style.height = 'auto';
            img.style.width = 'auto';
            document.body.style.width = `${img.naturalWidth}px`;
            header.style.width = `${img.naturalWidth}px`;
        } else {
            // 其他情況,auto
            img.style.height = 'auto';
            img.style.width = 'auto';
            document.body.style.width = '100%';
            header.style.width = `100%`;
        }
    }

    new MutationObserver(resizeImage).observe(document.body, { childList: true, subtree: true });
    window.addEventListener('load', resizeImage);

    // 自動捲動到右側大圖
    function scrollToRightIfNeeded() {
        const viewportWidth = window.innerWidth;
        document.querySelectorAll('img').forEach(img => {
            if (img.complete && img.offsetWidth > viewportWidth) {
                setTimeout(() => window.scrollTo({ left: document.documentElement.scrollWidth }), 50);
            }
        });
    }

    window.addEventListener('load', scrollToRightIfNeeded);
    new MutationObserver(scrollToRightIfNeeded).observe(document.body, { childList: true, subtree: true });

    // 自動上下一章
    new MutationObserver(() => {
        const okButton = document.querySelector('.pb-ok');
        okButton && okButton.click();
    }).observe(document.body, { childList: true, subtree: true });

    // 最後一頁自動回到目錄
    new MutationObserver(() => {
    const backLink = document.querySelector('.tip-alert a');
        if (backLink) backLink.click();
    }).observe(document.body, { childList: true, subtree: true });


} else {
        document.querySelectorAll('a[target]').forEach(link => {link.setAttribute('target', '_self');});
}
    //⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇記錄歷史頁面給Backspace回到漫畫的前一頁用⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
    // 初始化 sessionStorage 中的歷史記錄陣列
    if (!sessionStorage.getItem('urlHistory')) {
        sessionStorage.setItem('urlHistory', JSON.stringify([]));
    }
    // 更新歷史記錄
    function updateHistory() {
        const currentUrl = window.location.href;
        let history = JSON.parse(sessionStorage.getItem('urlHistory'));
        if (history[history.length - 1] !== currentUrl) { // 避免重複記錄相同 URL
            history.push(currentUrl);
            sessionStorage.setItem('urlHistory', JSON.stringify(history));
            console.log('Updated history:', history);
        }
    }
    // 查找上一個與當前 URL 相同的記錄的上一筆,並計算步數
    function findPreviousInstanceStep() {
        const currentUrl = window.location.href;
        let history = JSON.parse(sessionStorage.getItem('urlHistory'));
        console.log('Current history:', history);
        console.log('Current URL:', currentUrl);
    // 從倒數第二筆開始查找上一個與當前 URL 相同的記錄
        for (let i = history.length - 2; i >= 0; i--) {
            if (history[i] === currentUrl) {
                console.log('Found previous match at index:', i, 'URL:', history[i]);
                    if (i > 0) { // 確保有上一筆
                        const targetIndex = i - 1;
                        const currentIndex = history.length - 1;
                        const steps = targetIndex - currentIndex;
                        console.log('Target index:', targetIndex, 'Target URL:', history[targetIndex], 'Current index:', currentIndex, 'Steps:', steps);
                        return steps;
                    }
                console.log('No prior entry before match');
                break;
            }
        }
        console.log('No previous match found');
        return null;
    }

    // 在頁面加載時更新歷史記錄
    updateHistory();

    // 監聽 URL 變化
    window.addEventListener('popstate', updateHistory);
    window.addEventListener('hashchange', updateHistory);

    // 覆蓋 pushState
    (function(history) {
        const pushState = history.pushState;
        history.pushState = function(state) {
            pushState.apply(history, arguments);
            updateHistory();
        };
    })(window.history);
/*
    // 輪詢檢查 URL 變化(應對未觸發事件的情況)
    let lastUrl = window.location.href;
    setInterval(() => {
        const currentUrl = window.location.href;
        if (currentUrl !== lastUrl) {
            console.log('Detected URL change via polling:', currentUrl);
            updateHistory();
            lastUrl = currentUrl;
        }
    }, 500); // 每 500ms 檢查一次*/
    //⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆記錄歷史頁面給Backspace回到漫畫的前一頁用⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆

    // backspace回到上一層
    document.addEventListener('keydown', function(e) {
        if (e.key === 'Backspace' && !e.target.isContentEditable && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA') {
            const currentUrl = window.location.href;
            const matchHtml = currentUrl.match(/(https?:\/\/[^/]+\/comic\/\d+)\/.*html.*/);
            const matchNumber = currentUrl.match(/(https?:\/\/[^/]+\/comic\/\d+)\/?$/);

            if (matchHtml) {
                window.location.href = matchHtml[1] + '/';
            } else if (matchNumber) {
                //回到漫畫的前一頁
                const steps = findPreviousInstanceStep();
                if (steps !== null) {
                    console.log('Executing history.go(' + steps + ')');
                    history.go(steps);
                } else {
                    console.log('No valid step to go back');
                }

//                const rootUrl = matchNumber[1].replace(/\/comic\/\d+\/?$/, '/update/');
//                window.location.href = rootUrl;
            }
        }
    });
    //插入li
    const insertTip = (container) => {
        const ol = container.querySelector('ol');
        if (ol && !ol.querySelector('.backspace-tip')) { // 防止重複插入
            const newLi = document.createElement('li');
            newLi.className = 'backspace-tip';
            newLi.innerHTML = '<strong>回上层:</strong>Backspace键';
            ol.appendChild(newLi);
        }
    };

    const observeAndInsert = () => {
        const tipContainers = document.querySelectorAll('div.shadow.tip-cont');
        tipContainers.forEach(insertTip);
    };

    // 使用 setTimeout 確保 DOM 完全載入後執行
    setTimeout(observeAndInsert, 3000);

    const observer = new MutationObserver((mutations) => {
        mutations.forEach(mutation => {
            mutation.addedNodes.forEach(node => {
                if (node.nodeType === 1 && node.classList.contains('shadow') && node.classList.contains('tip-cont')) {
                    insertTip(node);
                }
            });
        });
    });

    // 漫畫頁面時觸控手勢控制
    let startX = 0;
    let startY = 0;
    let dragLength = 150;
    let isSingleTouch = false;

    window.addEventListener('touchstart', function(e) {
        if (e.touches.length === 1) { // Only trigger for single touch
            isSingleTouch = true;
            startX = e.touches[0].clientX;
            startY = e.touches[0].clientY;
        } else {
            isSingleTouch = false;
        }
    }, false);

    window.addEventListener('touchend', function(e) {
        if (isSingleTouch && e.changedTouches.length === 1 && e.touches.length === 0) { // Ensure only single touch ends
            const endX = e.changedTouches[0].clientX;
            const endY = e.changedTouches[0].clientY;

            const deltaX = endX - startX;
            const deltaY = endY - startY;

            const currentUrl = window.location.href;
            const matchHtml = currentUrl.match(/(https?:\/\/[^/]+\/comic\/\d+)\/.*html.*/);
            const matchNumber = currentUrl.match(/(https?:\/\/[^/]+\/comic\/\d+)\/?$/);

            if (Math.abs(deltaY) > Math.abs(deltaX)) {
                if (window.scrollY === 0 && deltaY > dragLength) {
                    if (matchHtml) {
                        window.location.href = matchHtml[1] + '/';
                    } else if (matchNumber) {
                        //回到漫畫的前一頁
                        const steps = findPreviousInstanceStep();
                        if (steps !== null) {
                            console.log('Executing history.go(' + steps + ')');
                            history.go(steps);
                        } else {
                            console.log('No valid step to go back');
                        }
//                        const rootUrl = matchNumber[1].replace(/\/comic\/\d+\/?$/, '/update/');
//                        window.location.href = rootUrl;
                    }
                }
            } else {
                if (window.scrollX === 0 && deltaX > dragLength && matchHtml) {
                    const prevButton = Array.from(document.querySelectorAll('.btn-red.prev')).find(btn => btn.textContent.trim() === '上一页');
                    if (prevButton) {
                        prevButton.click();
                    }
                } else if ((window.innerWidth >= document.body.scrollWidth || (window.innerWidth + window.scrollX) >= document.body.scrollWidth) && deltaX < -dragLength && matchHtml) {
                    const nextButton = Array.from(document.querySelectorAll('.btn-red.next')).find(btn => btn.textContent.trim() === '下一页');
                    if (nextButton) {
                        nextButton.click();
                    }
                }
            }
        }
    }, false);

    observer.observe(document.body, { childList: true, subtree: true });
    // 修改 cookie
    const targetCookie = 'country=CN; path=/; domain=.manhuagui.com; expires=' + new Date(Date.now() + 7 * 864e5).toUTCString();
    document.cookie = targetCookie;
})();