IDriveSafely.com auto skip

Auto-click navigation button when enabled, auto-play videos

// ==UserScript==
// @name         IDriveSafely.com auto skip
// @namespace    auto clicker 
// @version      4.2
// @description  Auto-click navigation button when enabled, auto-play videos
// @author       💩p💩o💩o
// @match        https://app.idrivesafely.com/*
// @license MIT
// ==/UserScript==

(function() {
    'use strict';
    
    console.log("IDriveSafely Auto Skip Script Started v4.2");
    
    let videoPlayed = false;
    let continueLearningButtonClicked = false;
    let lastButtonState = null;
    let lastUrl = window.location.href;
    
    // Function to check if an element appears disabled in any way
    function isButtonDisabled(button) {
        if (!button) return true;
        
        // Check standard disabled property
        if (button.disabled) return true;
        
        // Check disabled attribute
        if (button.hasAttribute('disabled')) return true;
        
        // Check aria-disabled
        if (button.getAttribute('aria-disabled') === 'true') return true;
        
        // Check for disabled class
        const classList = button.className || '';
        if (classList.includes('disabled') || classList.includes('btn-disabled')) return true;
        
        // Check if button has opacity suggesting it's disabled
        const computedStyle = window.getComputedStyle(button);
        if (computedStyle.opacity < 0.5) return true;
        
        // Check if button has pointer-events: none
        if (computedStyle.pointerEvents === 'none') return true;
        
        // Check parent elements for disabled state
        let parent = button.parentElement;
        while (parent && parent !== document.body) {
            if (parent.classList && parent.classList.contains('disabled')) return true;
            parent = parent.parentElement;
        }
        
        return false;
    }
    
    // Function to check if any video is playing
    function isVideoPlaying() {
        const videos = document.querySelectorAll('video');
        for (const video of videos) {
            if (video && !video.paused && video.currentTime > 0) {
                return true;
            }
        }
        return false;
    }
    
    // Function to auto-play video
    function autoPlayVideo() {
        if (videoPlayed || isVideoPlaying()) {
            if (!videoPlayed && isVideoPlaying()) {
                console.log("Video is already playing");
                videoPlayed = true;
            }
            return;
        }
        
        // Try to find and play video directly
        const videoElements = document.querySelectorAll('video');
        for (const video of videoElements) {
            if (video && video.paused && video.readyState >= 2) {
                console.log("Found video element - attempting to play directly");
                video.play().then(() => {
                    console.log("Video started playing successfully");
                    videoPlayed = true;
                }).catch(err => {
                    console.log("Direct video play failed:", err.message);
                    // Don't set videoPlayed = true here, let other methods try
                });
                // Give direct play a chance before trying other methods
                return;
            }
        }
        
        // Wait a bit before trying click methods to allow direct play attempt to complete
        setTimeout(() => {
            if (isVideoPlaying()) {
                videoPlayed = true;
                return;
            }
            
            // Try clicking the video poster (most reliable based on user feedback)
            const videoPoster = document.querySelector('.vjs-poster');
            if (videoPoster) {
                console.log("Video poster found - clicking to trigger playback");
                videoPoster.click();
                
                // Check if video started after a short delay
                setTimeout(() => {
                    if (isVideoPlaying()) {
                        console.log("Video started after poster click");
                        videoPlayed = true;
                    }
                }, 500);
                return;
            }
            
            // Try clicking the video container div (since clicking anywhere works)
            const videoContainer = document.querySelector('[data-vjs-player="true"]') || 
                                  document.querySelector('.video-js');
            if (videoContainer) {
                console.log("Video container found - clicking to trigger playback");
                
                // Try to simulate user interaction more thoroughly
                videoContainer.focus();
                
                // Create and dispatch a click event
                const clickEvent = new MouseEvent('click', {
                    view: window,
                    bubbles: true,
                    cancelable: true,
                    buttons: 1
                });
                videoContainer.dispatchEvent(clickEvent);
                
                // Also try direct click
                videoContainer.click();
                
                // Check if video started after a short delay
                setTimeout(() => {
                    if (isVideoPlaying()) {
                        console.log("Video started after container click");
                        videoPlayed = true;
                    }
                }, 500);
                return;
            }
            
            // Try clicking the custom play button
            const customPlayButton = document.querySelector('[data-test="playButton"]');
            if (customPlayButton && !isButtonDisabled(customPlayButton)) {
                console.log("Custom Play button found - clicking!");
                customPlayButton.click();
                setTimeout(() => {
                    if (isVideoPlaying()) {
                        console.log("Video started after play button click");
                        videoPlayed = true;
                    }
                }, 500);
                return;
            }
            
            // Try clicking the Video.js play button
            const vjsPlayButton = document.querySelector('.vjs-big-play-button');
            if (vjsPlayButton && !isButtonDisabled(vjsPlayButton)) {
                console.log("Video.js Play button found - clicking!");
                vjsPlayButton.click();
                setTimeout(() => {
                    if (isVideoPlaying()) {
                        console.log("Video started after Video.js button click");
                        videoPlayed = true;
                    }
                }, 500);
                return;
            }
            
            // Try the original play button selector
            const playButton = document.querySelector('[title="Play Video"]');
            if (playButton && !isButtonDisabled(playButton)) {
                console.log("Play Video button found - clicking!");
                playButton.click();
                setTimeout(() => {
                    if (isVideoPlaying()) {
                        console.log("Video started after play button click");
                        videoPlayed = true;
                    }
                }, 500);
                return;
            }
        }, 300);
    }
    
    // Function to check if we're on a video page
    function isVideoPage() {
        return document.querySelector('.gritCourseflowNode--video') !== null ||
               document.querySelector('video') !== null ||
               document.querySelector('.video-js') !== null;
    }
    
    // Function to reset state when page changes
    function checkPageChange() {
        if (window.location.href !== lastUrl) {
            console.log("Page changed - resetting state");
            videoPlayed = false;
            continueLearningButtonClicked = false;
            lastButtonState = null;
            lastUrl = window.location.href;
        }
    }
    
    // Main function to handle button clicks
    function clickButtons() {
        // Check if page changed
        checkPageChange();
        
        console.log("Checking for buttons and videos...");
        
        // Check for continue learning button first
        if (!continueLearningButtonClicked) {
            const continueButton = document.querySelector('[data-test="continueLearningButton"]');
            if (continueButton && !isButtonDisabled(continueButton)) {
                console.log("Continue Learning button found and enabled - clicking!");
                continueButton.click();
                continueLearningButtonClicked = true;
            }
        }
        
        // Check if we're on a video page and auto-play if needed
        if (isVideoPage()) {
            autoPlayVideo();
        }
        
        // Check for navigation arrow button
        const arrowButton = document.querySelector('#arrow-next') || 
                          document.querySelector('[data-test="courseflow-forward"]') ||
                          document.querySelector('button[id*="arrow"]') ||
                          document.querySelector('button[class*="arrow"]');
        
        if (arrowButton) {
            const isDisabled = isButtonDisabled(arrowButton);
            
            // Log state change
            if (lastButtonState !== isDisabled) {
                console.log(`Navigation button state changed: ${isDisabled ? 'DISABLED' : 'ENABLED'}`);
                lastButtonState = isDisabled;
            }
            
            if (!isDisabled) {
                console.log("Navigation button is ENABLED - clicking!");
                arrowButton.click();
                // Reset flags after navigation
                videoPlayed = false;
                continueLearningButtonClicked = false;
                console.log("Button clicked! Flags reset.");
            } else {
                console.log("Navigation button is disabled - waiting...");
            }
        } else {
            console.log("No navigation button found on page");
        }
    }
    
    // Add mutation observer to detect when video elements are added to the page
    const observer = new MutationObserver((mutations) => {
        for (const mutation of mutations) {
            if (mutation.type === 'childList') {
                // Check if video elements were added
                const addedVideos = Array.from(mutation.addedNodes).some(node => 
                    node.nodeName === 'VIDEO' || 
                    (node.querySelector && node.querySelector('video'))
                );
                
                if (addedVideos && !videoPlayed) {
                    console.log("New video element detected");
                    setTimeout(autoPlayVideo, 1000); // Give it more time to fully load
                }
            }
        }
    });
    
    // Start observing the document for changes
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
    
    // Run immediately on load with a longer delay
    setTimeout(clickButtons, 2000);
    
    // Then run every 2 seconds (faster than original but not too aggressive)
    setInterval(clickButtons, 2000);
    
    console.log("Script initialized - checking buttons and videos every 2 seconds");
})();