自动播放并静音,自动下一节,后台播放不暂停
Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyfork.org/scripts/588921/1887495/%E4%B8%93%E6%8A%80%E5%A4%A9%E4%B8%8B%E8%87%AA%E5%8A%A8%E5%88%B7%E8%AF%BE%E8%84%9A%E6%9C%AC.js
// ==UserScript==
// @name zgzjzj-autoplay
// @namespace https://tampermonkey.net/
// @version 2.0
// @description auto play zgzjzj courses, works when minimized
// @author Antigravity
// @match https://www.zgzjzj.com/learncenter/play*
// @match https://*.zgzjzj.com/learncenter/play*
// @grant none
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
// ============================================================
// PART 1: Override Page Visibility API
// This MUST run at document-start, before the site's own scripts
// ============================================================
// 1a. Override document.hidden to always return false
Object.defineProperty(document, 'hidden', {
get: function () { return false; },
configurable: true
});
// 1b. Override document.visibilityState to always return 'visible'
Object.defineProperty(document, 'visibilityState', {
get: function () { return 'visible'; },
configurable: true
});
// 1c. Override document.webkitVisibilityState (for older WebKit browsers)
Object.defineProperty(document, 'webkitVisibilityState', {
get: function () { return 'visible'; },
configurable: true
});
// 1d. Block visibilitychange events so the site never knows you left
document.addEventListener('visibilitychange', function (e) {
e.stopImmediatePropagation();
}, true);
document.addEventListener('webkitvisibilitychange', function (e) {
e.stopImmediatePropagation();
}, true);
// 1e. Block blur/focus events on window (some sites use these too)
window.addEventListener('blur', function (e) {
e.stopImmediatePropagation();
}, true);
window.addEventListener('focus', function (e) {
e.stopImmediatePropagation();
}, true);
// 1f. Override document.hasFocus to always return true
document.hasFocus = function () { return true; };
console.log('[zgzjzj-helper] Visibility API override applied');
// ============================================================
// PART 2: Web Worker based timer (immune to browser throttling)
// ============================================================
function createWorkerTimer(callback, interval) {
var blob = new Blob([
'var iv = setInterval(function(){ postMessage("tick"); }, ' + interval + ');'
], { type: 'application/javascript' });
var url = URL.createObjectURL(blob);
var worker = new Worker(url);
worker.onmessage = function () {
callback();
};
return worker;
}
// ============================================================
// PART 3: Main automation logic (runs after page loads)
// ============================================================
window.addEventListener('load', function () {
console.log('[zgzjzj-helper] script loaded, starting automation');
var CONFIG = {
playbackRate: 1.0,
checkInterval: 2000,
autoMute: true
};
// --- UI Panel ---
function createUI() {
if (document.getElementById('zgzjzj-helper-panel')) return;
var panel = document.createElement('div');
panel.id = 'zgzjzj-helper-panel';
panel.style.cssText = 'position:fixed;top:80px;right:20px;z-index:999999;background:rgba(15,23,42,0.92);color:#fff;padding:14px 18px;border-radius:10px;font-size:13px;box-shadow:0 8px 24px rgba(0,0,0,0.3);font-family:sans-serif;min-width:210px;border:1px solid rgba(255,255,255,0.1);backdrop-filter:blur(8px);';
panel.innerHTML = '<div style="font-weight:bold;margin-bottom:8px;color:#38bdf8;">⚡ \u8BFE\u7A0B\u81EA\u52A8\u64AD\u653E\u4E2D v2.0</div><div id="zgzjzj-status" style="margin-bottom:6px;color:#e2e8f0;">\u72B6\u6001: \u521D\u59CB\u5316...</div><div id="zgzjzj-progress" style="color:#94a3b8;font-size:12px;">\u6B63\u5728\u76D1\u542C\u89C6\u9891\u7EC4\u4EF6</div><div id="zgzjzj-vis" style="color:#4ade80;font-size:11px;margin-top:6px;">✅ \u53EF\u89C1\u6027\u9501\u5B9A\u5DF2\u542F\u7528\uFF08\u6700\u5C0F\u5316\u4E0D\u4F1A\u6682\u505C\uFF09</div>';
document.body.appendChild(panel);
}
function updateStatus(s, d) {
var a = document.getElementById('zgzjzj-status');
var b = document.getElementById('zgzjzj-progress');
if (a) a.innerText = '\u72B6\u6001: ' + s;
if (b && d) b.innerText = d;
}
// --- Popup handler ---
function handlePopups() {
var btns = document.querySelectorAll('.el-dialog__wrapper .el-button--primary, .el-message-box__btns .el-button--primary, .el-message-box__btns button');
for (var i = 0; i < btns.length; i++) {
if (btns[i] && btns[i].offsetParent !== null) {
console.log('[\u4E13\u6280\u5929\u4E0B\u52A9\u624B] \u70B9\u51FB\u5F39\u7A97\u6309\u94AE');
btns[i].click();
}
}
var allBtns = document.querySelectorAll('button, .el-button, a, div[role="button"]');
var keywords = ['\u7EE7\u7EED\u5B66\u4E60', '\u786E\u5B9A', '\u786E\u8BA4', '\u6211\u77E5\u9053\u4E86', '\u7EE7\u7EED\u64AD\u653E', '\u5F00\u59CB\u64AD\u653E'];
for (var j = 0; j < allBtns.length; j++) {
var txt = (allBtns[j].innerText || '').trim();
if (allBtns[j].offsetParent !== null) {
for (var k = 0; k < keywords.length; k++) {
if (txt === keywords[k]) {
console.log('[\u4E13\u6280\u5929\u4E0B\u52A9\u624B] \u70B9\u51FB: ' + txt);
allBtns[j].click();
break;
}
}
}
}
}
// --- Next section ---
function playNextSection() {
console.log('[\u4E13\u6280\u5929\u4E0B\u52A9\u624B] \u6B63\u5728\u5BFB\u627E\u4E0B\u4E00\u8282...');
updateStatus('\u5BFB\u627E\u4E0B\u4E00\u8282...', '\u68C0\u7D22\u8BFE\u7A0B\u76EE\u5F55\u4E2D');
var nextKeywords = ['\u4E0B\u4E00\u8282', '\u4E0B\u4E00\u8BFE', '\u4E0B\u4E00\u7AE0'];
var allEl = document.querySelectorAll('button, a, span, div');
for (var i = 0; i < allEl.length; i++) {
var t = (allEl[i].innerText || '').trim();
for (var n = 0; n < nextKeywords.length; n++) {
if (t === nextKeywords[n] && allEl[i].offsetParent !== null) {
console.log('[\u4E13\u6280\u5929\u4E0B\u52A9\u624B] \u627E\u5230\u4E0B\u4E00\u8282\u6309\u94AE');
allEl[i].click();
return true;
}
}
}
var items = document.querySelectorAll('.el-tree-node__content, li.el-menu-item, .course-item, .video-item, .catalog-item');
var visible = [];
for (var m = 0; m < items.length; m++) {
if (items[m].innerText && items[m].innerText.trim().length > 0 && items[m].offsetParent !== null) {
visible.push(items[m]);
}
}
if (visible.length > 0) {
var currentIndex = -1;
for (var p = 0; p < visible.length; p++) {
if (visible[p].classList.contains('active') || visible[p].classList.contains('is-active') || visible[p].classList.contains('current') || visible[p].querySelector('.active, .is-active')) {
currentIndex = p;
break;
}
}
if (currentIndex !== -1 && currentIndex + 1 < visible.length) {
console.log('[\u4E13\u6280\u5929\u4E0B\u52A9\u624B] \u70B9\u51FB\u7B2C ' + (currentIndex + 1) + ' \u4E2A\u5C0F\u8282');
visible[currentIndex + 1].click();
return true;
}
}
updateStatus('\u672A\u68C0\u6D4B\u5230\u4E0B\u4E00\u8282', '\u8BF7\u624B\u52A8\u70B9\u51FB\u4E0B\u4E00\u8BFE');
return false;
}
// --- Prevent video pause from external calls ---
var videoPatchApplied = false;
function patchVideoPause() {
var video = document.querySelector('video');
if (video && !videoPatchApplied) {
var originalPause = video.pause.bind(video);
video.pause = function () {
// Check if this pause call comes from visibility change
// Only allow pause if user explicitly clicks pause button
if (document.hidden === false && !video._userPaused) {
console.log('[zgzjzj-helper] blocked programmatic pause');
return;
}
return originalPause();
};
videoPatchApplied = true;
console.log('[zgzjzj-helper] video.pause() patched');
}
}
// --- Main loop ---
var nextSectionTriggered = false;
function mainLoop() {
createUI();
handlePopups();
patchVideoPause();
var video = document.querySelector('video');
if (!video) {
updateStatus('\u7B49\u5F85\u89C6\u9891\u52A0\u8F7D...', '\u672A\u627E\u5230\u64AD\u653E\u5668');
nextSectionTriggered = false;
return;
}
if (CONFIG.autoMute && !video.muted) {
video.muted = true;
}
if (video.playbackRate !== CONFIG.playbackRate) {
try { video.playbackRate = CONFIG.playbackRate; } catch (e) {}
}
if (video.ended) {
if (!nextSectionTriggered) {
nextSectionTriggered = true;
updateStatus('\u672C\u8282\u5B8C\u6210', '\u6B63\u5728\u8DF3\u8F6C\u4E0B\u4E00\u8282...');
setTimeout(function () {
playNextSection();
// Reset flag after some time to allow re-trigger on new video
setTimeout(function () { nextSectionTriggered = false; }, 5000);
}, 1500);
}
} else if (video.paused) {
nextSectionTriggered = false;
updateStatus('\u5DF2\u6682\u505C', '\u6B63\u5728\u6062\u590D\u64AD\u653E...');
video._userPaused = false;
var p = video.play();
if (p !== undefined) {
p.catch(function () {
video.muted = true;
video.play();
});
}
} else {
nextSectionTriggered = false;
var cur = Math.floor(video.currentTime);
var tot = Math.floor(video.duration || 0);
var pct = tot > 0 ? Math.floor((cur / tot) * 100) : 0;
updateStatus('\u64AD\u653E\u4E2D \u25B6', '\u8FDB\u5EA6: ' + pct + '% (' + cur + '\u79D2 / ' + tot + '\u79D2)');
}
}
// Use Web Worker timer so it keeps running when tab is in background
try {
createWorkerTimer(mainLoop, CONFIG.checkInterval);
console.log('[zgzjzj-helper] Web Worker timer started');
} catch (e) {
// Fallback to setInterval if Worker fails
console.log('[zgzjzj-helper] Worker failed, using setInterval fallback');
setInterval(mainLoop, CONFIG.checkInterval);
}
}); // end window.load
})();