Web-Font-Rendering-Core

全端统一交互:强制单行横向滚动预览,PC/移动端体验一致。支持全量画廊与静默坏图过滤。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Web-Font-Rendering-Core
// @namespace    http://tampermonkey.net/
// @version      2.6.0
// @description  全端统一交互:强制单行横向滚动预览,PC/移动端体验一致。支持全量画廊与静默坏图过滤。
// @author       Gemini-Adaptive
// @license      MIT
// @match        *://t66y.com/*
// @match        *://www.t66y.com/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

;(() => {
    const countRegex = /\d+[pP]/;

    const style = document.createElement('style');
    style.textContent = `
        /* --- 1. 统一列表预览容器 --- */
        .sys-list-container {
            display: flex;
            gap: 12px;
            margin: 15px 0;
            padding: 5px 2px 15px 2px; /* 底部预留空间给滚动条 */
            clear: both;
            flex-wrap: nowrap;
            overflow-x: auto;
            overflow-y: hidden;
            -webkit-overflow-scrolling: touch;
            /* 改善 PC 端滚动条样式,不隐藏它以便于鼠标拖动 */
            scrollbar-width: thin;
            scrollbar-color: #555 #222;
        }

        /* Webkit 滚动条美化 (PC端) */
        .sys-list-container::-webkit-scrollbar {
            height: 6px;
        }
        .sys-list-container::-webkit-scrollbar-track {
            background: #1a1a1a;
            border-radius: 10px;
        }
        .sys-list-container::-webkit-scrollbar-thumb {
            background: #444;
            border-radius: 10px;
        }
        .sys-list-container::-webkit-scrollbar-thumb:hover {
            background: #666;
        }

        /* --- 2. 统一缩略图尺寸 --- */
        .sys-list-thumb {
            height: 280px; /* 统一高度,兼顾视觉冲击力与排版 */
            width: auto;
            flex: 0 0 auto;
            border-radius: 8px;
            object-fit: cover;
            background: #222;
            cursor: zoom-in;
            box-shadow: 0 4px 12px rgba(0,0,0,0.4);
            transition: transform 0.2s;
        }
        .sys-list-thumb:hover {
            transform: translateY(-2px);
        }

        /* --- 3. 查看器与画廊 (保持高质交互) --- */
        .sys-viewer-overlay {
            position: fixed; top: 0; left: 0; width: 100%; height: 100%;
            background: rgba(0, 0, 0, 0.98); display: flex; flex-direction: column;
            align-items: center; justify-content: center; z-index: 999999;
            opacity: 0; pointer-events: none; transition: opacity 0.3s ease;
            outline: none; touch-action: none;
        }
        .sys-viewer-overlay.active { opacity: 1; pointer-events: auto; }
        .sys-viewer-stage { flex: 1; width: 100%; display: flex; align-items: center; justify-content: center; overflow: hidden; position: relative; }
        .sys-viewer-node { max-width: 98%; max-height: 98%; object-fit: contain; transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1), opacity 0.3s; opacity: 0; will-change: transform; cursor: zoom-out; }
        .sys-viewer-overlay.active .sys-viewer-node.loaded { opacity: 1; }

        .sys-viewer-error { display: none; color: #888; text-align: center; }
        .sys-viewer-overlay.img-error .sys-viewer-error { display: block; }
        .sys-viewer-overlay.img-error .sys-viewer-node { display: none; }

        .sys-viewer-gallery {
            width: 100%; height: 110px; background: rgba(0,0,0,0.8);
            display: flex; gap: 8px; padding: 10px; overflow-x: auto;
            border-top: 1px solid rgba(255,255,255,0.1); backdrop-filter: blur(15px);
            scrollbar-width: none;
        }
        .sys-viewer-gallery::-webkit-scrollbar { display: none; }
        .sys-gallery-item { height: 90px; width: auto; flex: 0 0 auto; border-radius: 4px; cursor: pointer; border: 2px solid transparent; transition: all 0.2s; opacity: 0.5; object-fit: cover; }
        .sys-gallery-item.current { border-color: #fff; opacity: 1; transform: scale(1.05); }

        .sys-loader { position: absolute; width: 40px; height: 40px; border: 3px solid rgba(255,255,255,0.1); border-radius: 50%; border-top-color: #fff; animation: sys-spin 0.8s linear infinite; display: none; }
        .sys-viewer-overlay.loading .sys-loader { display: block; }
        @keyframes sys-spin { to { transform: rotate(360deg); } }
    `;
    document.head.appendChild(style);

    // --- 结构初始化与逻辑 (逻辑部分保持健壮) ---
    const overlay = document.createElement('div');
    overlay.className = 'sys-viewer-overlay';
    overlay.tabIndex = 0;
    const stage = document.createElement('div');
    stage.className = 'sys-viewer-stage';
    const gallery = document.createElement('div');
    gallery.className = 'sys-viewer-gallery';
    const loader = document.createElement('div');
    loader.className = 'sys-loader';
    const errorTip = document.createElement('div');
    errorTip.className = 'sys-viewer-error';
    errorTip.innerHTML = '<div style="font-size:30px;">⚠️</div>加载失败';
    const bigImg = document.createElement('img');
    bigImg.className = 'sys-viewer-node';

    stage.append(loader, errorTip, bigImg);
    overlay.append(stage, gallery);
    document.body.appendChild(overlay);

    let currentSrcList = [];
    let currentImgIndex = -1;
    let startX = 0, deltaX = 0, isDragging = false;

    const setupImageErrorFilter = (imgNode) => {
        imgNode.onerror = () => { imgNode.style.display = 'none'; };
    };

    const updateViewer = (index) => {
        if (index < 0 || index >= currentSrcList.length) {
            bigImg.style.transform = `translateX(0px)`;
            return;
        }
        currentImgIndex = index;
        overlay.classList.add('loading');
        overlay.classList.remove('img-error');
        bigImg.classList.remove('loaded');
        bigImg.style.transition = 'none';
        bigImg.style.transform = `translateX(0px) scale(0.98)`;
        bigImg.src = currentSrcList[currentImgIndex];

        Array.from(gallery.children).forEach((item, idx) => {
            const isCurrent = idx === currentImgIndex;
            item.classList.toggle('current', isCurrent);
            if (isCurrent) item.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' });
        });
    };

    const releaseView = () => {
        overlay.classList.remove('active', 'loading', 'img-error');
        document.body.style.overflow = '';
        setTimeout(() => { bigImg.src = ''; gallery.innerHTML = ''; }, 300);
    };

    // 事件绑定
    bigImg.onclick = (e) => { e.stopPropagation(); releaseView(); };
    overlay.onclick = (e) => { if(e.target === stage || e.target === overlay) releaseView(); };
    overlay.onkeydown = (e) => {
        if (e.key === 'Escape') releaseView();
        if (e.key === 'ArrowLeft') updateViewer(currentImgIndex - 1);
        if (e.key === 'ArrowRight') updateViewer(currentImgIndex + 1);
    };

    // 触摸滑动逻辑
    stage.addEventListener('touchstart', (e) => {
        if (e.touches.length > 1) return;
        startX = e.touches[0].clientX;
        deltaX = 0; isDragging = true;
        bigImg.style.transition = 'none';
    }, { passive: false });

    stage.addEventListener('touchmove', (e) => {
        if (!isDragging) return;
        deltaX = e.touches[0].clientX - startX;
        if (Math.abs(deltaX) > 5) {
            e.preventDefault();
            bigImg.style.transform = `translateX(${deltaX}px)`;
        }
    }, { passive: false });

    stage.addEventListener('touchend', () => {
        if (!isDragging) return;
        isDragging = false;
        bigImg.style.transition = 'transform 0.3s cubic-bezier(0.2, 0, 0.2, 1)';
        if (Math.abs(deltaX) > window.innerWidth * 0.15) {
            deltaX > 0 ? updateViewer(currentImgIndex - 1) : updateViewer(currentImgIndex + 1);
        } else {
            bigImg.style.transform = `translateX(0px)`;
        }
    }, { passive: false });

    bigImg.onload = () => { overlay.classList.remove('loading', 'img-error'); bigImg.classList.add('loaded'); bigImg.style.transform = `translateX(0px) scale(1)`; };
    bigImg.onerror = () => { overlay.classList.remove('loading'); overlay.classList.add('img-error'); };

    const openViewer = async (targetSrc, containerSelector, imgSelector) => {
        const container = document.querySelector(containerSelector);
        let imgs = container ? Array.from(container.querySelectorAll(imgSelector)) : [];
        currentSrcList = imgs.map(img => img.getAttribute('ess-data') || img.src).filter(s => s && !s.includes('adblo_ck'));

        if (currentSrcList.length < 15 && container && container.dataset.fullurl) {
             overlay.classList.add('loading');
             try {
                const res = await fetch(container.dataset.fullurl);
                const text = await res.text();
                const doc = new DOMParser().parseFromString(text, 'text/html');
                const area = doc.querySelector('#conttpc');
                if (area) {
                    const fullImgs = Array.from(area.querySelectorAll('img[ess-data]')).map(el => {
                         let s = el.getAttribute("ess-data");
                         return s.startsWith('//') ? 'https:' + s : s;
                    }).filter(s => s && !s.includes('adblo_ck'));
                    if (fullImgs.length > currentSrcList.length) currentSrcList = fullImgs;
                }
             } catch (e) {}
             overlay.classList.remove('loading');
        }

        currentImgIndex = currentSrcList.indexOf(targetSrc);
        if (currentImgIndex === -1) currentImgIndex = 0;

        if (currentSrcList.length > 0) {
            gallery.innerHTML = '';
            currentSrcList.forEach((src, idx) => {
                const thumb = document.createElement('img');
                thumb.className = 'sys-gallery-item';
                thumb.src = src;
                thumb.onclick = (e) => { e.stopPropagation(); updateViewer(idx); };
                setupImageErrorFilter(thumb);
                gallery.appendChild(thumb);
            });
            document.body.style.overflow = 'hidden';
            overlay.classList.add('active');
            overlay.focus();
            updateViewer(currentImgIndex);
        }
    };

    async function fetchPreview(item, url, title) {
        if (!countRegex.test(title) || item.dataset.proc === "1") return;
        item.dataset.proc = "1";
        try {
            const res = await fetch(url);
            const text = await res.text();
            const doc = new DOMParser().parseFromString(text, 'text/html');
            const area = doc.querySelector('#conttpc');
            if (!area) return;
            const allImgs = Array.from(area.querySelectorAll('img[ess-data]'));
            if (!allImgs.length) return;

            const box = document.createElement("div");
            box.className = "sys-list-container";
            box.dataset.fullurl = url;

            allImgs.slice(0, 12).forEach(el => {
                let s = el.getAttribute("ess-data");
                if (s.startsWith('//')) s = 'https:' + s;
                const t = document.createElement("img");
                t.src = s;
                t.className = "sys-list-thumb";
                t.loading = "lazy";
                t.onclick = (e) => {
                    e.preventDefault(); e.stopPropagation();
                    openViewer(s, `.sys-list-container[data-fullurl="${url}"]`, '.sys-list-thumb');
                };
                setupImageErrorFilter(t);
                box.appendChild(t);
            });
            item.querySelector("h3").after(box);
        } catch (e) {}
    }

    // --- 初始化 ---
    const loc = window.location.href;
    if (loc.includes('/htm_data/')) {
        setTimeout(() => {
            const root = document.querySelector('#conttpc, .tpc_content');
            if (!root) return;
            root.querySelectorAll('img').forEach(img => {
                const src = img.getAttribute('ess-data') || img.src;
                if (!src || src.includes('adblo_ck') || src.includes('common/')) return;
                img.classList.add('sys-detail-node');
                img.onclick = (e) => { e.preventDefault(); openViewer(src, '#conttpc, .tpc_content', 'img.sys-detail-node'); };
            });
        }, 500);
    } else {
        const obs = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    const a = entry.target.querySelector("h3 > a");
                    if (a) fetchPreview(entry.target, a.href, a.innerText);
                    obs.unobserve(entry.target);
                }
            });
        }, { rootMargin: '800px' });
        document.querySelectorAll("tr.tac, tr.tal").forEach(r => { if (r.querySelector("h3 > a")) obs.observe(r); });
    }
})();