Skip to content

Instantly share code, notes, and snippets.

@OceanS2000
Last active February 23, 2024 01:53
Show Gist options
  • Save OceanS2000/0849a0582cfae4b4771958944883b4df to your computer and use it in GitHub Desktop.
Save OceanS2000/0849a0582cfae4b4771958944883b4df to your computer and use it in GitHub Desktop.
EH Page Scrobbler
// ==UserScript==
// @name EH – Page Scrobbler
// @namespace koisato.name
// @version 2022.11.03.2
// @description Visualize GID and add the ability to easily jump or scrobble
// @author FabulousCupcake, OsenTen
// @license MIT
// @run-at document-end
// @match http*://e-hentai.org/*
// @match http*://exhentai.org/*
// @grant GM_addStyle
// ==/UserScript==
const stylesheet = `
.search-scrobbler {
width: 800px;
outline: 1px cyan dashed;
margin: 0 auto;
padding: 20px 0 0 0;
display: flex;
flex-direction: column;
gap: 0.5em;
}
.search-scrobbler .bar {
display: block;
width: 800px;
height: 25px;
border: 1px solid red;
box-sizing: border-box;
position: relative;
}
.search-scrobbler .bar .bar-cursor {
height: 100%;
background: #0f0;
}
.search-scrobbler .bar-wrapper {
display: flex;
flex-direction: column;
}
.search-scrobbler .bar-labels {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.search-scrobbler .bar-hover {
display: block;
width: 1px;
height: 100%;
background: #f0f;
position: absolute;
}
.search-scrobbler .bar-hovertext {
position: absolute;
outline: 1px solid #f0f;
top: -1.5em;
}
.search-scrobbler,
.search-scrobbler * {
outline: 0px none !important;
}
`;
const injectStylesheet = () => {
if (typeof GM_addStyle != "undefined") {
GM_addStyle(stylesheet);
} else if (typeof addStyle != "undefined") {
addStyle(stylesheet);
} else {
const stylesheetEl = document.createElement("style");
stylesheetEl.innerHTML = stylesheet;
document.body.appendChild(stylesheetEl);
}
}
const hasGalleryListTable = () => {
return !!document.querySelector(".itg.gltm, .itg.gltc, .itg.glte, .itg.gld");
}
const tryUpdateKnownMaxGID = GID => {
const url = new URL(location.href);
if (url.pathname !== "/") return;
if (url.search !== "") return;
let maxGID = 0;
if (!!document.querySelector(".itg tr .glname a")) { // Minimal and Compact
maxGID = document.querySelector(".itg tr:nth-child(2) .glname a").href.match(/\/(\d+)\//)?.[1];
} else if (!!document.querySelector(".itg tr a")) { // Extended
maxGID = document.querySelector(".itg tr:first-child a").href.match(/\/(\d+)\//)?.[1];
} else { // Thumbnail
maxGID = document.querySelector(".itg .gl1t:first-child a").href.match(/\/(\d+)\//)?.[1];
}
localStorage.setItem("EHPS-maxGID", maxGID);
}
const addPageScrobbler = () => {
const insertInitialElement = () => {
const hook = document.querySelector(".searchnav");
const maxGID = localStorage.getItem("EHPS-maxGID");
let firstGID = maxGID, lastGID = 1;
if (!!document.querySelector(".itg tr .glname a")) { // Minimal and Compact
firstGID = document.querySelector(".itg tr:nth-child(2) .glname a").href.match(/\/(\d+)\//)?.[1];
lastGID = document.querySelector(".itg tr:last-child .glname a").href.match(/\/(\d+)\//)?.[1];
} else if (!!document.querySelector(".itg tr a")) { // Extended
firstGID = document.querySelector(".itg tr:first-child a").href.match(/\/(\d+)\//)?.[1];
lastGID = document.querySelector(".itg tr:last-child a").href.match(/\/(\d+)\//)?.[1];
} else { // Thumbnail
firstGID = document.querySelector(".itg .gl1t:first-child a").href.match(/\/(\d+)\//)?.[1];
lastGID = document.querySelector(".itg .gl1t:last-child a").href.match(/\/(\d+)\//)?.[1];
}
const cursorLeftMargin = (1.0 - firstGID / maxGID) * 100;
let cursorWidth = ((firstGID - lastGID) / maxGID) * 100;
if (cursorWidth < 0.2) cursorWidth = 0.2;
const el = `
<div class="search-scrobbler">
<div class="bar-wrapper bar-full">
<div class="bar">
<div class="bar-cursor" style="width: ${cursorWidth}%; margin-left: ${cursorLeftMargin}% ">
<div class="bar-hovertext">${firstGID}</div>
</div>
</div>
<div class="bar-labels">
<div class="bar-max">${maxGID}</div>
<div class="bar-min">1</div>
</div>
</div>
</div>`;
hook.insertAdjacentHTML("beforebegin", el);
}
const addEventListeners = () => {
const addHoverElement = offset => {
if (offset < 2) return;
document.querySelector(".bar-hover")?.remove();
const maxGID = localStorage.getItem("EHPS-maxGID");
const width = 800;
const hoverGID = ((1.0 - offset / 800) * maxGID).toFixed(0);
const url = new URL(location.href);
url.searchParams.set("next", hoverGID);
const hook = document.querySelector(".bar-full .bar");
const el = `
<a class="bar-hover" href="${url}" style="left: ${offset-2}px; width: 2px">
<div class="bar-hovertext">${hoverGID}</div>
</a>`;
hook.insertAdjacentHTML("afterbegin", el);
}
const handler = e => {
addHoverElement(e.layerX);
}
const el = document.querySelector(".bar-full .bar");
el.addEventListener("mousemove", handler);
}
insertInitialElement();
addEventListeners();
}
const main = () => {
if (!hasGalleryListTable()) return;
tryUpdateKnownMaxGID();
injectStylesheet();
addPageScrobbler();
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment