Jable视频播放进度记录

记住Jable网站视频播放进度,刷新后自动恢复

// ==UserScript==
// @name         Jable视频播放进度记录
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  记住Jable网站视频播放进度,刷新后自动恢复
// @author       You
// @match        https://jable.tv/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // 存储键前缀
    const STORAGE_PREFIX = 'jable_video_progress_';
    
    // 获取当前页面的唯一标识
    function getVideoId() {
        const url = window.location.href;
        const match = url.match(/\/videos\/([^\/]+)/);
        return match ? match[1] : null;
    }
    
    // 保存播放进度
    function saveProgress(videoId, currentTime, duration) {
        const progressData = {
            currentTime: currentTime,
            duration: duration,
            timestamp: Date.now(),
            url: window.location.href
        };
        localStorage.setItem(STORAGE_PREFIX + videoId, JSON.stringify(progressData));
    }
    
    // 获取播放进度
    function getProgress(videoId) {
        const data = localStorage.getItem(STORAGE_PREFIX + videoId);
        if (data) {
            try {
                const progressData = JSON.parse(data);
                // 检查数据是否过期(7天)
                if (Date.now() - progressData.timestamp < 7 * 24 * 60 * 60 * 1000) {
                    return progressData;
                }
            } catch (e) {
                console.error('解析进度数据失败:', e);
            }
        }
        return null;
    }
    
    // 清理过期数据
    function cleanExpiredData() {
        const keys = Object.keys(localStorage);
        const expireTime = 7 * 24 * 60 * 60 * 1000; // 7天
        
        keys.forEach(key => {
            if (key.startsWith(STORAGE_PREFIX)) {
                try {
                    const data = JSON.parse(localStorage.getItem(key));
                    if (Date.now() - data.timestamp > expireTime) {
                        localStorage.removeItem(key);
                    }
                } catch (e) {
                    // 删除无效数据
                    localStorage.removeItem(key);
                }
            }
        });
    }
    
    // 等待视频元素加载
    function waitForVideo(callback) {
        const checkVideo = () => {
            const video = document.querySelector('video');
            if (video) {
                callback(video);
            } else {
                setTimeout(checkVideo, 500);
            }
        };
        
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', checkVideo);
        } else {
            checkVideo();
        }
    }
    
    // 创建进度提示
    function showProgressTip(currentTime, duration) {
        const tip = document.createElement('div');
        tip.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 10px 15px;
            border-radius: 5px;
            font-size: 14px;
            z-index: 10000;
            max-width: 300px;
            word-wrap: break-word;
        `;
        
        const formatTime = (seconds) => {
            const minutes = Math.floor(seconds / 60);
            const secs = Math.floor(seconds % 60);
            return `${minutes}:${secs.toString().padStart(2, '0')}`;
        };
        
        tip.innerHTML = `
            <div>检测到播放记录</div>
            <div>上次播放到: ${formatTime(currentTime)} / ${formatTime(duration)}</div>
            <div style="margin-top: 5px; font-size: 12px;">
                <button id="resume-btn" style="margin-right: 10px; padding: 2px 8px; background: #007bff; color: white; border: none; border-radius: 3px; cursor: pointer;">恢复播放</button>
                <button id="start-over-btn" style="padding: 2px 8px; background: #6c757d; color: white; border: none; border-radius: 3px; cursor: pointer;">从头开始</button>
            </div>
        `;
        
        document.body.appendChild(tip);
        
        // 5秒后自动隐藏
        setTimeout(() => {
            if (tip.parentNode) {
                tip.remove();
            }
        }, 8000);
        
        return tip;
    }
    
    // 主要功能
    function initVideoProgress() {
        const videoId = getVideoId();
        if (!videoId) return;
        
        // 清理过期数据
        cleanExpiredData();
        
        waitForVideo((video) => {
            let progressRestored = false;
            let saveTimeout = null;
            
            // 检查是否有保存的进度
            const savedProgress = getProgress(videoId);
            
            // 视频元数据加载完成后处理
            const handleLoadedMetadata = () => {
                if (savedProgress && !progressRestored && savedProgress.currentTime > 10) {
                    const tip = showProgressTip(savedProgress.currentTime, savedProgress.duration);
                    
                    // 恢复播放按钮
                    tip.querySelector('#resume-btn').addEventListener('click', () => {
                        video.currentTime = savedProgress.currentTime;
                        progressRestored = true;
                        tip.remove();
                    });
                    
                    // 从头开始按钮
                    tip.querySelector('#start-over-btn').addEventListener('click', () => {
                        video.currentTime = 0;
                        progressRestored = true;
                        tip.remove();
                    });
                }
            };
            
            // 监听元数据加载
            if (video.readyState >= 1) {
                handleLoadedMetadata();
            } else {
                video.addEventListener('loadedmetadata', handleLoadedMetadata);
            }
            
            // 保存播放进度(防抖处理)
            const saveProgressDebounced = () => {
                if (saveTimeout) {
                    clearTimeout(saveTimeout);
                }
                saveTimeout = setTimeout(() => {
                    if (video.currentTime > 0 && video.duration > 0) {
                        saveProgress(videoId, video.currentTime, video.duration);
                    }
                }, 1000);
            };
            
            // 监听播放进度变化
            video.addEventListener('timeupdate', saveProgressDebounced);
            
            // 页面卸载前保存
            window.addEventListener('beforeunload', () => {
                if (video.currentTime > 0 && video.duration > 0) {
                    saveProgress(videoId, video.currentTime, video.duration);
                }
            });
            
            // 视频暂停时保存
            video.addEventListener('pause', () => {
                if (video.currentTime > 0 && video.duration > 0) {
                    saveProgress(videoId, video.currentTime, video.duration);
                }
            });
            
            console.log('Jable视频进度记录脚本已启动');
        });
    }
    
    // 页面加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initVideoProgress);
    } else {
        initVideoProgress();
    }
    
    // 处理单页应用的路由变化
    let currentUrl = window.location.href;
    const observer = new MutationObserver(() => {
        if (currentUrl !== window.location.href) {
            currentUrl = window.location.href;
            setTimeout(initVideoProgress, 1000); // 延迟执行,等待页面更新
        }
    });
    
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });

})();