东航易学助手

检测超时弹窗,稳定多开加速,并处理所有弹出按钮

// ==UserScript==
// @name         东航易学助手
// @namespace    http://tampermonkey.net/
// @version      2.2.1
// @description  检测超时弹窗,稳定多开加速,并处理所有弹出按钮
// @author       买不起泡面的Hanley
// @match        *://dhyx.ceair.com/*
// @require      http://code.jquery.com/jquery-1.9.1.min.js
// @grant        unsafeWindow
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @license MIT
// ==/UserScript==

var Status = 0; // 初始化状态标识
var lastClickTime = Date.now(); // 最后一次点击的时间
var refreshInterval; // 用于存储定时器ID
var isDragging = false; // 用于标识是否正在拖动
var dragStartX, dragStartY; // 记录拖动开始时的鼠标位置

function getAutoNavigateEnabled() {
    return localStorage.getItem('autoNavigateEnabled') === 'true';
}

function setAutoNavigateEnabled(value) {
    localStorage.setItem('autoNavigateEnabled', value);
    manageAutoRefresh();
}

function manageAutoRefresh() {
    clearInterval(refreshInterval); // 清除之前的定时器
    if (Status == 0 && !getAutoNavigateEnabled()) {
        refreshInterval = setInterval(function() {
            window.top.location.reload(true);
        }, 300000); // 5分钟刷新一次
    }
}

function updateToggleButton(toggleButton) {
    const autoNavigateEnabled = getAutoNavigateEnabled();
    toggleButton.innerText = autoNavigateEnabled ? "自动导航:开" : "自动导航:关";
    toggleButton.style.background = autoNavigateEnabled ? 'rgba(255, 255, 0, 0.5)' : 'rgba(128, 128, 128, 0.5)';
}

function detectAndClickAlertButton() {
    // 查找弹窗的wrapper
    const alertWrapper = document.querySelector('.alert-shadow.new-alert-shadow');
    if (!alertWrapper) {
        return;
    }

    // 查找确定按钮
    const alertButton = document.getElementById('D253btn-ok');
    if (alertButton) {
        alertButton.click(); // 自动点击确定按钮
    }
}


function detectString() {
    function checkString(node) {
        if (node.nodeType === Node.TEXT_NODE) {
            if (node.nodeValue.includes('可继续学习')) {
                var confirmBtns3 = document.getElementsByClassName("btn");
                if (confirmBtns3 != null && confirmBtns3.length > 0) {
                    confirmBtns3[0].click();
                    lastClickTime = Date.now();
                }
            } else if (node.nodeValue.includes('恭喜')) {
                var cancelBtns = document.querySelectorAll('button[data-bb-handler="cancel"]');
                if (cancelBtns.length > 0) {
                    cancelBtns[0].click();
                }
                if (getAutoNavigateEnabled()) {
                    setTimeout(function() {
                        window.top.location.reload(true);
                    }, 5000);
                }
            } else if (node.nodeValue.includes('进度已保存')) {
                if (getAutoNavigateEnabled()) {
                    // 5秒后刷新页面
                    setTimeout(function() {
                        window.top.location.reload(true);
                    }, 5000);
                }
            } else if (node.nodeValue.includes('小测试')) {
                // 执行一次遍历
            }
        } else if (node.nodeType === Node.ELEMENT_NODE) {
            // 检查元素节点中的文本内容
            if (node.textContent.includes('进度已保存')) {
                if (getAutoNavigateEnabled()) {
                    // 5秒后刷新页面
                    setTimeout(function() {
                        window.top.location.reload(true);
                    }, 5000);
                }
            }
            // 遍历子节点
            for (let child of node.childNodes) {
                checkString(child);
            }
        }
    }

    const observer = new MutationObserver(function(mutations) {
        for (let mutation of mutations) {
            for (let addedNode of mutation.addedNodes) {
                checkString(addedNode);
            }
        }
    });

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

function updateFlagStatus() {
    const flag1 = document.getElementById('flag');
    if (Status == 1) {
        flag1.innerText = "检测到考试!代码停止运行!\nby:买不起泡面的Hanley";
    } else if (Status == 2) {
        flag1.innerText = "运行阅卷脚本\nby:买不起泡面的Hanley";
    } else {
        flag1.innerText = "脚本正在运行\nby:买不起泡面的Hanley";
    }
}

function makeElementDraggable(element) {
    let offsetX, offsetY;

    element.addEventListener('mousedown', function(event) {
        isDragging = false;
        dragStartX = event.clientX;
        dragStartY = event.clientY;
        offsetX = event.clientX - element.getBoundingClientRect().left;
        offsetY = event.clientY - element.getBoundingClientRect().top;
        element.style.cursor = 'move';

        function onMouseMove(event) {
            const deltaX = event.clientX - dragStartX;
            const deltaY = event.clientY - dragStartY;
            if (!isDragging && (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5)) {
                isDragging = true;
            }
            if (isDragging) {
                element.style.left = event.clientX - offsetX + 'px';
                element.style.top = event.clientY - offsetY + 'px';
                event.preventDefault(); // 防止选择文本
            }
        }

        function onMouseUp() {
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseup', onMouseUp);
            element.style.cursor = 'pointer';
        }

        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseup', onMouseUp);
    });
}

if (window.self === window.top) { // 仅在顶层窗口显示悬浮窗
    setTimeout(function() {
        const flag = document.createElement("div");
        flag.id = 'flag';
        flag.style.cssText = 'left: 10px;bottom: 10px;background: rgba(26, 89, 183, 0.5);color:#ffffff;overflow: hidden;z-index: 9999;position: fixed;padding:3px;text-align:center;width: 175px;height: 45px;line-height: 20px;border-radius: 4px;cursor: pointer;';
        document.getElementById("content").appendChild(flag);

        updateFlagStatus();

        makeElementDraggable(flag);

        flag.addEventListener('click', function() {
            if (!isDragging && flag.innerText.includes("脚本正在运行")) {
                flag.style.background = 'rgba(255, 0, 0, 0.5)';
                flag.innerText = "正在尝试爆破\nby:买不起泡面的Hanley";
                markVideoAsCompleted();
                setTimeout(function() {
                    flag.style.background = 'rgba(26, 89, 183, 0.5)';
                    updateFlagStatus();
                }, 2000);
                loadKnockoutJs(proceedWithModifications);
            }
        });

        const toggleButton = document.createElement("div");
        toggleButton.id = 'toggleButton';
        toggleButton.style.cssText = 'right: 10px;bottom: 10px;color:#000000;overflow: hidden;z-index: 9999;position: fixed;padding:3px;text-align:center;width: 100px;height: 30px;line-height: 25px;border-radius: 4px;cursor: pointer;';
        document.body.appendChild(toggleButton);

        updateToggleButton(toggleButton); // 确保页面加载时立即更新按钮背景颜色

        makeElementDraggable(toggleButton);

        toggleButton.addEventListener('click', function() {
            if (!isDragging) {
                const newState = !getAutoNavigateEnabled();
                setAutoNavigateEnabled(newState);
                updateToggleButton(toggleButton);
                setTimeout(function() {
                    window.top.location.reload(true);
                }, 1000);//一秒刷新
            }
        });

        // 初始化时检查并设置自动刷新
        manageAutoRefresh();

    }, 4000); // 4秒后显示状态牌
}

var AutoClick = setInterval(function() { Clicker() }, 1000); // 每秒运行一次

function Clicker() {
    console.error = function() {};

    if (window.location.href.indexOf("exam") > -1) {
        if (window.location.href.indexOf("mark-paper") > -1) { // 检测到是在阅卷,停止运行但不跳弹窗
            clearInterval(AutoClick); // 阅卷了就不乱点了
            clearInterval(refreshInterval);
            Status = 2; // 阅卷了阅卷了
        } else {
            clearInterval(AutoClick); // 别是在考试,考试就直接摆烂
            clearInterval(refreshInterval);
            Status = 1; // 考试了还玩球,状态标异常
            alert('检测到考试!代码停止运行!');
        }
    }
    detectString(); // 叫外援
    checkLoginStatus();
    handleClicks();
    detectAndClickAlertButton();

    if (getAutoNavigateEnabled()) {
        clickNextButtonInIframe();
        autoNavigateNextChapter();
    }

    if (getAutoNavigateEnabled()) {
        const nextPage = document.querySelector(".navBtn.glyphicon.glyphicon-chevron-right");
        if (nextPage && !nextPage.disabled) {
            nextPage.click();
            lastClickTime = Date.now();
        }
    }
}

function handleClicks() {
    if (!getAutoNavigateEnabled()) return;

    const confirmBtns = document.querySelectorAll(".bootbox-close-button.close");
    if (confirmBtns.length > 0) {
        confirmBtns[0].click(); // 自动点击
        lastClickTime = Date.now();
    }

    const confirmBtns2 = document.querySelectorAll(".alertify-button.alertify-button-ok");
    if (confirmBtns2.length > 0) {
        confirmBtns2[0].click();
        lastClickTime = Date.now();
    }
}

// 自动导航到下一个章节
function autoNavigateNextChapter() {
    if (!getAutoNavigateEnabled()) return;

    const currentChapter = findCurrentChapter();
    if (currentChapter && isChapterCompleted(currentChapter)) {
        clickNextChapter(currentChapter);
    }
}

// 查找当前正在学习的章节
function findCurrentChapter() {
    return $(".chapter-list-box.focus");
}

// 判断章节是否完成
function isChapterCompleted(chapter) {
    return !chapter.find('.item.pointer.item22').length;
}

function clickNextChapter(currentChapter) {
    if (!getAutoNavigateEnabled()) {
        return;
    }
    // 从当前章节开始,查找下一个未完成的章节
    let chapters = Array.from(document.querySelectorAll('.chapter-list-box'));
    let currentChapterIndex = chapters.indexOf(currentChapter[0]); // 获取当前章节的索引

    for (let i = currentChapterIndex + 1; i < chapters.length; i++) {
        let nextChapterToStudy = chapters[i];
        if (nextChapterToStudy.querySelector('.item.pointer.item22')) {
            let clickableElement = nextChapterToStudy.querySelector('.chapter-item');
            if (clickableElement) {
                clickableElement.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
                lastClickTime = Date.now();
                break;
            }
        }
    }
}

// 在 iframe 内部执行点击操作
function clickNextButtonInIframe() {
    if (!getAutoNavigateEnabled()) return;

    const iframe = document.getElementById('scormIframe');
    if (iframe) {
        const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
        const nextPageButton = iframeDocument.querySelector('.navBtn.glyphicon.glyphicon-chevron-right.nextCompleted');
        if (nextPageButton) {
            nextPageButton.click();
            lastClickTime = Date.now();
        }
        const popupBtns = iframeDocument.querySelectorAll('.btn[data-bb-handler="ok"], .btn[data-bb-handler="next"], .btn[data-bb-handler="confirm"]');
        popupBtns.forEach(function(btn) {
            simulateClick(btn, iframe.contentWindow);
            if (getAutoNavigateEnabled()) {
                btn.click();
                lastClickTime = Date.now();
            }
        });

        const navigationLabel = iframeDocument.querySelector('.navigation-controls__label');
        if (navigationLabel && getAutoNavigateEnabled()) {
            const pageNumbers = navigationLabel.innerText.split('/');
            if (pageNumbers.length === 2 && pageNumbers[0].trim() === pageNumbers[1].trim()) {
                if (getAutoNavigateEnabled()) {
                    setTimeout(function() {
                        window.top.location.reload(true);
                    }, 10000); // 等待 10 秒后强制导航到下一个章节
                }
            }
        }

        const buttons = iframeDocument.querySelectorAll('.uikit-primary-button.uikit-primary-button_size_medium.play-controls-container__play-pause-button');
        buttons.forEach(function(button) {
            const svg = button.querySelector('svg');
            if (svg) {
                const path = svg.querySelector('path');
                if (path && getAutoNavigateEnabled() && path.getAttribute('d') === 'M5 16.3087V3.54659L5 3.54659L16.8484 8.87836C17.2245 9.04759 17.2455 9.57369 16.8842 9.77243L5 16.3087Z') {
                    simulateClick(button, iframe.contentWindow);
                }
            }
        });

        const popupBtns2 = iframeDocument.querySelectorAll('.message-box-buttons__window-button');
        popupBtns2.forEach(function(btn) {
            simulateClick(btn, iframe.contentWindow);
        });
    }
}

function simulateClick(element, win) {
    if (!getAutoNavigateEnabled()) return;

    const mouseDownEvent = new MouseEvent('mousedown', {
        bubbles: true,
        cancelable: true,
        view: win
    });
    const mouseUpEvent = new MouseEvent('mouseup', {
        bubbles: true,
        cancelable: true,
        view: win
    });
    const clickEvent = new MouseEvent('click', {
        bubbles: true,
        cancelable: true,
        view: win
    });

    element.dispatchEvent(mouseDownEvent);
    element.dispatchEvent(mouseUpEvent);
    element.dispatchEvent(clickEvent);
}

function loadKnockoutJs(callback) {
    var resources = performance.getEntriesByType('resource');
    var regex = /file-cloud\/01\/[0-9A-Za-z]+\/[0-9A-Za-z]+\/[0-9A-Za-z]+/;
    var knockoutJsUrl = '';

    for (var i = 0; i < resources.length; i++) {
        var resource = resources[i];
        if (resource.name.includes('scorm_api.jsp?')) {
            var match = resource.name.match(regex);
            if (match) {
                var dynamicPath = match[0];
                if (dynamicPath.includes('/player')) {
                    dynamicPath = dynamicPath.replace('/player', '');
                }
                knockoutJsUrl = 'https://dhyx.ceair.com/' + dynamicPath + '/lib/knockout/knockout.min.js';
                break;
            }
        }
    }

    if (knockoutJsUrl) {
        var script = document.createElement('script');
        script.src = knockoutJsUrl;
        document.head.appendChild(script);

        script.onload = function() {
            callback();
        };
    } else {
        callback();
    }
}

function proceedWithModifications() {
    function findViewModel(root) {
        var queue = [{ obj: root, path: '' }];
        var visited = new Set();

        while (queue.length > 0) {
            var current = queue.shift();
            var obj = current.obj;
            var path = current.path;

            if (visited.has(obj)) {
                continue;
            }
            visited.add(obj);

            for (var prop in obj) {
                if (obj.hasOwnProperty(prop) && typeof obj[prop] === 'object' && obj[prop] !== null) {
                    try {
                        if (obj[prop].constructor && obj[prop].constructor.name === 'CBTPlayer') {
                            return obj[prop];
                        }
                    } catch (e) {
                        continue;
                    }
                    queue.push({ obj: obj[prop], path: path + prop + '.' });
                }
            }
        }
        return null;
    }

    var cbtPlayer = findViewModel(window);

    if (cbtPlayer) {
        var currentOrg = cbtPlayer.currentOrg();
        if (currentOrg && currentOrg.items) {
            currentOrg.items().forEach(function(item) {
                item.completed(true);
                item.visited(true);
                item.playbackFinished(true);
                if (item.type === 'topic' || item.type === 'mergedpages') {
                    item.items().forEach(function(subItem) {
                        subItem.completed(true);
                        subItem.visited(true);
                        subItem.playbackFinished(true);
                    });
                }
            });

            currentOrg.items.valueHasMutated();

            if (typeof cbtPlayer.SavePlayer === 'function') {
                cbtPlayer.SavePlayer();
            }
        }
    }
}

function checkLoginStatus() {
    if (window.location.href.indexOf("oauth/#login") > -1) {
        setTimeout(function() {
            document.querySelector(".step-item.pointer:nth-child(2)").click();
        }, 5000);
        lastClickTime = Date.now();
    }
}

// 添加视频爆破功能
function markVideoAsCompleted() {
    var videoElements = document.querySelectorAll('video[id$="player_html5_api"]');
    if (videoElements.length > 0) {
        var videoElement = videoElements[0];
        videojs(videoElement).ready(function() {
            var player = this;
            player.currentTime(player.duration());
            player.trigger('ended');
        });
    }
}