广东省继续教育(含公需课)自动刷课

广东省继续教育(含公需课)刷课,自动答题 + 自动关闭弹窗 + 完成自动进入下章

当前为 2025-10-13 提交的版本,查看 最新版本

// ==UserScript==
// @name         广东省继续教育(含公需课)自动刷课
// @version      3.0
// @description  广东省继续教育(含公需课)刷课,自动答题 + 自动关闭弹窗 + 完成自动进入下章
// @author       lzhzssy
// @icon         https://ggfw.gdhrss.gov.cn/favicon.ico
// @match        http*://ggfw.hrss.gd.gov.cn/zxpx/auc/play/player*
// @license      GPLv3
// @namespace https://gf.qytechs.cn/
// ==/UserScript==


setTimeout(function () {
    // 静音
    p.tag.muted = true;
    var errChecking = setInterval(function () {
        if ($('.learnpercent').text().indexOf('已完成') != -1) {
            var learnlist = $("a:contains('未完成')").length != 0 ? $("a:contains('未完成')") : $("a:contains('未开始')");
            if (learnlist.length == 0) {
                if (confirm('本课程全部学习完成!即将关闭页面!')) {
                    window.close();
                }
            } else {
                learnlist.each(function () {
                    this.click();
                })
            }
        }
        // 暂停时自动开始播放
        if (p.paused()) {
            p.play()
        }
    }, 500);
}, 1000);





// ====== 自动答题 + 通用弹窗持续处理(修复版)======
(function () {
    const TRY_INTERVAL = 1000;
    let answeredThisQuestion = false;
    let currentQuestionId = null;
    let processedDialogs = new WeakSet();
    let isRetrying = false;
    let waitingForNextQuestion = false; // 新增:等待下一题加载的标志
    let lastAnswerTime = 0; // 记录最后一次答题时间

    // ================= 工具函数 =================
    function clickEl(el) {
        if (!el) return false;
        try {
            el.click();
            return true;
        } catch (e) {
            try {
                el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
                return true;
            } catch (err) {
                console.warn('click failed', err);
                return false;
            }
        }
    }

    function setInputChecked(input) {
        if (!input) return;
        input.checked = true;
        input.dispatchEvent(new Event('change', { bubbles: true }));
        input.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
    }

    function submitAnswer() {
        const submitBtn = document.querySelector('.reply-sub');
        if (submitBtn) {
            clickEl(submitBtn);
            return true;
        }
        if (typeof window.subAnswer === 'function') {
            try { window.subAnswer(); return true; } catch (e) { }
        }
        return false;
    }

    // 获取题目唯一标识
    function getQuestionId() {
        const form = document.querySelector('#from_ejectque');
        if (!form) return null;

        // 综合多个因素生成唯一ID
        const questionText = form.querySelector('.eject-title, .question-text, h3, .title');
        const text = questionText ? questionText.innerText.trim() : '';

        // 获取所有选项的状态
        const inputs = Array.from(form.querySelectorAll("input[name='panduan']"));
        const optionsState = inputs.map(i => `${i.value}:${i.checked}`).join('|');

        // 组合生成ID
        return `${text}_${optionsState}`;
    }

    // 检查是否有可见的题目表单
    function hasVisibleQuestion() {
        const form = document.querySelector('#from_ejectque');
        if (!form) return false;
        const style = window.getComputedStyle(form);
        return style.display !== 'none' && form.offsetParent !== null;
    }

    // ================= 答题自动化部分 =================
    function tryAutoAnswerOnce() {
        const form = document.querySelector('#from_ejectque');
        if (!form) return false;

        // 如果正在等待下一题或表单不可见,跳过
        if (waitingForNextQuestion || !hasVisibleQuestion()) {
            return false;
        }

        // 防抖:2秒内不重复答题
        const now = Date.now();
        if (now - lastAnswerTime < 2000) {
            return false;
        }

        // 检查是否是新题目
        const questionId = getQuestionId();
        if (!questionId) return false;

        if (questionId !== currentQuestionId) {
            console.log('[AutoAnswer] 检测到新题目');
            currentQuestionId = questionId;
            answeredThisQuestion = false;
            isRetrying = false;
            waitingForNextQuestion = false;
        }

        // 如果已经回答过或正在重试,跳过
        if (answeredThisQuestion || isRetrying) return false;

        let opt = form.querySelector("input[name='panduan'][value='0']");
        if (!opt) opt = form.querySelector("input[name='panduan']");
        if (!opt) return false;

        console.log('[AutoAnswer] 尝试提交答案:选项0');
        setInputChecked(opt);
        setTimeout(() => {
            if (submitAnswer()) {
                answeredThisQuestion = true;
                lastAnswerTime = Date.now();
                console.log('[AutoAnswer] 答案已提交');
            }
        }, 500);
        return true;
    }

    // =============== 通用弹窗检测处理 ===============
    function findVisibleDialogs() {
        const dialogs = Array.from(document.querySelectorAll('.messager-window, .panel.window, .prism-ErrorMessage'));
        return dialogs.filter(d => {
            if (processedDialogs.has(d)) return false;

            const style = window.getComputedStyle(d);
            if (style.display !== 'none' && d.offsetParent !== null) return true;
            const inline = d.getAttribute('style') || '';
            return inline.includes('display: block');
        });
    }

    function handleDialog(dialog) {
        processedDialogs.add(dialog);

        const text = dialog.innerText.trim();
        if (!text) return;
        console.log('[PopupHandler] 检测到弹窗:', text);

        if (text.includes('答案错误')) {
            console.log('[PopupHandler] 处理:答案错误 → 准备切换选项');

            clickDialogOk(dialog);
            isRetrying = true;
            answeredThisQuestion = false;

            setTimeout(() => {
                const form = document.querySelector('#from_ejectque');
                if (!form) {
                    isRetrying = false;
                    return;
                }

                const alt = form.querySelector("input[name='panduan'][value='1']");
                if (alt && !alt.checked) {
                    console.log('[PopupHandler] 切换到选项1');
                    setInputChecked(alt);
                    setTimeout(() => {
                        submitAnswer();
                        answeredThisQuestion = true;
                        lastAnswerTime = Date.now();
                        isRetrying = false;
                    }, 500);
                } else {
                    const anyOpt = Array.from(form.querySelectorAll("input[name='panduan']"));
                    const unchecked = anyOpt.find(o => !o.checked);
                    if (unchecked) {
                        console.log('[PopupHandler] 切换到其他选项');
                        setInputChecked(unchecked);
                        setTimeout(() => {
                            submitAnswer();
                            answeredThisQuestion = true;
                            lastAnswerTime = Date.now();
                            isRetrying = false;
                        }, 500);
                    } else {
                        isRetrying = false;
                    }
                }
            }, 1200);
        }
        else if (text.includes('答案正确')) {
            console.log('[PopupHandler] 处理:答案正确 → 点击确定,等待下一题');

            // 设置等待标志,防止在题目切换前重复答题
            waitingForNextQuestion = true;

            setTimeout(() => {
                clickDialogOk(dialog);
                console.log('[PopupHandler] 已点击确定,等待5秒后恢复答题');

                // 延长等待时间,确保题目完全切换
                setTimeout(() => {
                    currentQuestionId = null; // 强制重新识别题目
                    waitingForNextQuestion = false;
                    answeredThisQuestion = false;
                    console.log('[PopupHandler] 恢复答题检测');
                }, 5000); // 等待5秒
            }, 800);
        }
        else if (text.includes('网络') || text.includes('播放错误') || text.includes('重试')) {
            console.log('[PopupHandler] 处理:网络/播放错误 → 点击刷新或重试');
            const refreshBtn = dialog.querySelector('.prism-button-refresh, .prism-button-retry');
            if (refreshBtn) clickEl(refreshBtn);
            else clickDialogOk(dialog);
        }
        else {
            console.log('[PopupHandler] 处理:其他提示弹窗 → 点击确定');
            setTimeout(() => clickDialogOk(dialog), 800);
        }
    }

    function clickDialogOk(dialog) {
        let okBtn = Array.from(dialog.querySelectorAll('a.l-btn, .prism-button, button'))
            .find(a => (a.textContent || '').includes('确定') || (a.textContent || '').includes('刷新') || (a.textContent || '').includes('重试'));
        if (!okBtn) {
            const span = dialog.querySelector('.l-btn-text');
            if (span && /确定|刷新|重试/.test(span.textContent)) okBtn = span.closest('a') || span;
        }
        if (!okBtn) {
            okBtn = dialog.querySelector('.panel-tool-close');
        }
        if (okBtn) {
            clickEl(okBtn);
            console.log('[PopupHandler] 已点击弹窗按钮');
        }
    }

    // =============== 主循环:持续检测 ===============
    const mainInterval = setInterval(() => {
        try {
            if (!isRetrying) {
                tryAutoAnswerOnce();
            }

            const dialogs = findVisibleDialogs();
            dialogs.forEach(dialog => handleDialog(dialog));
        } catch (err) {
            console.error('[AutoAnswer] 主循环错误:', err);
        }
    }, TRY_INTERVAL);

    setInterval(() => {
        processedDialogs = new WeakSet();
    }, 30000);

    console.log('[AutoAnswer] 自动答题 + 弹窗处理脚本已启动 ✅');
})();




// 拖拉进度 + 倍速播放(但是没用,因为有要求学习时长)
(function () {
  'use strict';

  function enableVideoControl() {
    const video = document.querySelector('video');
    if (!video) return;

    console.log('[Prism增强] 找到视频元素,开始启用自定义控制。');

    // 允许拖动(有的播放器禁用 onseeked/onseeking)
    video.removeAttribute('disablepictureinpicture');
    video.controls = true; // 显示控制栏

    // 默认倍速
    video.playbackRate = 1.0;

    // 添加快捷键控制
    document.addEventListener('keydown', (e) => {
      if (e.target.tagName.toLowerCase() === 'input' || e.target.tagName.toLowerCase() === 'textarea') return;

      switch (e.key) {
        case '>': // Shift + .
          video.playbackRate = Math.min(video.playbackRate + 0.25, 4);
          showTip(`倍速:${video.playbackRate.toFixed(2)}x`);
          break;
        case '<': // Shift + ,
          video.playbackRate = Math.max(video.playbackRate - 0.25, 0.25);
          showTip(`倍速:${video.playbackRate.toFixed(2)}x`);
          break;
        case 'ArrowRight':
          video.currentTime += 10;
          showTip('快进10秒');
          break;
        case 'ArrowLeft':
          video.currentTime -= 10;
          showTip('后退10秒');
          break;
        case ' ': // 空格暂停/播放
          e.preventDefault();
          video.paused ? video.play() : video.pause();
          break;
      }
    });

    // 倍速提示
    function showTip(text) {
      let tip = document.getElementById('speed-tip');
      if (!tip) {
        tip = document.createElement('div');
        tip.id = 'speed-tip';
        tip.style.cssText =
          'position:fixed;bottom:15%;left:50%;transform:translateX(-50%);' +
          'background:rgba(0,0,0,0.7);color:#fff;padding:8px 15px;border-radius:8px;font-size:16px;z-index:999999;transition:opacity 0.5s;';
        document.body.appendChild(tip);
      }
      tip.textContent = text;
      tip.style.opacity = '1';
      clearTimeout(tip._timer);
      tip._timer = setTimeout(() => (tip.style.opacity = '0'), 1200);
    }
  }

  // 监听页面动态加载(Prism Player 是异步初始化的)
  const observer = new MutationObserver(() => {
    if (document.querySelector('video')) {
      enableVideoControl();
      observer.disconnect();
    }
  });

  observer.observe(document.body, { childList: true, subtree: true });
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址