您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
国家开放大学自动刷课
当前为
// ==UserScript== // @name 国开自动刷课 // @namespace ry版 // @version 202305051250 // @description 国家开放大学自动刷课 // @author 流浪的蛊惑 // @match *://lms.ouchn.cn/course/* // @license GPL-3.0 // @grant none // ==/UserScript== function LogHelper() { const el_text = ` <container-element class="normal" style="left: 10px; top: 50px; font: 14px Menlo, Monaco, Consolas, 'Courier New', monospace;"> <style> /** 默认字体 */ /** 输入框默认边距 */ ul, ol { padding-left: 16px; margin: 0px; } a { color: #1890ff; } hr { border-style: solid; border-color: #63636346; border-width: 0px; border-bottom: 1px solid #63636346; margin-block-start: 1em; margin-block-end: 1em; } container-element.close { display: none; } container-element.minimize { min-width: unset; } container-element { position: fixed; top: 10%; left: 10%; z-index: 9999999999; text-align: left; min-width: 300px; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #636363; box-shadow: 0 0 24px -12px #3f3f3f; border-radius: 8px; } container-element .header { display: flex; align-items: center; background-color: white; border-radius: 8px 8px 0px 0px; user-select: none; padding: 4px; color: #000; line-height: normal; height: auto; position: static; } container-element .header .profile { flex: 1; cursor: move; } container-element .header .switch:hover, container-element .header .dropdown:hover { background-color: #f3f3f3; } container-element .header .close:hover { background-color: #ff000038; } container-element .header .switch, container-element .header .close { cursor: pointer; } container-element .header .dropdown { line-height: 24px; } container-element .header .switch, container-element .header .close, container-element .header .profile { display: inline-flex; align-items: center; padding: 0px 8px; } container-element .logo { width: 18px; height: 18px; cursor: pointer; } container-element .body { overflow: auto; width: auto; height: 100%; } script-panel-element { display: block; background-color: white; border-radius: 0px 0px 8px 8px; padding: 0px 8px 12px 8px; resize: vertical; overflow: auto; } script-panel-element .script-panel-body { padding: 0px 8px; } script-panel-element+script-panel-element { margin-top: 12px; } container-element .card+.card { margin-top: 12px; } container-element .card { background-color: white; border-radius: 2px; padding: 0px 8px; border: none; } container-element .separator { display: flex; align-items: center; text-align: center; padding-bottom: 4px; } container-element .separator::before, container-element .separator::after { content: ''; flex: 1; border-bottom: 1px solid #63636346; } container-element .console { max-height: 300px; max-width: 400px; overflow: auto; background-color: #292929; padding: 12px 6px; color: #ececec; font-size: 12px; } container-element .console .item { padding: 3px 0px; border-radius: 2px; } container-element .console .item .time { color: #757575; } container-element .console .item .info { background-color: #2196f3a3; } container-element .console .item .warn { background-color: #ffc107db; } container-element .console .item .error { background-color: #f36c71cc; } container-element .console .item .debug, container-element .console .item .log { background-color: #9e9e9ec4; } container-element .console *::selection { background-color: #ffffff6b; } /* 设置滚动条的样式 */ container-element ::-webkit-scrollbar { width: 10px; height: 10px; } /* 滚动槽 */ container-element ::-webkit-scrollbar-track { background: #ffffffd8; border-radius: 4px; margin: 4px; } /* 滚动条滑块 */ container-element ::-webkit-scrollbar-thumb { border-radius: 4px; background: rgba(0, 0, 0, 0.253); box-shadow: inset006pxrgba(0, 0, 0, 0.3); } .footer { text-align: center; } .footer a { text-decoration: none; } </style> <div class="message-container"></div><header-element class="header" data-title="菜单栏-可拖动区域"> <div class="profile" data-title="菜单栏(可拖动区域)">日志输出</div> </header-element> <div class="body" style="max-height: 294px; max-width: 1870px;"><script-panel-element> <div class="separator">📄 日志输出</div> <div class="notes card"></div> <div class="configs card"> <div class="configs-body"></div> </div> <div class="script-panel-body"> <div class="card console"> </div> </div> </script-panel-element></div> <div class="footer"> <a id="startTech" href="javascript:void(0);">点我开始</a> </div> </container-element> `; $('.wrapper').append(el_text); this.WriteHtmlLine = (htmlContent, alignCenter = false, border = { borderTop: false, borderBottom: false }) => { const el = document.createElement('div'); container = document.querySelector('container-element'); el.classList.add('item'); el.innerHTML = htmlContent; if (alignCenter) { el.style.textAlign = "center"; }; if (border.borderTop) { el.style.borderTop = "1px solid #767676"; } if (border.borderBottom) { el.style.borderBottom = "1px solid #767676"; } console.log(htmlContent); const body = container.querySelector('.body'); const logEl = container.querySelector('.console'); body.scrollTop = body.scrollHeight; logEl.appendChild(el); logEl.scrollTop = logEl.scrollHeight; } } (function () { const Log = new LogHelper(); const notificationTypesAndText = { "material": "参考资料", "web_link": "线上链接", "online_video": "音视频教材", "slide": "微课", "lesson": "录播教材", "homework": "作业", "forum": "讨论区", "chatroom": "iSlide 直播", "questionnaire": "调查问卷", "page": "页面", "course_invite": "課程邀請", "scorm": "SCORM" }; async function LearnCourseId(courseId) { Log.WriteHtmlLine("===== 初始化中 =====", true, { borderBottom: true }); const getCriterion = completion_criterion => completion_criterion == undefined || completion_criterion == "" ? "无" : completion_criterion; const StartTime = performance.now(); // 代码开始时间 const StartCompletenessData = await new Promise(resolve => $.get(`https://lms.ouchn.cn/api/course/${courseId}/my-completeness`, (data, status, xhr) => status === "success" ? resolve(data) : { study_completeness: undefined })); const { study_completeness: StrartCompleteness } = StartCompletenessData; const CoursesModulesData = await new Promise(resolve => $.get(`https://lms.ouchn.cn/api/courses/${courseId}/modules`, (data, status, xhr) => status === "success" ? resolve(data) : { modules: [] })); const { modules: CoursesModulesModels } = CoursesModulesData; const CompletedCourseData = StartCompletenessData; const CompletedCourseModels = CompletedCourseData.completed_result.completed.learning_activity; for (let CoursesModulesModel of CoursesModulesModels) { let sleep = parseInt((Math.random() * (15 - 8) + 8) * 1000); // 取8000 - 15000之间的毫秒随机数 await new Promise(resolve => setTimeout(resolve, sleep)); Log.WriteHtmlLine(`课程模块:${CoursesModulesModel.name}(${CoursesModulesModel.id}) 当前进度${StrartCompleteness}% 随机延迟: <span class="time">${sleep}毫秒</span>`, true, { borderBottom: true }); // 日志输出 const LearnActivitieData = await new Promise(resolve => $.get(`https://lms.ouchn.cn/api/course/${courseId}/all-activities?module_ids=[${CoursesModulesModel.id}]&activity_types=learning_activities,exams,classrooms`, (data, status, xhr) => status === "success" ? resolve(data) : { learning_activities: [] })); const { learning_activities: LearnActivitieModels } = LearnActivitieData; try { for (let LearnActivitieModel of LearnActivitieModels) { const { completion_criterion, type, title, id, uploads } = LearnActivitieModel; if (CompletedCourseModels.indexOf(parseInt(id)) !== -1) { Log.WriteHtmlLine(`课程模块:${CoursesModulesModel.name} 模块标题:${title}(${notificationTypesAndText[type]}) 完成标准:${getCriterion(completion_criterion)}(${id}) <span class="info">已完成 跳过</span>`, false, { borderBottom: true }); continue; } else { await new Promise(resolve => setTimeout(resolve, sleep)); Log.WriteHtmlLine(`课程模块:${CoursesModulesModel.name} 模块标题:${title}(${notificationTypesAndText[type]}) 完成标准:${getCriterion(completion_criterion)}(${id}) 任务开始`, false, { borderBottom: true }); } switch (type) { case "page": await new Promise(resolve => $.post(`https://lms.ouchn.cn/api/course/activities-read/${id}`, {}, resolve)); Log.WriteHtmlLine(`模块标题:${title}(${notificationTypesAndText[type]}) 完成标准:${getCriterion(completion_criterion)} <span class="info">完成</span>`); break; case "online_video": for (let VideoUploadModel of uploads) { await new Promise(resolve => $.post(`https://lms.ouchn.cn/api/course/activities-read/${id}`, {}, resolve)); // 第一次的请求默认为没有参数。 for (let item of VideoUploadModel.videos) { await new Promise(resolve => setTimeout(resolve, sleep)); await new Promise(resolve => $.ajax({ type: "POST", url: `https://lms.ouchn.cn/api/course/activities-read/${id}`, contentType: "application/json", dataType: "JSON", data: JSON.stringify({ start: 0, end: item.duration }), success: resolve, error: resolve })); } Log.WriteHtmlLine(`模块标题:${title}(${notificationTypesAndText[type]}) 完成标准:${getCriterion(completion_criterion)} <span class="info">完成</span>`); } break; case "material": for (let uploadModel of uploads) { await new Promise(resolve => $.ajax({ type: "POST", url: `https://lms.ouchn.cn/api/course/activities-read/${id}`, contentType: "application/json", dataType: "JSON", data: JSON.stringify({ upload_id: uploadModel.id }), success: resolve })); Log.WriteHtmlLine(`模块标题:${title}(${notificationTypesAndText[type]}) 完成标准:${getCriterion(completion_criterion)} <span class="info">完成</span>`); } break; case "forum": if (title === "课程答疑讨论区") { const { topic_category: { id: CategoryId } } = await new Promise(resolve => $.get(`https://lms.ouchn.cn/api/forum/${id}/category?fields=id`, {}, resolve)); await new Promise(resolve => $.ajax({ type: "POST", url: `https://lms.ouchn.cn/api/topics`, contentType: "application/json", dataType: "JSON", data: JSON.stringify({ title: "好好学习", content: "<p>好好学习,天天向上。</p>", category_id: CategoryId, uploads: [] }), success: resolve, error: resolve })); Log.WriteHtmlLine(`模块标题:${title}(${notificationTypesAndText[type]}) 完成标准:${getCriterion(completion_criterion)} <span class="info">完成</span>`); } else { Log.WriteHtmlLine(`模块标题:${title}(${notificationTypesAndText[type]}) 完成标准:${getCriterion(completion_criterion)} 不需要发帖 <span class="info">完成</span>`); } break; case "web_link": Log.WriteHtmlLine(`模块标题:${title}(${notificationTypesAndText[type]}) 完成标准:${getCriterion(completion_criterion)} <span class="info">完成</span>`); await new Promise(resolve => $.post(`https://lms.ouchn.cn/api/course/activities-read/${id}`, {}, resolve)); break; default: Log.WriteHtmlLine(`模块标题:${LearnActivitieModel.title}(${notificationTypesAndText[type]}) 完成标准:${getCriterion(completion_criterion)} <span class="warn">未完成</span> <br> 该任务无法完成。`); break; } } } catch (error) { Log.WriteHtmlLine(`<span class="error">代码出现了异常 按F12在控制台查看错误。</span>`, true, { borderBottom: true }); console.error(error); await new Promise(resolve => setTimeout(resolve, sleep)); } Log.WriteHtmlLine(`课程模块:${CoursesModulesModel.name}(${CoursesModulesModel.id}) 随机延迟: <span class="time">${sleep}毫秒</span>`, true, { borderBottom: true }); } const EndCompletenessData = await new Promise(resolve => $.get(`https://lms.ouchn.cn/api/course/${courseId}/my-completeness`, (data, status, xhr) => status === "success" ? resolve(data) : { study_completeness: undefined })); const { study_completeness: EndCompleteness } = EndCompletenessData; const EndTime = performance.now(); // 代码结束时间 Log.WriteHtmlLine(`学习前进度:${StrartCompleteness}% 学习后进度:${EndCompleteness}% 耗时: <span class="time">${((EndTime - StartTime) / 1000).toFixed(2)}秒</span>`); } $('#startTech').on({ click: function () { const courseId = document.querySelector("#courseId").value; LearnCourseId(courseId); this.onclick = null; this.style.cursor = "no-drop"; this.style.color = "#ccc"; } }) })();