// ==UserScript==
// @name 东鼎学院助手
// @namespace https://github.com/ShiroMaple
// @version 1.1
// @description 用于基于知学云平台的东鼎学院学习助手,专题和课程页面点击右侧边栏的自动播放按钮,可以实现无人值守挂课;在考试页面提供复制功能,但不能替你考试。
// @author ShiroMaple
// @license GPL
// @match https://izpje.zhixueyun.com/
// @icon https://zxy9.zhixueyun.com/default/M00/03/19/Ci7mTVx80puAedq_AAAN-JKULPE589.png.webp
// @grant unsafeWindow
// @grant window.close
// @require https://cdn.bootcss.com/jquery/3.6.1/jquery.min.js
// @downloadURL none
// ==/UserScript==
//参考了 SharonLee 提供的 知学云助手,非常感谢!
;(function () {
'use strict'
let $ = window.jQuery
/**
* 添加自动播放按钮
*/
function addAutoPlayButton(callback) {
// 自动播放按钮的 HTML 结构
let autoPlayButton = `
`
// 等待其他按钮加载完成之后,添加自动播放按钮
let timer = setInterval(function () {
// 判断是否存在 ul.list 元素,并且自动播放按钮还未添加
if ($('ul.list').find('li').length != 0 && $('ul.list #autoPlay').length == 0) {
console.log('🔄 添加自动播放按钮');
$('ul.list').append(autoPlayButton);
// 监听开始按钮点击事件
$('ul.list #autoPlay').click(callback);
clearInterval(timer);
}
}, 200);
}
/**
* 专题页面功能
*/
function subjectHelper() {
// 专题页面
if (location.hash.match('#/study/subject/detail/')) {
console.log('🔄匹配专题页面')
// 课程列表
let items = null
// 当前课程索引
let currentIdx = -1
let timer = null
let opener = unsafeWindow.opener
// 添加自动播放按钮
addAutoPlayButton(autoPlay)
// 如果是自动打开的,直接自动播放
if (opener && opener.isAutoPlay) {
autoPlay()
}
/**
* 自动播放
*/
function autoPlay() {
console.log('🔵开始自动播放')
unsafeWindow.document.title = '🔵开始自动播放'
unsafeWindow.isAutoPlay = true
items = $('.subject-catalog .item')
currentIdx = -1
playNextCourse()
checkCurrentCourse()
// 定时检查当前课程状态
if (timer) {
clearInterval(timer)
}
timer = setInterval(checkCurrentCourse, 5000)
}
/**
* 播放下一个课程
*/
function playNextCourse() {
currentIdx++
items = $('.subject-catalog .item')
let item = items.eq(currentIdx)
if (item.length < 1) {
return
}
let name = item.find('.name-des').text()
let status = item.find('.operation').text().trim()
// 已完成当前课程
if (status == '重新学习' || status.includes("考试")) {
// 全部课程完成
if (currentIdx == items.length - 1) {
console.log('✅已完成当前专题下的所有课程')
unsafeWindow.document.title = '✅已完成当前专题下的所有课程'
alert('✅已完成当前专题下的所有课程')
// 通知打开的页面
if (opener) {
opener.postMessage('autoPlayComplete')
}
}
// 播放下一个课程
else {
playNextCourse()
}
}
// 未完成当前课程
else {
console.log(`▶️[${currentIdx + 1}/${items.length}]开始播放【${name}】`)
item.click()
}
}
// 监听事件
unsafeWindow.addEventListener('message', function (e) {
if (e.data == 'autoPlayComplete') {
console.log('📢接收到课程完成通知,开始播放下一个课程')
playNextCourse()
}
if (e.data == 'resourceNotExist'){
console.log('📢课程资源不存在,跳过并开始播放下一个课程')
playNextCourse()
}
})
// 检查当前课程状态
function checkCurrentCourse() {
items = $('.subject-catalog .item')
// 课程可能未加载完毕
if (items.length < currentIdx + 1) {
return
}
let item = items.eq(currentIdx)
let name = item.find('.name-des').text()
let status = item.find('.operation').text().trim()
// 已经完成自动播放下一个课程
if (status == '重新学习' || status.includes("考试")) {
playNextCourse()
} else {
unsafeWindow.document.title = `🟢[${currentIdx + 1}/${items.length}]正在播放【${name}】`
console.log(`🟢[${currentIdx + 1}/${items.length}]正在播放【${name}】`)
}
}
}
}
/**
* 课程页面功能
*/
function courseHelper() {
if (location.hash.match('#/study/course/detail/')) {
console.log('🔄匹配课程页面')
let opener = unsafeWindow.opener
let timer = null
// 添加自动播放按钮
addAutoPlayButton(autoPlay)
// 专题自动播放进入,直接开始自动播放
if (opener && opener.isAutoPlay) {
autoPlay()
}
/**
* 自动播放
*/
function autoPlay() {
if (unsafeWindow.isAutoPlay) {
return
}
console.log('🔵开始自动播放')
unsafeWindow.document.title = '🔵开始自动播放'
unsafeWindow.isAutoPlay = true
playSection()
//针对东鼎学院的首次播放触发一次id为D200的元素的click方法
let initialPlay=document.querySelector('#D200registerMask')
if (initialPlay){initialPlay.click()}
//资源不存在
if (document.body.innerText.includes('该资源已不存在')) {
if (opener) {
opener.postMessage('resourceNotExist')
}
unsafeWindow.close()
}
//每5秒执行一次playSection
if (timer) {
clearInterval(timer)
}
timer = setInterval(playSection, 5000)
}
/**
* 播放章节
*/
function playSection() {
//已学课程
if (document.body.innerText.includes('是否继续学习')) {
console.log('继续学习')
document.querySelectorAll('[id$="goOnStudy"]')[0].click()
}
//获取chapter列表
let items = $('.section-arrow .chapter-list-box')
for (let idx = 0; idx < items.length; idx++) {
let item = items.eq(idx)
//章节名
let name = item.find('.chapter-item').children().eq(0).text().trim()
//章节状态 时长、需学时间
let status = item.find('.section-item .pointer').text().trim()
//章节类型 必修或选修 文档或视频
let type = item.find('.section-item .sub-text').text().trim()
let lock = item.find('.chapter-left .icon-suo')
// 已完成
if ('重新学习' == status || status.includes('考试') || type.includes('考试') || lock.length > 0 || !status.includes('需')) {
// 全部完成,通知父页面并关闭当前页面
if (idx == items.length - 1) {
if (opener) {
opener.postMessage('autoPlayComplete')
}
unsafeWindow.close()
}
}
// 未完成
else {
// 未播放则点击播放
let isFocus = item.hasClass('focus')
if (!isFocus) {
console.log(`▶️[${idx + 1}/${items.length}]开始播放【${name}】`)
item.click()
} else {
unsafeWindow.document.title = `🟢[${idx + 1}/${items.length}]正在播放【${name}】`
console.log(`🟢[${idx + 1}/${items.length}]正在播放【${name}】`)
}
break
}
}
//针对视频课件
let video = document.querySelector('video')
if (video){
// 自动禁音
if (!video.muted) {
console.log('已自动静音')
video.muted = true
}
// 自动续播
if (video.paused) {
// 如果出现挂机检测弹窗,模拟点击ID为'D215btn-ok'的按钮
if (document.body.innerText.includes('计时中')) {
document.getElementById('D215btn-ok').click();
console.log('⏸侦测到挂机检测,自动恢复播放')
}
//console.log('⏸视频被暂停,自动恢复播放')
//video.muted = true
//video.play()
}
}
//处理异常弹窗
let erobtn=document.querySelector('#D218close-btn')
if (erobtn) {erobtn.click()}
}
}
}
/**
* 已学课程页面
*/
function skipStudied(){
if (location.hash.match('#/study/transition-page/')) {
console.log('🔄匹配已学课程页面')
let timer = null
if (timer) {
clearInterval(timer)
}
timer = setInterval(autoClick, 5000)
}
function autoClick(){
//已学课程
if (document.body.innerText.includes('是否继续学习')) {
console.log('继续学习')
//document.querySelector('#D321goOnStudy').click()
document.querySelectorAll('[id$="goOnStudy"]')[0].click()
}
}
}
/**
* 活动页面功能
*/
function trainHelper() {
if (location.hash.match('#/train-new/class-detail')) {
// 添加自动播放按钮
addAutoPlayButton(playNextSection)
let sectionIdx = -1
let courseIdx = -1
function playNextSection() {
unsafeWindow.isAutoPlay = true
sectionIdx++
courseIdx = -1
let timerId = setInterval(function() {
let pointer = $('.course-box .section-title .right-area > .pointer').eq(sectionIdx)
if (pointer.hasClass('icon-triangle-down')) {
pointer.click()
} else {
if ($('.course-box .btn.load-more').length > 0) {
$('.course-box .btn.load-more').click()
} else {
clearInterval(timerId)
playNextCourse()
}
}
}, 200)
}
function playNextCourse() {
courseIdx++
if ($('.course-box .train-citem .row-title-a').length <= courseIdx) {
playNextSection()
} else {
if ($('.course-box .train-citem .ms-train-state').eq(courseIdx).text().trim()=='已完成') {
playNextCourse()
} else {
$('.course-box .train-citem .row-title-a').eq(courseIdx).click()
}
}
}
// 监听事件
unsafeWindow.addEventListener('message', function (e) {
if (e.data == 'autoPlayComplete') {
console.log('📢接收到课程完成通知,开始播放下一个课程')
playNextCourse()
}
})
}
}
/**
* 外部链接页面功能
*/
function externalUrlHelper() {
// 10 秒后自动关闭外部链接
if (location.href.match('https://cms.myctu.cn/safe/topic')) {
let opener = unsafeWindow.opener
unsafeWindow.document.title = '10秒后关闭此页面'
setTimeout(function () {
if (opener) {
opener.postMessage('autoPlayComplete')
unsafeWindow.close()
}
}, 10000)
}
}
/**
* 考试页面功能
*/
function examHelper() {
if (location.hash.match('#/exam/exam/answer-paper')) {
console.log('🔄匹配考试页面')
let allowSwitchAndCopyButton = `允许复制
`
// 添加允许切屏/复制按钮
let timer = setInterval(function () {
if ($('#D165submit').length > 0) {
$('#D165submit').parent().prepend(allowSwitchAndCopyButton)
$('#allowSwitchAndCopy').click(allowSwitchAndCopy)
clearInterval(timer)
}
}, 200)
let interval = null
/**
* 允许切屏和复制
*/
function allowSwitchAndCopy() {
// 允许切屏
allowSwitch()
if (interval) {
clearInterval(interval)
}
// 每 500 毫秒监控一次
interval = setInterval(function () {
// 允许复制
allowCopy()
}, 500)
alert('操作成功')
}
/**
* 允许切屏
*/
function allowSwitch() {
unsafeWindow.onblur = null
Object.defineProperty(unsafeWindow, 'onblur', {
set: function (xx) {
/* 忽略 */
}
})
}
/**
* 允许复制
*/
function allowCopy() {
let previewContent = document.querySelector('.preview-content')
previewContent.oncontextmenu = null
previewContent.oncopy = null
previewContent.oncut = null
previewContent.onpaste = null
}
}
}
/**
* pdf下载功能
*/
function pdfDownloadHelper() {
// 等待 PDF.js 加载完成
let interval = setInterval(function() {
if (typeof PDFJS !== 'undefined') {
console.log('PDFJS loaded');
// 停止定时检查
clearInterval(interval);
// 保存原始的 PDFViewer 构造函数
let OriginalPDFViewer = PDFJS.PDFViewer;
// 确认PDFJS被定义了
console.log('PDFJS内容:',PDFJS);
console.log('PDFJS.PDFViewer内容:',PDFJS.PDFViewer);
console.log('OriginalPDFViewer内容:',OriginalPDFViewer);
// 替换 PDFViewer 构造函数以进行拦截
PDFJS.PDFViewer = function(options) {
console.log('PDFViewer instance created');
// 创建 PDFViewer 实例
let instance = new OriginalPDFViewer(options);
unsafeWindow.pdfViewer = instance;
// 返回修改后的 PDFViewer 实例
return instance;
};
// 确认PDFViewer是否被替换了
console.log(PDFJS.PDFViewer === OriginalPDFViewer); // 应该返回false
}
}, 100); // 每隔100毫秒检查一次,可以根据需要调整时间间隔
// 设置超时计数器,最多轮询20秒钟
let timeoutCounter = 0;
let maxTimeout = 20000; // 20秒钟
let timeoutInterval = setInterval(function() {
let fullScreenDiv = $('.pull-right .icon-com-a-fullscreen1');
let downloadDiv = $('#MyDownload')
if (unsafeWindow.pdfViewer && fullScreenDiv.length && !downloadDiv.length) {
// 创建下载按钮
downloadDiv = $('');
// 附加点击事件回调
downloadDiv.click(function() {
pdfViewer.pdfDocument.getData().then((data) => {
const blob = new Blob([data], { type: 'application/pdf' });
const url = window.URL.createObjectURL(blob);
// 创建一个下载链接
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = $('.other-toolbar .other-title').text() || 'document.pdf'; // 设置文件名
document.body.appendChild(a);
// 触发点击事件以下载文件
a.click();
// 清理URL对象以释放内存
window.URL.revokeObjectURL(url);
});
});
// 在fullScreenDiv后面添加下载按钮
fullScreenDiv.after(downloadDiv);
}
timeoutCounter += 1;
if (timeoutCounter >= maxTimeout / 1000) {
// 超过20秒钟,停止轮询
clearInterval(interval);
clearInterval(timeoutInterval);
}
}, 1000); // 每隔1秒检查一次超时计数器
}
// 统一调用助手功能
subjectHelper()
trainHelper()
courseHelper()
//skipStudied()
//externalUrlHelper()
examHelper()
//pdfDownloadHelper()
})()