// ==UserScript==
// @name 按鍵與滑鼠滾輪翻頁器(NSFW)
// @name:zh-TW 按鍵與滑鼠滾輪翻頁器(NSFW)
// @name:ja キーとマウスホイールでのページめくり機(NSFW)
// @name:en Keyboard and Mouse Wheel Page Turner(NSFW)
// @namespace https://greasyfork.org/
// @version 1.10
// @description 使用滑鼠滾輪或按鍵快速切換上下頁。在Pixiv頁面載入後自動展開所有作品。
// @description:zh-TW 使用滑鼠滾輪或按鍵快速切換上下頁。在Pixiv頁面載入後,自動展開所有作品。
// @description:ja マウスホイールをスクロールするか、キーを押すことで、簡単にページを上下に切り替えることができます。Pixivのページが完全に読み込まれた後、すべての作品を自動的に展開します。
// @description:en Quickly navigation between pages by scrolling the mouse wheel or pressing keys. Automatically expands all works after the Pixiv page is fully loaded.
// @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 PageInputNavigation {
constructor() {
this.PageButtonsOfDomainCollector =new PageButtonsOfDomain();
this.Menu = new inputCustomMenu();
this.pageButtons = this.getPageButtonsByDomain();
this.buttonClicked = false;
this.setEventListeners();
}
getPageButtonsByDomain(){
const pageButtons=this.PageButtonsOfDomainCollector.getAllPageButtons();
const domain = self.location.hostname;
//onsole.log(pageButtons);
if(pageButtons[domain]!=null){
console.log(domain);
console.log(pageButtons[domain]);
return pageButtons[domain];
}
console.log("general website");
console.log(pageButtons["general website"]);
return pageButtons["general website"];
}
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();
}
//此功能目前僅pivix需要
expandAllWorks() {
try {
const artistHomePattern = /^https:\/\/www.pixiv.net\/users\/[0-9]*$/;
if (artistHomePattern && artistHomePattern.test(self.location.href)) {
self.history.replaceState(null, null, self.location.href + "/artworks?p=1");
}
} catch (e) {
}
}
setEventListeners() {
this.scrollHandler = () => this.handleScroll();
this.keyPressHandler = (event) => this.handleKeyPress(event);
self.addEventListener("keypress", this.keyPressHandler);
this.expandAllWorks();
//console.log("開始聆聽");
}
handleScroll(scrollThreshold=3) {
const isBottom = document.documentElement.scrollHeight - self.innerHeight - self.pageYOffset <= this.scrollThreshold;
if (isBottom) {
this.toNextPage();
console.log("滾輪下一頁");
}
if (self.pageYOffset <= 0) {
this.toPrevPage();
console.log("滾輪上一頁");
}
}
handleKeyPress(event) {
let prevPageUpper = this.Menu.pageKey[0].toUpperCase();
let nextPageUpper = this.Menu.pageKey[1].toUpperCase();
let prevPageLower = this.Menu.pageKey[0].toLowerCase();
let nextPageLower = this.Menu.pageKey[1].toLowerCase();
if (event.key == prevPageUpper || event.key == prevPageLower) {
this.toPrevPage();
console.log("按鍵上一頁");
} else if (event.key == nextPageUpper || event.key == nextPageLower) {
this.toNextPage();
console.log("按鍵下一頁");
}
}
}
class inputCustomMenu{
constructor() {
this.registerMenuCommand(this);
this.loadPageKey();
}
async inputModeSwitch() {
//console.log("切換模式"+this.buttonClicked);
if (this.buttonClicked==true) {
self.removeEventListener("scroll", this.scrollHandler);
self.addEventListener("keypress", this.keyPressHandler);
console.log("切換為按鍵翻頁模式");
this.buttonClicked=false;
} else {
self.addEventListener("scroll", this.scrollHandler);
self.removeEventListener("keypress", this.keyPressHandler);
console.log("切換為滾輪翻頁模式");
this.buttonClicked=true;
}
}
async customizeKeys() {
//console.log(this.getFeatureMessageLocalization("EnterNewPrevPageLetter"));
const newPrevPage = prompt(this.getFeatureMessageLocalization("EnterNewPrevPageLetter"));
const newNextPage = prompt(this.getFeatureMessageLocalization("EnterNewNextPageLetter"));
if (newPrevPage && newPrevPage.length === 1 && newNextPage && newNextPage.length === 1) {
this.pageKey[0] = newPrevPage;
this.pageKey[1] = newNextPage;
this.savePageKey();
} else {
alert(this.getFeatureMessageLocalization("CustomKeyError"));
}
}
loadPageKey() {
this.pageKey = GM_getValue("pageKey", ["Z", "X"]);
}
savePageKey() {
GM_setValue("pageKey", this.pageKey);
}
getFeatureMessageLocalization(word) {
let display = {
"zh-TW": {
"TogglePageMode": "切換翻頁模式",
"CustomizeKeys": "自訂按鍵",
"EnterNewPrevPageLetter": "請輸入要替換上一頁的一個英文字母或數字:",
"EnterNewNextPageLetter": "請輸入要替換下一頁的一個英文字母或數字:",
"CustomKeyError": "自訂按鍵錯誤:輸入無效,請確保輸入一個英文字母或數字。"
},
"en": {
"TogglePageMode": "Toggle Page Navigation Mode",
"CustomizeKeys": "Customize Keys",
"EnterNewPrevPageLetter": "Enter a single English letter or number to replace the previous page:",
"EnterNewNextPageLetter": "Enter a single English letter or number to replace the next page:",
"CustomKeyError": "Custom Key Error: Invalid input, please ensure to input a single English letter or number."
},
"ja": {
"TogglePageMode": "ページ切り替えモードの切り替え",
"CustomizeKeys": "キーのカスタマイズ",
"EnterNewPrevPageLetter": "前のページを置き換える英字または數字を 1 つ入力してください:",
"EnterNewNextPageLetter": "次のページを置き換える英字または數字を 1 つ入力してください:",
"CustomKeyError": "カスタムキーエラー:入力が無効です。単一の英文字または數字を入力してください。"
}
};
//console.log(navigator.language);
//console.log(display[navigator.language][word]);
return display[navigator.language][word];
}
registerMenuCommand(instance) {
//console.log("註冊選單");
GM_registerMenuCommand(instance.getFeatureMessageLocalization("TogglePageMode"), () => instance.inputModeSwitch());
GM_registerMenuCommand(instance.getFeatureMessageLocalization("CustomizeKeys"), () => instance.customizeKeys());
}
}
class PageButtonsOfDomain{
constructor(){
this.allPageButtons = GM_getValue("PageButtons",{
"www.pixiv.net": {
"nextButton": ".sc-d98f2c-0.sc-xhhh7v-2.cCkJiq.sc-xhhh7v-1-filterProps-Styled-Component.kKBslM",
"prevButton": ".sc-d98f2c-0.sc-xhhh7v-2.cCkJiq.sc-xhhh7v-1-filterProps-Styled-Component.kKBslM",
},
"exhentai.org": {
"nextButton": "#dnext",
"prevButton": "#dprev",
},
"e-hentai.org": {
"nextButton": "#dnext",
"prevButton": "#dprev",
},
"www.asmr.one": {
"nextButton": ".ant-pagination-item-link",
"prevButton": ".ant-pagination-item-link",
},
"www.goddessfantasy.net": {
"nextButton": ".navPages",
"prevButton": ".navPages",
},
"general website": {
"nextButton": ".next",
"prevButton": ".prev",
},
})
console.log(this.allPageButtons);
}
getAllPageButtons(){
return this.allPageButtons;
}
addPageButtons(domain, buttons) {
this.allPageButtons[domain] = buttons;
this.savePageButtonsToStorage(this.allPageButtons);
}
getPageButtons(domain) {
return this.pageButtonsOfDomain[domain];
}
savePageButtonsToStorage(pageButtons) {
GM_setValue('pageButtons', JSON.stringify(pageButtons));
}
getPageButtonsFromStorage() {
let storedPageButtons = GM_getValue('pageButtons');
return storedPageButtons ? JSON.parse(storedPageButtons) : {};
}
getFeatureMessageLocalization(word) {
let display = {
"zh-TW": {
"addNewDomainSupper": "新增支援網站",
},
"en": {
"addNewDomainSupper": "Add new supper domain",
},
"ja": {
"addNewDomainSupper": "サポートサイトを追加",
}
};
return display[navigator.language][word];
}
}
/* class addNewDomainSupper {
constructor() {
this.floatingWindow = this.createFloatingWindow();
this.setupListeners();
//this.registerMenuCommand(this);
}
registerMenuCommand(instance) {
GM_registerMenuCommand(instance.getFeatureMessageLocalization("addNewDomainSupper"), () => instance.createFloatingWindow())
}
getFeatureMessageLocalization(word) {
let display = {
"zh-TW": {
"addNewDomainSupper": "新增支援網站",
},
"en": {
"addNewDomainSupper": "Add new supper domain",
},
"ja": {
"addNewDomainSupper": "サポートサイトを追加",
}
};
return display[navigator.language][word];
}
createFloatingWindow() {
const floatingWindow = document.createElement('div');
floatingWindow.style.position = 'fixed';
floatingWindow.style.top = '50%';
floatingWindow.style.left = '50%';
floatingWindow.style.transform = 'translate(-50%, -50%)';
floatingWindow.style.background = '#fff';
floatingWindow.style.border = '1px solid #000';
floatingWindow.style.color = '000';
floatingWindow.style.padding = '20px';
document.body.appendChild(floatingWindow);
return floatingWindow;
}
setupListeners() {
this.floatingWindow.addEventListener('click', this.handleClick.bind(this));
}
handleClick(event) {
const target = event.target;
if (target.tagName === 'BUTTON') {
const action = target.textContent;
if (action === '確認') {
this.confirm();
} else if (action === '取消') {
this.cancel();
}
}
}
confirm() {
const prevInput = this.floatingWindow.querySelector('.prev-input');
const nextInput = this.floatingWindow.querySelector('.next-input');
const selectOption = this.floatingWindow.querySelector('.select-option');
const selectedOption = selectOption.value;
const prevValue = prevInput.value;
const nextValue = nextInput.value;
const domain = window.location.hostname;
let buttons = {};
if (selectedOption === 'class') {
buttons = {
prevButton: `.${prevValue}`,
nextButton: `.${nextValue}`
};
} else if (selectedOption === 'id') {
buttons = {
prevButton: `#${prevValue}`,
nextButton: `#${nextValue}`
};
}
PageButtonsOfDomain.addPageButtons(domain, buttons);
this.floatingWindow.remove();
}
cancel() {
this.floatingWindow.remove();
}
} */
//const transferStudent = new addNewDomainSupper();
const johnTheAlmondHolder = new PageInputNavigation();