utilsmk

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

Dette scriptet burde ikke installeres direkte. Det er et bibliotek for andre script å inkludere med det nye metadirektivet // @require https://update.greasyfork.org/scripts/537081/1594864/utilsmk.js

// ==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 模块已加载');
})();