Greasy Fork

Greasy Fork is available in English.

B站保存播放进度

自动保存B站多集视频的进度(例如各类网课视频)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @author      oscarcx123
// @name        B站保存播放进度
// @description 自动保存B站多集视频的进度(例如各类网课视频)
// @namespace   https://github.com/oscarcx123
// @language    zh-CN
// @version     1
// @icon        https://www.bilibili.com/favicon.ico
// @website     https://github.com/oscarcx123/bili-seeker
// @supportURL  https://github.com/oscarcx123/bili-seeker/issues
// @include     https://www.bilibili.com/video/*
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_log
// @grant       unsafeWindow
// ==/UserScript==

(function () {
    'use strict';

    var video = document.querySelector(".bilibili-player-video video");
    var episodeLst = document.querySelector(".list-box"); // 检测有无视频选集列表(没有会返回null)
    var videoId = getVideoID();
    var savedEpisode = getVal("savedEpisode", 1); // 读取集数
    var savedTime = getVal("savedTime", 0); // 读取时间点
    var currEpisode = getCurrEpisode(); // 获取当前集数
    var currTime = getCurrTime(); // 获取当前时间点


    // 读取触发条件:超过1集的视频,并且当前进度和储存的进度不同
    if (episodeLst != null && ((savedEpisode != currEpisode) || (savedTime != currTime))) {
        loadEpisode();
    }

    // 储存触发条件:超过1集的视频
    if (episodeLst != null) {
        setInterval(saveEpisode, 10000); // 定时保存播放进度
    }

    // 读取播放进度
    function loadEpisode() {
        var savedEpisode = getVal("savedEpisode", 1);
        var savedTime = getVal("savedTime", 0);
        GM_log("CurrPos", savedEpisode, "@", savedTime);

        if (!(savedTime == 0 && savedEpisode == 1)) {
            location.href = `/video/${videoId}?p=${savedEpisode}&t=${savedTime}`;
        }
    }


    // 保存播放进度
    function saveEpisode() {
        var pageNo = getCurrEpisode();
        var currentTime = video.currentTime || 0;
        if (!(pageNo == 1 && currentTime == 0)) {
            setVal("savedEpisode", pageNo);
            setVal("savedTime", currentTime);
        }
    }


    // 读取数据
    function getVal(name, defaultValue) {
        var key = `${videoId}_${name}`;
        var res = GM_getValue(key, defaultValue);
        GM_log("getVal -", key, res);
        return res;
    }

    // 储存数据
    function setVal(name, value) {
        var key = `${videoId}_${name}`;
        GM_setValue(key, value);
        GM_log("setVal -", key, value);
    }


    // 获取视频id
    function getVideoID() {
        return location.pathname.split("/")[2];
    }


    // 获取参数(?p=xxx&t=xxx)
    function getParams() {
        var params = location.search;
        var res = {};
        if (params.length > 1) {
            var lst = params.substring(1).split("&");
            for (var i = 0; i < lst.length; i++) {
                var param = lst[i].split("=");
                res[param[0]] = param[1];
            }
        }
        return res;
    }


    // 获取当前集数(?p=xxx)
    function getCurrEpisode() {
        var lst = getParams();
        return lst.p || 1;
    }


    // 获取当前时间(?t=xxx)
    function getCurrTime() {
        var lst = getParams();
        return lst.t || 0;
    }
})();