按鍵與滑鼠滾輪翻頁器

使用滑鼠滾輪或按鍵快速切換上下頁。

Instalează acest script?
Script sugerat de autor

Poate îți va plăcea și隱藏youtube片尾畫面.

Instalează acest script
// ==UserScript==
// @name         按鍵與滑鼠滾輪翻頁器
// @name:zh-TW   按鍵與滑鼠滾輪翻頁器
// @name:ja      キーとマウスホイールでのページめくり機
// @name:en      Keyboard and Mouse Wheel Page Turner
// @name:ko      키보드 및 마우스 휠 페이지 전환기
// @name:es      Navegador de Páginas con Teclado y Rueda del Ratón
// @namespace    https://github.com/Max46656
// @version      1.2.5
// @description  使用滑鼠滾輪或按鍵快速切換上下頁。
// @description:zh-TW 使用滑鼠滾輪或按鍵快速切換上下頁。
// @description:ja マウスホイールをスクロールするか、キーを押すことで、簡単にページを上下に切り替えることができます。
// @description:en Quickly navigate between pages by scrolling the mouse wheel or pressing keys.
// @description:ko 마우스 휠을 스크롤하거나 키를 눌러 페이지를 쉽게 전환할 수 있습니다.
// @description:es Navega rápidamente entre páginas desplazando la rueda del ratón o presionando teclas.
// @author       Max
// @match        https://*/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=pixiv.net
// @grant    GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @license MPL2.0
// ==/UserScript==


class PageButtonManager {
    constructor() {
        this.pageButtonsMap = {};
        this.loadPageButtons();
    }

    loadPageButtons() {
        this.pageButtonsMap = GM_getValue('pageButtonsMap', {});
    }

    async savePageButtons() {
        await GM_setValue('pageButtonsMap', this.pageButtonsMap);
    }

    getButtonsForDomain(domain) {
        return this.pageButtonsMap[domain] || {
            nextButton: '.next',
            prevButton: '.prev'
        };
    }

    setButtonsForDomain(domain, buttons) {
        this.pageButtonsMap[domain] = buttons;
        this.savePageButtons();
    }

    getAllDomains() {
        return Object.keys(this.pageButtonsMap);
    }
}

class NavigationPaginationWithInput {
   constructor(buttonManager) {
        this.buttonManager = buttonManager;
        this.pageButtons = this.buttonManager.getButtonsForDomain(self.location.hostname);
        console.log(this.pageButtons);
        this.init();
    }

    async init() {
        await this.loadSettings();
        this.setEventListeners();
    }

    async loadSettings() {
        this.togglePaginationMode = await GM_getValue('togglePaginationMode', 'key');
        this.modifierKey = await GM_getValue('modifierKey', 'Control');
        this.nextPageKey = await GM_getValue('nextPageKey', 'W');
        this.prevPageKey = await GM_getValue('prevPageKey', 'Q');
        console.group("Settings");
        console.log("togglePaginationMode",this.togglePaginationMode);
        console.log("modifierKey",this.modifierKey);
        console.log("nextPageKey",this.nextPageKey);
        console.log("prevPageKey",this.prevPageKey);
        console.groupEnd();
    }

    async saveSettings() {
        await GM_setValue('togglePaginationMode', this.togglePaginationMode);
        await GM_setValue('modifierKey', this.modifierKey);
        await GM_setValue('nextPageKey', this.nextPageKey);
        await GM_setValue('prevPageKey', this.prevPageKey);
    }

    async toNextPage() {
        const pageButtons = document.querySelectorAll(this.pageButtons.nextButton);
        let nextPageButton = pageButtons[pageButtons.length-1];
        nextPageButton.click();
    }

    async toPrevPage() {
        const prevPageButton = document.querySelectorAll(this.pageButtons.prevButton)[0];
        prevPageButton.click();
    }

    async setEventListeners() {
        this.scrollHandler = () => this.handleScroll();
        this.keydownHandler = (event) => this.handleKeydown(event);

        if (this.togglePaginationMode !== "key") {
            self.addEventListener("scroll", this.scrollHandler);
        } else {
            self.addEventListener("keydown", this.keydownHandler);
        }
    }

    handleScroll(scrollThreshold=3) {
        const isBottom = document.documentElement.scrollHeight - self.innerHeight - self.pageYOffset <= scrollThreshold;
        if (isBottom) {
            this.toNextPage();
            console.log("滾輪下一頁");
        }
        if (self.pageYOffset <= 0) {
            this.toPrevPage();
            console.log("滾輪上一頁");
        }
    }

    handleKeydown(event) {
        if (event.getModifierState(this.modifierKey)) {
            if (event.key.toUpperCase() === this.nextPageKey.toUpperCase()) {
                event.preventDefault();
                this.toNextPage();
                console.log("快捷鍵下一頁");
            } else if (event.key.toUpperCase() === this.prevPageKey.toUpperCase()) {
                event.preventDefault();
                this.toPrevPage();
                console.log("快捷鍵上一頁");
            }
        }
    }
}

class MenuManager {
    constructor(buttonManager) {
        this.buttonManager = buttonManager;
        this.initMenu();
    }

    getMenuLabels() {
        const userLang = navigator.language || navigator.userLanguage;
        const labels = {
            'zh-TW': {
                viewAndModify: '修改上下頁的按鈕元素選取器',
                showAllDomains: '顯示所有網域',
                togglePageMode: '切換翻頁模式',
                customizeModifierKey: '自訂啟動快捷鍵',
                customizeNextPageKey: '自訂下一頁快捷鍵',
                customizePrevPageKey: '自訂上一頁快捷鍵',
                enterDomain: '輸入網域:',
                currentButtons: '當前按鈕:',
                enterNextButton: '輸入下一頁按鈕選擇器:',
                enterPrevButton: '輸入上一頁按鈕選擇器:',
                savedDomains: '已儲存的網域:',
                enterDomainToView: '輸入要檢視的網域:',
                enterModifierKey: '輸入啟動快捷鍵 (Control, Alt, Shift, CapsLock):',
                enterNextPageKey: '輸入下一頁快捷鍵:',
                enterPrevPageKey: '輸入上一頁快捷鍵:',
                invalidInput: '無效的輸入,請重試。'
            },
            'en': {
                viewAndModify: 'Modify Page Up/Down Button Selectors',
                showAllDomains: 'Show All Domains',
                togglePageMode: 'Toggle Page Mode',
                customizeModifierKey: 'Customize Modifier Key',
                customizeNextPageKey: 'Customize Next Page Key',
                customizePrevPageKey: 'Customize Previous Page Key',
                enterDomain: 'Enter the domain:',
                currentButtons: 'Current buttons:',
                enterNextButton: 'Enter the next page button selector:',
                enterPrevButton: 'Enter the previous page button selector:',
                savedDomains: 'Saved domains:',
                enterDomainToView: 'Enter the domain to view:',
                enterModifierKey: 'Enter modifier key (Control, Alt, Shift, CapsLock):',
                enterNextPageKey: 'Enter next page key:',
                enterPrevPageKey: 'Enter previous page key:',
                invalidInput: 'Invalid input, please try again.'
            },
            'ja': {
                viewAndModify: 'ページの上下ボタン要素セレクターの変更',
                showAllDomains: 'すべてのドメインを表示',
                togglePageMode: 'ページモードを切り替える',
                customizeModifierKey: '修飾キーをカスタマイズ',
                customizeNextPageKey: '次のページキーをカスタマイズ',
                customizePrevPageKey: '前のページキーをカスタマイズ',
                enterDomain: 'ドメインを入力してください:',
                currentButtons: '現在のボタン:',
                enterNextButton: '次のページボタンのセレクタを入力してください:',
                enterPrevButton: '前のページボタンのセレクタを入力してください:',
                savedDomains: '保存されたドメイン:',
                enterDomainToView: '表示するドメインを入力してください:',
                enterModifierKey: '修飾キーを入力してください(Control、Alt、Shift、CapsLock):',
                enterNextPageKey: '次のページキーを入力してください:',
                enterPrevPageKey: '前のページキーを入力してください:',
                invalidInput: '無効な入力です。もう一度お試しください。'
            },
            'ko': {
                viewAndModify: '페이지 위/아래 버튼 선택기 수정',
                showAllDomains: '모든 도메인 보기',
                togglePageMode: '페이지 모드 전환',
                customizeModifierKey: '수정 키 사용자화',
                customizeNextPageKey: '다음 페이지 키 사용자화',
                customizePrevPageKey: '이전 페이지 키 사용자화',
                enterDomain: '도메인을 입력하세요:',
                currentButtons: '현재 버튼:',
                enterNextButton: '다음 페이지 버튼 선택기 입력:',
                enterPrevButton: '이전 페이지 버튼 선택기 입력:',
                savedDomains: '저장된 도메인:',
                enterDomainToView: '보기할 도메인을 입력하세요:',
                enterModifierKey: '수정 키를 입력하세요 (Control, Alt, Shift, CapsLock):',
                enterNextPageKey: '다음 페이지 키 입력:',
                enterPrevPageKey: '이전 페이지 키 입력:',
                invalidInput: '잘못된 입력입니다. 다시 시도하세요.'
            },
            'es': {
                viewAndModify: 'Modificar Selectores de Botones de Página Arriba/Abajo',
                showAllDomains: 'Mostrar Todos los Dominios',
                togglePageMode: 'Alternar Modo de Página',
                customizeModifierKey: 'Personalizar Tecla Modificadora',
                customizeNextPageKey: 'Personalizar Tecla de Siguiente Página',
                customizePrevPageKey: 'Personalizar Tecla de Página Anterior',
                enterDomain: 'Ingrese el dominio:',
                currentButtons: 'Botones actuales:',
                enterNextButton: 'Ingrese el selector del botón de siguiente página:',
                enterPrevButton: 'Ingrese el selector del botón de página anterior:',
                savedDomains: 'Dominios guardados:',
                enterDomainToView: 'Ingrese el dominio a visualizar:',
                enterModifierKey: 'Ingrese tecla modificadora (Control, Alt, Shift, CapsLock):',
                enterNextPageKey: 'Ingrese tecla de siguiente página:',
                enterPrevPageKey: 'Ingrese tecla de página anterior:',
                invalidInput: 'Entrada inválida, por favor intente de nuevo.'
            }
        };
        return labels[userLang] || labels['en'];
    }

    initMenu() {
        const labels = this.getMenuLabels();
        GM_registerMenuCommand(labels.viewAndModify, this.viewAndModifyButtons.bind(this));
        GM_registerMenuCommand(labels.showAllDomains, this.showAllDomains.bind(this));
        GM_registerMenuCommand(labels.togglePageMode, this.inputModeSwitch.bind(this));
        GM_registerMenuCommand(labels.customizeModifierKey, this.customizeModifierKey.bind(this));
        GM_registerMenuCommand(labels.customizeNextPageKey, this.customizeNextPageKey.bind(this));
        GM_registerMenuCommand(labels.customizePrevPageKey, this.customizePrevPageKey.bind(this));
    }

    async viewAndModifyButtons() {
        const labels = this.getMenuLabels();
        const domain = prompt(labels.enterDomain, window.location.hostname);
        if (domain) {
            const currentButtons = this.buttonManager.getButtonsForDomain(domain);
            alert(`${labels.currentButtons}\nNext: ${currentButtons.nextButton}\nPrev: ${currentButtons.prevButton}`);
            const newNextButton = prompt(labels.enterNextButton, currentButtons.nextButton);
            const newPrevButton = prompt(labels.enterPrevButton, currentButtons.prevButton);
            if (newNextButton && newPrevButton) {
                this.buttonManager.setButtonsForDomain(domain, { nextButton: newNextButton, prevButton: newPrevButton });
                alert(`Updated buttons for ${domain}`);
            }
        }
    }

    async showAllDomains() {
        const labels = this.getMenuLabels();
        const allDomains = this.buttonManager.getAllDomains();
        const domain = prompt(`${labels.savedDomains}\n${allDomains.join('\n')}\n\n${labels.enterDomainToView}`);
        if (domain) {
            const buttons = this.buttonManager.getButtonsForDomain(domain);
            alert(`Buttons for domain ${domain}:\nNext: ${buttons.nextButton}\nPrev: ${buttons.prevButton}`);
        }
    }

    async inputModeSwitch() {
        if (this.togglePaginationMode === 'scroll') {
            this.togglePaginationMode = 'key';
            self.removeEventListener("scroll", this.scrollHandler);
            self.addEventListener("keydown", this.keydownHandler);
            console.log("切換為按鍵翻頁模式");
        } else {
            this.togglePaginationMode = 'scroll';
            self.addEventListener("scroll", this.scrollHandler);
            self.removeEventListener("keydown", this.keydownHandler);
            console.log("切換為滾輪翻頁模式");
        }
        this.saveSettings();
    }

    async customizeModifierKey() {
        const labels = this.getMenuLabels();
        const newModifierKey = prompt(labels.enterModifierKey, this.navigation.modifierKey);
        if (['Control', 'Alt', 'Shift', 'CapsLock'].includes(newModifierKey)) {
            this.navigation.modifierKey = newModifierKey;
            await this.navigation.saveSettings();
        } else {
            alert(labels.invalidInput);
        }
    }

    async customizeNextPageKey() {
        const labels = this.getMenuLabels();
        const newNextPageKey = prompt(labels.enterNextPageKey, this.navigation.nextPageKey);
        if (newNextPageKey && newNextPageKey.length === 1) {
            this.navigation.nextPageKey = newNextPageKey;
            await this.navigation.saveSettings();
        } else {
            alert(labels.invalidInput);
        }
    }

    async customizePrevPageKey() {
        const labels = this.getMenuLabels();
        const newPrevPageKey = prompt(labels.enterPrevPageKey, this.navigation.prevPageKey);
        if (newPrevPageKey && newPrevPageKey.length === 1) {
            this.navigation.prevPageKey = newPrevPageKey;
            await this.navigation.saveSettings();
        } else {
            alert(labels.invalidInput);
        }
    }
}

const buttonManager = new PageButtonManager();
new NavigationPaginationWithInput(buttonManager);
new MenuManager(buttonManager);