// ==UserScript== // @name nhentai 漫画下拉阅读模式(CSP 免弹窗版) // @namespace https://github/FENGLIAA // @version 0.2 // @description 下拉阅读模式,无需弹窗,直接插入页面 // @author FENGLIAA // @license MIT // @match https://nhentai.net/g/* // @grant GM_xmlhttpRequest // ==/UserScript== (function () { 'use strict'; const IMG_SELECTOR = '#image-container > a > img'; function getPageNum() { return document.querySelectorAll('.thumb-container').length; } function getPageUrls() { return Array.from(document.querySelectorAll('#thumbnail-container a')).map(a => a.href); } const pageNum = getPageNum(); if (!pageNum) return; const pageUrls = ['unused'].concat(getPageUrls()); const imgSrcMap = new Map(); // 创建阅读区域 const readBox = document.createElement('div'); readBox.id = 'nh-read-mode'; readBox.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #000; overflow-y: scroll; z-index: 999999; display: none; text-align: center; `; document.body.appendChild(readBox); // 创建关闭按钮 const closeBtn = document.createElement('button'); closeBtn.textContent = '✖ 关闭阅读'; closeBtn.style.cssText = ` position: fixed; top: 10px; right: 10px; z-index: 1000000; padding: 6px 10px; background: #e74c3c; color: #fff; border: none; border-radius: 4px; cursor: pointer; `; closeBtn.onclick = () => readBox.style.display = 'none'; document.body.appendChild(closeBtn); // 创建打开按钮 const openBtn = document.createElement('button'); openBtn.textContent = '📖 下拉阅读'; openBtn.style.cssText = ` position: fixed; bottom: 20px; right: 20px; z-index: 1000000; padding: 10px 14px; background: #27ae60; color: #fff; border: none; border-radius: 4px; cursor: pointer; `; openBtn.onclick = () => readBox.style.display = 'block'; document.body.appendChild(openBtn); // 加载所有图片 async function loadAllImages() { const promises = []; for (let i = 1; i <= pageNum; i++) { promises.push(loadImgSrc(i, pageUrls[i])); } await Promise.all(promises); renderImages(); } function loadImgSrc(page, url) { return new Promise(resolve => { GM_xmlhttpRequest({ method: 'GET', url: url, onload: resp => { const html = resp.responseText; const src = new DOMParser().parseFromString(html, 'text/html').querySelector(IMG_SELECTOR)?.src; if (src) imgSrcMap.set(page, src); resolve(); } }); }); } function renderImages() { const frag = document.createDocumentFragment(); for (let i = 1; i <= pageNum; i++) { const img = document.createElement('img'); img.src = imgSrcMap.get(i); img.style.cssText = 'width: 90%; max-width: 800px; margin: 20px auto; display: block;'; frag.appendChild(img); } readBox.appendChild(frag); } loadAllImages(); })();