EH – GID Navigation Scrollbar

Visualize GID and add the ability to easily jump or scrobble (since the old page navigation is going to be no more)

Version vom 03.11.2022. Aktuellste Version


    // ==UserScript==
    // @name         EH – GID Navigation Scrollbar
    // @namespace    fabulous.cupcake.jp.net
    // @version      2022.11.03.4
    // @description  Visualize GID and add the ability to easily jump or scrobble (since the old page navigation is going to be no more)
    // @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();