百度网盘视频笔记控制增强

ALT+1视频截图,ALT+2后退3秒,ALT+3快进3秒,自动调整布局宽度(全局生效)

// ==UserScript==
// @name         百度网盘视频笔记控制增强
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  ALT+1视频截图,ALT+2后退3秒,ALT+3快进3秒,自动调整布局宽度(全局生效)
// @author       微信公众号:阿虚同学
// @match        *://pan.baidu.com/fcb/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // ==================== 布局调整功能 ====================

    function adjustLayout() {
        const videoElement = document.querySelector('.wp-edit-content__video');
        const docElement = document.querySelector('.wp-edit-content__doc');
        const editorElement = document.querySelector('.wp-edit-content__editor');

        let adjusted = false;

        if (videoElement) {
            videoElement.style.width = '60%';
            adjusted = true;
        }

        if (docElement) {
            docElement.style.width = '40%';
            adjusted = true;
        }

        if (editorElement) {
            editorElement.style.width = '100%';
            adjusted = true;
        }

        return adjusted;
    }

    // 监听DOM变化,自动应用布局调整
    function observeLayoutChanges() {
        const observer = new MutationObserver(() => {
            adjustLayout();
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    // ==================== 截图功能相关 ====================

    // 控制栏的选择器
    const CONTROL_BAR_SELECTOR = 'section.wp-video__control-bar.vjs-user-active';

    // 备用选择器(如果上面的找不到)
    const CONTROL_BAR_FALLBACK_SELECTORS = [
        '.wp-video__control-bar.vjs-user-active',
        '.wp-video__control-bar',
        'section.wp-video__control-bar'
    ];

    // 视频截图按钮的文本和类名
    const SCREENSHOT_BUTTON_TEXT = '视频截图';
    const SCREENSHOT_BUTTON_CLASS = 'wp-ai-note-aside-item__title';

    // 添加防重复执行的标志
    let isExecutingScreenshot = false;

    function findControlBar() {
        // 首先尝试主要选择器
        let controlBar = document.querySelector(CONTROL_BAR_SELECTOR);

        if (controlBar) {
            console.log('找到主要控制栏:', controlBar);
            return controlBar;
        }

        // 尝试备用选择器
        for (const selector of CONTROL_BAR_FALLBACK_SELECTORS) {
            controlBar = document.querySelector(selector);
            if (controlBar) {
                console.log(`通过备用选择器找到控制栏 (${selector}):`, controlBar);
                return controlBar;
            }
        }

        console.warn('未找到任何控制栏元素');
        return null;
    }

    function simulateClick(element) {
        // 创建多种点击事件确保触发
        const events = [
            'mousedown',
            'mouseup',
            'click'
        ];

        console.log('开始模拟点击控制栏:', element);

        events.forEach(eventType => {
            const event = new MouseEvent(eventType, {
                bubbles: true,
                cancelable: true,
                view: window,
                button: 0, // 左键
                buttons: 1,
                clientX: element.offsetLeft + element.offsetWidth / 2,
                clientY: element.offsetTop + element.offsetHeight / 2
            });

            console.log(`触发 ${eventType} 事件在控制栏`);
            element.dispatchEvent(event);
        });

        // 也尝试在父元素上触发点击(如果需要)
        const videoContainer = element.closest('.video-img-container');
        if (videoContainer) {
            console.log('在父容器 video-img-container 上也触发点击事件');
            const clickEvent = new MouseEvent('click', {
                bubbles: true,
                cancelable: true,
                view: window
            });
            videoContainer.dispatchEvent(clickEvent);
        }

        // 尝试触发focus事件(可能有助于显示控制栏)
        if (element.focus) {
            element.focus();
            console.log('已对控制栏执行 focus()');
        }
    }

    function findScreenshotButton() {
        // 首先尝试精确匹配
        const buttons = document.querySelectorAll(`span.${SCREENSHOT_BUTTON_CLASS}`);
        for (const btn of buttons) {
            if (btn.textContent && btn.textContent.trim() === SCREENSHOT_BUTTON_TEXT) {
                console.log('通过类名找到截图按钮:', btn);
                return btn;
            }
        }

        // 备用方法:查找所有包含"视频截图"文本的span元素
        const allSpans = document.querySelectorAll('span');
        for (const span of allSpans) {
            if (span.textContent && span.textContent.trim() === SCREENSHOT_BUTTON_TEXT) {
                console.log('通过文本内容找到截图按钮:', span);
                return span;
            }
        }

        // 更广泛的搜索:查找任何包含"截图"文本的可点击元素
        const clickableElements = document.querySelectorAll('button, span, div, a, [role="button"]');
        for (const element of clickableElements) {
            if (element.textContent && element.textContent.includes('截图')) {
                console.log('找到包含"截图"的元素:', element);
                return element;
            }
        }

        // 尝试查找可能的截图相关按钮(通过属性)
        const screenshotSelectors = [
            '[title*="截图"]',
            '[aria-label*="截图"]',
            '[data-title*="截图"]'
        ];

        for (const selector of screenshotSelectors) {
            const element = document.querySelector(selector);
            if (element) {
                console.log(`通过属性选择器找到截图按钮 (${selector}):`, element);
                return element;
            }
        }

        return null;
    }

    function clickScreenshotButton(button) {
        console.log('准备点击截图按钮:', button);

        try {
            // 方式1: 直接点击
            button.click();
            console.log('✅ 已通过 click() 方法点击截图按钮');
            return true;
        } catch (e) {
            console.log('直接点击失败,尝试事件方式:', e);

            try {
                // 方式2: 通过事件触发
                const clickEvent = new MouseEvent('click', {
                    bubbles: true,
                    cancelable: true,
                    view: window,
                    button: 0,
                    buttons: 1
                });
                button.dispatchEvent(clickEvent);
                console.log('✅ 已通过事件方式点击截图按钮');
                return true;
            } catch (e2) {
                console.error('事件方式点击也失败:', e2);
                return false;
            }
        }
    }

    function executeScreenshot() {
        // 防止重复执行
        if (isExecutingScreenshot) {
            console.log('⚠️ 截图功能正在执行中,跳过重复调用');
            return;
        }

        isExecutingScreenshot = true;
        console.log('🎬 ALT+1 按下,开始执行截图操作...');

        const controlBar = findControlBar();

        if (controlBar) {
            console.log('✅ 控制栏已找到,开始模拟点击...');

            // 模拟点击控制栏
            simulateClick(controlBar);

            // 延时500ms后查找并点击截图按钮
            setTimeout(() => {
                console.log('⏰ 延时结束,开始查找截图按钮...');

                const screenshotButton = findScreenshotButton();

                if (screenshotButton) {
                    console.log('✅ 截图按钮已找到');

                    const success = clickScreenshotButton(screenshotButton);

                    if (success) {
                        showTips('📸 视频截图成功');
                    } else {
                        showTips('❌ 截图按钮点击失败');
                    }
                } else {
                    console.warn('❌ 未能找到截图按钮');
                    showTips('❌ 未找到截图按钮');
                }

                // 重置执行标志
                setTimeout(() => {
                    isExecutingScreenshot = false;
                }, 1000);

            }, 500);

        } else {
            console.log('❌ 未找到控制栏');
            showTips('❌ 未找到控制栏');

            // 重置执行标志
            setTimeout(() => {
                isExecutingScreenshot = false;
            }, 1000);
        }
    }

    // ==================== 视频控制功能相关 ====================

    // 创建提示元素的样式
    const style = document.createElement('style');
    style.textContent = `
        .video-custom-tips {
            position: fixed;
            background: rgba(0, 0, 0, 0.75);
            color: white;
            padding: 8px 12px;
            border-radius: 5px;
            z-index: 2147483647;
            font-size: 14px;
            pointer-events: none;
            opacity: 1;
            transition: opacity 0.5s ease-out;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
        }
    `;
    document.head.appendChild(style);

    // 显示提示的函数
    function showTips(message, videoElement, duration = 1000) {
        // 移除已存在的提示
        const oldTip = document.querySelector('.video-custom-tips');
        if (oldTip) {
            oldTip.remove();
        }
        // 创建新的提示元素
        const tip = document.createElement('div');
        tip.className = 'video-custom-tips';
        tip.textContent = message;
        // 如果指定了视频元素,则定位到视频左上角
        if (videoElement) {
            const rect = videoElement.getBoundingClientRect();
            tip.style.left = `${rect.left + window.scrollX + 10}px`;
            tip.style.top = `${rect.top + window.scrollY + 10}px`;
        } else {
            // 默认居中显示
            tip.style.left = '50%';
            tip.style.top = '50%';
            tip.style.transform = 'translate(-50%, -50%)';
        }
        document.body.appendChild(tip);
        // 设置延时自动移除
        setTimeout(() => {
            tip.style.opacity = '0';
            setTimeout(() => tip.remove(), 300);
        }, duration);
    }

    // 通用视频跳转函数
    function handleVideoSeek(seconds, message) {
        const videos = document.querySelectorAll('video, .vjs-tech, [data-vjs-player]');
        let found = false;
        let firstVideo = null;
        videos.forEach(video => {
            // 跳过不可操作的视频
            if (isNaN(video.duration)) return;
            const oldTime = video.currentTime;
            let newTime = oldTime + seconds;
            // 限制时间范围
            newTime = Math.max(0, newTime);
            newTime = Math.min(video.duration, newTime);
            // 执行跳转
            if (Math.abs(newTime - oldTime) > 0.1) { // 防止微小误差触发
                video.currentTime = newTime;
                if (!firstVideo) firstVideo = video;
                found = true;
            }
        });
        if (found) {
            showTips(message, firstVideo);
        } else {
            showTips('没有找到可操作的视频');
        }
    }

    // ==================== 统一的键盘事件处理 ====================

    function handleKeyDown(event) {
        // 日志记录事件状态
        console.log(`按下了: ${event.key} (altKey=${event.altKey}, ctrlKey=${event.ctrlKey}, shiftKey=${event.shiftKey}, target=${event.target.tagName})`);

        // 检查是否在内容可编辑区域(如笔记输入框)
        if ((event.target.isContentEditable ||
             event.target.tagName === 'INPUT' ||
             event.target.tagName === 'TEXTAREA') &&
            (event.altKey && (event.key === '2' || event.key === '3'))) {
            event.preventDefault(); // 防止默认行为
        }

        // ALT+1 触发截图功能
        if (event.altKey && event.key === '1') {
            event.preventDefault(); // 阻止可能的浏览器默认行为
            executeScreenshot();
            return false;
        }

        // 检查是否按下 ALT+2(后退3秒)
        if (event.altKey && event.key === '2') {
            handleVideoSeek(-3, '⏪ 后退3秒');
        }

        // 检查是否按下 ALT+3(快进3秒)
        if (event.altKey && event.key === '3') {
            handleVideoSeek(3, '⏩ 快进3秒');
        }
    }

    // ==================== 初始化和监听 ====================

    // 页面加载完成后的初始化
    function initialize() {
        // 截图功能初始化检查
        const controlBar = findControlBar();
        if (controlBar) {
            console.log('✅ 控制栏元素已找到,截图功能准备就绪');
        } else {
            console.log('⚠️ 未找到控制栏元素');
        }

        // 自动调整布局
        setTimeout(() => {
            adjustLayout();
        }, 1000);

        // 启动DOM变化监听
        setTimeout(() => {
            observeLayoutChanges();
        }, 2000);
    }

    // 使用事件捕获阶段监听事件
    document.addEventListener('keydown', handleKeyDown, true);

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

    // 页面完全加载后再次初始化
    window.addEventListener('load', () => {
        setTimeout(initialize, 1000);
    });

    console.log('🚀 百度网盘视频增强工具已加载');
    console.log('📸 ALT+1: 视频截图');
    console.log('⏪ ALT+2: 后退3秒');
    console.log('⏩ ALT+3: 快进3秒');
    console.log('📐 自动调整布局: 视频60% | 文档40% | 编辑器100%');

})();