Greasy Fork is available in English.

mike's lib

快速處理畫面操作

이 스크립트는 직접 설치하는 용도가 아닙니다. 다른 스크립트에서 메타 지시문 // @require https://update.greasyfork.org/scripts/570074/1869594/mike%27s%20lib.js을(를) 사용하여 포함하는 라이브러리입니다.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

Advertisement:

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

Advertisement:

// ==UserScript==
// @name         mike's lib
// @namespace    小說
// @version      2026.07.07
// @description  工具函式庫
// @author       mike
// @match        http*://*/*
// @grant        none
// ==/UserScript==

(function (global) {
    'use strict';

    // 等待物件 func
    const waitElement = (selector, callback) => {
        const interval = setInterval(() => {
            const element = document.querySelector(selector);
            if (element) {
                clearInterval(interval);
                callback(element);
            }
        }, 100);
    };

    // 移除物件
    const removeElement = (baseObj, removeTarget) => {
        let beRemoveObj = baseObj.querySelector(removeTarget);
        if (beRemoveObj) {
            beRemoveObj.remove();
        }
    };
    
    // 等並刪除
    const waitAndKillElement = (selector) => {
        waitElement(selector, () => {
            removeElement(document, selector);
        });
    };

    // 重置寬高
    const resetMarginPadding = (element) => {
        element.style.margin = '0px';
        element.style.padding = '0px';
    };
    
    // 取得 平台名稱
    const getPlatform = (platformList) => {
        const pathname = window.location.pathname // 用網址查
        const findPlatform = platformList.find(item => {
            const [key, value] = Object.entries(item)[0];
            return pathname.includes(key);
        });
        return Object.values(findPlatform)[0]
    }

    // 取得 平台名稱
    const getPlatformByHostname = (platformList) => {
        const hostname = window.location.hostname // 用網域查
        const findPlatform = platformList.find(item => {
            const [key, value] = Object.entries(item)[0];
            return hostname.includes(key);
        });
        if (!findPlatform) return '';
        return Object.values(findPlatform)[0];
    }

    // 製作快速跳轉浮窗
    // initChapterNavigator({selectors: ['.entry-content', 'p'], chapterStartsWith: ['[', '【']});
    const initChapterNavigator = ({
        selectors,
        chapterStartsWith
    }) => {

        if (
            !Array.isArray(selectors) ||
            selectors.length === 0 ||
            selectors.some(s => typeof s !== 'string' || !s.trim())
        ) {
            console.log('[ChapterNavigator] selectors 必須為非空字串陣列');
            return;
        }

        if (
            !Array.isArray(chapterStartsWith) ||
            chapterStartsWith.length === 0 ||
            chapterStartsWith.some(s => typeof s !== 'string' || !s)
        ) {
            console.log('[ChapterNavigator] chapterStartsWith 必須為非空字串陣列');
            return;
        }

        const queryBySelectors = () => {
            let current = document;

            for (let i = 0; i < selectors.length; i++) {
                if (!current) return [];

                if (i === selectors.length - 1) {
                    return Array.from(current.querySelectorAll(selectors[i]));
                }

                current = current.querySelector(selectors[i]);
            }

            return [];
        };

        const areaKeyList = () => {
            return queryBySelectors().filter(el => {
                const text = el.textContent.trim();
                return chapterStartsWith.some(prefix =>
                    text.startsWith(prefix)
                );
            });
        };

        const gotoText = (findText) => {
            areaKeyList().forEach(el => {
                if (el.textContent.includes(findText)) {
                    el.scrollIntoView({
                        behavior: 'smooth',
                        block: 'start'
                    });
                }
            });
        };

        const getChapterList = () =>
            areaKeyList().map(el => el.textContent);

        const createFloatingBox = (chapterList) => {
            if (document.getElementById('floatingBox')) {
                return;
            }

            const floatingBox = document.createElement('div');
            floatingBox.id = 'floatingBox';

            Object.assign(floatingBox.style, {
                position: 'fixed',
                right: '10px',
                bottom: '10px',
                width: '150px',
                height: '450px',
                overflow: 'auto',
                padding: '10px',
                backgroundColor: '#333',
                color: 'white',
                borderRadius: '8px',
                zIndex: '1000'
            });

            chapterList.forEach(text => {
                const btn = document.createElement('button');

                Object.assign(btn.style, {
                    width: '100%',
                    margin: '2px 0',
                    padding: '10px 5px',
                    backgroundColor: '#f44336',
                    color: 'white',
                    border: 'none',
                    borderRadius: '4px',
                    cursor: 'pointer'
                });

                btn.textContent = text;
                btn.onclick = () => gotoText(text);

                floatingBox.appendChild(btn);
            });

            document.body.appendChild(floatingBox);
        };

        const chapterList = getChapterList();

        if (!chapterList.length) {
            console.log('[ChapterNavigator] 未找到任何符合規則的章節');
            return;
        }

        createFloatingBox(chapterList);
    };

    // 處理 遊俠
    const process_ali213 = () => {
        // 移除
        let needRemoveElement;
        needRemoveElement = [".ns_t1", ".ns_t2", ".ns_t3", ".glzjfoot"];
        needRemoveElement.map((element) => {
            mikeLib.removeElement(document, element);
        });

        // 主要內容
        let main = document.querySelector(".main");
        mikeLib.resetMarginPadding(main);
        main.style.width = "100%";
        needRemoveElement = [".glzj_tj", "#ali_gl_detail_top_ad"];
        needRemoveElement.map((element) => {
            mikeLib.removeElement(main, element);
        });

        // 標題
        let gltitle = main.querySelector(".gltitle");
        mikeLib.resetMarginPadding(gltitle);
        gltitle.style.width = "initial";
        gltitle.querySelector(".tit").style.width = "initial";
        needRemoveElement = [".weizhi", ".showtag"];
        needRemoveElement.map((element) => {
            mikeLib.removeElement(main, element);
        });

        // 章節選項
        let dh = main.querySelector(".dh");
        mikeLib.resetMarginPadding(dh);
        dh.style.width = "initial";
        let changtiaodaohang = dh.querySelector(".changtiaodaohang");
        mikeLib.resetMarginPadding(changtiaodaohang);
        changtiaodaohang.style.width = "initial";
        changtiaodaohang.style.left = 0;

        // 內容
        let content = main.querySelector(".content");
        mikeLib.resetMarginPadding(content);
        content.style.width = "90%";
        needRemoveElement = [".gl_r"];
        needRemoveElement.map((element) => {
            mikeLib.removeElement(content, element);
        });

        let gl_l = content.querySelector(".gl_l");
        gl_l.style.width = "100%";
        needRemoveElement = [
            ".share-container",
            ".go-lb",
            ".glrelated",
            ".downrelated",
            "#newsbbs",
            ".gamecard_pc",
        ];
        needRemoveElement.map((element) => {
            mikeLib.removeElement(gl_l, element);
        });

        // let page = gl_l.querySelector('.page')
        // needRemoveElement = ['.n_show_b']
        // needRemoveElement.map((element) => {
        //     waitAndKillElement(page, element)
        // })
    };

    // 處理 娛樂計程車
    const process_entertainment14 = () => {
        const removeObjList = [
            "#masthead",
            ".entry-footer",
            "#nav-below",
            "#comments",
            "#secondary",
            "#colophon",
        ];
        removeObjList.forEach((item) => mikeLib.removeElement(document, item));

        // 主畫面拉寬
        const primary = document.getElementById("primary");
        primary.style.width = "100%";

        // 把圖都直接載入, 來方便正常跳轉
        const lazyHidden = document.querySelectorAll(".lazy-hidden");
        lazyHidden.forEach((item) =>
            item.setAttribute("src", item.getAttribute("data-lazy-src")),
        );
    };

    // 處理 遊民星空
    const process_gamersky = () => {
        const removeObjList = [
            ".QZnav",
            ".QZshade",
            ".QZlogin",
            "#tgs_back_down1000",
            ".bodybg",
            ".header",
            ".bgAdWrap",
            ".Mid_top",
            //
            ".gs_comm_content_bot_fun",
            ".Relevant",
            ".box",
            ".gs_nc_editor",
            ".gs_ccs_solve",
            ".Comment",
            //
            ".Mid2_R",
            ".Bot",
        ];
        removeObjList.forEach((item) => mikeLib.removeElement(document, item));

        const Mid2_L = document.querySelector(".Mid2_L");
        Mid2_L.style.width = "100%";

        const Mid2L_List = document.querySelectorAll('[class^="Mid2L_"]');
        Mid2L_List.forEach((item) => (item.style.width = "100%"));
    };

    // ⭐ 關鍵:對外輸出
    global.mikeLib = {
        waitElement,
        removeElement,
        waitAndKillElement,
        resetMarginPadding,
        getPlatform,
        getPlatformByHostname,
        initChapterNavigator,
        process_ali213,
        process_entertainment14,
        process_gamersky
    };

})(window);