Skip to content

Instantly share code, notes, and snippets.

@Gkjsdll
Last active March 16, 2023 01:49
Show Gist options
  • Save Gkjsdll/0b78b67294603f1325bd9adf5d2ba84f to your computer and use it in GitHub Desktop.
Save Gkjsdll/0b78b67294603f1325bd9adf5d2ba84f to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Comics key navigation
// @namespace https://gkjsdll.com/
// @version 0.11.0
// @description Add next & previous keybinds to multiple comic sites.
// @author Zack (Gkjsdll) Winchell
// @icon https://i.imgur.com/mBU8lYf.png
// @match *://alpha-scans.org/*
// @match *://www.alpha-scans.org/*
// @match *://www.asurascans.com/*
// @match *://asura.gg/*
// @match *://cosmicscans.com/*
// @match *://edelgardescans.com/comics/*
// @match *://flamescans.org/*
// @match *://imperfectcomic.org/*
// @match *://en.leviatanscans.com/*/manga/*
// @match *://leviatanscans.com/*/manga/*
// @match *://lhtranslation.net/manga*
// @match *://luminousscans.com/*
// @match *://mangakakalot.fun/*
// @match *://manganelo.com/chapter/*
// @match *://manhwafreak.com/*
// @match *://methodscans.com/comics/*
// @match *://mm-scans.org/manga/*
// @match *://reader.pmscans.com/*
// @match *://realmscans.com/*
// @match *://reset-scans.com/manga/*
// @match *://reaperscans.com/comics/*
// @match *://skscans.com/manga/*
// @match *://tritinia.com/manga/*
// @match *://void-scans.com/*
// @match *://zeroscans.com/comics/*
// @grant unsafeWindow
// ==/UserScript==
(function () {
'use strict';
const navFunctions = {
'alpha-scans.org': {
next: () => document.querySelector('a.ch-next-btn').click(),
previous: () => document.querySelector('a.ch-prev-btn').click(),
},
'asurascans.com': {
next: () => document.querySelector('a.ch-next-btn').click(),
previous: () => document.querySelector('a.ch-prev-btn').click(),
},
'cosmicscans.com': {
next: () => document.querySelector('a.ch-next-btn').click(),
previous: () => document.querySelector('a.ch-prev-btn').click(),
},
'edelgardescans.com': {
next: () => document.querySelector('a i.fa-arrow-right').parentElement.click(),
previous: () => document.querySelector('a i.fa-arrow-left').parentElement.click(),
},
'flamescans.org': {
next: () => document.querySelector('.ch-next-btn').click(),
previous: () => document.querySelector('.ch-prev-btn').click(),
},
'imperfectcomic.org': {
next: () => document.querySelector('a.ch-next-btn').click(),
previous: () => document.querySelector('a.ch-prev-btn').click(),
},
'leviatanscans.com': {
next: () => document.querySelector('.nav-next a.next_page').click(),
previous: () => document.querySelector('.nav-previous a.prev_page').click(),
},
'lhtranslation.net': {
next: () => document.querySelector('a.next_page').click(),
previous: () => document.querySelector('a.prev_page').click(),
},
'luminousscans.com': {
next: () => document.querySelector('a.ch-next-btn').click(),
previous: () => document.querySelector('a.ch-prev-btn').click(),
},
'mangakakalot.fun': {
next: () => document.querySelector('li.next a').click(),
previous: () => document.querySelector('li.previous a').click(),
validateUrl: () => window.location.pathname.startsWith('/chapter/'),
},
'manganelo.com': {
next: () => document.querySelector('a.navi-change-chapter-btn-next').click(),
previous: () => document.querySelector('a.navi-change-chapter-btn-prev').click(),
},
'manhwafreak.com': {
next: () => document.querySelector('a.ch-next-btn').click(),
previous: () => document.querySelector('a.ch-prev-btn').click(),
},
'methodscans.com': {
next: () => document.querySelector('a i.fa-arrow-right').parentElement.click(),
previous: () => document.querySelector('a i.fa-arrow-left').parentElement.click(),
},
'mm-scans.org': {
next: () => document.querySelector('a.btn.next_page').click(),
previous: () => document.querySelector('a.btn.prev_page').click(),
},
'pmscans.com': {
next: () => document.querySelector('a.ch-next-btn').click(),
previous: () => document.querySelector('a.ch-prev-btn').click(),
},
'realmscans.com': {
next: () => document.querySelector('a.ch-next-btn').click(),
previous: () => document.querySelector('a.ch-prev-btn').click(),
},
'reaperscans.com': {
next: () => document.querySelector('svg.fa-arrow-right-long').parentElement.click(),
previous: () => document.querySelector('svg.fa-arrow-left-long').parentElement.click(),
},
'reset-scans.com': {
next: () => document.querySelector('.btn.next_page').click(),
previous: () => document.querySelector('.btn.prev_page').click(),
},
'skscans.com': {
next: () => document.querySelector('.nav-next').click(),
previous: () => document.querySelector('.nav-previous').click(),
},
'tritinia.com': {
next: () => document.querySelector('a.next_page').click(),
previous: () => document.querySelector('a.prev_page').click(),
},
'void-scans.com': {
next: () => document.querySelector('a.ch-next-btn').click(),
previous: () => document.querySelector('a.ch-prev-btn').click(),
},
'zeroscans.com': {
// FIXME: first and last chapter have different numbers of a tags in .d-flex
next: () => {
// document.querySelector('.v-footer .row>.d-flex>a:nth-of-type(2)').click()
const pagePaths = Array.from(document.querySelectorAll('a svg path'));
const nextPaths = [
'M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z', // in-page
'M5.59,7.41L10.18,12L5.59,16.59L7,18L13,12L7,6L5.59,7.41M16,6H18V18H16V6Z', // in-footer
];
const nextPathsInPage = pagePaths.filter((path) => nextPaths.includes(path.attributes.d.value));
nextPathsInPage[0].closest('a').click();
},
previous: () => {
// document.querySelector('.v-footer .row>.d-flex>a:nth-of-type(1)').click()
const pagePaths = Array.from(document.querySelectorAll('a svg path'));
const previousPaths = [
'M15.41,16.58L10.83,12L15.41,7.41L14,6L8,12L14,18L15.41,16.58Z', // in-page
'M18.41,16.59L13.82,12L18.41,7.41L17,6L11,12L17,18L18.41,16.59M6,6H8V18H6V6Z', // in-footer
];
const previousPathsInPage = pagePaths.filter((path) => previousPaths.includes(path.attributes.d.value));
previousPathsInPage[0].closest('a').click();
},
},
};
navFunctions['asura.gg'] = navFunctions['asurascans.com'];
const domainPattern = /^(?:.*\.){0,1}(.*\..*)$/;
const hostname = window.location.hostname;
const domain = hostname.match(domainPattern)[1];
const { next, previous, validateUrl } = navFunctions[domain];
const onKeyPress = (keypress) => {
if (validateUrl?.() === false) {
console.log('url failed additional validation, ignoring key events');
return;
}
const nextTest = /^([dD]|ArrowRight)$/;
if (nextTest.test(keypress.key)) {
next();
return;
}
const previousTest = /^([aA]|ArrowLeft)$/;
if (previousTest.test(keypress.key)) {
previous();
return;
}
};
document.addEventListener('keydown', onKeyPress);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment