Quickly navigate between pages by scrolling the mouse wheel or pressing keys.
// ==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.6 // @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(); this.saveSettings(); } 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]; console.log(this.pageButtons.prevButton,prevPageButton); 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,navigation) { this.buttonManager = buttonManager; this.navigation = navigation; 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(); const Navigation = new NavigationPaginationWithInput(buttonManager); new MenuManager(buttonManager,Navigation);