// ==UserScript== // @name 长江雨课堂增强脚本更新版 // @namespace http://tampermonkey.net/ // @version 2.2 // @description 功能:后台播放+倍速静音+完成提示+标签闪烁+多课程 // @author YourName // @match https://changjiang.yuketang.cn/v2/web/* // @grant GM_addStyle // @grant GM_notification // @run-at document-start // ==/UserScript== (function() { 'use strict'; // 当前日期:2025年09月16日 星期二 const currentDate = new Date(); const lastModified = `${currentDate.getFullYear()}年${(currentDate.getMonth()+1).toString().padStart(2,'0')}月${currentDate.getDate().toString().padStart(2,'0')}日`; // ==================== 配置区 ==================== const config = { // 播放设置 playbackRate: 2.0, // 播放倍速(1.0为正常速度) muted: true, // 是否静音 // 完成提示设置 completionNotice: { enable: true, // 是否启用完成提示 duration: 10, // 提示显示秒数 text: "🎉 视频播放完成!", bgColor: "#4CAF50", // 提示背景色 textColor: "white", // 文字颜色 sound: false, // 是否播放提示音 tabFlash: { // 标签闪烁设置 enable: true, flashText: "【已完成】", interval: 800, // 闪烁间隔(ms) times: 15 // 闪烁次数 } }, // 多课程设置 multiCourse: { enable: true, // 是否启用多课程功能 btnText: "新建课程窗口", btnColor: "#4CAF50" } }; // ==================== 样式 ==================== GM_addStyle(` /* 完成提示样式 */ #xt-completion-alert { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 20px 40px; border-radius: 8px; font-size: 18px; font-weight: bold; z-index: 99999; box-shadow: 0 4px 12px rgba(0,0,0,0.15); animation: fadeIn 0.5s; display: flex; align-items: center; } /* 多课程按钮样式 */ #multi-course-container { position: fixed; bottom: 20px; right: 20px; z-index: 9999; font-family: Arial, sans-serif; background: rgba(255,255,255,0.9); padding: 10px; border-radius: 5px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); } #multi-course-btn { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; transition: all 0.3s; } /* 动画效果 */ @keyframes fadeIn { from { opacity: 0; transform: translate(-50%, -40%); } to { opacity: 1; transform: translate(-50%, -50%); } } @keyframes fadeOut { to { opacity: 0; transform: translate(-50%, -60%); } } /* 标签闪烁动画 */ @keyframes tabFlash { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } .xt-tab-flashing { animation: tabFlash ${config.completionNotice.tabFlash.interval/1000}s infinite; } `); // ==================== 核心功能 ==================== // 1. 修复版后台播放防暂停 const disableBackgroundPause = () => { // 保存原始方法 const originalPause = HTMLVideoElement.prototype.pause; // 重写pause方法 HTMLVideoElement.prototype.pause = function() { // 检查调用栈,排除系统自动暂停 const stack = new Error().stack; if (document.hidden && stack.includes('visibilitychange')) { console.log('[拦截] 阻止了后台暂停操作'); return Promise.resolve(); } return originalPause.apply(this, arguments); }; // 阻止所有visibilitychange事件 const blockEvent = (e) => { e.stopImmediatePropagation(); e.preventDefault(); return false; }; // 添加事件监听(捕获阶段) document.addEventListener('visibilitychange', blockEvent, true); window.addEventListener('visibilitychange', blockEvent, true); // 额外防护:定时恢复播放 setInterval(() => { document.querySelectorAll('video').forEach(video => { if (document.hidden && video.paused) { console.log('[防护] 自动恢复暂停的视频'); video.play().catch(e => console.log('自动播放错误:', e)); } }); }, 3000); }; // 2. 标签闪烁功能 const flashTabTitle = () => { if (!config.completionNotice.tabFlash.enable) return; const originalTitle = document.title; let flashCount = 0; const maxCount = config.completionNotice.tabFlash.times; const flashText = config.completionNotice.tabFlash.flashText; // 添加闪烁样式到favicon const favicon = document.querySelector('link[rel="icon"]'); if (favicon) { favicon.classList.add('xt-tab-flashing'); } const flashInterval = setInterval(() => { flashCount++; if (flashCount >= maxCount) { clearInterval(flashInterval); document.title = originalTitle; if (favicon) { favicon.classList.remove('xt-tab-flashing'); } return; } // 交替显示原标题和闪烁标题 document.title = flashCount % 2 === 0 ? originalTitle : `${flashText} ${originalTitle}`; }, config.completionNotice.tabFlash.interval); }; // 3. 播放完成提示 const showCompletionNotice = (video) => { if (!config.completionNotice.enable) return; // 创建提示元素 const alertBox = document.createElement('div'); alertBox.id = 'xt-completion-alert'; alertBox.textContent = config.completionNotice.text; Object.assign(alertBox.style, { background: config.completionNotice.bgColor, color: config.completionNotice.textColor }); // 添加图标 const icon = document.createElement('span'); icon.style.marginRight = '10px'; icon.textContent = '✓'; alertBox.prepend(icon); document.body.appendChild(alertBox); // 触发标签闪烁 flashTabTitle(); // 系统通知 if (typeof GM_notification !== 'undefined') { GM_notification({ title: '课程播放完成', text: `${document.title}`, timeout: 5000, silent: !config.completionNotice.sound }); } // 自动消失 setTimeout(() => { alertBox.style.animation = 'fadeOut 0.5s forwards'; setTimeout(() => alertBox.remove(), 500); }, config.completionNotice.duration * 1000); }; // 4. 视频控制器 const setupVideoControls = () => { const processVideo = (video) => { if (!video || video.dataset.xtEnhanced) return; video.dataset.xtEnhanced = 'true'; // 应用播放设置 video.muted = config.muted; video.playbackRate = config.playbackRate; // 锁定设置 Object.defineProperties(video, { 'playbackRate': { get: () => config.playbackRate, set: () => console.log('[拦截] 倍速修改已阻止') }, 'muted': { get: () => config.muted, set: () => {} } }); // 完成事件监听 video.addEventListener('ended', () => showCompletionNotice(video)); // 自动播放 const playVideo = () => { video.play().catch(e => { console.warn('自动播放失败:', e); setTimeout(playVideo, 3000); }); }; playVideo(); }; // 初始设置 document.querySelectorAll('video').forEach(processVideo); // 动态内容监控 new MutationObserver(() => { document.querySelectorAll('video:not([data-xt-enhanced])').forEach(processVideo); }).observe(document.body, { subtree: true, childList: true }); }; // 5. 多课程功能 const setupMultiCourse = () => { if (!config.multiCourse.enable) return; const container = document.createElement('div'); container.id = 'multi-course-container'; const btn = document.createElement('button'); btn.id = 'multi-course-btn'; btn.textContent = config.multiCourse.btnText; Object.assign(btn.style, { background: config.multiCourse.btnColor, color: 'white' }); btn.onclick = () => { const newWindow = window.open(window.location.href, '_blank', 'width=800,height=600'); newWindow.focus(); }; container.appendChild(btn); document.body.appendChild(container); }; // ==================== 初始化 ==================== const init = () => { try { console.log(`[脚本加载] 长江雨课堂增强功能 v2.2 (${lastModified})`); disableBackgroundPause(); setupVideoControls(); setupMultiCourse(); } catch (error) { console.error('[脚本错误] 初始化失败:', error); } }; // 启动方式 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { setTimeout(init, 1000); } })();