VideoHelper

看片小助肘 - 支持片头跳过设置,倍速播放记忆,自动全屏设置,音量记忆、截屏功能和自动播放功能

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         VideoHelper
// @namespace    https://github.com/Cocowwy/Tampermonkey-Tools
// @version      1.2
// @description  看片小助肘 - 支持片头跳过设置,倍速播放记忆,自动全屏设置,音量记忆、截屏功能和自动播放功能
// @author       Cocowwy
// @match        *://*/*
// @updateUrl    https://github.com/Cocowwy/Tampermonkey-Tools/blob/master/VideoHelper.js
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const STORAGE_KEY = 'video_auto_jump_time';
    const SPEED_STORAGE_KEY = 'video_playback_speed';
    const AUTO_FULLSCREEN_KEY = 'video_auto_fullscreen';
    const VOLUME_STORAGE_KEY = 'video_volume';
    const AUTO_PLAY_KEY = 'video_auto_play';
    let isPanelVisible = false;
    let isDragging = false;
    let startX, startY, initialX, initialY;

    // 创建折叠按钮
    const toggleBtn = document.createElement('div');
    toggleBtn.innerHTML = '📽️';
    toggleBtn.style.cssText = `
        position: fixed;
        left: 10px;
        top: 50%;
        transform: translateY(-50%);
        cursor: pointer;
        z-index: 9999;
        opacity: 0.7;
        transition: opacity 0.3s;
        font-size: 20px;
        border-radius: 50%;
        width: 40px;
        height: 40px;
        display: flex;
        align-items: center;
        justify-content: center;
        color: white;
        background: rgba(0, 0, 0, 0.85);
    `;
    toggleBtn.addEventListener('mouseenter', () => toggleBtn.style.opacity = '1');
    toggleBtn.addEventListener('mouseleave', () => toggleBtn.style.opacity = '0.7');
    document.body.appendChild(toggleBtn);

    // 创建配置面板
    const panel = document.createElement('div');
    panel.style.cssText = `
        position: fixed;
        left: -300px; /* 初始隐藏位置 */
        top: 50%;
        transform: translateY(-50%);
        background: rgba(0, 0, 0, 0.85);
        padding: 20px;
        border-radius: 8px;
        box-shadow: 0 0 15px rgba(0,0,0,0.3);
        transition: all 0.3s ease;
        color: white;
        width: 260px;
        z-index: 9998;
        backdrop-filter: blur(5px);
    `;

    // 拖动处理函数
    const handleMouseDown = (e) => {
        isDragging = true;
        startX = e.clientX;
        startY = e.clientY;
        initialX = panel.offsetLeft;
        initialY = panel.offsetTop;
        panel.style.transition = 'none';
    };

    const handleMouseMove = (e) => {
        if (!isDragging) return;
        const dx = e.clientX - startX;
        const dy = e.clientY - startY;
        panel.style.left = `${initialX + dx}px`;
        panel.style.top = `${initialY + dy}px`;
    };

    const handleMouseUp = () => {
        isDragging = false;
        panel.style.transition = 'all 0.3s ease';
    };

    // 面板内容
    panel.innerHTML = `
        <div style="margin-bottom: 15px; font-weight: bold; font-size: 16px;">
            🎬 视频小助肘
            <div style="float: right; cursor: pointer; opacity: 0.7;" id="closeBtn">×</div>
        </div>
        <div style="margin-bottom: 15px;">
            <label style="display: block; margin-bottom: 8px; font-size: 14px;">
                跳过片头时间(秒):
            </label>
            <input type="number"
                   id="timeInput"
                   style="width: 95%;
                          padding: 8px;
                          border: 1px solid rgba(255,255,255,0.2);
                          border-radius: 4px;
                          background: rgba(255,255,255,0.1);
                          color: white;
                          margin-bottom: 15px;">
            </input>
            <label style="display: block; margin-bottom: 8px; font-size: 14px;">
                播放倍速:
            </label>
            <input type="number"
                   id="speedInput"
                   style="width: 95%;
                          padding: 8px;
                          border: 1px solid rgba(255,255,255,0.2);
                          border-radius: 4px;
                          background: rgba(255,255,255,0.1);
                          color: white;
                          margin-bottom: 15px;">
            </input>
            <label style="display: block; margin-bottom: 8px; font-size: 14px;">
                音量 (0 - 100):
            </label>
            <input type="number"
                   id="volumeInput"
                   min="0"
                   max="100"
                   style="width: 95%;
                          padding: 8px;
                          border: 1px solid rgba(255,255,255,0.2);
                          border-radius: 4px;
                          background: rgba(255,255,255,0.1);
                          color: white;
                          margin-bottom: 15px;">
            </input>
            <label style="display: block; margin-bottom: 8px; font-size: 14px;">
                自动全屏:
            </label>
            <input type="checkbox" id="autoFullscreenCheckbox">
            <label style="display: block; margin-bottom: 8px; font-size: 14px;">
                自动播放:
            </label>
            <input type="checkbox" id="autoPlayCheckbox">
            <button id="saveBtn"
                    style="width: 100%;
                           padding: 8px;
                           background: #2196F3;
                           border: none;
                           border-radius: 4px;
                           color: white;
                           cursor: pointer;
                           transition: background 0.3s;">
                保存
            </button>
            <button id="screenshotBtn"
                    style="width: 100%;
                           padding: 8px;
                           background: #4CAF50;
                           border: none;
                           border-radius: 4px;
                           color: white;
                           cursor: pointer;
                           transition: background 0.3s;
                           margin-top: 10px;">
                视频截屏
            </button>
        </div>
    `;

    // 元素引用
    const timeInput = panel.querySelector('#timeInput');
    const speedInput = panel.querySelector('#speedInput');
    const volumeInput = panel.querySelector('#volumeInput');
    const autoFullscreenCheckbox = panel.querySelector('#autoFullscreenCheckbox');
    const autoPlayCheckbox = panel.querySelector('#autoPlayCheckbox');
    const saveBtn = panel.querySelector('#saveBtn');
    const closeBtn = panel.querySelector('#closeBtn');
    const screenshotBtn = panel.querySelector('#screenshotBtn');

    // 事件监听
    saveBtn.addEventListener('mouseenter', () => saveBtn.style.background = '#1976D2');
    saveBtn.addEventListener('mouseleave', () => saveBtn.style.background = '#2196F3');
    closeBtn.addEventListener('click', () => togglePanel(false));
    panel.addEventListener('mousedown', handleMouseDown);
    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);

    // 功能函数
    function togglePanel(show) {
        isPanelVisible = show;
        panel.style.left = show ? '60px' : '-300px'; // 展开时距离左侧60px
        toggleBtn.innerHTML = show ? 'X' : '📽️';
    }

    toggleBtn.addEventListener('click', () => togglePanel(!isPanelVisible));

    // 初始化存储值
    timeInput.value = localStorage.getItem(STORAGE_KEY) || 0;
    speedInput.value = localStorage.getItem(SPEED_STORAGE_KEY) || 1;
    volumeInput.value = localStorage.getItem(VOLUME_STORAGE_KEY) || 100;
    autoFullscreenCheckbox.checked = localStorage.getItem(AUTO_FULLSCREEN_KEY) === 'true';
    autoPlayCheckbox.checked = localStorage.getItem(AUTO_PLAY_KEY) === 'true';

    saveBtn.addEventListener('click', () => {
        const jumpTime = parseInt(timeInput.value, 10);
        const playbackSpeed = parseFloat(speedInput.value);
        const volume = parseInt(volumeInput.value, 10);
        const autoFullscreen = autoFullscreenCheckbox.checked;
        const autoPlay = autoPlayCheckbox.checked;

        if (!isNaN(jumpTime) && !isNaN(playbackSpeed) && !isNaN(volume) && volume >= 0 && volume <= 100) {
            localStorage.setItem(STORAGE_KEY, jumpTime);
            localStorage.setItem(SPEED_STORAGE_KEY, playbackSpeed);
            localStorage.setItem(VOLUME_STORAGE_KEY, volume);
            localStorage.setItem(AUTO_FULLSCREEN_KEY, autoFullscreen);
            localStorage.setItem(AUTO_PLAY_KEY, autoPlay);

            const video = document.querySelector('video');
            if (video) {
                video.currentTime = jumpTime;
                video.playbackRate = playbackSpeed;
                video.volume = volume / 100;
                
                if (autoPlay) {
                    video.play().catch(() => {
                        showToast('⚠️ 自动播放被浏览器阻止,请手动播放');
                    });
                }
            }

            showToast('✅ 设置已保存');
        } else {
            showToast('⚠️ 请输入有效数字,音量范围为 0 - 100');
        }
    });

    // 视频处理
    const video = document.querySelector('video');
    if (video) {
        video.addEventListener('loadedmetadata', () => {
            const jumpTime = parseInt(localStorage.getItem(STORAGE_KEY), 10);
            const playbackSpeed = parseFloat(localStorage.getItem(SPEED_STORAGE_KEY));
            const volume = parseFloat(localStorage.getItem(VOLUME_STORAGE_KEY));
            const autoFullscreen = localStorage.getItem(AUTO_FULLSCREEN_KEY) === 'true';

            if (!isNaN(jumpTime) && jumpTime <= video.duration) {
                video.currentTime = jumpTime;
            }
            if (!isNaN(playbackSpeed)) {
                video.playbackRate = playbackSpeed;
            }
            if (!isNaN(volume) && volume >= 0 && volume <= 100) {
                video.volume = volume / 100;
            }
        });

        video.addEventListener('play', () => {
            const autoFullscreen = localStorage.getItem(AUTO_FULLSCREEN_KEY) === 'true';
            if (autoFullscreen) {
                if (video.requestFullscreen) {
                    video.requestFullscreen();
                } else if (video.webkitRequestFullscreen) {
                    video.webkitRequestFullscreen();
                } else if (video.msRequestFullscreen) {
                    video.msRequestFullscreen();
                } else if (video.mozRequestFullscreen) {
                    video.mozRequestFullscreen();
                } else {
                    showToast('⚠️ 当前浏览器不支持全屏功能');
                }
            }
        });
    }

    // 截屏功能
    screenshotBtn.addEventListener('click', () => {
        const video = document.querySelector('video');
        if (video) {
            const canvas = document.createElement('canvas');
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
            const ctx = canvas.getContext('2d');
            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

            const link = document.createElement('a');
            link.href = canvas.toDataURL('image/png');
            link.download = 'video_screenshot.png';
            link.click();

            showToast('📸 截屏已保存');
        } else {
            showToast('⚠️ 未找到视频元素');
        }
    });

    // 提示信息函数
    function showToast(message) {
        const toast = document.createElement('div');
        toast.textContent = message;
        toast.style.cssText = `
            position: fixed;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            background: rgba(0,0,0,0.8);
            color: white;
            padding: 12px 24px;
            border-radius: 4px;
            font-size: 14px;
            z-index: 10000;
            animation: fadeInOut 2.5s;
        `;
        document.body.appendChild(toast);
        setTimeout(() => toast.remove(), 2500);
    }

    // 注入CSS动画
    const style = document.createElement('style');
    style.textContent = `
        @keyframes fadeInOut {
            0% { opacity: 0; transform: translate(-50%, 10px); }
            15% { opacity: 1; transform: translate(-50%, 0); }
            85% { opacity: 1; transform: translate(-50%, 0); }
            100% { opacity: 0; transform: translate(-50%, -10px); }
        }
    `;
    document.head.appendChild(style);

    document.body.appendChild(panel);
})();