腾讯视频vip解析 - 带顶部日志

在腾讯视频页面顶部显示日志面板,用于调试和信息展示

// ==UserScript==
// @name         腾讯视频vip解析 - 带顶部日志
// @namespace    https://jixiejidiguan.top/A2zml/
// @version      2025-08-05
// @description  在腾讯视频页面顶部显示日志面板,用于调试和信息展示
// @author       jixiejidiguan.top
// @match        https://v.qq.com/x/cover/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=qq.com
// @grant        none
// @license      MT
// ==/UserScript==

(function () {
    'use strict';

    // 视频解析接口配置
    const videoParsers = [
        { id: 'parser1', name: '解析接口 1', url: 'https://jx.playerjy.com/?ads=0&url=' },
        { id: 'parser2', name: '解析接口 2', url: 'https://jx.xmflv.com/?url=' },
        { id: 'parser3', name: '解析接口 3', url: 'https://z1.190000000007.top/?jx=' },
        { id: 'parser4', name: '解析接口 4', url: 'https://jx.dmflv.cc/?url=' },
        { id: 'parser5', name: '解析接口 5', url: 'https://www.yemu.xyz/?url=' },
        { id: 'parser6', name: '解析接口 6', url: 'https://jx.nnxv.cn/tv.php?url=' }
    ];

    // 日志管理模块
    const LogManager = {
        panel: null,
        content: null,
        hideTimeout: null,

        // 初始化日志面板
        init() {
            if (this.isAlreadyInjected('tampermonkey-log-panel')) {
                this.content = document.getElementById('tampermonkey-log-content');
                return this.content;
            }

            this.panel = document.createElement('div');
            this.panel.id = 'tampermonkey-log-panel';
            this.panel.style.cssText = `
                position: fixed;
                top: 0;
                left: 0;
                right: 0;
                background: #1e1e1e79;
                color: #fff;
                z-index: 99999;
                padding: 10px;
                font-family: monospace;
                font-size: 14px;
                border-bottom: 2px solid #007acc;
                max-height: 200px;
                overflow-y: auto;
            `;

            const title = document.createElement('div');
            title.textContent = '🔧 TamperMonkey 脚本日志';
            title.style.cssText = `
                font-weight: bold;
                margin-bottom: 8px;
                color: #00d4ff;
            `;
            this.panel.appendChild(title);

            this.content = document.createElement('div');
            this.content.id = 'tampermonkey-log-content';
            this.content.style.cssText = `
                white-space: pre-wrap;
                word-break: break-word;
                line-height: 1.4;
            `;
            this.panel.appendChild(this.content);

            // 将日志面板添加到页面顶部
            document.body.appendChild(this.panel);

            // 全局日志方法
            window.logToPage = (msg, type = 'info') => this.log(msg, type);

            return this.content;
        },

        // 检查元素是否已注入
        isAlreadyInjected(id) {
            return document.getElementById(id) !== null;
        },

        // 记录日志
        log(msg, type = 'info') {
            if (!this.content) return;
            const time = new Date().toLocaleTimeString();
            const prefix = {
                error: '[❌ ERROR]',
                warn: '[⚠️ WARN]',
                info: '[ℹ️ INFO]',
                log: '[💬 LOG]'
            }[type] || '[💬 LOG]';

            // 创建新的日志行元素
            const logLine = document.createElement('div');
            logLine.textContent = `${time} ${prefix} ${msg}`;

            // 添加日志行到内容容器
            this.content.appendChild(logLine);

            // 显示日志面板
            this.show();

            // 清除之前的隐藏定时器
            if (this.hideTimeout) {
                clearTimeout(this.hideTimeout);
            }

            // 5秒后隐藏日志面板
            this.hideTimeout = setTimeout(() => this.hide(), 3000);
        },

        // 显示日志面板
        show() {
            if (this.panel) {
                this.panel.style.display = "block";
            }
        },

        // 隐藏日志面板
        hide() {
            if (this.panel) {
                this.panel.style.display = "none";
            }
        }
    };

    // 工具栏按钮模块
    const ToolbarButton = {
        element: null,

        // 初始化工具栏按钮
        init() {
            if (LogManager.isAlreadyInjected('custom-popup-button')) return;

            const btnContainer = document.createElement('div');
            btnContainer.id = 'custom-popup-button';
            btnContainer.style.cssText = `
                position: fixed;
                top: 50%;
                left: 20px;
                transform: translateY(-50%);
                z-index: 99999;
            `;

            const btn = document.createElement('button');
            btn.textContent = '🔧 打开弹窗';
            btn.style.cssText = `
                writing-mode: vertical-rl;
                text-orientation: mixed;
                padding: 12px 8px;
                background: #1976d2;
                color: white;
                border: none;
                border-radius: 4px;
                font-weight: bold;
                cursor: pointer;
                box-shadow: 0 2px 6px rgba(0,0,0,0.2);
                transition: background 0.2s;
                font-size: 14px;
            `;

            // 添加事件监听器
            btn.addEventListener('mouseover', () => {
                btn.style.background = '#1565c0';
            });

            btn.addEventListener('mouseout', () => {
                btn.style.background = '#1976d2';
            });

            btn.addEventListener('click', ModalManager.show);

            btnContainer.appendChild(btn);
            document.body.appendChild(btnContainer);

            this.element = btnContainer;

            LogManager.log('🔧 工具按钮已添加', 'info');
        },

        // 移除工具栏按钮
        remove() {
            if (this.element && this.element.parentNode) {
                this.element.parentNode.removeChild(this.element);
                this.element = null;
            }
        }
    };

    // 模态框管理模块
    const ModalManager = {
        overlay: null,

        // 显示模态框
        show() {

            this.overlay = document.createElement('div');
            this.overlay.id = 'custom-modal-overlay';
            this.overlay.style.cssText = `
            position: fixed;
            inset: 0;
            background: rgba(0,0,0,0.5);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 100000;
        `;

            const modal = document.createElement('div');
            modal.style.cssText = `
            background: white;
            padding: 24px;
            border-radius: 8px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.3);
            min-width: 400px;
            max-width: 500px;
            font-family: sans-serif;
            position: relative;
        `;

            modal.innerHTML = `
            <h3 style="margin: 0 0 16px 0; color: #000;">🔧 视频解析工具</h3>
            <p style="margin: 0 0 20px 0; color: #666; line-height: 1.5;">
                请输入需要解析的视频地址,然后选择一个解析接口
            </p>
            <button id="close-modal-btn" style="color: #000;
                background: #f0f0f0;
                border: 1px solid #ccc;
                padding: 8px 16px;
                border-radius: 4px;
                cursor: pointer;
                margin-top: 15px;
            ">关闭</button>
        `;

            // 创建并添加视频解析区域
            const parserSection = VideoParser.createSection();
            modal.insertBefore(parserSection, modal.querySelector('#close-modal-btn'));

            this.overlay.appendChild(modal);
            document.body.appendChild(this.overlay);

            // 关闭按钮事件 - 使用箭头函数确保this指向正确
            const closeModalBtn = modal.querySelector('#close-modal-btn');
            if (closeModalBtn) {
                closeModalBtn.addEventListener('click', (e) => {
                    ModalManager.hide();
                    LogManager.log('🔧 关闭按钮触发关闭', 'info');
                }); // 添加once选项防止多次触发
            }

            // 点击背景关闭
            this.overlay.addEventListener('click', (e) => {
                if (e.target === this.overlay) {
                    ModalManager.hide();
                    LogManager.log('🔧 背景点击触发关闭', 'info');
                }
            }); // 添加once选项

            LogManager.log('🔧 视频解析工具已打开', 'info');
        },

        // 隐藏模态框
        hide() {
            const existingVideoContainer = document.getElementById('custom-modal-overlay');
            if (existingVideoContainer) {
                if (existingVideoContainer.parentNode) {
                    existingVideoContainer.parentNode.removeChild(existingVideoContainer);
                } else {
                    existingVideoContainer.remove();
                }
            }
        }
    };


    // 视频解析模块
    const VideoParser = {
        // 创建视频解析区域
        createSection() {
            const parserContainer = document.createElement('div');
            parserContainer.style.cssText = `
                margin-top: 20px;
                padding-top: 20px;
                border-top: 1px solid #eee;
            `;

            // 标题和输入框
            parserContainer.innerHTML = `
                <h4 style="margin: 0 0 12px 0; color: #333;">视频解析</h4>
                <p style="margin: 0 0 10px 0; font-size: 14px; color: #666;">
                    输入视频URL并选择解析接口
                </p>
                <div style="margin-bottom: 15px;">
                    <input type="text" id="video-url-input" placeholder="请输入视频地址"
                        style="color: #000;width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;" />
                </div>
                <div id="parser-buttons" style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px;">
                    <!-- 按钮会通过JS动态生成 -->
                </div>
            `;

            // 获取按钮容器
            const buttonsContainer = parserContainer.querySelector('#parser-buttons');

            // 动态生成解析按钮
            videoParsers.forEach(parser => {
                const button = this.createButton(parser);
                buttonsContainer.appendChild(button);
            });

            return parserContainer;
        },

        // 创建解析按钮
        createButton(parser) {
            const button = document.createElement('button');
            button.id = parser.id;
            button.textContent = parser.name;
            button.style.cssText = `
                padding: 8px 12px;
                background: #1976d2;
                color: white;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                transition: background 0.2s;
                text-align: center;
            `;

            // 添加事件监听器
            button.addEventListener('mouseover', () => {
                button.style.background = '#1565c0';
            });

            button.addEventListener('mouseout', () => {
                button.style.background = '#1976d2';
            });

            button.addEventListener('click', () => this.parseVideo(parser));

            return button;
        },

        // 解析视频
        parseVideo(parser) {
            // 获取视频URL(优先使用输入框内容,否则使用当前页面URL)
            const videoInput = document.getElementById('video-url-input');
            const currentUrl = window.location.href;
            const videoUrl = videoInput ? videoInput.value.trim() : '';

            // 如果输入框为空,则使用当前页面URL
            const finalUrl = videoUrl || currentUrl;

            if (!finalUrl) {
                alert('请输入视频地址');
                return;
            }

            // 1. 关闭弹窗
            ModalManager.hide();

            // 2. 清除已有的视频容器(避免重复)
            this.removeExistingPlayer();

            // 3. 构建完整的解析URL
            const fullUrl = `${parser.url}${encodeURIComponent(finalUrl)}`;

            // 4. 创建新的视频容器
            const videoContainer = this.createPlayerContainer(fullUrl);

            // 5. 添加到页面容器
            const container = document.querySelector('.container-main__wrapper');
            const containerleft = document.querySelector('.container-main__left');

            if (containerleft) {
                containerleft.style.cssText = `visibility: hidden;`;
            }

            // 暂停页面上的视频
            this.pausePageVideos();

            if (container) {
                container.appendChild(videoContainer);
                LogManager.log(`使用${parser.name}解析视频: ${finalUrl}`, 'info');
            } else {
                console.error('未找到.container-main容器');
                LogManager.log('未找到视频容器,无法播放视频', 'error');
            }
        },

        // 移除已存在的播放器
        removeExistingPlayer() {
            const existingVideoContainer = document.getElementById('video-player-container');
            if (existingVideoContainer) {
                if (existingVideoContainer.parentNode) {
                    existingVideoContainer.parentNode.removeChild(existingVideoContainer);
                } else {
                    existingVideoContainer.remove();
                }
            }
        },

        // 创建播放器容器
        createPlayerContainer(url) {
            const videoContainer = document.createElement('div');
            videoContainer.id = 'video-player-container';
            videoContainer.style.cssText = `
                position: absolute;
                top: 0;
                width: 100%;
                padding-top: 56.25%; /* 16:9比例 */
                margin-top: 20px;
            `;

            // 添加iframe视频播放器
            videoContainer.innerHTML = `
                <iframe src="${url}"
                    allowfullscreen
                    frameborder="0"
                    style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: #000;"></iframe>
            `;

            return videoContainer;
        },

        // 暂停页面上的视频
        pausePageVideos() {
            const videos = document.querySelectorAll('video[playsinline="isiPhoneShowPlaysinline"]');
            videos.forEach(video => {
                try {
                    video.pause();
                } catch (error) {
                    console.warn('Failed to pause video:', error);
                }
            });
        }
    };

    // 播放列表管理模块
    const PlaylistManager = {
        // 初始化播放列表事件监听
        init() {
            const playlistContainer = document.querySelector('.playlist-rect');
            if (!playlistContainer) return;

            playlistContainer.addEventListener('click', (event) => {
                // 通过 closest() 方法检测点击目标是否符合条件
                const targetCol = event.target.closest('.playlist-rect__col');

                if (targetCol) {
                    this.handlePlaylistClick();
                }
            });
        },

        // 处理播放列表点击事件
        handlePlaylistClick() {
            const videoContainer = document.getElementById('video-player-container');
            if (videoContainer) {
                // 添加过渡动画效果
                videoContainer.style.transition = 'opacity 0.3s';
                videoContainer.style.opacity = '0';

                // 动画结束后移除元素
                setTimeout(() => {
                    try {
                        if (videoContainer.parentNode) {
                            videoContainer.parentNode.removeChild(videoContainer);
                        } else {
                            videoContainer.remove();
                        }
                        console.log('视频容器已成功移除');
                    } catch (error) {
                        console.error('元素移除失败:', error);
                    }
                }, 300);
            }

            const containerleft = document.querySelector('.container-main__left');
            if (containerleft) {
                containerleft.style.cssText = `visibility: visible;`;
            }
        }
    };

    // 主初始化模块
    const App = {
        initialized: false,

        // 初始化应用
        init() {
            // 防止重复初始化
            if (this.initialized) return;

            // 先确保日志面板已设置好
            const logElement = LogManager.init();
            if (logElement) {
                LogManager.log('🚀 脚本启动初始化...', 'info');
                ToolbarButton.init();
                PlaylistManager.init();
                LogManager.log('✅ 脚本初始化完成', 'info');
                this.initialized = true;
            } else {
                console.error('日志面板初始化失败');
            }
        },

        // 清理应用资源
        cleanup() {
            ModalManager.hide();
            ToolbarButton.remove();
            LogManager.hide();
            this.initialized = false;
        }
    };

    // 页面加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => App.init());
    } else {
        App.init();
    }

    // 页面卸载时清理资源
    window.addEventListener('beforeunload', () => {
        App.cleanup();
    });
})();