// ==UserScript==
// @name 山东教师教育网(当前视频快速学习api版)
// @namespace http://tampermonkey.net/
// @version 1.7
// @author 桥风
// @license MIT
// @description 只抓取当前页面视频并模拟学习进度
// @match *://player.qlteacher.com/learning/*/*
// @match *://player.qlteacher.com/*
// @grant GM_xmlhttpRequest
// ==/UserScript==
(function () {
'use strict';
const baseUrl = "https://player.qlteacher.com/api/learning";
// 获取 courseId 和 videoId(从 URL 提取)
function getIdsFromUrl() {
const match = location.pathname.match(/learning\/([^/]+)\/([^/]+)/);
if (!match) return {};
return { courseId: match[1], videoId: match[2] };
}
// 获取 token
function getAccessToken() {
try {
const tokenObj = JSON.parse(localStorage.getItem("qlt_token"));
return tokenObj?.access_token || "";
} catch (e) {
console.error("获取 access_token 失败:", e);
return "";
}
}
// 封装请求
function apiRequest(url, method = "GET", data = null) {
const accessToken = getAccessToken();
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
url,
method,
headers: {
"content-type": "application/json",
"Authorization": "Bearer " + accessToken
},
withCredentials: true,
data: data ? JSON.stringify(data) : null,
onload: res => {
try {
resolve(JSON.parse(res.responseText));
} catch (e) {
reject(e);
}
},
onerror: err => reject(err)
});
});
}
// 获取视频详情
async function getActivityInfo(courseId, videoId) {
const url = `${baseUrl}/${courseId}/activity/${videoId}`;
const res = await apiRequest(url);
return {
actToken: res.data.actToken,
duration: res.data.duration,//已学时长
length: res.data.activity.length,// 视频总时长
standard: res.data.activity.standard // 学习标准时长
};
}
// 模拟逐步播放
async function simulateProgress(courseId, videoId, actToken,duration, length, standard) {
//let progress = 0;
// 每次增加多少秒(建议 15 秒或 20 秒)
const step = 30;
const remainingDuration = standard - duration; // 剩余时长= 标准时长 - 已学时长
let progress = duration; // 从已学时长开始
console.log(`▶ 开始模拟视频 ${videoId}, 总时长=${length}s, 标准时长=${standard},剩余时长=${remainingDuration}s`);
const timer = setInterval(async () => {
progress += step;
if (progress >= standard) {
progress = -1; // 播放到结尾就停止,-1代表结尾
}
const url = `${baseUrl}/${courseId}/duration/video/${videoId}/${actToken}/${progress}`;
try {
const res = await apiRequest(url, "PUT", {});
console.log(`上报 ${progress} 秒:`, res);
// 播放到结尾就停止
if (progress === -1) {
clearInterval(timer);
console.log(`✅ 当前视频 ${videoId} 模拟完成`);
alert("🎉 当前视频学习完成");
}
} catch (e) {
console.error(`上报 ${progress} 秒失败:`, e);
clearInterval(timer);
}
},1000); // 每秒上报一次
}
// 主程序
async function main() {
try {
const { courseId, videoId } = getIdsFromUrl();
if (!courseId || !videoId) {
alert("未能识别 courseId / videoId,请确认在视频播放页面运行");
return;
}
console.log("🚀 开始学习,courseId:", courseId, " videoId:", videoId);
const { actToken, duration,length, standard} = await getActivityInfo(courseId, videoId);
await simulateProgress(courseId, videoId, actToken, duration,length, standard);
} catch (e) {
console.error("运行出错:", e);
alert("运行出错: " + e.message);
}
}
// 页面按钮
function createButton() {
const btn = document.createElement("div");
btn.innerText = "🚀 当前视频学习";
btn.style.cssText = `
position: fixed;
left: 20px;
top: 200px;
padding: 10px 18px;
background: #dc3545;
color: white;
font-weight: bold;
border-radius: 8px;
cursor: pointer;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
z-index: 999999;
`;
btn.onclick = main;
document.body.appendChild(btn);
}
window.addEventListener("load", () => {
setTimeout(createButton, 1500);
});
})();