// ==UserScript== // @name 2026暑期教师研修3分钟极速搞定(国家智慧中小学) // @namespace http://tampermonkey.net/qi // @version 1.2.6 // @description 【超多好评推荐】免费、高效、一键开启自动刷课,无需充值。 // @match *://basic.smartedu.cn/* // @match *://https://www.smartedu.cn/* // @match *://https://www.smartedu.cn/jiaoshi/* // @require https://scriptcat.org/lib/637/1.4.6/ajaxHooker.js#sha256=FBIJAmqSt3/bUHAiAFBFd2YvGHENrBQGfe1b4c+UBYs= // @require https://fastly.jsdelivr.net/npm/crypto-js@4.2.0/crypto-js.min.js // @require https://fastly.jsdelivr.net/npm/sweetalert2@11.12.2/dist/sweetalert2.all.min.js // @require https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js // @grant unsafeWindow // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_xmlhttpRequest // @grant GM_info // @grant GM_addStyle // @connect x-study-record-api.ykt.eduyun.cn // @run-at document-end // @license MIT // @tag 国家中小学智慧教育平台 暑期培训 教师研修 自动学习 学习辅助 // ==/UserScript== // ============================================================ const ENCODED_PERMANENT_CODES='WyJLN1M5RDJGNEc4SDkiLCJNM1A1UTZSN1Q5VTIiLCJWMVc0WDVZOFozQTYiLCJCMkM3RTVGOUgxSjQiLCJMNk44TzJQM1M1RDciLCJGM0c2SDlKMks1TTgiLCJOMVE0UjdUM1U2VjkiLCJXMlk1WjhBMUI0QzciLCJENkU5RjJHNUg4SjEiLCJLM0w2TTlOMlA1UTgiXQ==',ENCODED_CODES='eyIyMDI2LTA4LTEyIjp7InRlbXAiOiIwQzI4RDkxRSIsImRhaWx5IjoiMTQyRTAzNTEifSwiMjAyNi0wOC0xMyI6eyJ0ZW1wIjoiOTY3QTY5QjMiLCJkYWlseSI6IjlGRDU2QjAwIn0sIjIwMjYtMDgtMTQiOnsidGVtcCI6IkU4NTQ0OTkxIiwiZGFpbHkiOiIzRjQyNjcxQSJ9LCIyMDI2LTA4LTE1Ijp7InRlbXAiOiJCQ0JDNzkzRCIsImRhaWx5IjoiQkYzRDI1RUUifSwiMjAyNi0wOC0xNiI6eyJ0ZW1wIjoiOEFCNTE4NjYiLCJkYWlseSI6IjJBMkNCNkI5In0sIjIwMjYtMDgtMTciOnsidGVtcCI6IjE1QTlCNTIyIiwiZGFpbHkiOiI1Q0Y0MjgyNSJ9LCIyMDI2LTA4LTE4Ijp7InRlbXAiOiI4RDQ5REY5RiIsImRhaWx5IjoiNTFERDhFQjMifSwiMjAyNi0wOC0xOSI6eyJ0ZW1wIjoiNjlGMEQ2QjMiLCJkYWlseSI6IjBGNEIxNUJCIn0sIjIwMjYtMDgtMjAiOnsidGVtcCI6IjA0Q0M5NzJFIiwiZGFpbHkiOiJGNDc0RURGQiJ9LCIyMDI2LTA4LTIxIjp7InRlbXAiOiIyMUQxMThDMiIsImRhaWx5IjoiN0YwMzU1REQifSwiMjAyNi0wOC0yMiI6eyJ0ZW1wIjoiMjVFQThDMjAiLCJkYWlseSI6IjA5NTU5OEQwIn0sIjIwMjYtMDgtMjMiOnsidGVtcCI6IjQ0OTlCMkFCIiwiZGFpbHkiOiJBRjZDNzgxNSJ9LCIyMDI2LTA4LTI0Ijp7InRlbXAiOiJEOTRBQTM0QyIsImRhaWx5IjoiNEE2MkQ5M0MifSwiMjAyNi0wOC0yNSI6eyJ0ZW1wIjoiOTVBRTNDQzAiLCJkYWlseSI6IkU1NDE5QjhDIn0sIjIwMjYtMDgtMjYiOnsidGVtcCI6IkIxQjZCNzM0IiwiZGFpbHkiOiIzNzZDMTVDRSJ9LCIyMDI2LTA4LTI3Ijp7InRlbXAiOiI2RDI5QjU1MyIsImRhaWx5IjoiRUQxQzQ2QjEifSwiMjAyNi0wOC0yOCI6eyJ0ZW1wIjoiOEU5REQyRjgiLCJkYWlseSI6IjZERTdENjkzIn0sIjIwMjYtMDgtMjkiOnsidGVtcCI6IkE2NDFCMUE0IiwiZGFpbHkiOiI5MkVCNEQ0RiJ9LCIyMDI2LTA4LTMwIjp7InRlbXAiOiI3MjQxQTcyMyIsImRhaWx5IjoiMUI5RUJEMzIifSwiMjAyNi0wOC0zMSI6eyJ0ZW1wIjoiMzdBMjk0RDgiLCJkYWlseSI6IjgyRTk0MEMxIn0sIjIwMjYtMDktMDEiOnsidGVtcCI6IkYxNDcyQkM1IiwiZGFpbHkiOiIwNkQzN0E1OSJ9LCIyMDI2LTA5LTAyIjp7InRlbXAiOiI1ODBFNjNBRiIsImRhaWx5IjoiQzkxQjgyNzQifSwiMjAyNi0wOS0wMyI6eyJ0ZW1wIjoiMkRCODcxOTAiLCJkYWlseSI6Ijc0RkEzNjBFIn0sIjIwMjYtMDktMDQiOnsidGVtcCI6IkM0NjEwRTJCIiwiZGFpbHkiOiJEMDU4QkYxMiJ9LCIyMDI2LTA5LTA1Ijp7InRlbXAiOiI3OTNBQzU0NyIsImRhaWx5IjoiNDE4MkU2OUQifSwiMjAyNi0wOS0wNiI6eyJ0ZW1wIjoiRTA1MkQ3MUMiLCJkYWlseSI6IkE3MzA5RDg1In0sIjIwMjYtMDktMDciOnsidGVtcCI6IjE2OEI0RkEzIiwiZGFpbHkiOiI1QkM3MjQ2MCJ9LCIyMDI2LTA5LTA4Ijp7InRlbXAiOiI5RjI0QTA3NiIsImRhaWx5IjoiMjMwRDFFNDgifSwiMjAyNi0wOS0wOSI6eyJ0ZW1wIjoiNDJENzE4NUUiLCJkYWlseSI6IkI4NkFGNzMxIn0sIjIwMjYtMDktMTAiOnsidGVtcCI6IkE1MTkzQ0YyIiwiZGFpbHkiOiI2RTQxMDVCQyJ9LCIyMDI2LTA5LTExIjp7InRlbXAiOiIwQjczODY0OSIsImRhaWx5IjoiRjM5Q0UyN0EifSwiMjAyNi0wOS0xMiI6eyJ0ZW1wIjoiRDNDNTIwODEiLCJkYWlseSI6IjE1NzY0OUUzIn0sIjIwMjYtMDktMTMiOnsidGVtcCI6IjY3OTBFQjI0IiwiZGFpbHkiOiI4RDJCQzA1RiJ9LCIyMDI2LTA5LTE0Ijp7InRlbXAiOiJCNDFDRjU3QSIsImRhaWx5IjoiMzBFQTZCMTYifSwiMjAyNi0wOS0xNSI6eyJ0ZW1wIjoiOEU2MzdEMDUiLCJkYWlseSI6IkMyNTkwN0FEIn0sIjIwMjYtMDktMTYiOnsidGVtcCI6IjIxRkE1QjlDIiwiZGFpbHkiOiI3QjA0RDgyOSJ9LCIyMDI2LTA5LTE3Ijp7InRlbXAiOiI1Qzg0MTJFNyIsImRhaWx5IjoiRTZBRjMxNTAifSwiMjAyNi0wOS0xOCI6eyJ0ZW1wIjoiRjYwQkQ5MzEiLCJkYWlseSI6IjA4MTdBQzY0In0sIjIwMjYtMDktMTkiOnsidGVtcCI6IjNBNzFDNDY4IiwiZGFpbHkiOiI5NEQyNTNCRiJ9LCIyMDI2LTA5LTIwIjp7InRlbXAiOiJDODJFODA1MyIsImRhaWx5IjoiRDdCMDFFQTYifSwiMjAyNi0wOS0yMSI6eyJ0ZW1wIjoiNzBCNjRBMUQiLCJkYWlseSI6IjRGMzhDOTcyIn0sIjIwMjYtMDktMjIiOnsidGVtcCI6IkU5NUQxRjhCIiwiZGFpbHkiOiJBMjFFNzQwQiJ9LCIyMDI2LTA5LTIzIjp7InRlbXAiOiIxQzQ4QjM3MCIsImRhaWx5IjoiNTY5MzJEQzgifSwiMjAyNi0wOS0yNCI6eyJ0ZW1wIjoiOTIwNTc2QUMiLCJkYWlseSI6IjI4Q0E5MDNFIn0sIjIwMjYtMDktMjUiOnsidGVtcCI6IjRCOTJFMUQ0IiwiZGFpbHkiOiJCQjQ1Rjg2MSJ9LCIyMDI2LTA5LTI2Ijp7InRlbXAiOiJBMTMwNjhDRiIsImRhaWx5IjoiNjU3RTEyOTcifSwiMjAyNi0wOS0yNyI6eyJ0ZW1wIjoiMDRFQURCNTIiLCJkYWlseSI6IkY5Mjc0Q0EwIn0sIjIwMjYtMDktMjgiOnsidGVtcCI6IkRENzQyMzk2IiwiZGFpbHkiOiIxMTBCNjU4QyJ9LCIyMDI2LTA5LTI5Ijp7InRlbXAiOiI2MzE5QzA0QSIsImRhaWx5IjoiOENFMjNGNTUifSwiMjAyNi0wOS0zMCI6eyJ0ZW1wIjoiQjc1RjhFNjEiLCJkYWlseSI6IjNENTBBQjc4In19';globalThis['ENCODED_PERMANENT_CODES']=ENCODED_PERMANENT_CODES;globalThis['ENCODED_CODES']=ENCODED_CODES; // // ============================================================ const PERMANENT_CODES=JSON['parse'](atob(ENCODED_PERMANENT_CODES)),CODES=JSON['parse'](atob(ENCODED_CODES));globalThis['PERMANENT_CODES']=PERMANENT_CODES;globalThis['CODES']=CODES; // // ============================================================ function getTodayStr() { const now = new Date(); const utc8 = new Date(now.getTime() + 8 * 3600 * 1000); const y = utc8.getUTCFullYear(); const m = String(utc8.getUTCMonth() + 1).padStart(2,'0'); const d = String(utc8.getUTCDate()).padStart(2,'0'); return `${y}-${m}-${d}`; } function getDeviceId() { let id = localStorage.getItem('qi_device_id'); if (!id) { id = 'DEV_' + Date.now() + '_' + Math.random().toString(36).substr(2, 12); localStorage.setItem('qi_device_id', id); } return id; } const sleep = (ms) => new Promise(r => setTimeout(r, ms)); // // ============================================================ class AuthManager { constructor() { this.usedCodes = GM_getValue('qi_used_codes', {}); this.permanentBindings = GM_getValue('qi_permanent_bindings', {}); this.currentAuth = GM_getValue('qi_current_auth', null); this.isAuthorized = false; this.authType = null; this.activatedAt = null; this.dailyDate = null; this.countdownInterval = null; this.countdownEl = null; this.onExpireCallback = null; this.todayStr = getTodayStr(); this.deviceId = getDeviceId(); this.validateAuth(); } validateAuth() { if (!this.currentAuth) { this.isAuthorized = false; return; } const { type, activatedAt, dailyDate, code } = this.currentAuth; this.authType = type; this.activatedAt = activatedAt; this.dailyDate = dailyDate; if (type === 'temporary_30min') { if (activatedAt && (Date.now() - activatedAt) < 30 * 60 * 1000) { this.isAuthorized = true; } else { this.isAuthorized = false; this.clearAuth(); } } else if (type === 'daily') { if (dailyDate === this.todayStr) { this.isAuthorized = true; } else { this.isAuthorized = false; this.clearAuth(); } } else if (type === 'permanent') { if (code && this.permanentBindings[code] === this.deviceId) { this.isAuthorized = true; } else { this.isAuthorized = false; this.clearAuth(); } } else { this.isAuthorized = false; } } activate(code) { const raw = code.trim().toUpperCase(); const clean = raw.replace(/[^A-Z0-9]/g, ''); if (this.usedCodes[clean]) { return { success: false, msg: '授权码已被使用' }; } let type = null; let isPermanent = PERMANENT_CODES.includes(clean); if (isPermanent) { if (this.permanentBindings[clean]) { if (this.permanentBindings[clean] !== this.deviceId) { return { success: false, msg: '该永久授权码已被其他设备绑定,无法使用' }; } } else { this.permanentBindings[clean] = this.deviceId; GM_setValue('qi_permanent_bindings', this.permanentBindings); } type = 'permanent'; } else { const today = this.todayStr; if (CODES[today]) { if (CODES[today].temp === clean) { type = 'temporary_30min'; } else if (CODES[today].daily === clean) { type = 'daily'; } } if (!type) { return { success: false, msg: '无效授权码' }; } } this.usedCodes[clean] = true; GM_setValue('qi_used_codes', this.usedCodes); const authData = { type: type, activatedAt: null, dailyDate: null, code: clean }; if (type === 'temporary_30min') authData.activatedAt = Date.now(); else if (type === 'daily') authData.dailyDate = this.todayStr; else if (type === 'permanent') authData.activatedAt = Date.now(); GM_setValue('qi_current_auth', authData); this.currentAuth = authData; this.isAuthorized = true; this.authType = type; this.activatedAt = authData.activatedAt; this.dailyDate = authData.dailyDate; this.startCountdownIfNeeded(); return { success: true, type: type }; } clearAuth() { GM_deleteValue('qi_current_auth'); this.currentAuth = null; this.isAuthorized = false; this.authType = null; this.activatedAt = null; this.dailyDate = null; this.removeCountdownUI(); if (this.countdownInterval) clearInterval(this.countdownInterval); if (this.onExpireCallback) this.onExpireCallback(); } getStatus() { return this.isAuthorized; } getType() { return this.authType; } getRemainingSeconds() { if (this.authType !== 'temporary_30min' || !this.activatedAt) return 0; const elapsed = Date.now() - this.activatedAt; return Math.max(0, Math.floor((30 * 60 * 1000 - elapsed) / 1000)); } createCountdownUI() { if (this.authType !== 'temporary_30min') return; if (document.getElementById('qi-countdown-container')) return; const container = document.createElement('div'); container.id = 'qi-countdown-container'; container.style.cssText = 'position:fixed;top:10px;right:10px;background:rgba(0,0,0,0.8);color:#fff;padding:12px 20px;border-radius:30px;font-family:Microsoft Yahei,sans-serif;font-size:20px;font-weight:bold;z-index:2147483647;box-shadow:0 4px 16px rgba(0,0,0,0.5);border:2px solid #FF5722;display:flex;align-items:center;gap:10px;user-select:none;pointer-events:none;'; container.innerHTML = '30:00剩余'; document.body.appendChild(container); this.countdownEl = document.getElementById('qi-countdown-time'); this.startCountdownTimer(); } startCountdownTimer() { if (this.countdownInterval) clearInterval(this.countdownInterval); this.updateCountdownDisplay(); this.countdownInterval = setInterval(() => this.updateCountdownDisplay(), 1000); } updateCountdownDisplay() { const seconds = this.getRemainingSeconds(); if (!this.countdownEl) return; if (seconds <= 0) { this.countdownEl.textContent = '00:00'; this.clearAuth(); if (window._qiInstance) { window._qiInstance.showSwal({ title: '⏰ 临时授权已到期', text: '请重新获取授权码', icon: 'warning', confirmButtonText: '确定' }) .then(() => window.location.href = 'https://basic.smartedu.cn/training/2026jjsqpx'); } return; } const mins = Math.floor(seconds / 60); const secs = seconds % 60; this.countdownEl.textContent = `${String(mins).padStart(2,'0')}:${String(secs).padStart(2,'0')}`; } removeCountdownUI() { const el = document.getElementById('qi-countdown-container'); if (el) el.remove(); this.countdownEl = null; if (this.countdownInterval) clearInterval(this.countdownInterval); } startCountdownIfNeeded() { if (this.authType === 'temporary_30min') { setTimeout(() => this.createCountdownUI(), 200); } else { this.removeCountdownUI(); } } initOnPageLoad() { if (this.isAuthorized && this.authType === 'temporary_30min') this.createCountdownUI(); this.startCountdownIfNeeded(); } } // // ============================================================ class SmartEduModule { // constructor() { this.authManager = new AuthManager(); this.authorized = this.authManager.getStatus(); this.fullDatas = null; this.resourceMap = new Map(); this.stats = { completedVideos: [], totalDuration: 0, totalCount: 0 }; this.courseId = null; this.targetCredit = 0; this.targetSeconds = 0; this.creditCompleted = 0; this.popupObserver = null; this.keepAliveTimer = null; this.isProcessing = false; this.Swal = unsafeWindow.Swal || window.Swal; this.autoPlayEnabled = false; this.isPlaying = false; this.processedVideos = new WeakSet(); this.popupBlockEnabled = false; this.parseCourseId(); this.freeCourseId = FREE_COURSE_ID; this.pendingAuth = GM_getValue('qi_pending_auth', false); this._freePromptShown = false; this._finished = false; this._autoMode = GM_getValue('qi_auto_mode', false); this._started = false; this._detecting = false; this._homeTimer = null; this._lastJumpedCourse = null; this._lastJumpTime = 0; this._urlCheckTimer = null; this._lastUrl = window.location.href; if (this.authorized) { this.enableUI(); this.authManager.startCountdownIfNeeded(); if (!this.isTrainingHomePage()) { this.popupBlockEnabled = GM_getValue(POPUP_BLOCK_KEY, false); } else { this.popupBlockEnabled = false; } if (this.popupBlockEnabled && !this.isTrainingHomePage()) { this.startPopupObserver(); } } else { this.showUnauthorizedBanner(); this.disableUI(); } window._qiInstance = this; this.authManager.onExpireCallback = () => { this.lockAllFeatures(); this.showUnauthorizedBanner(); }; } // showUnauthorizedBanner() { if (document.getElementById('qi-unauth-banner')) return; const banner = document.createElement('div'); banner.id = 'qi-unauth-banner'; banner.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; z-index: 9999999; background: #d32f2f; color: #fff; text-align: center; padding: 10px 20px; font-size: 16px; font-weight: bold; font-family: 'Microsoft Yahei'; box-shadow: 0 2px 10px rgba(0,0,0,0.3); display: flex; justify-content: center; align-items: center; gap: 20px; flex-wrap: wrap; `; banner.innerHTML = ` ⚠️ 未授权 — 请关注微信公众号“叙言哥哥”发送“授权码”获取免费授权,或先免费学习“学科美育教学改革专题培训”。 `; document.body.appendChild(banner); document.getElementById('qi-free-btn').addEventListener('click', () => { this._autoMode = true; this._started = true; this._finished = false; GM_setValue('qi_auto_mode', true); window.location.href = `https://basic.smartedu.cn/teacherTraining/courseIndex?courseId=${this.freeCourseId}`; }); document.getElementById('qi-auth-btn').addEventListener('click', () => { this.requestAuthorization(); }); } // disableUI() { const btnIds = ['qi-screenshot-btn', 'qi-donate-btn', 'qi-instant-btn']; btnIds.forEach(id => { const btn = document.getElementById(id); if (btn) { btn.style.opacity = '0.5'; btn.style.pointerEvents = 'none'; btn.title = '未授权,暂时不可用'; } }); const autoToggle = document.getElementById('qi-auto-toggle'); if (autoToggle) { autoToggle.disabled = true; autoToggle.checked = false; document.getElementById('qi-auto-status').textContent = '关'; } const popupToggle = document.getElementById('qi-popup-toggle'); if (popupToggle) { popupToggle.disabled = true; popupToggle.checked = false; document.getElementById('qi-popup-status').textContent = '关'; } } // enableUI() { const btnIds = ['qi-guide-btn', 'qi-instant-btn', 'qi-screenshot-btn', 'qi-donate-btn', 'qi-start-btn']; btnIds.forEach(id => { const btn = document.getElementById(id); if (btn) { btn.style.opacity = '1'; btn.style.pointerEvents = 'auto'; btn.title = ''; } }); const autoToggle = document.getElementById('qi-auto-toggle'); if (autoToggle) { autoToggle.disabled = false; autoToggle.checked = this.autoPlayEnabled; } const popupToggle = document.getElementById('qi-popup-toggle'); if (popupToggle) { if (this.isTrainingHomePage()) { popupToggle.disabled = true; popupToggle.checked = false; document.getElementById('qi-popup-status').textContent = '关(强制)'; } else { popupToggle.disabled = false; popupToggle.checked = this.popupBlockEnabled; document.getElementById('qi-popup-status').textContent = this.popupBlockEnabled ? '开' : '关'; } } const banner = document.getElementById('qi-unauth-banner'); if (banner) banner.remove(); this.updateStartButtonVisibility(); } // async requestAuthorization() { try { let result; if (this.Swal) { result = await this.showSwal({ title: '🔐 请输入授权码', html: `
获取授权码请关注微信公众号“叙言哥哥”发送“授权码”即可。
📱 公众号二维码 📱 联系作者(备用)
`, input: 'text', inputPlaceholder: '输入授权码(字母数字)', showCancelButton: true, confirmButtonText: '验证', cancelButtonText: '取消', inputValidator: (value) => { if (!value) return '请输入授权码'; return null; }, preConfirm: (value) => { const result = this.authManager.activate(value); if (!result.success) { this.showSwal({ title: '❌ 激活失败', text: result.msg, icon: 'error', confirmButtonText: '确定' }); return false; } return result; } }); } else { const input = prompt('请输入授权码:'); if (!input) return false; const result = this.authManager.activate(input); if (!result.success) { alert(result.msg); return false; } result.isConfirmed = true; } if (result.isConfirmed) { this.authorized = true; this.enableUI(); this.authManager.startCountdownIfNeeded(); this.showAuthSuccessMessage(result.type); return true; } else { return false; } } catch (e) { console.error('授权出错:', e); return false; } } // showAuthSuccessMessage(type) { let title, text; if (type === 'temporary_30min') { title = '⏳ 30分钟临时授权已生效'; text = '从现在开始倒计时30分钟,页面右上角显示剩余时间,刷新不受影响。'; } else if (type === 'daily') { title = '🎉 恭喜你解锁今日授权'; text = '今日内您可无限使用,明日失效,请及时完成研修。'; } else if (type === 'permanent') { title = '🔓 永久授权已生效'; text = '该码已绑定您的设备,其他设备无法使用。'; } this.showSwal({ title, text, icon: 'success', timer: 3000, showConfirmButton: false }); } // clearAuth() { this.authManager.clearAuth(); this.authorized = false; this.lockAllFeatures(); if (!this.isTrainingHomePage()) { window.location.href = 'https://basic.smartedu.cn/training/2026jjsqpx'; } } // isTrainingHomePage() { const url = window.location.href.split('?')[0]; return url === 'https://basic.smartedu.cn/training/2026jjsqpx'; } // parseCourseId() { const params = new URLSearchParams(window.location.search); const id = params.get('courseId'); if (id && id in COURSE_CREDIT_MAP) { this.courseId = id; this.targetCredit = COURSE_CREDIT_MAP[id]; this.targetSeconds = this.targetCredit * 2700; } else { this.courseId = null; this.targetCredit = 0; this.targetSeconds = 0; } } // showSwal(options) { if (this.Swal) return this.Swal.fire(options); else { if (options.input) { const val = prompt(options.title + '\n' + (options.text || '') + '\n' + (options.inputPlaceholder || '')); if (val === null) return Promise.resolve({ dismiss: 'cancel' }); else return Promise.resolve({ value: val, isConfirmed: true }); } else { alert(options.title + '\n' + (options.text || '')); return Promise.resolve({ isConfirmed: true }); } } } // togglePopupBlock(enabled) { if (this.isTrainingHomePage()) enabled = false; this.popupBlockEnabled = enabled; GM_setValue(POPUP_BLOCK_KEY, enabled); if (enabled && !this.isTrainingHomePage()) { this.startPopupObserver(); } else { if (this.popupObserver) { this.popupObserver.disconnect(); this.popupObserver = null; } } const toggle = document.getElementById('qi-popup-toggle'); if (toggle) { if (this.isTrainingHomePage()) { toggle.disabled = true; toggle.checked = false; document.getElementById('qi-popup-status').textContent = '关(强制)'; } else { toggle.disabled = false; toggle.checked = enabled; document.getElementById('qi-popup-status').textContent = enabled ? '开' : '关'; } } } // dismissAllPopups() { if (!this.popupBlockEnabled) return; const selectors = ['.el-message-box__wrapper', '.el-dialog__wrapper', '.vjs-modal-dialog', '.course-video-reload', '.speed-popup', '[class*="dialog"]', '[class*="modal"]']; const keywords = ["关闭", "取消", "知道了", "确定", "继续", "重播", "再播", "倍速", "暂停学习", "close", "cancel", "我知道了"]; document.querySelectorAll(selectors.join(',')).forEach(el => { if (getComputedStyle(el).display === 'none') return; const closeBtns = el.querySelectorAll('button, div, span, i, a'); for (let btn of closeBtns) { const text = btn.innerText?.trim() || ''; const cls = btn.className?.baseVal || btn.className || ''; if (keywords.some(kw => text.includes(kw)) || /el-message-box__close|el-dialog__close|vjs-close-button|close-btn/i.test(cls)) { if (btn.offsetWidth > 0 && !btn.disabled) { btn.click(); return; } } } el.style.display = 'none'; }); } // startPopupObserver() { if (this.popupObserver) this.popupObserver.disconnect(); this.popupObserver = new MutationObserver(() => { clearTimeout(this._popupTimer); this._popupTimer = setTimeout(() => this.dismissAllPopups(), 100); }); this.popupObserver.observe(document.body, { childList: true, subtree: true }); } // showGuide(force = false) { if (!force && localStorage.getItem('noMoreDialog') === 'true') return; this.showSwal({ title: `📚 使用指南`, html: `
🚀 免费体验流程
1
点击 “免费体验” 按钮(或 “开始自动学习”),自动跳转至 “学科美育教学改革专题培训” 课程,免费获取 3 学时
2
免费体验结束后,弹出授权框,关注微信公众号“叙言哥哥”发送“授权码”获取免费授权,解锁全部课程继续学习。
🛠️ 研修脚本详细操作步骤
1
进入研修主页后,点击左侧 “开始自动学习” 按钮,脚本会弹窗确认,确认后自动检测并跳转学习。
2
每个板块学习时,自动弹窗询问是否 “一键开刷”,确认后刷课并自动轮播。
3
截图分享:点击紫色按钮,截取学习完成截图,可保存或复制。
4
打赏:点击粉色按钮,查看打赏二维码,即可对作者进行打赏。
💡 提示
免费体验全程包含弹窗拦截,与授权后体验完全一致。授权后按顺序学习其余四门必修课程,全部完成后将显示恭喜页面。
`, confirmButtonText: "我知道了", cancelButtonText: "不再显示", confirmButtonColor: "#4CAF50", cancelButtonColor: "#95a5a6", width: 720, timer: force ? undefined : 5000, timerProgressBar: force ? undefined : true, showCloseButton: false }).then((result) => { if (result.dismiss === 'cancel') { localStorage.setItem('noMoreDialog', 'true'); } }); } // onDonateClick() { window.open('https://ibb.co/gFg4YYLx', '_blank'); } // createUI() { const style = document.createElement('style'); style.textContent = ` .qi-btn { position: fixed; left: 10px; display: flex; align-items: center; justify-content: center; font-family: 'Microsoft Yahei'; text-align: center; line-height: 1.2; padding: 0; z-index: 2147483647; border: none; cursor: pointer; transition: transform 0.2s, box-shadow 0.2s, background 0.3s; user-select: none; box-shadow: 0 2px 12px rgba(0,0,0,0.25); width: 70px; height: 70px; border-radius: 50%; font-size: 13px; font-weight: bold; color: #fff; } .qi-btn:hover { transform: scale(1.06); } .qi-btn:active { transform: scale(0.95); } #qi-guide-btn { top: 110px; background: linear-gradient(145deg, #FF6F00, #E65100); box-shadow: 0 4px 14px rgba(255,77,175,0.3); } #qi-instant-btn { top: 195px; background: linear-gradient(145deg, #43A047, #388E3C); box-shadow: 0 4px 16px rgba(76,175,80,0.4); } #qi-instant-btn:disabled { background: #94d3a2; cursor: default; transform: none; box-shadow: none; } #qi-screenshot-btn { top: 280px; background: linear-gradient(145deg, #9C27B0, #6A1B9A); box-shadow: 0 4px 14px rgba(156,39,176,0.3); } #qi-donate-btn { top: 365px; background: linear-gradient(145deg, #FF4081, #C2185B); box-shadow: 0 4px 14px rgba(255,64,129,0.3); } #qi-start-btn { top: 470px; width: 72px; height: 72px; border-radius: 50%; background: linear-gradient(145deg, #FF9800, #E65100); color: #fff; font-size: 12px; font-weight: bold; box-shadow: 0 4px 14px rgba(255,152,0,0.4); line-height: 1.3; border: 2px solid #fff; transition: background 0.3s, border-color 0.3s; display: flex; } #qi-start-btn.active { background: linear-gradient(145deg, #4CAF50, #2E7D32); border-color: #4CAF50; box-shadow: 0 0 20px rgba(76,175,80,0.6); } #qi-start-btn.completed { background: linear-gradient(145deg, #9E9E9E, #616161); border-color: #9E9E9E; box-shadow: none; cursor: default; } .qi-swal-confirm-btn { font-size: 18px !important; padding: 12px 40px !important; } .qi-toggle-wrapper { position: fixed; left: 10px; z-index: 2147483647; display: flex; flex-direction: column; gap: 8px; background: rgba(0,0,0,0.7); padding: 10px 16px; border-radius: 16px; backdrop-filter: blur(8px); color: #fff; font-family: 'Microsoft Yahei'; font-size: 13px; user-select: none; bottom: 30px; } .qi-toggle-item { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-width: 140px; } .qi-toggle-label { display: flex; align-items: center; gap: 6px; white-space: nowrap; } .qi-toggle-switch { position: relative; width: 50px; height: 30px; flex-shrink: 0; } .qi-toggle-switch input { opacity: 0; width: 0; height: 0; } .qi-toggle-slider { position: absolute; cursor: pointer; inset: 0; background: #ccc; transition: 0.3s; border-radius: 30px; } .qi-toggle-slider:before { content: ""; position: absolute; height: 26px; width: 26px; left: 2px; bottom: 2px; background: white; transition: 0.3s; border-radius: 50%; box-shadow: 0 2px 4px rgba(0,0,0,0.2); } .qi-toggle-switch input:checked + .qi-toggle-slider { background: #4cd964; } .qi-toggle-switch input:checked + .qi-toggle-slider:before { transform: translateX(20px); } .qi-toggle-status { font-size: 12px; opacity: 0.8; min-width: 16px; text-align: right; } .qi-toggle-divider { border-top: 1px solid rgba(255,255,255,0.15); margin: 2px 0; } `; document.head.appendChild(style); const btnData = [ { id: 'qi-guide-btn', text: '使用
指南' }, { id: 'qi-instant-btn', text: '一键开刷' }, { id: 'qi-screenshot-btn', text: '截图
分享' }, { id: 'qi-donate-btn', text: '💖
打赏' } ]; btnData.forEach(({id, text}) => { const btn = document.createElement('div'); btn.id = id; btn.className = 'qi-btn'; btn.innerHTML = text; document.body.appendChild(btn); }); const startBtn = document.createElement('div'); startBtn.id = 'qi-start-btn'; startBtn.className = 'qi-btn'; startBtn.innerHTML = '🚀
开始
自动学习'; document.body.appendChild(startBtn); document.getElementById('qi-instant-btn').addEventListener('click', this.onInstantClick.bind(this)); document.getElementById('qi-screenshot-btn').addEventListener('click', this.onScreenshotClick.bind(this)); document.getElementById('qi-guide-btn').addEventListener('click', () => this.showGuide(true)); document.getElementById('qi-donate-btn').addEventListener('click', this.onDonateClick.bind(this)); document.getElementById('qi-start-btn').addEventListener('click', async () => { if (this._finished) { this._finished = false; this._autoMode = true; this._started = true; GM_setValue('qi_auto_mode', true); const btn = document.getElementById('qi-start-btn'); if (btn) { btn.classList.add('active'); btn.style.background = 'linear-gradient(145deg, #4CAF50, #2E7D32)'; btn.innerHTML = '🟢
运行中
点击关闭'; } this.startHomeDetector(); await this.detectAndJump(); return; } if (this._started && this._autoMode) { this._autoMode = false; this._started = false; GM_setValue('qi_auto_mode', false); this.stopHomeDetector(); const btn = document.getElementById('qi-start-btn'); if (btn) { btn.classList.remove('active'); btn.style.background = 'linear-gradient(145deg, #FF9800, #E65100)'; btn.innerHTML = '🚀
开始
自动学习'; } this.showSwal({ title: '⏹️ 已关闭自动学习', icon: 'info', timer: 1500, showConfirmButton: false }); return; } if (!this.isTrainingHomePage()) { const confirmNav = await this.showSwal({ title: '🔁 跳转至研修主页', text: '当前不在研修主页,需要跳转后启动自动学习,是否继续?', icon: 'question', confirmButtonText: '跳转', cancelButtonText: '取消', showCancelButton: true }); if (!confirmNav.isConfirmed) return; this._autoMode = true; this._started = true; this._finished = false; GM_setValue('qi_auto_mode', true); const btn = document.getElementById('qi-start-btn'); if (btn) { btn.classList.add('active'); btn.style.background = 'linear-gradient(145deg, #4CAF50, #2E7D32)'; btn.innerHTML = '🟢
运行中
点击关闭'; } window.location.href = 'https://basic.smartedu.cn/training/2026jjsqpx'; return; } const result = await this.showSwal({ title: '📚 已检测到 2026 暑期教师研修页面', text: '是否开启自动跳转学习?(将先免费学习“学科美育”,完成后需授权继续)', icon: 'info', confirmButtonText: '开启', cancelButtonText: '暂不', showCancelButton: true, reverseButtons: false, allowOutsideClick: false }); if (result.isConfirmed) { this._started = true; this._autoMode = true; this._finished = false; GM_setValue('qi_auto_mode', true); const btn = document.getElementById('qi-start-btn'); if (btn) { btn.classList.add('active'); btn.style.background = 'linear-gradient(145deg, #4CAF50, #2E7D32)'; btn.innerHTML = '🟢
运行中
点击关闭'; } this.startHomeDetector(); await this.detectAndJump(); this.showSwal({ title: '✅ 已启动自动学习', text: '脚本将自动跳转课程并完成,请稍候。', icon: 'success', timer: 2000, showConfirmButton: false }); } }); const toggleWrapper = document.createElement('div'); toggleWrapper.className = 'qi-toggle-wrapper'; toggleWrapper.innerHTML = `
▶️ 自动轮播 ${this.autoPlayEnabled ? '开' : '关'}
🛡️ 弹窗拦截 ${this.popupBlockEnabled ? '开' : '关'}
`; document.body.appendChild(toggleWrapper); const autoToggle = document.getElementById('qi-auto-toggle'); const autoStatus = document.getElementById('qi-auto-status'); autoToggle.addEventListener('change', (e) => { const checked = e.target.checked; this.toggleAutoPlay(checked); autoStatus.textContent = checked ? '开' : '关'; }); const popupToggle = document.getElementById('qi-popup-toggle'); const popupStatus = document.getElementById('qi-popup-status'); if (this.isTrainingHomePage()) { popupToggle.disabled = true; popupToggle.checked = false; popupStatus.textContent = '关(强制)'; toggleWrapper.style.opacity = '0.8'; toggleWrapper.title = '研修首页强制关闭弹窗拦截'; } popupToggle.addEventListener('change', (e) => { const checked = e.target.checked; if (this.isTrainingHomePage()) { e.target.checked = false; popupStatus.textContent = '关(强制)'; this.togglePopupBlock(false); this.showSwal({ title: '⚠️ 研修首页强制关闭', text: '在研修首页无法开启弹窗拦截,请进入课程详情页后操作。', icon: 'warning', timer: 2000, showConfirmButton: false }); return; } this.togglePopupBlock(checked); popupStatus.textContent = checked ? '开' : '关'; }); if (!this.authorized) { this.disableUI(); this.showUnauthorizedBanner(); } else { this.enableUI(); } this.updateStartButtonVisibility(); this.startUrlCheck(); console.log('✅ UI创建完成'); } // lockAllFeatures() { if (this.autoPlayEnabled) this.stopAutoPlay(); if (this.popupBlockEnabled) this.togglePopupBlock(false); this.disableUI(); this.showUnauthorizedBanner(); } // updateStartButtonVisibility() { const btn = document.getElementById('qi-start-btn'); if (!btn) return; btn.style.display = 'flex'; if (this._finished) { btn.className = 'qi-btn completed'; btn.innerHTML = '✅
已完成
点击重置'; btn.style.background = 'linear-gradient(145deg, #9E9E9E, #616161)'; btn.style.borderColor = '#9E9E9E'; btn.style.boxShadow = 'none'; btn.style.cursor = 'pointer'; } else if (this._started && this._autoMode) { btn.className = 'qi-btn active'; btn.innerHTML = '🟢
运行中
点击关闭'; btn.style.background = 'linear-gradient(145deg, #4CAF50, #2E7D32)'; btn.style.borderColor = '#4CAF50'; btn.style.boxShadow = '0 0 20px rgba(76,175,80,0.6)'; btn.style.cursor = 'pointer'; } else { btn.className = 'qi-btn'; btn.innerHTML = '🚀
开始
自动学习'; btn.style.background = 'linear-gradient(145deg, #FF9800, #E65100)'; btn.style.borderColor = '#fff'; btn.style.boxShadow = '0 4px 14px rgba(255,152,0,0.4)'; btn.style.cursor = 'pointer'; } } // startUrlCheck() { if (this._urlCheckTimer) clearInterval(this._urlCheckTimer); this._urlCheckTimer = setInterval(() => { const currentUrl = window.location.href; if (currentUrl !== this._lastUrl) { this._lastUrl = currentUrl; this.parseCourseId(); this.updateStartButtonVisibility(); if (this.isTrainingHomePage() && this._autoMode && !this._finished) { this._started = true; this.startHomeDetector(); this.detectAndJump(); } } }, 500); } // async onScreenshotClick() { if (!this.authorized) { await this.showSwal({ title: '⚠️ 未授权', text: '请先授权', icon: 'warning' }); return; } if (typeof html2canvas === 'undefined') { this.showSwal({ title: '截图库未加载', text: '请刷新页面重试。', icon: 'error' }); return; } const uiElements = document.querySelectorAll('.qi-btn, .qi-toggle-wrapper'); const originalDisplays = []; uiElements.forEach(el => { originalDisplays.push(el.style.display); el.style.display = 'none'; }); try { await sleep(200); const halfHeight = window.innerHeight / 2; const canvas = await html2canvas(document.body, { useCORS: true, scale: 2, allowTaint: false, logging: false, backgroundColor: '#ffffff', x: 0, y: 0, width: window.innerWidth, height: halfHeight }); uiElements.forEach((el, idx) => { el.style.display = originalDisplays[idx] || ''; }); const dataUrl = canvas.toDataURL('image/png'); const result = await this.showSwal({ title: '📸 截图预览(上半部分)', html: `
截图范围:视口上半部分(高度 ${Math.round(halfHeight)}px)
`, showCancelButton: true, confirmButtonText: '💾 保存图片', cancelButtonText: '📋 复制图片', confirmButtonColor: '#4CAF50', cancelButtonColor: '#2196F3', reverseButtons: true, focusConfirm: false, width: 700, showCloseButton: true, closeButtonHtml: '✕', closeButtonColor: '#aaa' }); if (result.isConfirmed) { const link = document.createElement('a'); link.download = `截图分享_${new Date().toISOString().slice(0,19).replace(/[:-]/g, '')}.png`; link.href = dataUrl; link.click(); this.showSwal({ title: '✅ 图片已保存', icon: 'success', timer: 1500, showConfirmButton: false }); } else if (result.dismiss === 'cancel') { try { const blob = await fetch(dataUrl).then(res => res.blob()); await navigator.clipboard.write([ new ClipboardItem({ [blob.type]: blob }) ]); this.showSwal({ title: '✅ 图片已复制', text: '已复制到剪贴板,可直接粘贴(Ctrl+V)', icon: 'success', timer: 2000, showConfirmButton: false }); } catch (err) { this.showSwal({ title: '复制失败', text: '请使用保存功能。', icon: 'error' }); } } } catch (err) { console.error('截图失败:', err); uiElements.forEach((el, idx) => { el.style.display = originalDisplays[idx] || ''; }); this.showSwal({ title: '截图失败', text: err.message || '未知错误', icon: 'error' }); } } // async init() { this.createUI(); if (this.pendingAuth) { GM_deleteValue('qi_pending_auth'); this.pendingAuth = false; const ok = await this.requestAuthorization(); if (ok) { this.enableUI(); this.showSwal({ title: '✅ 授权成功', text: '请再次点击“开始自动学习”以继续学习剩余课程。', icon: 'success' }); } else { this.disableUI(); this.showUnauthorizedBanner(); } } if (this.authorized) { this.enableUI(); console.log('✅ 已授权'); } else { this.showUnauthorizedBanner(); this.disableUI(); } if (typeof ajaxHooker !== 'undefined') { ajaxHooker.filter([{ url: 'fulls.json' }]); ajaxHooker.hook(request => { if (request.url.includes('fulls.json')) { request.response = res => { try { const data = JSON.parse(res.responseText); this.parseFullDatas(data); console.log('📦 捕获到 fulls.json'); } catch(e) { console.error('解析 fulls.json 失败', e); } }; } }); } else { const OriginalXHR = window.XMLHttpRequest; window.XMLHttpRequest = function() { const xhr = new OriginalXHR(); const originalOpen = xhr.open; const originalSend = xhr.send; let requestUrl = ''; xhr.open = function(method, url) { requestUrl = url; return originalOpen.apply(this, arguments); }; xhr.send = function(body) { this.addEventListener('readystatechange', function() { if (this.readyState === 4 && this.status === 200 && requestUrl.includes('fulls.json')) { try { const data = JSON.parse(this.responseText); if (window._qiInstance) { window._qiInstance.parseFullDatas(data); } console.log('📦 [XHR] 捕获到 fulls.json'); } catch(e) {} } }); return originalSend.apply(this, arguments); }; return xhr; }; } this.startKeepAlive(); const pageType = this.getPageType(); console.log('当前页面类型:', pageType); if (pageType === 'courseIndex') { if (this.courseId === this.freeCourseId) { setTimeout(() => { const btn = document.getElementById('qi-instant-btn'); if (btn) btn.click(); }, 2000); } else { if (this.authorized) { const confirmed = await this.showAutoStartPrompt(); if (confirmed) { let btn = document.getElementById('qi-instant-btn'); let retries = 0; while (!btn && retries < 10) { await sleep(300); btn = document.getElementById('qi-instant-btn'); retries++; } if (btn) btn.click(); else this.showSwal({ title: '按钮未找到', text: '未能找到“一键开刷”按钮,请手动点击。', icon: 'warning', timer: 2000, showConfirmButton: false }); } } } } else if (pageType === 'training' && this.authorized && this._autoMode && !this._finished) { this._started = true; this.startHomeDetector(); await this.detectAndJump(); this.updateStartButtonVisibility(); } else if (pageType === 'training' && !this.authorized && this._autoMode) { this.startHomeDetector(); await this.detectAndJump(); } setTimeout(() => { if (!localStorage.getItem('noMoreDialog')) { this.showGuide(false); } }, 3000); const observer = new MutationObserver(() => { this.scanVideos(); }); observer.observe(document.body, { childList: true, subtree: true }); console.log('🚀 脚本已启动(免费美育 + 授权后续)'); } // getPageType() { const path = window.location.pathname; if (path.includes('/training/')) return 'training'; if (path.includes('/courseIndex')) return 'courseIndex'; if (path.includes('/courseDetail')) return 'courseDetail'; return 'other'; } // ==================== startHomeDetector(){if(this._homeTimer)return;this._homeTimer=setInterval(()=>this.detectAndJump(),1e3);setTimeout(()=>this.detectAndJump(),500)} stopHomeDetector(){if(this._homeTimer){clearInterval(this._homeTimer);this._homeTimer=null}} async detectAndJump(){if(!this._autoMode||!this.isTrainingHomePage()||this._detecting)return;this._detecting=true;try{const a=this.scanCourseCards();if(!a||a.length===0){this._detecting=false;return}const b=this.authManager.getStatus();const c=a.find(d=>d.courseId===this.freeCourseId);const e=c&&c.completed;const f=c?c.creditDone:0;const g=e||f>=3;if(!b){if(!g){this.jumpToCourse(this.freeCourseId);this._detecting=false;return}else{if(!this._freePromptShown){this._freePromptShown=true;this.stopHomeDetector();this._autoMode=false;this._started=false;GM_setValue('qi_auto_mode',false);await this.requestAuthorization();if(this.authorized)location.reload()}this._detecting=false;return}}if(g){GM_setValue('qi_free_done',true)}const h=GM_getValue('qi_free_done',false);if(h||g){const i=COURSE_ORDER.filter(j=>j!==this.freeCourseId);const k=i.every(j=>{const l=a.find(m=>m.courseId===j);return l&&l.completed});if(k){this.finishStudy();this._detecting=false;return}for(const j of i){const l=a.find(m=>m.courseId===j);if(!l||!l.completed){if(this._lastJumpedCourse===j&&(Date.now()-this._lastJumpTime)<30000)continue;this.jumpToCourse(j);this._detecting=false;return}}if(i.every(j=>{const l=a.find(m=>m.courseId===j);return l&&l.completed})){this.finishStudy()}this._detecting=false;return}if(!g){this.jumpToCourse(this.freeCourseId);this._detecting=false;return}}catch(n){console.error('检测出错:',n)}finally{this._detecting=false}} scanCourseCards(){const a=document.querySelector('div[class*="index-module_items_"]');if(!a)return null;const b=a.children;const c=[];for(let d of b){const e=this.getCourseIdFromDom(d);if(!e||!ALL_COURSE_IDS.includes(e))continue;const f=this.extractCreditInfo(d);if(!f)continue;const{g,h}=f;const i=g>=h;c.push({courseId:e,creditDone:g,creditRequired:h,completed:i})}return c} getCourseIdFromDom(a){const b=a.querySelector('a[href*="courseId"]');if(b){const c=b.href.match(/courseId=([^&]+)/);if(c)return c[1]}const d=a.getAttribute('data-course-id');if(d)return d;const e=Object.keys(a).find(f=>f.startsWith('__reactFiber'));if(e){let g=a[e];while(g){if(g.key&&ALL_COURSE_IDS.includes(g.key))return g.key;g=g.return}}return null} extractCreditInfo(a){const b=a.innerText||'';let c=b.match(/已认定\s*([\d.]+)\s*\/\s*认定\s*([\d.]+)\s*学时/);if(c){return{done:parseFloat(c[1]),required:parseFloat(c[2])}}c=b.match(/已学习\s*([\d.]+)\s*学时/);if(c){return{done:parseFloat(c[1]),required:3}}c=b.match(/已学习\s*[\d.]+\s*已认定\s*([\d.]+)\s*\/\s*认定\s*([\d.]+)\s*学时/);if(c){return{done:parseFloat(c[1]),required:parseFloat(c[2])}}return null} finishStudy(){if(this._finished)return;this._finished=true;GM_setValue('qi_auto_mode',false);this._autoMode=false;this.stopHomeDetector();if(this.autoPlayEnabled)this.stopAutoPlay();const a='🎊 恭喜您完成 2026 年暑期教师研修培训,祝你假期愉快! 🎊';this.Swal.fire({title:'🎉 研修完成!',html:`
您已按顺序完成全部课程的学习任务,获得相应学时。
${a}
本次研修圆满结束,祝您假期愉快!
`,icon:'success',showConfirmButton:false,showCancelButton:false,background:'linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%)',backdrop:'rgba(0,0,0,0.5)',width:600,padding:'2em',showClass:{popup:'animate__animated animate__fadeInDown'},hideClass:{popup:'animate__animated animate__fadeOutUp'},didOpen:()=>{document.getElementById('qi-thanks-btn').addEventListener('click',()=>{window.open('https://ibb.co/gFg4YYLx','_blank');this.Swal.close()})}}).then(()=>{this.updateStartButtonVisibility()})} jumpToCourse(a){this._lastJumpedCourse=a;this._lastJumpTime=Date.now();window.location.href=`https://basic.smartedu.cn/teacherTraining/courseIndex?courseId=${a}`} checkCreditCompletion(){if(this.targetSeconds>0&&this.stats.totalDuration>=this.targetSeconds){if(this.courseId===this.freeCourseId){GM_setValue('qi_free_done',true);this.stopAutoPlay();if(this.authorized){this.showSwal({title:'🎉 学科美育板块已完成',text:'即将返回研修主页,继续学习其余课程。',icon:'success',timer:2000,showConfirmButton:false}).then(()=>{window.location.href='https://basic.smartedu.cn/training/2026jjsqpx'})}else{this.stopHomeDetector();this._autoMode=false;this._started=false;GM_setValue('qi_auto_mode',false);this.authManager.clearAuth();GM_setValue('qi_pending_auth',true);this.showSwal({title:'🎉 免费体验结束',text:'您已完成“学科美育”3学时学习,如需继续其余课程,请获取授权码。',icon:'info',timer:2000,showConfirmButton:false}).then(()=>{window.location.href='https://basic.smartedu.cn/training/2026jjsqpx'})}return}else{this.stopAutoPlay();this.showSwal({title:'🎉 板块学时已达标',text:`已完成 ${(this.stats.totalDuration/2700).toFixed(3)} / ${this.targetCredit} 学时,即将返回研修主页。`,icon:'success',timer:3000,showConfirmButton:false}).then(()=>{if(this.popupBlockEnabled)this.togglePopupBlock(false);window.location.href='https://basic.smartedu.cn/training/2026jjsqpx'})}}} async expandAllMenus(a=30){let b=0;while(bd.click());b++;await sleep(1200)}} async startAutoPlay(){if(this.autoPlayEnabled)return;if(!this.authorized&&this.courseId!==this.freeCourseId)return;this.autoPlayEnabled=true;this.isPlaying=false;this.resetStats();if(!this.isTrainingHomePage()){this.togglePopupBlock(true)}const a=document.getElementById('qi-auto-toggle');if(a)a.checked=true;document.getElementById('qi-auto-status').textContent='开';await this.expandAllMenus();this.scanVideos();this.playFirstUnfinished()} async doubleStartAutoPlay(){if(!this.authorized&&this.courseId!==this.freeCourseId)return;if(this.autoPlayEnabled){this.stopAutoPlay();await sleep(300)}await this.startAutoPlay();await sleep(800);this.stopAutoPlay();await sleep(300);await this.startAutoPlay()} stopAutoPlay(){this.autoPlayEnabled=false;if(!this.isTrainingHomePage()){this.togglePopupBlock(false)}const a=document.getElementById('qi-auto-toggle');if(a)a.checked=false;document.getElementById('qi-auto-status').textContent='关'} toggleAutoPlay(a){if(!this.authorized&&this.courseId!==this.freeCourseId){this.showSwal({title:'⚠️ 未授权',text:'请先授权',icon:'warning'});return}if(a)this.doubleStartAutoPlay();else this.stopAutoPlay()} playFirstUnfinished(){let a=document.querySelectorAll('.resource-item.resource-item-train');if(!a||a.length===0){a=document.querySelectorAll('.video-item, .course-video-list li, [class*="video"]')}if(!a||a.length===0){setTimeout(()=>this.playFirstUnfinished(),3000);return}const b=this.courseId===SCIENCE_COURSE_ID;let c=b?SCIENCE_SKIP_COUNT:0;if(b&&a.length<=SCIENCE_SKIP_COUNT)c=0;for(let d=c;d{if(!this.processedVideos.has(a)){this.autoJumpVideo(a)}})} autoJumpVideo(a){if(this.processedVideos.has(a))return;this.processedVideos.add(a);if(a.readyState<2){a.addEventListener('loadedmetadata',()=>this.doJump(a),{once:true})}else{this.doJump(a)}} doJump(a){const b=a.duration;if(!b||isNaN(b)||b===Infinity){setTimeout(()=>{if(a.duration&&isFinite(a.duration))this.doJump(a)},500);return}if(b<10){let c=this.generateVideoId(a);let d=this.getVideoName(a,c);if(!c)c=`vid_${b}_${Date.now()}_${Math.random().toString(36).substr(2,6)}`;if(!this.isVideoCompleted(c)){this.addCompletedVideo(c,b,d)}setTimeout(()=>{this.playNextVideo()},1500);return}const e=Math.max(0,b-3);a.currentTime=e;a.muted=true;a.playbackRate=2;a.play().catch(()=>{});if(!a._pauseIntercepted){const f=a.pause;a.pause=function(){if(this.currentTime{});return}return f.apply(this,arguments)};a._pauseIntercepted=true}let c=this.generateVideoId(a);let d=this.getVideoName(a,c);if(!c)c=`vid_${b}_${Date.now()}_${Math.random().toString(36).substr(2,6)}`;if(this.isVideoCompleted(c))return;let g=false;let h=null;const i=()=>{if(h)clearTimeout(h);h=setTimeout(()=>{if(g)return;g=true;a.removeEventListener('ended',j);a.removeEventListener('timeupdate',j);const k=Math.min(a.currentTime+3,b);this.addCompletedVideo(c,k,d);setTimeout(()=>{this.playNextVideo()},1500)},7000)};const j=()=>{if(g)return;const k=a.duration-a.currentTime;if(k<=1.0||a.ended){g=true;if(h)clearTimeout(h);a.removeEventListener('ended',j);a.removeEventListener('timeupdate',j);this.addCompletedVideo(c,b,d);setTimeout(()=>{this.playNextVideo()},3000)}};a.addEventListener('ended',j);a.addEventListener('timeupdate',j);i()} getVideoName(a,b){let c=null;if(b&&this.resourceMap.has(b)){c=this.resourceMap.get(b).name}else{let d=a.closest('[data-title], .video-title, .course-name, [class*="title"]');if(d){c=d.dataset.title||d.innerText.trim()||null}else{const e=document.querySelector('.video-title, .course-name, h1, h2');if(e)c=e.innerText.trim()}if(!c)c='未命名视频'}return c} generateVideoId(a){let b=a.closest('[data-resource-id]');if(b){const c=b.dataset.resourceId;if(c&&this.resourceMap.has(c))return c}let d=a.src||a.currentSrc||'';if(d&&!d.startsWith('blob:')){const e=d.match(/[\/?]resourceId=([^&]+)/);if(e)return e[1]}try{if(unsafeWindow.p&&unsafeWindow.p.itemId){const e=unsafeWindow.p.itemId;if(this.resourceMap.has(e))return e}}catch(f){}const g=new URLSearchParams(location.search);if(g.get('videoId')){const e=g.get('videoId');if(this.resourceMap.has(e))return e}return null} playNextVideo(){const a=["下一节","下一课","下一集","下一页","next","下一章"];const b=document.querySelectorAll('button, a, div, span');for(let c of b){const d=c.innerText.trim();if(a.some(e=>d.includes(e))&&c.offsetWidth>0&&!c.disabled){c.click();return true}}const f=document.querySelectorAll('.resource-item.resource-item-train');let g=false;for(let h=0;h10&&a.currentTime<5&&!a.ended){a.currentTime=Math.max(0,a.duration-3);a.play().catch(()=>{})}if(a.paused&&!a.ended)a.play().catch(()=>{});if(!a._pauseIntercepted){const b=a.pause;a.pause=function(){if(this.currentTime{});return}return b.apply(this,arguments)};a._pauseIntercepted=true}} startKeepAlive(){if(this.keepAliveTimer)clearInterval(this.keepAliveTimer);this.keepAliveTimer=setInterval(()=>this.maintainVideo(),1500)} resetStats(){this.stats.completedVideos=[];this.stats.totalDuration=0;this.stats.totalCount=0;this.creditCompleted=0} isVideoCompleted(a){return this.stats.completedVideos.includes(a)} addCompletedVideo(a,b,c){if(this.isVideoCompleted(a))return false;this.stats.completedVideos.push(a);this.stats.totalDuration+=b;this.stats.totalCount++;this.creditCompleted=this.stats.totalDuration/2700;this.showDanmaku(c,b);this.checkCreditCompletion();return true} showDanmaku(a,b){const c=this.stats.totalDuration;const d=Math.floor(c/60);const e=Math.floor(d/60);let f=e>0?`${e}小时${d%60}分钟`:`${d}分钟`;const g=this.creditCompleted;const h=this.targetCredit;const i=h>0?`${g.toFixed(3)}/${h} 学时`:`${g.toFixed(3)} 学时`;const j=document.createElement('div');j.style.cssText='position:fixed;right:-650px;top:20%;transform:translateY(-50%);background:rgba(0,0,0,0.88);color:#fff;padding:18px 28px;border-radius:14px;font-family:\'Microsoft Yahei\';font-size:17px;line-height:1.8;z-index:9999999;box-shadow:0 6px 28px rgba(0,0,0,0.6);border-left:6px solid #4CAF50;white-space:nowrap;transition:right 0.7s cubic-bezier(0.34,1.56,0.64,1);pointer-events:none;user-select:none;letter-spacing:0.5px;';j.innerHTML=`
已完成:${a}
累计看时 ${f} | 约 ${i} | 已看 ${this.stats.totalCount} 个视频
`;document.body.appendChild(j);setTimeout(()=>{j.style.right='20px'},150);setTimeout(()=>{j.style.right='-650px';setTimeout(()=>{if(j.parentNode)j.remove()},700)},5500)} async showAutoStartPrompt(){return new Promise((a)=>{let b=null;let c=3;const d='qi-countdown';const e=`
是否自动开启一键开刷功能?
将在 3 秒后自动开启
(需要时可自动开启)
`;this.Swal.fire({title:'即将开启一键开刷功能',html:e,confirmButtonText:'好的',cancelButtonText:'暂时不需要',showCancelButton:true,reverseButtons:true,focusConfirm:false,allowOutsideClick:false,allowEscapeKey:false,willOpen:()=>{const f=document.getElementById(d);const g=setInterval(()=>{c--;if(f)f.textContent=c;if(c<=0){clearInterval(g);this.Swal.clickConfirm()}},1000);b=g},willClose:()=>{if(b)clearInterval(b)}}).then((f)=>{a(f.isConfirmed)})})} // ========== API 请求与上报 ========== // parseFullDatas(data) { this.fullDatas = data; this.resourceMap.clear(); if (!data || !data.nodes) return; const traverse = (node) => { if (node.node_type === 'catalog' && node.child_nodes) { node.child_nodes.forEach(child => traverse(child)); } else if (node.node_type === 'activity') { const resources = node.relations?.activity?.activity_resources || []; resources.forEach(resource => { const resId = resource.resource_id; if (resId) { this.resourceMap.set(resId, { name: node.node_name || '未命名课程', duration: resource.study_time || 0 }); } }); } }; data.nodes.forEach(node => traverse(node)); } // getResourceList() { const result = []; for (let [id, info] of this.resourceMap) { result.push({ resource_id: id, name: info.name, studyTime: info.duration }); } return result; } // getDynamicToken() { try { const pattern = /^ND_UC_AUTH-([0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12})&ncet-xedu&token$/; for (let key of Object.keys(localStorage)) { if (pattern.test(key)) { return { key: key, appId: key.match(pattern)[1], token: JSON.parse(JSON.parse(localStorage.getItem(key)).value) }; } } throw Error("未找到登录 Token"); } catch (err) { throw Error("获取 Token 失败: " + err.message); } } // getMACAuthorizationHeaders(url, method) { let n = this.getDynamicToken().token; return this.He(url, method, { accessToken: n.access_token, macKey: n.mac_key, diff: n.diff }); } // Ze(e) { var t = "0123456789ABCDEFGHIJKLMNOPQRTUVWXZYS".split(""); var n = ""; for (var r = 0; r < e; r++) n += t[Math.floor(t.length * Math.random())]; return n; } // Fe(e) { return (new Date).getTime() + parseInt(e, 10) + ":" + this.Ze(8); } // ze(e, t, n, r) { let o = { relative: new URL(e).pathname, authority: new URL(e).hostname }; let i = t + "\n" + n.toUpperCase() + "\n" + o.relative + "\n" + o.authority + "\n"; return CryptoJS.HmacSHA256(i, r).toString(CryptoJS.enc.Base64); } // He(e) { let t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "GET", n = arguments.length > 2 ? arguments[2] : void 0, r = n.accessToken, o = n.macKey, i = n.diff, s = this.Fe(i), a = this.ze(e, s, t, o); return 'MAC id="'.concat(r, '",nonce="').concat(s, '",mac="').concat(a, '"'); } // async setProgressWithRetry(url, duration, retries = 3) { let lastError; let delay = 500; for (let attempt = 1; attempt <= retries; attempt++) { try { const result = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ url: url, method: 'PUT', headers: { "accept": "application/json, text/plain, */*", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "authorization": this.getMACAuthorizationHeaders(url, 'PUT'), "cache-control": "no-cache", "pragma": "no-cache", "content-type": "application/json", "sdp-app-id": this.getDynamicToken().appId, "sec-ch-ua": "\"Not A(Brand\";v=\"8\", \"Chromium\";v=\"132\", \"Microsoft Edge\";v=\"132\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"Windows\"", "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "cross-site", "host": "x-study-record-api.ykt.eduyun.cn", "origin": "https://basic.smartedu.cn", "referer": "https://basic.smartedu.cn/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0" }, data: JSON.stringify({ position: Math.max(0, duration - 3) }), onload: function (res) { if (res.status === 200) resolve(res); else reject(new Error('服务器返回 ' + res.status)); }, onerror: function (err) { reject(new Error('请求失败: ' + err)); } }); }); console.log(`✅ 刷课成功 (尝试 ${attempt})`); return result; } catch (err) { lastError = err; console.warn(`⏳ 请求失败 (尝试 ${attempt}/${retries}),${err.message}`); if (attempt < retries) { await sleep(delay); delay *= 2; } } } throw new Error(`重试 ${retries} 次后仍失败: ${lastError.message}`); } // async onInstantClick() { if (!this.authorized && this.courseId !== this.freeCourseId) { this.showSwal({ title: '⚠️ 未授权', text: '请先完成免费课程或输入授权码', icon: 'warning' }); return; } if (this.isProcessing) { this.showSwal({ title: '操作进行中', text: '正在刷课中,请勿重复点击!', icon: 'warning' }); return; } try { this.isProcessing = true; const btn = document.getElementById('qi-instant-btn'); if (btn) { btn.disabled = true; btn.innerHTML = '刷课中...'; } this.resetStats(); let resources = this.getResourceList(); let waitCount = 0; while (resources.length === 0 && waitCount < 10) { await sleep(500); resources = this.getResourceList(); waitCount++; } if (resources.length === 0) { this.showSwal({ title: '未找到视频资源', text: '请确保已进入课程详情页并刷新页面。', icon: 'info' }); return; } const totalDuration = resources.reduce((acc, item) => acc + (item.studyTime || 0), 0); const totalCredit = totalDuration / 2700; const totalMinutes = Math.floor(totalDuration / 60); const totalHours = Math.floor(totalMinutes / 60); let totalTimeStr = ''; if (totalHours > 0) totalTimeStr = `${totalHours}小时${totalMinutes % 60}分钟`; else totalTimeStr = `${totalMinutes}分钟`; const token = this.getDynamicToken(); const allResults = []; for (let i = 0; i < resources.length; i++) { const item = resources[i]; console.log(`⏳ 处理 (${i+1}/${resources.length}): ${item.name}`); try { const url = "https://x-study-record-api.ykt.eduyun.cn/v1/resource_learning_positions/" + item.resource_id + '/' + token.token.user_id; await this.setProgressWithRetry(url, item.studyTime, 3); allResults.push({ name: item.name, status: 'success', duration: item.studyTime }); } catch (err) { console.error(`${item.name} 失败!`, err); allResults.push({ name: item.name, status: 'fail', error: err.message, duration: item.studyTime }); } } const successCount = allResults.filter(r => r.status === 'success').length; const failCount = allResults.filter(r => r.status === 'fail').length; const listHtml = allResults.map(result => { const dur = result.duration || 0; const minutes = Math.floor(dur / 60); const seconds = Math.round(dur % 60); const durationStr = `${minutes}分${seconds}秒`; const icon = result.status === 'success' ? '✅' : '❌'; const errorMsg = result.error ? ` — ${result.error}` : ''; return `
  • ${icon} ${result.name} (${durationStr}) ${errorMsg}
  • `; }).join(''); const result = await this.showSwal({ title: '✅ 本板块刷课完成', html: `

    视频总数:${resources.length}

    成功:${successCount} 个

    失败:${failCount} 个

    板块总时长:${totalTimeStr}

    📊 板块总预估学时:${totalCredit.toFixed(3)} 学时


      ${listHtml}
    ⏳ 1.5秒后即将开启自动轮播...
    `, icon: successCount === resources.length ? 'success' : 'warning', confirmButtonText: '好的', cancelButtonText: '我不需要', showCancelButton: true, reverseButtons: true, focusConfirm: false, customClass: { confirmButton: 'qi-swal-confirm-btn' }, willOpen: () => { setTimeout(() => { this.Swal.clickConfirm(); }, 1500); } }); if (result.isConfirmed) { await this.doubleStartAutoPlay(); } } catch (e) { console.error(e); this.showSwal({ title: '刷课失败', text: e.message || '异常,请刷新重试。', icon: 'error' }); } finally { this.isProcessing = false; const btn = document.getElementById('qi-instant-btn'); if (btn) { btn.disabled = false; btn.innerHTML = '一键开刷'; } } } } // // ============================================================ // 配置常量(课程ID、学分映射等) // ============================================================ // const POPUP_BLOCK_KEY = 'qi_popup_block_enabled'; const COURSE_ORDER = [ '6a46308e-17ff-456a-a320-b5bdb494e93d', '79d28f6c-0b8a-443d-bdda-a78165c462f3', '165d9433-5486-43e4-926e-3f33b92635e4', 'b2ec4202-c747-4ad2-a1b1-35a6c277c856', 'ca2a448a-5ff5-4183-92c2-6506f6696228' ]; const ALL_COURSE_IDS = COURSE_ORDER; const COURSE_CREDIT_MAP = { '6a46308e-17ff-456a-a320-b5bdb494e93d': 3, '79d28f6c-0b8a-443d-bdda-a78165c462f3': 2, '165d9433-5486-43e4-926e-3f33b92635e4': 3, 'b2ec4202-c747-4ad2-a1b1-35a6c277c856': 1, 'ca2a448a-5ff5-4183-92c2-6506f6696228': 1 }; const SCIENCE_COURSE_ID = 'b2ec4202-c747-4ad2-a1b1-35a6c277c856'; const SCIENCE_SKIP_COUNT = 6; const FREE_COURSE_ID = '6a46308e-17ff-456a-a320-b5bdb494e93d'; // // ============================================================ // 启动代码(IIFE 调用) // ============================================================ // (async function() { const instance = new SmartEduModule(); instance.authManager.initOnPageLoad(); await instance.init(); })(); //