diff --git a/qingshuxuetang_auto_play.user.js b/qingshuxuetang_auto_play.user.js index 30b9220..9c69db1 100644 --- a/qingshuxuetang_auto_play.user.js +++ b/qingshuxuetang_auto_play.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name 平顶山学院(青书学堂)自动学习脚本 // @namespace http://tampermonkey.net/ -// @version 2026-06-05.5 +// @version 2026-06-05.7 // @description 自动进入青书学堂未完成课件,支持视频播放、文本课件停留和运行状态提示 // @author JK // @license MIT @@ -40,10 +40,10 @@ // 视频默认播放倍速;想改成 1.5 倍、3 倍可以从 Tampermonkey 菜单配置。 videoPlaybackRate: 2, - // toast 默认显示时长,单位毫秒;4000 表示 4 秒后自动隐藏。 + // 提示消息默认显示时长,单位毫秒;4000 表示 4 秒后自动隐藏。 toastDefaultDuration: 4000, - // 运行心跳提示间隔,单位秒;视频播放中、文本课件等待中都会按这个间隔提醒。 + // 运行提醒间隔,单位秒;视频播放中、文本课件等待中都会按这个间隔提醒。 heartbeatSeconds: 10, // 课程列表最多等待多少秒;超过后认为可能请求失败,触发刷新。 @@ -60,7 +60,7 @@ ...GM_getValue(CONFIG_STORAGE_KEY, {}), }; - // toast 容器和样式标签的 id,通常不用改,除非和页面元素冲突。 + // 提示消息容器和样式标签的 id,通常不用改,除非和页面元素冲突。 const TOAST_CONTAINER_ID = "qingshu-auto-toast-container"; const TOAST_STYLE_ID = "qingshu-auto-toast-style"; @@ -71,8 +71,8 @@ location.pathname + location.search; - // 创建右下角 toast 容器和样式。 - // 每次通知都会创建一个新的 toast,所以多个通知会一起堆叠显示。 + // 创建右下角提示消息容器和样式。 + // 每次通知都会创建一个新的提示消息,所以多个通知会一起堆叠显示。 const ensureToastContainer = () => { let container = document.querySelector("#" + TOAST_CONTAINER_ID); @@ -141,7 +141,7 @@ return container; }; - // 显示一条 toast,同时保留 console 输出。 + // 显示一条提示消息,同时保留 console 输出。 // type 可用 info、success、warning、error;duration 是自动隐藏时间。 const notify = ( message, @@ -175,7 +175,7 @@ const saveConfig = (patch) => { Object.assign(CONFIG, patch); GM_setValue(CONFIG_STORAGE_KEY, CONFIG); - notify("配置已保存,刷新页面后完全生效", "success", 6000); + notify("设置已保存,刷新页面后生效", "success", 6000); }; const promptNumberConfig = (label, key, unit, currentValue, toStoredValue) => { @@ -188,7 +188,7 @@ const value = Number(input); if (!Number.isFinite(value) || value <= 0) { - notify("配置失败:请输入大于0的数字", "error", 6000); + notify("设置失败:请输入大于0的数字", "error", 6000); return; } @@ -209,9 +209,9 @@ ); }); - GM_registerMenuCommand("设置最小学习时间", () => { + GM_registerMenuCommand("设置课件最小学习时间", () => { promptNumberConfig( - "设置最小学习时间", + "设置课件最小学习时间", "minStudySeconds", "分钟", CONFIG.minStudySeconds / 60, @@ -219,9 +219,9 @@ ); }); - GM_registerMenuCommand("设置心跳提示间隔", () => { + GM_registerMenuCommand("设置运行提醒间隔", () => { promptNumberConfig( - "设置心跳提示间隔", + "设置运行提醒间隔", "heartbeatSeconds", "秒", CONFIG.heartbeatSeconds @@ -237,9 +237,9 @@ ); }); - GM_registerMenuCommand("设置课程列表最大刷新次数", () => { + GM_registerMenuCommand("设置课程列表自动刷新次数", () => { promptNumberConfig( - "设置课程列表最大刷新次数", + "设置课程列表自动刷新次数", "maxCourseListRefreshCount", "次", CONFIG.maxCourseListRefreshCount, @@ -247,9 +247,9 @@ ); }); - GM_registerMenuCommand("设置 toast 显示时长", () => { + GM_registerMenuCommand("设置提示消息显示时间", () => { promptNumberConfig( - "设置 toast 显示时长", + "设置提示消息显示时间", "toastDefaultDuration", "秒", CONFIG.toastDefaultDuration / 1000, @@ -257,15 +257,15 @@ ); }); - GM_registerMenuCommand("重置脚本配置", () => { + GM_registerMenuCommand("恢复默认设置", () => { GM_deleteValue(CONFIG_STORAGE_KEY); Object.assign(CONFIG, DEFAULT_CONFIG); - notify("配置已重置,刷新页面后完全生效", "success", 6000); + notify("设置已重置,刷新页面后生效", "success", 6000); }); }; registerConfigMenus(); - notify("插件加载完成,等待界面渲染", "info"); + notify("脚本已启动,等待页面内容加载", "info"); // 等待某个 DOM 条件成立。 // 页面里的课程列表、视频、文本课件经常是后加载的,所以不用固定延迟, @@ -398,7 +398,7 @@ document.querySelector(TEXT_SELECTOR) ); - // 把秒数格式化成“x分x秒”,用于心跳提示。 + // 把秒数格式化成“x分x秒”,用于运行提醒。 const formatSeconds = (seconds) => { if (!Number.isFinite(seconds) || seconds < 0) { return "未知"; @@ -411,10 +411,10 @@ }; const onPageLoad = async () => { - notify("页面加载完成,开始执行脚本", "info"); + notify("页面加载完成,脚本开始运行", "info"); if (url.includes("CourseStudy")) { - notify("进入准备阶段,等待课程列表", "info"); + notify("进入课程列表页,等待课程列表加载", "info"); // 课程列表是异步渲染的,等到至少有一个课程节点后再开始遍历。 const items = await waitForCondition( @@ -434,7 +434,7 @@ clearCourseStudyRefreshCount(); - notify("获取到课程数量:" + items.length, "success"); + notify("已加载课程数量:" + items.length, "success"); // 从上到下找到第一个“没学过”或“学习不足配置时长”的课件并进入。 for (const item of items) { @@ -442,7 +442,7 @@ const mark = item.querySelector(".study_being"); const studiedSeconds = mark ? parseStudySeconds(mark.innerText) : 0; notify( - "点击未完成学习时长的视频:" + + "进入未完成学习时长的课件:" + item.querySelector(".title").innerText + ",已学习:" + studiedSeconds + @@ -454,9 +454,9 @@ return; } } - notify("所有视频均已播放完毕,结束脚本", "success", 6000); + notify("所有课件均已达到学习时长,脚本停止", "success", 6000); } else if (url.includes("CourseShow")) { - notify("进入学习阶段,等待课件加载", "info"); + notify("进入课件页面,等待课件加载", "info"); // 等到播放页真正渲染出视频或文本课件,再决定如何处理。 const coursewareElement = await waitForCoursewareElement(); @@ -464,9 +464,9 @@ // 文本课件没有 video 标签,不需要播放;停留到配置的学习时长后返回列表页。 if (coursewareElement.matches(TEXT_SELECTOR)) { notify( - "检测到文本课件,等待" + + "检测到文本课件,将停留" + formatSeconds(CONFIG.minStudySeconds) + - "后返回准备页面", + "后返回课程列表", "warning", 6000 ); @@ -478,13 +478,13 @@ if (studiedSeconds >= CONFIG.minStudySeconds) { clearInterval(textInterval); - notify("文本课件等待完成,返回准备页面", "success"); + notify("文本课件停留完成,返回课程列表", "success"); returnToStudyPage(); return; } notify( - "文本课件学习中,已等待:" + + "文本课件学习中,已停留:" + formatSeconds(studiedSeconds) + ",剩余:" + formatSeconds(CONFIG.minStudySeconds - studiedSeconds), @@ -509,7 +509,7 @@ // 有些播放器会重建 video 元素,短暂找不到时继续等下一轮。 if (!video) { if (!videoMissingNotified) { - notify("视频元素暂时不可用,继续等待", "warning"); + notify("正在等待视频加载", "warning"); videoMissingNotified = true; } return; @@ -518,12 +518,12 @@ if (video.paused && video.currentTime === 0) { video.play(); - notify("视频未播放,开始播放视频", "success"); + notify("视频已开始播放", "success"); return; } if (video.currentTime >= video.duration - 1) { - notify("视频播放结束,返回准备页面", "success"); + notify("视频播放结束,返回课程列表", "success"); clearInterval(videoInterval); returnToStudyPage(); }