您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
岐黄天使刷课助手的视频播放页面导航模块,负责视频播放页面的上一课/下一课功能。
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/537082/1595111/videoNavigation.js
- // ==UserScript==
- // @name 岐黄天使刷课助手 - 视频导航模块
- // @namespace http://tampermonkey.net/qhtx-modules
- // @version 1.3.1
- // @description 岐黄天使刷课助手的视频播放页面导航模块,负责视频播放页面的上一课/下一课功能。
- // @author AI助手
- // ==/UserScript==
- // 视频导航模块 - 专门处理视频播放页面的导航
- (function() {
- 'use strict';
- // 初始化视频导航
- window.initVideoNavigation = function() {
- console.log('初始化视频导航');
- // 创建导航按钮
- createNavigationButtons();
- // 监听视频结束事件
- listenVideoEnd();
- };
- // 创建导航按钮
- function createNavigationButtons() {
- // 检查是否已存在导航按钮
- if (document.querySelector('.qh-nav-buttons')) {
- console.log('导航按钮已存在,无需创建');
- return;
- }
- console.log('创建导航按钮');
- // 创建导航按钮容器
- const navContainer = document.createElement('div');
- navContainer.className = 'qh-nav-buttons';
- navContainer.style.cssText = `
- position: fixed;
- bottom: 20px;
- left: 0;
- right: 0;
- display: flex;
- justify-content: space-between;
- padding: 0 36px;
- z-index: 9999;
- `;
- // 创建上一课按钮
- const prevButton = document.createElement('div');
- prevButton.className = 'qh-prev-btn';
- prevButton.textContent = '上一课';
- prevButton.style.cssText = `
- padding: 10px 20px;
- background-color: #40b65a;
- color: white;
- border-radius: 5px;
- cursor: pointer;
- text-align: center;
- user-select: none;
- `;
- // 创建下一课按钮
- const nextButton = document.createElement('div');
- nextButton.className = 'qh-next-btn';
- nextButton.textContent = '下一课';
- nextButton.style.cssText = `
- padding: 10px 20px;
- background-color: #40b65a;
- color: white;
- border-radius: 5px;
- cursor: pointer;
- text-align: center;
- user-select: none;
- `;
- // 添加按钮到容器
- navContainer.appendChild(prevButton);
- navContainer.appendChild(nextButton);
- // 添加容器到页面
- document.body.appendChild(navContainer);
- // 绑定事件
- prevButton.addEventListener('click', function() {
- navigateToPrevVideo();
- });
- nextButton.addEventListener('click', function() {
- navigateToNextVideo();
- });
- console.log('导航按钮创建完成');
- }
- // 监听视频结束事件
- function listenVideoEnd() {
- // 定义视频结束处理函数
- window.videoEndHandler = function() {
- console.log('视频播放结束,准备切换到下一个视频');
- // 防止重复触发
- if (window.qh.isNavigating) {
- console.log('导航已在进行中,忽略视频结束事件');
- return;
- }
- // 延迟一秒后切换到下一课,避免与其他事件冲突
- setTimeout(() => {
- navigateToNextVideo();
- }, 1000);
- };
- // 查找并监听所有视频元素
- function findAndListenVideos() {
- console.log('查找视频元素并添加结束事件监听器');
- // 查找页面中的视频元素
- const videoElements = document.querySelectorAll('video');
- let foundVideos = false;
- videoElements.forEach(video => {
- // 移除之前可能存在的事件监听器
- video.removeEventListener('ended', window.videoEndHandler);
- // 添加事件监听器
- video.addEventListener('ended', window.videoEndHandler);
- console.log('已为视频添加结束事件监听器');
- foundVideos = true;
- // 监听视频进度
- monitorVideoProgress(video);
- });
- // 如果没有找到视频元素,尝试在iframe中查找
- if (!foundVideos) {
- const iframes = document.querySelectorAll('iframe');
- iframes.forEach(iframe => {
- try {
- if (!iframe.contentDocument && iframe.contentWindow) {
- console.log('尝试通过contentWindow访问iframe内容');
- const iframeDoc = iframe.contentWindow.document;
- processIframeVideos(iframeDoc);
- } else if (iframe.contentDocument) {
- console.log('尝试通过contentDocument访问iframe内容');
- const iframeDoc = iframe.contentDocument;
- processIframeVideos(iframeDoc);
- } else {
- console.log('无法访问iframe内容,可能是跨域限制');
- }
- } catch (e) {
- console.error('访问iframe内容时出错:', e);
- }
- });
- }
- }
- // 处理iframe中的视频
- function processIframeVideos(iframeDoc) {
- if (!iframeDoc) {
- console.log('iframe文档为空');
- return;
- }
- const iframeVideos = iframeDoc.querySelectorAll('video');
- if (iframeVideos.length > 0) {
- console.log(`在iframe中找到 ${iframeVideos.length} 个视频元素`);
- iframeVideos.forEach(video => {
- // 移除之前可能存在的事件监听器
- video.removeEventListener('ended', window.videoEndHandler);
- // 添加事件监听器
- video.addEventListener('ended', window.videoEndHandler);
- console.log('已为iframe视频添加结束事件监听器');
- // 监听视频进度
- monitorVideoProgress(video);
- });
- } else {
- console.log('在iframe中未找到视频元素');
- }
- }
- // 监听视频进度,处理视频结束但未触发ended事件的情况
- function monitorVideoProgress(video) {
- // 创建进度监听器
- const progressInterval = setInterval(() => {
- if (!video || video.paused || video.ended || !video.duration) {
- return;
- }
- // 计算进度百分比
- const progress = Math.floor((video.currentTime / video.duration) * 100);
- // 如果进度接近100%(大于等于99%),认为视频已结束
- if (progress >= 99) {
- console.log('视频进度达到99%以上,视为已结束');
- clearInterval(progressInterval);
- // 防止重复触发
- if (window.qh.isNavigating) {
- console.log('导航已在进行中,忽略视频进度事件');
- return;
- }
- // 延迟一秒后切换到下一课
- setTimeout(() => {
- navigateToNextVideo();
- }, 1000);
- }
- }, 2000); // 每2秒检查一次
- // 保存interval ID,以便在需要时清除
- if (!window.qh.progressIntervals) {
- window.qh.progressIntervals = [];
- }
- window.qh.progressIntervals.push(progressInterval);
- }
- // 初始查找视频
- findAndListenVideos();
- // 使用MutationObserver监听DOM变化,处理动态加载的视频
- const observer = new MutationObserver(function(mutations) {
- mutations.forEach(function(mutation) {
- if (mutation.addedNodes.length) {
- // 检查是否添加了视频元素或iframe
- const hasNewVideo = Array.from(mutation.addedNodes).some(node =>
- node.nodeName === 'VIDEO' ||
- (node.querySelectorAll && node.querySelectorAll('video').length > 0) ||
- node.nodeName === 'IFRAME' ||
- (node.querySelectorAll && node.querySelectorAll('iframe').length > 0)
- );
- if (hasNewVideo) {
- console.log('检测到新的视频元素或iframe被添加到DOM,重新查找视频');
- findAndListenVideos();
- }
- }
- });
- });
- // 配置观察选项
- const config = { childList: true, subtree: true };
- // 开始观察
- observer.observe(document.body, config);
- // 保存observer,以便在需要时断开连接
- window.qh.videoObserver = observer;
- }
- // 导航到上一个视频
- function navigateToPrevVideo() {
- console.log('导航到上一个视频');
- // 防止重复触发
- if (window.qh.isNavigating) {
- console.log('导航已在进行中,忽略本次请求');
- return;
- }
- // 设置导航状态
- window.qh.isNavigating = true;
- try {
- // 尝试查找原始的上一课按钮
- const originalPrevButton = document.querySelector('.prev-next .btns:first-child');
- if (originalPrevButton) {
- console.log('找到原始上一课按钮,模拟点击');
- // 模拟点击原始按钮
- const clickEvent = new MouseEvent('click', {
- bubbles: true,
- cancelable: true,
- view: window
- });
- originalPrevButton.dispatchEvent(clickEvent);
- } else {
- console.log('未找到原始上一课按钮,尝试其他方法');
- // 尝试使用window.prev函数(如果存在)
- if (typeof window.prev === 'function') {
- console.log('使用window.prev函数');
- window.prev();
- }
- // 尝试使用脚本中的导航函数
- else if (typeof window.navigateToPrevCourse === 'function') {
- console.log('使用脚本导航函数navigateToPrevCourse');
- window.navigateToPrevCourse();
- }
- // 尝试查找其他可能的上一课按钮
- else {
- console.log('尝试查找其他可能的上一课按钮');
- // 尝试查找包含"上一"文本的按钮或链接
- const prevElements = Array.from(document.querySelectorAll('a, button, div')).filter(el =>
- el.textContent && el.textContent.includes('上一') &&
- getComputedStyle(el).display !== 'none'
- );
- if (prevElements.length > 0) {
- console.log('找到可能的上一课元素,点击第一个');
- prevElements[0].click();
- } else {
- console.log('未找到任何可能的上一课元素');
- alert('无法导航到上一课,请手动切换');
- }
- }
- }
- } catch (e) {
- console.error('导航到上一课出错:', e);
- }
- // 5秒后重置导航状态
- setTimeout(() => {
- window.qh.isNavigating = false;
- }, 5000);
- }
- // 导航到上一课的兼容函数(与UI模块保持一致)
- function navigateToPrevCourse() {
- console.log('[视频导航] 调用 navigateToPrevCourse (兼容函数)');
- navigateToPrevVideo();
- }
- // 导航到下一个视频
- function navigateToNextVideo() {
- console.log('导航到下一个视频');
- // 防止重复触发
- if (window.qh.isNavigating) {
- console.log('导航已在进行中,忽略本次请求');
- return;
- }
- // 设置导航状态
- window.qh.isNavigating = true;
- try {
- // 尝试查找原始的下一课按钮
- const originalNextButton = document.querySelector('.prev-next .btns:last-child');
- if (originalNextButton) {
- console.log('找到原始下一课按钮,模拟点击');
- // 模拟点击原始按钮
- const clickEvent = new MouseEvent('click', {
- bubbles: true,
- cancelable: true,
- view: window
- });
- originalNextButton.dispatchEvent(clickEvent);
- } else {
- console.log('未找到原始下一课按钮,尝试其他方法');
- // 尝试使用window.next函数(如果存在)
- if (typeof window.next === 'function') {
- console.log('使用window.next函数');
- window.next();
- }
- // 尝试使用脚本中的导航函数
- else if (typeof window.navigateToNextCourse === 'function') {
- console.log('使用脚本导航函数navigateToNextCourse');
- window.navigateToNextCourse();
- }
- // 尝试查找其他可能的下一课按钮
- else {
- console.log('尝试查找其他可能的下一课按钮');
- // 尝试查找包含"下一"文本的按钮或链接
- const nextElements = Array.from(document.querySelectorAll('a, button, div')).filter(el =>
- el.textContent && el.textContent.includes('下一') &&
- getComputedStyle(el).display !== 'none'
- );
- if (nextElements.length > 0) {
- console.log('找到可能的下一课元素,点击第一个');
- nextElements[0].click();
- } else {
- console.log('未找到任何可能的下一课元素');
- alert('无法导航到下一课,请手动切换');
- }
- }
- }
- } catch (e) {
- console.error('导航到下一课出错:', e);
- }
- // 5秒后重置导航状态
- setTimeout(() => {
- window.qh.isNavigating = false;
- }, 5000);
- }
- // 导航到下一课的兼容函数(与UI模块保持一致)
- function navigateToNextCourse() {
- console.log('[视频导航] 调用 navigateToNextCourse (兼容函数)');
- navigateToNextVideo();
- }
- // 导出函数
- window.navigateToPrevVideo = navigateToPrevVideo;
- window.navigateToNextVideo = navigateToNextVideo;
- window.navigateToPrevCourse = navigateToPrevCourse;
- window.navigateToNextCourse = navigateToNextCourse;
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址