Greasy Fork

Greasy Fork is available in English.

Chapter Changer + Smooth Scrolling

For Mangakakalot & Manganelo & ReaperScans

当前为 2021-01-15 提交的版本,查看 最新版本

// ==UserScript==
// @name         Chapter Changer + Smooth Scrolling
// @description  For Mangakakalot & Manganelo & ReaperScans
// @version      0.81
// @namespace    http://greasyfork.icu/en/users/55535-sllypper
// @author       sllypper
// @match        https://mangakakalot.com/chapter/*
// @match        https://manganelo.com/chapter/*
// @match        https://reaperscans.com/comics/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Smooth Scrolling Settings

    // how much it scrolls every tick (in pixels)
    let scrollAmount = 64;

    // how long between ticks (in ms)
    // 16.666667 = 60 frames per second
    let scrollPeriod = 33.33;

    // how much holding Shift will multiply the scrollAmount
    let shiftSpeedMod = 2.0;

    //

    let implementations = [
        {
            name: 'mangakakalot',
            match: '^https?://mangakakalot.com/chapter/*',
            nextchap: function(prev) {
                let nextButtonSel = '.btn-navigation-chap > .back';
                let prevButtonSel = '.btn-navigation-chap > .next';

                if (!prev) return document.querySelector(nextButtonSel);
                return document.querySelector(prevButtonSel);
            },
            prevchap: function() {
                return this.nextchap(true);
            }
        },
        {
            name: 'manganelo',
            match: '^https?://manganelo.com/chapter/*',
            nextchap: function(prev) {
                let nextButtonSel = '.navi-change-chapter-btn-next';
                let prevButtonSel = '.navi-change-chapter-btn-prev';

                if (!prev) return document.querySelector(nextButtonSel);
                return document.querySelector(prevButtonSel);
            },
            prevchap: function() {
                return this.nextchap(true);
            }
        },
        {
            name: 'reaperscans',
            match: '^https?://reaperscans.com/comics/*',
            nextchap: function(prev) {
                let buttons = document.querySelector('div.d-flex:nth-child(4)');

                if (!prev) return buttons.querySelector('div:nth-child(3) > a');
                return buttons.querySelector('div:nth-child(1) > a');
            },
            prevchap: function() {
                return this.nextchap(true);
            }
        }
    ];


    let clickEl = el => {
        if (!el) return;
        el.click();
    }

    let loadHotkeys = imp => {
        window.addEventListener('keydown', event => {
            switch(event.code) {
                case 'KeyC':
                    clickEl(imp.nextchap());
                    break;
                case 'KeyZ':
                    clickEl(imp.prevchap());
                    break;
            }
        });
    }

    let pageUrl = window.location.href;

    implementations.some(function(imp) {
        if (imp.match && (new RegExp(imp.match, 'i')).test(pageUrl)) {
            loadHotkeys(imp);
            return true;
        }
    });

    // Scroller

    const states = {
        NONE: 0,
        UP: 1,
        SHIFTUP: 2,
        DOWN: 3,
        SHIFTDOWN: 4
    }
    let scrollState = states.NONE;
    let currScrollAction = null;
/*
    let buttonsContainer = document.getElementsByClassName('navi-change-chapter-btn');
    if (buttonsContainer.length === 0) {
        buttonsContainer = document.getElementsByClassName('btn-navigation-chap');
        if (buttonsContainer.length === 0) { console.log('Chapter Changer + Smooth Scrolling ERROR: No Navigation Buttons found'); return; }
    }

    let buttons = buttonsContainer[0].childNodes;

    let prevButton = buttons[0];
    let nextButton = buttons[buttons.length-1];

    // if there's only one button
    if (buttons.length != 2) {
        // check if it's the next button
        // mangakakalot has "back" and "next" button classes are switched around
        if (buttons[0].classList.contains("back") || buttons[0].classList.contains("navi-change-chapter-btn-next")) {
            // then we're in chapter 1 and there's no prev button
            prevButton = null;
        } else {
            // else we're in the last chapter and there's no next button
            nextButton = null;
        }
    } */

    document.addEventListener("keydown", event => {
        if (event.code === "KeyW" || event.code === "KeyK") {
            if (scrollState !== states.UP && !event.shiftKey) {
                clearScrollAction();
                scrollState = states.UP;
                scrollAction(-scrollAmount);
            } else if (scrollState !== states.SHIFTUP && event.shiftKey) {
                clearScrollAction();
                scrollState = states.SHIFTUP;
                scrollAction(-scrollAmount*shiftSpeedMod);
            }
        } else if (event.code === "KeyS" || event.code === "KeyJ") {
            if (scrollState !== states.DOWN && !event.shiftKey) {
                clearScrollAction();
                scrollState = states.DOWN;
                scrollAction(scrollAmount);
            } else if (scrollState !== states.SHIFTDOWN && event.shiftKey) {
                clearScrollAction();
                scrollState = states.SHIFTDOWN;
                scrollAction(scrollAmount*shiftSpeedMod);
            }
/*         } else if (event.code === "KeyC" && nextButton != null) {
            nextButton.click();
        } else if (event.code === "KeyZ" && prevButton != null) {
            prevButton.click(); */
        }
    });

    document.addEventListener("keyup", event => {
        if (event.code === "KeyW" || event.code === "KeyK") {
            clearScrollAction();
        } else if (event.code === "KeyS" || event.code === "KeyJ") {
            clearScrollAction();
        } else if (event.key === "Shift") {
            clearScrollAction();
        }
    });

    function scrollAction(amount) {
        currScrollAction = setInterval(() => {
            window.scrollBy(0, amount);
        }, scrollPeriod)
    }

    function clearScrollAction() {
        clearInterval(currScrollAction);
        currScrollAction = null;
        scrollState = states.NONE;
    }

})();