您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自动找到视频播放按钮并触发播放,处理自动播放限制
// ==UserScript== // @name 鸽子宝宝自动学习 // @namespace http://tampermonkey.net/ // @version 1.0 // @description 自动找到视频播放按钮并触发播放,处理自动播放限制 // @author x2in // @match *://ols.v.zzu.edu.cn/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; // 配置参数 - 新增播放速度设置 const config = { // 课程项选择器 dirItemSelector: '.dir-item', // 状态元素选择器 statusSelector: '.item-status', // 完成状态文本 completedText: '已完成', // 视频播放相关选择器 playButtonSelectors: [ '.prism-big-play-btn', '.prism-play-btn', '#J_prismPlayer_component_A506AD5A-D221-4218-B5E1-9E3BE9AEFBB7' ], videoSelector: '.prism-player video', // 倍速控制相关选择器 speedSelector: '.prism-speed-selector', // 倍速选择器容器 speedOptionSelector: '.prism-speed-selector .selector-list li', // 倍速选项 // 播放速度设置 targetPlaybackRate: 2, // 默认2倍速 // 重试与检查间隔配置 maxRetries: 20, checkInterval: 1000, statusCheckInterval: 5000, speedCheckInterval: 3000, // 倍速检查间隔 allowUnmuteAfterInteraction: true }; // 全局状态变量 let currentItemIndex = 0; let dirItems = []; let videoElement = null; let isPlaying = false; let userInteracted = false; let statusCheckTimer = null; let speedCheckTimer = null; // 初始化 function init() { console.log('自动课程学习脚本初始化'); handleUserInteraction(); processDirItems(); } // 获取并处理所有课程项 function processDirItems() { dirItems = Array.from(document.querySelectorAll(config.dirItemSelector)); if (dirItems.length === 0) { console.log('未找到课程项('.concat(config.dirItemSelector,'),将在',config.checkInterval,'ms后重试')); setTimeout(processDirItems, config.checkInterval); return; } console.log('找到'.concat(dirItems.length,'个课程项,开始处理')); processCurrentDirItem(); } // 处理当前课程项 function processCurrentDirItem() { // 清除之前的定时器 if (speedCheckTimer) { clearInterval(speedCheckTimer); } // 检查是否所有课程都已完成 if (currentItemIndex >= dirItems.length) { checkAllCompleted(); return; } const currentItem = dirItems[currentItemIndex]; console.log('正在处理第'.concat(currentItemIndex + 1,'个课程项')); // 查找状态元素 const statusElement = currentItem.querySelector(config.statusSelector); if (!statusElement) { console.log('未找到状态元素,跳过当前项'); currentItemIndex++; setTimeout(processCurrentDirItem, config.checkInterval); return; } const statusText = statusElement.textContent.trim(); console.log('当前课程状态: '.concat(statusText)); // 检查是否已完成 if (statusText === config.completedText) { console.log('当前课程已完成,处理下一个'); currentItemIndex++; setTimeout(processCurrentDirItem, config.checkInterval); } else { console.log('当前课程未完成,准备学习'); // 点击当前课程项 clickElement(currentItem); // 等待课程加载 setTimeout(startVideoPlayback, 2000); } } // 开始视频播放 function startVideoPlayback() { // 清除之前的状态检查定时器 if (statusCheckTimer) { clearInterval(statusCheckTimer); } // 尝试播放视频 const playInterval = setInterval(async () => { const success = await tryPlayVideo(); if (success) { clearInterval(playInterval); console.log('视频开始播放,开始监控状态和设置倍速'); // 设置2倍速 setPlaybackSpeed(); // 定期检查倍速是否保持 startSpeedMonitoring(); // 开始监控课程状态 startStatusMonitoring(); } }, config.checkInterval); } // 设置播放速度为2倍速 function setPlaybackSpeed() { // 方法1: 直接设置video元素的playbackRate(最直接有效) if (videoElement) { videoElement.playbackRate = config.targetPlaybackRate; console.log('已直接设置视频播放速度为'.concat(config.targetPlaybackRate,'倍')); } // 方法2: 尝试通过页面的倍速控制UI设置(作为备份) setTimeout(() => { try { // 先点击倍速按钮打开选项列表 const speedButton = document.querySelector(config.speedSelector); if (speedButton) { speedButton.click(); console.log('已点击倍速按钮'); // 查找并点击2倍速选项 setTimeout(() => { const speedOptions = document.querySelectorAll(config.speedOptionSelector); let targetOption = null; // 查找包含"2x"或"2.0x"或"2倍"的选项 speedOptions.forEach(option => { const text = option.textContent.trim().toLowerCase(); if (text.includes('2x') || text.includes('2.0x') || text.includes('2倍')) { targetOption = option; } }); if (targetOption) { targetOption.click(); console.log('已通过UI设置2倍速'); // 关闭倍速选择面板 if (speedButton) speedButton.click(); } else { console.log('未找到2倍速选项,将继续使用直接设置方式'); if (speedButton) speedButton.click(); // 关闭面板 } }, 500); } } catch (err) { console.log('通过UI设置倍速失败,将继续使用直接设置方式:', err); } }, 1000); } // 监控播放速度,确保保持2倍速 function startSpeedMonitoring() { speedCheckTimer = setInterval(() => { if (videoElement && Math.abs(videoElement.playbackRate - config.targetPlaybackRate) > 0.1) { console.log('检测到播放速度变化,重新设置为2倍速'); videoElement.playbackRate = config.targetPlaybackRate; } }, config.speedCheckInterval); } // 监控课程状态,判断是否完成 function startStatusMonitoring() { statusCheckTimer = setInterval(() => { if (currentItemIndex >= dirItems.length) { clearInterval(statusCheckTimer); return; } const currentItem = dirItems[currentItemIndex]; const statusElement = currentItem.querySelector(config.statusSelector); if (statusElement && statusElement.textContent.trim() === config.completedText) { console.log('当前课程已完成'); clearInterval(statusCheckTimer); // 停止当前视频 stopVideo(); // 处理下一个课程 currentItemIndex++; setTimeout(processCurrentDirItem, 2000); } else if (videoElement && videoElement.ended) { console.log('视频播放结束,等待状态更新'); } }, config.statusCheckInterval); } // 检查是否所有课程都已完成 function checkAllCompleted() { const allCompleted = dirItems.every(item => { const statusElement = item.querySelector(config.statusSelector); return statusElement && statusElement.textContent.trim() === config.completedText; }); if (allCompleted) { console.log('所有课程已学习完成!'); showCompletionMessage(); } else { console.log('检测到有课程未完成,重新开始处理'); currentItemIndex = 0; setTimeout(processDirItems, config.checkInterval); } } // 显示学习完成提示 function showCompletionMessage() { // 创建提示元素 const notification = document.createElement('div'); notification.style.position = 'fixed'; notification.style.top = '50%'; notification.style.left = '50%'; notification.style.transform = 'translate(-50%, -50%)'; notification.style.padding = '20px 40px'; notification.style.backgroundColor = '#4CAF50'; notification.style.color = 'white'; notification.style.fontSize = '24px'; notification.style.borderRadius = '8px'; notification.style.zIndex = '999999'; notification.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)'; notification.textContent = '所有课程学习完成!'; document.body.appendChild(notification); // 5秒后自动移除提示 setTimeout(() => { notification.style.opacity = '0'; notification.style.transition = 'opacity 0.5s'; setTimeout(() => notification.remove(), 500); }, 5000); } // 尝试播放视频 async function tryPlayVideo() { // 先尝试直接播放视频元素 if (await playVideoElement()) { return true; } // 再尝试点击播放按钮 if (clickPlayButtons()) { setTimeout(playVideoElement, 500); return true; } return false; } // 直接播放视频元素 async function playVideoElement() { videoElement = document.querySelector(config.videoSelector); if (!videoElement) return false; try { // 检查是否已经在播放 if (!videoElement.paused) { isPlaying = true; return true; } // 强制保持静音,直到用户交互 if (!videoElement.muted) { videoElement.muted = true; console.log('已强制静音以符合浏览器自动播放政策'); } // 尝试播放 const promise = videoElement.play(); if (promise !== undefined) { await promise; console.log('视频已静音播放'); isPlaying = true; return true; } } catch (err) { console.log('播放尝试失败:', err.message); return false; } } // 点击播放按钮 function clickPlayButtons() { for (const selector of config.playButtonSelectors) { const button = document.querySelector(selector); if (button) { console.log('找到播放按钮并点击: '.concat(selector)); return simulateClick(button); } } return false; } // 停止视频播放 function stopVideo() { if (videoElement && !videoElement.paused) { videoElement.pause(); isPlaying = false; console.log('已停止当前视频播放'); } } // 模拟点击元素 function simulateClick(element) { if (!element) return false; try { const clickEvent = new MouseEvent('click', { bubbles: true, cancelable: true, view: window, button: 0 }); element.dispatchEvent(clickEvent); console.log('已模拟点击元素'); return true; } catch (err) { console.error('模拟点击失败:', err); return false; } } // 点击元素(直接点击) function clickElement(element) { if (element.click) { try { element.click(); console.log('已点击元素'); return true; } catch (err) { console.error('点击元素失败:', err); return simulateClick(element); } } return simulateClick(element); } // 监听用户交互 function handleUserInteraction() { const markAsInteracted = () => { if (!userInteracted) { userInteracted = true; console.log('检测到用户交互'); } }; // 监听所有可能的用户交互 window.addEventListener('click', markAsInteracted); window.addEventListener('keydown', markAsInteracted); window.addEventListener('touchstart', markAsInteracted); } // 监控页面动态变化 const observer = new MutationObserver((mutations) => { if (dirItems.length === 0) { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType === 1 && node.matches(config.dirItemSelector)) { console.log('检测到新的课程项,重新处理'); processDirItems(); } }); }); } }); observer.observe(document.body, { childList: true, subtree: true }); // 页面加载完成后初始化 if (document.readyState === 'complete') { init(); } else { window.addEventListener('load', init); } })();