// ==UserScript==
// @name 🍀重庆医科大学|使用说明:http://doc.zhanyc.cn/pages/cqykdx/
// @namespace free
// @version 1.1
// @description 当前是免费版本,只包含了列表自动打开、解除视频播放限制功能。如需自动下一集、自动换课程、全自动无人值守等高级功能可升级付费版本|接各类脚本开发、代挂任务,微信:zhanyc_cn 个人网站:http://doc.zhanyc.cn
// @include *://*cqmu.edu.cn*
// @include *://*.cqmu.edu.cn/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant window.close
// @run-at document-end
// @require http://libs.baidu.com/jquery/2.0.0/jquery.min.js
// @antifeature payment
// @license Creative Commons
// ==/UserScript==
(function () {
let $jq = $;
unsafeWindow.$jq = $;
let docUrl = "http://doc.zhanyc.cn/pages/cqykdx/";
let isDev = false;
let xyb = {
pageData: {
videoTimer: null,
videoCheckTimer: null,
waitIndexArr: [],
},
// 悬浮引流面板
showFloatingPanel() {
if ($(".xyb-float-panel").length > 0) return;
let panelHtml = `
🍀 重庆医科大学脚本
脚本准备就绪
🔥 一次付费 · 永久使用 · 免费维护
如需使用全功能版本,请通过地址安装付费版本购买授权后可使用
✅ 5倍速
✅ 自动下一集
✅ 自动换课程
✅ 全自动无人值守
✅ 永久授权
接各类脚本开发、代挂、网站小程序开发工作
微信:zhanyc_cn
`;
$("body").append(panelHtml);
$(".xyb-panel-close").on("click", function () {
$(".xyb-float-panel").remove();
});
},
updateStatus(msg) {
let $panel = $(".xyb-float-panel");
if ($panel.length > 0) {
$panel.find(".xyb-panel-status").text(msg);
}
},
// 初始化
async init() {
console.log("%c xyb init", "background:rgb(0,0,0);color:#fff");
xyb.showFloatingPanel();
await xyb.waitUntil(() => $("body").length > 0);
xyb.routeByUrl(location.href);
// URL变更检测
let lastUrl = location.href;
setInterval(() => {
if (lastUrl != location.href) {
lastUrl = location.href;
// 清理定时器
if (xyb.pageData.videoTimer) {
clearInterval(xyb.pageData.videoTimer);
xyb.pageData.videoTimer = null;
}
if (xyb.pageData.videoCheckTimer) {
clearTimeout(xyb.pageData.videoCheckTimer);
xyb.pageData.videoCheckTimer = null;
}
xyb.pageData.waitIndexArr.forEach(idx => clearInterval(idx));
xyb.pageData.waitIndexArr = [];
xyb.routeByUrl(location.href);
}
}, 500);
},
// 路由
async routeByUrl(url) {
url = url.toLowerCase();
if (url.includes("/courseadult")) {
xyb.page_list();
} else if (url.includes("/studynotes")) {
xyb.page_video();
}
},
// 列表页面 - 自动打开未完成课程
async page_list() {
console.log("%c page_list", "background:rgb(0,0,0);color:#fff");
xyb.updateStatus("正在加载课程列表...");
await xyb.waitUntil(() => $(".course-list .item:visible").length > 0);
await xyb.sleep(1000);
let $el = null;
$(".course-list .item:visible").each((i, el) => {
let jd = Number($(el).find(`[role="progressbar"]`).attr('aria-valuenow'));
if (jd < 100) {
$el = $(el);
return false;
}
});
if ($el == null) {
xyb.updateStatus("所有课程已完成");
return;
}
xyb.updateStatus("正在打开课程...");
await xyb.sleep(3000);
$el.find('.itemButton button').click();
},
// 视频页面 - 解除播放限制
async page_video() {
console.log("%c page_video", "background:rgb(0,0,0);color:#fff");
if (xyb.pageData.videoTimer != null) return;
let lastTime = null;
let stuckCount = 0;
xyb.updateStatus("视频播放功能已启动");
// 卡住检测
xyb.pageData.videoCheckTimer = setTimeout(async () => {
let t = xyb.getCurTime();
await xyb.sleep(5000);
if (xyb.getCurTime() == t) {
xyb.updateStatus("视频卡住,正在刷新页面...");
location.reload();
}
}, 60 * 1000);
// 主循环
xyb.pageData.videoTimer = setInterval(async () => {
try {
if (!xyb.getVideo()) return;
// 点击大播放按钮
if ($(".vjs-big-play-button:visible").length > 0) {
$(".vjs-big-play-button:visible").click();
return;
}
// 解除播放限制 - 自动播放
let isPlaying = await xyb.checkIsPlaying();
if (!isPlaying) {
xyb.playVideo();
xyb.updateStatus("▶ 正在播放视频...");
}
xyb.getVideo().volume = 0;
let curTime = xyb.getCurTime();
let totalTime = xyb.getTotalTime();
// 卡住检测
if (curTime == lastTime) {
stuckCount += 2;
if (stuckCount >= 60) {
xyb.updateStatus("视频卡住,正在刷新...");
location.reload();
return;
}
} else {
stuckCount = 0;
lastTime = curTime;
}
// 更新进度显示
let progress = totalTime > 0 ? (curTime / totalTime * 100).toFixed(1) : 0;
let curStr = xyb.formatTime(curTime);
let totalStr = xyb.formatTime(totalTime);
xyb.updateStatus(`▶ 视频播放中 ${progress}% [${curStr}/${totalStr}]`);
// 标题显示进度
$("title").text(`进度:${curTime.toFixed(0)}/${totalTime.toFixed(0)}`);
// 检测播放完成
if (totalTime > 0 && curTime + 5 >= totalTime) {
xyb.updateStatus("视频即将结束,准备下一个...");
clearInterval(xyb.pageData.videoTimer);
xyb.pageData.videoTimer = null;
xyb.goNextVideo();
}
} catch (e) {
console.error("视频页面定时器出错", e);
}
}, 2000);
},
// 播放完成后点击下一个
goNextVideo() {
setTimeout(() => {
$(".opera.fr").click();
}, 10000);
},
// 获取视频元素
getVideo() {
return $("video")[0];
},
// 播放视频
playVideo() {
let video = xyb.getVideo();
if (video) {
video.volume = 0;
setTimeout(() => {
xyb.getVideo().play();
}, 200);
}
},
// 检测视频是否在播放
checkIsPlaying() {
return new Promise((resolve) => {
try {
let curTime = xyb.getCurTime();
setTimeout(() => {
let time1 = xyb.getCurTime();
if (time1 > curTime) {
setTimeout(() => {
let time2 = xyb.getCurTime();
resolve(time2 > time1);
}, 100);
} else {
resolve(false);
}
}, 100);
} catch (e) {
resolve(false);
}
});
},
// 获取当前播放时间(硬编码)
getCurTime() {
try {
return xyb.getVideo().currentTime;
} catch (e) {
return 0;
}
},
// 获取总时长(硬编码)
getTotalTime() {
try {
return xyb.getVideo().duration;
} catch (e) {
return 0;
}
},
// 格式化时间为 HH:MM:SS
formatTime(seconds) {
seconds = Math.floor(Math.abs(seconds));
let hours = Math.floor(seconds / 3600);
let minutes = Math.floor((seconds % 3600) / 60);
let secs = seconds % 60;
hours = (hours < 10) ? "0" + hours : hours;
minutes = (minutes < 10) ? "0" + minutes : minutes;
secs = (secs < 10) ? "0" + secs : secs;
return hours + ":" + minutes + ":" + secs;
},
// 等待条件满足
waitUntil(fun, interval = 1000, timeout = 60) {
return new Promise((resolve, reject) => {
let _timeOut = timeout * 1000;
try {
if (fun()) return resolve();
} catch (e) { }
let index = setInterval(() => {
try {
if (timeout != -1) {
_timeOut -= interval;
if (_timeOut < 0) {
clearInterval(index);
return reject();
}
}
if (fun()) {
clearInterval(index);
return resolve();
}
} catch (e) { }
}, interval);
xyb.pageData.waitIndexArr.push(index);
});
},
// 延时
sleep(timeout) {
return new Promise((resolve) => {
setTimeout(resolve, timeout);
});
},
};
// 3秒后初始化,检测付费版本是否在运行
setTimeout(() => {
if (typeof (zfk) == 'undefined') {
xyb.init();
} else {
console.log('skip init');
}
}, 3000);
})();