// ==UserScript== // @name 【收费版】2026年广东省药师协会自动学习器(执业药师继续教育)补丁版 // @namespace http://tampermonkey.net/ // @version 2.1.2 // @description 自动学习,需付费激活后使用。购买请联系:微信号:jiaobenjinlin // @match https://www.gdysxh.com/my_classes/public_course/index.html // @match https://www.gdysxh.com/my_classes/public_course/video/* // @match https://www.gdysxh.com/my_classes/classes/index.html // @match https://www.gdysxh.com/my_classes/classes/video/* // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_setClipboard // @grant GM_registerMenuCommand // @grant GM_addStyle // @grant GM_xmlhttpRequest // ==/UserScript== (function() { 'use strict'; const CONFIG = { contact: "微信:jiaobenjinlin", price: "10元/永久", secretKey: "GDYSXH_SECRET_KEY_2024_7x9k2m4p_YOUR_OWN_STRING", wechatQrcodeUrl: "https://s41.ax1x.com/2026/06/11/pmKcuxH.jpg", debug: false, speedConfig: { public_course: { speeds: [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0], defaultSpeed: 4.0, title: "公需课" }, classes: { speeds: [1.5, 2.0, 2.5], defaultSpeed: 2.0, title: "专业课" } } }; function getPageType() { const url = window.location.href; if (url.includes('/public_course/')) { return 'public_course'; } else if (url.includes('/classes/')) { return 'classes'; } return 'public_course'; } GM_addStyle(` #video-control-panel { position: fixed; top: 10px; left: 10px; z-index: 99999; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 12px; padding: 12px 16px; color: white; font-family: system-ui, -apple-system, sans-serif; box-shadow: 0 4px 15px rgba(0,0,0,0.2); backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,0.2); min-width: 240px; } #video-control-panel .title { font-size: 16px; font-weight: bold; margin-bottom: 8px; text-align: center; letter-spacing: 1px; border-bottom: 1px solid rgba(255,255,255,0.3); padding-bottom: 5px; } #video-control-panel .speed-buttons { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin-bottom: 8px; } #video-control-panel .speed-btn { background: rgba(255,255,255,0.2); border: none; color: white; padding: 5px 12px; border-radius: 20px; cursor: pointer; font-size: 14px; transition: all 0.2s ease; font-weight: 500; } #video-control-panel .speed-btn:hover { background: rgba(255,255,255,0.4); transform: scale(1.05); } #video-control-panel .speed-btn.active { background: #ffd700; color: #333; box-shadow: 0 0 8px rgba(255,215,0,0.5); } #video-control-panel .pause-btn { background: #ff4d4f; border: none; color: white; padding: 5px 12px; border-radius: 20px; cursor: pointer; font-size: 14px; transition: all 0.2s ease; font-weight: 500; margin-top: 5px; width: 100%; } #video-control-panel .pause-btn:hover { background: #ff7875; transform: scale(1.02); } #video-control-panel .pause-btn.paused { background: #52c41a; } #video-control-panel .speed-note { font-size: 12px; text-align: center; color: rgba(255,255,255,0.7); border-top: 1px solid rgba(255,255,255,0.2); padding-top: 6px; margin-top: 4px; line-height: 1.3; } @keyframes slideIn { from { opacity: 0; transform: translateX(-20px); } to { opacity: 1; transform: translateX(0); } } #video-control-panel { animation: slideIn 0.3s ease; } .activation-modal { background: white; padding: 30px; border-radius: 12px; max-width: 500px; width: 90%; max-height: 90vh; overflow-y: auto; box-shadow: 0 5px 20px rgba(0,0,0,0.3); font-family: system-ui, -apple-system, sans-serif; } .activation-modal h2 { margin: 0 0 10px 0; color: #333; text-align: center; } .activation-modal .desc { color: #666; margin-bottom: 20px; text-align: center; } .activation-modal .machine-box { background: #f5f5f5; padding: 12px; border-radius: 6px; margin-bottom: 20px; } .activation-modal .machine-label { font-size: 12px; color: #999; margin-bottom: 5px; } .activation-modal .machine-code { font-family: monospace; font-size: 13px; word-break: break-all; background: #fff; padding: 8px; border-radius: 4px; border: 1px solid #ddd; } .activation-modal .btn-copy { margin-top: 8px; padding: 4px 12px; background: #1890ff; color: white; border: none; border-radius: 4px; cursor: pointer; width: 100%; } .activation-modal .qr-area { text-align: center; margin-bottom: 20px; padding: 15px; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border-radius: 12px; } .activation-modal .qr-title { font-size: 15px; color: #2c3e50; margin-bottom: 12px; font-weight: bold; } .activation-modal .qr-img { width: 180px; height: 180px; border-radius: 12px; border: 2px solid #fff; box-shadow: 0 2px 10px rgba(0,0,0,0.1); object-fit: contain; } .activation-modal .qr-note { font-size: 12px; color: #555; margin-top: 12px; } .activation-modal .license-input { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 6px; font-family: monospace; box-sizing: border-box; margin-bottom: 20px; } .activation-modal .btn-activate { flex: 1; padding: 10px; background: #52c41a; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: bold; } .activation-modal .btn-activate:hover { background: #45a817; } .activation-modal .btn-close { padding: 10px 20px; background: #999; color: white; border: none; border-radius: 6px; cursor: pointer; } .activation-modal .btn-close:hover { background: #777; } .activation-modal .footer { border-top: 1px solid #eee; padding-top: 15px; font-size: 12px; color: #999; text-align: center; } .activation-modal .btn-group { display: flex; gap: 10px; margin-bottom: 20px; } .status-badge { position: fixed; bottom: 20px; right: 20px; background: #52c41a; color: white; padding: 6px 12px; border-radius: 20px; font-size: 12px; z-index: 99999; font-family: system-ui, -apple-system, sans-serif; box-shadow: 0 2px 8px rgba(0,0,0,0.15); cursor: pointer; transition: all 0.3s ease; } .status-badge:hover { transform: scale(1.05); background: #45a817; } .status-badge.inactive { background: #ff4d4f; } `); function getMachineId() { let machineId = GM_getValue('machine_id', null); if (!machineId) { machineId = generateMachineFingerprint(); GM_setValue('machine_id', machineId); if (CONFIG.debug) console.log('[激活] 生成本机ID:', machineId); } return machineId; } function generateMachineFingerprint() { const components = [ navigator.userAgent, navigator.language, screen.width + 'x' + screen.height, screen.colorDepth, new Date().getTimezoneOffset(), navigator.hardwareConcurrency || 0, navigator.deviceMemory || 0 ]; let fingerprint = components.join('|'); let hash = 0; for (let i = 0; i < fingerprint.length; i++) { hash = ((hash << 5) - hash) + fingerprint.charCodeAt(i); hash |= 0; } return 'MACHINE_' + Math.abs(hash).toString(16) + '_' + generateRandomString(8); } function generateRandomString(length) { let result = ''; const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for (let i = 0; i < length; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } return result; } function simpleHash(str) { let hash = 0; for (let i = 0; i < str.length; i++) { hash = ((hash << 5) - hash) + str.charCodeAt(i); hash |= 0; } return Math.abs(hash).toString(16); } function verifyLicense(license, currentMachineId) { if (!license || license.length < 10) { return { valid: false, reason: '激活码格式错误' }; } try { let decoded; try { decoded = atob(license); } catch(e) { return { valid: false, reason: '激活码格式错误' }; } let decrypted = ''; for (let i = 0; i < decoded.length; i++) { decrypted += String.fromCharCode(decoded.charCodeAt(i) ^ 0x55); } const parts = decrypted.split('|'); if (parts.length !== 3) { return { valid: false, reason: '激活码格式错误' }; } const [machineId, expireTimestamp, checksum] = parts; if (machineId !== currentMachineId) { return { valid: false, reason: '机器码不匹配,请使用本机的激活码' }; } const expireTime = parseInt(expireTimestamp); if (isNaN(expireTime)) { return { valid: false, reason: '激活码格式错误' }; } if (expireTime < Date.now()) { return { valid: false, reason: '激活码已过期' }; } const expectedChecksum = simpleHash(machineId + '|' + expireTimestamp + '|' + CONFIG.secretKey); if (checksum !== expectedChecksum) { return { valid: false, reason: '激活码无效' }; } return { valid: true, expireTimestamp: expireTime }; } catch(e) { if (CONFIG.debug) console.error('[激活] 验证错误:', e); return { valid: false, reason: '激活码无效' }; } } function isActivated() { let activated = GM_getValue('activated', false); if (!activated) { return false; } const expireTime = GM_getValue('expire_time', null); if (expireTime && expireTime < Date.now()) { console.log('[激活] 激活码已过期,需要重新激活'); GM_setValue('activated', false); GM_deleteValue('expire_time'); return false; } return true; } function showActivationUI() { const existingOverlay = document.getElementById('activation-overlay'); if (existingOverlay) { existingOverlay.remove(); } const machineId = getMachineId(); const overlay = document.createElement('div'); overlay.id = 'activation-overlay'; overlay.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); z-index: 999999; display: flex; justify-content: center; align-items: center; overflow-y: auto; `; const qrcodeHtml = CONFIG.wechatQrcodeUrl && CONFIG.wechatQrcodeUrl !== "https://your-image-host.com/wechat-qrcode.png" ? `微信二维码` : `
📱 请手动添加微信
${CONFIG.contact}
`; const modal = document.createElement('div'); modal.className = 'activation-modal'; modal.innerHTML = `

🔐 脚本需要激活

本脚本为付费脚本,激活后可永久使用
💡 脚本付费才能使用!
半杯咖啡💰永久使用!付费才能保证脚本好用、持续更新、省心省力。
🚀 付费版公需课最高可 8倍 播放,专业课最高 2.5倍 播放,
🛡️ 播放自动屏蔽所有题目,节省你宝贵的时间。
📋 本机机器码(复制发给卖家)
${machineId}
📱 扫码添加微信购买激活码
${qrcodeHtml}
⚡ 添加时请备注 脚本激活
🔑 激活码
`; overlay.appendChild(modal); document.body.appendChild(overlay); const copyBtn = document.getElementById('copy-machine-id'); if (copyBtn) { copyBtn.onclick = () => { GM_setClipboard(machineId); const btn = document.getElementById('copy-machine-id'); const originalText = btn.textContent; btn.textContent = '✅ 已复制!'; btn.style.background = '#52c41a'; setTimeout(() => { btn.textContent = originalText; btn.style.background = '#1890ff'; }, 2000); }; } const activateBtn = document.getElementById('activate-btn'); if (activateBtn) { activateBtn.onclick = () => { const license = document.getElementById('license-input').value.trim(); if (!license) { alert('❌ 请输入激活码'); return; } const result = verifyLicense(license, machineId); if (result.valid) { GM_setValue('activated', true); GM_setValue('expire_time', result.expireTimestamp); alert('🎉 激活成功!即将刷新页面开始使用'); overlay.remove(); location.reload(); } else { alert(`❌ 激活失败:${result.reason}\n请联系卖家解决`); } }; } const closeBtn = document.getElementById('close-btn'); if (closeBtn) { closeBtn.onclick = () => { overlay.remove(); showStatusBadge(false); }; } } function showStatusBadge(activated) { const existingBadge = document.getElementById('activation-status-badge'); if (existingBadge) existingBadge.remove(); const badge = document.createElement('div'); badge.id = 'activation-status-badge'; badge.className = `status-badge ${activated ? '' : 'inactive'}`; badge.innerHTML = activated ? '✅ 已激活' : '⚠️ 未激活'; badge.onclick = () => { if (!activated) { showActivationUI(); } else { const expireTime = GM_getValue('expire_time', null); const expireDate = expireTime ? new Date(expireTime).toLocaleDateString() : '永久'; alert(`✅ 脚本已激活\n到期时间:${expireDate}\n如有疑问请联系卖家。`); } }; document.body.appendChild(badge); } let currentVideo = null; let currentSpeed = 2.0; let isPaused = false; function createControlPanel() { if (document.getElementById('video-control-panel')) return; const pageType = getPageType(); const config = CONFIG.speedConfig[pageType] || CONFIG.speedConfig.public_course; let speedButtonsHtml = ''; config.speeds.forEach(speed => { speedButtonsHtml += ``; }); currentSpeed = config.defaultSpeed; const panel = document.createElement('div'); panel.id = 'video-control-panel'; panel.innerHTML = `
🎬 ${config.title} + ${config.defaultSpeed}x倍速自动播放 —— 脚本精灵
${speedButtonsHtml}
⚡ 最高${Math.max(...config.speeds)}倍速,网速过慢会导致卡顿,请根据自己网速自由选择合适的倍速!
`; document.body.appendChild(panel); const pauseBtn = document.getElementById('pause-script-btn'); if (pauseBtn) { pauseBtn.onclick = () => { isPaused = !isPaused; if (isPaused) { pauseBtn.innerHTML = '▶️ 继续学习'; pauseBtn.classList.add('paused'); console.log('[控制面板] ⏸️ 脚本已暂停'); showTip('⏸️ 脚本已暂停,点击「继续学习」恢复', '#ffd700'); if (currentVideo && !currentVideo.ended) { currentVideo.pause(); } } else { pauseBtn.innerHTML = '⏸️ 暂停学习'; pauseBtn.classList.remove('paused'); console.log('[控制面板] ▶️ 脚本已继续'); showTip('▶️ 脚本已继续,继续学习', '#52c41a'); if (currentVideo && !currentVideo.ended && currentVideo.paused) { currentVideo.play().catch(e => console.log('[自动学习] 播放失败', e)); } } }; } const buttons = panel.querySelectorAll('.speed-btn'); buttons.forEach(btn => { btn.addEventListener('click', (e) => { if (isPaused) { showTip('⚠️ 请先点击「继续学习」再调整速度', '#ffaa00'); return; } const speed = parseFloat(btn.getAttribute('data-speed')); setVideoSpeed(speed); buttons.forEach(b => b.classList.remove('active')); btn.classList.add('active'); const titleDiv = panel.querySelector('.title'); if (titleDiv) { titleDiv.innerHTML = `🎬 ${config.title} + ${speed}x倍速自动播放 —— 脚本精灵`; } }); }); const defaultBtn = Array.from(buttons).find(btn => parseFloat(btn.getAttribute('data-speed')) === config.defaultSpeed ); if (defaultBtn) defaultBtn.classList.add('active'); } function setVideoSpeed(speed) { currentSpeed = speed; if (currentVideo && !currentVideo.ended) { currentVideo.playbackRate = speed; console.log(`[控制面板] 已设置播放速度为 ${speed}x`); showTip(`⚡ 播放速度已设为: ${speed}x`, '#ffd700'); } else { console.log(`[控制面板] 已保存速度设置: ${speed}x`); } } function showTip(message, color) { const tip = document.createElement('div'); tip.style.cssText = ` position: fixed; top: 80px; left: 250px; background: rgba(0,0,0,0.85); color: ${color}; padding: 8px 14px; border-radius: 8px; font-size: 14px; font-weight: bold; z-index: 99999; animation: fadeOut 1.5s ease forwards; pointer-events: none; font-family: system-ui, -apple-system, sans-serif; box-shadow: 0 2px 8px rgba(0,0,0,0.2); `; tip.innerHTML = message; document.body.appendChild(tip); const style = document.createElement('style'); style.textContent = ` @keyframes fadeOut { 0% { opacity: 1; transform: translateY(0); } 70% { opacity: 1; transform: translateY(-5px); } 100% { opacity: 0; transform: translateY(-10px); display: none; } } `; document.head.appendChild(style); setTimeout(() => { tip.remove(); style.remove(); }, 1500); } GM_registerMenuCommand('📋 复制机器码', () => { GM_setClipboard(getMachineId()); alert('机器码已复制到剪贴板'); console.log('[激活] 机器码已复制'); }); GM_registerMenuCommand('📊 查看激活状态', () => { const activated = isActivated(); if (activated) { const expireTime = GM_getValue('expire_time', null); const expireDate = expireTime ? new Date(expireTime).toLocaleString() : '永久'; alert(`✅ 脚本已激活\n到期时间:${expireDate}`); } else { alert('❌ 脚本未激活\n请点击右下角「未激活」按钮进行激活'); } }); const activated = isActivated(); if (!activated) { console.log('[自动学习] ⚠️ 脚本未激活,请购买激活码'); showActivationUI(); showStatusBadge(false); return; } console.log('[自动学习] ✅ 已激活,开始执行自动学习'); showStatusBadge(true); const currentUrl = window.location.href; console.log(`[自动学习] 当前页面: ${currentUrl}`); if (currentUrl.includes('/public_course/index.html') || currentUrl.includes('/classes/index.html')) { console.log('[自动学习] 进入课程列表页,准备查找"待学习"课程...'); createControlPanel(); window.addEventListener('load', () => { setTimeout(() => { if (!isPaused) { findAndJumpToCourse(); } else { console.log('[自动学习] ⏸️ 脚本已暂停,不自动跳转'); } }, 1500); }); function findAndJumpToCourse() { if (isPaused) { console.log('[自动学习] ⏸️ 脚本已暂停,不执行跳转'); return; } const allElements = document.querySelectorAll('*'); let targetElement = null; for (let el of allElements) { if (el.children.length === 0 && el.innerText && el.innerText.trim() === '待学习') { targetElement = el; break; } } if (!targetElement) { console.warn('[自动学习] ⚠️ 未找到"待学习"课程'); return; } let parentContainer = targetElement.closest('.course-item, li, tr, div, .list-group-item'); if (!parentContainer) { parentContainer = targetElement.parentElement; while (parentContainer && !parentContainer.querySelector('a[data-href*="video"], a[onclick*="open_video"]')) { parentContainer = parentContainer.parentElement; } } if (!parentContainer) { console.error('[自动学习] ❌ 未找到播放链接容器'); return; } const playLink = parentContainer.querySelector('a[data-href*="video"], a[onclick*="open_video"]'); if (!playLink) { console.error('[自动学习] ❌ 未找到播放链接'); return; } let targetUrl = null; if (playLink.getAttribute('data-href')) { let href = playLink.getAttribute('data-href'); if (href.startsWith('/')) { targetUrl = 'https://www.gdysxh.com' + href; } else { const basePath = currentUrl.includes('/classes/') ? '/my_classes/classes/' : '/my_classes/public_course/'; targetUrl = 'https://www.gdysxh.com' + basePath + href; } } else if (playLink.getAttribute('onclick')) { const onclick = playLink.getAttribute('onclick'); const match = onclick.match(/open_video\([^,]*,\s*'([^']+)'/); if (match && match[1]) { const basePath = currentUrl.includes('/classes/') ? 'classes' : 'public_course'; targetUrl = `https://www.gdysxh.com/my_classes/${basePath}/video/course_id/${match[1]}/order_id/xxx.html`; } } if (targetUrl && !isPaused) { console.log(`[自动学习] 🚀 跳转到: ${targetUrl}`); window.location.href = targetUrl; } else { console.error('[自动学习] ❌ 无法获取跳转链接'); } } } else if (currentUrl.includes('/public_course/video/') || currentUrl.includes('/classes/video/')) { console.log('[自动学习] 进入视频播放页,准备自动播放...'); createControlPanel(); let checkVideoInterval = setInterval(() => { const video = document.querySelector('video'); if (video) { clearInterval(checkVideoInterval); console.log('[自动学习] ✅ 视频元素已加载'); currentVideo = video; initVideoControl(video); } else { console.log('[自动学习] ⏳ 等待视频元素加载...'); } }, 500); function initVideoControl(video) { if (!isPaused) { video.playbackRate = currentSpeed; console.log(`[自动学习] 🚀 播放速度: ${video.playbackRate}x`); video.muted = true; video.play().then(() => { console.log('[自动学习] ✅ 视频已自动播放'); }).catch(e => { console.warn('[自动学习] ⚠️ 自动播放失败', e); }); } else { console.log('[自动学习] ⏸️ 脚本已暂停,不自动播放'); } video.addEventListener('ratechange', () => { if (!isPaused) { console.log(`[自动学习] 速度变更为: ${video.playbackRate}x`); currentSpeed = video.playbackRate; updateSpeedButtonHighlight(video.playbackRate); } }); let closeInterval = setInterval(() => { if (!isPaused) { if (typeof layer !== 'undefined' && layer.closeAll) { layer.closeAll(); console.log('[自动学习] 🛡️ 已清理弹窗'); } const popups = document.querySelectorAll('.layui-layer, .layui-layer-shade'); if (popups.length) { popups.forEach(el => el.remove()); console.log(`[自动学习] 🛡️ 清理 ${popups.length} 个弹窗`); } } }, 1000); // ========== 新增:轮询检查视频暂停状态 ========== let pausedCheckInterval = setInterval(() => { if (!isPaused && video && !video.ended) { if (video.paused) { console.log('[自动学习] 🔄 检测到视频暂停,尝试恢复播放...'); video.play().then(() => { console.log('[自动学习] ✅ 视频已恢复播放'); }).catch(e => { console.warn('[自动学习] ⚠️ 恢复播放失败', e); }); } } }, 2000); // ========== 新增结束 ========== let endCheckInterval = setInterval(() => { if (!isPaused && video.ended) { console.log('[自动学习] 🎉 视频结束,返回列表'); clearInterval(closeInterval); clearInterval(endCheckInterval); clearInterval(pausedCheckInterval); // 清理暂停检查器 const returnUrl = currentUrl.includes('/classes/') ? 'https://www.gdysxh.com/my_classes/classes/index.html' : 'https://www.gdysxh.com/my_classes/public_course/index.html'; window.location.href = returnUrl; } else if (!isPaused) { console.log(`[自动学习] ⏰ 播放中: ${Math.floor(video.currentTime)}/${Math.floor(video.duration)}秒 | 速度: ${video.playbackRate}x`); } }, 5000); } function updateSpeedButtonHighlight(speed) { const panel = document.getElementById('video-control-panel'); if (!panel) return; const buttons = panel.querySelectorAll('.speed-btn'); buttons.forEach(btn => { const btnSpeed = parseFloat(btn.getAttribute('data-speed')); if (Math.abs(btnSpeed - speed) < 0.1) { btn.classList.add('active'); } else { btn.classList.remove('active'); } }); const pageType = getPageType(); const config = CONFIG.speedConfig[pageType] || CONFIG.speedConfig.public_course; const titleDiv = panel.querySelector('.title'); if (titleDiv) { titleDiv.innerHTML = `🎬 ${config.title} + ${speed}x倍速自动播放 —— 脚本精灵`; } } } })();