// ==UserScript== // @name 小雅自动刷 // @namespace http://tampermonkey.net/ // @version 1.1 // @description 小雅平台自动刷课脚本。 // @author Qy // @match https://*.ai-augmented.com/* // @connect docs.qq.com // @grant GM_xmlhttpRequest // @icon data:image/png;base64,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 // @run-at document-end // ==/UserScript== (function () { 'use strict'; const STORAGE_KEY = 'xy_qy_task_queue'; const POS_KEY = 'xy_qy_ui_pos'; const NOTICE_CACHE_KEY = 'xy_qy_notice_cache'; const DOMAIN = window.location.hostname; const DEFAULT_DURATION = 10; const NOTICE_URL = "https://docs.qq.com/doc/DYXZ5VUpyVXRnU1Fx"; let taskQueue = []; let heartbeatInterval = null; let timerInterval = null; let isExpanded = false; let currentTask = null; let remainingTime = 0; let uiPos = null; let noticeContent = "⏳ 初始化中..."; function loadData() { try { const q = localStorage.getItem(STORAGE_KEY); const p = localStorage.getItem(POS_KEY); if (q) taskQueue = JSON.parse(q); if (p) uiPos = JSON.parse(p); } catch (e) { taskQueue = []; } } function saveData() { localStorage.setItem(STORAGE_KEY, JSON.stringify(taskQueue)); } function savePos(top, left) { uiPos = { top, left }; localStorage.setItem(POS_KEY, JSON.stringify(uiPos)); } function getCookie(keyword = 'prd-access-token') { const cookies = document.cookie.split('; '); for (const cookie of cookies) { const [name, value] = cookie.split('='); if (name.includes(keyword)) return value; } return null; } function getPageInfo() { const url = window.location.href; const match = url.match(/mycourse\/(\d+)\/resource\/(\d+)\/(\d+)/); if (match) return { groupId: match[1], resourceId: match[2], nodeId: match[3] }; return { groupId: null, resourceId: null, nodeId: null }; } function formatSeconds(s) { if (!s || s < 0) return "0:00"; const min = Math.floor(s / 60); const sec = Math.floor(s % 60); return `${min}:${sec.toString().padStart(2, '0')}`; } function runOneShotNoticeCheck() { const isDangerZone = /\/mycourse\/\d+/.test(window.location.href); if (isDangerZone) { const cached = localStorage.getItem(NOTICE_CACHE_KEY); if (cached) { noticeContent = cached; } else { noticeContent = "⚠️ 读取失败,为了防止检测,请离开课程区返回首页后再尝试读取公告。"; } } else { GM_xmlhttpRequest({ method: "GET", url: NOTICE_URL, onload: function(response) { try { const match = response.responseText.match(/(.*?)<\/title>/); let title = match ? match[1] : "暂无公告"; title = title.replace(" - 腾讯文档", "").trim(); const tempSpan = document.createElement('span'); tempSpan.innerHTML = title; const finalContent = "📢 " + tempSpan.innerText; localStorage.setItem(NOTICE_CACHE_KEY, finalContent); noticeContent = finalContent; const el = document.getElementById('xy-notice-board'); if (el) el.innerText = finalContent; } catch (e) { noticeContent = "❌ 公告解析失败"; } }, onerror: function() { noticeContent = "❌ 公告网络错误"; } }); } } async function submitFinishActivity() { if (!currentTask) return; const { groupId } = getPageInfo(); const token = getCookie(); try { const res = await fetch(`https://${DOMAIN}/api/jx-iresource/resource/finishActivity`, { method: 'POST', headers: { 'authorization': `Bearer ${token}`, 'content-type': 'application/json; charset=UTF-8' }, body: JSON.stringify({ group_id: groupId, node_id: currentTask.nodeId, task_id: currentTask.taskId }) }); await res.json(); } catch (e) { } } function tryReadVideoDuration(retryCount = 0) { if (!currentTask || (currentTask.duration && currentTask.duration > 0)) return; const video = document.querySelector('video'); const { nodeId } = getPageInfo(); if (!nodeId || String(nodeId) !== String(currentTask.nodeId)) return; if (video && video.duration && video.duration > 1) { const realDuration = Math.ceil(video.duration) + 5; updateTaskDuration(realDuration); } else { if (retryCount < 2) { setTimeout(() => tryReadVideoDuration(retryCount + 1), 2000); } else { updateTaskDuration(DEFAULT_DURATION * 60); } } } function updateTaskDuration(seconds) { if (!currentTask) return; currentTask.duration = seconds; remainingTime = seconds; const index = taskQueue.findIndex(t => String(t.nodeId) === String(currentTask.nodeId)); if (index !== -1) { taskQueue[index].duration = seconds; saveData(); } renderUI(); } function tryAutoPlay() { const video = document.querySelector('video'); if (video && video.paused) { video.muted = true; video.play().catch(() => {}); } } async function fetchResources(groupId, token) { try { const res = await fetch(`https://${DOMAIN}/api/jx-iresource/resource/queryCourseResources?group_id=${groupId}`, { headers: { "authorization": `Bearer ${token}` } }); const data = await res.json(); return data.success ? data.data : []; } catch (e) { return []; } } async function fetchTasksFromApi() { const { groupId } = getPageInfo(); const token = getCookie(); if (!groupId || !token) { alert("请先进入具体的课程页面再点击刷新!"); return; } const btn = document.getElementById('xy-refresh-btn'); if(btn) btn.innerText = "加载中..."; try { const [taskRes, resourceList] = await Promise.all([ fetch(`https://${DOMAIN}/api/jx-stat/group/task/queryTaskNotices?group_id=${groupId}&role=1`, { headers: { "authorization": `Bearer ${token}` } }).then(r => r.json()), fetchResources(groupId, token) ]); if (taskRes.success) { const resourceMap = new Map(); if (Array.isArray(resourceList)) { resourceList.forEach(r => { if (r.is_task) resourceMap.set(String(r.task_id), r); }); } const newTasks = taskRes.data.student_tasks .filter(t => t.task_type === 1 && t.finish !== 2) .map(t => { const resInfo = resourceMap.get(String(t.task_id)); const realName = resInfo ? resInfo.name : (t.name || `未知任务(${t.task_id})`); let isVideo = false; if (resInfo) { isVideo = (resInfo.type && String(resInfo.type).includes('video')) || (resInfo.mimetype && resInfo.mimetype.includes('video')) || (resInfo.name && /\.(mp4|avi|mov|flv|mkv)$/i.test(resInfo.name)); } let initDuration = 0; if (isVideo) { initDuration = 0; } else { if (resInfo && resInfo.watch_min_minutes > 0) { initDuration = (resInfo.watch_min_minutes * 60) + 20; } else { initDuration = DEFAULT_DURATION * 60; } } return { nodeId: String(t.node_id), taskId: String(t.task_id), name: realName, duration: Math.ceil(initDuration), isVideo: isVideo }; }); if (newTasks.length === 0) { alert("🎉 没有未完成的观看任务!"); } taskQueue = newTasks; saveData(); renderUI(); checkCurrentTask(); } } catch (e) { alert("获取失败,请检查网络"); } finally { if(btn) btn.innerText = "刷新列表"; } } async function sendHeartbeat() { const { groupId, resourceId } = getPageInfo(); const token = getCookie(); if (!groupId || !token) return; try { let userId = localStorage.getItem('xy_user_id'); if (!userId) { const userRes = await fetch(`https://${DOMAIN}/api/jx-auth/oauth2/info`, { headers: { "authorization": `Bearer ${token}` } }); const userData = await userRes.json(); userId = userData.data.info.id; localStorage.setItem('xy_user_id', userId); } const targetResourceId = resourceId || (currentTask ? currentTask.taskId : null); if (!targetResourceId) return; const message = JSON.stringify({ user_id: userId, group_id: groupId, clientType: 1, roleType: 1, resourceId: targetResourceId }); const timestamp = Date.now().toString(); const nonce = crypto.randomUUID(); const arr = [encodeURIComponent(message), timestamp, nonce, "--xy-create-signature--"].sort().join(""); const msgBuffer = new TextEncoder().encode(arr); const hashBuffer = await crypto.subtle.digest('SHA-1', msgBuffer); const signature = Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join(''); await fetch(`https://${DOMAIN}/api/jx-iresource/learnLength/learnRecord`, { method: 'POST', headers: { 'authorization': `Bearer ${token}`, 'content-type': 'application/json; charset=UTF-8' }, body: JSON.stringify({ message, signature, timestamp, nonce }) }); } catch (e) {} } function stopTimer() { if (timerInterval) clearInterval(timerInterval); if (heartbeatInterval) clearInterval(heartbeatInterval); timerInterval = null; heartbeatInterval = null; currentTask = null; renderUI(); } function jumpToNext() { if (taskQueue.length === 0) { stopTimer(); alert("🎉 所有任务已完成!"); return; } const nextTask = taskQueue[0]; const { groupId } = getPageInfo(); const safeGroupId = groupId || window.location.href.match(/mycourse\/(\d+)/)[1]; window.location.replace(`https://${DOMAIN}/app/jx-web/mycourse/${safeGroupId}/resource/${nextTask.taskId}/${nextTask.nodeId}`); } async function handleTaskComplete() { if (!currentTask) { jumpToNext(); return; } const finishedNodeId = currentTask.nodeId; if (currentTask.isVideo === false) { await submitFinishActivity(); } stopTimer(); const removeIndex = taskQueue.findIndex(t => String(t.nodeId) === String(finishedNodeId)); if (removeIndex !== -1) { taskQueue.splice(removeIndex, 1); saveData(); } setTimeout(jumpToNext, 1000); } function startTimer(task) { currentTask = task; remainingTime = parseInt(task.duration) || 0; if (heartbeatInterval) clearInterval(heartbeatInterval); heartbeatInterval = setInterval(sendHeartbeat, 30000); sendHeartbeat(); if (timerInterval) clearInterval(timerInterval); timerInterval = setInterval(() => { if (remainingTime > 0) { remainingTime--; updateTimerDisplay(); if (remainingTime <= 0) handleTaskComplete(); } }, 1000); if (task.duration === 0) { setTimeout(() => tryReadVideoDuration(0), 2000); } if (task.isVideo) { setTimeout(tryAutoPlay, 2000); } renderUI(); } function checkCurrentTask() { const { nodeId } = getPageInfo(); if (!nodeId) { stopTimer(); return; } const task = taskQueue.find(t => String(t.nodeId) === String(nodeId)); if (task) { if (!currentTask || String(currentTask.nodeId) !== String(task.nodeId)) startTimer(task); } else { stopTimer(); } } function makeDraggable(el, handle) { handle.addEventListener('mousedown', (e) => { e.preventDefault(); const rect = el.getBoundingClientRect(); const offsetX = e.clientX - rect.left; const offsetY = e.clientY - rect.top; el.style.right = 'auto'; el.style.bottom = 'auto'; el.style.left = rect.left + 'px'; el.style.top = rect.top + 'px'; handle.style.cursor = 'grabbing'; function onMouseMove(e) { el.style.left = (e.clientX - offsetX) + 'px'; el.style.top = (e.clientY - offsetY) + 'px'; } function onMouseUp() { document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); handle.style.cursor = 'grab'; savePos(el.style.top, el.style.left); } document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); }); } const container = document.createElement('div'); container.id = 'xy-helper-container'; if (uiPos) { container.style.top = uiPos.top; container.style.left = uiPos.left; } else { container.style.top = '20%'; container.style.right = '10px'; } Object.assign(container.style, { position: 'fixed', zIndex: '999999', fontFamily: "'PingFang SC', sans-serif" }); document.body.appendChild(container); const style = document.createElement('style'); style.textContent = ` .xy-ball { width: 50px; height: 50px; background-image: url('data:image/png;base64,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'); background-size: 100% 100%; background-repeat: no-repeat; background-position: center; border-radius: 50%; box-shadow: 0 4px 10px rgba(0,0,0,0.3); cursor: grab; display: flex; align-items: center; justify-content: center; color: white; font-size: 24px; user-select: none; } .xy-panel { width: 280px; background: rgba(30, 30, 30, 0.95); color: #fff; border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,0.5); overflow: hidden; display: flex; flex-direction: column; border: 1px solid rgba(255,255,255,0.1); } .xy-header { padding: 12px; background: rgba(255,255,255,0.1); display: flex; justify-content: space-between; align-items: center; cursor: grab; user-select: none; } .xy-controls { padding: 8px; background: rgba(0,0,0,0.2); text-align: center; } .xy-btn { background: #0072FF; border: none; color: white; padding: 6px 15px; border-radius: 4px; cursor: pointer; font-size: 12px; } .xy-btn:hover { background: #005bb5; } .xy-btn.danger { background: #ff4757; } .xy-list { max-height: 300px; overflow-y: auto; padding: 5px; } .xy-list::-webkit-scrollbar { width: 5px; } .xy-list::-webkit-scrollbar-thumb { background: #555; border-radius: 5px; } .xy-item { display: flex; justify-content: space-between; align-items: center; padding: 8px; border-bottom: 1px solid rgba(255,255,255,0.05); } .xy-item.active { background: rgba(0, 114, 255, 0.2); border-left: 3px solid #00C6FF; } .xy-item-name { flex: 1; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-right: 10px; cursor: pointer; } .xy-item-right { display: flex; align-items: center; gap: 5px; } .xy-time-input { width: 45px; background: #222; border: 1px solid #444; color: #fff; font-size: 11px; text-align: center; border-radius: 3px; } .xy-time-input.waiting { color: #aaa; font-style: italic; border-color: #666; } .xy-delete { cursor: pointer; color: #ff6b81; font-size: 16px; padding: 0 5px; } .xy-status-bar { padding: 8px; text-align: center; font-size: 12px; color: #00C6FF; background: rgba(0,0,0,0.3); } .xy-tag { font-size:10px; padding:1px 3px; border-radius:3px; border:1px solid #aaa; color:#aaa; } .xy-tag.video { border-color:#3498db; color:#3498db; } .xy-notice { padding: 8px 10px; background: rgba(0,0,0,0.4); color: #e0e0e0; font-size: 11px; border-top: 1px solid rgba(255,255,255,0.1); max-height: 60px; overflow-y: auto; line-height: 1.4; text-align: left; } .xy-notice::-webkit-scrollbar { width: 3px; } .xy-notice::-webkit-scrollbar-thumb { background: #666; } `; document.head.appendChild(style); function renderUI() { container.innerHTML = ''; if (!isExpanded) { const ball = document.createElement('div'); ball.className = 'xy-ball'; ball.innerHTML = ''; ball.ondblclick = () => { isExpanded = true; renderUI(); }; makeDraggable(container, ball); container.appendChild(ball); } else { const panel = document.createElement('div'); panel.className = 'xy-panel'; const header = document.createElement('div'); header.className = 'xy-header'; header.innerHTML = `<span>小雅自动刷 v1.1</span>`; const minBtn = document.createElement('button'); minBtn.innerHTML = '➖'; minBtn.style = "background:none;border:none;color:white;cursor:pointer;"; minBtn.onclick = () => { isExpanded = false; renderUI(); }; header.appendChild(minBtn); makeDraggable(container, header); panel.appendChild(header); const controls = document.createElement('div'); controls.className = 'xy-controls'; const refreshBtn = document.createElement('button'); refreshBtn.className = 'xy-btn'; refreshBtn.id = 'xy-refresh-btn'; refreshBtn.innerText = '刷新/重置列表'; refreshBtn.onclick = () => { if(confirm("确定重置列表吗?")) fetchTasksFromApi(); }; controls.appendChild(refreshBtn); panel.appendChild(controls); const status = document.createElement('div'); status.className = 'xy-status-bar'; status.id = 'xy-timer-display'; if(currentTask) { if(remainingTime > 0) status.innerHTML = `▶ 进行中: ${formatSeconds(remainingTime)}`; else status.innerHTML = `⏳ 正在读取时长...`; } else { status.innerHTML = `⏸ 待机中`; } panel.appendChild(status); const list = document.createElement('div'); list.className = 'xy-list'; if (taskQueue.length === 0) { list.innerHTML = `<div style="text-align:center;padding:20px;color:#888;font-size:12px;">列表为空<br>请点击刷新</div>`; } else { taskQueue.forEach((task, index) => { const item = document.createElement('div'); const isActive = currentTask && String(task.nodeId) === String(currentTask.nodeId); item.className = `xy-item ${isActive ? 'active' : ''}`; const name = document.createElement('div'); name.className = 'xy-item-name'; name.innerHTML = `${task.isVideo ? '<span class="xy-tag video">视</span>' : '<span class="xy-tag">文</span>'} ${task.name}`; name.onclick = () => { const { groupId } = getPageInfo(); const gid = groupId || window.location.href.match(/mycourse\/(\d+)/)[1]; if(gid) window.location.replace(`https://${DOMAIN}/app/jx-web/mycourse/${gid}/resource/${task.taskId}/${task.nodeId}`); }; const right = document.createElement('div'); right.className = 'xy-item-right'; const timeInput = document.createElement('input'); timeInput.type = 'text'; timeInput.className = 'xy-time-input'; if (task.duration && task.duration > 0) { timeInput.value = (task.duration / 60).toFixed(1); } else { timeInput.value = ""; timeInput.placeholder = "待读取"; timeInput.className += " waiting"; } timeInput.onchange = (e) => { const val = parseFloat(e.target.value); if(val && val > 0) { task.duration = Math.ceil(val * 60); if(isActive) remainingTime = task.duration; saveData(); renderUI(); } }; const delBtn = document.createElement('div'); delBtn.className = 'xy-delete'; delBtn.innerHTML = '✖'; delBtn.onclick = () => { if (isActive) stopTimer(); taskQueue.splice(index, 1); saveData(); renderUI(); }; right.appendChild(timeInput); if(task.duration > 0) right.appendChild(document.createTextNode('m')); right.appendChild(delBtn); item.appendChild(name); item.appendChild(right); list.appendChild(item); }); } panel.appendChild(list); const footer = document.createElement('div'); footer.style.textAlign = "center"; footer.style.padding = "5px"; const clearBtn = document.createElement('button'); clearBtn.className = 'xy-btn danger'; clearBtn.innerText = '清空'; clearBtn.onclick = () => { if(confirm("确定清空?")) { taskQueue=[]; saveData(); stopTimer(); renderUI(); } }; footer.appendChild(clearBtn); const noticeBoard = document.createElement('div'); noticeBoard.className = 'xy-notice'; noticeBoard.id = 'xy-notice-board'; noticeBoard.innerText = noticeContent; panel.appendChild(noticeBoard); container.appendChild(panel); } } function updateTimerDisplay() { const el = document.getElementById('xy-timer-display'); if (el && currentTask) { if(remainingTime > 0) el.innerHTML = `▶ 进行中: ${formatSeconds(remainingTime)}`; else el.innerHTML = `⏳ 正在读取时长...`; } } function init() { loadData(); renderUI(); setTimeout(checkCurrentTask, 1500); } runOneShotNoticeCheck(); let lastUrl = location.href; new MutationObserver(() => { if (location.href !== lastUrl) { lastUrl = location.href; init(); } }).observe(document, {subtree: true, childList: true}); init(); })();