utilsmk

岐黄天使刷课助手的工具函数模块,提供通用的辅助功能,如模拟点击、延迟等。

Tento skript by neměl být instalován přímo. Jedná se o knihovnu, kterou by měly jiné skripty využívat pomocí meta příkazu // @require https://update.greasyfork.org/scripts/537081/1594864/utilsmk.js

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

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

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

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.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         岐黄天使刷课助手 - 工具函数模块
// @namespace    http://tampermonkey.net/qhtx-modules
// @version      1.3.0
// @description  岐黄天使刷课助手的工具函数模块,提供通用的辅助功能,如模拟点击、延迟等。
// @author       AI助手
// ==/UserScript==

// 工具函数模块
(function() {
    'use strict';

    // 记录最近点击的元素,防止重复点击
    let lastClickedElement = null;
    let lastClickTime = 0;
    const MIN_CLICK_INTERVAL = 500; // 最小点击间隔(毫秒)

    // 模拟点击元素
    // 新增模块加载日志功能
    function logModuleLoad(moduleName) {
      const timestamp = new Date().toISOString().slice(11, 23);
      console.log(`[${timestamp}] 模块加载追踪: ${moduleName} 已初始化完成`);
      GM_setValue('last_module_load', {
        module: moduleName,
        time: Date.now()
      });
    }

    // 增强模拟点击函数日志
    function simulateClick(element, question) {
      // 安全地访问moduleStatus
      if (window.moduleStatus && window.moduleStatus.loaded) {
        console.log('[模块状态] 当前已加载模块:', Array.from(window.moduleStatus.loaded));
      } else {
        console.log('[模块状态] moduleStatus未定义或未初始化');
      }
      try {
          // 防止重复点击同一元素
          const now = Date.now();
          if (element === lastClickedElement && now - lastClickTime < MIN_CLICK_INTERVAL) {
              console.log('防止重复点击:', element.textContent || element.id || element.className);
              return;
          }

          // 更新最近点击记录
          lastClickedElement = element;
          lastClickTime = now;

          // 检查元素是否在iframe中
          const isInIframe = question && question.isInIframe;
          const iframe = question && question.iframe;
          const targetWindow = isInIframe ? iframe.contentWindow : window;

          // 模拟鼠标移动到元素上
          const mouseoverEvent = new MouseEvent('mouseover', {
              view: targetWindow,
              bubbles: true,
              cancelable: true
          });
          element.dispatchEvent(mouseoverEvent);

          // 直接模拟点击,不添加延迟
          // 模拟鼠标按下
          const mousedownEvent = new MouseEvent('mousedown', {
              view: targetWindow,
              bubbles: true,
              cancelable: true
          });
          element.dispatchEvent(mousedownEvent);

          // 模拟鼠标释放
          const mouseupEvent = new MouseEvent('mouseup', {
              view: targetWindow,
              bubbles: true,
              cancelable: true
          });
          element.dispatchEvent(mouseupEvent);

          // 模拟点击
          const clickEvent = new MouseEvent('click', {
              view: targetWindow,
              bubbles: true,
              cancelable: true
          });
          element.dispatchEvent(clickEvent);

          // 如果元素有onclick属性,直接调用
          if (element.onclick) {
              element.onclick();
          }

          // 如果元素有choose函数,尝试调用
          if (isInIframe) {
              // 在iframe中尝试调用choose函数
              if (typeof iframe.contentWindow.choose === 'function' && element.classList.contains('option')) {
                  iframe.contentWindow.choose(element);
              }
          } else {
              // 在主窗口中尝试调用choose函数
              if (typeof choose === 'function' && element.classList.contains('option')) {
                  choose(element);
              }
          }

          // 如果元素有setti函数,尝试调用(用于题目导航)
          if (element.getAttribute('onclick') && element.getAttribute('onclick').includes('setti(')) {
              try {
                  const onclickAttr = element.getAttribute('onclick');
                  const match = onclickAttr.match(/setti\((\d+)/);
                  if (match && match[1]) {
                      const questionNumber = parseInt(match[1]);
                      if (isInIframe) {
                          if (typeof iframe.contentWindow.setti === 'function') {
                              iframe.contentWindow.setti(questionNumber, element);
                          }
                      } else {
                          if (typeof setti === 'function') {
                              setti(questionNumber, element);
                          }
                      }
                  }
              } catch (e) {
                  console.error('调用setti函数失败:', e);
              }
          }

          console.log('模拟点击元素:', element.textContent || element.id || element.className);

          // 添加网络请求监控
          const originalFetch = window.fetch;
          const originalXHROpen = XMLHttpRequest.prototype.open;

          // 请求跟踪器
          const requestTracker = {
            startMonitoring() {
              window.fetch = this.wrapFetch;
              XMLHttpRequest.prototype.open = this.wrapXHROpen;
              this.cleanupTimer = setTimeout(() => this.stopMonitoring(), 5000);
            },
            stopMonitoring() {
              window.fetch = originalFetch;
              XMLHttpRequest.prototype.open = originalXHROpen;
              clearTimeout(this.cleanupTimer);
            },
            wrapFetch: async function(input, init) {
              const startTime = Date.now();
              try {
                const response = await originalFetch(input, init);
                console.log('[网络请求] FETCH成功:', {
                  url: input.url || input,
                  status: response.status,
                  duration: Date.now() - startTime + 'ms'
                });
                return response;
              } catch (error) {
                console.log('[网络请求] FETCH失败:', {
                  url: input.url || input,
                  error: error.message
                });
                throw error;
              }
            },
            wrapXHROpen: function(method, url) {
              this._requestStartTime = Date.now();
              this.addEventListener('loadend', () => {
                console.log('[网络请求] XHR完成:', {
                  method: method,
                  url: url,
                  status: this.status,
                  duration: Date.now() - this._requestStartTime + 'ms'
                });
              });
              return originalXHROpen.apply(this, arguments);
            }
          };

          // 启动请求监控
          requestTracker.startMonitoring();
      } catch (e) {
          console.error('模拟点击出错:', e);

          // 尝试直接点击
          try {
              if (element.click) {
                  element.click();
              }
          } catch (e2) {
              console.error('直接点击也失败:', e2);
          }
      }
  };

    // 获取随机延迟时间
    function getRandomDelay(range) {
        return Math.floor(Math.random() * (range.max - range.min + 1)) + range.min;
    }

    // 关闭弹窗
    function closePopups(doc) {
        // 尝试关闭各种可能的弹窗
        const closeButtons = doc.querySelectorAll('.close-btn, .close, .popup-close, .messager-button a');
        closeButtons.forEach(btn => {
            try {
                btn.click();
            } catch (e) {
                console.error('关闭弹窗失败:', e);
            }
        });

        // 特别处理messager-window弹窗
        const messagerWindows = doc.querySelectorAll('.messager-window');
        if (messagerWindows.length > 0) {
            messagerWindows.forEach(window => {
                try {
                    const closeBtn = window.querySelector('.messager-button a');
                    if (closeBtn) {
                        closeBtn.click();
                    }
                } catch (e) {
                    console.error('关闭messager-window失败:', e);
                }
            });
        }
    };

    // 检查页面类型
    function checkPageType() {
        // 确定当前页面类型
        let pageType = 'unknown';

        if (window.location.href.includes('courseLearn.html')) {
            pageType = 'courseLearn';
        } else if (window.location.href.includes('courseSimulate.html')) {
            pageType = 'courseSimulate';
        } else if (window.location.href.includes('courseExam.html')) {
            pageType = 'courseExam';
        } else if (window.location.href.includes('courseList.html')) {
            pageType = 'courseList';
        } else if (window.location.href.includes('视频播放.html')) {
            pageType = 'videoPlay';
        }

        console.log('当前页面类型:', pageType);

        // 根据页面类型执行不同操作
        switch (pageType) {
            case 'courseLearn':
                // 在课程学习页面,检查是否应该自动开始
                let isRunning;
                if (typeof GM_getValue !== 'undefined') {
                    isRunning = GM_getValue('qh-is-running', false);
                } else {
                    isRunning = localStorage.getItem('qh-is-running') === 'true';
                }

                if (isRunning) {
                    console.log('自动学习已启用,尝试播放视频');
                    // 延迟执行,确保页面加载完成
                    setTimeout(() => {
                        if (typeof playAllVideos === 'function') {
                            playAllVideos();
                        }
                    }, 2000);
                }
                break;

            case 'courseSimulate':
            case 'courseExam':
                // 在模拟练习或考试页面,添加自动答题按钮
                if (window.qh.autoFlowConfig.enabled && typeof startAutoAnswer === 'function') {
                    setTimeout(() => {
                        startAutoAnswer();
                    }, 2000);
                }
                break;

            case 'courseList':
                // 在课程列表页面,可以添加一些特定操作
                console.log('在课程列表页面,可以选择课程开始学习');
                break;

            case 'videoPlay':
                // 在视频播放页面,初始化视频导航
                console.log('在视频播放页面,初始化视频导航');
                if (typeof initVideoNavigation === 'function') {
                    setTimeout(() => {
                        initVideoNavigation();
                    }, 2000);
                }
                break;

            default:
                // 即使在其他页面,也尝试检测和播放视频
                setTimeout(() => {
                    const videos = document.querySelectorAll('video');
                    if (videos.length > 0) {
                        console.log('在其他页面检测到视频,尝试播放');
                        if (typeof playAllVideos === 'function') {
                            playAllVideos();
                        }
                    }
                }, 3000);
                break;
        }
    }

    // 导出模块函数
    window.utils = checkPageType;
    window.simulateClick = simulateClick;
    window.getRandomDelay = getRandomDelay;
    window.closePopups = closePopups;
    window.logModuleLoad = logModuleLoad;
    window.checkPageType = checkPageType;

    // 通知主脚本模块已加载
    console.log('[模块加载] utils 模块已加载');
})();