专技天下自动刷课脚本

自动播放并静音,自动下一节,后台播放不暂停

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @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

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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;">&#9889; \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;">&#x2705; \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

})();