diff --git a/ehentai_better_viewer.user.js b/ehentai_better_viewer.user.js index 0af15b2..06b2444 100644 --- a/ehentai_better_viewer.user.js +++ b/ehentai_better_viewer.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name E-Hentai better viewer // @namespace https://github.com/lifegpc/userscript -// @version 0.2.0 +// @version 0.2.1 // @description Add a viewer to view original picture on website. // @author lifegpc // @match https://*.e-hentai.org/s/*/* @@ -14,34 +14,136 @@ // @run-at document-start // ==/UserScript== GM_addStyle(GM_getResourceText("viewercss")); -let cur_img = null; -let obs = new MutationObserver((list) => { - for (const m of list) { - if (m.type == 'childList') { - m.removedNodes.forEach(v => { - if (cur_img != null && v == cur_img) { - load(); - cur_img = null; - } - }) +function indirectEval(script) { + return eval(`"use strict";${script}`); +} +function find_script() { + let cols = document.getElementsByTagName("script"); + for (let col of cols) { + if (col.innerHTML.startsWith("var ")) { + return col.innerHTML; } } -}) +} +let base_url = undefined; +let cur_img = null; +let cur_viewer = null; +let script_text = undefined; +let api_url = undefined; +let gid = undefined; +let showkey = undefined; +let img_keys = {}; +let cur_page = null; +let total_page = null; +function get_api_url() { + if (api_url !== undefined) return api_url; + if (script_text === undefined) { + script_text = find_script(); + } + if (script_text === undefined) return undefined; + api_url = indirectEval(`${script_text};api_url`); + return api_url; +} +function get_base_url() { + if (base_url !== undefined) return base_url; + base_url = new URL(document.location.href) + return base_url; +} +function get_gid() { + if (gid !== undefined) return gid; + if (script_text === undefined) { + script_text = find_script(); + } + if (script_text === undefined) return undefined; + gid = indirectEval(`${script_text};gid`); + return gid; +} +function get_showkey() { + if (showkey !== undefined) return showkey; + if (script_text === undefined) { + script_text = find_script(); + } + if (script_text === undefined) return undefined; + showkey = indirectEval(`${script_text};showkey`); + return showkey; +} +function api_call(data) { + return new Promise((resolve, reject) => { + let api_url = get_api_url(); + if (!api_url) { + reject("api_url not found."); + return; + } + let xhr = new XMLHttpRequest(); + xhr.open("POST", api_url); + xhr.withCredentials = true; + xhr.onload = (ev) => { + resolve(xhr); + }; + xhr.onerror = (ev) => { + reject(ev); + } + xhr.onabort = (ev) => { + reject(ev); + } + xhr.send(JSON.stringify(data)); + }) +} +function genUrl(gid, imgkey, page) { + return new URL(`/s/${imgkey}/${gid}-${page}`, get_base_url()) +} +async function loadPage(page) { + let gid = get_gid(); + if (!gid) throw Error("gid not found."); + let showkey = get_showkey(); + if (!showkey) throw Error("showkey not found."); + let imgkey = img_keys[page]; + if (!imgkey) return; + history.pushState({ page, imgkey }, document.title, genUrl(gid, imgkey, page).toString()); + let xhr = await api_call({ method: "showpage", gid, page, imgkey, showkey }); + let a = JSON.parse(xhr.responseText); + if (cur_viewer) cur_viewer.destroy(); + document.getElementById("i1").style.width = a.x + "px"; + document.getElementById("i2").innerHTML = a.n + a.i; + document.getElementById("i3").innerHTML = a.i3; + document.getElementById("i4").innerHTML = a.i + a.n; + document.getElementById("i5").innerHTML = a.i5; + document.getElementById("i6").innerHTML = a.i6; + document.getElementById("i7").innerHTML = a.i7; + update_window_extents(parseInt(a.x), parseInt(a.y)); + load(); +} +function replaceLink(a) { + let ohtml = a.innerHTML; + let na = document.createElement('a'); + let matched = a.href.match(/e[x-]hentai\.org\/s\/([^\/]+)\/\d+-(\d+)/); + if (!matched) return; + let num = parseInt(matched[2]); + let img_key = matched[1]; + img_keys[num] = img_key; + na.innerHTML = ohtml; + na.addEventListener("click", () => { loadPage(num); }); + a.replaceWith(na); +} let load = () => { let img = document.getElementById("img"); if (img == null) { setTimeout(load, 100); return; } + cur_page = parseInt(document.querySelector('#i2 span').innerText); + total_page = parseInt(document.querySelector('#i2 span:last-child').innerText); cur_img = img; let parent = img.parentElement; parent.replaceWith(img); - obs.observe(img.parentElement, {'childList': true, 'subtree': true}); let options = { title: () => { return document.getElementsByTagName("h1")[0].innerText }, - navbar: false + keyboard: false, + navbar: false, + loop: false, + toolbar: { prev: { show: true, click: prevImage }, zoomIn: { show: true }, zoomOut: { show: true }, oneToOne: { show: true }, next: { show: true, click: nextImage } } }; /**@type {HTMLAnchorElement}*/ let original = document.querySelector("#i7>a"); @@ -58,6 +160,74 @@ let load = () => { console.log("Inited complete"); await viewer.show(); }; + cur_viewer = viewer; img.addEventListener("click", click); + let links = document.querySelectorAll(".sn a"); + for (let i of links) { + replaceLink(i); + } + console.log(img_keys); }; window.addEventListener("DOMContentLoaded", load); +window.addEventListener("DOMContentLoaded", () => { + // Remove default keyboard binding. + // Add custom event listener. + let scr = document.createElement("script"); + scr.innerHTML = 'document.onkeydown = () => {};document.addEventListener("update_window_extents", (ev) => {xres=ev.xres;yres=ev.yres;update_window_extents();});'; + document.head.append(scr); +}); +function zoomIn() { + if (cur_viewer) cur_viewer.zoom(-0.1); +} +function zoomOut() { + if (cur_viewer) cur_viewer.zoom(0.1); +} +function moveDown() { + if (cur_viewer) cur_viewer.move(0, -10); +} +function moveUp() { + if (cur_viewer) cur_viewer.move(0, 10); +} +function moveLeft() { + if (cur_viewer) cur_viewer.move(10, 0); +} +function moveRight() { + if (cur_viewer) cur_viewer.move(-10, 0); +} +function prevImage() { + if (cur_page === null) return; + loadPage(cur_page - 1) +} +function nextImage() { + if (cur_page === null) return; + loadPage(cur_page + 1) +} +function update_window_extents(xres, yres) { + let ev = new Event("update_window_extents"); + ev.xres = xres; + ev.yres = yres; + document.dispatchEvent(ev); +} +window.addEventListener("keydown", (e) => { + if (!e.ctrlKey && !e.shiftKey) { + if (e.key == "ArrowDown") { + zoomIn(); + } else if (e.key == "ArrowUp") { + zoomOut(); + } else if (e.key == "ArrowLeft") { + prevImage(); + } else if (e.key == "ArrowRight") { + nextImage(); + } + } else if (e.ctrlKey && !e.shiftKey) { + if (e.key == "ArrowDown") { + moveDown(); + } else if (e.key == "ArrowUp") { + moveUp(); + } else if (e.key == "ArrowLeft") { + moveLeft(); + } else if (e.key == "ArrowRight") { + moveRight(); + } + } +})