TKAUTO

Combines v1.6 Timer Sync, Stop Button, and Auto-Check-In for 2cool site.

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         TKAUTO
// @namespace    http://tampermonkey.net/
// @version      1.6.4
// @description  Combines v1.6 Timer Sync, Stop Button, and Auto-Check-In for 2cool site.
// @match        https://school.toocooltrafficschool.com/*
// @grant        none
// ==/UserScript==

/*INSTRUCTIONS:
  To use this on a different site, change the @match line above.
  Example: @match  *://app.driversed.com/*
*/

(function() {
    'use strict';

    // PERSISTENCE: Using localStorage so the STOP state survives page changes
    let isDisabled = localStorage.getItem('autoSkipDisabled') === 'true';

    // --- 1. Create UI Dashboard (Top Level Only) ---
    if (window.self === window.top) {
        const dashboard = document.createElement('div');
        dashboard.id = 'skip-dash-v16';
        dashboard.style = `
            position: fixed; top: 0; left: 0; width: 100%;
            background: #111; color: #fff; z-index: 2147483647;
            display: flex; justify-content: space-around; align-items: center;
            padding: 10px; font-family: sans-serif;
            border-bottom: 3px solid #f1c40f; box-shadow: 0 4px 15px rgba(0,0,0,0.6);
        `;
        dashboard.innerHTML = `
            <div style="font-weight: bold;">SKIPPER: <span id="dash-status">--</span></div>
            <div style="font-size: 20px;">TOTAL TIME: <span id="dash-timer" style="color: #f1c40f; font-weight: bold;">--:--:--</span></div>
        `;
        document.body.appendChild(dashboard);
        document.body.style.marginTop = '60px';
    }

    // --- 2. THE "STILL HERE" CHECK-IN LOGIC ---
    function handleCheckpoints(doc) {
        // Keywords from your previous script
        const keywords = ["still here", "i'm still here", "stay active", "stay logged in", "yes", "continue"];
        const buttons = doc.querySelectorAll('button, input[type="button"], a, .dismiss-timeout');

        buttons.forEach(btn => {
            const text = (btn.innerText || btn.value || '').trim().toLowerCase();
            // If text matches or has the specific timeout class
            if (keywords.some(k => text.includes(k)) || btn.classList.contains("dismiss-timeout")) {
                // Only click if the button is visible (not hidden behind the scenes)
                if (btn.offsetParent !== null) {
                    console.log(`✅ Auto-clicked checkpoint: "${text}"`);
                    btn.click();
                }
            }
        });
    }

    // --- 3. THE TIMER SYNC LOGIC (Iframe Aware) ---
    function findTimerAcrossFrames(doc) {
        let timer = doc.getElementById('time-in-course') || doc.querySelector('.total-course-time');
        if (timer) return timer.textContent;

        const iframes = doc.getElementsByTagName('iframe');
        for (let i = 0; i < iframes.length; i++) {
            try {
                let frameDoc = iframes[i].contentDocument || iframes[i].contentWindow.document;
                let found = findTimerAcrossFrames(frameDoc);
                if (found) return found;
            } catch (e) { /* Cross-origin security block */ }
        }
        return null;
    }

    // --- 4. MAIN LOOP ---
    function mainLoop() {
        if (window.self !== window.top) return;

        const statusText = document.getElementById('dash-status');
        const timerText = document.getElementById('dash-timer');

        // Update Dashboard UI
        const currentTimerVal = findTimerAcrossFrames(document);
        if (currentTimerVal && timerText) timerText.textContent = currentTimerVal.trim();

        if (statusText) {
            statusText.textContent = isDisabled ? 'PAUSED' : 'ACTIVE';
            statusText.style.color = isDisabled ? '#ff4d4d' : '#2ecc71';
        }

        // STEP A: Always handle checkpoints (Still Here checks) regardless of "Stop" button
        handleCheckpoints(document);
        const iframes = document.getElementsByTagName('iframe');
        for (let i = 0; i < iframes.length; i++) {
            try {
                handleCheckpoints(iframes[i].contentDocument || iframes[i].contentWindow.document);
            } catch (e) {}
        }

        // STEP B: Handle Auto-Clicking "Next" (Only if NOT paused)
        if (isDisabled) return;

        const nextBtn = document.getElementById('next-button') || document.getElementById('arrow-next');
        if (nextBtn && !nextBtn.disabled && nextBtn.offsetParent !== null) {
            console.log("Next ready. Skipping...");
            nextBtn.click();
        }
    }

    // Run every 500ms to keep the clock smooth and catch popups quickly
    setInterval(mainLoop, 500);

    // --- 5. PERSISTENT STOP/RESUME BUTTON ---
    if (window.self === window.top) {
        const stopBtn = document.createElement('button');
        stopBtn.style = `
            position: fixed; bottom: 20px; right: 20px; z-index: 2147483647;
            color: #fff; border: none; padding: 12px 22px; border-radius: 50px;
            cursor: pointer; font-weight: bold; font-size: 15px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.4); transition: 0.3s;
        `;

        const updateBtn = () => {
            stopBtn.textContent = isDisabled ? '▶ RESUME' : '█ STOP';
            stopBtn.style.background = isDisabled ? '#2ecc71' : '#e74c3c';
        };

        stopBtn.onclick = () => {
            isDisabled = !isDisabled;
            localStorage.setItem('autoSkipDisabled', isDisabled);
            updateBtn();
        };

        updateBtn();
        document.body.appendChild(stopBtn);
    }
})();