Greasy Fork

Greasy Fork is available in English.

视频完成自动下一个

检查视频进度,达到目标时间后点击下一节/章并尝试自动播放,无视频时直接跳过,执行一次后结束

目前为 2025-02-24 提交的版本。查看 最新版本

// ==UserScript==
// @name         视频完成自动下一个
// @namespace    http://tampermonkey.net/
// @version      0.22
// @description  检查视频进度,达到目标时间后点击下一节/章并尝试自动播放,无视频时直接跳过,执行一次后结束
// @author       yhxwyzm
// @match        https://www.learnin.com.cn/*
// @grant        none
// @license      AGPL
// ==/UserScript==

(function() {
    'use strict';

    // 将时间字符串转换为秒数
    function timeToSeconds(timeStr) {
        const cleanedTime = timeStr.replace(/[^\d:]/g, '');
        const [hours, minutes, seconds] = cleanedTime.split(':').map(Number);
        return hours * 3600 + minutes * 60 + seconds;
    }

    // 模拟用户点击
    function simulateClick(element) {
        const event = new MouseEvent('click', { bubbles: true, cancelable: true, view: window });
        element.dispatchEvent(event);
    }

    // 自动播放视频(带重试机制)
    function autoPlayVideo() {
        console.log('尝试自动播放视频...');
        const video = document.querySelector('video');
        const playButton = document.querySelector('.pv-iconfont.pv-iconfont-hover');

        function tryPlayVideo(attempt = 1, maxAttempts = 3) {
            if (!video) {
                console.log('未找到视频元素');
                if (playButton) {
                    console.log('尝试点击播放按钮');
                    simulateClick(playButton);
                }
                return;
            }

            video.muted = true; // 确保静音
            if (video.paused && video.readyState >= 2) {
                const playPromise = video.play();
                if (playPromise !== undefined) {
                    playPromise.then(() => {
                        console.log('静音自动播放成功');
                    }).catch(error => {
                        console.error('静音自动播放失败:', error.message);
                        if (playButton) {
                            console.log('尝试点击播放按钮作为备用');
                            simulateClick(playButton);
                        }
                    });
                }
            } else if (!video.paused) {
                console.log('视频已在播放,无需操作');
            } else if (video.readyState < 2) {
                console.log('视频未准备好,readyState:', video.readyState);
                if (attempt < maxAttempts) {
                    console.log(`第 ${attempt} 次尝试失败,1秒后重试...`);
                    setTimeout(() => tryPlayVideo(attempt + 1, maxAttempts), 1000);
                } else {
                    console.log('达到最大重试次数,尝试点击播放按钮');
                    if (playButton) {
                        simulateClick(playButton);
                    } else {
                        console.log('无播放按钮可用,放弃尝试');
                    }
                }
            }
        }

        tryPlayVideo();
    }

    // 检查视频进度或跳过无视频页面
    function checkVideoProgress() {
        console.log('检查页面状态...');

        const videoHint = document.querySelector('.video-hint');
        const nextButton = document.querySelector('.next-chapter button');

        console.log('下一节/章/页按钮:', nextButton ? nextButton.textContent.trim() : '未找到');

        if (!nextButton) {
            console.log('未找到下一节/章/页按钮,停止检查');
            return;
        }

        // 无视频情况:没有.video-hint,直接点击下一节/章/页
        if (!videoHint) {
            console.log('未找到.video-hint,视为无视频页面,直接点击下一节/章/页');
            simulateClick(nextButton);
            return;
        }

        // 有视频情况:检查时间进度
        const spans = videoHint.querySelectorAll('span');
        console.log('找到的span数量:', spans.length, '内容:', Array.from(spans).map(s => s.textContent.trim()));

        let targetTime = null;
        let currentTime = null;
        for (let i = 0; i < spans.length; i++) {
            const text = spans[i].textContent.trim();
            if (/^\d{2}:\d{2}:\d{2}$/.test(text)) {
                if (!targetTime) {
                    targetTime = text;
                } else if (!currentTime) {
                    currentTime = text;
                    break;
                }
            }
        }

        if (!targetTime || !currentTime) {
            console.log('未找到完整的时间对', { targetTime, currentTime });
            return;
        }

        console.log('目标时间:', targetTime, '当前时间:', currentTime);

        const targetSeconds = timeToSeconds(targetTime);
        const currentSeconds = timeToSeconds(currentTime);

        console.log('目标秒数:', targetSeconds, '当前秒数:', currentSeconds);

        if (currentSeconds >= targetSeconds) {
            console.log('时间条件满足,点击下一节/章/页按钮');
            simulateClick(nextButton);
            setTimeout(() => {
                autoPlayVideo();
            }, 5000); // 5秒延迟等待加载
        } else {
            console.log('时间尚未达到目标');
        }
    }

    // 启动单次检查
    function startSingleCheck() {
        console.log('启动单次检查...');
        checkVideoProgress();
    }

    // 初始化
    function init() {
        startSingleCheck(); // 启动单次检查
    }

    // 页面加载后启动
    if (document.readyState === 'complete' || document.readyState === 'interactive') {
        console.log('页面初始状态:', document.readyState);
        setTimeout(init, 3000);
    } else {
        window.addEventListener('load', () => {
            console.log('页面加载完成,开始初始化');
            setTimeout(init, 3000);
        });
    }

    // 监听SPA路由变化
    let lastUrl = location.href;
    new MutationObserver(() => {
        const currentUrl = location.href;
        if (currentUrl !== lastUrl) {
            console.log('检测到路由变化,重新初始化');
            lastUrl = currentUrl;
            setTimeout(init, 3000); // 路由变化后重新启动
        }
    }).observe(document.body, { childList: true, subtree: true });

    // 设置定时器,1分钟后再次执行
    setTimeout(() => {
        console.log('一分钟时间到,再次执行');
        init();
    }, 60000); // 60000毫秒 = 1分钟
})();