// ==UserScript== // @name 绵阳人社继续教育 - 自动学习 // @namespace https://rsjapp.mianyang.cn/ // @version 1.1 // @description 登录后自动完成视频学习 // @description 脚本定制qq1915455753 // @author Marvis // @match https://rsjapp.mianyang.cn/jxjy/pc/zxxx_* // @grant GM_addStyle // @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js // ==/UserScript== (function () { 'use strict'; const AES_KEY = CryptoJS.enc.Utf8.parse('123456ABCDEABCDE'); const ENCODE_KEY = '6e3f7bb708ff1ba0564e8264d8c7bedb4031af2580b8b8eac94088c055b51d8db74a6dcef6df7740cb6aaa9dd442d5a77111b21173b377b0467982ad30a180e631670b4aa8f56d69df9c6b58be747e29e7f6ccbb843a27be9833505105e218741792a1eed34cefec23539825a7f3a0b3a4aaa8a98cd44a6ca5a92474d631fb14'; const API_BASE = '/jxjy/pc/lcService/getData'; // ==================== AES ==================== function aesEncrypt(v) { if (v == null) v = 'undefined'; const e = CryptoJS.AES.encrypt( CryptoJS.enc.Utf8.parse(encodeURIComponent(String(v))), AES_KEY, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 } ); return e.ciphertext.toString(CryptoJS.enc.Base64); } function aesDecrypt(b64) { if (!b64) return null; try { while (b64.length % 4) b64 += '='; const d = CryptoJS.AES.decrypt(b64, AES_KEY, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); const t = d.toString(CryptoJS.enc.Utf8); const s = t.indexOf('{'), e = t.lastIndexOf('}'); return s >= 0 && e > s ? JSON.parse(t.slice(s, e + 1)) : t; } catch (e) { return null; } } function buildData(p) { return Object.entries(p).map(([k, v]) => k + '=' + encodeURIComponent(aesEncrypt(v))) .concat('encodeKey=' + encodeURIComponent(ENCODE_KEY)).join('&'); } async function apiPost(url, params) { const r = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest' }, body: buildData(params), credentials: 'include', }); const body = (await r.text()).trim().replace(/^"|"$/g, ''); return aesDecrypt(body); } // ==================== UI ==================== GM_addStyle(` #mys-panel{position:fixed;top:10px;right:10px;z-index:99999;width:300px; background:#fff;border-radius:8px;box-shadow:0 4px 20px rgba(0,0,0,.25); font:13px "Microsoft YaHei",sans-serif;} #mys-panel .hd{background:#2c3e50;color:#fff;padding:10px 14px;border-radius:8px 8px 0 0; font-size:14px;font-weight:bold;cursor:move;} #mys-panel .bd{padding:10px 14px 14px;} #mys-panel .btn{display:block;width:100%;padding:8px;border:none;border-radius:4px; font-size:14px;font-weight:bold;color:#fff;cursor:pointer;background:#27ae60;} #mys-panel .btn:disabled{background:#95a5a6;cursor:not-allowed;} #mys-panel .bar-wrap{margin-top:8px;height:8px;background:#ecf0f1;border-radius:4px;overflow:hidden;} #mys-panel .bar-inner{height:100%;background:#3498db;width:0;transition:width .3s;} #mys-panel .info{margin-top:6px;font-size:12px;color:#888;} #mys-panel .log{margin-top:8px;max-height:160px;overflow-y:auto;background:#1e1e1e; color:#d4d4d4;padding:8px;border-radius:4px;font:11px Consolas,monospace;white-space:pre-wrap;} #mys-toggle{position:fixed;top:10px;right:10px;z-index:99998;background:#2c3e50; color:#fff;border:none;padding:6px 12px;border-radius:4px;cursor:pointer;display:none;} `); const panel = document.createElement('div'); panel.id = 'mys-panel'; panel.innerHTML = `
绵阳人社 · 自动学习 _
`; document.body.appendChild(panel); const toggle = document.createElement('button'); toggle.id = 'mys-toggle'; toggle.textContent = '显示面板'; toggle.onclick = () => { panel.querySelector('.bd').style.display = ''; toggle.style.display = 'none'; }; document.body.appendChild(toggle); document.getElementById('mys-min').onclick = () => { panel.querySelector('.bd').style.display = 'none'; toggle.style.display = ''; }; // ==================== 日志 & 进度 ==================== const $ = id => document.getElementById(id); function log(msg) { const el = $('mys-log'); el.textContent += msg + '\n'; el.scrollTop = el.scrollHeight; } function setProgress(cur, total) { $('mys-bar').style.width = total ? Math.round(cur / total * 100) + '%' : '0%'; $('mys-info').textContent = `进度: ${cur}/${total}`; } const sleep = ms => new Promise(r => setTimeout(r, ms)); // ==================== 主流程 ==================== async function run() { const btn = $('mys-start'); btn.disabled = true; btn.textContent = '运行中...'; $('mys-log').textContent = ''; // 从页面获取课程ID和用户ID const adz280 = location.href.match(/adz280=([a-f0-9]+)/)?.[1]; // 自动获取 aac001:先无参请求 myd003,从响应中提取 let aac001 = null; try { const r0 = await apiPost(API_BASE + '/myd003.do', { adz280 }); // 尝试从响应中提取用户ID(可能在 resultData 或 data 字段中) const data = r0?.resultData?.data?.data; if (data) { aac001 = data.aac001 || data.userId || data.user_id || data.uid; } // 如果目录中有 aac001 字段也可以提取 if (!aac001 && data?.directory?.[0]) { aac001 = data.directory[0].aac001; } } catch (e) {} // 如果自动获取不到,弹窗让用户输入 if (!aac001) { aac001 = prompt('请输入用户ID (aac001),可从页面源码中查找:'); if (!aac001) { log('未输入用户ID'); btn.disabled = false; btn.textContent = '开始学习'; return; } } log(`用户ID: ${aac001}`); log('='.repeat(50)); log('获取视频列表...'); const r = await apiPost(API_BASE + '/myd003.do', { adz280, aac001 }); if (!r?.resultData) { log('获取失败,请确认已登录'); btn.disabled = false; btn.textContent = '开始学习'; return; } const dir = r.resultData.data.data.directory; const total = dir.length; let done = dir.filter(v => v.videoOver === '1').length; log(`共 ${total} 个视频,已完成 ${done},待完成 ${total - done}`); let processed = 0; const remaining = total - done; while (processed < remaining) { const r2 = await apiPost(API_BASE + '/myd003.do', { adz280, aac001 }); const dir2 = r2.resultData.data.data.directory; let v = null, idx = 0; for (let j = 0; j < dir2.length; j++) { if (dir2[j].videoOver !== '1') { v = dir2[j]; idx = j; break; } } if (!v) { log('所有视频已完成!'); break; } log(`[${idx + 1}/${total}] ${v.adz125}`); setProgress(processed, remaining); // 获取时长 const r4 = await apiPost(API_BASE + '/myd004.do', { adz290: v.adz290, aac001, adz127: 'undefined' }); let dur = 3600, fresh = true; if (r4?.resultData) { const d = r4.resultData.data.data?.old_time; if (d && parseFloat(d) > 0) { dur = parseFloat(d); fresh = false; } } log(` 时长: ${Math.round(dur)}s (${fresh ? '新视频' : '有进度'})`); // 上报进度(新视频分6次递增) if (fresh) { for (let s = 1; s <= 6; s++) { await apiPost(API_BASE + '/myd007.do', { adz290: v.adz290, aac001, adz341: String(Math.round(dur * s / 6)) }); await sleep(1000); } } else { await apiPost(API_BASE + '/myd007.do', { adz290: v.adz290, aac001, adz341: String(Math.round(dur)) }); } await sleep(2000); // 标记完成 const r5 = await apiPost(API_BASE + '/myd005.do', { adz290: v.adz290, aac001 }); const ok = r5?.resultData?.data?.code === '1'; log(ok ? ' 标记完成: OK' : ` 标记完成: 失败 (${r5?.resultData?.data?.msg || ''})`); processed++; await sleep(5000); } setProgress(processed, remaining); log('\n全部完成!'); btn.disabled = false; btn.textContent = '开始学习'; } $('mys-start').addEventListener('click', run); })();