// ==UserScript== // @name 华医网课程自动收藏工具-增强版(批量)V2.5 稳定【赛博朋克风格】 // @namespace http://tampermonkey.net/ // @version 2.5 // @description 华医网课程批量收藏工具!稳定!业内人士专用! // @author vx:hapens1986 课程代学可咨询! // @license MIT // @match https://cme28.91huayi.com/* // @ICON https://cdn-icons-png.flaticon.com/128/4594/4594681.png // @grant GM_addStyle // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_openInTab // @grant GM_notification // @connect 91huayi.com // ==/UserScript== (function() { 'use strict'; GM_addStyle(` #cid-input-container { position: fixed; top: 100px; right: 20px; z-index: 9999; background: #0a0a1a; padding: 15px; border: 1px solid #00f0ff; border-radius: 5px; box-shadow: 0 0 10px rgba(0, 240, 255, 0.3); font-family: 'Courier New', monospace; width: 300px; cursor: move; color: #00f0ff; } #cid-input-container.dragging { opacity: 0.8; box-shadow: 0 0 15px rgba(0, 240, 255, 0.5); } #cid-input-container-header { padding: 5px; margin: -15px -15px 10px -15px; background: #121230; border-bottom: 1px solid #00f0ff; border-radius: 5px 5px 0 0; font-weight: bold; user-select: none; text-shadow: 0 0 5px #00f0ff; } #cid-input, #cid-input-batch { width: 100%; padding: 8px; margin: 10px 0 5px; background: #0f0f1a; border: 1px solid #ff00aa; border-radius: 3px; box-sizing: border-box; color: #00f0ff; font-family: 'Courier New', monospace; } #cid-input-batch { height: 300px; resize: vertical; } #collect-btn, #batch-collect-btn { background: linear-gradient(90deg, #ff00aa, #00f0ff); color: #0a0a1a; border: none; padding: 8px 15px; border-radius: 3px; cursor: pointer; width: 100%; margin: 5px 0; font-weight: bold; transition: all 0.3s; text-shadow: none; } #batch-collect-btn { background: linear-gradient(90deg, #00f0ff, #ff00aa); } #collect-btn:hover, #batch-collect-btn:hover { box-shadow: 0 0 10px rgba(0, 240, 255, 0.7); } #collect-btn:disabled, #batch-collect-btn:disabled { background: #333344; color: #666677; cursor: not-allowed; box-shadow: none; } #status-message { margin-top: 10px; font-size: 13px; line-height: 1.4; } .success { color: #00ff88; text-shadow: 0 0 3px #00ff88; } .error { color: #ff0055; text-shadow: 0 0 3px #ff0055; } .warning { color: #ffaa00; text-shadow: 0 0 3px #ffaa00; } .loading { color: #00f0ff; text-shadow: 0 0 3px #00f0ff; } .course-name { font-weight: bold; margin: 5px 0; } .hidden-iframe { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); border: 0; } .toggle-mode-btn { background: #333344; color: #00f0ff; border: 1px solid #00f0ff; padding: 6px 12px; border-radius: 3px; cursor: pointer; width: 100%; margin: 5px 0; transition: all 0.3s; font-size: 13px; } .toggle-mode-btn:hover { background: #444455; box-shadow: 0 0 8px rgba(0, 240, 255, 0.5); } .batch-instruction { font-size: 12px; color: #6666ff; margin: 5px 0; } .progress-container { margin: 10px 0; font-size: 13px; font-family: 'Courier New', monospace; } .progress-text { font-weight: bold; color: #00f0ff; text-shadow: 0 0 3px #00f0ff; } .cyber-progress { height: 20px; background: #0f0f1a; position: relative; overflow: hidden; border: 1px solid #00f0ff; box-shadow: 0 0 10px rgba(0, 240, 255, 0.3); margin-top: 5px; } .cyber-bar { height: 100%; width: 0%; background: linear-gradient(90deg, #ff00aa, #00f0ff); transition: width 0.5s ease; position: relative; } .cyber-glitch { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient( 90deg, transparent 25%, rgba(255, 255, 255, 0.3) 50%, transparent 75% ); background-size: 200% 100%; animation: glitch 2s linear infinite; opacity: 0.3; } @keyframes glitch { 0% { background-position: 200% 0; } } @media (max-width: 400px) { #cid-input-container { width: 280px; right: 10px; } } `); const container = document.createElement('div'); container.id = 'cid-input-container'; container.innerHTML = `
华医网课程收藏工具V2.5
进度: 0% [0/0]
`; document.body.appendChild(container); // 获取元素 const cidInput = document.getElementById('cid-input'); const cidInputBatch = document.getElementById('cid-input-batch'); const collectBtn = document.getElementById('collect-btn'); const batchCollectBtn = document.getElementById('batch-collect-btn'); const statusMessage = document.getElementById('status-message'); const hiddenIframe = document.getElementById('hidden-iframe'); const singleMode = document.getElementById('single-mode'); const batchMode = document.getElementById('batch-mode'); const modeToggle = document.getElementById('mode-toggle'); const progressText = document.querySelector('.progress-text'); const cyberProgressBar = document.getElementById('cyber-progress-bar'); // 当前模式 let isBatchMode = false; // 设置状态消息 function setStatus(message, type = '') { statusMessage.innerHTML = message; statusMessage.className = type; } // 更新进度条 function updateProgress(current, total) { const percent = Math.round((current / total) * 100); progressText.textContent = `进度: ${percent}% [${current}/${total}]`; cyberProgressBar.style.width = `${percent}%`; } // 初始化拖动功能 function initDrag() { const container = document.getElementById('cid-input-container'); const header = document.getElementById('cid-input-container-header'); let isDragging = false; let offsetX, offsetY; header.addEventListener('mousedown', function(e) { isDragging = true; container.classList.add('dragging'); // 计算鼠标位置与面板位置的偏移量 const rect = container.getBoundingClientRect(); offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; e.preventDefault(); }); document.addEventListener('mousemove', function(e) { if (!isDragging) return; // 计算新位置 let left = e.clientX - offsetX; let top = e.clientY - offsetY; // 限制在视窗范围内 const maxLeft = window.innerWidth - container.offsetWidth; const maxTop = window.innerHeight - container.offsetHeight; left = Math.max(0, Math.min(left, maxLeft)); top = Math.max(0, Math.min(top, maxTop)); // 应用新位置 container.style.left = left + 'px'; container.style.top = top + 'px'; container.style.right = 'auto'; }); document.addEventListener('mouseup', function() { isDragging = false; container.classList.remove('dragging'); }); } // 切换模式 function toggleMode() { isBatchMode = !isBatchMode; singleMode.style.display = isBatchMode ? 'none' : 'block'; batchMode.style.display = isBatchMode ? 'block' : 'none'; modeToggle.textContent = isBatchMode ? '切换到单条模式' : '切换到批量模式'; setStatus(''); updateProgress(0, 0); } // 获取课程信息 async function getCourseInfo(cid) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: `https://cme28.91huayi.com/pages/course.aspx?cid=${cid}`, onload: function(response) { try { const parser = new DOMParser(); const doc = parser.parseFromString(response.responseText, "text/html"); const title = doc.querySelector('h1.course-title')?.textContent?.trim() || `课程 (CID: ${cid})`; const isCollected = doc.getElementById('btnCollect')?.getAttribute('data-collect') === '1'; resolve({ title, isCollected }); } catch (e) { reject(`解析课程页面失败: ${e.message}`); } }, onerror: function(error) { reject(`获取课程信息失败: ${error.statusText}`); }, timeout: 10000 }); }); } function collectWithIframe(cid, title) { return new Promise((resolve) => { hiddenIframe.src = `https://cme28.91huayi.com/pages/course.aspx?cid=${cid}`; let checkCount = 0; const maxChecks = 5; const checkInterval = 1000; const checkCollection = setInterval(() => { checkCount++; try { const iframeDoc = hiddenIframe.contentDocument || hiddenIframe.contentWindow.document; const collectBtn = iframeDoc.getElementById('btnCollect'); if (collectBtn) { clearInterval(checkCollection); if (collectBtn.getAttribute('data-collect') === '1') { resolve(true); } else { collectBtn.click(); setTimeout(() => { resolve(true); }, 1500); } } else if (checkCount >= maxChecks) { clearInterval(checkCollection); resolve(false); } } catch (e) { if (checkCount >= maxChecks) { clearInterval(checkCollection); resolve(false); } } }, checkInterval); setTimeout(() => { clearInterval(checkCollection); resolve(false); }, (maxChecks + 2) * checkInterval); }); } // 收藏单个课程 async function collectSingleCourse(cid) { try { // 获取课程信息 const { title, isCollected } = await getCourseInfo(cid); if (isCollected) { return { success: false, message: `课程已收藏: ${title}` }; } // 使用iframe方式收藏 const success = await collectWithIframe(cid, title); if (success) { return { success: true, message: `收藏成功: ${title}` }; } else { GM_openInTab(`https://cme28.91huayi.com/pages/course.aspx?cid=${cid}`, false); return { success: false, message: `请在新标签页中手动收藏: ${title}` }; } } catch (error) { return { success: false, message: `收藏失败: ${error}` }; } } async function handleSingleCollect() { const cid = cidInput.value.trim(); if (!cid) { setStatus('请输入有效的CID值', 'error'); return; } collectBtn.disabled = true; setStatus('正在处理...', 'loading'); updateProgress(0, 1); const result = await collectSingleCourse(cid); updateProgress(1, 1); if (result.success) { setStatus(`
${result.message}
`, 'success'); GM_notification({ title: '收藏成功', text: result.message, timeout: 3000, highlight: true }); } else { setStatus(`
${result.message}
`, result.message.includes('手动收藏') ? 'warning' : 'error'); } collectBtn.disabled = false; } async function handleBatchCollect() { const input = cidInputBatch.value.trim(); if (!input) { setStatus('请输入有效的CID值', 'error'); return; } const cids = input.split(/[\n,]+/).map(cid => cid.trim()).filter(cid => cid); if (cids.length === 0) { setStatus('未检测到有效的CID值', 'error'); return; } batchCollectBtn.disabled = true; setStatus(`准备收藏 ${cids.length} 个课程...`, 'loading'); updateProgress(0, cids.length); let successCount = 0; let messages = []; // 逐个处理课程 for (let i = 0; i < cids.length; i++) { const cid = cids[i]; setStatus(`正在处理第 ${i+1}/${cids.length} 个课程 (CID: ${cid})...`, 'loading'); updateProgress(i, cids.length); const result = await collectSingleCourse(cid); if (result.success) { successCount++; messages.push(`✓ ${result.message}`); } else { messages.push(`✗ ${result.message}`); } // 稍微延迟一下,避免请求过于频繁 await new Promise(resolve => setTimeout(resolve, 500)); } // 显示最终结果 updateProgress(cids.length, cids.length); setStatus(`
已完成 ${cids.length} 个课程处理
成功收藏: ${successCount}
失败: ${cids.length - successCount}
${messages.join('
')}
`, successCount === cids.length ? 'success' : (successCount > 0 ? 'warning' : 'error')); batchCollectBtn.disabled = false; // 显示桌面通知 if (successCount > 0) { GM_notification({ title: '批量收藏完成', text: `成功收藏 ${successCount}/${cids.length} 个课程`, timeout: 5000, highlight: true }); } } // 监听收藏按钮点击 collectBtn.addEventListener('click', handleSingleCollect); batchCollectBtn.addEventListener('click', handleBatchCollect); modeToggle.addEventListener('click', toggleMode); // 监听输入框回车键 cidInput.addEventListener('keypress', function(e) { if (e.key === 'Enter') { handleSingleCollect(); } }); // 初始化拖动功能 initDrag(); // 自动填充当前页面CID function getCIDFromURL() { const urlParams = new URLSearchParams(window.location.search); return urlParams.get('cid'); } const currentCID = getCIDFromURL(); if (currentCID) { cidInput.value = currentCID; } })();