Skip to content

Instantly share code, notes, and snippets.

@sorz
Last active November 11, 2022 01:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sorz/714b547ce2101866075aeeffe77675f8 to your computer and use it in GitHub Desktop.
Save sorz/714b547ce2101866075aeeffe77675f8 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name E-Hentai Prefetch Next Page
// @namespace Violentmonkey Scripts
// @match https://e-hentai.org/s/*
// @match https://exhentai.org/s/*
// @grant none
// @version 0.2.0
// @author sorz
// @description Prefetch image file on the next page for faster browsing.
// ==/UserScript==
const MAX_PREFETCH_PAGES = 4;
// page no -> response from api_response
const pageRespCache = new Map();
// page no. -> image key
const pageImgKeyCache = new Map();
const currentPageNo = () => history.state.page;
const getPageNoImgKey = (doc) => {
let [_, page, imgKey] = doc.querySelector('a#next')
.attributes.onclick.value
.match(/load_image\((\d+), '([0-9a-f]+)'\)/);
return [parseInt(page), imgKey];
};
const template = (html) => {
const template = document.createElement('template');
template.innerHTML = html;
return template.content;
}
function prefetchPage(pageNo, n) {
const onResponse = (resp) => {
const [nextPageNo, nextImgKey] = getPageNoImgKey(template(resp.n));
if (!pageRespCache.has(pageNo)) {
// Cache response
pageRespCache.set(pageNo, resp);
pageImgKeyCache.set(nextPageNo, nextImgKey);
// Prefetch image file
const src = template(resp.i3).querySelector('img#img').src;
const img = new Image();
img.onload = () => console.log('image fetched', 'page', pageNo);
img.src = src;
}
if (n > 0) prefetchPage(nextPageNo, n - 1);
}
if (pageRespCache.has(pageNo)) {
onResponse(pageRespCache.get(pageNo));
return;
}
const imgKey = pageImgKeyCache.get(pageNo);
if (!imgKey) {
logging.warn('missing image key for page', pageNo);
return;
}
const request = {
method: "showpage",
gid: gid,
page: pageNo,
imgkey: imgKey,
showkey: showkey
};
const xhr = new XMLHttpRequest();
api_call(xhr, request, () => {
const resp = api_response(xhr);
if (resp == false || resp.error != undefined) return;
onResponse(resp);
});
}
function prefetchNextNPage(n) {
let [pageNo, imgKey] = getPageNoImgKey(document);
pageImgKeyCache.set(pageNo, imgKey);
prefetchPage(pageNo, n);
}
apply_json_state = new Proxy(apply_json_state, {
apply: function(target, thisArg, args) {
Reflect.apply(target, thisArg, args);
prefetchNextNPage(MAX_PREFETCH_PAGES);
}
});
load_image = new Proxy(load_image, {
apply: function(target, thisArg, [page, imgKey]) {
const resp = pageRespCache.get(page);
if (!resp) return Reflect.apply(target, thisArg, [page, imgKey]);
console.log('cached resp found', 'page', page);
history.pushState(
{
page: resp.p,
imgkey: resp.k,
json: resp,
expire: get_unixtime() + 300
},
document.title,
base_url + resp.s
);
apply_json_state(resp);
return false;
}
});
prefetchNextNPage(MAX_PREFETCH_PAGES);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment