更新脚本版本号至2026-06-05.7,优化提示消息文本和逻辑,提升用户体验
This commit is contained in:
parent
8ae3f92996
commit
d5100655ee
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue