Greasy Fork

Greasy Fork is available in English.

西瓜卡通 - 辅助播放插件

该功能允许用户在不离开当前页面的情况下更换视频播放源,以及播放历史记录。

当前为 2023-11-04 提交的版本,查看 最新版本

// ==UserScript==
// @name         西瓜卡通 - 辅助播放插件
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  该功能允许用户在不离开当前页面的情况下更换视频播放源,以及播放历史记录。
// @author       神梦无痕
// @match        https://cn.xgcartoon.com/*
// @match        https://www.xgcartoon.com/*
// @match        https://pframe.xgcartoon.com/player.htm*
// @icon         https://cn.xgcartoon.com/icon/favicon.ico
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 播放历史列表的键名
    var historyKey = 'playHistory';

    // 当前播放的视频信息
    window.G_currentVideo = {
        title: null,
        url: null,
        curTime: null,
        durTime: null
    };

    window.setLocalStorage = GM_setValue;
    window.getLocalStorage = GM_getValue;


    var path = window.location.pathname;
    console.log(path);
    if(path === '/user/bookshelf'){
        userBookshelf();
    }else if(path.split('/')[1] === 'video' || path.split('/')[1] === 'user' ){
        inlineVideoSourceSwitch();
    }else if(path === '/player.htm'){
        pframePlayer();
    }

    // 从 GM_getValue 获取播放历史
    function getPlayHistory(dramaTitle) {
        var history = GM_getValue(historyKey, "{}");
        history = JSON.parse(history);
        if(!history[dramaTitle]){
            history[dramaTitle] = {};
        }
        return history;
    }

    // 将播放历史保存到 GM_setValue
    function savePlayHistory(dramaTitle, video) {
        var history = getPlayHistory(dramaTitle);
        if(video.title) history[dramaTitle].title = video.title;
        if(video.url) history[dramaTitle].url = video.url;
        if(video.curTime) history[dramaTitle].curTime = video.curTime;
        if(video.durTime) history[dramaTitle].durTime = video.durTime;
        GM_setValue(historyKey, JSON.stringify(history));

        console.log(GM_getValue(historyKey, ''));
    }

    // 将秒转化为时间格式
    function formatTime(seconds) {
        seconds = Math.floor(seconds);

        const hours = Math.floor(seconds / 3600);
        const minutes = Math.floor((seconds % 3600) / 60);
        const remainingSeconds = seconds % 60;

        const formattedHours = hours > 0 ? `${hours.toString().padStart(2, '0')}:` : '';
        const formattedMinutes = minutes.toString().padStart(2, '0');
        const formattedSeconds = remainingSeconds.toString().padStart(2, '0');

        return `${formattedHours}${formattedMinutes}:${formattedSeconds}`;
    }

    // 格式化为百分号
    function formatAsPercentage(decimal, minimumFractionDigits = 0, maximumFractionDigits = 0) {
        var formatter = new Intl.NumberFormat('en-US', {
            style: 'percent',
            minimumFractionDigits: minimumFractionDigits,
            maximumFractionDigits: maximumFractionDigits
        });
        return formatter.format(decimal);
    }

    function pframePlayer(){
        var elevideo = document.querySelector("#video_frame");
        elevideo.addEventListener('progress', function (e) {
            // 客户端正在请求数据
            // console.log('客户端正在请求数据:', elevideo.buffered.end(0));
        });
        elevideo.addEventListener('loadedmetadata', function () { //成功获取资源长度
            //视频的总长度
            console.log('视频的总长度:' + elevideo.duration);
            window.G_currentVideo.durTime = elevideo.duration;
            savePlayHistoryTime(window.G_currentVideo);

            // 获取历史播放进度
            var history = GM_getValue(historyKey, '{}');
            history = JSON.parse(history);
            var history_book = history[getDramaTitle()];
            if(history_book){
                var seconds = history_book.curTime || 0;
                elevideo.currentTime = seconds;
            }
            elevideo.play();
        });

        elevideo.addEventListener('play', function () { //播放开始执行的函数
            console.log("开始播放");
        });
        elevideo.addEventListener('playing', function () { //播放中
            console.log("播放中");
        });
        elevideo.addEventListener('waiting', function () { //加载
            console.log("加载中");
        });
        elevideo.addEventListener('pause', function () { //暂停开始执行的函数
            console.log("暂停播放", elevideo.currentTime);
            window.G_currentVideo.curTime = elevideo.currentTime;
            savePlayHistoryTime(window.G_currentVideo);
        });
        elevideo.addEventListener('ended', function () { //结束
            console.log("播放结束");
            window.G_currentVideo.curTime = elevideo.currentTime;
            savePlayHistoryTime(window.G_currentVideo);
        }, false);

        function getDramaTitle(){
            var params = new URLSearchParams(window.location.search);
            var vid = params.get('vid');
            return GM_getValue(vid);
        }

        function savePlayHistoryTime(video){
            savePlayHistory(getDramaTitle(), video)
        }
    }


    function userBookshelf(){
        var bookshelfItems = document.querySelectorAll("#layout > div.bookshelf.container .bookshelf-item");
        bookshelfItems.forEach(function(book) {
            var bookshelf = book.querySelector("div.bookshelf-item-info > div > a");
            var lastChapter = book.querySelector(".last-chapter");
            var btnBase = book.querySelector(".btn-base");

            // 获取动画名
            var bookTitle = bookshelf.textContent || bookshelf.innerText;

            // 获取历史播放记录
            var history = GM_getValue(historyKey, '{}');
            history = JSON.parse(history);
            var history_book = history[bookTitle];
            if(history_book){
                var chapterTitle = history_book.title;
                var btnBaseURL = history_book.url;
                var seconds = history_book.curTime || 0;
                var duration = history_book.durTime;
                var progress = "";

                // 计算播放进度
                if(duration){
                     progress = '【' + formatAsPercentage(seconds / duration) + '】'
                }

                // 修改最后播放标题
                if(chapterTitle){
                    lastChapter.innerHTML = '上次看到' + progress + ':  ' + chapterTitle;
                }

                // 修改最后播放链接
                if(btnBaseURL){
                    btnBase.href = btnBaseURL;
                }
            }
        });
    }


    function inlineVideoSourceSwitch(){

        // 获取当前的剧名
        window.G_dramaTitle = '';
        var breadcrumbItem = document.querySelector("nav > ol > a.breadcrumb-item:nth-child(3)")
        if(breadcrumbItem){
            window.G_dramaTitle = breadcrumbItem.textContent || breadcrumbItem.innerText;
        }

        // 关联剧名和vid
        var src = document.querySelector('iframe')?.src;
        var search = src.split('?')[1];
        var params = new URLSearchParams(search);
        var vid = params.get('vid');
        GM_setValue(vid, window.G_dramaTitle);


        // 保存当前页面视频信息
        var aActive = document.querySelector('#video-volumes-items a.active');
        if(aActive){
            // 父组件滚动法,滚动到 active 元素位置
            var activeParent = aActive.parentElement;
            document.querySelector("#video-volumes-items").scrollTo(0, activeParent.offsetTop - activeParent.offsetHeight);

            // 获取a标签的href属性和文本内容(标题)
            var href = aActive.getAttribute('href');
            var aActiveTitle = aActive.querySelector('.title');
            var title = aActiveTitle.textContent || aActiveTitle.innerText;

            // 更新当前视频信息
            window.G_currentVideo = { title: title, url: href };
            savePlayHistory(window.G_dramaTitle, window.G_currentVideo);
        }

        // 获取#video-volumes-items元素下的所有a标签
        var videoVolumeItems = document.querySelectorAll('#video-volumes-items a');


        // 页面关闭前保存当前视频到播放历史
        window.addEventListener('beforeunload', function() {
            if (window.G_dramaTitle && window.G_currentVideo.title && window.G_currentVideo.url) {
                savePlayHistory(window.G_dramaTitle, window.G_currentVideo);
            }
        });

        // 页面窗口前保存当前视频到播放历史
        window.addEventListener('unload', function() {
            if (window.G_dramaTitle && window.G_currentVideo.title && window.G_currentVideo.url) {
                savePlayHistory(window.G_dramaTitle, window.G_currentVideo);
            }
        });

        // 为每个a标签添加点击事件监听器
        videoVolumeItems.forEach(function(item) {
            item.addEventListener('click', function(event) {
                // 阻止a标签的默认点击行为
                event.preventDefault();

                // 移除所有a标签的active类
                videoVolumeItems.forEach(function(el) {
                    el.classList.remove('active');
                });

                // 给当前点击的a标签添加active类
                item.classList.add('active');

                // 获取a标签的href属性和文本内容(标题)
                var href = item.getAttribute('href');
                var item_title = item.querySelector('.title');
                var title = item_title.textContent || item_title.innerText;

                // 更新当前视频信息
                window.G_currentVideo = { title: title, url: href };
                savePlayHistory(window.G_dramaTitle, window.G_currentVideo);

                // 创建XHR请求
                var xhr = new XMLHttpRequest();
                xhr.open('GET', href, true);
                xhr.responseType = 'document';

                // XHR请求完成后的处理
                xhr.onload = function() {
                    if (xhr.status === 200) {
                        // 请求成功,获取iframe元素
                        var iframeSrc = xhr.response.querySelector('iframe')?.src;
                        if (iframeSrc) {
                            // 找到当前页面的iframe元素
                            var currentIframe = document.querySelector('iframe');
                            if (currentIframe) {
                                // 替换当前页面iframe的src属性
                                currentIframe.src = iframeSrc;
                            } else {
                                console.log('No iframe found on the current page to replace src.');
                            }
                        } else {
                            console.log('No iframe found in the response.');
                        }
                    } else {
                        console.log('Request failed. Returned status of ' + xhr.status);
                    }
                };

                // 发送XHR请求
                xhr.send();
            });
        });
    }

})();