// ==UserScript==
// @name 上海大学继续教育学院自动刷课,倍速,自动换课
// @namespace 一心向善
// @namespace https://www.icce.shu.edu.cn
// @version 1.5.0
// @description 自动、倍速播放、自动下一页【可用于:上海大学继续教育学院继续教育管理平台|上海立信会计金融学院|上海理工大学|韩山师范学院|广州软件学院|上海出版印刷高等专科学校|广东职业技术学院|华南农业大学继续教育学院|开封大学继续教育学院|东华大学网络教育学院考试系统|广州学涯|华南农业大学|东华大学|延安大学|上海应用技术大学等】
// @author Your Name
// @match *://*.learnin.com.cn/*
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// ============= 配置 =============
const DEFAULT_SPEED = 1; // 默认倍速
const CHECK_INTERVAL = 300; // 检查间隔(毫秒)
const END_CHECK_DELAY = 1000; // 视频结束后等待多久再跳转
// ============= 状态 =============
let currentSpeed = DEFAULT_SPEED;
let panel = null;
let lastVideoTime = 0;
let videoEnded = false;
let videoEndedTimer = null;
let isPanelMinimized = false;
// 拖动相关
let isDragging = false;
let dragOffsetX = 0;
let dragOffsetY = 0;
let panelX = 20;
let panelY = 20;
// ============= 启动日志 =============
console.log('%c🔥🔥🔥 天府上海大学视频助手 v1.5 启动!🔥🔥🔥', 'color:red;font-size:20px;font-weight:bold;');
console.log('当前页面URL:', window.location.href);
// ============= 创建控制面板 =============
function createPanel() {
if (document.getElementById('learnin-helper-v8')) {
return;
}
panel = document.createElement('div');
panel.id = 'learnin-helper-v8';
panel.style.cssText = `
position: fixed !important;
left: ${panelX}px !important;
top: ${panelY}px !important;
z-index: 2147483647 !important;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
color: #ffffff !important;
padding: 0 !important;
border-radius: 15px !important;
font-family: Arial, sans-serif !important;
font-size: 14px !important;
box-shadow: 0 10px 40px rgba(0,0,0,0.3) !important;
min-width: 300px !important;
user-select: none !important;
`;
panel.innerHTML = `
1、本脚本仅适用于处理视频;
2、如需处理答题、考试等联系:TFJYPXJG
`;
document.body.appendChild(panel);
console.log('✅ 控制面板已创建!');
bindEvents();
}
// ============= 添加日志到状态栏 =============
let logLines = [];
function addStatusLog(text) {
const now = new Date().toLocaleTimeString();
logLines.unshift(`[${now}] ${text}`);
if (logLines.length > 10) logLines.pop();
const statusEl = document.getElementById('status-v8');
if (statusEl) {
statusEl.innerHTML = logLines.join('
');
}
console.log('📝', text);
}
// ============= 设置视频速度 =============
function setSpeed(sp) {
currentSpeed = sp;
const speedVal = document.getElementById('speed-val-v8');
const speedRange = document.getElementById('speed-range-v8');
if (speedVal) speedVal.textContent = sp;
if (speedRange) speedRange.value = sp;
const videos = document.querySelectorAll('video');
videos.forEach(video => {
video.playbackRate = sp;
});
addStatusLog(`设置倍速: ${sp}x`);
}
// ============= 查找所有可能的下一页按钮 =============
function findAllNextButtons() {
const all = Array.from(document.querySelectorAll('button, a'));
const keywords = [
'下一页', '下一节', '下一章', 'next', 'Next', 'NEXT',
'下一个', 'Next lesson', 'Next chapter'
];
return all.filter(el => {
const t = el.textContent.trim();
return keywords.some(k => t.includes(k));
});
}
// ============= 查找播放按钮 =============
function findPlayButtons() {
const all = Array.from(document.querySelectorAll('button'));
const keywords = ['Play', 'Play Video', '播放', '▶', '►'];
return all.filter(el => {
const t = el.textContent.trim();
return keywords.some(k => t.includes(k));
});
}
// ============= 绑定事件 =============
function bindEvents() {
// 快捷按钮
document.querySelectorAll('.sp-v8').forEach(btn => {
btn.addEventListener('click', () => {
const sp = parseFloat(btn.dataset.sp);
setSpeed(sp);
});
});
// 滑块
const range = document.getElementById('speed-range-v8');
range.addEventListener('input', (e) => {
const sp = parseFloat(e.target.value);
setSpeed(sp);
});
// 最小化/还原按钮 - 只隐藏控制部分,保留说明
const toggleBtn = document.getElementById('toggle-btn-v8');
const controls = document.getElementById('panel-controls-v8');
toggleBtn.addEventListener('click', () => {
isPanelMinimized = !isPanelMinimized;
if (isPanelMinimized) {
controls.style.display = 'none';
toggleBtn.textContent = '+';
addStatusLog('控制区已隐藏');
} else {
controls.style.display = 'block';
toggleBtn.textContent = '−';
addStatusLog('控制区已展开');
}
});
// 拖动功能
const header = document.getElementById('panel-header-v8');
header.addEventListener('mousedown', (e) => {
isDragging = true;
const rect = panel.getBoundingClientRect();
dragOffsetX = e.clientX - rect.left;
dragOffsetY = e.clientY - rect.top;
panel.style.cursor = 'grabbing';
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
panelX = e.clientX - dragOffsetX;
panelY = e.clientY - dragOffsetY;
// 限制边界,防止拖出屏幕
panelX = Math.max(0, Math.min(window.innerWidth - panel.offsetWidth, panelX));
panelY = Math.max(0, Math.min(window.innerHeight - panel.offsetHeight, panelY));
panel.style.left = panelX + 'px';
panel.style.top = panelY + 'px';
});
document.addEventListener('mouseup', () => {
isDragging = false;
panel.style.cursor = 'default';
});
// 防止在其他元素上释放时的问题
document.addEventListener('mouseleave', () => {
isDragging = false;
panel.style.cursor = 'default';
});
}
// ============= 处理视频结束 =============
function handleVideoEnded(video) {
if (videoEnded) return;
videoEnded = true;
addStatusLog('🎬 视频即将结束!');
if (videoEndedTimer) {
clearTimeout(videoEndedTimer);
}
videoEndedTimer = setTimeout(() => {
const nextButtons = findAllNextButtons();
addStatusLog(`🔍 找到 ${nextButtons.length} 个下一页按钮`);
if (nextButtons.length > 0) {
const btn = nextButtons[0];
addStatusLog(`✅ 点击: ${btn.textContent.trim()}`);
btn.click();
setTimeout(() => {
videoEnded = false;
}, 2000);
} else {
addStatusLog('❌ 没找到下一页按钮');
videoEnded = false;
}
}, END_CHECK_DELAY);
}
// ============= 主循环 =============
function mainLoop() {
// 确保面板存在
if (!panel || !document.body.contains(panel)) {
createPanel();
}
// 处理所有视频
const videos = document.querySelectorAll('video');
videos.forEach(video => {
// 强制速度
if (video.playbackRate !== currentSpeed) {
video.playbackRate = currentSpeed;
}
// 检查视频播放状态
if (video.paused && !video.ended) {
const playBtns = findPlayButtons();
if (playBtns.length > 0) {
playBtns[0].click();
addStatusLog('▶️ 点击播放按钮');
} else {
video.play().catch(() => {});
}
}
// 检查视频是否接近结束
const nearEnd = video.duration > 0 && video.currentTime > video.duration - 2;
const isActuallyEnded = video.ended;
if (nearEnd || isActuallyEnded) {
handleVideoEnded(video);
}
lastVideoTime = video.currentTime;
});
if (videos.length > 0 && !isPanelMinimized) {
const v = videos[0];
const percent = v.duration > 0 ? Math.round((v.currentTime / v.duration) * 100) : 0;
addStatusLog(`播放进度: ${percent}% | ${Math.round(v.currentTime)}s / ${Math.round(v.duration)}s`);
}
}
// ============= 启动 =============
function start() {
createPanel();
setSpeed(DEFAULT_SPEED);
addStatusLog('✅ 助手启动成功!拖动标题栏可移动面板');
setInterval(mainLoop, CHECK_INTERVAL);
}
setTimeout(start, 1000);
})();