Hentai Reader

A generalized multi-site reading framework. Provides an enhanced reading experience with infinite scroll, full-screen reader mode, and smart image loading for E-Hentai, 18comic, 4KHD, etc.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name               Hentai Reader
// @name:zh-CN         绅士阅读器
// @namespace          http://tampermonkey.net/
// @version            3.0.0
// @author             Viki
// @description        A generalized multi-site reading framework. Provides an enhanced reading experience with infinite scroll, full-screen reader mode, and smart image loading for E-Hentai, 18comic, 4KHD, etc.
// @description:zh-CN  多站点通用阅读框架,为 E-Hentai、18comic、4KHD 等提供无限滚动、全屏阅读模式、智能预取与硬件加速解码
// @license            MIT
// @icon               data:image/png;base64,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
// @homepageURL        https://github.com/Leovikii/Hentai-Reader
// @match              https://e-hentai.org/g/*
// @match              https://exhentai.org/g/*
// @match              https://e-hentai.org/s/*
// @match              https://exhentai.org/s/*
// @match              *://*.4khd.com/*
// @match              *://*.xxtt.ink/*
// @match              *://*.uuss.uk/*
// @match              *://*.ssuu.uk/*
// @match              *://*.18comic.vip/*
// @match              *://*.18comic.ink/*
// @grant              GM_addStyle
// @grant              GM_getValue
// @grant              GM_registerMenuCommand
// @grant              GM_setValue
// @grant              unsafeWindow
// ==/UserScript==

(function () {
  'use strict';

  const d=new Set;const importCSS = async e=>{d.has(e)||(d.add(e),(t=>{typeof GM_addStyle=="function"?GM_addStyle(t):(document.head||document.documentElement).appendChild(document.createElement("style")).append(t);})(e));};

  importCSS(" *,:before,:after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }::backdrop{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: } ");

  const stylesCss = ':root{--accent: #F596AA;--accent-hover: #F7ABBE}html.scroll-mode{background-color:#111!important;color:#ccc!important;overflow-x:hidden}html.scroll-mode body{background-color:#111!important;color:#ccc!important;margin:0;overflow:visible!important}html.scroll-mode #gdt{display:flex;flex-direction:column;align-items:center;width:100%;max-width:1200px;margin:auto;padding-bottom:100px}.page-batch{width:100%;display:flex;flex-direction:column;align-items:center;margin-bottom:60px}.r-img{display:block;width:auto;max-width:100%;margin-bottom:20px;background:transparent;box-shadow:0 0 20px #00000080;position:relative}.r-ph{color:#555;margin-bottom:50px;text-align:center;min-height:400px;display:flex;align-items:center;justify-content:center;font-family:sans-serif;font-size:18px;border:1px dashed #333;width:100%;flex-direction:column;gap:10px}.r-ph.loading{color:#888;border-color:#555}.r-ph.error{color:#d44;border-color:#d44}.retry-btn{padding:8px 16px;background:#333;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:14px;margin-top:10px}.retry-btn:hover{background:#555}.sp-virtualized{content-visibility:hidden}.float-control{position:fixed;right:30px;bottom:30px;z-index:2147483647;display:flex;flex-direction:row;align-items:center;transition:opacity .3s,transform .3s;-webkit-user-select:none;user-select:none;opacity:.4}.float-control:hover{opacity:1}.float-control.hidden{opacity:0;pointer-events:none}.side-btn.top-btn{position:absolute;bottom:calc(100% + 10px);left:50%;transform:translate(-50%);opacity:.3;pointer-events:auto}.float-control:hover .side-btn.top-btn{opacity:.8}.side-btn.top-btn:hover{opacity:1!important;background:#555;transform:translate(-50%) scale(1.1)}.side-btn{width:36px;height:36px;background:#333;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .3s;opacity:0;pointer-events:none}.float-control:hover .side-btn{opacity:1;pointer-events:auto}.side-btn:hover{background:#555;transform:scale(1.1)}.side-btn svg{width:18px;height:18px;fill:#fff}.side-btn.active{background:var(--accent)}.side-btn.active:hover{background:var(--accent-hover)}.auto-play-btn.hidden{display:none}.circle-control{position:relative;width:50px;height:50px;background:#1a1a1a;border:2px solid #555;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .3s;box-shadow:0 4px 12px #00000080;margin:0 6px}.circle-control:hover{border-color:#888;box-shadow:0 6px 16px #000000b3;transform:scale(1.05)}.circle-control svg{width:24px;height:24px;fill:#fff}.settings-btn{cursor:pointer}.settings-panel{position:absolute;bottom:calc(100% + 10px);right:0;background:#1a1a1a;border:1px solid #555;border-radius:8px;padding:12px;min-width:180px;opacity:0;pointer-events:none;transition:all .3s;box-shadow:0 4px 12px #00000080;transform:translateY(5px)}.settings-panel.show{opacity:1;pointer-events:auto;transform:translateY(0)}.settings-item{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;font-size:13px;color:#ccc}.settings-item:last-child{margin-bottom:0}.settings-label{margin-right:10px;white-space:nowrap}.toggle-switch{width:40px;height:20px;background:#333;border-radius:10px;position:relative;cursor:pointer;transition:background .3s}.toggle-switch.on{background:var(--accent)}.toggle-slider{width:16px;height:16px;background:#fff;border-radius:50%;position:absolute;top:2px;left:2px;transition:left .3s}.toggle-switch.on .toggle-slider{left:22px}.interval-input{width:60px;background:#333;border:1px solid #555;border-radius:4px;color:#fff;padding:4px 8px;font-size:12px;text-align:center}.interval-input:focus{outline:none;border-color:#888}.single-page-overlay{position:fixed;top:0;right:0;bottom:0;left:0;width:100vw;height:100vh;background-color:#000!important;z-index:2147483646;display:none;align-items:center;justify-content:center}.single-page-overlay.active{display:flex}.sp-image-container{width:100%;height:100%;display:flex;align-items:center;justify-content:center;position:relative}.sp-current-image{width:100%;height:100%;object-fit:contain;-webkit-user-select:none;user-select:none;transition:opacity .1s}.sp-current-image:not([src]),.sp-current-image[src=""]{opacity:0}.sp-close-btn{position:absolute;top:20px;right:20px;width:40px;height:40px;background:#333c;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:24px;color:#fff;transition:all .3s;z-index:10}.sp-close-btn:hover{background:#555555e6;transform:scale(1.1)}.sp-sidebar-track{position:absolute;right:12px;top:10%;width:12px;height:80%;background:#2828284d;border-radius:6px;z-index:10;pointer-events:none;opacity:0;transition:opacity .3s,background .3s}.sp-sidebar-track.active{opacity:1;pointer-events:auto}.sp-sidebar-track:hover{background:#32323280}.sp-sidebar-thumb{position:absolute;left:0;width:100%;min-height:60px;background:#fff6;border-radius:6px;transition:background .3s;cursor:grab;-webkit-user-select:none;user-select:none}.sp-sidebar-thumb:hover{background:#fff9}.sp-sidebar-thumb:active{cursor:grabbing;background:#ffffffb3}.sp-sidebar-label{position:absolute;right:calc(100% + 16px);top:50%;transform:translateY(-50%);background:#1a1a1af2;padding:8px 14px;border-radius:8px;color:#fff;font-family:monospace;font-size:14px;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .3s;box-shadow:0 2px 8px #0000004d}.sp-sidebar-track:hover .sp-sidebar-label{opacity:1}.sp-thumb-panel{position:absolute;right:12px;top:10%;max-height:80%;height:fit-content;width:116px;background:#141414f2;border-radius:8px;border:1px solid rgba(255,255,255,.1);box-shadow:-4px 4px 16px #00000080;overflow:hidden;pointer-events:none;display:flex;flex-direction:column;z-index:11;opacity:0;transform:translate(20px);transition:opacity .3s,transform .3s cubic-bezier(.2,.8,.2,1);-webkit-user-select:none;user-select:none}.sp-thumb-panel.active{opacity:1;transform:translate(0);pointer-events:auto}.sp-thumb-viewport{flex:1;min-height:0;width:100%;overflow:hidden;position:relative}.sp-thumb-content{position:relative;width:100%}.sp-thumb-item{position:absolute;left:8px;width:100px;height:72px;border-radius:4px;overflow:hidden;cursor:pointer;border:2px solid transparent;transition:border-color .15s;box-sizing:border-box}.sp-thumb-item:hover{border-color:#fff6}.sp-thumb-item.sp-thumb-active{border-color:var(--accent)}.sp-thumb-img{width:100%;height:100%;object-fit:cover;pointer-events:none}.sp-thumb-label{position:absolute;bottom:0;right:0;padding:1px 5px;background:#00000080;color:#fff9;font-family:monospace;font-size:11px;border-radius:4px 0 0;pointer-events:none}.sp-thumb-ph{width:100%;height:100%;background:#222;display:flex;align-items:center;justify-content:center;color:#555;font-family:monospace;font-size:13px;-webkit-user-select:none;user-select:none}.sp-thumb-counter{padding:8px 0;text-align:center;color:#999;font-family:monospace;font-size:13px;border-top:1px solid rgba(255,255,255,.08);-webkit-user-select:none;user-select:none}.sp-hud-container{position:absolute;top:40px;left:50%;transform:translate(-50%);z-index:100;opacity:0;pointer-events:none;transition:opacity .3s ease,transform .3s ease}.sp-hud-container.show{opacity:1;pointer-events:auto;transform:translate(-50%)}.sp-hud-box{display:flex;align-items:center;gap:10px;background:#141414b3;border:1px solid rgba(255,255,255,.1);padding:10px 20px;border-radius:30px;box-shadow:0 4px 16px #00000080;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);transition:all .2s}.sp-hud-box.hud-error{background:#b41e1eb3;border-color:#ff64644d}.sp-hud-box.hud-error:hover{background:#dc2828cc}.sp-hud-text{font-size:14px;color:#f3f4f6;font-family:sans-serif;font-weight:500;letter-spacing:.5px;white-space:nowrap;-webkit-user-select:none;user-select:none}.sp-hud-page{font-size:13px;color:#ffffff80;font-family:monospace;letter-spacing:1px;margin-left:6px;padding-left:10px;border-left:1px solid rgba(255,255,255,.2);-webkit-user-select:none;user-select:none}';
  importCSS(stylesCss);
  var _GM_getValue = (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
  var _GM_registerMenuCommand = (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
  var _GM_setValue = (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
  const CFG = {
    nextPage: "3000px 0px",
    maxRetries: 3,
    retryDelay: 1e3,
    maxConcurrent: 3,
    requestSpacing: 100,
    imageLoadTimeout: 8e3
  };
  function loadSettings(adapterName) {
    const prefix = adapterName ? `${adapterName}_` : "";
    const is4KHD = adapterName === "4KHD";
    const globalScrollMode = _GM_getValue("scrollMode", true);
    return {
      scrollMode: _GM_getValue(`${prefix}scrollMode`, is4KHD ? true : globalScrollMode),
      showControl: _GM_getValue("showControl", true),
      autoEnterSinglePage: _GM_getValue("autoEnterSinglePage", false),
      autoPlayInterval: _GM_getValue("autoPlayInterval", 3e3)
    };
  }
  class Store {
constructor() {
      this.listeners = new Map();
      this.activeAdapter = null;
      this.currPage = 1;
      this.totalPage = 1;
      this.perPage = 20;
      this.imageOffset = 0;
      this.nextUrl = null;
      this.prevUrl = null;
      this.isFetching = false;
      this.nextPagePrefetched = false;
      this.currentImageIndex = 0;
      this.allImages = [];
      this.autoPlayTimer = null;
      this.autoPlay = false;
      this._settings = loadSettings();
    }
    get settings() {
      return this._settings;
    }
    reloadSettings() {
      var _a;
      this._settings = loadSettings((_a = this.activeAdapter) == null ? void 0 : _a.name);
    }
    updateSetting(key, value) {
      this._settings[key] = value;
      if (key === "scrollMode" && this.activeAdapter) {
        _GM_setValue(`${this.activeAdapter.name}_scrollMode`, value);
      } else {
        _GM_setValue(key, value);
      }
      this.emit("settingsChanged");
    }
    on(event, listener) {
      if (!this.listeners.has(event)) {
        this.listeners.set(event, new Set());
      }
      this.listeners.get(event).add(listener);
    }
    emit(event) {
      var _a;
      (_a = this.listeners.get(event)) == null ? void 0 : _a.forEach((fn) => fn());
    }
  }
  const store = new Store();
  const q = (selector, root = document) => root.querySelector(selector);
  const qa = (selector, root = document) => root.querySelectorAll(selector);
  function isImageReady(img) {
    if (img.dataset.realSrc) return true;
    return !!(img && img.src && !img.src.includes("data:") && img.complete && img.naturalWidth > 0);
  }
  let toastContainer = null;
  function showToast(msg, duration = 3e3) {
    if (!toastContainer) {
      toastContainer = document.createElement("div");
      toastContainer.style.position = "fixed";
      toastContainer.style.top = "20px";
      toastContainer.style.left = "50%";
      toastContainer.style.transform = "translateX(-50%)";
      toastContainer.style.zIndex = "2147483647";
      toastContainer.style.pointerEvents = "none";
      toastContainer.style.display = "flex";
      toastContainer.style.flexDirection = "column";
      toastContainer.style.gap = "8px";
      document.body.appendChild(toastContainer);
    }
    const toast = document.createElement("div");
    toast.style.background = "rgba(20, 20, 20, 0.9)";
    toast.style.color = "#fff";
    toast.style.padding = "8px 16px";
    toast.style.borderRadius = "20px";
    toast.style.fontSize = "14px";
    toast.style.boxShadow = "0 4px 12px rgba(0,0,0,0.5)";
    toast.style.border = "1px solid rgba(255,255,255,0.1)";
    toast.style.transition = "opacity 0.3s";
    toast.textContent = msg;
    toastContainer.appendChild(toast);
    setTimeout(() => {
      toast.style.opacity = "0";
      setTimeout(() => {
        toast.remove();
      }, 300);
    }, duration);
  }
  class RequestQueue {
    constructor() {
      this.queue = [];
      this.running = 0;
      this.pausedUntil = 0;
    }
    enqueue(task, priorityFn) {
      return new Promise((resolve, reject) => {
        this.queue.push({ execute: task, resolve, reject, priorityFn });
        this.run();
      });
    }
    pauseGlobally(durationMs) {
      const until = Date.now() + durationMs;
      if (until > this.pausedUntil) {
        this.pausedUntil = until;
      }
    }
    run() {
      if (Date.now() < this.pausedUntil) {
        setTimeout(() => this.run(), this.pausedUntil - Date.now() + 10);
        return;
      }
      if (this.queue.length > 1) {
        this.queue.sort((a, b) => {
          const pa = a.priorityFn ? a.priorityFn() : 0;
          const pb = b.priorityFn ? b.priorityFn() : 0;
          return pb - pa;
        });
      }
      while (this.running < CFG.maxConcurrent && this.queue.length > 0) {
        const task = this.queue.shift();
        this.running++;
        const next = () => {
          this.running--;
          setTimeout(() => this.run(), CFG.requestSpacing);
        };
        task.execute().then((value) => {
          task.resolve(value);
          next();
        }).catch((reason) => {
          task.reject(reason);
          next();
        });
      }
    }
  }
  const requestQueue = new RequestQueue();
  const parser$1 = new DOMParser();
  function getNextUrl$1(doc) {
    const ptt = q(".ptt", doc);
    if (!ptt) return null;
    const nextBtn = Array.from(qa("td a", ptt)).find((a) => (a.textContent ?? "").includes(">"));
    return nextBtn ? nextBtn.href : null;
  }
  function getPrevUrl$1(doc) {
    const ptt = q(".ptt", doc);
    if (!ptt) return null;
    const prevBtn = Array.from(qa("td a", ptt)).find((a) => (a.textContent ?? "").includes("<"));
    return prevBtn ? prevBtn.href : null;
  }
  function extractLinks(doc) {
    return Array.from(qa("#gdt a", doc)).map((a) => {
      const url = a.href;
      let thumb;
      const divWithBg = a.closest('div[style*="background"]');
      if (divWithBg) {
        const style = divWithBg.getAttribute("style") || "";
        const match = style.match(/url\(['"]?([^)'"]+)['"]?\)/);
        if (match) thumb = match[1];
      } else {
        const img = a.querySelector("img");
        if (img && img.src && !img.src.endsWith("x.gif")) {
          thumb = img.src;
        }
      }
      return { url, thumb };
    });
  }
  const EHentaiAdapter = {
    name: "E-Hentai/ExHentai",
    match(url) {
      return /https?:\/\/(e-|ex)hentai\.org\/(g|s)\//.test(url);
    },
    async init(doc) {
      const initLinks = extractLinks(doc);
      let totalPage = 1;
      const gpc = q(".gpc", doc);
      if (gpc) {
        const txt = gpc.textContent ?? "";
        const m = txt.match(/of\s+([\d,]+)\s+images/);
        if (m && m[1]) {
          const totalImgs = parseInt(m[1].replace(/,/g, ""));
          const perPage = initLinks.length || 20;
          totalPage = Math.ceil(totalImgs / perPage);
        }
      } else {
        const allLinks = Array.from(qa(".ptt td a", doc));
        const lastA = allLinks.pop();
        if (lastA) {
          const t = parseInt(lastA.textContent ?? "");
          if (!isNaN(t)) totalPage = t;
        }
      }
      if (gpc) {
        const txt = gpc.textContent ?? "";
        const m = txt.match(/Showing\s+([\d,]+)\s*-\s*([\d,]+)\s+of\s+([\d,]+)/);
        if (m) {
          store.imageOffset = parseInt(m[1].replace(/,/g, "")) - 1;
        }
      }
      return {
        links: initLinks,
        nextUrl: getNextUrl$1(doc),
        prevUrl: getPrevUrl$1(doc),
        totalPage
      };
    },
    async resolveImage(url, nlToken) {
      const fetchUrl = nlToken ? `${url}${url.includes("?") ? "&" : "?"}nl=${nlToken}` : url;
      let retries = 0;
      while (retries <= CFG.maxRetries) {
        try {
          const response = await fetch(fetchUrl);
          if (response.status === 429 || response.status === 503) {
            requestQueue.pauseGlobally(5e3);
            throw { rateLimited: true };
          }
          if (!response.ok) throw new Error(`HTTP ${response.status}`);
          const html = await response.text();
          const doc = parser$1.parseFromString(html, "text/html");
          const imgEl = q("#img", doc);
          const imgSrc = imgEl == null ? void 0 : imgEl.src;
          if (!imgSrc) throw new Error("Image not found");
          const onerror = imgEl.getAttribute("onerror") || "";
          const m = onerror.match(/nl\(['"]([^'"]+)['"]\)/);
          const nextNlToken = m ? m[1] : null;
          return { src: imgSrc, nl: nextNlToken ?? void 0 };
        } catch (err) {
          if (retries < CFG.maxRetries) {
            const isRateLimited = err && typeof err === "object" && "rateLimited" in err;
            const delay = isRateLimited ? 5e3 : CFG.retryDelay * Math.pow(2, retries);
            await new Promise((resolve) => setTimeout(resolve, delay));
            retries++;
          } else {
            return null;
          }
        }
      }
      return null;
    },
    async fetchPage(url) {
      const response = await fetch(url);
      if (!response.ok) throw new Error("Failed to fetch page");
      const html = await response.text();
      const doc = parser$1.parseFromString(html, "text/html");
      const links = extractLinks(doc);
      return {
        links,
        nextUrl: getNextUrl$1(doc),
        prevUrl: getPrevUrl$1(doc)
      };
    },
    getContainer() {
      return document.querySelector("#gdt") || document.querySelector(".gm");
    },
    hideOriginalElements() {
      const HIDDEN_SELECTORS = [
        ".c1",
        ".c2",
        ".c3",
        ".c4",
        ".c5",
        ".c6",
        ".c7",
        ".c8",
        ".ptt",
        ".ptb",
        ".gdtl",
        ".gdtm",
        "#gdo",
        "#cdiv",
        "table.itg"
      ];
      document.querySelectorAll(HIDDEN_SELECTORS.join(",")).forEach((el) => {
        el.style.display = "none";
      });
    }
  };
  const parser = new DOMParser();
  function extract4KHDImages(doc) {
    const images = Array.from(qa("figure.wp-block-image img, #basicExample img, .entry-content p img", doc));
    return images.map((img) => {
      let src = img.src;
      let thumb = src;
      src = src.replace(/i\d\.wp\.com\//, "");
      src = src.replace("pic.4khd.com", "img.4khd.com");
      src = src.replace(/\?.+$/, "");
      src = src.replace(/\/w\d+-rw\//, "/w2500-h2500-rw/");
      return { url: src, thumb };
    }).filter((link) => link.url && !link.url.includes("avatar"));
  }
  function get4KHDNextUrl(doc) {
    const pageBox = doc.querySelector(".page-link-box, .pagination, .nav-links, .nav-previous");
    if (pageBox) {
      const current = pageBox.querySelector(".current, .active") || Array.from(pageBox.querySelectorAll("span")).find((s) => !s.querySelector("a"));
      if (current) {
        const currentPageNum = parseInt(current.textContent || "1", 10);
        if (!isNaN(currentPageNum)) {
          const nextBtn = Array.from(pageBox.querySelectorAll("a")).find((a) => parseInt(a.textContent || "0", 10) === currentPageNum + 1);
          if (nextBtn && nextBtn.href && nextBtn.href !== window.location.href) {
            return nextBtn.href;
          }
        }
      }
      const nextBtnFallback = pageBox.querySelector("a.next") || doc.querySelector("a.next.page-numbers");
      if (nextBtnFallback && nextBtnFallback.href) {
        const url = nextBtnFallback.href;
        if (url !== window.location.href) return url;
      }
    }
    return null;
  }
  function get4KHDPrevUrl(doc) {
    const pageBox = doc.querySelector(".page-link-box, .pagination, .nav-links, .nav-previous");
    if (pageBox) {
      const current = pageBox.querySelector(".current, .active") || Array.from(pageBox.querySelectorAll("span")).find((s) => !s.querySelector("a"));
      if (current) {
        const currentPageNum = parseInt(current.textContent || "1", 10);
        if (!isNaN(currentPageNum) && currentPageNum > 1) {
          const prevBtn = Array.from(pageBox.querySelectorAll("a")).find((a) => parseInt(a.textContent || "0", 10) === currentPageNum - 1);
          if (prevBtn && prevBtn.href && prevBtn.href !== window.location.href) {
            return prevBtn.href;
          }
        }
      }
      const prevBtnFallback = pageBox.querySelector("a.prev") || doc.querySelector("a.prev.page-numbers");
      if (prevBtnFallback && prevBtnFallback.href) {
        const url = prevBtnFallback.href;
        if (url !== window.location.href) return url;
      }
    }
    return null;
  }
  const FourKHDAdapter = {
    name: "4KHD",
    match(url) {
      return url.includes("4khd.com") || url.includes("xxtt.ink") || url.includes("uuss.uk") || url.includes("ssuu.uk");
    },
    async init(doc) {
      const initLinks = extract4KHDImages(doc);
      const totalPage = 1;
      const pageBox = doc.querySelector(".page-link-box, .pagination, .nav-links, .nav-previous");
      let currentPageNum = 1;
      if (pageBox) {
        const current = pageBox.querySelector(".current, .active") || Array.from(pageBox.querySelectorAll("span")).find((s) => !s.querySelector("a"));
        if (current) {
          currentPageNum = parseInt(current.textContent || "1", 10);
          if (isNaN(currentPageNum)) currentPageNum = 1;
        }
      }
      if (currentPageNum > 1) {
        const perPage = initLinks.length > 0 ? initLinks.length : 20;
        store.imageOffset = (currentPageNum - 1) * perPage;
      }
      return {
        links: initLinks,
        nextUrl: get4KHDNextUrl(doc),
        prevUrl: get4KHDPrevUrl(doc),
        totalPage
      };
    },
    async resolveImage(url) {
      return { src: url };
    },
    async fetchPage(url) {
      const response = await fetch(url);
      if (!response.ok) throw new Error("Failed to fetch page");
      const html = await response.text();
      const doc = parser.parseFromString(html, "text/html");
      const links = extract4KHDImages(doc);
      return {
        links,
        nextUrl: get4KHDNextUrl(doc),
        prevUrl: get4KHDPrevUrl(doc)
      };
    },
    getContainer() {
      const entryContent = document.querySelector(".entry-content, .wp-block-post-content");
      if (entryContent) return entryContent;
      const basicExample = document.querySelector("#basicExample");
      if (basicExample && basicExample.parentElement) return basicExample.parentElement;
      return document.querySelector(".post-content");
    },
    hideOriginalElements() {
      const HIDDEN_SELECTORS = [
        ".centbtd",
        ".popup",
        ".wp-container-13",
        ".popup-iframe",
        "#basicExample",
        ".wp-block-image",
        ".page-link-box"
      ];
      document.querySelectorAll(HIDDEN_SELECTORS.join(",")).forEach((el) => {
        el.style.display = "none";
      });
    }
  };
  class Mutex {
    constructor(maxConcurrent) {
      this.maxConcurrent = maxConcurrent;
      this.queue = [];
      this.activeCount = 0;
    }
    async lock() {
      if (this.activeCount < this.maxConcurrent) {
        this.activeCount++;
        return;
      }
      return new Promise((resolve) => this.queue.push(resolve));
    }
    unlock() {
      if (this.queue.length > 0) {
        const next = this.queue.shift();
        next == null ? void 0 : next();
      } else {
        this.activeCount--;
      }
    }
  }
  const decodeMutex = new Mutex(3);
  const Comic18Adapter = {
    name: "18comic",
    match: (url) => {
      return url.includes("18comic.vip") || url.includes("18comic.ink");
    },
    init: async (doc) => {
      const aidMatch = doc.documentElement.innerHTML.match(/aid\s*=\s*['"]?(\d+)['"]?/);
      const scrambleMatch = doc.documentElement.innerHTML.match(/scramble_id\s*=\s*['"]?(\d+)['"]?/);
      const aid = aidMatch ? aidMatch[1] : unsafeWindow.aid ? String(unsafeWindow.aid) : "";
      const scrambleId = scrambleMatch ? scrambleMatch[1] : unsafeWindow.scramble_id ? String(unsafeWindow.scramble_id) : "";
      const links = [];
      const imgs = doc.querySelectorAll(".scramble-page img[id], .owl-item .center img[id]");
      imgs.forEach((img) => {
        const url = img.getAttribute("data-original") || img.getAttribute("data-src") || img.src;
        if (url) {
          const urlObj = new URL(url, window.location.href);
          if (aid) urlObj.searchParams.set("18aid", aid);
          if (scrambleId) urlObj.searchParams.set("18scid", scrambleId);
          const viewerUrl = urlObj.toString();
          links.push({ url: viewerUrl });
          try {
            img.getBoundingClientRect = () => ({
              top: 999999,
              left: 0,
              right: 0,
              bottom: 999999,
              width: 0,
              height: 0,
              x: 0,
              y: 0,
              toJSON: () => {
              }
            });
          } catch (e) {
          }
        }
      });
      return {
        links,
        nextUrl: getNextUrl(doc),
        prevUrl: getPrevUrl(doc)
      };
    },
    fetchPage: async (url) => {
      const res = await fetch(url);
      const html = await res.text();
      const doc = new DOMParser().parseFromString(html, "text/html");
      const aidMatch = html.match(/aid\s*=\s*['"]?(\d+)['"]?/);
      const scrambleMatch = html.match(/scramble_id\s*=\s*['"]?(\d+)['"]?/);
      const aid = aidMatch ? aidMatch[1] : "";
      const scrambleId = scrambleMatch ? scrambleMatch[1] : "";
      const links = [];
      const imgs = doc.querySelectorAll(".scramble-page img[id], .owl-item .center img[id]");
      imgs.forEach((img) => {
        const imgUrl = img.getAttribute("data-original") || img.getAttribute("data-src") || img.src;
        if (imgUrl) {
          const urlObj = new URL(imgUrl, window.location.href);
          if (aid) urlObj.searchParams.set("18aid", aid);
          if (scrambleId) urlObj.searchParams.set("18scid", scrambleId);
          links.push({ url: urlObj.toString() });
        }
      });
      return {
        links,
        nextUrl: getNextUrl(doc),
        prevUrl: getPrevUrl(doc)
      };
    },
    resolveImage: async (urlStr) => {
      try {
        const urlObj = new URL(urlStr);
        const aid = urlObj.searchParams.get("18aid");
        const scrambleId = urlObj.searchParams.get("18scid");
        urlObj.searchParams.delete("18aid");
        urlObj.searchParams.delete("18scid");
        const realUrl = urlObj.toString();
        if (realUrl.includes(".gif") || !aid || !scrambleId || Number(aid) < Number(scrambleId)) {
          return { src: realUrl };
        }
        const res = await fetch(realUrl);
        if (!res.ok) throw new Error("Failed to fetch image");
        const blob = await res.blob();
        const fileName = urlObj.pathname.split("/").pop() || "";
        const id = fileName.split(".")[0];
        if (!id) return { src: realUrl };
        await decodeMutex.lock();
        try {
          const bitmap = await createImageBitmap(blob);
          const imgWidth = bitmap.width;
          const imgHeight = bitmap.height;
          if (!unsafeWindow.get_num) {
            bitmap.close();
            return { src: realUrl };
          }
          const num = unsafeWindow.get_num(btoa(aid), btoa(id));
          if (!num || num <= 1) {
            bitmap.close();
            return { src: realUrl };
          }
          const canvas = new OffscreenCanvas(imgWidth, imgHeight);
          const ctx = canvas.getContext("2d");
          if (!ctx) {
            bitmap.close();
            return { src: realUrl };
          }
          ctx.fillStyle = "#ffffff";
          ctx.fillRect(0, 0, imgWidth, imgHeight);
          const cropHeight = Number(imgHeight % num);
          const sHeight = Math.floor(imgHeight / num);
          let sy = imgHeight - cropHeight - sHeight;
          let dy = cropHeight + sHeight;
          ctx.drawImage(bitmap, 0, sy, imgWidth, cropHeight + sHeight, 0, 0, imgWidth, cropHeight + sHeight);
          for (let i = 1; i < num; ++i) {
            sy -= sHeight;
            ctx.drawImage(bitmap, 0, sy, imgWidth, sHeight, 0, dy, imgWidth, sHeight);
            dy += sHeight;
          }
          bitmap.close();
          const finalBlob = await canvas.convertToBlob({ type: "image/jpeg", quality: 0.85 });
          const finalUrl = URL.createObjectURL(finalBlob);
          return { src: finalUrl };
        } finally {
          decodeMutex.unlock();
        }
      } catch (err) {
        const cleanUrl = new URL(urlStr);
        cleanUrl.searchParams.delete("18aid");
        cleanUrl.searchParams.delete("18scid");
        return { src: cleanUrl.toString() };
      }
    },
    getContainer: () => {
      return document.querySelector(".scramble-page") || document.body;
    },
    hideOriginalElements: () => {
    }
  };
  function getNextUrl(doc) {
    var _a;
    const activeLi = doc.querySelector(".pagination li.active");
    if (activeLi) {
      const nextA = (_a = activeLi.nextElementSibling) == null ? void 0 : _a.querySelector("a:not(.prevnext)");
      if (nextA) return nextA.href;
    }
    const nextChapter = Array.from(doc.querySelectorAll('.menu-bolock-ul a[href^="/photo/"]')).find((a) => {
      var _a2;
      return (_a2 = a.textContent) == null ? void 0 : _a2.includes("下一");
    });
    if (nextChapter) return nextChapter.href;
    return null;
  }
  function getPrevUrl(doc) {
    var _a;
    const activeLi = doc.querySelector(".pagination li.active");
    if (activeLi) {
      const prevA = (_a = activeLi.previousElementSibling) == null ? void 0 : _a.querySelector("a:not(.prevnext)");
      if (prevA) return prevA.href;
    }
    const prevChapter = Array.from(doc.querySelectorAll('.menu-bolock-ul a[href^="/photo/"]')).find((a) => {
      var _a2;
      return (_a2 = a.textContent) == null ? void 0 : _a2.includes("上一");
    });
    if (prevChapter) return prevChapter.href;
    return null;
  }
  const adapters = [EHentaiAdapter, FourKHDAdapter, Comic18Adapter];
  const SiteManager = {
    register(adapter) {
      adapters.push(adapter);
    },
    getAdapter(url, doc = document) {
      return adapters.find((a) => a.match(url, doc)) || null;
    }
  };
  function setErrorState(placeholder, pIndex, index) {
    placeholder.className = "r-ph sp-placeholder error";
    placeholder.innerHTML = `
    <div style="display: flex; flex-direction: column; align-items: center; justify-content: center; transform: translateY(-20px);">
      <div style="display: flex; align-items: center; gap: 10px; background: rgba(200, 40, 40, 0.8); border: 1px solid rgba(255, 255, 255, 0.2); padding: 10px 20px; border-radius: 30px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); backdrop-filter: blur(8px); margin-bottom: 16px;">
        <svg style="color: #fff; width: 20px; height: 20px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
          <circle cx="12" cy="12" r="10"></circle>
          <line x1="12" y1="8" x2="12" y2="12"></line>
          <line x1="12" y1="16" x2="12.01" y2="16"></line>
        </svg>
        <div style="font-size: 15px; color: #fff; font-weight: 500; letter-spacing: 0.5px;">Load Failed</div>
      </div>
      <div style="font-size: 14px; color: rgba(255, 255, 255, 0.5); font-family: monospace; letter-spacing: 1px;">P${pIndex}-${index + 1}</div>
    </div>
  `;
  }
  let virtualizationObserver = null;
  let lazyLoadObserver = null;
  function initVirtualization() {
    if (virtualizationObserver) return;
    virtualizationObserver = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        const img = entry.target;
        if (entry.isIntersecting) {
          img.classList.remove("sp-virtualized");
        } else {
          img.classList.add("sp-virtualized");
        }
      });
    }, { rootMargin: "3000px" });
  }
  function loadPlaceholderImage(placeholder) {
    const url = placeholder.dataset.url;
    const pIndex = parseInt(placeholder.dataset.pIndex);
    const index = parseInt(placeholder.dataset.index);
    const thumb = placeholder.dataset.thumb;
    const adapter = store.activeAdapter;
    if (!adapter) return;
    adapter.resolveImage(url).then((res) => {
      var _a;
      if (res) {
        let showError = function() {
          if (placeholder.parentNode) {
            setErrorState(placeholder, pIndex, index);
            if (img.parentNode) {
              img.parentNode.replaceChild(placeholder, img);
            }
            virtualizationObserver == null ? void 0 : virtualizationObserver.unobserve(img);
          }
        };
        const img = document.createElement("img");
        img.className = "r-img";
        img.dataset.viewerUrl = url;
        img.dataset.realSrc = res.src;
        if (thumb) img.dataset.thumbSrc = thumb;
        if (res.nl) img.dataset.nl = res.nl;
        let currentNlToken = res.nl;
        let autoRetries = 0;
        const MAX_AUTO_RETRIES = 3;
        img.onerror = () => {
          if (currentNlToken && autoRetries < MAX_AUTO_RETRIES) {
            autoRetries++;
            showToast(`P${pIndex}-${index + 1}: Auto requesting new node... (${autoRetries}/${MAX_AUTO_RETRIES})`, 3e3);
            if (placeholder.parentNode) {
              placeholder.className = "r-ph sp-placeholder loading";
              placeholder.innerHTML = `
              <div style="display: flex; flex-direction: column; align-items: center; justify-content: center; transform: translateY(-20px);">
                <div style="display: flex; align-items: center; gap: 10px; background: rgba(20, 20, 20, 0.8); border: 1px solid rgba(255, 255, 255, 0.1); padding: 10px 20px; border-radius: 30px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); backdrop-filter: blur(8px); margin-bottom: 16px;">
                  <style>@keyframes sp-spin { 100% { transform: rotate(360deg); } }</style>
                  <svg style="color: #F596AA; width: 20px; height: 20px; animation: sp-spin 1s linear infinite;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
                    <path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
                  </svg>
                  <div style="font-size: 15px; color: #f3f4f6; font-weight: 500; letter-spacing: 0.5px;">Auto Retrying...</div>
                </div>
                <div style="font-size: 14px; color: rgba(255, 255, 255, 0.5); font-family: monospace; letter-spacing: 1px;">P${pIndex}-${index + 1}</div>
              </div>
            `;
              if (img.parentNode) {
                img.parentNode.replaceChild(placeholder, img);
              }
            }
            adapter.resolveImage(url, currentNlToken).then((newRes) => {
              if (newRes) {
                img.src = newRes.src;
                img.dataset.realSrc = newRes.src;
                currentNlToken = newRes.nl;
                if (placeholder.parentNode) {
                  placeholder.parentNode.replaceChild(img, placeholder);
                }
              } else {
                showError();
              }
            }).catch(showError);
          } else {
            showError();
          }
        };
        img.onload = () => {
          if (!img.dataset.locked && img.naturalWidth > 0) {
            img.style.aspectRatio = `${img.naturalWidth} / ${img.naturalHeight}`;
            img.style.width = "100%";
            img.style.maxWidth = `${img.naturalWidth}px`;
            img.style.height = "auto";
            img.dataset.locked = "true";
          }
        };
        img.src = res.src;
        (_a = placeholder.parentNode) == null ? void 0 : _a.replaceChild(img, placeholder);
        virtualizationObserver == null ? void 0 : virtualizationObserver.observe(img);
      } else {
        setErrorState(placeholder, pIndex, index);
      }
    }).catch(() => {
      setErrorState(placeholder, pIndex, index);
    });
  }
  function initLazyLoad() {
    if (lazyLoadObserver) return;
    lazyLoadObserver = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          const placeholder = entry.target;
          if (placeholder.dataset.lazyLoaded) return;
          placeholder.dataset.lazyLoaded = "true";
          lazyLoadObserver == null ? void 0 : lazyLoadObserver.unobserve(placeholder);
          loadPlaceholderImage(placeholder);
        }
      });
    }, { rootMargin: "4000px 0px 4000px 0px" });
  }
  function processBatch(links, pIndex, container, prepend = false, pageUrl) {
    const batchDiv = document.createElement("div");
    batchDiv.className = "page-batch";
    if (pageUrl) {
      batchDiv.dataset.pageUrl = pageUrl;
    }
    const fragment = document.createDocumentFragment();
    initVirtualization();
    initLazyLoad();
    let targetContainer = container;
    if (!targetContainer) {
      targetContainer = document.querySelector("#gdt-hidden") || document.querySelector(".scroll-mode #gdt, .scroll-mode .gm, .scroll-mode .entry-content, .scroll-mode .wp-block-post-content, .scroll-mode .post-content") || document.body;
    }
    links.forEach((link, index) => {
      const url = link.url;
      const placeholder = document.createElement("div");
      placeholder.className = "r-ph sp-placeholder loading";
      placeholder.dataset.url = url;
      placeholder.dataset.pIndex = String(pIndex);
      placeholder.dataset.index = String(index);
      if (link.thumb) placeholder.dataset.thumb = link.thumb;
      placeholder.innerHTML = `
      <div style="display: flex; flex-direction: column; align-items: center; justify-content: center; transform: translateY(-20px);">
        <div style="display: flex; align-items: center; gap: 10px; background: rgba(20, 20, 20, 0.8); border: 1px solid rgba(255, 255, 255, 0.1); padding: 10px 20px; border-radius: 30px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); backdrop-filter: blur(8px); margin-bottom: 16px;">
          <style>@keyframes sp-spin { 100% { transform: rotate(360deg); } }</style>
          <svg style="color: #F596AA; width: 20px; height: 20px; animation: sp-spin 1s linear infinite;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
            <path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
          </svg>
          <div style="font-size: 15px; color: #f3f4f6; font-weight: 500; letter-spacing: 0.5px;">Loading...</div>
        </div>
        <div style="font-size: 14px; color: rgba(255, 255, 255, 0.5); font-family: monospace; letter-spacing: 1px;">P${pIndex}-${index + 1}</div>
      </div>
    `;
      fragment.appendChild(placeholder);
      if (store.settings.scrollMode) {
        lazyLoadObserver == null ? void 0 : lazyLoadObserver.observe(placeholder);
      } else {
        placeholder.dataset.lazyLoaded = "true";
        loadPlaceholderImage(placeholder);
      }
    });
    batchDiv.appendChild(fragment);
    if (prepend && targetContainer.firstChild) {
      targetContainer.insertBefore(batchDiv, targetContainer.firstChild);
    } else {
      targetContainer.appendChild(batchDiv);
    }
  }
  function setupAutoScroll() {
    const scrollSent = document.createElement("div");
    document.body.appendChild(scrollSent);
    const pageObs = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting && store.nextUrl && !store.isFetching) {
        store.isFetching = true;
        store.activeAdapter.fetchPage(store.nextUrl).then(({ links, nextUrl: nUrl }) => {
          store.currPage++;
          processBatch(links, store.currPage, document.querySelector(".scroll-mode #gdt, .scroll-mode .gm, .scroll-mode .entry-content, .scroll-mode .wp-block-post-content, .scroll-mode .post-content") || document.body);
          store.nextUrl = nUrl;
          store.isFetching = false;
          store.nextPagePrefetched = false;
          if (!store.nextUrl) pageObs.disconnect();
        }).catch(() => {
          store.isFetching = false;
        });
      }
    }, { rootMargin: CFG.nextPage });
    pageObs.observe(scrollSent);
  }
  const ITEM_HEIGHT = 80;
  const VISIBLE_COUNT = 12;
  const BUFFER = 3;
  function createSidebar(onIndexChange, onScrollToBottom, onScrollToTop) {
    const progressTrack = document.createElement("div");
    progressTrack.className = "sp-sidebar-track";
    const progressThumb = document.createElement("div");
    progressThumb.className = "sp-sidebar-thumb";
    const progressLabel = document.createElement("div");
    progressLabel.className = "sp-sidebar-label";
    progressTrack.appendChild(progressThumb);
    progressTrack.appendChild(progressLabel);
    const thumbPanel = document.createElement("div");
    thumbPanel.className = "sp-thumb-panel";
    const viewport = document.createElement("div");
    viewport.className = "sp-thumb-viewport";
    const content = document.createElement("div");
    content.className = "sp-thumb-content";
    const counter = document.createElement("div");
    counter.className = "sp-thumb-counter";
    viewport.appendChild(content);
    thumbPanel.appendChild(viewport);
    thumbPanel.appendChild(counter);
    let scrollOffset = 0;
    let lastCenteredIndex = -1;
    let clickedFromPanel = false;
    const itemPool = [];
    const activeItems = new Map();
    let cachedTrackHeight = 0;
    let progressWakeTimer = null;
    let isPanelActive = false;
    function wakeUpProgressBar() {
      if (isPanelActive) return;
      progressTrack.classList.add("active");
      if (progressWakeTimer) clearTimeout(progressWakeTimer);
      progressWakeTimer = setTimeout(() => {
        progressTrack.classList.remove("active");
      }, 1500);
    }
    function closePanel() {
      if (!isPanelActive) return;
      isPanelActive = false;
      thumbPanel.classList.remove("active");
    }
    function openPanel() {
      if (isPanelActive) return;
      isPanelActive = true;
      thumbPanel.classList.add("active");
      progressTrack.classList.remove("active");
      if (progressWakeTimer) clearTimeout(progressWakeTimer);
    }
    document.addEventListener("mousemove", (e) => {
      if (!document.querySelector(".single-page-overlay.active")) return;
      if (isDragging) return;
      if (e.clientX < 0 || e.clientY < 0 || e.clientY >= window.innerHeight - 1) {
        closePanel();
        return;
      }
      const dx = window.innerWidth - e.clientX;
      if (dx <= 140) {
        openPanel();
      } else {
        closePanel();
      }
    });
    document.addEventListener("mouseout", (e) => {
      if (!e.relatedTarget) closePanel();
    });
    document.documentElement.addEventListener("mouseleave", closePanel);
    function refreshTrackHeight() {
      cachedTrackHeight = progressTrack.offsetHeight;
    }
    window.addEventListener("resize", refreshTrackHeight, { passive: true });
    function clamp(val, min, max) {
      return Math.max(min, Math.min(max, val));
    }
    function vpHeight() {
      return viewport.offsetHeight || Math.min(VISIBLE_COUNT * ITEM_HEIGHT, store.allImages.length * ITEM_HEIGHT);
    }
    function maxOffset() {
      return Math.max(0, store.allImages.length * ITEM_HEIGHT - vpHeight());
    }
    function acquireItem() {
      return itemPool.pop() || (() => {
        const el = document.createElement("div");
        el.className = "sp-thumb-item";
        return el;
      })();
    }
    function releaseItem(el) {
      el.remove();
      itemPool.push(el);
    }
    function renderItemContent(el, index) {
      el.dataset.index = String(index);
      el.classList.toggle("sp-thumb-active", index === store.currentImageIndex);
      const img = store.allImages[index];
      if (img && img.src) {
        let thumbCanvas = el.querySelector("canvas.sp-thumb-img");
        if (!thumbCanvas) {
          el.innerHTML = "";
          thumbCanvas = document.createElement("canvas");
          thumbCanvas.className = "sp-thumb-img";
          el.appendChild(thumbCanvas);
          const label2 = document.createElement("span");
          label2.className = "sp-thumb-label";
          el.appendChild(label2);
        }
        const realSrc = img.dataset.thumbSrc || img.dataset.realSrc || img.src;
        if (thumbCanvas.dataset.src !== realSrc) {
          thumbCanvas.dataset.src = realSrc;
          const tempImg = new Image();
          tempImg.onload = () => {
            if (thumbCanvas.dataset.src === realSrc) {
              thumbCanvas.width = tempImg.naturalWidth;
              thumbCanvas.height = tempImg.naturalHeight;
              const ctx = thumbCanvas.getContext("2d");
              if (ctx) {
                ctx.drawImage(tempImg, 0, 0);
              }
            }
          };
          tempImg.src = realSrc;
        }
        const label = el.querySelector(".sp-thumb-label");
        if (label) label.textContent = String(store.imageOffset + index + 1);
      } else {
        if (!el.querySelector(".sp-thumb-ph")) {
          el.innerHTML = "";
          const ph = document.createElement("div");
          ph.className = "sp-thumb-ph";
          ph.textContent = String(store.imageOffset + index + 1);
          el.appendChild(ph);
        }
      }
    }
    function renderVisibleItems() {
      const total = store.allImages.length;
      if (total === 0) return;
      const vp = vpHeight();
      content.style.height = `${total * ITEM_HEIGHT}px`;
      scrollOffset = clamp(scrollOffset, 0, maxOffset());
      const startIdx = Math.max(0, Math.floor(scrollOffset / ITEM_HEIGHT) - BUFFER);
      const endIdx = Math.min(total - 1, Math.ceil((scrollOffset + vp) / ITEM_HEIGHT) + BUFFER);
      for (const [idx, el] of activeItems) {
        if (idx < startIdx || idx > endIdx) {
          releaseItem(el);
          activeItems.delete(idx);
        }
      }
      for (let i = startIdx; i <= endIdx; i++) {
        let el = activeItems.get(i);
        if (!el) {
          el = acquireItem();
          activeItems.set(i, el);
          content.appendChild(el);
        }
        el.style.transform = `translateY(${i * ITEM_HEIGHT}px)`;
        renderItemContent(el, i);
      }
      content.style.transform = `translateY(${-scrollOffset}px)`;
    }
    function centerOnCurrent() {
      const vp = vpHeight();
      const target = store.currentImageIndex * ITEM_HEIGHT - vp / 2 + ITEM_HEIGHT / 2;
      scrollOffset = clamp(target, 0, maxOffset());
    }
    function ensureVisible() {
      const vp = vpHeight();
      const itemTop = store.currentImageIndex * ITEM_HEIGHT;
      const itemBottom = itemTop + ITEM_HEIGHT;
      if (itemTop < scrollOffset) {
        scrollOffset = itemTop;
      } else if (itemBottom > scrollOffset + vp) {
        scrollOffset = itemBottom - vp;
      }
      scrollOffset = clamp(scrollOffset, 0, maxOffset());
    }
    function update() {
      if (store.allImages.length === 0) return;
      if (store.currentImageIndex !== lastCenteredIndex) {
        if (clickedFromPanel) {
          ensureVisible();
          clickedFromPanel = false;
        } else {
          centerOnCurrent();
        }
        lastCenteredIndex = store.currentImageIndex;
      }
      renderVisibleItems();
      const displayLabel = `${store.imageOffset + store.currentImageIndex + 1} / ${store.imageOffset + store.allImages.length}`;
      counter.textContent = displayLabel;
      if (!cachedTrackHeight) refreshTrackHeight();
      const trackHeight = cachedTrackHeight;
      let thumbHeight;
      if (store.allImages.length <= 10) {
        thumbHeight = 60;
      } else if (store.allImages.length <= 50) {
        thumbHeight = Math.max(60, trackHeight * (10 / store.allImages.length));
      } else {
        thumbHeight = Math.max(60, trackHeight * (5 / store.allImages.length));
      }
      const scrollProgress = store.currentImageIndex / Math.max(1, store.allImages.length - 1);
      const maxThumbTop = trackHeight - thumbHeight;
      const thumbTop = scrollProgress * maxThumbTop;
      progressThumb.style.height = `${thumbHeight}px`;
      progressThumb.style.top = `${thumbTop}px`;
      progressLabel.textContent = displayLabel;
    }
    viewport.addEventListener("wheel", (e) => {
      e.preventDefault();
      e.stopPropagation();
      scrollOffset = clamp(scrollOffset + e.deltaY, 0, maxOffset());
      renderVisibleItems();
      if (onScrollToBottom && scrollOffset >= maxOffset() - ITEM_HEIGHT) {
        onScrollToBottom();
      }
      if (onScrollToTop && scrollOffset <= ITEM_HEIGHT) {
        onScrollToTop();
      }
    }, { passive: false });
    content.addEventListener("click", (e) => {
      const item = e.target.closest(".sp-thumb-item");
      if (item == null ? void 0 : item.dataset.index) {
        const index = parseInt(item.dataset.index);
        if (!isNaN(index) && index >= 0 && index < store.allImages.length) {
          clickedFromPanel = true;
          onIndexChange(index);
        }
      }
    });
    progressTrack.onclick = (e) => {
      if (e.target === progressThumb) return;
      const rect = progressTrack.getBoundingClientRect();
      const clickY = e.clientY - rect.top;
      const scrollProgress = Math.min(1, Math.max(0, clickY / rect.height));
      const targetIndex = Math.round(scrollProgress * (store.allImages.length - 1));
      if (targetIndex >= 0 && targetIndex < store.allImages.length) {
        onIndexChange(targetIndex);
      }
    };
    let isDragging = false;
    let dragStartY = 0;
    let thumbStartTop = 0;
    progressThumb.onmousedown = (e) => {
      e.preventDefault();
      e.stopPropagation();
      isDragging = true;
      dragStartY = e.clientY;
      thumbStartTop = progressThumb.offsetTop;
      document.body.style.userSelect = "none";
    };
    document.addEventListener("mousemove", (e) => {
      if (!isDragging) return;
      const deltaY = e.clientY - dragStartY;
      const newTop = thumbStartTop + deltaY;
      const trackHeight = cachedTrackHeight;
      const thumbHeight = progressThumb.offsetHeight;
      const maxTop = trackHeight - thumbHeight;
      const clampedTop = Math.max(0, Math.min(maxTop, newTop));
      const scrollProgress = maxTop > 0 ? clampedTop / maxTop : 0;
      const targetIndex = Math.round(scrollProgress * (store.allImages.length - 1));
      if (targetIndex >= 0 && targetIndex < store.allImages.length && targetIndex !== store.currentImageIndex) {
        onIndexChange(targetIndex);
      }
    });
    document.addEventListener("mouseup", () => {
      if (isDragging) {
        isDragging = false;
        document.body.style.userSelect = "";
        wakeUpProgressBar();
      }
    });
    progressThumb.onclick = (e) => e.stopPropagation();
    return { update, getElements: () => [progressTrack, thumbPanel], wakeUpProgressBar };
  }
  function setupNavigation(deps) {
    function hasLoadingPlaceholders() {
      return document.querySelectorAll(".r-ph").length > 0;
    }
    function syncAllImages() {
      const freshImages = Array.from(qa(".r-img"));
      if (freshImages.length !== store.allImages.length) {
        store.allImages = freshImages;
      }
    }
    function nextImage() {
      if (store.currentImageIndex >= store.allImages.length - 3) {
        syncAllImages();
      }
      if (store.currentImageIndex < store.allImages.length - 1) {
        store.currentImageIndex++;
        deps.updateImage();
        deps.checkAndLoadNextPage();
      } else if (hasLoadingPlaceholders()) {
        deps.updateImage();
        deps.checkAndLoadNextPage();
      } else {
        deps.checkAndLoadNextPage();
        if (store.autoPlay) {
          deps.stopAutoPlayAtEnd();
        }
      }
    }
    function previousImage() {
      if (store.currentImageIndex > 0) {
        store.currentImageIndex--;
        deps.updateImage();
        if (store.autoPlay) {
          deps.resetAutoPlay();
        }
      }
      if (store.currentImageIndex <= 3) {
        deps.checkAndLoadPrevPage();
      }
    }
    let accumulatedDelta = 0;
    let isScrolling = false;
    let lastFlipTime = 0;
    let wheelTimeout;
    const processWheelScroll = () => {
      if (!isScrolling) return;
      const threshold = 70;
      const now = Date.now();
      if (Math.abs(accumulatedDelta) >= threshold && now - lastFlipTime >= 40) {
        if (accumulatedDelta > 0) {
          nextImage();
        } else {
          previousImage();
        }
        accumulatedDelta = accumulatedDelta > 0 ? accumulatedDelta - threshold : accumulatedDelta + threshold;
        lastFlipTime = now;
      }
      if (isScrolling) {
        requestAnimationFrame(processWheelScroll);
      }
    };
    deps.overlay.addEventListener("wheel", (e) => {
      e.preventDefault();
      let normalizedDelta = e.deltaY;
      if (e.deltaMode === 1) {
        normalizedDelta *= 33;
      } else if (e.deltaMode === 2) {
        normalizedDelta *= 800;
      }
      accumulatedDelta += normalizedDelta;
      if (!isScrolling) {
        isScrolling = true;
        processWheelScroll();
      }
      clearTimeout(wheelTimeout);
      wheelTimeout = setTimeout(() => {
        isScrolling = false;
        accumulatedDelta = 0;
      }, 150);
    }, { passive: false });
    document.addEventListener("keydown", (e) => {
      if (!deps.overlay.classList.contains("active")) return;
      if (e.key === "Escape") {
        deps.closeSinglePageMode();
      } else if (e.key === "ArrowDown" || e.key === "ArrowRight") {
        nextImage();
      } else if (e.key === "ArrowUp" || e.key === "ArrowLeft") {
        previousImage();
      }
    });
    return { nextImage, previousImage };
  }
  function createAutoPlay(nextImageFn) {
    function start() {
      if (store.autoPlayTimer) clearInterval(store.autoPlayTimer);
      if (store.autoPlay) {
        store.autoPlayTimer = setInterval(nextImageFn, store.settings.autoPlayInterval);
      }
    }
    function stop() {
      if (store.autoPlayTimer) {
        clearInterval(store.autoPlayTimer);
        store.autoPlayTimer = null;
      }
    }
    function reset() {
      if (store.autoPlay) {
        stop();
        start();
      }
    }
    function stopAtEnd() {
      store.autoPlay = false;
      store.emit("settingsChanged");
      stop();
    }
    return { start, stop, reset, stopAtEnd };
  }
  function createStatusHUD() {
    const container = document.createElement("div");
    container.className = "sp-hud-container";
    function show(config) {
      const isError = config.status === "error";
      const color = isError ? "#ef4444" : "#F596AA";
      const iconSvg = isError ? `<svg style="color: ${color}; width: 18px; height: 18px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>` : `<style>@keyframes sp-spin { 100% { transform: rotate(360deg); } }</style><svg style="color: ${color}; width: 18px; height: 18px; animation: sp-spin 1s linear infinite;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><path d="M21 12a9 9 0 1 1-6.219-8.56"></path></svg>`;
      container.innerHTML = `
      <div class="sp-hud-box ${isError ? "hud-error" : ""}">
        ${iconSvg}
        <div class="sp-hud-text">${config.text}</div>
        ${config.pageText ? `<div class="sp-hud-page">${config.pageText}</div>` : ""}
      </div>
    `;
      const box = container.querySelector(".sp-hud-box");
      if (config.onClick) {
        box.style.cursor = "pointer";
        box.onclick = config.onClick;
      }
      container.classList.add("show");
    }
    function hide() {
      container.classList.remove("show");
    }
    return { show, hide, getElement: () => container };
  }
  const isZH = navigator.language.toLowerCase().includes("zh");
  const i18n = {
readerMode: isZH ? "阅读器模式" : "Reader Mode",
    autoPlay: isZH ? "自动翻页" : "Auto Play",
    settings: isZH ? "设置" : "Settings",
    backToTop: isZH ? "回到顶部" : "Back to Top",
scrollMode: isZH ? "卷轴模式" : "Scroll Mode",
    autoEnter: isZH ? "自动进入阅读器" : "Auto Enter Reader",
    showControl: isZH ? "显示悬浮控件" : "Show Float Control",
    playSpeed: isZH ? "自动翻页速度" : "Auto Play Speed",
toggle: isZH ? "切换: " : "Toggle: ",
    enabled: isZH ? "已开启" : "Enabled",
    disabled: isZH ? "已关闭" : "Disabled",
waitingForNetwork: isZH ? "等待网络请求..." : "Waiting for network...",
    downloading: isZH ? "下载中..." : "Downloading...",
    loadFailed: isZH ? "加载失败" : "Load Failed",
    waitImagesToLoad: isZH ? "请等待图片加载" : "Please wait for images to load"
  };
  function createSinglePageOverlay(deps) {
    const overlay = document.createElement("div");
    overlay.className = "single-page-overlay";
    const closeBtn = document.createElement("div");
    closeBtn.className = "sp-close-btn";
    closeBtn.innerHTML = "&#10005;";
    const imageContainer = document.createElement("div");
    imageContainer.className = "sp-image-container";
    const currentImage = document.createElement("img");
    currentImage.className = "sp-current-image";
    imageContainer.appendChild(currentImage);
    currentImage.addEventListener("error", () => {
      if (!overlay.classList.contains("active")) return;
      if (!currentImage.src || currentImage.src === location.href) return;
      showError();
    });
    let loadPollTimer = null;
    let loadTimeoutTimer = null;
    let loadObserver = null;
    function clearLoadPoll() {
      if (loadPollTimer) {
        clearInterval(loadPollTimer);
        loadPollTimer = null;
      }
      if (loadTimeoutTimer) {
        clearTimeout(loadTimeoutTimer);
        loadTimeoutTimer = null;
      }
      if (loadObserver) {
        loadObserver.disconnect();
        loadObserver = null;
      }
    }
    const statusHUD = createStatusHUD();
    function showPlaceholder(statusText = "Loading...") {
      statusHUD.show({
        status: "loading",
        text: statusText,
        pageText: `${store.imageOffset + store.currentImageIndex + 1} / ${store.imageOffset + store.allImages.length}`
      });
    }
    function removePlaceholder() {
      statusHUD.hide();
    }
    function showError() {
      clearLoadPoll();
      currentImage.style.display = "none";
      statusHUD.show({
        status: "error",
        text: i18n.loadFailed,
        pageText: `${store.imageOffset + store.currentImageIndex + 1} / ${store.imageOffset + store.allImages.length}`
      });
    }
    function removeErrorUI() {
      statusHUD.hide();
    }
    function syncImages() {
      const freshImages = Array.from(qa(".r-img, .r-ph"));
      if (freshImages.length !== store.allImages.length || freshImages.some((img, i) => img !== store.allImages[i])) {
        store.allImages = freshImages;
        sidebar.update();
      }
    }
    function applyOverlaySrc(imgSrc, currentImg) {
      if (imgSrc && currentImage.dataset.assignedSrc !== imgSrc) {
        currentImage.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
        setTimeout(() => {
          currentImage.src = imgSrc;
          currentImage.dataset.assignedSrc = imgSrc;
          if (!isImageReady(currentImg)) {
            showPlaceholder(i18n.downloading);
          } else {
            removePlaceholder();
          }
        }, 0);
      } else if (!imgSrc && currentImage.dataset.assignedSrc) {
        currentImage.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
        delete currentImage.dataset.assignedSrc;
      }
    }
    function updateImage() {
      clearLoadPoll();
      removeErrorUI();
      const idx = store.currentImageIndex;
      syncImages();
      const img = store.allImages[idx];
      if (!img) {
        showPlaceholder(i18n.waitingForNetwork);
        sidebar.update();
        startLoadPoll(idx);
        return;
      }
      if (img.classList.contains("r-ph") && !img.dataset.lazyLoaded) {
        img.dataset.lazyLoaded = "true";
        loadPlaceholderImage(img);
      }
      const nextImg = store.allImages[idx + 1];
      if (nextImg && nextImg.classList.contains("r-ph") && !nextImg.dataset.lazyLoaded) {
        nextImg.dataset.lazyLoaded = "true";
        loadPlaceholderImage(nextImg);
      }
      const imgSrc = img.dataset.realSrc || img.src;
      applyOverlaySrc(imgSrc, img);
      currentImage.style.display = "block";
      if (!imgSrc) {
        showPlaceholder(i18n.waitingForNetwork);
      }
      sidebar.update();
      if (!isImageReady(img)) {
        startLoadPoll(idx);
      }
    }
    function startLoadPoll(idx) {
      if (store.autoPlay) autoPlay.stop();
      let imageErrored = false;
      let lastKnownImg = store.allImages[idx];
      function onImageReady() {
        if (store.currentImageIndex !== idx) return;
        const img = store.allImages[idx];
        if (img && isImageReady(img)) {
          clearLoadPoll();
          removePlaceholder();
          sidebar.update();
          if (store.autoPlay) autoPlay.start();
        }
      }
      function onImageError() {
        imageErrored = true;
        if (store.autoPlay) {
          tryAutoSkip();
        } else {
          if (store.currentImageIndex === idx) {
            showError();
          }
        }
      }
      function tryAutoSkip() {
        if (store.currentImageIndex !== idx) return;
        const nextIdx = idx + 1;
        if (nextIdx < store.allImages.length) {
          const nextImg = store.allImages[nextIdx];
          if (nextImg && isImageReady(nextImg)) {
            clearLoadPoll();
            store.currentImageIndex = nextIdx;
            updateImage();
            checkAndLoadNextPage();
            if (store.autoPlay) autoPlay.start();
            return;
          }
        }
        if (nextIdx < store.allImages.length || imageErrored) {
          clearLoadPoll();
          store.currentImageIndex = nextIdx < store.allImages.length ? nextIdx : idx;
          updateImage();
          if (nextIdx < store.allImages.length) {
            checkAndLoadNextPage();
          }
        }
      }
      if (lastKnownImg && lastKnownImg.tagName === "IMG") {
        lastKnownImg.addEventListener("load", onImageReady, { once: true });
        lastKnownImg.addEventListener("error", onImageError, { once: true });
      }
      const mainBox = document.querySelector(store.settings.scrollMode ? "#gdt" : "#gdt-hidden");
      if (mainBox) {
        loadObserver = new MutationObserver(() => {
          if (store.currentImageIndex !== idx) {
            clearLoadPoll();
            return;
          }
          syncImages();
          const currentImg = store.allImages[idx];
          if (currentImg) {
            if (currentImg.classList.contains("error")) {
              showError();
              return;
            } else if (currentImg.classList.contains("loading")) {
              showPlaceholder(i18n.downloading);
              return;
            }
            const imgSrc = currentImg.dataset.realSrc || currentImg.src;
            applyOverlaySrc(imgSrc, currentImg);
            if (currentImg !== lastKnownImg) {
              lastKnownImg = currentImg;
              if (currentImg.tagName === "IMG") {
                currentImg.addEventListener("load", onImageReady, { once: true });
                currentImg.addEventListener("error", onImageError, { once: true });
                if (isImageReady(currentImg)) onImageReady();
              }
            }
          }
        });
        loadObserver.observe(mainBox, { childList: true, subtree: true });
      }
      loadPollTimer = setInterval(() => {
        if (store.currentImageIndex !== idx) {
          clearLoadPoll();
          return;
        }
        const currentImg = store.allImages[idx];
        if (currentImg) {
          if (currentImg.classList.contains("error")) {
            showError();
            return;
          } else if (currentImg.classList.contains("loading")) {
            showPlaceholder(i18n.downloading);
            return;
          }
          const imgSrc = currentImg.dataset.realSrc || currentImg.src;
          applyOverlaySrc(imgSrc, currentImg);
          if (currentImg !== lastKnownImg) {
            lastKnownImg = currentImg;
            if (currentImg.tagName === "IMG") {
              currentImg.addEventListener("load", onImageReady, { once: true });
              currentImg.addEventListener("error", onImageError, { once: true });
            }
          }
        }
        onImageReady();
      }, 500);
      if (store.autoPlay) {
        loadTimeoutTimer = setTimeout(() => {
          if (store.currentImageIndex !== idx) return;
          const img = store.allImages[idx];
          if (img && isImageReady(img)) return;
          tryAutoSkip();
        }, CFG.imageLoadTimeout);
      }
    }
    const autoPlay = createAutoPlay(() => nav.nextImage());
    const sidebar = createSidebar((index) => {
      store.currentImageIndex = index;
      updateImage();
      autoPlay.reset();
    }, () => loadNextPage(), () => loadPrevPage());
    const nav = setupNavigation({
      overlay,
      updateImage,
      checkAndLoadNextPage: () => checkAndLoadNextPage(),
      checkAndLoadPrevPage: () => loadPrevPage(),
      resetAutoPlay: () => autoPlay.reset(),
      stopAutoPlayAtEnd: () => autoPlay.stopAtEnd(),
      closeSinglePageMode: () => close()
    });
    overlay.addEventListener("wheel", () => {
      sidebar.wakeUpProgressBar();
    }, { passive: true });
    overlay.appendChild(closeBtn);
    sidebar.getElements().forEach((el) => overlay.appendChild(el));
    overlay.appendChild(statusHUD.getElement());
    overlay.appendChild(imageContainer);
    document.body.appendChild(overlay);
    closeBtn.onclick = () => close();
    function open() {
      var _a, _b;
      store.allImages = Array.from(qa(".r-img, .r-ph"));
      if (store.allImages.length === 0) {
        alert(i18n.waitImagesToLoad);
        return;
      }
      let startIndex = 0;
      if (store.settings.scrollMode) {
        let minDistance = Infinity;
        store.allImages.forEach((img, index) => {
          const rect = img.getBoundingClientRect();
          const viewportCenter = window.innerHeight / 2;
          if (rect.top <= viewportCenter && rect.bottom >= viewportCenter) {
            startIndex = index;
            minDistance = -1;
          } else if (minDistance !== -1) {
            const distanceToCenter = rect.bottom < viewportCenter ? viewportCenter - rect.bottom : rect.top - viewportCenter;
            if (distanceToCenter < minDistance) {
              minDistance = distanceToCenter;
              startIndex = index;
            }
          }
        });
      } else {
        const adapter = store.activeAdapter;
        let nativeImages = [];
        if (adapter == null ? void 0 : adapter.getNativeImages) {
          nativeImages = adapter.getNativeImages();
        } else {
          const container = adapter == null ? void 0 : adapter.getContainer();
          if (container) {
            nativeImages = Array.from(container.querySelectorAll("img")).filter((img) => img.clientWidth > 50 || img.clientHeight > 50);
          }
        }
        if (nativeImages.length > 0) {
          let minDistance = Infinity;
          let bestNativeImg = null;
          nativeImages.forEach((img) => {
            const rect = img.getBoundingClientRect();
            if (rect.width === 0 || rect.height === 0) return;
            const viewportCenter = window.innerHeight / 2;
            if (rect.top <= viewportCenter && rect.bottom >= viewportCenter) {
              bestNativeImg = img;
              minDistance = -1;
            } else if (minDistance !== -1) {
              const distanceToCenter = rect.bottom < viewportCenter ? viewportCenter - rect.bottom : rect.top - viewportCenter;
              if (distanceToCenter < minDistance) {
                minDistance = distanceToCenter;
                bestNativeImg = img;
              }
            }
          });
          if (bestNativeImg) {
            const currentSrc = ((_a = bestNativeImg.dataset) == null ? void 0 : _a.viewerUrl) || ((_b = bestNativeImg.dataset) == null ? void 0 : _b.src) || bestNativeImg.src;
            const foundIdx = store.allImages.findIndex((i) => {
              var _a2, _b2, _c;
              const iSrc = ((_a2 = i.dataset) == null ? void 0 : _a2.viewerUrl) || ((_b2 = i.dataset) == null ? void 0 : _b2.realSrc) || ((_c = i.dataset) == null ? void 0 : _c.src) || i.src;
              return iSrc === currentSrc;
            });
            if (foundIdx !== -1) {
              startIndex = foundIdx;
            }
          }
        } else {
          startIndex = 0;
        }
      }
      store.currentImageIndex = startIndex;
      overlay.classList.add("active");
      document.body.style.overflow = "hidden";
      updateImage();
      store.emit("readerModeChanged");
      if (store.autoPlay) {
        autoPlay.start();
      }
    }
    function close() {
      var _a, _b;
      clearLoadPoll();
      removeErrorUI();
      autoPlay.stop();
      store.autoPlay = false;
      overlay.classList.remove("active");
      document.body.style.overflow = "";
      store.emit("readerModeChanged");
      if (store.settings.scrollMode) {
        const currentImages = Array.from(qa(".r-img, .r-ph"));
        if (store.currentImageIndex >= 0 && store.currentImageIndex < currentImages.length) {
          const targetImg = currentImages[store.currentImageIndex];
          if (targetImg) {
            setTimeout(() => {
              targetImg.scrollIntoView({ behavior: "smooth", block: "center" });
            }, 100);
          }
        }
      } else {
        const adapter = store.activeAdapter;
        let nativeImages = [];
        if (adapter == null ? void 0 : adapter.getNativeImages) {
          nativeImages = adapter.getNativeImages();
        } else {
          const container = adapter == null ? void 0 : adapter.getContainer();
          if (container) {
            nativeImages = Array.from(container.querySelectorAll("img")).filter((img) => img.clientWidth > 50 || img.clientHeight > 50);
          }
        }
        const targetImgFallback = store.allImages[store.currentImageIndex];
        const batchDiv = targetImgFallback == null ? void 0 : targetImgFallback.closest(".page-batch");
        if (batchDiv && batchDiv.dataset.pageUrl) {
          const targetUrl = new URL(batchDiv.dataset.pageUrl, window.location.href);
          const currentUrl = new URL(window.location.href);
          if (targetUrl.pathname !== currentUrl.pathname || targetUrl.search !== currentUrl.search) {
            window.location.href = targetUrl.toString();
            return;
          }
        }
        if (store.currentImageIndex >= 0 && nativeImages.length > 0) {
          const currentSrc = ((_a = targetImgFallback == null ? void 0 : targetImgFallback.dataset) == null ? void 0 : _a.viewerUrl) || ((_b = targetImgFallback == null ? void 0 : targetImgFallback.dataset) == null ? void 0 : _b.realSrc) || (targetImgFallback == null ? void 0 : targetImgFallback.src);
          if (currentSrc) {
            const targetNativeImg = nativeImages.find((img) => {
              var _a2, _b2;
              const nativeSrc = ((_a2 = img.dataset) == null ? void 0 : _a2.viewerUrl) || ((_b2 = img.dataset) == null ? void 0 : _b2.src) || img.src;
              return nativeSrc === currentSrc;
            });
            if (targetNativeImg) {
              setTimeout(() => {
                targetNativeImg.scrollIntoView({ behavior: "smooth", block: "center" });
              }, 100);
              return;
            }
          }
        }
        if ((adapter == null ? void 0 : adapter.name) === "E-Hentai" || (adapter == null ? void 0 : adapter.name) === "ExHentai") {
          const globalIndex = store.imageOffset + store.currentImageIndex;
          if (globalIndex >= 0) {
            const targetPage = Math.floor(globalIndex / store.perPage);
            const url = new URL(window.location.href);
            const currentPage = parseInt(url.searchParams.get("p") || "0");
            if (targetPage !== currentPage) {
              url.searchParams.set("p", String(targetPage));
              window.location.href = url.toString();
            }
          }
        }
      }
    }
    store.on("settingsChanged", () => {
      if (!overlay.classList.contains("active")) return;
      if (store.autoPlay) {
        const img = store.allImages[store.currentImageIndex];
        if (img && isImageReady(img)) {
          autoPlay.start();
        }
      } else {
        autoPlay.stop();
      }
    });
    function loadNextPage() {
      if (!store.nextUrl || store.isFetching) return;
      store.isFetching = true;
      store.activeAdapter.fetchPage(store.nextUrl).then(({ links, nextUrl, prevUrl }) => {
        deps.onLoadNextPage(links, nextUrl, prevUrl);
        syncImages();
        store.isFetching = false;
        checkAndLoadNextPage();
      }).catch((err) => {
        console.error("[Single Page] Load failed", err);
        store.isFetching = false;
      });
    }
    function loadPrevPage() {
      if (!store.prevUrl || store.isFetching) return;
      store.isFetching = true;
      store.activeAdapter.fetchPage(store.prevUrl).then(({ links, prevUrl }) => {
        const prevCount = links.length;
        deps.onLoadPrevPage(links, prevUrl ?? null);
        store.currentImageIndex += prevCount;
        store.imageOffset = Math.max(0, store.imageOffset - prevCount);
        if (prevCount > 0 && store.currentImageIndex === prevCount) {
          store.currentImageIndex--;
        }
        store.allImages = Array.from(qa(".r-img, .r-ph"));
        sidebar.update();
        updateImage();
        store.isFetching = false;
      }).catch((err) => {
        console.error("[Single Page] Load prev failed", err);
        store.isFetching = false;
      });
    }
    function checkAndLoadNextPage() {
      if (!store.nextUrl || store.isFetching) return;
      const remainingImages = store.allImages.length - store.currentImageIndex;
      if (remainingImages <= 10) {
        loadNextPage();
      }
    }
    function jumpTo(index) {
      if (!overlay.classList.contains("active")) return;
      store.currentImageIndex = Math.max(0, Math.min(index, store.allImages.length - 1));
      updateImage();
      autoPlay.reset();
    }
    return {
      open,
      close,
      isActive: () => overlay.classList.contains("active"),
      getOverlayElement: () => overlay,
      jumpTo
    };
  }
  function initSinglePageMode() {
    const spm = createSinglePageOverlay({
      onLoadNextPage: (links, nextUrl) => {
        store.currPage++;
        processBatch(links, store.currPage, void 0, false, store.nextUrl || void 0);
        store.nextUrl = nextUrl;
      },
      onLoadPrevPage: (links, prevUrl) => {
        processBatch(links, store.currPage - 1, void 0, true, store.prevUrl || void 0);
        store.prevUrl = prevUrl;
      }
    });
    return spm;
  }
  const svgSettings = `<svg viewBox="0 0 24 24"><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/></svg>`;
  const svgReader = `<svg viewBox="0 0 24 24"><path d="M21 5c-1.11-.35-2.33-.5-3.5-.5-1.95 0-4.05.4-5.5 1.5-1.45-1.1-3.55-1.5-5.5-1.5S2.45 4.9 1 6v14.65c0 .25.25.5.5.5.1 0 .15-.05.25-.05C3.1 20.45 5.05 20 6.5 20c1.95 0 4.05.4 5.5 1.5 1.35-.85 3.8-1.5 5.5-1.5 1.65 0 3.35.3 4.75 1.05.1.05.15.05.25.05.25 0 .5-.25.5-.5V6c-.6-.45-1.25-.75-2-1zm0 13.5c-1.1-.35-2.3-.5-3.5-.5-1.7 0-4.15.65-5.5 1.5V8c1.35-.85 3.8-1.5 5.5-1.5 1.2 0 2.4.15 3.5.5v11.5z"/></svg>`;
  const svgPlay = `<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>`;
  const svgPause = `<svg viewBox="0 0 24 24"><path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/></svg>`;
  const svgTop = `<svg viewBox="0 0 24 24"><path d="M4 4h16v2H4V4zm4 8l1.41 1.41L11 11.83V22h2V11.83l1.59 1.58L16 12l-4-4-4 4z"/></svg>`;
  const SETTINGS = [
    { label: i18n.scrollMode, key: "scrollMode" },
    { label: i18n.showControl, key: "showControl" },
    { label: i18n.autoEnter, key: "autoEnterSinglePage" }
  ];
  function createSettingsPanel() {
    const settingsBtn = document.createElement("div");
    settingsBtn.className = "settings-btn";
    const settingsPanel = document.createElement("div");
    settingsPanel.className = "settings-panel";
    SETTINGS.forEach(({ label, key }) => {
      if (key === "scrollMode" && store.activeAdapter && ["18comic", "4KHD"].includes(store.activeAdapter.name)) {
        return;
      }
      const item = document.createElement("div");
      item.className = "settings-item";
      const labelEl = document.createElement("span");
      labelEl.className = "settings-label";
      labelEl.textContent = label;
      const toggle = document.createElement("div");
      toggle.className = `toggle-switch${store.settings[key] ? " on" : ""}`;
      const slider = document.createElement("div");
      slider.className = "toggle-slider";
      toggle.appendChild(slider);
      toggle.onclick = () => {
        const newValue = !store.settings[key];
        store.updateSetting(key, newValue);
        toggle.classList.toggle("on", newValue);
        if (key === "scrollMode") {
          window.location.reload();
        }
      };
      item.appendChild(labelEl);
      item.appendChild(toggle);
      settingsPanel.appendChild(item);
    });
    const intervalItem = document.createElement("div");
    intervalItem.className = "settings-item";
    const intervalLabel = document.createElement("span");
    intervalLabel.className = "settings-label";
    intervalLabel.textContent = i18n.playSpeed;
    const intervalRight = document.createElement("div");
    intervalRight.style.cssText = "display:flex;align-items:center;gap:4px;";
    const intervalInput = document.createElement("input");
    intervalInput.type = "number";
    intervalInput.className = "interval-input";
    intervalInput.min = "1";
    intervalInput.max = "60";
    intervalInput.step = "0.5";
    intervalInput.value = String(store.settings.autoPlayInterval / 1e3);
    intervalInput.onclick = (e) => e.stopPropagation();
    intervalInput.onchange = (e) => {
      const value = parseFloat(e.target.value);
      if (!isNaN(value) && value >= 1 && value <= 60) {
        store.updateSetting("autoPlayInterval", value * 1e3);
      }
    };
    const intervalUnit = document.createElement("span");
    intervalUnit.textContent = "s";
    intervalUnit.style.cssText = "font-size:12px;color:#888;";
    intervalRight.appendChild(intervalInput);
    intervalRight.appendChild(intervalUnit);
    intervalItem.appendChild(intervalLabel);
    intervalItem.appendChild(intervalRight);
    settingsPanel.appendChild(intervalItem);
    settingsBtn.onclick = (e) => {
      e.stopPropagation();
      settingsPanel.classList.toggle("show");
    };
    document.addEventListener("click", (e) => {
      if (!settingsPanel.contains(e.target) && !settingsBtn.contains(e.target)) {
        settingsPanel.classList.remove("show");
      }
    });
    return {
      getButtonElement: () => settingsBtn,
      getPanelElement: () => settingsPanel
    };
  }
  function createFloatControl(spmHandle) {
    const floatControl = document.createElement("div");
    floatControl.className = `float-control${store.settings.showControl ? "" : " hidden"}`;
    const autoPlayBtn = document.createElement("div");
    autoPlayBtn.className = `side-btn auto-play-btn hidden${store.autoPlay ? " active" : ""}`;
    autoPlayBtn.innerHTML = store.autoPlay ? svgPause : svgPlay;
    autoPlayBtn.title = i18n.autoPlay;
    autoPlayBtn.onclick = (e) => {
      e.stopPropagation();
      const newValue = !store.autoPlay;
      store.autoPlay = newValue;
      store.emit("settingsChanged");
      autoPlayBtn.innerHTML = newValue ? svgPause : svgPlay;
      autoPlayBtn.classList.toggle("active", newValue);
    };
    const circleControl = document.createElement("div");
    circleControl.className = "circle-control";
    circleControl.innerHTML = svgReader;
    circleControl.title = i18n.readerMode;
    circleControl.onclick = (e) => {
      var _a;
      if (e.target !== circleControl && !((_a = circleControl.querySelector("svg")) == null ? void 0 : _a.contains(e.target))) return;
      if (spmHandle.isActive()) {
        spmHandle.close();
      } else {
        spmHandle.open();
      }
    };
    store.on("readerModeChanged", () => {
      if (spmHandle.isActive()) {
        autoPlayBtn.classList.remove("hidden");
        autoPlayBtn.innerHTML = store.autoPlay ? svgPause : svgPlay;
        autoPlayBtn.classList.toggle("active", store.autoPlay);
      } else {
        autoPlayBtn.classList.add("hidden");
      }
    });
    const settings = createSettingsPanel();
    const settingsBtn = settings.getButtonElement();
    settingsBtn.className = "side-btn";
    settingsBtn.innerHTML = svgSettings;
    settingsBtn.title = i18n.settings;
    const topBtn = document.createElement("div");
    topBtn.className = "side-btn top-btn";
    topBtn.innerHTML = svgTop;
    topBtn.title = i18n.backToTop;
    topBtn.onclick = (e) => {
      e.stopPropagation();
      if (spmHandle.isActive()) {
        spmHandle.jumpTo(0);
      } else {
        window.scrollTo({ top: 0, behavior: "smooth" });
        document.documentElement.scrollTo({ top: 0, behavior: "smooth" });
        document.body.scrollTo({ top: 0, behavior: "smooth" });
      }
    };
    circleControl.appendChild(topBtn);
    floatControl.appendChild(autoPlayBtn);
    floatControl.appendChild(circleControl);
    floatControl.appendChild(settingsBtn);
    floatControl.appendChild(settings.getPanelElement());
    document.body.appendChild(floatControl);
  }
  function registerMenuCommands() {
    if (!store.activeAdapter || !["18comic", "4KHD"].includes(store.activeAdapter.name)) {
      _GM_registerMenuCommand(`${i18n.toggle}${i18n.scrollMode}`, () => {
        store.updateSetting("scrollMode", !store.settings.scrollMode);
        alert(`${i18n.scrollMode} ${store.settings.scrollMode ? i18n.enabled : i18n.disabled}`);
        location.reload();
      });
    }
    _GM_registerMenuCommand(`${i18n.toggle}${i18n.showControl}`, () => {
      store.updateSetting("showControl", !store.settings.showControl);
      alert(`${i18n.showControl} ${store.settings.showControl ? i18n.enabled : i18n.disabled}`);
      location.reload();
    });
    _GM_registerMenuCommand(`${i18n.toggle}${i18n.autoEnter}`, () => {
      store.updateSetting("autoEnterSinglePage", !store.settings.autoEnterSinglePage);
      alert(`${i18n.autoEnter} ${store.settings.autoEnterSinglePage ? i18n.enabled : i18n.disabled}`);
      location.reload();
    });
  }
  function initMemoryManager() {
    const mainBox = document.querySelector(store.settings.scrollMode ? "#gdt" : "#gdt-hidden");
    if (mainBox) {
      const domObs = new MutationObserver(() => {
        const images = Array.from(qa(".r-img, .r-ph"));
        let changed = images.length !== store.allImages.length;
        if (!changed) {
          for (let i = 0; i < images.length; i++) {
            if (images[i] !== store.allImages[i]) {
              changed = true;
              break;
            }
          }
        }
        if (changed) {
          store.allImages = images;
        }
      });
      domObs.observe(mainBox, { childList: true, subtree: true });
    }
    setInterval(() => {
      if (store.allImages.length < 40) return;
      if (document.querySelector(".single-page-overlay.active")) return;
      const viewportCenter = window.innerHeight / 2;
      let minDistance = Infinity;
      let closestIndex = store.currentImageIndex;
      store.allImages.forEach((el, i) => {
        const rect = el.getBoundingClientRect();
        if (rect.height > 0) {
          const center = rect.top + rect.height / 2;
          const dist = Math.abs(center - viewportCenter);
          if (dist < minDistance) {
            minDistance = dist;
            closestIndex = i;
          }
        }
      });
      store.currentImageIndex = closestIndex;
      const curr = store.currentImageIndex;
      const buffer = 30;
      store.allImages.forEach((img, i) => {
        const distance = Math.abs(i - curr);
        if (distance > buffer) {
          if (img.tagName === "IMG" && img.hasAttribute("src") && img.complete) {
            img.dataset.recycledSrc = img.getAttribute("src") || "";
            img.removeAttribute("src");
          }
        } else {
          if (img.tagName === "IMG" && !img.hasAttribute("src") && img.dataset.recycledSrc) {
            img.setAttribute("src", img.dataset.recycledSrc);
            delete img.dataset.recycledSrc;
          }
        }
      });
    }, 2e3);
  }
  (async function main() {
    var _a;
    const adapter = SiteManager.getAdapter(window.location.href);
    if (!adapter) {
      return;
    }
    store.activeAdapter = adapter;
    store.reloadSettings();
    if (adapter.name === "18comic" || adapter.name === "4KHD") {
      store.settings.scrollMode = true;
    }
    const initData = await adapter.init(document);
    if (!initData.links || initData.links.length === 0) return;
    store.totalPage = initData.totalPage ?? 1;
    store.nextUrl = initData.nextUrl;
    store.prevUrl = initData.prevUrl;
    store.perPage = initData.links.length;
    let container = adapter.getContainer();
    if (store.settings.scrollMode) {
      document.documentElement.classList.add("scroll-mode");
      (_a = adapter.hideOriginalElements) == null ? void 0 : _a.call(adapter);
      if (!container) {
        container = document.createElement("div");
        container.id = "gdt";
        document.body.appendChild(container);
      }
      container.innerHTML = "";
      processBatch(initData.links, store.currPage, container, false, window.location.href);
      setupAutoScroll();
    } else {
      const hiddenBox = document.createElement("div");
      hiddenBox.id = "gdt-hidden";
      hiddenBox.style.display = "none";
      document.body.appendChild(hiddenBox);
      processBatch(initData.links, store.currPage, hiddenBox, false, window.location.href);
    }
    let spmHandle;
    createFloatControl({
      open: () => spmHandle.open(),
      close: () => spmHandle.close(),
      isActive: () => spmHandle.isActive(),
      getOverlayElement: () => spmHandle.getOverlayElement(),
      jumpTo: (index) => spmHandle.jumpTo(index)
    });
    spmHandle = initSinglePageMode();
    registerMenuCommands();
    if (store.settings.autoEnterSinglePage) {
      setTimeout(() => spmHandle.open(), 1e3);
    }
    initMemoryManager();
  })();

})();