// ==UserScript== // @name 高教在线刷课助手(谷歌适配版) // @namespace http://tampermonkey.net/ // @version 0.0.7 // @description 修复谷歌浏览器窗口拖拽问题,优化兼容性 // @author Sweek // @match *://*.cqooc.com/* // @license GPLv3 // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @run-at document-idle // ==/UserScript== (function() { 'use strict'; // 单实例控制(防止重复加载) const instanceKey = 'sweek_cqooc_helper_v06'; if (GM_getValue(instanceKey)) { return; } GM_setValue(instanceKey, true); window.addEventListener('beforeunload', () => { GM_setValue(instanceKey, false); }); // 核心样式(适配谷歌浏览器) GM_addStyle(` #sweek-helper-window { position: fixed !important; top: 20px !important; left: 20px !important; width: 380px !important; height: 500px !important; background: white !important; border: 2px solid #479e82 !important; border-radius: 8px !important; z-index: 2147483647 !important; /* 谷歌最大z-index值 */ box-shadow: 0 0 15px rgba(0,0,0,0.2) !important; overflow: hidden !important; font-family: "Microsoft YaHei", sans-serif !important; transform: translateZ(0) !important; /* 启用硬件加速 */ pointer-events: auto !important; /* 确保能接收鼠标事件 */ } #sweek-window-header { height: 45px !important; background: #479e82 !important; color: white !important; padding: 0 15px !important; line-height: 45px !important; font-size: 15px !important; font-weight: bold !important; cursor: grab !important; display: flex !important; justify-content: space-between !important; align-items: center !important; user-select: none !important; /* 禁止文本选择干扰拖拽 */ } #sweek-window-header:active { cursor: grabbing !important; } #sweek-minimize-btn { width: 30px !important; height: 30px !important; line-height: 30px !important; text-align: center !important; cursor: pointer !important; border-radius: 4px !important; background: rgba(255,255,255,0.2) !important; transition: all 0.2s !important; } #sweek-minimize-btn:hover { background: rgba(255,255,255,0.3) !important; } #sweek-tab-container { height: 40px !important; display: flex !important; border-bottom: 1px solid #eee !important; } .sweek-tab { flex: 1 !important; text-align: center !important; line-height: 40px !important; cursor: pointer !important; font-size: 14px !important; color: #666 !important; background: #f5f5f5 !important; user-select: none !important; } .sweek-tab.active { background: white !important; color: #479e82 !important; border-bottom: 2px solid #479e82 !important; } #sweek-content-container { height: calc(100% - 85px) !important; overflow: hidden !important; } .sweek-content { height: 100% !important; overflow-y: auto !important; padding: 10px !important; display: none !important; } .sweek-content.active { display: block !important; } #sweek-log-container { color: #333 !important; font-size: 13px !important; line-height: 1.6 !important; } #sweek-status-container { color: #333 !important; font-size: 13px !important; line-height: 1.8 !important; } .sweek-log-item { margin: 3px 0 !important; padding: 2px 0 !important; border-bottom: 1px dashed #f0f0f0 !important; } .sweek-notification { position: fixed !important; top: 20px !important; right: 20px !important; padding: 12px 15px !important; background: white !important; border-left: 4px solid #479e82 !important; box-shadow: 0 2px 10px rgba(0,0,0,0.1) !important; z-index: 2147483646 !important; font-size: 14px !important; color: #333 !important; } `); // 全局变量 let taskQueue = []; let isWindowMinimized = false; let dragState = { isDragging: false, offsetX: 0, offsetY: 0, initialX: 0, initialY: 0 }; let activeTimer = null; let helperWindow = null; // 窗口DOM引用 // 初始化窗口 function initWindow() { // 清理旧窗口 const oldWindow = document.getElementById('sweek-helper-window'); if (oldWindow) oldWindow.remove(); // 创建新窗口 helperWindow = document.createElement('div'); helperWindow.id = 'sweek-helper-window'; helperWindow.innerHTML = `
高教在线刷课助手 v0.0.6
状态信息
执行日志

初始化中...

[${getCurrentTime()}] 日志启动
`; document.body.appendChild(helperWindow); // 绑定窗口事件 bindWindowEvents(); addLog('窗口初始化完成(谷歌适配版)'); } // 绑定窗口事件(重点修复拖拽问题) function bindWindowEvents() { const header = helperWindow.querySelector('#sweek-window-header'); const minimizeBtn = helperWindow.querySelector('#sweek-minimize-btn'); const tabContainer = helperWindow.querySelector('#sweek-tab-container'); // 窗口拖拽(谷歌浏览器兼容版) header.addEventListener('mousedown', startDrag); document.addEventListener('mousemove', handleDrag); document.addEventListener('mouseup', endDrag); document.addEventListener('mouseleave', endDrag); // 鼠标离开窗口时结束拖拽 // 最小化功能 minimizeBtn.addEventListener('click', () => { isWindowMinimized = !isWindowMinimized; const contentContainer = helperWindow.querySelector('#sweek-content-container'); const tabContainerEl = helperWindow.querySelector('#sweek-tab-container'); if (isWindowMinimized) { contentContainer.style.display = 'none'; tabContainerEl.style.display = 'none'; helperWindow.style.height = '45px'; minimizeBtn.textContent = '□'; } else { contentContainer.style.display = 'block'; tabContainerEl.style.display = 'flex'; helperWindow.style.height = '500px'; minimizeBtn.textContent = '—'; } }); // Tab切换 tabContainer.addEventListener('click', (e) => { const tab = e.target.closest('.sweek-tab'); if (!tab) return; helperWindow.querySelectorAll('.sweek-tab').forEach(el => el.classList.remove('active')); tab.classList.add('active'); const tabName = tab.dataset.tab; helperWindow.querySelectorAll('.sweek-content').forEach(el => el.classList.remove('active')); helperWindow.querySelector(`#sweek-${tabName}-container`).classList.add('active'); }); } // 拖拽相关函数(谷歌浏览器专用修复) function startDrag(e) { // 只响应左键点击 if (e.button !== 0) return; e.preventDefault(); e.stopPropagation(); // 阻止事件冒泡到父元素 const rect = helperWindow.getBoundingClientRect(); dragState.isDragging = true; dragState.offsetX = e.clientX - rect.left; dragState.offsetY = e.clientY - rect.top; dragState.initialX = rect.left; dragState.initialY = rect.top; // 增加拖拽时的视觉反馈 helperWindow.style.transition = 'none'; // 拖拽时关闭动画 helperWindow.style.boxShadow = '0 0 20px rgba(0,0,0,0.3)'; } function handleDrag(e) { if (!dragState.isDragging) return; e.preventDefault(); e.stopPropagation(); // 计算新位置 const newX = e.clientX - dragState.offsetX; const newY = e.clientY - dragState.offsetY; // 限制在可视区域内 const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const windowWidth = helperWindow.offsetWidth; const windowHeight = helperWindow.offsetHeight; const constrainedX = Math.max(0, Math.min(newX, viewportWidth - windowWidth)); const constrainedY = Math.max(0, Math.min(newY, viewportHeight - windowHeight)); // 应用新位置(使用transform提高谷歌浏览器性能) helperWindow.style.transform = `translate(${constrainedX}px, ${constrainedY}px)`; helperWindow.style.left = '0px'; helperWindow.style.top = '0px'; } function endDrag(e) { if (!dragState.isDragging) return; dragState.isDragging = false; // 恢复样式 helperWindow.style.transition = 'box-shadow 0.2s'; helperWindow.style.boxShadow = '0 0 15px rgba(0,0,0,0.2)'; // 保存最终位置(转换transform为left/top) const transform = helperWindow.style.transform; if (transform) { const match = transform.match(/translate\((\d+)px, (\d+)px\)/); if (match) { helperWindow.style.left = `${match[1]}px`; helperWindow.style.top = `${match[2]}px`; helperWindow.style.transform = 'translateZ(0)'; // 只保留硬件加速 } } } // 工具函数 function getCurrentTime() { const date = new Date(); return date.toLocaleTimeString('zh-CN', { hour12: false }); } function formatTime(seconds) { const mins = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${mins}:${secs < 10 ? '0' + secs : secs}`; } function addLog(message) { const logContainer = helperWindow.querySelector('#sweek-log-container'); if (!logContainer) return; const logItem = document.createElement('div'); logItem.className = 'sweek-log-item'; logItem.textContent = `[${getCurrentTime()}] ${message}`; logContainer.appendChild(logItem); logContainer.scrollTop = logContainer.scrollHeight; } function updateStatus(html) { const statusContainer = helperWindow.querySelector('#sweek-status-container'); if (statusContainer) { statusContainer.innerHTML = html; } } function showNotification(message, duration = 3000) { const notification = document.createElement('div'); notification.className = 'sweek-notification'; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.style.opacity = '0'; notification.style.transition = 'opacity 0.3s'; setTimeout(() => notification.remove(), 300); }, duration); } // 内容处理函数(保持原有功能) function getContentType() { const body = document.body.innerHTML.toLowerCase(); if (body.includes('ppt') || body.includes('powerpoint') || body.includes('幻灯片') || body.includes('slide') && !body.includes('video')) { return 'ppt'; } else if (body.includes('video') || body.includes('dplayer')) { return 'video'; } else if (body.includes('pdf') || body.includes('pdf-viewer')) { return 'pdf'; } return 'unknown'; } function handlePPT() { return new Promise((resolve) => { const totalSeconds = 35; let remainingSeconds = totalSeconds; addLog(`开始处理PPT,${totalSeconds}秒后完成`); if (activeTimer) clearInterval(activeTimer); // 精确计时 const startTime = Date.now(); activeTimer = setInterval(() => { const elapsed = Math.floor((Date.now() - startTime) / 1000); remainingSeconds = totalSeconds - elapsed; if (remainingSeconds <= 0) { clearInterval(activeTimer); activeTimer = null; addLog('PPT处理完成'); resolve(); } else { const progress = ((totalSeconds - remainingSeconds) / totalSeconds) * 100; updateStatus(`

内容类型: PPT

处理进度: ${progress.toFixed(1)}%

剩余时间: ${remainingSeconds}秒

`); } }, 1000); }); } function handleVideo() { return new Promise((resolve) => { addLog('开始处理视频'); const video = document.querySelector('video'); if (!video) { addLog('未找到视频,5秒后重试'); setTimeout(resolve, 5000); return; } if (activeTimer) clearInterval(activeTimer); function forcePlay() { if (video.paused && !video.ended) { video.play().catch(() => { video.muted = true; video.play().catch(err => addLog(`播放失败: ${err.message}`)); }); } } video.playbackRate = 1.5; addLog(`视频倍速: ${video.playbackRate}x`); forcePlay(); video.addEventListener('pause', forcePlay); activeTimer = setInterval(() => { if (video.duration) { const progress = (video.currentTime / video.duration) * 100; updateStatus(`

内容类型: 视频

进度: ${progress.toFixed(1)}%

时长: ${formatTime(video.currentTime)}/${formatTime(video.duration)}

倍速: ${video.playbackRate}x

`); } }, 1000); const endHandler = () => { clearInterval(activeTimer); activeTimer = null; video.removeEventListener('ended', endHandler); video.removeEventListener('pause', forcePlay); addLog('视频播放完成'); resolve(); }; video.addEventListener('ended', endHandler); }); } function handlePDF() { return new Promise((resolve) => { addLog('开始处理PDF,35秒后完成'); let countdown = 35; if (activeTimer) clearInterval(activeTimer); activeTimer = setInterval(() => { countdown--; const progress = ((35 - countdown) / 35) * 100; updateStatus(`

内容类型: PDF

进度: ${progress.toFixed(1)}%

剩余: ${countdown}秒

`); if (countdown <= 0) { clearInterval(activeTimer); activeTimer = null; addLog('PDF处理完成'); resolve(); } }, 1000); }); } async function processCurrentContent() { const contentType = getContentType(); addLog(`检测到内容类型: ${contentType}`); switch (contentType) { case 'video': await handleVideo(); break; case 'pdf': await handlePDF(); break; case 'ppt': await handlePPT(); break; default: addLog('未知内容类型,35秒后跳过'); await new Promise(resolve => setTimeout(resolve, 35000)); break; } } function goToNextTask() { if (taskQueue.length === 0) { addLog('所有任务已完成'); updateStatus('

所有任务已完成!

'); return; } const nextTask = taskQueue.shift(); const taskText = nextTask.textContent.trim().substring(0, 20) + '...'; addLog(`准备处理: ${taskText}`); updateStatus(`

准备处理: ${taskText}

`); setTimeout(() => { nextTask.click(); setTimeout(async () => { await processCurrentContent(); setTimeout(goToNextTask, 3000); }, 5000); }, 1000); } function getTaskList() { return Array.from(document.querySelectorAll('.third-level-box')).filter(el => { const text = el.textContent.toLowerCase(); return !text.includes('作业') && !text.includes('测验') && !text.includes('考试'); }); } function startTasks() { const tasks = getTaskList(); if (tasks.length === 0) { addLog('未找到可处理的任务'); updateStatus('

未找到可处理的任务

'); return; } const activeIndex = tasks.findIndex(el => el.classList.contains('active')); taskQueue = tasks.slice(activeIndex > -1 ? activeIndex : 0); addLog(`共${tasks.length}个任务,从第${activeIndex + 1}个开始`); updateStatus(`

总任务: ${tasks.length}个

剩余: ${taskQueue.length}个

开始处理...

`); goToNextTask(); } // 初始化函数 function init() { // 确保在文档完全就绪后初始化 if (document.readyState !== 'complete') { setTimeout(init, 500); return; } initWindow(); addLog('谷歌浏览器适配版启动成功'); const currentPath = window.location.pathname; if (currentPath.includes('/course/detail/courseStudy')) { showNotification('已进入课程页面,即将开始处理', 3000); setTimeout(startTasks, 2000); } else if (currentPath.includes('/account/course')) { showNotification('请选择要学习的课程', 3000); } else { showNotification('请先进入"在学课程"页面', 3000); } } // 启动 init(); })();