twitter长图浏览优化

twitter上很多文字长图,总是以缩略图的形式显示,字根本看不清楚。以前有一些显示长图的插件,慢慢的都不能用了,只好自己动手搓了一个。我不会代码,零基础,全程AI编程,chrome和Firefox完美兼容,甚至比以前下载的插件体验更好。现在的程序员太幸福了。

点击查看代码
// ==UserScript==
// @name         Twitter/X 图片高清查看器 (v5.3 默认原图版)
// @namespace    http://tampermonkey.net/
// @version      5.3
// @description  默认以原图(Original)模式打开图片。支持模态窗口查看、点击空白/ESC退出。
// @author       Expert Analyst
// @match        *://twitter.com/*
// @match        *://x.com/*
// @match        *://*.twitter.com/*
// @match        *://*.x.com/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    console.log(">>> HD查看器 v5.3 (默认原图版) 已加载 <<<");

    // --- 全局变量 ---
    let currentModal = null;
    let scrollPosition = 0;

    // --- 1. 样式注入 ---
    function injectStyles() {
        const style = document.createElement('style');
        style.textContent = `
            /* 注入在推文图片上的小按钮 */
            .hd-btn-v5 {
                position: absolute; bottom: 6px; right: 6px;
                background: rgba(0,0,0,0.6); color: #fff;
                border: 1px solid rgba(255,255,255,0.5); border-radius: 4px;
                padding: 2px 8px; font-size: 11px; cursor: pointer;
                z-index: 90; font-family: system-ui, -apple-system, sans-serif; font-weight: bold;
                backdrop-filter: blur(2px); transition: background 0.2s;
            }
            .hd-btn-v5:hover { background: rgba(29, 155, 240, 0.9); border-color: transparent; }

            /* 模态窗口全屏遮罩 */
            #hd-modal-overlay {
                position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
                background: rgba(0, 0, 0, 0.92); z-index: 9999999;
                display: flex; flex-direction: column; align-items: center; justify-content: center;
                opacity: 0; animation: hd-fade-in 0.2s forwards;
            }

            /* 图片滚动容器 */
            #hd-image-wrapper {
                width: 100%; height: 100%;
                display: flex; align-items: center; justify-content: center;
                overflow: auto;
                padding: 0;
            }

            /* 图片通用样式 */
            .hd-viewer-img {
                transition: transform 0.2s;
                display: block;
            }

            /* --- 视图模式 --- */

            /* 适屏: 完整显示图片 */
            .hd-mode-contain .hd-viewer-img {
                max-width: 100vw; max-height: 100vh;
                width: auto; height: auto;
                object-fit: contain; cursor: zoom-in;
            }

            /* 适宽: 宽度填满 */
            .hd-mode-width #hd-image-wrapper {
                display: block;
                overflow-y: scroll;
            }
            .hd-mode-width .hd-viewer-img {
                width: 100vw; height: auto;
                max-width: none; max-height: none;
                margin: 0 auto; cursor: zoom-out;
            }

            /* 原图 (默认): 原始像素显示 */
            .hd-mode-original #hd-image-wrapper {
                display: flex; align-items: flex-start; justify-content: center;
                overflow: scroll;
            }
            .hd-mode-original .hd-viewer-img {
                width: auto; height: auto;
                max-width: none; max-height: none;
                cursor: zoom-out;
            }

            /* --- 底部控制栏 --- */
            #hd-controls {
                position: fixed;
                bottom: 20px; right: 20px;
                background: rgba(0, 0, 0, 0.5);
                padding: 8px 12px; border-radius: 8px;
                display: flex; gap: 8px;
                border: 1px solid rgba(255,255,255,0.1);
                opacity: 0.4;
                transition: opacity 0.3s, background 0.3s;
            }
            #hd-controls:hover {
                opacity: 1;
                background: rgba(0, 0, 0, 0.85);
            }

            .hd-control-btn {
                background: transparent; border: 1px solid rgba(255,255,255,0.3); color: white;
                padding: 4px 10px; border-radius: 4px; cursor: pointer; font-size: 12px;
                transition: all 0.2s; white-space: nowrap;
            }
            .hd-control-btn:hover { background: rgba(255,255,255,0.2); border-color: white; }
            .hd-control-btn.active { background: #1d9bf0; border-color: #1d9bf0; color: white; font-weight: bold; }

            /* 关闭按钮 */
            #hd-close-btn {
                position: fixed; top: 20px; right: 20px;
                width: 40px; height: 40px; border-radius: 50%;
                background: rgba(0,0,0,0.3); border: 1px solid rgba(255,255,255,0.2); color: white;
                font-size: 24px; cursor: pointer; display: flex; align-items: center; justify-content: center;
                transition: background 0.2s; z-index: 100;
            }
            #hd-close-btn:hover { background: rgba(255,255,255,0.4); }

            @keyframes hd-fade-in { from { opacity: 0; } to { opacity: 1; } }
        `;
        document.head.appendChild(style);
    }

    // --- 2. 模态窗口逻辑 ---
    function openModal(url) {
        if (currentModal) return;

        // 锁定背景滚动
        scrollPosition = window.scrollY;
        document.body.style.overflow = 'hidden';

        // 创建DOM
        const overlay = document.createElement('div');
        overlay.id = 'hd-modal-overlay';

        // === 修改点:默认设置为原图模式 ===
        overlay.className = 'hd-mode-original';

        overlay.innerHTML = `
            <div id="hd-image-wrapper">
                <img src="${url}" class="hd-viewer-img" alt="高清图片">
            </div>
            <button id="hd-close-btn" title="关闭 (ESC)">×</button>
            <div id="hd-controls">
                <button class="hd-control-btn" data-mode="contain">适屏</button>
                <button class="hd-control-btn" data-mode="width">适宽</button>
                <button class="hd-control-btn active" data-mode="original">原图</button>
            </div>
        `;

        document.body.appendChild(overlay);
        currentModal = overlay;

        const imgWrapper = overlay.querySelector('#hd-image-wrapper');
        const img = overlay.querySelector('.hd-viewer-img');
        const btns = overlay.querySelectorAll('.hd-control-btn');

        // 事件:点击空白处关闭
        imgWrapper.addEventListener('click', (e) => {
            if (e.target === imgWrapper) closeModal();
        });

        // 事件:点击关闭按钮
        overlay.querySelector('#hd-close-btn').addEventListener('click', closeModal);

        // 事件:ESC 键关闭
        const escHandler = (e) => {
            if (e.key === 'Escape') {
                e.preventDefault();
                e.stopPropagation();
                closeModal();
            }
        };
        window.addEventListener('keydown', escHandler, { capture: true });

        // 事件:模式切换按钮
        btns.forEach(btn => {
            btn.addEventListener('click', (e) => {
                e.stopPropagation();
                btns.forEach(b => b.classList.remove('active'));
                btn.classList.add('active');

                const mode = btn.dataset.mode;
                overlay.className = `hd-mode-${mode}`;
                if (mode === 'width') imgWrapper.scrollTop = 0;
            });
        });

        // 事件:点击图片快速切换 (原图 <-> 适屏)
        // 逻辑调整:如果当前是适屏,切原图;如果当前是原图,切适屏。
        img.addEventListener('click', (e) => {
            e.stopPropagation();
            const isContain = overlay.classList.contains('hd-mode-contain');
            // 如果现在是适屏,就点原图按钮;否则点适屏按钮
            const targetBtn = isContain ? '[data-mode="original"]' : '[data-mode="contain"]';
            overlay.querySelector(targetBtn).click();
        });

        // 挂载清理函数
        overlay.cleanup = () => {
            window.removeEventListener('keydown', escHandler, { capture: true });
        };
    }

    function closeModal() {
        if (!currentModal) return;
        if (currentModal.cleanup) currentModal.cleanup();

        currentModal.remove();
        currentModal = null;

        document.body.style.overflow = '';
        window.scrollTo(0, scrollPosition);
    }

    // --- 3. 按钮注入逻辑 ---
    function initObserver() {
        setInterval(() => {
            const images = document.querySelectorAll('img[src*="pbs.twimg.com/media/"]');

            images.forEach(img => {
                if (img.hasAttribute('data-hd-v5')) return;

                let parent = img.parentElement;
                for(let i=0; i<3; i++) {
                    if(!parent) break;
                    const testId = parent.getAttribute('data-testid');
                    if(testId === 'tweetPhoto' || testId === 'mediaContainer') break;
                    parent = parent.parentElement;
                }
                if (!parent) parent = img.parentElement;

                if (parent) {
                    img.setAttribute('data-hd-v5', 'true');

                    const style = window.getComputedStyle(parent);
                    if (style.position === 'static') {
                        parent.style.position = 'relative';
                    }

                    const btn = document.createElement('div');
                    btn.className = 'hd-btn-v5';
                    btn.innerText = 'HD';
                    btn.title = '查看高清大图';

                    btn.onclick = (e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        const urlObj = new URL(img.src);
                        urlObj.searchParams.set('name', 'orig');
                        openModal(urlObj.toString());
                    };

                    parent.appendChild(btn);
                }
            });
        }, 800);
    }

    // --- 4. 启动 ---
    if (document.readyState === 'complete') {
        injectStyles();
        initObserver();
    } else {
        window.addEventListener('load', () => {
            injectStyles();
            initObserver();
        });
    }

})();
posted @ 2025-11-22 12:20  布鲁伊  阅读(2)  评论(0)    收藏  举报