百度网盘网课进度同步神器教程


百度网盘网课进度同步神器教程

百度网盘视频自动识别 + 坚果云跨设备同步(油猴脚本)

v10.0 更新:支持记录播放时间,按钮实时显示已观看时长,自动消失提示不打断操作


一、脚本介绍

这款油猴脚本专为公考网课学习打造,完美解决百度网盘看课的三大痛点:

  1. 多门网课来回切换,找不到上次看到哪一集
  2. 换电脑,学习进度全部丢失
  3. 手动记网址、存书签太麻烦,效率极低

v10.0 新功能

  • 自动识别当前播放的网盘视频属于哪门课程
  • 仅需1个保存按钮,一键同步进度到坚果云云端
  • 跳转按钮实时显示播放时长(如 花生资料分析(01:30)
  • 提示改为自动消失弹窗,不再打断视频播放
  • 修复拖动冲突:拖动面板时不会误触发按钮点击
  • 跨电脑、跨浏览器 100% 同步进度
  • 多课程进度独立存储,互不覆盖冲突
  • 基于坚果云 WebDAV 存储,安全稳定、无广告、不失效

适配课程:可无限添加,言语理解/判断推理/申论等任意网盘课程


二、前置准备

1. 安装脚本管理器

Tampermonkey(推荐)

脚本猫(国产浏览器友好)

官网安装指引:https://docs.scriptcat.org

2. 开启坚果云 WebDAV(用于云端同步)

  1. 打开坚果云官网并登录:https://www.jianguoyun.com/
  2. 进入「账号信息」→「安全选项」
  3. 找到 WebDAV 密码,点击「添加应用密码」
  4. 记录3项信息:
    • WebDAV 地址:https://dav.jianguoyun.com/dav/
    • 坚果云登录账号(手机号/邮箱)
    • 刚生成的应用密码(不是登录密码)

三、脚本安装步骤

  1. 点击浏览器右上角 🐵 油猴图标
  2. 选择「添加新脚本」
  3. 全选删除默认的空白模板代码
  4. 复制下方完整脚本代码,粘贴进去
  5. 点击「文件」→「保存」(或 Ctrl+S)
  6. 关闭编辑页面,安装完成
// ==UserScript==
// @name         公考网课进度同步
// @namespace    http://tampermonkey.net/
// @version      10.0
// @description  保存视频进度,按钮显示时分,自动消失提示,修复拖动冲突,坚果云同步
// @author       豆包
// @match        *://pan.baidu.com/pfile/video*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @grant        GM_log
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // ==================== 课程配置 ====================
    const COURSES = [
        {
            name: "花生资料分析",
            pathFlag: "/2026%E4%B8%8A%E5%B2%B8/%E8%B5%84%E6%96%99%E5%88%86%E6%9E%90/",
            saveFile: "progress_huasheng.txt"
        },
        {
            name: "高照数量关系",
            pathFlag: "/2026%E4%B8%8A%E5%B2%B8/2025%E5%B9%B4%E9%AB%98%E7%85%A7%E8%B5%84%E6%96%99%E9%A2%98%E5%9E%8B%E5%A4%B8%E5%A4%B8%E5%88%B7%E5%88%B7%E9%A2%98%E8%90%A5/",
            saveFile: "progress_gaozhao.txt"
        }
    ];

    // ==================== 坚果云配置 ====================
    const WEBDAV_ROOT = "https://dav.jianguoyun.com/dav/";
    const ACCOUNT = "替换为你的@qq.com";
    const AUTH_TOKEN = "替换为你的";
    const SAVE_DIR = "tampermonkey_sync/";
    const auth = btoa(unescape(encodeURIComponent(ACCOUNT + ":" + AUTH_TOKEN)));

    // ==================== 秒数 → 仅显示 时:分 ====================
    function formatTime(seconds) {
        const totalMin = Math.round(seconds / 60);
        const h = Math.floor(totalMin / 60);
        const m = totalMin % 60;
        return `${h.toString().padStart(2,'0')}:${m.toString().padStart(2,'0')}`;
    }

    // ==================== 获取当前视频播放秒数 ====================
    function getVideoTime() {
        const videos = document.querySelectorAll('video');
        return videos.length ? (videos[0].currentTime || 0) : 0;
    }

    // ==================== 识别当前课程 ====================
    function getCurrentCourse() {
        const url = location.href;
        return COURSES.find(c => url.includes(c.pathFlag)) || null;
    }

    // ==================== 确保目录 ====================
    async function ensureDir() {
        return new Promise(resolve => {
            GM_xmlhttpRequest({
                method: "MKCOL",
                url: WEBDAV_ROOT + SAVE_DIR,
                headers: { Authorization: "Basic " + auth },
                onload: () => resolve(true),
                onerror: () => resolve(true)
            });
        });
    }

    // ==================== 自动消失提示框(替代alert) ====================
    function toast(msg) {
        const old = document.getElementById('syncToast');
        if (old) old.remove();

        const div = document.createElement('div');
        div.id = 'syncToast';
        div.textContent = msg;
        document.body.appendChild(div);

        setTimeout(() => div.style.opacity = '0', 2000);
        setTimeout(() => div.remove(), 2500);
    }

    // ==================== 保存进度(含播放时间) ====================
    async function saveProgress() {
        const course = getCurrentCourse();
        if (!course) return toast("⚠️ 不属于配置课程");
        await ensureDir();
        const videoUrl = location.href;
        const currentSec = getVideoTime();
        const saveData = `${videoUrl}|${currentSec}`;

        GM_xmlhttpRequest({
            method: "PUT",
            url: WEBDAV_ROOT + SAVE_DIR + course.saveFile,
            headers: { Authorization: "Basic " + auth, "Content-Type": "text/plain" },
            data: saveData,
            onload: resp => {
                if (resp.status >= 200 && resp.status < 300) {
                    toast(`✅ 已保存\n${course.name} ${formatTime(currentSec)}`);
                    loadAllCourseProgress();
                } else toast(`❌ 保存失败 ${resp.status}`);
            },
            onerror: () => toast("⚠️ 网络异常")
        });
    }

    // ==================== 打开课程链接 ====================
    function openCourse(course) {
        GM_xmlhttpRequest({
            method: "GET",
            url: WEBDAV_ROOT + SAVE_DIR + course.saveFile,
            headers: { Authorization: "Basic " + auth },
            onload: r => {
                if (r.status === 200 && r.responseText.trim()) {
                    const [url] = r.responseText.trim().split('|');
                    window.open(url, '_blank');
                    toast(`✅ 正在打开 ${course.name}`);
                } else toast(`🆘 ${course.name} 无进度记录`);
            }
        });
    }

    // ==================== 加载进度显示到按钮 ====================
    function loadAllCourseProgress() {
        COURSES.forEach((course, idx) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: WEBDAV_ROOT + SAVE_DIR + course.saveFile,
                headers: { Authorization: "Basic " + auth },
                onload: r => {
                    let timeText = "未记录";
                    if (r.status === 200 && r.responseText.trim()) {
                        const [, sec] = r.responseText.trim().split('|');
                        timeText = formatTime(parseFloat(sec) || 0);
                    }
                    const btn = document.querySelector(`.jumpBtn[data-index="${idx}"]`);
                    if (btn) btn.innerText = `${course.name}(${timeText})`;
                }
            });
        });
    }

    // ==================== 全局样式 ====================
    GM_addStyle(`
        #studyPanel { position: fixed; z-index: 999999; width: 240px; background: #fff;
            border-radius: 8px; box-shadow: 0 3px 10px rgba(0,0,0,.1); padding: 10px;
            font-size: 14px; user-select: none; cursor: grab; top: 20px; right: 20px; }
        #studyPanel:active { cursor: grabbing; }
        #saveBtn { width: 100%; height: 40px; border: none; border-radius: 6px;
            background: #007BFF; color: #fff; font-size: 15px; cursor: pointer; margin-bottom: 10px; }
        #saveBtn:hover { background: #0056b3; }
        .jumpBtn { width: 100%; height: 38px; border: none; border-radius: 4px;
            background: #f5f5f5; color: #333; cursor: pointer; margin: 4px 0;
            padding: 0 10px; text-align: left; }
        .jumpBtn:hover { background: #e6f7ff; color: #007BFF; }
        #syncToast { position: fixed; z-index: 9999999; bottom: 30px; left: 50%;
            transform: translateX(-50%); background: #333; color: #fff; padding: 10px 20px;
            border-radius: 6px; font-size: 14px; opacity: 1;
            transition: opacity 0.5s ease; white-space: pre-line; }
    `);

    // ==================== 面板 ====================
    const panel = document.createElement('div');
    panel.id = 'studyPanel';
    let html = `<button id="saveBtn">📌 保存当前播放进度</button>`;
    html += `<div style="margin:6px 0;font-weight:bold;color:#666">上次进度(hh:mm)</div>`;
    COURSES.forEach((_, i) => {
        html += `<button class="jumpBtn" data-index="${i}">加载中...</button>`;
    });
    panel.innerHTML = html;
    document.body.appendChild(panel);

    // ==================== 修复拖动逻辑(仅空白处可拖动) ====================
    function makeDraggable(element) {
        let isDragging = false;
        let offsetX, offsetY;

        element.addEventListener('mousedown', (e) => {
            if (e.target.tagName === 'BUTTON') return;
            isDragging = true;
            offsetX = e.clientX - element.getBoundingClientRect().left;
            offsetY = e.clientY - element.getBoundingClientRect().top;
            element.style.cursor = 'grabbing';
            e.preventDefault();
        });

        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            element.style.left = e.clientX - offsetX + 'px';
            element.style.top = e.clientY - offsetY + 'px';
            element.style.right = 'auto';
        });

        document.addEventListener('mouseup', () => {
            if (isDragging) {
                isDragging = false;
                element.style.cursor = 'grab';
            }
        });
    }
    makeDraggable(panel);

    // ==================== 按钮事件 ====================
    document.getElementById('saveBtn').onclick = saveProgress;
    document.querySelectorAll('.jumpBtn').forEach(btn => {
        btn.onclick = (e) => {
            e.stopPropagation();
            openCourse(COURSES[btn.dataset.index]);
        };
    });

    loadAllCourseProgress();
    GM_log("进度同步脚本 完美版加载完成");
})();

四、v10.0 升级说明

相比 v7.0,主要变化:

功能 v7.0 v10.0
保存内容 仅视频链接 视频链接 + 播放秒数
按钮显示 课程名称 课程名称 + 已观看时长
提示方式 alert() 弹窗(打断播放) toast() 自动消失(不打断)
拖动冲突 可能误触发按钮 仅空白处可拖动
按钮初始状态 直接显示课程名 显示"加载中..."

五、基础使用教程

1. 打开网盘视频

在浏览器中打开百度网盘的视频播放页: https://pan.baidu.com/pfile/video?path=/2026省考/花生资料分析/xxx.mp4

2. 识别当前课程

脚本会自动识别当前视频属于哪门课程,面板右上角显示实时已观看时长。

3. 保存学习进度

点击右侧面板: 📌 保存当前播放进度 底部弹出自动消失提示,显示 ✅ 已保存 花生资料分析 01:30

4. 跳转到最新进度

直接点击对应课程名称按钮,按钮上会显示上次保存时记录的总时长。

5. 跨设备使用

在另一台电脑/浏览器安装油猴 + 本脚本,点击课程名即可同步进度,无需任何额外设置。


六、自定义修改教程

1. 修改坚果云账号(替换为自己的)

找到代码中这一段,替换为你的坚果云账号和 WebDAV 应用密码:

const WEBDAV_ROOT = "https://dav.jianguoyun.com/dav/";
const ACCOUNT = "替换为你的@qq.com";
const AUTH_TOKEN = "替换为你的";

修改后保存,即可使用自己的坚果云存储。

2. 添加新一门网课(无限扩展)

COURSES 数组中追加对象:

{
    name: "课程名称",
    pathFlag: "网盘链接路径前缀",
    saveFile: "progress_自定义文件名.txt"
}

如何获取 pathFlag(关键)

  1. 打开该课程任意几集视频
  2. 复制地址栏中 path= 之后、.mp4 之前的公共前缀
  3. 示例:/2026%E4%B8%8A%E5%B2%B8/xxx课程/

添加完成后,刷新页面,面板会自动新增该课程的跳转按钮。

3. 修改界面样式

找到代码中的 GM_addStyle 部分,可以自定义:

  • 面板宽度:width: 240px
  • 按钮颜色:background: #007BFF
  • 面板位置:right: 20px; top: 20px

七、常见问题排查

1. 保存失败 404 / 409

  • 原因:坚果云目录未创建成功
  • 解决:脚本已内置 MKCOL 自动创建目录,重新点击保存即可
  • 检查:WebDAV 账号密码是否正确

2. 提示「不属于已配置的课程」

  • 原因:pathFlag 路径前缀填写错误
  • 解决:重新复制网盘链接中的编码路径,确保完全匹配

3. 跳转提示「无进度记录」

  • 原因:该课程从未保存过进度
  • 解决:先打开对应课程视频,点击「保存进度」后再跳转

4. 油猴不显示面板

  • 原因:仅在 pan.baidu.com/pfile/video 播放页生效
  • 解决:必须打开视频播放页面,而非文件列表页

5. 跨设备不同步

  • 原因:两台设备使用的不是同一个坚果云账号
  • 解决:确认所有设备脚本中的 ACCOUNT、AUTH_TOKEN 完全一致

6. 按钮一直显示"加载中..."

  • 原因:坚果云账号密码错误,无法读取云端文件
  • 解决:检查 ACCOUNT 和 AUTH_TOKEN 是否填写正确

八、让AI把本文代码修改为适合自己的方式

请把本文全部复制后给到AI。

提示词:请你学习后,把代码改为适合我的。我可以提供你几个我在学习的网课视频链接,你分析下。

  • 链接1
  • 链接2
  • 链接3 .......

文章作者: 摸鱼
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 摸鱼 !
  目录