// ==UserScript== // @name 新疆大学继续教育专业科目培训 // @namespace https://www.wlxy.live/ // @version 1.0 // @description 新疆大学继续教育学院(xjdxjxjy.xju.edu.cn):勾选课程、 常速免打开播放页面自动排队完成视频学时;免费体验 3 个视频章节,专业版激活后 30 天有效。 // @author 柠檬真酸 // @icon https://huaweicloudobs.ahjxjy.cn/895789f9086469785b846d30c0ed95f9.png // @match *://xjdxjxjy.xju.edu.cn/* // @exclude *://xjdxjxjy.xju.edu.cn/lms/web/course/view* // @exclude *://xjdxjxjy.xju.edu.cn/*/lms/web/course/view* // @noframes // @antifeature payment 免费体验3个视频章节,升级专业版激活后30天有效 // @antifeature membership 需会员授权 // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @grant GM_openInTab // @connect xjdxjxjy.xju.edu.cn // @connect fs.cjnep.net // @connect huaweicloudobs.ahjxjy.cn // @connect oa31.ahzsksw.cn // @connect card.wlxy.live // @require https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/vue/3.4.27/vue.global.prod.min.js // @require https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/vue-demi/0.14.6/index.iife.js // @require data:application/javascript,%3Bwindow.Vue%3DVue%3B // @require https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/dompurify/3.1.6/purify.min.js // @require https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/crypto-js/4.2.0/crypto-js.min.js // @require https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/pinia/2.2.4/pinia.iife.prod.js // @run-at document-idle // @tag 新疆大学继续教育学院 // @tag 学习辅助 // @license All Rights Reserved // ==/UserScript== (function(Vue,DOMPurify,Pinia,CryptoJS){ "use strict"; (() => { var Fe = "1.0", Ve = "\u65B0\u7586\u5927\u5B66\u7EE7\u7EED\u6559\u80B2\u4E13\u4E1A\u79D1\u76EE\u57F9\u8BAD", we = "__XJDXJXJY_WATCH_BOOT__", S = location.hostname.replace(/^www\./, ""), Y = location.origin, g = { enabled: `xjdx_enabled_${S}`, pace: `xjdx_pace_${S}`, onlyIncomplete: `xjdx_only_incomplete_${S}`, autoExam: `xjdx_auto_exam_${S}`, selected: `xjdx_selected_${S}`, panelPos: `xjdx_panel_pos_${S}`, collapsed: `xjdx_panel_collapsed_${S}`, examBank: `xjdx_exam_bank_${S}`, userId: `xjdx_user_id_${S}` }, j = { realtime: "realtime" }, W = 30; var ye = 0.8; var je = 300, Ge = "https://huaweicloudobs.ahjxjy.cn/895789f9086469785b846d30c0ed95f9.png", He = "\u514D\u8D39\u53EF\u4F53\u9A8C 3 \u4E2A\u89C6\u9891\u7AE0\u8282\uFF1B\u4E13\u4E1A\u7248\u6FC0\u6D3B\u540E 30 \u5929\u6709\u6548\u3002\u6309\u771F\u5B9E\u65F6\u957F\u5B66\u4E60\u3002", Be = "903117129", Je = "https://qun.qq.com/universal-share/share?ac=1&authKey=rxdL6YIJ0%2FxOEemjLqTGULvl5aAfJIVQcIvkvnwvmL%2FAmpFZnSafajYHgSXMUXvx&busi_data=eyJncm91cENvZGUiOiI5MDMxMTcxMjkiLCJ0b2tlbiI6IlB2dkFGSm5XRXBrSEhtQVFTUGQzdVNZakhNWDNMbW1kODA2enpoMi9obDh4SWp0YzBDODNFaGtwRU44Z0hyU0siLCJ1aW4iOiIxMjU0MzE1MTQifQ%3D%3D&data=9oyJixSPcigCQW-saV5eXlcMwV9C6J36XySx-rDHwVwNlofvRmd2ze5sLwFtHTbYbG4nAWIUrI0qftC6aTX9xg&svctype=4&tempid=h5_group_info", se = "https://oa31.ahzsksw.cn", Q = "xjdx_cloud_token_v1", le = "xjdx_cloud_lease_cache_v1", V = "https://card.wlxy.live/details/E97ED248", L = 3, Ce = 30, z = { courseIndex: "/lms/web/course/index", courseDetail: "/lms/web/course/detail", courseView: "/lms/web/course/view", startupXml: "/lms/web/course/startupxml", updStatus: "/lms/web/timing/updstatus", myInfo: "/lms/web/myinfo/index", home: "/lms/web/default/index" }; var ce = null; function Xe(e) { ce = e; } var K = { ws: null, hb: null }, n = { enabled: !1, stopFlag: !1, running: !1, pace: j.realtime, onlyIncomplete: !0, autoExam: !1, learningCourses: [], completedCourses: [], selectedIds: /* @__PURE__ */ new Set(), selectMode: "all", chapters: [], activeCourse: null, currentCourse: "", currentChapter: "", logs: [], task: "", panelHint: "", reportInterval: W, semester: (/* @__PURE__ */ new Date()).getFullYear(), userName: "", learningUserId: "", examBank: {}, queueVideoTotal: 0, queueVideoDone: 0, queueExamTotal: 0, queueExamDone: 0, queueChapterTotal: 0, queueChapterDone: 0, queueProgressPct: 0, queueMetricLabel: "\u95E8\u8BFE\u5DF2\u5B8C\u6210", studyModeHintTimer: null, cloudApiBase: se, cloudToken: String(localStorage.getItem(Q) || "").trim(), cloudLease: "", cloudLeaseExp: 0, cloudTier: "unknown", cloudProExpireAt: 0, freeCourseLimit: L, freeUsedCourses: 0, proActivationDays: 30, proBuyUrl: V, remotePanelNotice: "", cloudReady: !1 }, q = null; function Ye(e) { q = e; } function E(e) { return new Promise((t) => setTimeout(t, Math.max(0, e))); } function C(e) { return String(e ?? "").replace(/&/g, "&").replace(//g, ">"); } function R(e, t) { let r = String(e || ""); return r.length > t ? r.slice(0, t) + "\u2026" : r; } function w(e) { let t = Math.max(0, Math.floor(Number(e) || 0)), r = Math.floor(t / 60), i = t % 60; return `${r}:${String(i).padStart(2, "0")}`; } function Z(e, t) { try { let r = GM_getValue(e, null); return r == null ? t : typeof r == "string" ? JSON.parse(r) : r; } catch { return t; } } function de(e, t) { GM_setValue(e, JSON.stringify(t)); } function _e(e, t) { let r = e.startsWith("http") ? e : `${Y}${e}`; return fetch(r, { credentials: "include", ...t }).then(async (i) => { let o = await i.text(); if (!i.ok) throw new Error(`HTTP ${i.status}`); return { status: i.status, text: o, url: i.url }; }); } function ve(e, t, r, i) { let o = e.startsWith("http") ? e : `${Y}${e}`; return new Promise((a, s) => { if (typeof GM_xmlhttpRequest != "function") { _e(o, { method: t || "GET", headers: r, body: i }).then(a).catch(s); return; } GM_xmlhttpRequest({ method: t || "GET", url: o, headers: r || {}, data: i, withCredentials: !0, anonymous: !1, onload(l) { a({ status: l.status, text: l.responseText || "", url: l.finalUrl || o }); }, onerror() { s(new Error("\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25")); }, ontimeout() { s(new Error("\u8BF7\u6C42\u8D85\u65F6")); } }); }); } async function T(e) { try { return await _e(e, { method: "GET" }); } catch { return ve(e, "GET", { Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" }); } } async function We(e, t, r) { let i = new URLSearchParams(); Object.keys(t || {}).forEach((a) => { t[a] != null && i.set(a, String(t[a])); }); let o = { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", Accept: "application/xml, text/xml, */*; q=0.01", "X-Requested-With": "XMLHttpRequest" }; if (r && (o.Referer = r), r && typeof GM_xmlhttpRequest == "function") return ve(e, "POST", o, i.toString()); try { return await _e(e, { method: "POST", headers: o, body: i.toString() }); } catch { return ve(e, "POST", o, i.toString()); } } function v(e, t) { let r = String(e || "").match( new RegExp(`<${t}[^>]*>([\\s\\S]*?)`, "i") ); return r ? r[1].trim() : ""; } function Se(e) { let t = parseFloat(v(e, "maxViewedTime")) || 0, r = parseFloat(v(e, "lastViewedTime")) || 0, i = parseInt(v(e, "updInterval"), 10) || 30, o = v(e, "finish").toLowerCase(); return { userId: v(e, "userId"), courseId: v(e, "courseId"), scoId: v(e, "scoId"), scoTitle: v(e, "scoTitle"), historyId: v(e, "historyId"), maxViewedTime: t, lastViewedTime: r, updInterval: i, finish: o === "true" || o === "1", updStatusUrl: v(e, "updStatusUrl") || z.updStatus, status: v(e, "status"), raw: e }; } function ue(e) { let t = String(e || ""); if (/\/lms\/web\/default\/login/i.test(t) && /logincheck|验证码|登录/i.test(t) && !/default\/logout/i.test(t) && !/myinfo/i.test(t)) throw new Error("\u672A\u767B\u5F55\u6216\u4F1A\u8BDD\u5DF2\u5931\u6548\uFF0C\u8BF7\u5148\u767B\u5F55\u5E73\u53F0"); if (/请先登录|重新登录|会话已过期/i.test(t) && !/default\/logout/i.test(t)) throw new Error("\u672A\u767B\u5F55\u6216\u4F1A\u8BDD\u5DF2\u5931\u6548\uFF0C\u8BF7\u5148\u767B\u5F55\u5E73\u53F0"); } function O(e) { let t = String(e || "").trim(); if (t) { n.learningUserId = t; try { GM_setValue(g.userId, t); } catch { } } } function b() { if (n.learningUserId) return String(n.learningUserId); try { let e = String(GM_getValue(g.userId, "") || "").trim(); if (e) return n.learningUserId = e, e; } catch { } return ""; } function Qe() { return { userInfo: { id: b(), name: n.userName || "" }, token: { access_token: "cookie-session" } }; } async function pe() { try { let e = await T(z.home); ue(e.text); let t = e.text.match(/欢迎[^<]{0,6}([\u4e00-\u9fa5A-Za-z0-9_·]{2,20})/) || e.text.match(/class="[^"]*user[^"]*"[^>]*>([^<]{2,20}) { }; function Ze(e) { Ee = typeof e == "function" ? e : () => { }; } function et() { n.enabled = !!GM_getValue(g.enabled, !1), n.pace = j.realtime, GM_setValue(g.pace, j.realtime), n.onlyIncomplete = GM_getValue(g.onlyIncomplete, !0) !== !1, n.autoExam = !1, GM_setValue(g.autoExam, !1), n.examBank = Z(g.examBank, {}) || {}, n.learningUserId = String(GM_getValue(g.userId, "") || "").trim(); let e = Z(g.selected, null); e && typeof e == "object" && !Array.isArray(e) ? (n.selectMode = e.mode === "none" || e.mode === "partial" ? e.mode : "all", n.selectedIds = new Set(Array.isArray(e.ids) ? e.ids.map(String) : [])) : Array.isArray(e) ? (n.selectMode = e.length ? "partial" : "all", n.selectedIds = new Set(e.map(String))) : (n.selectMode = "all", n.selectedIds = /* @__PURE__ */ new Set()); } function fe() { de(g.selected, { mode: n.selectMode, ids: Array.from(n.selectedIds) }); } function Te(e) { let t = String(e); return n.selectMode === "none" ? !1 : n.selectMode === "all" ? !0 : n.selectedIds.has(t); } function D() { if (n.selectMode === "none") return []; let e = n.learningCourses; return n.selectMode === "all" ? e.slice() : e.filter((t) => n.selectedIds.has(String(t.id))); } function tt() { n.selectMode = "all", n.selectedIds = /* @__PURE__ */ new Set(), fe(), Ee(); } function nt() { n.selectMode = "none", n.selectedIds = /* @__PURE__ */ new Set(), fe(), Ee(); } function _(e, t) { if (t && t.completedView) return 100; let r = parseFloat(e.myCourseProgress ?? e.progress ?? 0) || 0; return r <= 0 && e.finished && (r = 100), Math.min(100, Math.max(0, r)); } function rt(e) { let t = parseFloat(e.credit); return Number.isFinite(t) && t > 0 ? t : 0; } function $t(e, t) { let r = rt(e), i = _(e, t); return r ? t && t.completedView || i >= 99.5 ? r : Math.round(r * i / 100 * 10) / 10 : null; } function Lt(e, t) { let r = _(e, t), i = rt(e), o = $t(e, t), a = []; return i > 0 && o != null ? a.push(`\u5B66\u65F6 ${o}/${i}`) : a.push(`\u5B66\u4E60\u8FDB\u5EA6 ${r.toFixed(0)}%`), e.lessonHours > 0 ? a.push(`\u5B66\u4E60\u65F6\u957F ${e.lessonHours} \u8BFE\u65F6`) : e.chapterTotal > 0 && a.push(`\u5171 ${e.chapterTotal} \u8BB2`), i > 0 && o != null && a.push(`\u8FDB\u5EA6 ${r.toFixed(0)}%`), a.join(" \xB7 "); } function Ie(e) { return _(e) >= 99.5 || !!e.finished; } function ke(e, t) { let r = t || {}, i = String(e.id), o = Te(i), a = _(e, r), s = !!(r.completedView || Ie(e)), l = C(e.name || e.title || `\u8BFE\u7A0B ${i}`), d = C(Lt(e, r)), u = s ? "#f1f5f9" : "#f8fafc", c = s ? "#64748b" : "#0f172a", p = r.completedView ? "disabled" : "", x = s ? '\u5DF2\u5B8C\u6210' : ""; return ``; } function Pt(e) { ue(e); let t = [], r = /* @__PURE__ */ new Set(), i = /class="[^"]*mycourse[^"]*"[\s\S]*?href="\/lms\/web\/course\/detail\?id=(\d+)"[\s\S]*?class="namediv">([^<]*)<\/div>\s*
([\s\S]*?)<\/div>/gi, o; for (; o = i.exec(e); ) { let a = o[1]; if (r.has(a)) continue; r.add(a); let s = String(o[2] || "").trim(), l = String(o[3] || ""), d = l.match(/(\d+(?:\.\d+)?)%<\/font>/i) || l.match(/(\d+(?:\.\d+)?)\s*%/), u = d ? parseFloat(d[1]) : 0, c = l.match(/学习时长\s*[::]\s*(\d+(?:\.\d+)?)\s*课时/i) || l.match(/(\d+(?:\.\d+)?)\s*课时/), p = l.match(/(\d+(?:\.\d+)?)\s*学时/), x = c ? parseFloat(c[1]) : 0; t.push({ id: a, name: s || `\u8BFE\u7A0B ${a}`, title: s || `\u8BFE\u7A0B ${a}`, myCourseProgress: u, progress: u, credit: p ? parseFloat(p[1]) : 0, lessonHours: x, hourText: x > 0 ? `\u5B66\u4E60\u65F6\u957F ${x} \u8BFE\u65F6` : "", chapterTotal: 0, chapterDone: 0, finished: u >= 99.5, isExam: !1, classId: "" }); } if (!t.length) { let a = [...e.matchAll(/\/lms\/web\/course\/detail\?id=(\d+)/g)].map( (s) => s[1] ); for (let s of [...new Set(a)]) t.push({ id: s, name: `\u8BFE\u7A0B ${s}`, title: `\u8BFE\u7A0B ${s}`, myCourseProgress: 0, progress: 0, credit: 0, lessonHours: 0, hourText: "", chapterTotal: 0, chapterDone: 0, finished: !1, isExam: !1, classId: "" }); } return t; } function Ke(e) { let t = String(e || ""), r = t.match(/(\d+)\s*:\s*(\d+)/); if (r) return parseInt(r[1], 10) * 60 + parseInt(r[2], 10); let i = t.match(/(\d+)\s*分\s*(?:钟)?\s*(\d+)\s*秒/); if (i) return parseInt(i[1], 10) * 60 + parseInt(i[2], 10); let o = t.match(/(\d+)\s*分\s*(?:钟)?/); if (o) return parseInt(o[1], 10) * 60; let a = t.match(/(\d+)\s*秒/); return a ? parseInt(a[1], 10) : 0; } function Mt(e, t) { ue(e); let r = [], i = /]*onClick\s*=\s*["']window\.location\s*=\s*['"]\/lms\/web\/course\/view\?id=(\d+)&itemid=(\d+)['"]\s*;?\s*["']\s*>([\s\S]*?)(?=\s*<\/div>\s*
\s*]*>([^<]+)/i) || [])[1] || "", A = (p.match(/class="[^"]*namediv[^"]*"[^>]*>([^<]+)/i) || [])[1] || "", ie = (p.match(/class="[^"]*date[^"]*"[^>]*>([^<]+)/i) || [])[1] || "", k = (p.match(/zbtn-border[^>]*>([^<]+)/i) || [])[1] || "", X = (p.match(/fdiv[^>]*>([^<]+)/i) || [])[1] || "", $ = String(A || "").trim() || `\u7AE0\u8282 ${c}`, N = Ke(ie), F = Ke(X), ae = /\bitem-finish\b/i.test(d) || /^(已完成|学习完成|已学完)$/.test(String(k).trim()); r.push({ id: c, itemId: c, scoId: c, courseId: u || t, name: $, title: $, num: String(x).trim(), duration: String(N || 0), timespan: String(F || 0), progress: N > 0 ? F / N * 100 : ae ? 100 : 0, isComplete: ae, btn: String(k).trim(), credit: "", score: 0 }); } let a = e.match(/class="[^"]*rdiv[^"]*"[\s\S]*?class="[^"]*namediv[^"]*"[^>]*>([^<]+)/i) || e.match(/class="[^"]*namediv[^"]*"[^>]*>([^<]+)/i), s = e.match(/目前已完成了\s*(\d+(?:\.\d+)?)\s*%/) || e.match(/progress-bar[^>]*style="[^"]*width:\s*(\d+(?:\.\d+)?)%/i), l = r.filter((d) => d.isComplete).length; return { id: String(t), name: a ? a[1].trim() : "", courseProgress: s ? parseFloat(s[1]) : 0, chapter: r, chapterTotal: r.length, chapterDone: l, projectId: "" }; } async function ee() { await pe(); let e = await T(z.courseIndex), t = Pt(e.text); return n.learningCourses = t.filter((r) => _(r) < 99.5), n.completedCourses = t.filter((r) => _(r) >= 99.5), !n.learningCourses.length && t.length && (n.learningCourses = t.slice(), n.completedCourses = t.filter((r) => _(r) >= 99.5)), t; } async function G(e) { let t = await T(`${z.courseDetail}?id=${encodeURIComponent(e)}`); return Mt(t.text, e); } async function ot(e, t) { let r = await G(e), i = (r.chapter || []).find( (o) => String(o.itemId || o.id) === String(t) ); return i ? { found: !0, learned: parseFloat(i.timespan) || 0, duration: parseFloat(i.duration) || 0, isComplete: !!i.isComplete, name: i.name, courseProgress: r.courseProgress || 0 } : { found: !1, learned: 0, duration: 0, isComplete: !1, courseProgress: r.courseProgress || 0 }; } var it = () => { }; function at(e) { it = typeof e == "function" ? e : () => { }; } function f(e, t) { let r = { t: Date.now(), msg: String(e || ""), type: t || "info" }; n.logs.unshift(r), n.logs.length > je && (n.logs.length = je), it(); } function m(e) { if (ce) { let t = ce.querySelector("#" + e); if (t) return t; } return document.getElementById(e); } function H(e, t) { if (!e) return; let r = typeof DOMPurify < "u" && DOMPurify.sanitize ? DOMPurify.sanitize(t, { USE_PROFILES: { html: !0 } }) : t; e.innerHTML = r; } var st = () => { }; function lt(e) { st = typeof e == "function" ? e : () => { }; } function Ut() { return String(n.cloudApiBase || se).replace(/\/+$/, ""); } function $e() { return String(n.proBuyUrl || V).trim() || V; } function At() { return n.cloudTier === "pro"; } function qt() { try { let e = JSON.parse(localStorage.getItem(le) || "null"), t = String(e?.lease || "").trim(), r = Number(e?.exp || 0); return !t || !Number.isFinite(r) || r * 1e3 <= Date.now() + 15e3 ? null : e; } catch { return null; } } function te(e, t, r) { if (!e || !t) { localStorage.removeItem(le); return; } localStorage.setItem( le, JSON.stringify(Object.assign({ lease: e, exp: t }, r || {})) ); } function Rt(e) { let t = String(e || "").trim(), r = { "invalid token": "\u6FC0\u6D3B\u7801\u65E0\u6548", revoked: "\u6FC0\u6D3B\u7801\u5DF2\u505C\u7528", expired: "\u6FC0\u6D3B\u7801\u5DF2\u8FC7\u671F", expired_after_activation: "\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u5F00\u901A", token_bound_to_other_learning_user: "\u6FC0\u6D3B\u7801\u5DF2\u7ED1\u5B9A\u5176\u4ED6\u8D26\u53F7", free_course_quota_exceeded: "\u514D\u8D39\u4F53\u9A8C\u7AE0\u8282\u5DF2\u7528\u5B8C\uFF0C\u8BF7\u5347\u7EA7\u4E13\u4E1A\u7248", free_quota_exhausted: "\u514D\u8D39\u4F53\u9A8C\u7AE0\u8282\u5DF2\u7528\u5B8C\uFF0C\u8BF7\u5347\u7EA7\u4E13\u4E1A\u7248", invalid_lease: "\u4F1A\u8BDD\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u8BD5", rate_limited: "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5" }; return r[t] || r[t.toLowerCase()] || t || "\u64CD\u4F5C\u5931\u8D25"; } function ct(e, t, r) { let o = `${Ut()}${e.startsWith("/") ? e : `/${e}`}`, a = { Accept: "application/json", "Content-Type": "application/json" }, s = b(); s && (a["x-learning-user-id"] = s), n.cloudToken && (a.Authorization = `Bearer ${n.cloudToken}`); let l = r == null ? null : JSON.stringify(r); return new Promise((d, u) => { let c = { method: t || "GET", url: o, headers: a, timeout: 3e4, withCredentials: !1, responseType: "text", onload: (p) => d({ status: p.status, text: p.responseText || "" }), onerror: () => u(new Error("\u7F51\u7EDC\u5F02\u5E38")), ontimeout: () => u(new Error("\u8BF7\u6C42\u8D85\u65F6")) }; if (l != null && (c.data = l), typeof GM_xmlhttpRequest == "function") { GM_xmlhttpRequest(c); return; } fetch(o, { method: c.method, headers: a, body: l }).then(async (p) => d({ status: p.status, text: await p.text() })).catch(() => u(new Error("\u7F51\u7EDC\u5F02\u5E38"))); }); } async function me(e, t, r) { let i = await ct(e, t, r), o = String(i.text || "").trim(), a = null; if (o) try { a = JSON.parse(o); } catch { throw new Error(`\u670D\u52A1\u5F02\u5E38(HTTP ${i.status})`); } if (i.status >= 400) { let s = a?.message || a?.detail || `HTTP ${i.status}`, l = new Error(Rt(s)); throw l.status = i.status, l.data = a, l; } return a || {}; } async function dt() { return n.cloudToken && await me("/api/license/verify", "GET", null), !0; } async function M(e) { let t = e ? null : qt(); if (t?.lease) return n.cloudLease = t.lease, n.cloudLeaseExp = Number(t.exp || 0), t.tier && (n.cloudTier = String(t.tier)), t.free_course_limit != null && (n.freeCourseLimit = Number(t.free_course_limit) || L), t.free_used_courses != null && (n.freeUsedCourses = Number(t.free_used_courses) || 0), t.pro_expires_at && (n.cloudProExpireAt = Number(t.pro_expires_at) || 0), n.cloudReady = !0, P(), !0; let r = b(); if (!r) throw new Error("\u672A\u767B\u5F55\uFF0C\u8BF7\u5148\u767B\u5F55\u5E73\u53F0"); let i = Qe(), o = await me("/api/xjdxjxjy/lease", "POST", { learning_user_id: r, name: n.userName || i?.userInfo?.name || "", userName: n.userName || i?.userInfo?.name || "" }), a = String(o.lease || ""), s = Number(o.exp || 0); if (!a) throw new Error("\u5F00\u901A\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5"); if (n.cloudLease = a, n.cloudLeaseExp = s, n.cloudTier = String(o.tier || "free"), n.freeCourseLimit = Number( o.free_course_limit != null ? o.free_course_limit : L ) || L, n.freeUsedCourses = Number(o.free_used_courses != null ? o.free_used_courses : 0) || 0, n.cloudProExpireAt = Number(o.pro_expires_at || 0) || 0, o.proBuyUrl) { let l = String(o.proBuyUrl).trim(); l && (n.proBuyUrl = l); } return te(a, s, { tier: n.cloudTier, free_course_limit: n.freeCourseLimit, free_used_courses: n.freeUsedCourses, pro_expires_at: n.cloudProExpireAt }), n.cloudReady = !0, P(), !0; } async function ut(e, t) { await M(!1); let r = String( t?.itemId || t?.scoId || t?.id || "" ).trim(); if (!r) throw new Error("\u7F3A\u5C11\u7AE0\u8282\u7F16\u53F7\uFF0C\u65E0\u6CD5\u6838\u9500\u514D\u8D39\u989D\u5EA6"); let i = await me("/api/xjdxjxjy/course/consume", "POST", { lease: n.cloudLease, course_id: r, chapter_id: r, course_name: String(e?.name || e?.title || ""), chapter_name: String(t?.name || t?.title || "") }); return i.tier && (n.cloudTier = String(i.tier)), i.free_used_courses != null && (n.freeUsedCourses = Number(i.free_used_courses) || 0), i.free_course_limit != null && (n.freeCourseLimit = Number(i.free_course_limit) || n.freeCourseLimit), te(n.cloudLease, n.cloudLeaseExp, { tier: n.cloudTier, free_course_limit: n.freeCourseLimit, free_used_courses: n.freeUsedCourses, pro_expires_at: n.cloudProExpireAt }), P(), i; } async function pt() { try { let e = await ct("/api/xjdxjxjy/panel-notice", "GET", null); if (e.status === 200 && e.text) { n.remotePanelNotice = String(e.text).trim(); let t = m("nmg-panel-notice-text"); t && n.remotePanelNotice && (t.textContent = n.remotePanelNotice); } } catch { } } async function ft() { try { let e = await me("/api/xjdxjxjy/client-config", "GET", null); e.cloudApiBase && (n.cloudApiBase = String(e.cloudApiBase).replace(/\/+$/, "")), e.freeCourseLimit != null && (n.freeCourseLimit = Number(e.freeCourseLimit) || L), e.proBuyUrl && (n.proBuyUrl = String(e.proBuyUrl).trim() || V), e.activationTtlDays != null && (n.proActivationDays = Number(e.activationTtlDays) || Ce); } catch { } } function P() { let e = n.proActivationDays || Ce, t = n.cloudTier === "pro" ? n.cloudProExpireAt ? `\u4E13\u4E1A\u7248\uFF08\u81F3 ${new Date(n.cloudProExpireAt * 1e3).toLocaleDateString()}\uFF09` : `\u4E13\u4E1A\u7248\uFF08\u6FC0\u6D3B\u540E ${e} \u5929\uFF09` : n.cloudTier === "unknown" ? "\u52A0\u8F7D\u4E2D\u2026" : `\u514D\u8D39\u7248\uFF08\u5DF2\u7528 ${n.freeUsedCourses}/${n.freeCourseLimit} \u8BB2\uFF09`, r = m("nmg-cloud-tier"); r && (r.textContent = t); let i = m("nmg-pro-buy"); i && (i.href = $e()); let o = m("nmg-pro-banner"); o && (o.style.display = At() ? "none" : ""); let a = o && o.querySelector(".zjzx-pro-banner-desc"); a && (a.textContent = `\u514D\u8D39\u53EF\u4F53\u9A8C ${n.freeCourseLimit || L} \u4E2A\u89C6\u9891\u7AE0\u8282\uFF1B\u4E13\u4E1A\u7248\u6FC0\u6D3B\u540E ${e} \u5929\u6709\u6548\u3002`), st(); } var re = () => { }, Ot = async () => ({ ok: !0, skipped: !0 }); function gt(e) { e && typeof e.upd == "function" && (re = e.upd), e && typeof e.exam == "function" && (Ot = e.exam); } function Pe() { K.hb && (clearInterval(K.hb), K.hb = null), K.ws = null; } function Dt(e) { let t = String(e || "").match( /startupxml\?courseid=(\d+)&itemid=(\d+)&historyid=(\d+)/i ); if (!t) throw new Error("\u64AD\u653E\u9875\u672A\u627E\u5230 historyId\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u767B\u5F55\u4E14\u7AE0\u8282\u53EF\u5B66"); return { courseId: t[1], itemId: t[2], historyId: t[3] }; } function Le(e) { if (e.isComplete === !0) return !0; let t = String(e.btn || ""); return !!/已完成|学习完成|已学完/.test(t); } function Nt(e) { return (e && e.chapter || []).filter((r) => n.onlyIncomplete ? !Le(r) : !0); } async function y(e) { try { await T(`${z.courseDetail}?id=${encodeURIComponent(e)}`); } catch { } await E(800); } async function ge(e, t, r = 3) { await y(e); let i = null; for (let o = 0; o < r; o++) try { let a = `${z.courseView}?id=${encodeURIComponent( e )}&itemid=${encodeURIComponent(t)}`, s = await T(a), l = Dt(s.text), d = `${z.startupXml}?courseid=${l.courseId}&itemid=${l.itemId}&historyid=${l.historyId}`, u = await T(d), c = Se(u.text); if (!c.userId && !c.scoId && c.status && c.status !== "1") throw new Error(`startupxml \u5F02\u5E38 status=${c.status}`); if (c.userId && O(c.userId), c.historyId || (c.historyId = l.historyId), c.courseId || (c.courseId = l.courseId), c.scoId || (c.scoId = l.itemId), c.viewReferer = `${Y}${a}`, c.meta = l, await xe(c, { addTime: 0, totalTime: c.maxViewedTime || 1, currentTime: Math.min( Number(c.lastViewedTime) || 0, c.maxViewedTime || 0 ), firstUpdate: !0, _soft: !0 }) === -1) { i = new Error("\u68C0\u6D4B\u5230\u540C\u65F6\u6253\u5F00\u591A\u4E2A\u770B\u8BFE\u9875"), f("\u68C0\u6D4B\u5230\u591A\u5F00\u770B\u8BFE\uFF0C\u91CA\u653E\u4F1A\u8BDD\u540E\u91CD\u8BD5\u2026", "info"), await y(e), await E(1500); continue; } return c; } catch (a) { i = a; let s = String(a && a.message ? a.message : a); if (/同时打开多个看课页|-1/.test(s) && o < r - 1) { f("\u68C0\u6D4B\u5230\u591A\u5F00\u770B\u8BFE\uFF0C\u91CA\u653E\u4F1A\u8BDD\u540E\u91CD\u8BD5\u2026", "info"), await y(e), await E(1500); continue; } throw a; } throw i || new Error("\u6253\u5F00\u7AE0\u8282\u5931\u8D25"); } async function Ft(e) { let t = e.meta || { courseId: e.courseId, itemId: e.scoId, historyId: e.historyId }, r = `${z.startupXml}?courseid=${t.courseId}&itemid=${t.itemId}&historyid=${t.historyId}`, i = await T(r), o = Se(i.text); return o.userId && O(o.userId), e.maxViewedTime = o.maxViewedTime || e.maxViewedTime, e.lastViewedTime = o.lastViewedTime, e.finish = o.finish, e.updInterval = o.updInterval || e.updInterval, o.scoTitle && (e.scoTitle = o.scoTitle), e; } async function U(e, t) { return ot(e, t); } async function xe(e, t) { let r = e.userId || b(); if (!r) throw new Error("\u65E0\u6CD5\u5F00\u59CB\u5B66\u4E60\uFF0C\u8BF7\u5148\u767B\u5F55"); let i = { userId: r, courseId: e.courseId, scoId: e.scoId, historyId: e.historyId, addTime: t.addTime, totalTime: t.totalTime, currentTime: t.currentTime, hasCheckOne: !1, hasCheckTwo: !1, hasCheckThree: !1, firstUpdate: !!t.firstUpdate }; t.finished && (i.finished = 1); let a = ((await We( e.updStatusUrl || z.updStatus, i, e.viewReferer )).text.match(/([^<]+)<\/status>/i) || [])[1], s = a == null || a === "" ? 1 : parseInt(a, 10); if (t._soft) return Number.isFinite(s) ? s : 1; if (s === -1) throw new Error("\u68C0\u6D4B\u5230\u540C\u65F6\u6253\u5F00\u591A\u4E2A\u770B\u8BFE\u9875\uFF0C\u8BF7\u5173\u95ED\u5176\u4ED6\u64AD\u653E\u9875\u540E\u91CD\u8BD5"); if (s === -2) throw new Error("\u5B66\u4E60\u8FDB\u5EA6\u540C\u6B65\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u6216\u624B\u52A8\u6253\u5F00\u7AE0\u8282\u786E\u8BA4"); if (Number.isFinite(s) && s < 0) throw new Error(`\u5B66\u4E60\u8FDB\u5EA6\u540C\u6B65\u5931\u8D25\uFF08${s}\uFF09`); return s; } function Vt(e) { let t = new Date(Date.now() + Math.max(0, Number(e) || 0) * 1e3), r = String(t.getHours()).padStart(2, "0"), i = String(t.getMinutes()).padStart(2, "0"); return `${r}:${i}`; } async function mt(e, t) { await Ft(e); let r = Math.max(Number(t) || 0, 1), i = Math.min( r, Math.max( Number(e.lastViewedTime) || 0, r * Math.max(ye, 0.99) ) ); return await xe(e, { addTime: 0, totalTime: r, currentTime: i, firstUpdate: !1 }), await E(400), await xe(e, { addTime: 0, totalTime: r, currentTime: 0, firstUpdate: !1, finished: !0 }), r; } function ne(e) { return /同时打开多个看课页|-1/.test(String(e && e.message ? e.message : e)); } async function B(e, t) { return f("\u68C0\u6D4B\u5230\u591A\u5F00\u770B\u8BFE\uFF0C\u91CA\u653E\u4F1A\u8BDD\u540E\u91CD\u8BD5\u2026", "info"), await y(e), await E(2e3), ge(e, t); } async function xt(e, t, r, i) { let o = r; for (let s = 0; s < 3; s++) try { s > 0 && (o = await B(e, t)), await mt(o, i), await E(1600); let l = await U(e, t); return l.isComplete ? { ok: !0, info: o, detailProg: l } : (o = await B(e, t), await mt(o, i), await E(2e3), l = await U(e, t), { ok: !!l.isComplete, info: o, detailProg: l }); } catch (l) { if (!ne(l) || s >= 2) throw l; o = await B(e, t); } let a = await U(e, t); return { ok: !!a.isComplete, info: o, detailProg: a }; } function Gt(e) { let t = Math.max(5, e || W); return { waitSec: t, creditSec: t }; } async function Ht(e, t) { let r = String(e.id), i = String(t.itemId || t.id); n.currentCourse = e.name || e.title || "", n.currentChapter = t.name || "", n.task = `${R(n.currentCourse, 14)} \xB7 ${R(t.name, 12)}`, re(), f(`\u6253\u5F00\u7AE0\u8282 \xB7 ${t.name}`, "progress"); let o = await U(r, i); if (o.found && o.isComplete) { f( `\u7AE0\u8282\u5DF2\u5B8C\u6210 \xB7 ${t.name}\uFF08\u5DF2\u5B66\u4E60 ${w(o.learned)}/${w(o.duration)}\uFF09`, "info" ); return; } await ut(e, t); let a = await ge(r, i); if (o = await U(r, i), o.found && o.isComplete) { f(`\u7AE0\u8282\u5DF2\u5B8C\u6210 \xB7 ${t.name}`, "info"), await y(r); return; } if (a.finish && o.isComplete) { f(`\u7AE0\u8282\u5DF2\u5B8C\u6210 \xB7 ${t.name}`, "info"), await y(r); return; } let s = (o.duration > 0 ? o.duration : 0) || parseFloat(t.duration) || 0; if (!(s > 0)) throw new Error(`\u7AE0\u8282 ${t.name} \u65E0\u6709\u6548\u65F6\u957F`); let l = s * ye, d = Math.min( s, Math.max(0, o.found ? o.learned : 0) ), u = Math.max( 5, parseInt(a.updInterval, 10) || n.reportInterval || W ); n.reportInterval = u; let { waitSec: c, creditSec: p } = Gt(u), x = s, A = Math.max(0, l - d), ie = p > 0 ? Math.ceil(A / p * c) : A; f(`\u5F00\u59CB\u5B66\u4E60 \xB7 ${a.scoTitle || t.name}`, "progress"), f( `\u8FDB\u5EA6 ${w(d)}/${w(s)} \xB7 \u9884\u8BA1 ${Vt(ie)} \u5B8C\u6210\uFF08\u7EA6 ${Math.max(1, Math.ceil(ie / 60))} \u5206\u949F\uFF09`, "info" ); let k = !1, X = 0, $ = 0; for (; !n.stopFlag; ) { if (o = await U(r, i), o.found && (d = Math.max(d, o.learned), o.isComplete)) { f( `\u7AE0\u8282\u5B8C\u6210 \xB7 ${t.name}\uFF08\u5DF2\u5B66\u4E60 ${w(d)}/${w(s)}\uFF09`, "info" ), await y(r); return; } if (!k && d >= l - 0.5) { k = !0; try { let h = await xt( r, i, a, s ); if (a = h.info, h.ok) { f( `\u7AE0\u8282\u5B8C\u6210 \xB7 ${t.name}\uFF08\u5DF2\u5B66\u4E60 ${w(h.detailProg.learned)}/${w(s)}\uFF09`, "info" ), await y(r); return; } } catch (h) { if (!ne(h)) throw h; a = await B(r, i), k = !1; } } if (await E(Math.round(c * 1e3)), n.stopFlag) break; let N = Math.min( p, Math.ceil(Math.max(1, s - d + p)) ), F = Math.min(d + N, x); try { await xe(a, { addTime: N, totalTime: x, currentTime: F, firstUpdate: !1 }); } catch (h) { if (ne(h)) try { a = await B(r, i), k = !1; continue; } catch (Ne) { if (ne(Ne)) { f("\u591A\u5F00\u672A\u89E3\u9664\uFF0C5 \u79D2\u540E\u7EE7\u7EED\u91CD\u8BD5\u2026", "info"), await y(r), await E(5e3), k = !1; continue; } throw Ne; } throw h; } if ($ += 1, $ % 2 === 0 ? (o = await U(r, i), o.found ? d = Math.max(d, o.learned) : d = Math.max(d, Math.min(s, F))) : d = Math.max(d, Math.min(s, F)), d >= s * 0.98 && $ % 4 === 0) try { let h = await xt( r, i, a, s ); if (a = h.info, h.ok) { f( `\u7AE0\u8282\u5B8C\u6210 \xB7 ${t.name}\uFF08\u5DF2\u5B66\u4E60 ${w(h.detailProg.learned)}/${w(s)}\uFF09`, "info" ), await y(r); return; } } catch (h) { if (!ne(h)) throw h; a = await B(r, i); } let ae = s > 0 ? Math.min(100, Math.round(d / s * 100)) : 0, De = Date.now(); if ((!X || De - X >= 6e4) && (X = De, f( `\u5F53\u524D\u8FDB\u5EA6 ${w(d)}/${w(s)} ${ae}%`, "progress" )), d >= s * 0.995 && $ > 5) { if (o = await U(r, i), o.isComplete) { f(`\u7AE0\u8282\u5B8C\u6210 \xB7 ${t.name}`, "info"), await y(r); return; } if ($ > 20) { f( `\u8FDB\u5EA6\u5DF2\u6EE1\u4F46\u7AE0\u8282\u72B6\u6001\u672A\u66F4\u65B0\uFF0C\u8BF7\u624B\u52A8\u6253\u5F00\u8BE5\u8BB2\u64AD\u653E\u9875\u786E\u8BA4 \xB7 ${t.name}`, "error" ), await y(r); return; } } } } async function ht(e) { let t = await G(e.id); if (!t) throw new Error("\u8BFE\u7A0B\u8BE6\u60C5\u4E3A\u7A7A"); t.courseProgress != null && f(`\u8BFE\u7A0B\u8BE6\u60C5\u603B\u8FDB\u5EA6 ${t.courseProgress}%`, "info"); let r = t.chapter || []; n.queueChapterTotal = r.length, n.queueChapterDone = r.filter((o) => Le(o)).length, re(); let i = Nt(t); if (n.activeCourse = e, i.length) for (let o of i) { if (n.stopFlag) break; await Ht( { ...e, name: e.name || e.title || t.name }, o ); try { let a = await G(e.id), s = a && a.chapter || []; n.queueChapterTotal = s.length || n.queueChapterTotal, n.queueChapterDone = s.filter((l) => Le(l)).length, re(); } catch { n.queueChapterDone = Math.min( n.queueChapterTotal, (n.queueChapterDone || 0) + 1 ), re(); } } else f(`\u7AE0\u8282\u5DF2\u5B66\u5B8C \xB7 ${e.name || e.title}`, "info"); await y(e.id), n.queueChapterTotal = 0, n.queueChapterDone = 0; } var bt = () => { }; function zt(e) { bt = typeof e == "function" ? e : () => { }; } async function wt() { return bt(), { ok: !0, skipped: !0, msg: "\u672C\u5E73\u53F0\u8003\u8BD5\u63A5\u53E3\u5C1A\u672A\u9002\u914D\uFF0C\u5DF2\u8DF3\u8FC7" }; } var J = () => { }, yt = () => { }, jt = () => { }, Me = () => { }; function Ct(e) { e && (e.upd && (J = e.upd), e.hint && (yt = e.hint), e.clear && (jt = e.clear), e.lists && (Me = e.lists)); } async function vt(e) { if (b()) return b(); if (await pe(), b()) return b(); let t = e && e[0] || n.learningCourses[0]; if (!t) throw new Error("\u672A\u767B\u5F55\u6216\u65E0\u6CD5\u8BC6\u522B\u5B66\u5458\u8D26\u53F7"); let i = ((await G(t.id)).chapter || [])[0]; if (!i) throw new Error("\u8BFE\u7A0B\u65E0\u7AE0\u8282\uFF0C\u65E0\u6CD5\u8BC6\u522B\u5B66\u5458\u8D26\u53F7"); let o = await ge(t.id, i.itemId || i.id); if (o.userId && O(o.userId), !b()) throw new Error("\u672A\u80FD\u83B7\u53D6\u5B66\u5458 userId\uFF0C\u8BF7\u624B\u52A8\u6253\u5F00\u4E00\u8282\u8BFE\u540E\u518D\u8BD5"); return b(); } async function Ue() { if (!n.running) { n.running = !0, n.stopFlag = !1, n.pace = j.realtime; try { f("\u5237\u65B0\u8BFE\u7A0B\u5217\u8868\u2026", "info"), await ee(), Me(); let e = D().filter((t) => n.onlyIncomplete ? Ie(t) ? !1 : _(t) < 99.5 : !0); if (!e.length) { f("\u52FE\u9009\u8BFE\u7A0B\u5747\u5DF2\u5B66\u5B8C\uFF0C\u65E0\u9700\u7EE7\u7EED", "info"); return; } await vt(e), await M(!1), f(`\u5F00\u59CB\u987A\u5E8F\u5B66\u4E60 \xB7 ${e.length} \u95E8\u8BFE`, "info"); for (let t of e) { if (n.stopFlag) break; try { await ht(t); } catch (r) { f(`\u65E0\u6CD5\u7EE7\u7EED: ${r.message || r}`, "error"); break; } } n.stopFlag || (f("\u5168\u90E8\u4EFB\u52A1\u5B8C\u6210", "info"), await ee(), Me()); } catch (e) { f(`\u9519\u8BEF: ${e.message || e}`, "error"); } finally { n.running = !1, n.enabled = !1, GM_setValue(g.enabled, !1), Pe(), n.queueChapterTotal = 0, n.queueChapterDone = 0, n.stopFlag || (n.task = "", n.currentCourse = "", n.currentChapter = "", n.activeCourse = null), J(); } } } function _t() { return "1:1 \u65F6\u957F"; } function St() { n.stopFlag = !0, n.enabled = !1, GM_setValue(g.enabled, !1), Pe(), n.queueChapterTotal = 0, n.queueChapterDone = 0, n.task = "\u5DF2\u505C\u6B62", J(), f("\u81EA\u52A8\u770B\u8BFE\u5DF2\u6682\u505C", "info"); } function Et() { if (!(n.running || n.enabled)) { if (n.pace = j.realtime, GM_setValue(g.pace, j.realtime), n.selectMode === "none" || !D().length) { yt("\u8BF7\u5148\u52FE\u9009\u81F3\u5C11\u4E00\u95E8\u8BFE\u7A0B"), J(); return; } jt(), vt(D()).then(() => M(!1)).then(() => { n.enabled = !0, n.stopFlag = !1, GM_setValue(g.enabled, !0), J(), f("\u81EA\u52A8\u770B\u8BFE\u5DF2\u5F00\u542F", "info"), Ue(); }).catch((e) => { f(`\u65E0\u6CD5\u5F00\u59CB: ${e.message || e}`, "error"), J(); }); } } function oe() { q && (q.cloudTier = n.cloudTier, q.freeUsedCourses = n.freeUsedCourses, q.freeCourseLimit = n.freeCourseLimit, q.running = !!(n.running || n.enabled)); } function Tt(e, t) { if (!(!e || !t || typeof t.createPinia != "function")) try { let { createPinia: r, defineStore: i } = t, o = i("xjdxjxjy", { state: () => ({ cloudTier: n.cloudTier, freeUsedCourses: n.freeUsedCourses, freeCourseLimit: n.freeCourseLimit, running: !1 }) }), a = r(), s = e.createApp({ render: () => null }); s.use(a); let l = document.createElement("div"); l.style.display = "none", document.body.appendChild(l), s.mount(l), Ye(o()), oe(); } catch { } } var It = null, kt = null; function Bt() { let e = m("nmg-start"), t = m("nmg-stop"); e && (e.disabled = !!n.enabled || !!n.running, e.classList.toggle("zjzx-btn-off", !!n.enabled || !!n.running)), t && (t.disabled = !n.enabled && !n.running, t.classList.toggle("zjzx-btn-off", !n.enabled && !n.running)); } function qe(e) { n.panelHint = String(e || ""); let t = m("nmg-start-hint"); t && (n.panelHint ? (t.style.display = "", t.textContent = n.panelHint) : (t.style.display = "none", t.textContent = "")); } function be() { qe(""); } function Jt() { let e = D(), t = 0, r = 0, i = 0, o = "\u95E8\u8BFE\u5DF2\u5B8C\u6210"; if ((n.running || n.enabled) && n.queueChapterTotal > 0 && n.activeCourse) t = Math.min(n.queueChapterDone || 0, n.queueChapterTotal), r = n.queueChapterTotal, o = "\u8BB2\u5DF2\u5B8C\u6210", i = r > 0 ? t / r * 100 : 0; else { r = e.length; for (let a of e) { let s = _(a); i += s, s >= 99.5 && (t += 1); } o = "\u95E8\u8BFE\u5DF2\u5B8C\u6210", i = r > 0 ? i / r : 0; } n.queueVideoTotal = r, n.queueVideoDone = t, n.queueExamTotal = 0, n.queueExamDone = 0, n.queueProgressPct = Math.round(Math.min(100, Math.max(0, i))), n.queueMetricLabel = o; } function I() { Jt(); let e = m("nmg-auto-status"); e && (n.running || n.enabled ? (e.textContent = n.running ? "\u8FD0\u884C\u4E2D" : "\u5DF2\u5F00\u542F", e.style.background = "#dcfce7", e.style.borderColor = "#86efac", e.style.color = "#166534") : (e.textContent = "\u5DF2\u505C\u6B62", e.style.background = "#fff", e.style.borderColor = "#cbd5e1", e.style.color = "#334155")); let t = n.queueVideoDone, r = n.queueVideoTotal, i = n.queueProgressPct || 0, o = (c, p) => { let x = m(c); x && (x.textContent = p); }; o("nmg-queue-done", String(t)), o("nmg-queue-total", String(r)), o("nmg-queue-percent", `${i}%`), o("nmg-queue-metric-label", n.queueMetricLabel || "\u95E8\u8BFE\u5DF2\u5B8C\u6210"); let a = m("nmg-queue-progress"); a && (a.style.width = `${i}%`), o("nmg-current-course", R(n.currentCourse || "\u65E0", 28)), o("nmg-current-chapter", R(n.currentChapter || "\u65E0", 28)), o("nmg-current-task", R(n.task || "\u70B9\u5F00\u59CB\u540E\u81EA\u52A8\u63D0\u4EA4", 36)); let s = m("nmg-current-course"), l = m("nmg-current-chapter"), d = m("nmg-current-task"); s && (s.title = n.currentCourse || ""), l && (l.title = n.currentChapter || ""), d && (d.title = n.task || ""); let u = m("nmg-queue-text"); if (u) { let p = D().length; n.selectMode === "none" ? u.textContent = "\u672A\u52FE\u9009\u4EFB\u4F55\u8BFE\u7A0B" : n.selectMode === "all" && n.learningCourses.length ? u.textContent = n.queueChapterTotal > 0 && (n.running || n.enabled) ? `\u5DF2\u9009\u5168\u90E8 ${p} \u95E8 \xB7 ${t}/${r} \u8BB2` : `\u5DF2\u9009\u5168\u90E8 ${p} \u95E8 \xB7 \u8FDB\u5EA6 ${i}%` : u.textContent = p ? n.queueChapterTotal > 0 && (n.running || n.enabled) ? `\u5DF2\u9009 ${p} \u95E8 \xB7 ${t}/${r} \u8BB2` : `\u5DF2\u9009 ${p} \u95E8 \xB7 \u8FDB\u5EA6 ${i}%` : "\u672A\u52FE\u9009\u4EFB\u4F55\u8BFE\u7A0B"; } Bt(), oe(); } function Xt(e) { let t = m("nmg-auto-panel"); t && (t.querySelectorAll(".zjzx-tab-btn").forEach((r) => { r.classList.toggle("active", r.dataset.tab === e); }), t.querySelectorAll(".zjzx-pane").forEach((r) => { r.classList.toggle("active", r.dataset.pane === e); })); } function Ae(e, t) { let r = e.querySelector("#nmg-btn-min"), i = e.querySelector("#nmg-btn-max"); e.classList.toggle("zjzx-panel-min", !!t), e.classList.toggle("zjzx-panel-max", !t), r && (r.style.display = t ? "none" : ""), i && (i.style.display = t ? "" : "none"); } function Yt(e) { let t = e.querySelector("#nmg-panel-header"); if (!t) return; let r = !1, i = 0, o = 0, a = 0, s = 0; t.addEventListener("mousedown", (l) => { if (l.target?.closest("#nmg-panel-controls, .zjzx-panel-ctl")) return; r = !0, i = l.clientX, o = l.clientY; let d = e.getBoundingClientRect(); a = d.left, s = d.top, e.style.right = "auto", e.style.bottom = "auto", l.preventDefault(); }), document.addEventListener("mousemove", (l) => { if (!r) return; let d = Math.max( 0, Math.min(window.innerWidth - e.offsetWidth, a + (l.clientX - i)) ), u = Math.max( 0, Math.min(window.innerHeight - e.offsetHeight, s + (l.clientY - o)) ); e.style.left = `${d}px`, e.style.top = `${u}px`; }), document.addEventListener("mouseup", () => { if (!r) return; r = !1; let l = e.getBoundingClientRect(); de(g.panelPos, { left: l.left, top: l.top }); }); } function Wt(e) { let t = document.createElement("style"); t.textContent = ` :host{all:initial;} #nmg-auto-panel{position:fixed;right:20px;top:80px;z-index:999999;width:412px;display:flex;flex-direction:column;background:#f4f7fb;border:1px solid #dbe4f0;border-radius:16px;box-shadow:0 16px 40px rgba(15,23,42,.17);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"PingFang SC","Microsoft YaHei",sans-serif;font-size:12px;color:#0f172a;overflow:hidden;transition:max-height .22s ease,box-shadow .22s ease;} #nmg-auto-panel.zjzx-panel-max{max-height:min(92vh,780px);} #nmg-auto-panel.zjzx-panel-min{max-height:none;box-shadow:0 10px 28px rgba(15,23,42,.14);} #nmg-auto-panel.zjzx-panel-min #nmg-panel-header{border-bottom:none;} #nmg-auto-panel.zjzx-panel-min #nmg-panel-body,#nmg-auto-panel.zjzx-panel-min #nmg-panel-footer,#nmg-auto-panel.zjzx-panel-min .zjzx-footer-extra{display:none !important;} #nmg-panel-header{flex:0 0 auto;padding:8px 11px;background:linear-gradient(180deg,#f8ecd5,#f4e8cf);border-bottom:1px solid #e5dbc6;display:flex;justify-content:space-between;align-items:center;cursor:move;user-select:none;} #nmg-panel-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding:8px;} .zjzx-footer-extra{flex:0 0 auto;} #nmg-panel-footer{flex:0 0 auto;padding:7px 11px;background:#eef2f7;border-top:1px solid #dbe4f0;font-size:12px;} #nmg-panel-brand{display:flex;align-items:center;gap:9px;min-width:0;flex:1;} #nmg-panel-logo{width:30px;height:30px;border-radius:9px;object-fit:cover;box-shadow:0 2px 9px rgba(15,23,42,.11);border:1px solid rgba(148,163,184,.45);background:#fff;flex:0 0 auto;} #nmg-panel-title{font-size:13px;font-weight:900;color:#9a3412;line-height:1.26;display:flex;align-items:flex-start;gap:5px;flex-wrap:wrap;} .zjzx-panel-title-text{flex:1 1 12em;min-width:0;letter-spacing:-0.01em;} #nmg-panel-sub{display:flex;flex-wrap:wrap;align-items:center;gap:3px 5px;margin-top:3px;line-height:1.32;} .zjzx-sub-chip{font-size:11px;color:#7c2d12;background:rgba(255,255,255,.62);padding:2px 7px;border-radius:999px;border:1px solid rgba(180,83,9,.18);font-weight:700;} .zjzx-sub-chip-em{color:#0f766e;background:rgba(236,253,245,.9);border-color:rgba(15,118,110,.28);} .zjzx-sub-dot{color:#d6d3d1;font-size:10px;font-weight:400;} .zjzx-panel-ctl .zjzx-ctl-ico{display:block;box-sizing:border-box;margin:0 auto;} .zjzx-ctl-min{width:10px;height:2px;background:#64748b;border-radius:1px;} .zjzx-ctl-plus{font-size:16px;line-height:1;font-weight:700;color:#64748b;} .zjzx-panel-version{font-size:11px;font-weight:900;color:#64748b;padding:2px 7px;border-radius:999px;background:#f1f5f9;border:1px solid #e2e8f0;} #nmg-panel-controls{display:flex;align-items:center;gap:5px;flex:0 0 auto;} .zjzx-panel-ctl{border:none;background:#fff;color:#64748b;width:28px;height:28px;border-radius:999px;cursor:pointer;box-shadow:0 1px 2px rgba(15,23,42,.1);font-size:15px;line-height:1;font-weight:900;padding:0;} .zjzx-card{background:#fff;border:1px solid #d9e2ee;border-radius:12px;padding:7px 9px;margin-bottom:7px;} .zjzx-card-status{padding:6px 8px;margin-bottom:6px;} .zjzx-status-row{display:flex;justify-content:space-between;align-items:center;gap:7px;line-height:1.28;} .zjzx-status-label{font-size:11px;color:#64748b;font-weight:700;} .zjzx-status-main{margin-top:3px;} .zjzx-status-metrics{display:flex;align-items:center;gap:5px;font-size:12px;color:#475569;min-width:0;flex:1;} .zjzx-status-metrics em{font-style:normal;font-weight:900;color:#0f172a;} .zjzx-metric-div{color:#cbd5e1;} .zjzx-card-status .zjzx-progress-pct{font-size:14px;font-weight:900;color:#0369a1;flex:0 0 auto;} .zjzx-card-status .zjzx-progress-bar{height:5px;margin-top:4px;margin-bottom:0;} .zjzx-progress-bar{height:9px;border-radius:999px;background:#e2e8f0;overflow:hidden;margin-top:5px;} .zjzx-progress-bar>span{display:block;height:100%;width:0;background:linear-gradient(90deg,#22d3ee,#2563eb);transition:width .2s ease;} .zjzx-list-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;} .zjzx-list-head-actions{display:flex;align-items:center;gap:5px;} .zjzx-log-clear-btn{border:1px solid #cbd5e1;background:#fff;color:#64748b;padding:1px 7px;border-radius:999px;font-size:10px;font-weight:700;cursor:pointer;line-height:1.4;} .zjzx-plan-select{width:100%;border:1px solid #cbd5e1;border-radius:8px;padding:6px 9px;font-size:12px;background:#fff;color:#0f172a;} .zjzx-list-title{font-size:12px;color:#64748b;font-weight:700;} .zjzx-list-tag{font-size:11px;color:#92400e;background:#ffedd5;border:1px solid #fdba74;border-radius:999px;padding:2px 7px;} .zjzx-empty-state{padding:12px 7px;text-align:center;color:#94a3b8;font-size:12px;font-weight:900;} #nmg-course-list,#nmg-completed-list,#nmg-run-log{max-height:188px;overflow-y:auto;background:#f8fafc;border:1px solid #dbe4f0;border-radius:11px;padding:5px;} .zjzx-chapter-course{margin-bottom:7px;border:1px solid #dbe4f0;border-radius:9px;background:#fff;overflow:hidden;} .zjzx-chapter-title{padding:6px 9px;background:#eaf1ff;border-bottom:1px solid #dbe4f0;color:#1d4ed8;font-size:12px;font-weight:700;display:flex;justify-content:space-between;gap:8px;} .zjzx-chapter-item{padding:5px 9px;font-size:12px;display:flex;justify-content:space-between;gap:7px;border-bottom:1px dashed #eef2f7;} .zjzx-chapter-item:last-child{border-bottom:none;} .zjzx-footer-extra{padding:6px 9px;background:#f8fafc;border-top:1px solid #e2e8f0;opacity:.95;} .zjzx-ann{position:relative;font-size:12px;color:#334155;line-height:1.42;background:linear-gradient(180deg,#fffdf5,#fff7e6);border:1px solid #fcd34d;border-radius:11px;padding:8px 9px 8px 11px;margin-bottom:0;} .zjzx-ann-text{display:block;word-break:break-word;} .zjzx-ann::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:linear-gradient(180deg,#f59e0b,#ef4444);border-top-left-radius:11px;border-bottom-left-radius:11px;} .zjzx-qq-row{display:flex;align-items:center;justify-content:space-between;gap:9px;margin-top:5px;} .zjzx-qq-text{font-size:12px;color:#475569;} .zjzx-qq-title{font-size:13px;font-weight:800;color:#0f172a;} .zjzx-qq-btn{border:none;background:linear-gradient(135deg,#1d4ed8,#0ea5e9);color:#fff;padding:5px 12px;border-radius:999px;font-size:12px;font-weight:800;cursor:pointer;} .zjzx-study-mode-hint{margin-top:5px;padding:7px 9px;border-radius:9px;border:1px solid #e2e8f0;font-size:11px;line-height:1.42;} .zjzx-study-mode-hint-title{display:block;font-weight:800;margin-bottom:3px;} .zjzx-study-mode-hint-body{margin:0;color:#475569;} .zjzx-study-mode-hint-efficiency{background:linear-gradient(135deg,#eff6ff,#f0f9ff);border-color:#bfdbfe;color:#1e3a8a;} .zjzx-study-mode-hint-realtime{background:linear-gradient(135deg,#fffbeb,#fef3c7);border-color:#f59e0b;color:#78350f;} .zjzx-start-hint{font-size:11px;color:#b45309;background:#fffbeb;border:1px solid #fcd34d;border-radius:7px;padding:5px 7px;margin-bottom:5px;line-height:1.32;text-align:center;font-weight:600;} .zjzx-tabbar{display:flex;gap:6px;margin-bottom:7px;} .zjzx-tab-btn{flex:1;border:1px solid #cbd5e1;background:#f8fafc;color:#475569;padding:4px 4px;border-radius:9px;cursor:pointer;font-weight:700;font-size:11px;} .zjzx-tab-btn.active{background:linear-gradient(135deg,#1d4ed8,#0ea5e9);color:#fff;border-color:transparent;} .zjzx-pane{display:none;}.zjzx-pane.active{display:block;} .zjzx-btn-row{display:flex;gap:7px;margin-bottom:6px;flex-wrap:wrap;} .zjzx-btn-row-nowrap{flex-wrap:nowrap;} .zjzx-btn{flex:1;border:none;color:#fff;padding:7px 9px;border-radius:10px;cursor:pointer;font-weight:800;font-size:12px;min-width:68px;} .zjzx-btn-action{min-width:0 !important;flex:1 1 0 !important;} .zjzx-btn-ico{font-size:13px;line-height:1;display:inline-flex;align-items:center;margin-right:5px;} .zjzx-btn-label{white-space:nowrap;} .zjzx-btn-start{background:#16a34a;}.zjzx-btn-stop{background:#ef4444;} .zjzx-btn-start.zjzx-btn-off,.zjzx-btn-start:disabled{background:#cbd5e1 !important;color:#64748b !important;cursor:not-allowed;box-shadow:none;pointer-events:none;} .zjzx-btn-stop.zjzx-btn-off,.zjzx-btn-stop:disabled{background:#e2e8f0 !important;color:#94a3b8 !important;cursor:not-allowed;box-shadow:none;pointer-events:none;} .zjzx-btn-ghost{border:1px solid #cbd5e1;background:#fff;color:#0f172a;flex:0 0 auto;} .zjzx-meta-row{display:flex;justify-content:space-between;gap:7px;font-size:12px;margin-bottom:5px;align-items:center;} .zjzx-meta-label{color:#64748b;}.zjzx-meta-value{font-weight:700;text-align:right;} .zjzx-card-current{padding:5px 8px;margin-bottom:6px;} .zjzx-card-current .zjzx-meta-row{font-size:11px;margin-bottom:2px;gap:5px;line-height:1.28;align-items:flex-start;} .zjzx-card-current .zjzx-meta-row:last-child{margin-bottom:0;} .zjzx-card-current .zjzx-meta-label{flex:0 0 auto;font-size:10px;white-space:nowrap;} .zjzx-card-current .zjzx-meta-value{flex:1 1 auto;min-width:0;font-size:11px;font-weight:600;text-align:right;word-break:break-all;line-height:1.28;} .zjzx-card-actions{padding:6px 8px;} .zjzx-study-mode-block{margin-bottom:5px;} .zjzx-study-mode-block .zjzx-study-mode-row{display:flex;align-items:center;gap:5px;margin-bottom:0;} .zjzx-study-mode-block .zjzx-plan-select{flex:1 1 auto;min-width:0;width:auto;padding:3px 22px 3px 7px;font-size:11px;line-height:1.25;border-radius:7px;} #nmg-auto-status{padding:2px 7px;border-radius:999px;font-weight:900;font-size:11px;background:#fff;border:1px solid #cbd5e1;} .zjzx-log-row{padding:4px 6px;border-bottom:1px dashed #d4deea;font-size:12px;line-height:1.42;} .zjzx-log-row.err{color:#b91c1c}.zjzx-log-row.prog{color:#0369a1} .zjzx-settings-check{display:flex;gap:6px;align-items:center;margin:6px 0;font-size:12px;font-weight:700;color:#334155;} .zjzx-pro-banner{margin:0 0 8px;padding:9px 10px;border-radius:11px;background:linear-gradient(135deg,#fff7ed,#fef3c7);border:1px solid #fdba74;} .zjzx-pro-banner-title{font-size:12px;font-weight:900;color:#9a3412;margin-bottom:3px;} .zjzx-pro-banner-desc{font-size:11px;color:#78350f;line-height:1.38;margin-bottom:7px;} .zjzx-btn-pro{display:inline-block;text-decoration:none;background:linear-gradient(135deg,#ea580c,#f59e0b);color:#fff;padding:6px 12px;border-radius:999px;font-size:11px;font-weight:800;} .zjzx-token-input{flex:1;min-width:0;border:1px solid #cbd5e1;border-radius:8px;padding:5px 8px;font-size:12px;} `, e.appendChild(t); } function he() { let e = m("nmg-run-log"); e && H( e, n.logs.slice(0, 80).map((t) => { let r = t.type === "error" ? "err" : t.type === "progress" ? "prog" : "", i = new Date(t.t).toLocaleTimeString(); return `
[${i}] ${C(t.msg)}
`; }).join("") ); } function ze() { let e = m("nmg-course-list"); if (!e) return; let t = n.learningCourses; if (!t.length) { H( e, '
\u6682\u65E0\u5728\u5B66\u8BFE\u7A0B
\u5B66\u5B8C\u540E\u4F1A\u51FA\u73B0\u5728\u300C\u5DF2\u5B66\u8BFE\u7A0B\u300D
' ), I(); return; } let r = n.activeCourse && n.activeCourse.id; H( e, t.map( (i) => ke(i, { checkable: !0, checked: Te(i.id), isActive: i.id === r }) ).join("") ), e.querySelectorAll('input[type="checkbox"]').forEach((i) => { i.addEventListener("change", () => { let o = []; e.querySelectorAll('input[type="checkbox"]').forEach((s) => { s.checked && o.push(s.getAttribute("data-id")); }); let a = n.learningCourses.length; o.length ? o.length === a ? (n.selectMode = "all", n.selectedIds = /* @__PURE__ */ new Set()) : (n.selectMode = "partial", n.selectedIds = new Set(o)) : (n.selectMode = "none", n.selectedIds = /* @__PURE__ */ new Set()), fe(), be(), I(); }); }), I(); } function Re() { let e = m("nmg-completed-list"); if (!e) return; let t = n.completedCourses; if (!t.length) { H( e, `
\u6682\u65E0\u5DF2\u5B66\u8BFE\u7A0B
${n.semester} \u5E74\u5EA6\u5B66\u5B8C\u7684\u8BFE\u7A0B\u4F1A\u663E\u793A\u5728\u6B64
` ); return; } H(e, t.map((r) => ke(r, { completedView: !0 })).join("")); } async function Qt() { await ee(), ze(), Re(), f( `\u5DF2\u5237\u65B0 \xB7 \u5728\u5B66 ${n.learningCourses.length} \u95E8 \xB7 \u5DF2\u5B66 ${n.completedCourses.length} \u95E8`, "info" ), I(); } function Oe(e, t, r) { let i = document.getElementById("nmg-panel-host"); i && i.remove(); let o = document.createElement("div"); o.id = "nmg-panel-host", document.body.appendChild(o); let a = o.attachShadow({ mode: "closed" }); Wt(a); let s = document.createElement("div"); a.appendChild(s), Xe(s); let l = n.remotePanelNotice || He, d = String( typeof GM_info < "u" && GM_info?.script?.version || "" ).trim(), u = document.createElement("div"); u.id = "nmg-auto-panel", u.className = "zjzx-panel-max", u.innerHTML = `
${C(Ve)}v${C(d)}
\u4E00\u952E\u5B8C\u6210\u89C6\u9891\u5B66\u65F6\xB71:1 \u771F\u5B9E\u65F6\u957F\xB7\u7701\u5FC3\u7701\u529B
\u8FD0\u884C\u72B6\u6001 \u5DF2\u505C\u6B62
0/0 \u95E8\u8BFE\u5DF2\u5B8C\u6210
0%
\u52FE\u9009\u8981\u5B66\u7684\u8BFE\u7A0B
\u5728\u5B66
\u767B\u5F55\u540E\u5C06\u81EA\u52A8\u52A0\u8F7D\u8BFE\u7A0B
\u5DF2\u5B66\u8BFE\u7A0B${n.semester} \u5E74\u5EA6
\u6682\u65E0\u5DF2\u5B66\u8BFE\u7A0B
\u8FD0\u884C\u65E5\u5FD7
\u5B9E\u65F6\u65E5\u5FD7
\u6388\u6743
\u4F1A\u5458\u72B6\u6001\u52A0\u8F7D\u4E2D\u2026
\u6FC0\u6D3B\u7801
\u5F53\u524D\u8BFE\u7A0B\u65E0
\u5F53\u524D\u7AE0\u8282\u65E0
\u5F53\u524D\u4EFB\u52A1\u70B9\u5F00\u59CB\u540E\u81EA\u52A8\u63D0\u4EA4
`, s.appendChild(u); let c = Z(g.panelPos, null); c && c.left != null && (u.style.left = `${c.left}px`, u.style.top = `${c.top}px`, u.style.right = "auto"), Ae(u, !!GM_getValue(g.collapsed, !1)), Yt(u), m("nmg-btn-min")?.addEventListener("click", (x) => { x.stopPropagation(), GM_setValue(g.collapsed, !0), Ae(u, !0); }), m("nmg-btn-max")?.addEventListener("click", (x) => { x.stopPropagation(), GM_setValue(g.collapsed, !1), Ae(u, !1); }), u.querySelectorAll(".zjzx-tab-btn").forEach((x) => { x.addEventListener("click", () => Xt(x.dataset.tab)); }), m("nmg-clear-log")?.addEventListener("click", () => { n.logs = [], he(); }), m("nmg-select-all")?.addEventListener("click", tt), m("nmg-deselect-all")?.addEventListener("click", nt), m("nmg-start").addEventListener("click", Et), m("nmg-stop").addEventListener("click", St), m("nmg-join-qq")?.addEventListener("click", () => { try { window.open(Je, "_blank"); } catch { } }); let p = m("nmg-cloud-token"); p && (p.value = n.cloudToken || ""), m("nmg-save-token")?.addEventListener("click", async () => { let x = String(p?.value || "").trim(); n.cloudToken = x, localStorage.setItem(Q, x), te("", 0), n.cloudLease = ""; try { x && await dt(), await M(!0), f("\u6FC0\u6D3B\u7801\u5DF2\u4FDD\u5B58", "info"); } catch (A) { f(`\u4FDD\u5B58\u5931\u8D25: ${A.message || A}`, "error"); } P(); }), m("nmg-clear-token")?.addEventListener("click", async () => { n.cloudToken = "", localStorage.removeItem(Q), te("", 0), n.cloudLease = "", n.cloudTier = "free", p && (p.value = ""); try { await M(!0), f("\u5DF2\u5207\u6362\u4E3A\u514D\u8D39\u7248", "info"); } catch (x) { f(`\u5237\u65B0\u5931\u8D25: ${x.message || x}`, "error"); } P(); }), he(), I(), P(), It = e, kt = t, Tt(It, kt), ft().then(() => pt()).then(() => M(!1).catch(() => { })).then(() => P()).finally(() => { Qt().catch((x) => f(`\u52A0\u8F7D\u8BFE\u7A0B\u5931\u8D25: ${x.message}`, "error")); }); } function Kt() { let e = String(location.pathname || ""); return /\/lms\/web\/course\/view\/?$/i.test(e) || /\/lms\/web\/course\/view\b/i.test(e); } function Zt(e, t, r, i) { window.top === window.self && (Kt() || window[we] || (window[we] = Fe, at(he), lt(oe), gt({ upd: I, exam: wt }), zt(I), Ct({ upd: I, hint: qe, clear: be, modeLbl: _t, lists: () => { ze(), Re(); } }), Ze(() => { be(), ze(), I(); }), et(), n.pace = j.realtime, document.readyState === "loading" ? document.addEventListener( "DOMContentLoaded", () => Oe(e, r, t) ) : Oe(e, r, t), n.enabled && setTimeout(() => Ue(), 1200))); } Zt(Vue, DOMPurify, Pinia, CryptoJS); })(); })(Vue,DOMPurify,Pinia,CryptoJS);