';
for (var i = 0; i < SPEED_OPTIONS.length; i++) {
var s = SPEED_OPTIONS[i];
var isActive = Math.abs(s - CONFIG.videoSpeed) < 0.01;
html += '';
}
html += '
';
// 开关选项
html += '';
// 操作按钮
html += '';
// 状态显示
html += '
';
return html;
}
function updatePanelStatus(msg) {
var el = document.getElementById('gdou-status');
if (el) {
var time = new Date();
var timeStr = String(time.getHours()).padStart(2, '0') + ':' + String(time.getMinutes()).padStart(2, '0') + ':' + String(time.getSeconds()).padStart(2, '0');
el.innerHTML = '
[' + timeStr + '] ' + msg + '
' + el.innerHTML;
// 只保留最近5条
var children = el.children;
while (children.length > 5) el.removeChild(children[children.length - 1]);
}
}
// 辅助函数:设置倍速
function setSpeed(val) {
CONFIG.videoSpeed = val;
var display = document.getElementById('gdou-speed-display');
if (display) display.textContent = val + 'x';
applyVideoSpeed(val);
updateSpeedButtonsUI(val);
saveConfig();
toast('倍速设置为 ' + val + 'x');
}
// 辅助函数:更新倍速按钮高亮
function updateSpeedButtonsUI(current) {
var btns = document.querySelectorAll('.gdou-speed-btn');
btns.forEach(function(b) {
var v = parseFloat(b.getAttribute('data-speed'));
if (Math.abs(v - current) < 0.01) {
b.style.background = '#1e88e5';
b.style.fontWeight = 'bold';
} else {
b.style.background = '#2d4a7a';
b.style.fontWeight = 'normal';
}
});
}
function bindPanelEvents(panel) {
var speedDisplay = panel.querySelector('#gdou-speed-display');
var speedGrid = panel.querySelector('#gdou-speed-grid');
var speedDown = panel.querySelector('#gdou-speed-down');
var speedUp = panel.querySelector('#gdou-speed-up');
// 点击数字显示区域:显示/隐藏选择网格
speedDisplay.addEventListener('click', function() {
if (speedGrid.style.display === 'none') {
speedGrid.style.display = 'grid';
} else {
speedGrid.style.display = 'none';
}
});
// 减号按钮:降低倍速
speedDown.addEventListener('click', function() {
var idx = SPEED_OPTIONS.indexOf(CONFIG.videoSpeed);
if (idx > 0) {
setSpeed(SPEED_OPTIONS[idx - 1]);
} else if (idx === -1) {
// 找到最近的较低值
for (var i = SPEED_OPTIONS.length - 1; i >= 0; i--) {
if (SPEED_OPTIONS[i] < CONFIG.videoSpeed) {
setSpeed(SPEED_OPTIONS[i]);
break;
}
}
}
});
// 加号按钮:提高倍速
speedUp.addEventListener('click', function() {
var idx = SPEED_OPTIONS.indexOf(CONFIG.videoSpeed);
if (idx >= 0 && idx < SPEED_OPTIONS.length - 1) {
setSpeed(SPEED_OPTIONS[idx + 1]);
} else if (idx === -1) {
// 找到最近的较高值
for (var i = 0; i < SPEED_OPTIONS.length; i++) {
if (SPEED_OPTIONS[i] > CONFIG.videoSpeed) {
setSpeed(SPEED_OPTIONS[i]);
break;
}
}
}
});
// 快速选择按钮
var buttons = panel.querySelectorAll('.gdou-speed-btn');
buttons.forEach(function(btn) {
btn.addEventListener('click', function() {
var val = parseFloat(this.getAttribute('data-speed'));
setSpeed(val);
speedGrid.style.display = 'none';
});
});
// 开关
panel.querySelector('#gdou-autoplay').addEventListener('change', function() {
CONFIG.autoPlay = this.checked; saveConfig();
if (this.checked && getPageType() === 'video') {
handleVideoPage();
toast('已启用自动播放');
}
});
panel.querySelector('#gdou-autoscroll').addEventListener('change', function() {
CONFIG.autoScrollDocs = this.checked; saveConfig();
if (this.checked && getPageType() === 'page') {
handlePage_autoScroll();
toast('已启用自动滚动');
}
});
panel.querySelector('#gdou-autonext').addEventListener('change', function() {
CONFIG.autoNext = this.checked; saveConfig();
toast(this.checked ? '已启用自动切换到下一个' : '已关闭自动切换');
});
// 操作按钮
panel.querySelector('#gdou-btn-next').addEventListener('click', goToNextActivity);
panel.querySelector('#gdou-btn-play').addEventListener('click', function() {
var vids = getAllVideos();
vids.forEach(function(v) { v.play(); });
toast('正在尝试播放所有视频...');
});
panel.querySelector('#gdou-btn-scroll').addEventListener('click', function() {
handlePage_autoScroll(true);
toast('开始滚动文档...');
});
}
// ========== 视频处理 ==========
function getAllVideos() {
var videos = [];
// 主文档
document.querySelectorAll('video').forEach(function(v) { videos.push(v); });
// iframe内
var iframes = document.querySelectorAll('iframe');
for (var i = 0; i < iframes.length; i++) {
try {
var iframeDoc = iframes[i].contentDocument || iframes[i].contentWindow.document;
iframeDoc.querySelectorAll('video').forEach(function(v) { videos.push(v); });
} catch(e) { /* 跨域忽略 */ }
}
return videos;
}
function applyVideoSpeed(speed) {
var vids = getAllVideos();
vids.forEach(function(v) {
try {
v.playbackRate = speed;
v.defaultPlaybackRate = speed;
log('设置视频倍速:', speed);
} catch(e) { log('设置倍速失败:', e); }
});
}
var videoProcessed = false;
function handleVideoPage() {
if (videoProcessed) return;
// 1. 等待iframe加载并设置倍速
var attempts = 0;
var maxAttempts = 20;
var trySetup = function() {
attempts++;
var vids = getAllVideos();
if (vids.length > 0) {
videoProcessed = true;
// 设置倍速
applyVideoSpeed(CONFIG.videoSpeed);
// 监听视频事件保持倍速
vids.forEach(function(v) {
v.addEventListener('ratechange', function() {
if (Math.abs(v.playbackRate - CONFIG.videoSpeed) > 0.1) {
v.playbackRate = CONFIG.videoSpeed;
}
});
v.addEventListener('loadedmetadata', function() {
v.playbackRate = CONFIG.videoSpeed;
});
v.addEventListener('play', function() {
v.playbackRate = CONFIG.videoSpeed;
});
// 自动播放
if (CONFIG.autoPlay && v.paused) {
var p = v.play();
if (p && p.catch) {
p.catch(function() {
v.muted = true;
v.play().catch(function() {
log('自动播放失败,请手动点击播放');
});
});
}
}
});
updatePanelStatus('✓ 已设置视频倍速 ' + CONFIG.videoSpeed.toFixed(1) + 'x');
toast('视频倍速设置为 ' + CONFIG.videoSpeed.toFixed(1) + 'x');
// 如果启用了自动下一个,监听视频播放进度(匹配系统70%完成规则)
if (CONFIG.autoNext) {
var triggered = false;
vids.forEach(function(v) {
v.addEventListener('ended', function() {
if (!triggered) {
triggered = true;
updatePanelStatus('✓ 视频播放完成,等待切换下一个...');
setTimeout(goToNextActivity, CONFIG.nextDelay);
}
});
v.addEventListener('timeupdate', function() {
if (!triggered && v.duration && v.duration > 0) {
var progress = v.currentTime / v.duration;
if (progress >= 0.70) {
triggered = true;
updatePanelStatus('✓ 进度70%(系统标记完成),准备切换下一个...');
toast('视频完成进度已达70%,即将跳转下一个...');
setTimeout(goToNextActivity, CONFIG.nextDelay);
}
}
});
v.addEventListener('play', function() {
// 重新设置倍速(有些播放器在play时会重置倍速)
if (Math.abs(v.playbackRate - CONFIG.videoSpeed) > 0.1) {
v.playbackRate = CONFIG.videoSpeed;
}
});
});
}
} else if (attempts < maxAttempts) {
setTimeout(trySetup, 1000);
} else {
updatePanelStatus('⚠ 未发现视频元素,请刷新页面');
}
};
trySetup();
// 使用MutationObserver监测iframe变化
var observer = new MutationObserver(function() {
var vids = getAllVideos();
if (vids.length > 0) {
vids.forEach(function(v) {
if (Math.abs(v.playbackRate - CONFIG.videoSpeed) > 0.1) {
v.playbackRate = CONFIG.videoSpeed;
}
});
}
});
// 监控所有iframe的加载
var iframes = document.querySelectorAll('iframe');
iframes.forEach(function(iframe) {
iframe.addEventListener('load', function() {
setTimeout(handleVideoPage, 1500);
});
});
observer.observe(document.documentElement, { childList: true, subtree: true });
}
// ========== 文档页面处理 ==========
var pageProcessing = false;
function handlePage_autoScroll(force) {
if (pageProcessing && !force) return;
// 如果不启用自动滚动,且不是强制调用,则跳过
if (!CONFIG.autoScrollDocs && !force) return;
pageProcessing = true;
updatePanelStatus('📄 开始自动阅读文档...');
// 自动滚动到底部以触发"查看"状态
var totalHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
var viewport = window.innerHeight;
var scrollAmount = Math.min(300, Math.max(100, (totalHeight - viewport) / 20));
var current = 0;
var scrollInterval = null;
scrollInterval = setInterval(function() {
current += scrollAmount;
window.scrollTo(0, current);
if (current >= totalHeight - viewport - 50) {
clearInterval(scrollInterval);
window.scrollTo(0, totalHeight);
updatePanelStatus('✓ 文档阅读完成');
// 自动下一个
if (CONFIG.autoNext) {
setTimeout(function() {
goToNextActivity();
}, CONFIG.nextDelay);
}
}
}, 300);
}
// ========== 讨论区页面处理 ==========
function handleForumPage() {
updatePanelStatus('💬 讨论区 - 请手动阅读和参与讨论');
}
// ========== 课程列表页面处理 ==========
function handleCoursePage() {
var count = document.querySelectorAll('a[href*="mod/"]').length;
updatePanelStatus('📚 课程页面,发现 ' + count + ' 个学习资源链接');
}
// ========== 仪表盘页面处理 ==========
function handleDashboardPage() {
var courseLinks = document.querySelectorAll('[data-course-id], a[href*="course/view.php"]');
updatePanelStatus('🏠 课程主页,共发现 ' + courseLinks.length + ' 个课程入口');
}
// ========== 快捷键 ==========
function setupShortcuts() {
if (!CONFIG.enableShortcuts) return;
document.addEventListener('keydown', function(e) {
var active = document.activeElement;
if (active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA' || active.isContentEditable)) return;
var key = e.key;
var handled = false;
if (key === '[' || key === '【') {
// 减速
CONFIG.videoSpeed = Math.max(0.5, CONFIG.videoSpeed - 0.25);
applyVideoSpeed(CONFIG.videoSpeed);
updateShortcutUI();
toast('倍速: ' + CONFIG.videoSpeed.toFixed(2) + 'x');
handled = true;
} else if (key === ']' || key === '】') {
// 加速
CONFIG.videoSpeed = Math.min(4.0, CONFIG.videoSpeed + 0.25);
applyVideoSpeed(CONFIG.videoSpeed);
updateShortcutUI();
toast('倍速: ' + CONFIG.videoSpeed.toFixed(2) + 'x');
handled = true;
} else if (key === ';') {
// 1.5x
CONFIG.videoSpeed = 1.5;
applyVideoSpeed(CONFIG.videoSpeed);
updateShortcutUI();
toast('倍速: 1.50x');
handled = true;
} else if (key === "'" || key === '\"') {
// 2x
CONFIG.videoSpeed = 2.0;
applyVideoSpeed(CONFIG.videoSpeed);
updateShortcutUI();
toast('倍速: 2.00x');
handled = true;
} else if (key === '\\' || key === '|') {
// 1x
CONFIG.videoSpeed = 1.0;
applyVideoSpeed(CONFIG.videoSpeed);
updateShortcutUI();
toast('倍速: 1.00x');
handled = true;
} else if (key === ' ') {
// 空格: 播放/暂停
var vids = getAllVideos();
if (vids.length > 0) {
vids.forEach(function(v) {
if (v.paused) v.play();
else v.pause();
});
handled = true;
}
} else if (key === 'n' || key === 'N') {
// N键: 下一个
goToNextActivity();
handled = true;
}
if (handled) {
e.preventDefault();
saveConfig();
}
});
}
function updateShortcutUI() {
var display = document.querySelector('#gdou-speed-display');
if (display) display.textContent = CONFIG.videoSpeed + 'x';
updateSpeedButtonsUI(CONFIG.videoSpeed);
}
// ========== 主初始化 ==========
function init() {
var pageType = getPageType();
log('页面类型:', pageType, 'URL:', location.href);
// 创建控制面板
createPanel();
// 根据页面类型处理
switch(pageType) {
case 'video':
handleVideoPage();
break;
case 'page':
setTimeout(handlePage_autoScroll, 1500);
break;
case 'forum':
case 'discuss':
handleForumPage();
break;
case 'course':
handleCoursePage();
break;
case 'dashboard':
handleDashboardPage();
break;
case 'login':
updatePanelStatus('🔐 登录页面,请手动登录');
break;
default:
// 尝试检测是否有视频
setTimeout(function() {
var vids = getAllVideos();
if (vids.length > 0) {
applyVideoSpeed(CONFIG.videoSpeed);
updatePanelStatus('✓ 发现 ' + vids.length + ' 个视频,已应用倍速');
}
}, 2000);
}
// 设置快捷键
setupShortcuts();
// 定期检查和刷新倍速(防止页面重置)
setInterval(function() {
if (getPageType() === 'video') {
applyVideoSpeed(CONFIG.videoSpeed);
}
}, 5000);
log('GDOU学习助手初始化完成');
}
// 根据页面加载状态启动
if (document.readyState === 'complete' || document.readyState === 'interactive') {
setTimeout(init, 1200);
} else {
document.addEventListener('DOMContentLoaded', function() {
setTimeout(init, 1200);
});
}
// 兜底方案:3秒后强制执行一次
setTimeout(function() {
if (!document.getElementById('gdou-panel')) init();
}, 3000);
})();