动画疯弹幕播放器

为动画疯添加自定义视频播放器,支持弹幕显示和时间微调

当前为 2025-07-11 提交的版本,查看 最新版本

// ==UserScript==
// @name         动画疯弹幕播放器
// @namespace    http://tampermonkey.net/
// @version      2025-07-11
// @description  为动画疯添加自定义视频播放器,支持弹幕显示和时间微调
// @author       You
// @match        https://ani.gamer.com.tw/animeVideo.php*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=ani.gamer.com.tw
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    let danmuData = [];
    let timeOffset = 0; // 时间偏移量(秒)
    let customPlayer = null;
    let danmuContainer = null;
    let isPlaying = false; // 视频播放状态
    let activeDanmuElements = new Set(); // 活跃的弹幕元素集合
    let isCustomFullscreen = false; // 自定义全屏状态

    // 弹幕设置
    let danmuSettings = {
        displayArea: 'full', // 'full' | 'half' | 'quarter'
        opacity: 0.9,
        fontSize: 1.0,
        speed: 1.0,
        density: 1.0,
        showScroll: true,
        showTop: true,
        showBottom: true
    };

    // 从URL中提取视频sn
    function getVideoSn() {
        const urlParams = new URLSearchParams(window.location.search);
        return urlParams.get('sn');
    }

    // 获取弹幕数据
    async function fetchDanmu(sn) {
        try {
            const response = await fetch(`https://api.gamer.com.tw/anime/v1/danmu.php?videoSn=${sn}&geo=TW%2CHK`);
            const data = await response.json();
            if (data.data && data.data.danmu) {
                danmuData = data.data.danmu;
                console.log(`获取到 ${danmuData.length} 条弹幕`);
                return true;
            }
            return false;
        } catch (error) {
            console.error('获取弹幕失败:', error);
            return false;
        }
    }

    // 创建自定义播放器
    function createCustomPlayer() {
        const playerContainer = document.createElement('div');
        playerContainer.id = 'custom-player-container';
        playerContainer.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 80vw;
            max-width: 1200px;
            height: 70vh;
            background: #000;
            border-radius: 8px;
            box-shadow: 0 8px 32px rgba(0,0,0,0.8);
            z-index: 10000;
            display: none;
            flex-direction: column;
        `;

        // 播放器头部控制栏
        const playerHeader = document.createElement('div');
        playerHeader.id = 'player-header';
        playerHeader.style.cssText = `
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 10px 15px;
            background: rgba(0,0,0,0.8);
            color: white;
            border-radius: 8px 8px 0 0;
            transition: opacity 0.3s ease, transform 0.3s ease;
            position: relative;
            z-index: 1000;
        `;

        const playerTitle = document.createElement('div');
        playerTitle.textContent = '自定义弹幕播放器';
        playerTitle.style.fontSize = '16px';

        const controlButtons = document.createElement('div');
        controlButtons.style.display = 'flex';
        controlButtons.style.gap = '10px';

        // 时间微调控件
        const timeAdjustContainer = document.createElement('div');
        timeAdjustContainer.style.cssText = `
            display: flex;
            align-items: center;
            gap: 3px;
            font-size: 12px;
        `;

        const timeAdjustLabel = document.createElement('span');
        timeAdjustLabel.textContent = '时间微调:';

        // 减少按钮组
        const minusButtonsContainer = document.createElement('div');
        minusButtonsContainer.style.cssText = `
            display: flex;
            gap: 2px;
        `;

        // 创建减少按钮
        const adjustValues = [0.1, 0.5, 1, 5];
        const minusButtons = [];
        const plusButtons = [];

        adjustValues.forEach(value => {
            const minusBtn = document.createElement('button');
            minusBtn.textContent = `-${value}s`;
            minusBtn.style.cssText = `
                padding: 2px 4px;
                background: #dc3545;
                color: white;
                border: none;
                border-radius: 3px;
                cursor: pointer;
                font-size: 10px;
                min-width: 35px;
            `;
            minusButtons.push({ button: minusBtn, value: value });
            minusButtonsContainer.appendChild(minusBtn);
        });

        // 时间显示
        const timeAdjustDisplay = document.createElement('span');
        timeAdjustDisplay.textContent = '0.0s';
        timeAdjustDisplay.style.cssText = `
            min-width: 50px;
            text-align: center;
            background: rgba(255,255,255,0.1);
            padding: 4px 8px;
            border-radius: 3px;
            margin: 0 3px;
        `;

        // 增加按钮组
        const plusButtonsContainer = document.createElement('div');
        plusButtonsContainer.style.cssText = `
            display: flex;
            gap: 2px;
        `;

        adjustValues.forEach(value => {
            const plusBtn = document.createElement('button');
            plusBtn.textContent = `+${value}s`;
            plusBtn.style.cssText = `
                padding: 2px 4px;
                background: #28a745;
                color: white;
                border: none;
                border-radius: 3px;
                cursor: pointer;
                font-size: 10px;
                min-width: 35px;
            `;
            plusButtons.push({ button: plusBtn, value: value });
            plusButtonsContainer.appendChild(plusBtn);
        });

        // 重置按钮
        const resetButton = document.createElement('button');
        resetButton.textContent = '重置';
        resetButton.style.cssText = `
            padding: 2px 6px;
            background: #6c757d;
            color: white;
            border: none;
            border-radius: 3px;
            cursor: pointer;
            font-size: 10px;
            margin-left: 5px;
        `;

        timeAdjustContainer.appendChild(timeAdjustLabel);
        timeAdjustContainer.appendChild(minusButtonsContainer);
        timeAdjustContainer.appendChild(timeAdjustDisplay);
        timeAdjustContainer.appendChild(plusButtonsContainer);
        timeAdjustContainer.appendChild(resetButton);

        // 弹幕设置按钮
        const danmuSettingsButton = document.createElement('button');
        danmuSettingsButton.textContent = '⚙️';
        danmuSettingsButton.title = '弹幕设置';
        danmuSettingsButton.style.cssText = `
            background: #6c757d;
            color: white;
            border: none;
            border-radius: 4px;
            padding: 5px 10px;
            cursor: pointer;
            font-size: 14px;
            margin-right: 5px;
        `;

        // 自定义全屏按钮
        const fullscreenButton = document.createElement('button');
        fullscreenButton.textContent = '⛶';
        fullscreenButton.title = '全屏播放';
        fullscreenButton.style.cssText = `
            background: #007bff;
            color: white;
            border: none;
            border-radius: 4px;
            padding: 5px 10px;
            cursor: pointer;
            font-size: 16px;
            margin-right: 5px;
        `;

        // 关闭按钮
        const closeButton = document.createElement('button');
        closeButton.textContent = '✕';
        closeButton.style.cssText = `
            background: #dc3545;
            color: white;
            border: none;
            border-radius: 4px;
            padding: 5px 10px;
            cursor: pointer;
            font-size: 14px;
        `;

        controlButtons.appendChild(timeAdjustContainer);
        controlButtons.appendChild(danmuSettingsButton);
        controlButtons.appendChild(fullscreenButton);
        controlButtons.appendChild(closeButton);

        playerHeader.appendChild(playerTitle);
        playerHeader.appendChild(controlButtons);

        // 视频播放区域
        const videoContainer = document.createElement('div');
        videoContainer.style.cssText = `
            position: relative;
            flex: 1;
            overflow: hidden;
        `;

        const video = document.createElement('video');
        video.id = 'custom-video-player';
        video.controls = true;
        video.style.cssText = `
            width: 100%;
            height: 100%;
            object-fit: contain;
        `;

        // 完全禁用video原生全屏
        video.disablePictureInPicture = true;
        video.controlsList = 'nodownload nofullscreen';

        // 双击视频全屏
        video.addEventListener('dblclick', () => {
            toggleCustomFullscreen();
        });

        // 阻止任何可能的原生全屏
        video.addEventListener('webkitbeginfullscreen', (e) => {
            e.preventDefault();
            e.stopPropagation();
            toggleCustomFullscreen();
        });

        video.addEventListener('webkitendfullscreen', (e) => {
            e.preventDefault();
            e.stopPropagation();
        });

        // 弹幕容器
        danmuContainer = document.createElement('div');
        danmuContainer.id = 'danmu-container';
        danmuContainer.style.cssText = `
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            overflow: hidden;
            z-index: 2147483647;
        `;

        // 初始化弹幕容器显示区域
        updateDanmuContainer();

        videoContainer.appendChild(video);
        videoContainer.appendChild(danmuContainer);

        playerContainer.appendChild(playerHeader);
        playerContainer.appendChild(videoContainer);

        // 事件监听
        // 减少按钮事件
        minusButtons.forEach(({ button, value }) => {
            button.addEventListener('click', () => {
                timeOffset -= value;
                timeAdjustDisplay.textContent = `${timeOffset.toFixed(1)}s`;
            });
        });

        // 增加按钮事件
        plusButtons.forEach(({ button, value }) => {
            button.addEventListener('click', () => {
                timeOffset += value;
                timeAdjustDisplay.textContent = `${timeOffset.toFixed(1)}s`;
            });
        });

        // 重置按钮事件
        resetButton.addEventListener('click', () => {
            timeOffset = 0;
            timeAdjustDisplay.textContent = '0.0s';
        });

        danmuSettingsButton.addEventListener('click', () => {
            toggleDanmuSettings();
        });

        fullscreenButton.addEventListener('click', () => {
            toggleCustomFullscreen();
        });

        closeButton.addEventListener('click', () => {
            playerContainer.style.display = 'none';
        });

        // 视频事件监听
        video.addEventListener('timeupdate', () => {
            if (isPlaying) {
                displayDanmu(video.currentTime);
            }
        });

        video.addEventListener('play', () => {
            isPlaying = true;
            resumeAllDanmu();
        });

        video.addEventListener('pause', () => {
            isPlaying = false;
            pauseAllDanmu();
        });

        video.addEventListener('ended', () => {
            isPlaying = false;
            clearAllDanmu();
        });

        // 监听视频元素的全屏事件
        video.addEventListener('webkitbeginfullscreen', () => {
            console.log('视频开始全屏 (webkit)');
            handleVideoFullscreen(true);
        });

        video.addEventListener('webkitendfullscreen', () => {
            console.log('视频结束全屏 (webkit)');
            handleVideoFullscreen(false);
        });

        video.addEventListener('seeked', () => {
            // 拖拽进度条时清除所有弹幕
            clearAllDanmu();
        });

        // 全屏状态变化监听
        document.addEventListener('fullscreenchange', () => {
            handleFullscreenChange();
        });

        document.addEventListener('webkitfullscreenchange', () => {
            handleFullscreenChange();
        });

        document.addEventListener('mozfullscreenchange', () => {
            handleFullscreenChange();
        });

        document.addEventListener('MSFullscreenChange', () => {
            handleFullscreenChange();
        });

        document.body.appendChild(playerContainer);
        return { container: playerContainer, video: video, fullscreenButton: fullscreenButton, header: playerHeader, danmuSettingsButton: danmuSettingsButton };
    }

    // 创建弹幕设置面板
    function createDanmuSettingsPanel() {
        const panel = document.createElement('div');
        panel.id = 'danmu-settings-panel';
        panel.style.cssText = `
            position: absolute;
            top: 60px;
            right: 10px;
            width: 300px;
            background: rgba(0, 0, 0, 0.9);
            color: white;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.5);
            z-index: 10000;
            display: none;
            font-size: 14px;
        `;

        panel.innerHTML = `
            <h3 style="margin: 0 0 15px 0; font-size: 16px; color: #fff;">弹幕设置</h3>

            <div style="margin-bottom: 15px;">
                <label style="display: block; margin-bottom: 5px;">显示区域:</label>
                <select id="danmu-display-area" style="width: 100%; padding: 5px; border-radius: 4px; border: none; background: #333; color: white;">
                    <option value="full">全屏显示</option>
                    <option value="half">半屏显示</option>
                    <option value="quarter">1/4屏显示</option>
                </select>
            </div>

            <div style="margin-bottom: 15px;">
                <label style="display: block; margin-bottom: 5px;">透明度:<span id="opacity-value">90%</span></label>
                <input type="range" id="danmu-opacity" min="0.1" max="1" step="0.1" value="0.9" style="width: 100%;">
            </div>

            <div style="margin-bottom: 15px;">
                <label style="display: block; margin-bottom: 5px;">字体大小:<span id="fontsize-value">100%</span></label>
                <input type="range" id="danmu-fontsize" min="0.5" max="2" step="0.1" value="1.0" style="width: 100%;">
            </div>

            <div style="margin-bottom: 15px;">
                <label style="display: block; margin-bottom: 5px;">滚动速度:<span id="speed-value">100%</span></label>
                <input type="range" id="danmu-speed" min="0.5" max="2" step="0.1" value="1.0" style="width: 100%;">
            </div>

            <div style="margin-bottom: 15px;">
                <label style="display: block; margin-bottom: 5px;">弹幕密度:<span id="density-value">100%</span></label>
                <input type="range" id="danmu-density" min="0.1" max="2" step="0.1" value="1.0" style="width: 100%;">
            </div>

            <div style="margin-bottom: 15px;">
                <label style="display: block; margin-bottom: 10px;">弹幕类型:</label>
                <div style="display: flex; gap: 10px; flex-wrap: wrap;">
                    <label style="display: flex; align-items: center; cursor: pointer;">
                        <input type="checkbox" id="danmu-scroll" checked style="margin-right: 5px;">
                        滚动弹幕
                    </label>
                    <label style="display: flex; align-items: center; cursor: pointer;">
                        <input type="checkbox" id="danmu-top" checked style="margin-right: 5px;">
                        顶部弹幕
                    </label>
                    <label style="display: flex; align-items: center; cursor: pointer;">
                        <input type="checkbox" id="danmu-bottom" checked style="margin-right: 5px;">
                        底部弹幕
                    </label>
                </div>
            </div>

            <div style="display: flex; gap: 10px; margin-top: 20px;">
                <button id="danmu-settings-reset" style="flex: 1; padding: 8px; background: #6c757d; color: white; border: none; border-radius: 4px; cursor: pointer;">
                    重置
                </button>
                <button id="danmu-settings-close" style="flex: 1; padding: 8px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer;">
                    关闭
                </button>
            </div>
        `;

        return panel;
    }

    // 弹幕设置面板控制
    let danmuSettingsPanel = null;
    let isSettingsPanelOpen = false;

    function toggleDanmuSettings() {
        if (!danmuSettingsPanel) {
            danmuSettingsPanel = createDanmuSettingsPanel();
            if (customPlayer && customPlayer.container) {
                customPlayer.container.appendChild(danmuSettingsPanel);
                setupDanmuSettingsEvents();
            }
        }

        if (isSettingsPanelOpen) {
            danmuSettingsPanel.style.display = 'none';
            isSettingsPanelOpen = false;
        } else {
            danmuSettingsPanel.style.display = 'block';
            isSettingsPanelOpen = true;
            updateSettingsDisplay();
        }
    }

    // 设置弹幕设置面板的事件监听
    function setupDanmuSettingsEvents() {
        if (!danmuSettingsPanel) return;

                 // 显示区域
         const displayAreaSelect = danmuSettingsPanel.querySelector('#danmu-display-area');
         displayAreaSelect.addEventListener('change', (e) => {
             danmuSettings.displayArea = e.target.value;
             updateDanmuContainer();
         });

        // 透明度
        const opacitySlider = danmuSettingsPanel.querySelector('#danmu-opacity');
        const opacityValue = danmuSettingsPanel.querySelector('#opacity-value');
        opacitySlider.addEventListener('input', (e) => {
            danmuSettings.opacity = parseFloat(e.target.value);
            opacityValue.textContent = Math.round(danmuSettings.opacity * 100) + '%';
            updateDanmuStyles();
        });

        // 字体大小
        const fontsizeSlider = danmuSettingsPanel.querySelector('#danmu-fontsize');
        const fontsizeValue = danmuSettingsPanel.querySelector('#fontsize-value');
        fontsizeSlider.addEventListener('input', (e) => {
            danmuSettings.fontSize = parseFloat(e.target.value);
            fontsizeValue.textContent = Math.round(danmuSettings.fontSize * 100) + '%';
            updateDanmuStyles();
        });

        // 滚动速度
        const speedSlider = danmuSettingsPanel.querySelector('#danmu-speed');
        const speedValue = danmuSettingsPanel.querySelector('#speed-value');
        speedSlider.addEventListener('input', (e) => {
            danmuSettings.speed = parseFloat(e.target.value);
            speedValue.textContent = Math.round(danmuSettings.speed * 100) + '%';
        });

        // 弹幕密度
        const densitySlider = danmuSettingsPanel.querySelector('#danmu-density');
        const densityValue = danmuSettingsPanel.querySelector('#density-value');
        densitySlider.addEventListener('input', (e) => {
            danmuSettings.density = parseFloat(e.target.value);
            densityValue.textContent = Math.round(danmuSettings.density * 100) + '%';
        });

        // 弹幕类型
        const scrollCheckbox = danmuSettingsPanel.querySelector('#danmu-scroll');
        const topCheckbox = danmuSettingsPanel.querySelector('#danmu-top');
        const bottomCheckbox = danmuSettingsPanel.querySelector('#danmu-bottom');

        scrollCheckbox.addEventListener('change', (e) => {
            danmuSettings.showScroll = e.target.checked;
        });

        topCheckbox.addEventListener('change', (e) => {
            danmuSettings.showTop = e.target.checked;
        });

        bottomCheckbox.addEventListener('change', (e) => {
            danmuSettings.showBottom = e.target.checked;
        });

        // 重置按钮
        const resetButton = danmuSettingsPanel.querySelector('#danmu-settings-reset');
        resetButton.addEventListener('click', () => {
            resetDanmuSettings();
        });

        // 关闭按钮
        const closeButton = danmuSettingsPanel.querySelector('#danmu-settings-close');
        closeButton.addEventListener('click', () => {
            toggleDanmuSettings();
        });
    }

    // 更新设置显示
    function updateSettingsDisplay() {
        if (!danmuSettingsPanel) return;

        const displayAreaSelect = danmuSettingsPanel.querySelector('#danmu-display-area');
        const opacitySlider = danmuSettingsPanel.querySelector('#danmu-opacity');
        const opacityValue = danmuSettingsPanel.querySelector('#opacity-value');
        const fontsizeSlider = danmuSettingsPanel.querySelector('#danmu-fontsize');
        const fontsizeValue = danmuSettingsPanel.querySelector('#fontsize-value');
        const speedSlider = danmuSettingsPanel.querySelector('#danmu-speed');
        const speedValue = danmuSettingsPanel.querySelector('#speed-value');
        const densitySlider = danmuSettingsPanel.querySelector('#danmu-density');
        const densityValue = danmuSettingsPanel.querySelector('#density-value');
        const scrollCheckbox = danmuSettingsPanel.querySelector('#danmu-scroll');
        const topCheckbox = danmuSettingsPanel.querySelector('#danmu-top');
        const bottomCheckbox = danmuSettingsPanel.querySelector('#danmu-bottom');

        displayAreaSelect.value = danmuSettings.displayArea;
        opacitySlider.value = danmuSettings.opacity;
        opacityValue.textContent = Math.round(danmuSettings.opacity * 100) + '%';
        fontsizeSlider.value = danmuSettings.fontSize;
        fontsizeValue.textContent = Math.round(danmuSettings.fontSize * 100) + '%';
        speedSlider.value = danmuSettings.speed;
        speedValue.textContent = Math.round(danmuSettings.speed * 100) + '%';
        densitySlider.value = danmuSettings.density;
        densityValue.textContent = Math.round(danmuSettings.density * 100) + '%';
        scrollCheckbox.checked = danmuSettings.showScroll;
        topCheckbox.checked = danmuSettings.showTop;
        bottomCheckbox.checked = danmuSettings.showBottom;
    }

    // 重置弹幕设置
    function resetDanmuSettings() {
        danmuSettings = {
            displayArea: 'full',
            opacity: 0.9,
            fontSize: 1.0,
            speed: 1.0,
            density: 1.0,
            showScroll: true,
            showTop: true,
            showBottom: true
        };
        updateSettingsDisplay();
        updateDanmuContainer();
        updateDanmuStyles();
    }

    // 更新弹幕容器显示区域
    function updateDanmuContainer() {
        if (!danmuContainer) return;

        // 全屏时强制使用全屏显示,不修改容器
        if (isCustomFullscreen) {
            return;
        }

        let height = '100%';
        let top = '0';

        switch (danmuSettings.displayArea) {
            case 'half':
                height = '50%';
                top = '0';
                break;
            case 'quarter':
                height = '25%';
                top = '0';
                break;
            case 'full':
            default:
                height = '100%';
                top = '0';
                break;
        }

        danmuContainer.style.height = height;
        danmuContainer.style.top = top;
    }

    // 更新现有弹幕样式
    function updateDanmuStyles() {
        const existingDanmu = document.querySelectorAll('.danmu-item');
        existingDanmu.forEach(element => {
            element.style.opacity = danmuSettings.opacity;

            // 更新字体大小
            const currentFontSize = parseFloat(element.style.fontSize);
            if (currentFontSize) {
                const baseFontSize = currentFontSize / (element.dataset.fontScale || 1);
                element.style.fontSize = (baseFontSize * danmuSettings.fontSize) + 'px';
                element.dataset.fontScale = danmuSettings.fontSize;
            }
        });
    }

    // 真正的全屏切换(让播放器容器进入全屏)
    function toggleCustomFullscreen() {
        if (!customPlayer) return;

        if (!isCustomFullscreen) {
            // 进入真正的全屏
            const container = customPlayer.container;

            // 准备全屏样式
            container.style.width = '100vw';
            container.style.height = '100vh';
            container.style.background = '#000';
            container.style.borderRadius = '0';
            container.style.boxShadow = 'none';

            // 使用浏览器全屏API让容器进入全屏
            if (container.requestFullscreen) {
                container.requestFullscreen();
            } else if (container.webkitRequestFullscreen) {
                container.webkitRequestFullscreen();
            } else if (container.mozRequestFullScreen) {
                container.mozRequestFullScreen();
            } else if (container.msRequestFullscreen) {
                container.msRequestFullscreen();
            }

            console.log('请求进入真正的全屏模式');
        } else {
            // 退出全屏
            if (document.exitFullscreen) {
                document.exitFullscreen();
            } else if (document.webkitExitFullscreen) {
                document.webkitExitFullscreen();
            } else if (document.mozCancelFullScreen) {
                document.mozCancelFullScreen();
            } else if (document.msExitFullscreen) {
                document.msExitFullscreen();
            }

            console.log('请求退出全屏模式');
        }
    }

    // 处理全屏状态变化
    function handleFullscreenChange() {
        const fullscreenElement = document.fullscreenElement ||
                                document.webkitFullscreenElement ||
                                document.mozFullScreenElement ||
                                document.msFullscreenElement;

        if (fullscreenElement) {
            // 进入全屏
            isCustomFullscreen = true;

            // 更新全屏按钮
            if (customPlayer && customPlayer.fullscreenButton) {
                customPlayer.fullscreenButton.textContent = '⛷';
                customPlayer.fullscreenButton.title = '退出全屏';
            }

            // 隐藏顶部工具栏
            if (customPlayer && customPlayer.header) {
                customPlayer.header.style.opacity = '0';
                customPlayer.header.style.transform = 'translateY(-100%)';
                customPlayer.header.style.pointerEvents = 'none';
            }

            // 添加鼠标移动显示工具栏的功能
            setupFullscreenControls();

            // 确保弹幕容器正确显示
            if (danmuContainer) {
                danmuContainer.style.position = 'absolute';
                danmuContainer.style.top = '0';
                danmuContainer.style.left = '0';
                danmuContainer.style.width = '100%';
                danmuContainer.style.height = '100%';
                danmuContainer.style.zIndex = '2147483647';
                danmuContainer.style.pointerEvents = 'none';
                danmuContainer.style.display = 'block';
                danmuContainer.style.visibility = 'visible';
            }

            console.log('已进入全屏模式');
        } else {
            // 退出全屏
            isCustomFullscreen = false;

            // 更新全屏按钮
            if (customPlayer && customPlayer.fullscreenButton) {
                customPlayer.fullscreenButton.textContent = '⛶';
                customPlayer.fullscreenButton.title = '全屏播放';
            }

            // 显示顶部工具栏
            if (customPlayer && customPlayer.header) {
                customPlayer.header.style.opacity = '1';
                customPlayer.header.style.transform = 'translateY(0)';
                customPlayer.header.style.pointerEvents = 'auto';
            }

            // 清除全屏控制
            clearFullscreenControls();

            // 恢复播放器容器样式
            if (customPlayer && customPlayer.container) {
                customPlayer.container.style.width = '80vw';
                customPlayer.container.style.height = '70vh';
                customPlayer.container.style.background = '#000';
                customPlayer.container.style.borderRadius = '8px';
                customPlayer.container.style.boxShadow = '0 8px 32px rgba(0,0,0,0.8)';
            }

            // 更新弹幕容器显示区域
            updateDanmuContainer();

            console.log('已退出全屏模式');
        }
    }

    // 全屏控制相关变量
    let fullscreenMouseTimer;
    let fullscreenMouseListener;

    // 设置全屏控制
    function setupFullscreenControls() {
        if (!customPlayer || !customPlayer.container) return;

        // 鼠标移动监听器
        fullscreenMouseListener = (e) => {
            // 显示工具栏
            if (customPlayer.header) {
                customPlayer.header.style.opacity = '1';
                customPlayer.header.style.transform = 'translateY(0)';
                customPlayer.header.style.pointerEvents = 'auto';
            }

            // 清除之前的定时器
            if (fullscreenMouseTimer) {
                clearTimeout(fullscreenMouseTimer);
            }

            // 3秒后隐藏工具栏
            fullscreenMouseTimer = setTimeout(() => {
                if (customPlayer.header && isCustomFullscreen) {
                    customPlayer.header.style.opacity = '0';
                    customPlayer.header.style.transform = 'translateY(-100%)';
                    customPlayer.header.style.pointerEvents = 'none';
                }
            }, 3000);
        };

        // 添加鼠标移动监听
        customPlayer.container.addEventListener('mousemove', fullscreenMouseListener);

        // 初始隐藏工具栏
        setTimeout(() => {
            if (customPlayer.header && isCustomFullscreen) {
                customPlayer.header.style.opacity = '0';
                customPlayer.header.style.transform = 'translateY(-100%)';
                customPlayer.header.style.pointerEvents = 'none';
            }
        }, 3000);
    }

    // 清除全屏控制
    function clearFullscreenControls() {
        if (fullscreenMouseTimer) {
            clearTimeout(fullscreenMouseTimer);
            fullscreenMouseTimer = null;
        }

        if (fullscreenMouseListener && customPlayer && customPlayer.container) {
            customPlayer.container.removeEventListener('mousemove', fullscreenMouseListener);
            fullscreenMouseListener = null;
        }
    }

    // 处理视频全屏(移动端)
    function handleVideoFullscreen(isFullscreen) {
        if (isFullscreen && danmuContainer) {
            console.log('处理视频全屏模式');
            // 创建全屏弹幕容器
            const fullscreenDanmuContainer = document.createElement('div');
            fullscreenDanmuContainer.id = 'fullscreen-danmu-container';
            fullscreenDanmuContainer.style.cssText = `
                position: fixed;
                top: 0;
                left: 0;
                width: 100vw;
                height: 100vh;
                pointer-events: none;
                overflow: hidden;
                z-index: 2147483647;
                background: transparent;
            `;

            // 将现有弹幕移动到全屏容器
            while (danmuContainer.firstChild) {
                fullscreenDanmuContainer.appendChild(danmuContainer.firstChild);
            }

            document.body.appendChild(fullscreenDanmuContainer);
            danmuContainer.dataset.originalContainer = 'true';
            danmuContainer = fullscreenDanmuContainer;
        } else if (!isFullscreen && danmuContainer && danmuContainer.id === 'fullscreen-danmu-container') {
            console.log('退出视频全屏模式');
            // 恢复原始容器
            const originalContainer = document.getElementById('danmu-container');
            if (originalContainer) {
                // 将弹幕移回原始容器
                while (danmuContainer.firstChild) {
                    originalContainer.appendChild(danmuContainer.firstChild);
                }

                // 移除全屏容器
                danmuContainer.remove();
                danmuContainer = originalContainer;
            }
        }
    }

    // 显示弹幕
    function displayDanmu(currentTime) {
        if (!danmuData.length || !danmuContainer || !isPlaying) return;

        // 检查是否处于全屏状态,如果是则确保弹幕容器正确显示
        ensureDanmuVisibility();

        const adjustedTime = (currentTime + timeOffset) * 10; // 转换为0.1秒单位

        // 清除过期弹幕
        const existingDanmu = danmuContainer.querySelectorAll('.danmu-item');
        existingDanmu.forEach(item => {
            const itemTime = parseFloat(item.dataset.time);
            if (adjustedTime - itemTime > 100) { // 10秒后清除
                item.remove();
                activeDanmuElements.delete(item);
            }
        });

        // 添加新弹幕(应用密度设置)
        let danmuCount = 0;
        const maxDanmuPerFrame = Math.ceil(5 * danmuSettings.density);

        danmuData.forEach(danmu => {
            const danmuTime = danmu.time;
            const timeDiff = Math.abs(adjustedTime - danmuTime);

            if (timeDiff <= 1 && !danmuContainer.querySelector(`[data-sn="${danmu.sn}"]`)) {
                // 应用弹幕类型过滤
                const position = danmu.position === 2 ? 'bottom' : danmu.position === 1 ? 'top' : 'scroll';

                if ((position === 'scroll' && !danmuSettings.showScroll) ||
                    (position === 'top' && !danmuSettings.showTop) ||
                    (position === 'bottom' && !danmuSettings.showBottom)) {
                    return;
                }

                // 应用密度限制
                if (danmuCount >= maxDanmuPerFrame) {
                    return;
                }

                createDanmuElement(danmu);
                danmuCount++;
            }
        });
    }

    // 确保弹幕容器可见
    function ensureDanmuVisibility() {
        if (!danmuContainer) return;

        // 确保弹幕容器始终可见
        danmuContainer.style.position = 'absolute';
        danmuContainer.style.top = '0';
        danmuContainer.style.left = '0';
        danmuContainer.style.width = '100%';
        danmuContainer.style.height = '100%';
        danmuContainer.style.zIndex = '2147483647';
        danmuContainer.style.pointerEvents = 'none';
        danmuContainer.style.display = 'block';
        danmuContainer.style.visibility = 'visible';
    }

    // 暂停所有弹幕动画
    function pauseAllDanmu() {
        activeDanmuElements.forEach(element => {
            // 对于滚动弹幕,记录当前位置并停止动画
            if (element.classList.contains('scroll-danmu')) {
                const computedStyle = window.getComputedStyle(element);
                const currentRight = computedStyle.right;
                element.style.transition = 'none';
                element.style.right = currentRight;
                element.dataset.pausedRight = currentRight;

                // 记录暂停时间,用于计算剩余时间
                element.dataset.pausedTime = Date.now();
            }

            // 对于固定弹幕,清除自动移除的定时器
            if (element.classList.contains('fixed-danmu') && element.dataset.removeTimer) {
                clearTimeout(parseInt(element.dataset.removeTimer));
                delete element.dataset.removeTimer;
            }
        });
    }

    // 恢复所有弹幕动画
    function resumeAllDanmu() {
        activeDanmuElements.forEach(element => {
            // 对于滚动弹幕,从暂停位置继续滚动
            if (element.classList.contains('scroll-danmu') && element.dataset.pausedRight) {
                const pausedRight = parseFloat(element.dataset.pausedRight);
                const containerWidth = element.parentElement.offsetWidth;
                const elementWidth = element.offsetWidth;
                const totalDistance = containerWidth + elementWidth;

                // 计算已经移动的距离
                const movedDistance = totalDistance * (100 - pausedRight) / 100;
                const remainingDistance = totalDistance - movedDistance;
                const remainingTime = (remainingDistance / totalDistance) * 8; // 8秒总时长

                element.style.transition = `right ${remainingTime}s linear`;
                element.style.right = '100%';

                // 设置新的移除定时器
                const removeTimer = setTimeout(() => {
                    if (element.parentNode) {
                        element.remove();
                        activeDanmuElements.delete(element);
                    }
                }, remainingTime * 1000);

                element.dataset.removeTimer = removeTimer.toString();
                delete element.dataset.pausedRight;
                delete element.dataset.pausedTime;
            }

            // 对于固定弹幕,重新设置移除定时器
            if (element.classList.contains('fixed-danmu') && !element.dataset.removeTimer) {
                const removeTimer = setTimeout(() => {
                    if (element.parentNode) {
                        element.remove();
                        activeDanmuElements.delete(element);
                    }
                }, 3000);

                element.dataset.removeTimer = removeTimer.toString();
            }
        });
    }

    // 清除所有弹幕
    function clearAllDanmu() {
        const existingDanmu = danmuContainer.querySelectorAll('.danmu-item');
        existingDanmu.forEach(item => {
            item.remove();
        });
        activeDanmuElements.clear();
    }

    // 创建弹幕元素
    function createDanmuElement(danmu) {
        const danmuElement = document.createElement('div');
        danmuElement.className = 'danmu-item';
        danmuElement.dataset.sn = danmu.sn;
        danmuElement.dataset.time = danmu.time;
        danmuElement.textContent = danmu.text;

        // 弹幕样式(应用设置)
        const baseFontSize = danmu.size === 2 ? 20 : danmu.size === 1 ? 16 : 14;
        const fontSize = (baseFontSize * danmuSettings.fontSize) + 'px';
        const position = danmu.position === 2 ? 'bottom' : danmu.position === 1 ? 'top' : 'scroll';

        danmuElement.style.cssText = `
            position: absolute;
            color: ${danmu.color};
            font-size: ${fontSize};
            font-weight: bold;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.8);
            white-space: nowrap;
            z-index: 2147483647;
            pointer-events: none;
            font-family: Arial, sans-serif;
            opacity: ${danmuSettings.opacity};
        `;

        // 保存字体缩放比例
        danmuElement.dataset.fontScale = danmuSettings.fontSize;

        // 添加到活跃弹幕集合
        activeDanmuElements.add(danmuElement);

        // 根据位置类型设置弹幕位置和动画
        if (position === 'scroll') {
            // 滚动弹幕(应用速度设置)
            danmuElement.classList.add('scroll-danmu');

            // 根据显示区域调整位置(全屏时使用全区域)
            let maxTop = 70;
            if (!isCustomFullscreen) {
                switch (danmuSettings.displayArea) {
                    case 'half':
                        maxTop = 35;
                        break;
                    case 'quarter':
                        maxTop = 15;
                        break;
                    default:
                        maxTop = 70;
                        break;
                }
            }

            const randomTop = Math.random() * maxTop + 10;
            danmuElement.style.top = `${randomTop}%`;
            danmuElement.style.right = '-100%';

            // 应用速度设置
            const duration = 8 / danmuSettings.speed;
            danmuElement.style.transition = `right ${duration}s linear`;

            danmuContainer.appendChild(danmuElement);

            // 触发滚动动画
            setTimeout(() => {
                if (isPlaying) {
                    danmuElement.style.right = '100%';
                }
            }, 50);

            // 根据速度调整移除时间
            const removeTimer = setTimeout(() => {
                if (danmuElement.parentNode) {
                    danmuElement.remove();
                    activeDanmuElements.delete(danmuElement);
                }
            }, duration * 1000);

            danmuElement.dataset.removeTimer = removeTimer.toString();
        } else if (position === 'top') {
            // 顶部固定弹幕
            danmuElement.classList.add('fixed-danmu');
            danmuElement.style.top = '10%';
            danmuElement.style.left = '50%';
            danmuElement.style.transform = 'translateX(-50%)';
            danmuContainer.appendChild(danmuElement);

            const removeTimer = setTimeout(() => {
                if (danmuElement.parentNode) {
                    danmuElement.remove();
                    activeDanmuElements.delete(danmuElement);
                }
            }, 3000);

            danmuElement.dataset.removeTimer = removeTimer.toString();
        } else if (position === 'bottom') {
            // 底部固定弹幕
            danmuElement.classList.add('fixed-danmu');
            danmuElement.style.bottom = '10%';
            danmuElement.style.left = '50%';
            danmuElement.style.transform = 'translateX(-50%)';
            danmuContainer.appendChild(danmuElement);

            const removeTimer = setTimeout(() => {
                if (danmuElement.parentNode) {
                    danmuElement.remove();
                    activeDanmuElements.delete(danmuElement);
                }
            }, 3000);

            danmuElement.dataset.removeTimer = removeTimer.toString();
        }
    }

    // 创建上传按钮
    function createUploadButton() {
        const button = document.createElement('button');
        button.innerHTML = '🎬 上传视频+弹幕';
        button.style.cssText = `
            position: fixed;
            bottom: 20px;
            right: 20px;
            z-index: 9999;
            padding: 12px 16px;
            background: #007bff;
            color: white;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            font-size: 14px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
            transition: all 0.3s ease;
        `;

        button.addEventListener('mouseenter', () => {
            button.style.background = '#0056b3';
            button.style.transform = 'scale(1.05)';
        });

        button.addEventListener('mouseleave', () => {
            button.style.background = '#007bff';
            button.style.transform = 'scale(1)';
        });

        return button;
    }

    // 创建文件输入框
    function createFileInput() {
        const fileInput = document.createElement('input');
        fileInput.type = 'file';
        fileInput.accept = 'video/*';
        fileInput.style.display = 'none';
        return fileInput;
    }

    // 显示通知
    function showNotification(message, type = 'info') {
        const notification = document.createElement('div');
        notification.textContent = message;
        notification.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            z-index: 10001;
            padding: 12px 20px;
            border-radius: 6px;
            color: white;
            font-size: 14px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
            transition: all 0.3s ease;
            ${type === 'success' ? 'background: #28a745;' :
              type === 'error' ? 'background: #dc3545;' : 'background: #17a2b8;'}
        `;

        document.body.appendChild(notification);

        setTimeout(() => {
            notification.style.opacity = '0';
            setTimeout(() => {
                if (notification.parentNode) {
                    notification.remove();
                }
            }, 300);
        }, 3000);
    }

    // 处理视频上传
    async function handleVideoUpload(file) {
        const videoSn = getVideoSn();
        if (!videoSn) {
            showNotification('无法获取视频SN,请确保在正确的页面', 'error');
            return;
        }

        showNotification('正在获取弹幕数据...', 'info');

        const success = await fetchDanmu(videoSn);
        if (!success) {
            showNotification('获取弹幕失败', 'error');
            return;
        }

        // 创建播放器(如果还没有)
        if (!customPlayer) {
            customPlayer = createCustomPlayer();
        }

        // 加载视频
        const fileURL = URL.createObjectURL(file);
        customPlayer.video.src = fileURL;

        // 显示播放器
        customPlayer.container.style.display = 'flex';

        showNotification(`视频加载成功,共 ${danmuData.length} 条弹幕`, 'success');
    }

    // 初始化脚本
    function init() {
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', init);
            return;
        }

        // 创建按钮和文件输入框
        const uploadButton = createUploadButton();
        const fileInput = createFileInput();

        document.body.appendChild(uploadButton);
        document.body.appendChild(fileInput);

        // 事件监听
        uploadButton.addEventListener('click', () => {
            fileInput.click();
        });

        fileInput.addEventListener('change', (event) => {
            const file = event.target.files[0];

            if (!file) return;

            if (!file.type.startsWith('video/')) {
                showNotification('请选择视频文件!', 'error');
                return;
            }

            handleVideoUpload(file);
            fileInput.value = '';
        });

        // ESC键退出全屏由浏览器自动处理,不需要手动监听

        console.log('动画疯弹幕播放器已加载');
    }

    // 启动脚本
    init();
})();