// ==UserScript== // @name 2026广东干部培训网络学院自动学习助手 // @namespace https://gdpx-shop.pages.dev // @version 4.1.0 // @description 自动播放、播完自动切换下一课、卡死自动续播、动态水印。内置 20 分钟免费试用,到期后可付费激活永久使用。 // @author LEEMO2023 // @match https://gbpx.gd.gov.cn/* // @match https://wcs1.shawcoder.xyz/* // @match https://cs1.gdgbpx.com/* // @match *://*gzqinghui.com.cn/* // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_xmlhttpRequest // @grant GM_registerMenuCommand // @grant GM_setClipboard // @grant window.close // @grant unsafeWindow // @connect * // @run-at document-idle // @noframes // @license MIT // @homepageURL https://gdpx-shop.pages.dev // @supportURL https://gdpx-shop.pages.dev/help.html // @antifeature payment 本脚本内置 20 分钟免费试用,到期后需付费购买激活码才能继续使用 // ==/UserScript== (function () { 'use strict'; /* ================== 配置区:改成你自己的服务地址 ================== */ var CONFIG = { // 授权服务端根地址(结尾必须带 /)。没有服务器请留空字符串 '',走纯卡密离线路线 // 当这里填了真实地址,脚本会自动切换成"扫码付款 → 自动出码 → 自动激活"模式 API_BASE: '', // 购买页地址(暂无在线支付通道时使用)。付款后由客服/网页把激活码发给你 SHOP_URL: 'https://gdpx-shop.pages.dev', // 免费试用时长(分钟),到点后弹出付款窗并暂停刷课 TRIAL_MINUTES: 20, // 单个视频最长播放时间(分钟)保险丝,超时强制关窗换下一课 MAX_VIDEO_MINUTES: 12, // 视频被认为看完的进度阈值(%) DONE_PERCENT: 98, // 课程列表页判定"已完成"的阈值(%) COURSE_DONE_PERCENT: 95, DEBUG: true }; /* 服务端公钥(SPKI PEM)。由 tools/genkey.js 生成,与服务端 keys/private.pem 配对 */ var PUBLIC_KEY_PEM = [ '-----BEGIN PUBLIC KEY-----', 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhMsflDqHj1qGdNcBJrhe', '0f8GJwsEo1acQFDFcUA6HJFjUzbGO6SbgXsbnuBvUYhL25KbOMFQ9/4udbEIY83y', 'pqOoqEAo9T7ayR2qrx2mR+htvYjTt1gid9D85UA4WAvt0a3GO5mMVhJ8KEzZU4z9', 'PJC4W1eY9AlAAWQeyeivEuiNywBjl8vJNRrRai5pThKWHbgut2dtspdJCQZV4TJV', 'XQd6oVsqfVO3cgJlfoa0a0Ex/vGoj8EKapuoEXAW3WbRAx+v4B3YvRugwmP1KduJ', 'LqWj34SBZYpVEUZfPfz91DWNKD+5yJml8FW7S5coN1YeLwRQGFbQq0i4KvwtHKHw', 'UwIDAQAB', '-----END PUBLIC KEY-----' ].join('\n'); var LOG_PREFIX = '[学习助手]'; function log() { if (!CONFIG.DEBUG) return; var a = Array.prototype.slice.call(arguments).map(function (x) { return typeof x === 'object' ? JSON.stringify(x) : String(x); }); console.log(LOG_PREFIX, a.join(' ')); } /* ================== 存储键 ================== */ var K = { deviceId: 'gdpx_v4_device_id', license: 'gdpx_v4_license', trialUsed: 'gdpx_v4_trial_used_ms', // 累计已试用毫秒(防刷新重置) trialTick: 'gdpx_v4_trial_tick_at', // 上次心跳时间戳 payOrder: 'gdpx_v4_pending_order' }; /* ================== 设备号 ================== */ function getDeviceId() { var id = GM_getValue(K.deviceId, ''); if (!id) { var t = Date.now().toString(36).toUpperCase(); var r = Math.random().toString(36).substring(2, 8).toUpperCase(); id = 'GD-' + t.substring(0, 4) + '-' + r; GM_setValue(K.deviceId, id); log('生成设备号', id); } return id; } /* ================== 激活码校验核心(可离线验签) ================== */ /* ---BEGIN LICENSE VERIFY CORE--- */ function b64uToBuf(str) { var s = String(str).replace(/-/g, '+').replace(/_/g, '/'); while (s.length % 4) s += '='; var bin = atob(s); var buf = new Uint8Array(bin.length); for (var i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i); return buf; } function pemToBuf(pem) { var b64 = String(pem) .replace(/-----BEGIN PUBLIC KEY-----/, '') .replace(/-----END PUBLIC KEY-----/, '') .replace(/\s+/g, ''); return b64uToBuf(b64); } /** * 校验激活码 * @returns {Promise<{ok:boolean, reason?:string, expire?:number}>} */ async function verifyLicense(license, deviceId) { license = String(license || '').trim(); var parts = license.split('.'); if (parts.length !== 2) return { ok: false, reason: '激活码格式错误' }; var payload = parts[0]; var sig = parts[1]; // payload: GDPX1|deviceId|expireTs(秒,0=永久)|nonce // deviceId 为 * 时表示"通用卡密"(发卡平台批量预生成场景),任意机器可用 var f = payload.split('|'); if (f.length !== 4) return { ok: false, reason: '激活码格式错误' }; if (f[0] !== 'GDPX1') return { ok: false, reason: '激活码版本不匹配' }; if (f[1] !== deviceId && f[1] !== '*') return { ok: false, reason: '激活码与本机设备不匹配(一码一机)' }; var expire = parseInt(f[2], 10); if (isNaN(expire)) return { ok: false, reason: '激活码格式错误' }; if (expire !== 0 && Date.now() / 1000 > expire) return { ok: false, reason: '激活码已过期' }; // 浏览器 Web Crypto 验签(RSASSA-PKCS1-v1_5 + SHA-256) var floating = (f[1] === '*'); var subtle = (window.crypto && window.crypto.subtle) || (self.crypto && self.crypto.subtle); if (!subtle) { // 安全修复:离线卡密路线没有服务端可兜底,此时若放行, // 任何人只要构造 "GDPX1|*|0|任意.任意" 就能激活,等于授权形同虚设。 // 只有在确实配了在线服务端(激活码由服务端下发)时,才允许信任服务端结果。 if (!hasApi()) { return { ok: false, reason: '当前页面环境不支持本地验签(需 HTTPS),请换用 HTTPS 页面或联系客服' }; } return { ok: true, expire: expire, floating: floating, weak: true }; } try { var key = await subtle.importKey( 'spki', pemToBuf(PUBLIC_KEY_PEM), { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, false, ['verify'] ); var ok = await subtle.verify( { name: 'RSASSA-PKCS1-v1_5' }, key, b64uToBuf(sig), new TextEncoder().encode(payload) ); if (!ok) return { ok: false, reason: '激活码签名无效' }; return { ok: true, expire: expire, floating: floating }; } catch (e) { return { ok: false, reason: '验签失败:' + e.message }; } } /* ---END LICENSE VERIFY CORE--- */ /* ================== 服务端通信 ================== */ function api(action, params, method) { return new Promise(function (resolve, reject) { var qs = []; for (var k in params) if (params.hasOwnProperty(k)) { qs.push(encodeURIComponent(k) + '=' + encodeURIComponent(params[k])); } var url = CONFIG.API_BASE + 'api.php?action=' + action + (qs.length ? '&' + qs.join('&') : ''); GM_xmlhttpRequest({ method: method || 'GET', url: url, timeout: 20000, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, onload: function (res) { try { resolve(JSON.parse(res.responseText)); } catch (e) { reject(new Error('服务端返回异常:' + res.responseText.slice(0, 200))); } }, onerror: function (e) { reject(new Error('无法连接授权服务器')); }, ontimeout: function () { reject(new Error('授权服务器响应超时')); } }); }); } /* ================== 状态 ================== */ var STATE = { deviceId: getDeviceId(), activated: false, license: '', expire: 0, trialUsedMs: 0, stopped: false // 试用到期后暂停学习 }; (async function boot() { registerMenus(); var saved = GM_getValue(K.license, ''); if (saved) { var v = await verifyLicense(saved, STATE.deviceId); if (v.ok) { STATE.activated = true; STATE.license = saved; STATE.expire = v.expire || 0; log('已激活', v.weak ? '(在线模式)' : '(离线验签通过)'); } else { log('本地激活码失效:' + v.reason); GM_deleteValue(K.license); } } STATE.trialUsedMs = parseInt(GM_getValue(K.trialUsed, '0'), 10) || 0; if (STATE.activated) { startStudy(); } else { startTrialCountdown(); // 先按剩余试用时间跑,余额用尽时自动弹付款窗 if (trialLeftMs() <= 0) { STATE.stopped = true; showPayDialog('试用已结束'); } else { log('试用剩余', Math.ceil(trialLeftMs() / 60000), '分钟'); startStudy(); } } })(); function trialTotalMs() { return CONFIG.TRIAL_MINUTES * 60 * 1000; } function trialLeftMs() { return Math.max(0, trialTotalMs() - STATE.trialUsedMs); } /** 试用计时:每 30 秒累加一次实际在线时长,刷新/换页不会清零 */ function startTrialCountdown() { var last = parseInt(GM_getValue(K.trialTick, '0'), 10) || Date.now(); var now = Date.now(); if (now > last) { var delta = Math.min(now - last, 10 * 60 * 1000); // 单段最多计 10 分钟,防止挂机跨天暴涨 STATE.trialUsedMs += delta; GM_setValue(K.trialUsed, STATE.trialUsedMs); } GM_setValue(K.trialTick, now); setInterval(function () { if (STATE.activated || STATE.stopped) { GM_setValue(K.trialTick, Date.now()); return; } var t = Date.now(); var prev = parseInt(GM_getValue(K.trialTick, '0'), 10) || t; var d = Math.min(t - prev, 10 * 60 * 1000); if (d > 0) { STATE.trialUsedMs += d; GM_setValue(K.trialUsed, STATE.trialUsedMs); } GM_setValue(K.trialTick, t); if (trialLeftMs() <= 0) { STATE.stopped = true; stopLearning(); showPayDialog('试用时间已用完'); } }, 30000); } /* ================== 支付弹窗(全自动:扫码 → 轮询 → 激活 → 继续刷课) ================== */ function showPayDialog(reason) { if (document.getElementById('gdpx-pay-root')) return; log('显示支付窗口:' + reason); var root = document.createElement('div'); root.id = 'gdpx-pay-root'; root.innerHTML = '
' + '
' + '
' + '
学习助手 · 授权激活
' + '
扫码付款后自动激活,无需联系任何人
' + '×
' + '
' + '
' + reason + ',付款后立即恢复自动学习
' + '
' + '
正在生成收款二维码…
' + '
' + '
已有激活码?直接粘贴(离线可用)
' + '
' + '' + '
' + '
' + '
' + '设备号:' + STATE.deviceId + '' + '' + '
' + '
'; (document.body || document.documentElement).appendChild(root); document.getElementById('gdpx-pay-close').onclick = function () { root.remove(); }; // 复制设备号:买家把设备号发给客服,客服据此签发激活码 var copyBtn = document.getElementById('gdpx-copy-dev'); if (copyBtn) copyBtn.onclick = function () { copyText(STATE.deviceId); var t = document.getElementById('gdpx-copy-tip'); if (t) { t.textContent = '已复制'; setTimeout(function () { t.textContent = ''; }, 2000); } }; document.getElementById('gdpx-lic-btn').onclick = function () { var val = document.getElementById('gdpx-lic-input').value.trim(); redeemLicense(val).then(function (r) { var el = document.getElementById('gdpx-lic-msg'); if (r.ok) { el.innerHTML = '✓ 激活成功,正在恢复学习…'; setTimeout(function () { root.remove(); location.reload(); }, 1200); } else { el.innerHTML = '✗ ' + r.reason + ''; } }); }; if (hasApi()) createOrderAndRender(root); else renderOfflineGuide(root); } /** 复制文本:优先用脚本管理器的剪贴板 API,失败则回退到临时 textarea */ function copyText(text) { try { if (typeof GM_setClipboard === 'function') { GM_setClipboard(text); return; } } catch (e) { /* 继续走降级 */ } try { var ta = document.createElement('textarea'); ta.value = text; ta.style.cssText = 'position:fixed;top:-9999px;opacity:0'; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); ta.remove(); } catch (e2) { log('复制失败', e2.message); } } /** 是否已配置真正的授权服务端 */ function hasApi() { return !!CONFIG.API_BASE && CONFIG.API_BASE.indexOf('your-domain.com') < 0; } /** 无服务器路线:引导自助购买 → 粘贴卡密(卡密离线验签,永久有效) */ function renderOfflineGuide(root) { var stage = document.getElementById('gdpx-pay-stage'); var shop = CONFIG.SHOP_URL; var buyBtn = shop ? '' + '① 点此自助购买激活码' : '
未配置购买链接(CONFIG.SHOP_URL)
'; stage.innerHTML = '
' + '激活三步:
' + '① 点下方按钮到购买页付款(请同时把设备号发给客服,下方「复制」按钮可一键复制)
' + '② 客服核对收款后,把激活码发给你(通常 30 分钟内)
' + '③ 把激活码粘贴到下方输入框,点「激活」即可使用' + '
' + '
' + buyBtn + '
' + '
激活码本地离线校验,激活后无需联网
'; } function createOrderAndRender(root) { var stage = document.getElementById('gdpx-pay-stage'); api('create_order', { device_id: STATE.deviceId }).then(function (d) { if (!d.ok) throw new Error(d.msg || '下单失败'); log('订单已创建', d.order_no, d.amount); GM_setValue(K.payOrder, d.order_no); stage.innerHTML = '
应付金额 ' + '¥' + Number(d.amount).toFixed(2) + ' · 永久授权
' + '
收款码
' + '
' + '' + '请用支付宝/微信扫码付款,付款后本页面自动激活
' + '
二维码无法显示?点此打开收银台 →
' + '
订单号 ' + d.order_no + '
'; pollOrder(root, d.order_no); }).catch(function (e) { log('下单失败', e.message); stage.innerHTML = '
下单失败:' + e.message + '
' + '
请检查网络,或稍后重试。也可使用下方激活码直接激活。
' + ''; var b = document.getElementById('gdpx-retry'); if (b) b.onclick = function () { createOrderAndRender(root); }; }); } function pollOrder(root, orderNo) { var tries = 0; var maxTries = 600; // 30 分钟 var timer = setInterval(function () { if (!document.getElementById('gdpx-pay-root')) { clearInterval(timer); return; } tries++; if (tries > maxTries) { clearInterval(timer); var tip = document.getElementById('gdpx-pay-tip'); if (tip) tip.innerHTML = '订单已超时,请关闭本窗口重新发起支付'; return; } api('query_order', { order_no: orderNo }).then(function (d) { if (!d.ok) return; if (d.status === 'paid' && d.license) { clearInterval(timer); log('支付成功,收到激活码'); redeemLicense(d.license).then(function (r) { if (r.ok) { var tip = document.getElementById('gdpx-pay-tip'); if (tip) tip.innerHTML = '✓ 支付成功,已激活,正在恢复学习…'; setTimeout(function () { root.remove(); location.reload(); }, 1500); } else { var tip2 = document.getElementById('gdpx-pay-tip'); if (tip2) tip2.innerHTML = '激活码校验失败:' + r.reason + ''; } }); } }).catch(function () { /* 网络抖动,下一轮继续 */ }); }, 3000); // 收银台页面支付成功时也会主动通知(iframe / 新窗口场景) window.addEventListener('message', function (e) { if (e.data && e.data.type === 'gdpx_paid' && e.data.license) { clearInterval(timer); redeemLicense(e.data.license).then(function (r) { if (r.ok) { root.remove(); location.reload(); } }); } }); } async function redeemLicense(license) { var v = await verifyLicense(license, STATE.deviceId); if (!v.ok) return { ok: false, reason: v.reason }; GM_setValue(K.license, license); STATE.activated = true; STATE.license = license; STATE.expire = v.expire || 0; STATE.stopped = false; log('激活成功'); return { ok: true }; } /* ================== 学习主流程 ================== */ var currentUrl = window.location.href; function startStudy() { if (currentUrl.indexOf('LearningCourse.aspx') >= 0) { setTimeout(handleCourseListPage, 2500); } else if (currentUrl.indexOf('StudyCenter.aspx') >= 0) { setTimeout(handleStudyCenterPage, 2500); } else if (currentUrl.indexOf('play_pc') >= 0 || currentUrl.indexOf('CourseWare') >= 0) { setTimeout(handleVideoPage, 2000); } else if (currentUrl === 'https://wcs1.shawcoder.xyz/gdcecw/play_pc/playdo_pc.html') { setTimeout(handleCompletionPage, 1500); } else { log('当前页面无需处理'); } } function stopLearning() { removeWatermark(); if (window.videoTimer) { clearTimeout(window.videoTimer); window.videoTimer = null; } if (window.playInterval) { clearInterval(window.playInterval); window.playInterval = null; } if (window.watchTimer) { clearInterval(window.watchTimer); window.watchTimer = null; } try { var v = document.querySelector('video'); if (v) v.pause(); } catch (e) { } } function guard() { if (STATE.stopped) { stopLearning(); return false; } return true; } /* ---------- 课程列表页:挑一门没学完的课 ---------- */ function handleCourseListPage() { if (!guard()) return; log('处理课程列表页'); setTimeout(function () { if (!guard()) return; var links = document.querySelectorAll('a.courseware-list-reed'); if (!links.length) links = document.querySelectorAll("a[id^='gvList_ctl']"); if (!links.length) { log('未找到课程链接'); return; } var target = null; for (var i = 0; i < links.length; i++) { var t = links[i].title || links[i].textContent || ''; var p = parseProgress(t); if (p < CONFIG.COURSE_DONE_PERCENT) { target = { el: links[i], idx: i + 1, p: p }; break; } } if (target) { log('开始第 ' + target.idx + ' 门课,已完成 ' + target.p + '%'); setTimeout(function () { if (guard()) target.el.click(); }, 1500); } else { log('全部课程已完成 🎉'); } }, 1200); // 监听子窗口关闭后刷新,继续下一课 window.addEventListener('message', function (e) { if (e.data && (e.data.type === 'refreshPage' || e.data.type === 'gdpx_next')) { log('收到刷新消息,2 秒后刷新'); setTimeout(function () { if (guard()) location.reload(); }, 2000); } }); } /* ---------- 学习中心页 ---------- */ function handleStudyCenterPage() { if (!guard()) return; log('检测学习中心进度'); setTimeout(function () { if (!guard()) return; var p = getCurrentProgress(); log('当前进度 ' + p + '%'); if (p >= CONFIG.COURSE_DONE_PERCENT) { location.href = 'https://gbpx.gd.gov.cn/gdceportal/Study/LearningCourse.aspx'; } else { findAndClickCourse(); } }, 2000); } /* ---------- 视频播放页 ---------- */ function handleVideoPage() { if (!guard()) return; log('处理视频播放页'); createWatermark(); // 保险丝:最长播放时间 window.videoTimer = setTimeout(function () { log('达到单课时长上限,切换下一课'); closeVideoAndNext(); }, CONFIG.MAX_VIDEO_MINUTES * 60 * 1000); setTimeout(startPlayback, 1500); startWatchdog(); } function startPlayback() { if (!guard()) return; tryDirectPlay(); setTimeout(clickPlayButtons, 400); setTimeout(clickPageCenter, 900); var n = 0; window.playInterval = setInterval(function () { if (!guard()) { clearInterval(window.playInterval); return; } n++; if (isPlaying()) { clearInterval(window.playInterval); log('视频播放中'); return; } if (n >= 12) { clearInterval(window.playInterval); log('多次尝试后仍未播放'); return; } log('第 ' + n + ' 次尝试播放'); tryDirectPlay(); clickPlayButtons(); }, 4000); } /** 看门狗:检测播放结束或卡死 */ function startWatchdog() { var lastTime = -1, stall = 0; window.watchTimer = setInterval(function () { if (!guard()) return; var v = document.querySelector('video'); if (!v) return; var pct = v.duration ? (v.currentTime / v.duration) * 100 : 0; if (v.ended || pct >= CONFIG.DONE_PERCENT) { log('本章已播完(' + pct.toFixed(1) + '%),切换下一课'); closeVideoAndNext(); return; } if (Math.abs(v.currentTime - lastTime) < 0.05) { stall++; if (stall >= 3) { log('播放停滞,重新触发'); stall = 0; tryDirectPlay(); clickPlayButtons(); } } else { stall = 0; } lastTime = v.currentTime; }, 10000); } function isPlaying() { try { var v = document.querySelector('video'); if (v) return !v.paused && !v.ended && v.currentTime > 0; var pe = document.querySelector('.vjs-play-progress'); if (pe && pe.style.width && pe.style.width !== '0%' && pe.style.width !== '0px') return true; } catch (e) { } return false; } function tryDirectPlay() { try { var vs = document.querySelectorAll('video'); for (var i = 0; i < vs.length; i++) { var v = vs[i]; v.muted = true; try { v.volume = 0; } catch (e) { } var pr = v.play(); if (pr && pr.then) pr.then(function () { log('video.play() 成功'); }).catch(function () { }); } } catch (e) { } } function clickPlayButtons() { var sels = ['.vjs-big-play-button', '.vjs-play-control', '.vjs-play-button', 'button[title*="播放"]', 'button[title*="play"]', 'button[aria-label*="播放"]', 'button[aria-label*="play"]', '.play-btn', '.video-play', '.play-button', '.start-play', '.start-button', '.begin-btn', '.vjs-poster', '.video-poster']; sels.forEach(function (s) { try { var els = document.querySelectorAll(s); for (var i = 0; i < els.length; i++) { if (visible(els[i])) { els[i].click(); log('点击 ' + s); } } } catch (e) { } }); } function clickPageCenter() { try { var x = window.innerWidth / 2, y = window.innerHeight / 2; var el = document.elementFromPoint(x, y); if (el) el.dispatchEvent(new MouseEvent('click', { view: window, bubbles: true, cancelable: true, clientX: x, clientY: y })); } catch (e) { } } function visible(el) { if (!el) return false; var r = el.getBoundingClientRect(); return r.width > 0 && r.height > 0 && r.top >= 0 && r.left >= 0 && r.bottom <= window.innerHeight && r.right <= window.innerWidth; } function closeVideoAndNext() { removeWatermark(); if (window.videoTimer) { clearTimeout(window.videoTimer); window.videoTimer = null; } if (window.playInterval) { clearInterval(window.playInterval); window.playInterval = null; } if (window.watchTimer) { clearInterval(window.watchTimer); window.watchTimer = null; } try { if (window.opener && !window.opener.closed) { var n = 0; var send = function () { n++; window.opener.postMessage({ type: 'refreshPage', source: 'videoWindow', count: n }, '*'); if (n < 3) setTimeout(send, 4000); }; setTimeout(send, 800); } } catch (e) { } setTimeout(function () { try { window.close(); log('窗口已关闭'); } catch (e) { location.href = 'https://gbpx.gd.gov.cn/gdceportal/Study/LearningCourse.aspx'; } }, 1800); } function handleCompletionPage() { log('播放完成页'); setTimeout(function () { try { var b = document.querySelectorAll('button.instructions-close'); if (b.length) { b[0].click(); log('点击关闭按钮'); } } catch (e) { } setTimeout(function () { try { window.close(); } catch (e) { location.href = 'https://gbpx.gd.gov.cn/gdceportal/study/StudyCenter.aspx'; } }, 1200); }, 1500); } /* ================== 工具 ================== */ function parseProgress(text) { var m = String(text || '').match(/([\d.]+)\s*[%%]/); if (m) return parseFloat(m[1]); return 0; } function getCurrentProgress() { var divs = document.querySelectorAll('div'); for (var i = 0; i < divs.length; i++) { var m = (divs[i].textContent || '').match(/([\d.]+)%/); if (m) return parseFloat(m[1]); } return 0; } function findAndClickCourse() { var a = document.querySelectorAll('a.courseware-list-reed'); if (!a.length) a = document.querySelectorAll("a[id^='gvList_ctl']"); if (a.length) { log('继续学习'); a[0].click(); } else setTimeout(function () { location.href = 'https://gbpx.gd.gov.cn/gdceportal/Study/LearningCourse.aspx'; }, 2500); } /* ================== 动态水印 ================== */ var wmEl = null, wmTimer = null; function createWatermark() { removeWatermark(); wmEl = document.createElement('div'); wmEl.textContent = '视频自动播放中'; wmEl.style.cssText = 'position:fixed;z-index:2147483000;pointer-events:none;background:rgba(0,0,0,.72);' + 'color:#4CAF50;padding:12px 24px;border-radius:30px;font-size:16px;font-weight:700;border:3px solid #4CAF50;' + 'box-shadow:0 0 25px rgba(76,175,80,.6);white-space:nowrap;user-select:none;font-family:Arial,sans-serif;' + 'transition:transform .2s linear;'; document.body.appendChild(wmEl); var vx = (Math.random() > .5 ? 1 : -1) * (1.5 + Math.random() * 1.5); var vy = (Math.random() > .5 ? 1 : -1) * (1 + Math.random()); var x = Math.random() * Math.max(10, window.innerWidth - 240); var y = Math.random() * Math.max(10, window.innerHeight - 80); wmTimer = setInterval(function () { if (!wmEl) return; var w = wmEl.offsetWidth || 200, h = wmEl.offsetHeight || 50; x += vx; y += vy; if (x < 10) { x = 10; vx = Math.abs(vx); } if (y < 10) { y = 10; vy = Math.abs(vy); } if (x > window.innerWidth - w - 10) { x = window.innerWidth - w - 10; vx = -Math.abs(vx); } if (y > window.innerHeight - h - 10) { y = window.innerHeight - h - 10; vy = -Math.abs(vy); } wmEl.style.left = x + 'px'; wmEl.style.top = y + 'px'; wmEl.style.transform = 'rotate(' + (Math.sin(Date.now() / 800) * 2) + 'deg)'; }, 40); } function removeWatermark() { if (wmEl) { wmEl.remove(); wmEl = null; } if (wmTimer) { clearInterval(wmTimer); wmTimer = null; } } /* ================== 脚本菜单(脚本猫/油猴 的扩展菜单里可点) ================== */ function registerMenus() { if (typeof GM_registerMenuCommand !== 'function') return; GM_registerMenuCommand('查看授权状态 / 激活', function () { showPayDialog('手动打开'); }); GM_registerMenuCommand('复制设备号(发给客服)', function () { copyText(STATE.deviceId); alert('设备号已复制:' + STATE.deviceId + '\n把它和付款截图一起发给客服即可。'); }); GM_registerMenuCommand('查看剩余试用时间', function () { var leftMs = Math.max(0, CONFIG.TRIAL_MINUTES * 60000 - STATE.trialUsedMs); alert(STATE.activated ? '已激活' + (STATE.expire ? ',有效期至 ' + new Date(STATE.expire * 1000).toLocaleString() : '(永久)') : '未激活,剩余试用约 ' + Math.ceil(leftMs / 60000) + ' 分钟'); }); } /* ================== 调试入口 ================== */ unsafeWindow.GDPX = { state: STATE, resetLicense: function () { GM_deleteValue(K.license); }, resetTrial: function () { GM_deleteValue(K.trialUsed); GM_deleteValue(K.trialTick); }, pay: function () { showPayDialog('手动触发'); }, deviceId: function () { return STATE.deviceId; } }; })();