// ==UserScript==
// @name 广州华立科技职业学院课程助手
// @namespace http://tampermonkey.net/
// @version 2024-04-13
// @description 广州华立科技职业学院挂机课程,适用于https://gzhlxy.sccchina.net/
// @author ZaneBill
// @match https://gzhlxy.sccchina.net/student/
// @icon https://www.google.com/s2/favicons?sz=64&domain=sccchina.net
// @require https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.2.1/jquery.min.js
// @require http://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js
// @grant none
// @license AGPL License
// @downloadURL https://update.greasyfork.icu/scripts/492491/%E5%B9%BF%E5%B7%9E%E5%8D%8E%E7%AB%8B%E7%A7%91%E6%8A%80%E8%81%8C%E4%B8%9A%E5%AD%A6%E9%99%A2%E8%AF%BE%E7%A8%8B%E5%8A%A9%E6%89%8B.user.js
// @updateURL https://update.greasyfork.icu/scripts/492491/%E5%B9%BF%E5%B7%9E%E5%8D%8E%E7%AB%8B%E7%A7%91%E6%8A%80%E8%81%8C%E4%B8%9A%E5%AD%A6%E9%99%A2%E8%AF%BE%E7%A8%8B%E5%8A%A9%E6%89%8B.meta.js
// ==/UserScript==
(function() {
'use strict';
$(document).ready(function(){
// 定义全局变量
let UPDATE_COURSE_GAP = 60 // 多久上传一次进度 秒
let UPDATE_PROGRESS_GAP = UPDATE_COURSE_GAP + 2 // 多久更新一次列表进度 秒
let STUDY_DURATION = 6 // 每次观看进度 官方是30 setInterval间隔一分钟
let courseList = []
let timerMap = new Map()
// 分割已观看/总时长分钟数
function splitPlayTime(str){
const arr = str.split(' / ')
return {
finished: arr[0],
total: arr[1]
}
}
// 根据我的课程列表 创建脚本界面
function makeLayout(list = courseList){
let operateBox = "
"
$('body').append(operateBox)
let head = ""
let inputBox1 = `列表更新频率(秒)
`
let inputBox2 = `课程提交频率(秒)
`
let inputBox3 = `课程提交跨度
`
let inputBox = `${inputBox1}${inputBox2}${inputBox3}
`
$('.operateBox .table').before(inputBox)
$('.operateBox .table').before(head)
$('#tip1').text(`每隔${UPDATE_PROGRESS_GAP}秒自动更新列表,每隔${UPDATE_COURSE_GAP}秒提交课程,跨度为${STUDY_DURATION}秒`)
let content = list.reduce((pre, item, index)=> {
let tr = `${index + 1} | ${item.courseName} | ${item.coursewareLearningProgress} | ${splitPlayTime(item.realCoursewarePlayTime).finished} | ` +
`${splitPlayTime(item.realCoursewarePlayTime).total} | | |
`;
return pre += tr
}, '序号 | 课程名 | 完成度 | 已完成分钟数 | 总分钟数 | 新分钟数 | 新完成度 |
')
$('.operateBox .table tbody').append(content)
// 去掉操作栏的单个开刷按钮 用一键开刷 操作 | 开刷 |
$('.operateBox').css({
'position': 'fixed',
'bottom': '50px',
'right': '30px',
'background': '#eee',
'border-radius': '4px',
'padding': '5px'
})
$('.operateBox .inputBox').css({
'display': 'flex',
'justify-content': 'space-between',
'padding': '10px 0'
})
$('.operateBox .inputBox input').css({
'width': '100px',
})
$('.operateBox .head').css({
'display':'flex',
'justify-content': 'space-between',
'align-items': 'center'
})
$('#oneKeyStart').css({
'cursor': 'pointer',
})
$('table').css({
'border-collapse':'collapse'
})
$('td,th').css({
'padding':'0 5px'
})
$('table,th,td ').css({
'border': '1px solid black',
})
$('#oneKeyStart,.opt_btn').css({
'cursor': 'pointer',
'color': '#1890ff'
})
$('.newMinute,.newPercent').css({
'min-width': '30px',
})
}
// 获取我的课程进度
function getList(){
return new Promise((resolve, reject)=> {
try{
$.ajax({
url: '/student/student/coursestudy/getlist',
type: 'POST',
dataType: 'json',
contentType: "application/json",
processData: false,
data: JSON.stringify({
data:""
}),
success: function(response) {
if(response.items){
courseList = response.items
resolve(response.items)
}
},
error: function(xhr, status, error) {
reject(error)
},
});
}catch (error){
reject(error)
}
})
}
// 获取token
function getCourseToken(item){
return new Promise((resolve, reject)=> {
try{
const { courseVersionID, sign, teachplanCourseVersionId } = item
$.ajax({
url: '/student/common/common/getcoursewareaddress',
type: 'POST',
dataType: 'json',
contentType: "application/json",
processData: false,
data: JSON.stringify({
data:{
courseVersionId: courseVersionID,
sign,
teachplanCourseVersionId,
roleType: "1"
}
}),
success: function(response) {
if(response.code === 1){
resolve(response.data.token)
}
},
error: function(xhr, status, error) {
reject(error)
},
});
}catch(error){
reject(error)
}
})
}
// 增加时长
function addDurationFn(data = {}){
const {
courseVersionId,
studyDuration,
token
} = data
return new Promise((resolve, reject)=> {
try{
$.ajax({
url: '/student/student/coursestudyrecord/adddurationpc',
type: 'POST',
dataType: 'json',
contentType: "application/json",
processData: false,
data: JSON.stringify({
data:{
courseVersionId,
studyDuration,
token
}
}),
success: function(response) {
if(response.code === 1){
resolve('success')
}
},
error: function(xhr, status, error) {
reject(error)
},
});
}catch (error){
reject(error)
}
})
}
// 主要逻辑 循环发送请求更新课程观看进度
async function updateCourse(curItem){
const token = await getCourseToken(curItem)
const data = {
courseVersionId:curItem.courseVersionID,
studyDuration: STUDY_DURATION,
token
}
let timer = setInterval(async ()=> {
await addDurationFn(data)
}, UPDATE_COURSE_GAP * 1000)
timerMap.set(timer, curItem.courseName)
}
// 更新页面展示的进度
async function updateTable(){
let timer = setInterval(async ()=> {
const list = await getList()
// 新完成度 百分比
$('.operateBox .table .newPercent').text(function(index, currentText) {
const item = list[index]
const beforeText = `${item.coursewareLearningProgress}`
if(currentText && beforeText != currentText){
// 增加对比样式
const node = $('.operateBox .table .newPercent')[index]
$(node).css({
'background-color': 'gold'
})
}
return beforeText || currentText;
});
// 新分钟数
$('.operateBox .table .newMinute').text(function(index, currentText) {
const item = list[index]
const beforeText = `${splitPlayTime(item.realCoursewarePlayTime).finished}`
if(currentText && beforeText != currentText){
// 增加对比样式
const node = $('.operateBox .table .newMinute')[index]
$(node).css({
'background-color': 'green'
})
}
return beforeText || currentText;
});
}, UPDATE_PROGRESS_GAP * 1000)
timerMap.set(timer, new Date())
}
// 事件监听
function addListening(){
$('.operateBox .opt_btn').on("click", async function(e){
const index = e.target.dataset.index
const curItem = courseList[index]
await updateCourse(curItem)
updateTable()
});
$('.operateBox .inputBox input').on("input", async function(e){
const value = +e.target.value
const name = e.target.dataset.name
switch (name) {
case 'list':
UPDATE_PROGRESS_GAP = value || UPDATE_PROGRESS_GAP
break;
case 'course':
UPDATE_COURSE_GAP = value || UPDATE_COURSE_GAP
break;
case 'step':
STUDY_DURATION = value || STUDY_DURATION
break;
default:
break;
}
});
$('#oneKeyStart').on("click",function(){
timerMap.forEach((item,key) => {
clearInterval(key)
})
timerMap = new Map()
onFastStart()
})
}
// 一键开刷
function onFastStart(){
// 开刷前清空定时器
timerMap.forEach((item,key) => {
clearInterval(key)
})
timerMap = new Map()
let taskNum = 0
for(const item of courseList){
// 未完成的才启动
const progress = item.coursewareLearningProgress.slice(0, -1)
if(progress < 100){
taskNum++
updateCourse(item)
}
}
updateTable()
$('#tip1').text(`每隔${UPDATE_PROGRESS_GAP}秒自动更新列表,每隔${UPDATE_COURSE_GAP}秒提交课程,跨度为${STUDY_DURATION}秒`)
$('#tip2').text(`,已启动${taskNum}个任务,正在更新···`)
}
// 程序运行入口
async function main (){
await getList()
makeLayout()
addListening()
}
// 稍微等一下主页面渲染出来再加载脚本
setTimeout(()=>{
main()
},2000)
})
})();