// ==UserScript== // @name 河南专技学习网-课程助手 // @namespace http://tampermonkey.net/zzzzzzys_河南专技学习网-课程助手 // @version 1.0.2 // @copyright zzzzzzys.All Rights Reserved. // @description 河南专技学习网-课程助手(https://hnzj.59iedu.com/),脚本功能有限,可自动静音播放视频,防暂停。更全自动方法,请查看文档介绍!客户端支持全自动学习继续教育学习内的未完成课程 // @author zzzzzzys // @match https://hnzj.59iedu.com/* // @require https://fastly.jsdelivr.net/npm/crypto-js@4.2.0/crypto-js.min.js // @resource https://cdn.staticfile.org/limonte-sweetalert2/11.7.1/sweetalert2.min.css // @require https://fastly.jsdelivr.net/npm/sweetalert2@11.12.2/dist/sweetalert2.all.min.js // @require https://scriptcat.org/lib/637/1.4.5/ajaxHooker.js#sha256=EGhGTDeet8zLCPnx8+72H15QYRfpTX4MbhyJ4lJZmyg= // @connect fc-mp-8ba0e2a3-d9c9-45a0-a902-d3bde09f5afd.next.bspapp.com // @connect mp-8ba0e2a3-d9c9-45a0-a902-d3bde09f5afd.cdn.bspapp.com // @grant unsafeWindow // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_xmlhttpRequest // @grant GM_info // @grant GM_addStyle // @run-at document-start // @antifeature ads 有弹窗广告,介绍完全自动化软件 // @antifeature payment 脚本基础功能使用免费,但需要使用完全自动化软件时,可能收费 // ==/UserScript== (function() { 'use strict'; const delay = ms => new Promise(r => setTimeout(r, ms)); class EntryPoint { constructor() { this.executor = null; this._initInterceptor(); this._awaitReady(); } _initInterceptor() { ajaxHooker.hook(req => { const uri = req.url; if (uri.includes('vedioValidQuestions/getQuestions')) { req.response = res => { try { const data = JSON.parse(res.responseText); unsafeWindow.QuestionInfo = data.data; console.log("QuestionInfo:", unsafeWindow.QuestionInfo); } catch(e) {} }; } else if (uri.indexOf('p/play/config') !== -1) { req.response = res => { try { const cfg = JSON.parse(res.responseText); console.log("play/config:"); console.log(cfg); unsafeWindow.playConfig = cfg.data; } catch(e) {} }; } else if (uri.indexOf('learning/learnVerify/checkCode') !== -1) { req.abort = true; req.response = res => { res.responseText = '{"code":0,"msg":null,"data":{"data":"请勿频繁请求","status":9999}}'; }; } else if (uri.indexOf('learning/learnVerify') !== -1) { req.abort = true; } }); console.log("Interceptor ready:", ajaxHooker); } _awaitReady() { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => this._kickoff()); } else { this._kickoff(); } } _kickoff() { this.executor = new CourseEngine("channel-hunau"); } } class CourseEngine { constructor(commChannel) { this.commChannel = commChannel; this.broadcast = new BroadcastChannel(commChannel); this.isPremium = false; this.isBusy = false; this.premiumUrl = null; this.pauseGuard = null; this.interface = new UserPanel({ VIPBtnText: "高级功能-已弃用,请前往软件学习" }); this._setup(); } _setup() { this.interface.setOnVerifyCallback(async (data) => { const url = await ToolBox.validateCode(data); if (url) { this.premiumUrl = url; this.isPremium = true; this.interface.setTip(ToolBox.vipText); return true; } return false; }); this.interface.setOnBegin(() => { if (this.isBusy) return; this.isBusy = true; console.log("Executing:", this.isPremium); this._process().finally(() => { this.isBusy = false; }); }); this.interface.setOnVIP(async () => { if (!this.premiumUrl) { await this.interface.handleVerify(); } await this._execPremium(); }); this._checkPremium(); try { Swal.fire({ title: "提示", text: ToolBox.swFireText, icon: 'info', timer: 10000, // 关键修改:从5000改为10000(10秒) confirmButtonText: '确定', timerProgressBar: true, willClose: () => { this.interface.startAutomation(); } }); } catch (e) { console.error(e); this.interface.startAutomation(); } } _checkPremium() { if (ToolBox.loadStatus()) { this.interface.setTip(ToolBox.vipText); this.isPremium = true; } else { this.interface.setTip(ToolBox.baseText); this.isPremium = false; } console.log("Premium:", this.isPremium); } async _execPremium() { try { ToolBox.showUpgradeAlert(); } catch (error) { console.error(error); Swal.fire({ title: "高级功能执行失败!", text: "若一直失败,请联系进行售后处理!", icon: 'error', confirmButtonText: '确定', allowOutsideClick: false }); } } async _process() { try { await this._ensurePlayback(); } catch (e) { console.error(e); Swal.fire({ title: "失败!", text: `视频基础播放失败!`, icon: 'error', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "确定", timer: 5000, timerProgressBar: true }); } } async _ensurePlayback() { const media = document.querySelector('video'); if (!media) return; media.volume = 0; media.muted = true; if (this.pauseGuard) { media.removeEventListener('pause', this.pauseGuard); } let timer = null; this.pauseGuard = async () => { if (media.ended) return; if (timer) clearTimeout(timer); timer = setTimeout(async () => { console.log("检测到视频暂停,自动恢复播放..."); media.volume = 0; media.muted = true; try { await media.play(); } catch (e) { console.error("恢复播放失败:", e); } }, 500); }; media.addEventListener('pause', this.pauseGuard); media.addEventListener('ended', () => { this._advance(); }, { once: true }); await media.play(); } _advance() { const chapters = Array.from(document.querySelectorAll('ul.lis-content li.lis-inside-content')); if (!chapters.length) { console.log("未找到目录列表"); return; } const current = chapters.findIndex(li => li.querySelector('#top_play')); console.log("当前目录索引:", current); const start = current + 1; for (let i = start; i < chapters.length; i++) { const item = chapters[i]; const btn = item.querySelector('button'); const h2 = item.querySelector('h2'); if (!h2) continue; const status = btn ? btn.textContent.trim() : ''; console.log(`目录[${i}] 状态: ${status}`); const onclick = h2.getAttribute('onclick') || ''; const match = onclick.match(/window\.location\.href='([^']+)'/); if (match) { const nextUrl = match[1]; const title = h2.textContent.trim().replace(/\s+/g, ' '); console.log("跳转下一节:", nextUrl); Swal.fire({ title: "视频已播放完毕", html: `即将跳转到下一节:
${title}`, icon: 'success', timer: 5000, timerProgressBar: true, confirmButtonText: '立即跳转', showCancelButton: true, cancelButtonText: '取消', }).then((result) => { if (result.isConfirmed || result.dismiss === Swal.DismissReason.timer) { window.location.href = nextUrl; } }); return; } } console.log("已是最后一节,无下一个目录"); this._finalize(); } _finalize() { if (!this.isPremium) { Swal.fire({ title: "请升级高级版!", text: `脚本已停止!基础版只能连播几个视频!`, icon: 'info', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "确定", timer: 0 }); return; } this.broadcast.postMessage('finish'); Swal.fire({ title: "学习完成!", text: `学习完成,5s后页面自动关闭!`, icon: 'success', confirmButtonColor: "#FF4DAFFF", confirmButtonText: "确定", timer: 5000, willClose: () => { history.back(); setTimeout(() => location.reload(), 1000); } }); } captchaHandler() { const selector = ".layui-layer1"; const self = this; const check = setInterval(async () => { const layer = document.querySelector(selector); if (layer) { console.log("检查到验证码窗口"); clearInterval(check); const inputSel = "#captchaInput"; const btnSel = ".layui-layer-btn0"; for (let i = 0; i < 20; i++) { try { const input = layer.querySelector(inputSel); const btn = layer.querySelector(btnSel); if (!input || !btn) break; input.value = i; await delay(100); btn.click(); await delay(100); } catch(err) { console.error(err); break; } } self.captchaHandler(); } }, 5000); } } class ToolBox { static flag = 'hnedu123_VIP' static js_Flag = 'hnedu123_jsCode' static vipSign = 'hnedu123_vipSign' static webId = '687f7fc37ad52db7e748dbd8' static swFireText = "请在视频播放页面使用脚本,脚本检测到视频会自动开始,脚本功能有限,也可能页面有所更新,导致脚本不能正常使用,建议下载软件使用!全自动学习所有未完成视频" static baseText = '建议下载软件使用!全自动学习所有未完成视频' static vipText = '全自动建议下载客户端使用!河南专技学习网-课程助手' static vipBtnText = "前往软件使用课程助手,全自动学习所有未完成视频!" static scriptFeatures = [ "辅助当前页面视频播放", "防暂停", "自动静音播放", "视频播放完成自动切换", "仅限单页面使用", ] static softwareFeatures = [ "输入账号密码即可全自动", "全自动完成所有未完成课程", "支持批量多账号同时学习", ] static aliLink = "https://www.alipan.com/s/wViqbLvgSF8" static directLink = 'http://112.124.58.51/static/课程助手.exe' static link = [ "https://68n.cn/IJ8QB", "https://68n.cn/RM9ob", ] static web_list = [ { name: "备用地址0", url: "https://www.zzzzzzys.com/" }, { name: "备用地址1", url: "https://zzzzzzys.lovestoblog.com/" }, { name: "备用地址2", url: "https://zzzzzzys.us.kg/" }, { name: "备用地址3", url: "https://zzysdocs.dpdns.org/" }, { name: "备用地址4", url: "https://zzzzzzys.dpdns.org/" }, { name: "备用地址5", url: "https://zzzzzzys.kesug.com/" }, { name: "备用地址6", url: "https://zzysdocs.great-site.net/" }, ] static docLink = `${ToolBox.web_list[0].url}?webId=` + ToolBox.webId static loadStatus() { return false } static async validateCode(data) { try { ToolBox.showUpgradeAlert(); return; } catch (e) { console.error(e); Swal.fire({ title: "验证失败!", text: e.toString(), icon: 'error', confirmButtonText: '确定', }); } } static async fetchScript(url) { try { let cached = GM_getValue(ToolBox.js_Flag); if (cached) return cached; const code = await new Promise((resolve, reject) => { GM_xmlhttpRequest({ url: url, method: 'GET', onload: res => { if (res.status === 200) resolve(res.responseText); else reject('Server error'); }, onerror: err => reject(err) }); }); const escaped = code .replace(/\\/g, '\\\\') .replace(/'/g, '\'') .replace(/"/g, '\"'); GM_setValue(ToolBox.js_Flag, escaped); return escaped; } catch (error) { console.error('Remote load failed:', error); throw new Error("远程加载失败"); } } static showPurchaseModal() { const links = ToolBox.link; Swal.fire({ title: ' 高级功能解锁', html: `

需要验证授权码才能使用

高级版

1

需有效授权码激活高级功能模块

2

当前账户权限:基础版

获取授权码步骤:

  1. 点击前往以下链接,获取授权码
  2. 获取授权码链接1
  3. 获取授权码链接2
`, icon: 'info', confirmButtonText: '前往激活', showCloseButton: true, timer: 30000, customClass: { popup: 'vip-alert-popup', confirmButton: 'vip-confirm-btn' } }); } static waitElement(selector, mode = 'node', timeout = 10000) { return new Promise((resolve, reject) => { if (!['node', 'nodeList'].includes(mode)) { reject('Invalid mode'); return; } const finder = () => { try { if (mode === 'node') { return document.querySelector(selector); } const list = document.querySelectorAll(selector); return list.length ? list : null; } catch (e) { return null; } }; const timer = setTimeout(() => { clearInterval(interval); resolve(null); }, timeout); const interval = setInterval(() => { const found = finder(); if (found) { clearTimeout(timer); clearInterval(interval); console.log(`${selector} ready!`); resolve(found); } else { console.log(`等待节点: ${selector}...`); } }, 1000); }); } static parseDuration(str, opts = {}) { const m = str.match(/(?:(\d+)小时)?(?:(\d+)分)?(?:(\d+)秒)?/) || []; const h = parseInt(m[1] || 0, 10); const min = parseInt(m[2] || 0, 10); const s = parseInt(m[3] || 0, 10); const total = h * 3600 + min * 60 + s; return opts.returnObject ? { hours: h, minutes: min, seconds: s } : total; } static decodeToken(token) { try { const parts = token.split('.'); const decode = str => atob(str.replace(/-/g, '+').replace(/_/g, '/').padEnd(str.length + (4 - str.length % 4) % 4, '=')); const header = JSON.parse(decode(parts[0])); const payload = JSON.parse( decodeURIComponent( decode(parts[1]) .split('') .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)) .join('') ) ); return { header, payload }; } catch (error) { console.error('Decode failed:', error); return null; } } static showUpgradeAlert() { return Swal.fire({ title: '全自动学习功能说明', html: `

⚠️ 网页脚本有局限性

浏览器脚本运行在沙盒中,无法跨页面、无法自动登录、无法批量管理账号
若需要 输入账号密码后全自动完成所有视频,推荐使用本地客户端。

📄 当前脚本

    ${ToolBox.scriptFeatures.map(f => `
  • ${f}
  • `).join('')}
推荐

🖥️ 客户端工具

    ${ToolBox.softwareFeatures.map((f, i) => `
  • ${i === 0 ? `${f}` : f}
  • `).join('')}

🔗 前往查看 / 下载

官网文档 · 查看使用说明 & 下载
📦 阿里云盘备用下载 ⚡ 直链下载
▸ 官网无法访问?点击展开备用网址
${ToolBox.web_list.map(item => ` ${item.name} `).join('')}
`, showCancelButton: true, confirmButtonText: '前往官网', cancelButtonText: '关闭', confirmButtonColor: '#38a169', cancelButtonColor: '#a0aec0', width: '620px', padding: '1.8em', background: '#ffffff', backdrop: 'rgba(0,0,0,0.25)', customClass: { popup: 'shadow-lg' } }).then((result) => { if (result.isConfirmed) { window.open(ToolBox.docLink, '_blank'); } }); } } class UserPanel { constructor(config = {}) { this.cacheKey = 'AuthData'; this.active = false; this.startStamp = null; this.timerId = null; this.callbacks = {}; this._injectStyles(); this._build(); this._restore(); this._reveal(); this.setVIPBtnText(ToolBox.vipText); this.setTip(config.VIPInfo || "您正在使用基础版本,功能可能存在限制"); } _injectStyles() { const css = ` .auth-window { position: fixed; bottom: 10px; right: 10px; z-index: 999999999999; background: white; padding: 24px; border-radius: 12px; box-shadow: 0 6px 30px rgba(0,0,0,0.15); border: 1px solid #e4e7ed; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; min-width: 320px; transform: translateY(20px); opacity: 0; transition: all 0.3s ease; } .auth-window.visible { transform: translateY(0); opacity: 1; } .auth-title { margin: 0 0 16px; font-size: 20px; color: #2c3e50; font-weight: 600; display: flex; align-items: center; gap: 8px; } .auth-version { font-size: 12px; color: #95a5a6; font-weight: normal; } .auth-tip { margin: 0 0 20px; color: #ffbb00; font-size: 14px; font-weight: weight; line-height: 1.5; } .input-group { margin-bottom: 18px; } .input-label { display: block; margin-bottom: 6px; color: #34495e; font-size: 14px; font-weight: 500; } .input-field { width: 80%; padding: 10px 12px; border: 2px solid #e0e0e0; border-radius: 8px; font-size: 14px; transition: border-color 0.2s; } .input-field:focus { outline: none; border-color: #3498db; box-shadow: 0 0 0 3px rgba(52,152,219,0.1); } .auth-button { width: 100%; padding: 12px; background: #3498db; color: white; border: none; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; gap: 8px; } .auth-button:hover { background: #2980b9; transform: translateY(-1px); } .auth-button:active { transform: translateY(0); } .error-message { color: #e74c3c; font-size: 13px; margin-top: 8px; padding: 8px; background: #fdeded; border-radius: 6px; display: none; animation: shake 0.4s; } @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } } .control-panel { opacity: 1; transform: translateY(10px); transition: all 0.3s ease; } .control-panel.visible { opacity: 1; transform: translateY(0); } .auth-button[disabled] { background: #bdc3c7 !important; cursor: not-allowed; } .auth-window { position: fixed; right: 30px; bottom: 80px; transition: transform 0.3s ease; } .window-toggle:hover .toggle-icon { animation: bounce 0.6s; } .toggle-icon { width: 20px; height: 20px; transition: transform 0.3s ease; } @keyframes bounce { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(4px); } } .vip-btn { width: 100%; position: relative; padding: 12px 24px; border: none; border-radius: 8px; background: linear-gradient(135deg, #ffd700 0%, #ffd900 30%, #ffae00 70%, #ff8c00 100%); color: #2c1a00; font-weight: 600; font-family: 'Segoe UI', sans-serif; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); overflow: hidden; box-shadow: 0 4px 15px rgba(255, 174, 0, 0.3); } .glow-effect::after { content: ''; position: absolute; inset: 0; background: radial-gradient(circle at 50% 0%, rgba(255, 255, 255, 0.4) 0%, transparent 70%); opacity: 0; transition: opacity 0.3s; } .vip-btn:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(255, 174, 0, 0.5); } .vip-btn:hover::after { opacity: 1; } .vip-btn:active { transform: translateY(1px); box-shadow: 0 2px 8px rgba(255, 174, 0, 0.3); } .crown-icon { width: 20px; height: 20px; margin-right: 8px; vertical-align: middle; transition: transform 0.3s; } .vip-btn:hover .crown-icon { transform: rotate(10deg) scale(1.1); } .vip-text { background: linear-gradient(45deg, #2c1a00, #5a3a00); -webkit-background-clip: text; background-clip: text; color: transparent; display: inline-block; } .vip-alert-popup { border: 2px solid #ffd700; border-radius: 12px; background: linear-gradient(145deg, #1a1a1a, #2d2d2d); } .alert-header { border-bottom: 1px solid #404040; padding-bottom: 12px; margin-bottom: 15px; } .swal-vip-icon { color: #ffd700; font-size: 2.2em; margin-right: 8px; } .requirements-box { background: rgba(255,215,0,0.1); border-radius: 8px; padding: 15px; margin: 15px 0; } .requirement-item { display: flex; align-items: center; margin: 10px 0; } .number-badge { background: #ffd700; color: #000; width: 24px; height: 24px; border-radius: 50%; text-align: center; margin-right: 12px; font-weight: bold; } .status-tag { padding: 4px 8px; border-radius: 4px; font-size: 0.9em; } .free-status { background: #ff4444; color: white; } .action-guide { background: rgba(255,255,255,0.05); padding: 15px; border-radius: 8px; } .step-list li { margin: 8px 0; padding-left: 8px; } .pricing-link { color: #00ff9d !important; text-decoration: underline dotted; transition: all 0.3s; } .pricing-link:hover { color: #00cc7a !important; text-decoration: underline; } .vip-confirm-btn { background: linear-gradient(135deg, #ffd700 0%, #ff9900 100%) !important; border: none !important; font-weight: bold !important; transition: transform 0.2s !important; } .vip-confirm-btn:hover { transform: scale(1.05); } div.swal2-container { all: initial !important; position: fixed !important; z-index: 999999 !important; inset: 0 !important; display: flex !important; align-items: center !important; justify-content: center !important; background: rgba(0,0,0,0.4) !important; } .swal2-popup { all: initial !important; max-width: 600px !important; width: 90vw !important; min-width: 300px !important; position: relative !important; box-sizing: border-box !important; padding: 20px !important; background: white !important; border-radius: 8px !important; font-family: Arial !important; animation: none !important; } @keyframes swal2-show { 0% { transform: scale(0.9); opacity: 0 } 100% { transform: scale(1); opacity: 1 } } .beta-container { margin: 18px 0; border-radius: 10px; background: linear-gradient(145deg, #2d2d2d, #1a1a1a); border: 1px solid rgba(255, 215, 0, 0.2); box-shadow: 0 4px 20px rgba(0,0,0,0.2); } .beta-card { padding: 16px; } .beta-header { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; } .beta-icon { width: 28px; height: 28px; fill: #ffd700; filter: drop-shadow(0 0 4px rgba(255,215,0,0.3)); } .beta-title { margin: 0; color: #ffd700; font-size: 16px; font-weight: 600; text-shadow: 0 2px 4px rgba(0,0,0,0.2); } .beta-toggle { display: flex; align-items: center; gap: 12px; cursor: pointer; padding: 10px; border-radius: 8px; transition: background 0.3s; } .beta-toggle:hover { background: rgba(255,215,0,0.05); } .beta-checkbox { display: none; } .beta-track { position: relative; width: 50px; height: 28px; border-radius: 14px; background: rgba(255,215,0,0.1); border: 1px solid rgba(255,215,0,0.3); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } .beta-thumb { position: absolute; left: 2px; top: 2px; width: 24px; height: 24px; background: linear-gradient(145deg, #ffd700, #ffae00); border-radius: 50%; transform: translateX(0); transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 2px 4px rgba(0,0,0,0.2); } .beta-checkbox:checked + .beta-track { background: rgba(255,215,0,0.2); border-color: #ffd700; } .beta-checkbox:checked + .beta-track .beta-thumb { transform: translateX(22px); } .beta-sparkles { position: absolute; width: 100%; height: 100%; background: radial-gradient(circle at 50% 50%, rgba(255,255,255,0.8) 10%, transparent 60%); opacity: 0; transition: opacity 0.3s; } .beta-checkbox:checked + .beta-track .beta-sparkles { opacity: 0.3; } .beta-label { color: #fff; font-size: 14px; font-weight: 500; letter-spacing: 0.5px; background: linear-gradient(90deg, #ffd700, #ffae00); -webkit-background-clip: text; background-clip: text; color: transparent; } .beta-tip { margin: 12px 0 0; color: rgba(255,215,0,0.6); font-size: 12px; line-height: 1.4; padding-left: 8px; border-left: 3px solid rgba(255,215,0,0.3); } .progress-overlay { position: fixed; bottom: 0; left: 30%; transform: translate(0 -50%); background: rgba(0,0,0,0.8); padding: 24px; border-radius: 12px; color: white; z-index: 9999999999; display: none; min-width: 300px; height:100px; box-shadow: 0 4px 20px rgba(0,0,0,0.3); backdrop-filter: blur(8px); } .progress-header { margin-bottom: 12px; display: flex; justify-content: space-between; align-items: center; } .progress-title { margin: 0; font-size: 16px; color: #fff; } .progress-bar { display:block; width: 100%; height: 8px; background: rgba(255,255,255,0.1); border-radius: 4px; overflow: hidden; } .progress-fill { height: 100%; background: linear-gradient(90deg, #00ff88, #00ccff); transition: width 0.3s ease; } .progress-info { margin-top: 15px; text-align: center; gap: 20px; font-size: 12px; color: rgba(255,255,255,0.8); } `; GM_addStyle(css); } _build() { this.root = document.createElement('div'); this.root.className = 'auth-window'; const header = document.createElement('h3'); header.className = 'auth-title'; header.innerHTML = ` 脚本控制台v${GM_info.script.version} `; this.hintEl = document.createElement('p'); this.hintEl.className = 'auth-tip'; this.hintEl.textContent = '您正在使用基础版本,功能可能存在限制'; this.authInp = this._createInput(' 授权密钥', 'password', '#auth'); const lnk1 = this._createLink('authLink1', ToolBox.link[0], '获取授权链接1'); const lnk2 = this._createLink('authLink2', ToolBox.link[1], '获取授权链接2'); this.verifyBtn = document.createElement('button'); this.verifyBtn.className = 'auth-button'; this.verifyBtn.innerHTML = ` 验证授权码 `; this.verifyBtn.onclick = () => this._verify(); this.ctrlArea = document.createElement('div'); this.ctrlArea.className = 'control-panel'; this.ctrlArea.style.cssText = 'margin-top: 20px; border-top: 1px solid #eee; padding-top: 16px;'; this.upgradeBtn = document.createElement('button'); this.upgradeBtn.className = 'vip-btn glow-effect'; this.upgradeBtn.innerHTML = ` 高级功能-全自动挂机 `; this.upgradeBtn.onclick = () => this._upgrade(); this.timeEl = document.createElement('div'); this.timeEl.className = 'timer'; this.timeEl.textContent = '运行时间: 00:00:00'; this.timeEl.style.cssText = 'color: #2ecc71; font-size: 13px; margin-bottom: 12px;'; this.runBtn = document.createElement('button'); this.runBtn.className = 'auth-button'; this.runBtn.style.backgroundColor = '#2ecc71'; this.runBtn.innerHTML = ` 开始运行-自动化挂机 `; this.runBtn.onclick = () => this.startAutomation(); this.errEl = document.createElement('div'); this.errEl.className = 'error-message'; this.ctrlArea.append(this.upgradeBtn, this.timeEl, this.runBtn); this.root.append(header, this.hintEl, this.authInp.container, lnk1, lnk2, this.verifyBtn, this.ctrlArea, this.errEl); document.body.appendChild(this.root); this._makeToggle(); } _createInput(lbl, type, id) { const wrap = document.createElement('div'); wrap.className = 'input-group'; const label = document.createElement('label'); label.className = 'input-label'; label.textContent = lbl; label.htmlFor = id; const inp = document.createElement('input'); inp.className = 'input-field'; inp.type = type; inp.id = id; inp.maxLength = 16; wrap.append(label, inp); return { container: wrap, input: inp }; } _createLink(id, href, txt) { const a = document.createElement('a'); a.id = id; a.className = 'auth-link'; a.href = href; a.target = '_blank'; a.textContent = txt; a.style.cssText = 'display: block; margin: 12px 0; color: #3498db; text-decoration: none; font-size: 13px; transition: opacity 0.2s;'; a.onmouseenter = () => { a.style.opacity = '0.8'; a.style.textDecoration = 'underline'; }; a.onmouseleave = () => { a.style.opacity = '1'; a.style.textDecoration = 'none'; }; return a; } _makeToggle() { this.toggle = document.createElement('button'); this.toggle.className = 'window-toggle'; this.toggle.innerHTML = ` 展开面板 `; this.toggle.style.cssText = ` position: fixed; right: 30px; bottom: 30px; padding: 12px 20px; background: #fff; border: none; border-radius: 30px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); cursor: pointer; display: flex; align-items: center; gap: 8px; transition: all 0.3s ease; z-index: 9999999; `; this.toggle.onmouseenter = () => { this.toggle.style.transform = 'translateY(-2px)'; this.toggle.style.boxShadow = '0 6px 16px rgba(0,0,0,0.2)'; }; this.toggle.onmouseleave = () => { this.toggle.style.transform = 'none'; this.toggle.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)'; }; this.toggle.onclick = () => { const shown = this.root.style.display !== 'none'; this.root.style.display = shown ? 'none' : 'block'; this.toggle.querySelector('.toggle-icon').style.transform = shown ? 'rotate(180deg)' : 'none'; this.toggle.querySelector('.toggle-text').textContent = shown ? '展开面板' : '收起面板'; if (!shown) { this.root.animate([ { opacity: 0, transform: 'translateY(20px)' }, { opacity: 1, transform: 'none' } ], { duration: 300, easing: 'ease-out' }); } }; document.body.appendChild(this.toggle); } _reveal() { setTimeout(() => this.root.classList.add('visible'), 100); } _restore() { const saved = GM_getValue(this.cacheKey); if (saved) { const data = JSON.parse(saved); this.authInp.input.value = data.key || ''; } } startAutomation() { if (this.active) return; this.active = true; this.startStamp = Date.now(); this.runBtn.innerHTML = ` 运行中... `; this.runBtn.style.backgroundColor = '#e67e22'; this.runBtn.disabled = true; this.timerId = setInterval(() => { const delta = Date.now() - this.startStamp; const hrs = Math.floor(delta / 3600000).toString().padStart(2, '0'); const mins = Math.floor((delta % 3600000) / 60000).toString().padStart(2, '0'); const secs = Math.floor((delta % 60000) / 1000).toString().padStart(2, '0'); this.timeEl.textContent = `运行时间: ${hrs}:${mins}:${secs}`; }, 1000); if (this.callbacks.begin) this.callbacks.begin(); } async _verify() { const data = { key: this.authInp.input.value }; if (!data.key || !/^[A-Z0-9]{16}$/.test(data.key)) { Swal.fire({ title: "授权码不正确,应为16位", text: "请正确输入!", icon: 'info', confirmButtonText: '确定', }); return; } if (this.callbacks.verify) { const ok = await this.callbacks.verify(data); if (ok) { GM_setValue(this.cacheKey, JSON.stringify(data)); } } } _upgrade() { if (this.callbacks.vip) { this.callbacks.vip(); } else { Swal.fire({ title: "提示", text: "请在视频播放页面使用!", icon: 'info', confirmButtonText: '确定' }); } } async handleVerify() { await this._verify(); } setTip(txt) { this.hintEl.innerText = txt; } setVIPBtnText(txt) { this.upgradeBtn.innerHTML = ` ${txt} `; } setOnVerifyCallback(fn) { this.callbacks.verify = fn; } setOnBegin(fn) { this.callbacks.begin = fn; } setOnVIP(fn) { this.callbacks.vip = fn; } showError(msg) { this.errEl.textContent = msg; this.errEl.style.display = 'block'; setTimeout(() => this.errEl.style.display = 'none', 5000); } } new EntryPoint(); })();