Focus always and replay if video is paused

To learn more faster and efficiently

// ==UserScript==
// @name         Focus always and replay if video is paused
// @name:zh-TW   始終保持焦點並在視頻暫停時自動播放
// @namespace    http://tampermonkey.net/
// @version      0.4.5
// @description  To learn more faster and efficiently
// @description:zh-tw   此腳本旨在提高在線學習效率,透過自動保持視頻播放視窗的焦點並在視頻暫停時自動重播。適用於 `https://iedu.foxconn.com/*` 網站,能夠確保學習過程中視頻連續播放,無需手動干預,特別適合忙碌且希望提高學習效率的用戶。
// @author       pjiaquan
// @match        https://iedu.foxconn.com/public/user/*
// @match        https://iedu.foxconn.com/public/play/*
// @run-at       document-start
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        GM.xmlHttpRequest
// @connect      us-central1-exam-fc1f9.cloudfunctions.net
// @connect      127.0.0.1
// @license      MIT
// ==/UserScript==
(function() {
    'use strict';

    window.onblur = null;
    window.blurred = false;
    let projectName = "";
    let playingVideoTitle = "";
    let isClicked = false;

    document.hasFocus = () => true;
    window.onFocus = () => true;

    [
        "hidden",
        "mozHidden",
        "msHidden",
        "webkitHidden"
    ].forEach(prop_name => {
        Object.defineProperty(document, prop_name, {value: false});
    });

    Object.defineProperty(document, "visibilityState", {get: () => "visible"});
    Object.defineProperty(document, "webkitVisibilityState", {get: () => "visible"});

    document.onvisibilitychange = undefined;

    var event_handler = (event) => {
        if (["blur", "mouseleave", "mouseout"].includes(event.type) &&
            (event.target instanceof HTMLInputElement ||
             event.target instanceof HTMLAnchorElement ||
             event.target instanceof HTMLSpanElement)) {
            return; // exclude input, anchor, and span elements
        }
        event.preventDefault();
        event.stopPropagation();
        event.stopImmediatePropagation();
    };

    [
        "visibilitychange",
        "webkitvisibilitychange",
        "blur",
        "hasFocus",
        "mouseleave",
        "mouseout",
        "mozvisibilitychange",
        "msvisibilitychange"
    ].forEach(event_name => {
        window.addEventListener(event_name, event_handler, true);
        document.addEventListener(event_name, event_handler, true);
    });

    let videoData = {
        filename: null,
        waresMap: new Map()
    };

    // script1 functionality
    function updateVideoProgress() {
        // if(sn) {
        //     console.log(sn);
        // }

        if (!isVideoPlaying()) {
            console.log('Video is not playing!');
            startPlayingVideo();
        } else {

            // console.log(wares);

            var videoElement = document.getElementById('realvideo_html5_api');
            if (videoElement && videoElement.tagName === 'VIDEO') {
                const activeElement = document.querySelector('dl .active');

                // Check if the active element exists and log its title attribute or inner text
                if (activeElement) {
                    // console.log('Active element found:', activeElement);
                    // console.log('Title:', activeElement.getAttribute('title'));
                    playingVideoTitle = activeElement.getAttribute('title');
                    // console.log('Content:', activeElement.innerText);

                    //console.log('title: ', playingVideoTitle);
                } else {
                    console.log('No active element found');
                }

                // videoElement.muted();
                // console.log('#301: video is playing', videoElement);
                if(videoElement.src.indexOf("hdvideo") >= 0){
                    //console.log("您正在播放的是高清版本的");

                    var currentSrc = videoElement.src;

                    if(currentSrc.indexOf() >= 0) {
                        console.log('you are hd mode');

                        var newSrc = currentSrc.replace('hdvideo', 'sdvideo');

                        videoElement.src = newSrc;

                        videoElement.muted = true;
                        // Load the new video source and mute it
                        videoElement.load();
                    }

                }

                if (wares && wares.length > 0) {
                    //console.log(window.wares);
                    var i = 0;
                    for(i = 0; i < wares.length; i++) {
                        if(wares[i].isComplete === "N") {

                            let v = wares[i];
                            let duration = v.duration;
                            let playtime = v.playtime;
                            let percentage = (playtime / duration) * 100;

                            console.log(`${wares[i].name} 沒完成, 剩下: ${percentage.toFixed(2)}% ${new Date().toLocaleString()} #1`);

                            // Usage example
                            const progress_data = {
                                userId: userId,
                                userName: userName,
                                // examName: window.wares[i].name,
                                progress: percentage.toFixed(2),
                                examName: projectName + ': ' + playingVideoTitle || 'Sample Exam Title' // Replace with actual data
                            };

                            sendDataToServer(progress_data);

                            // Find the element by its title attribute
                            // var myElement = document.querySelector('dd[title="六西格玛项目定义"]');
                            var myElement = document.querySelector(`dd[title="${wares[i].name}"]`);

                            if (myElement) {

                                console.log('found element 1');

                                if(playingVideoTitle !== wares[i].name) {
                                    console.log('found element 1 cliked');
                                    //myElement.click();
                                }
                                break; // Exit the loop after the first click
                            } else {
                                console.log('Element not found');
                            }
                        } else if(wares[i].isComplete === undefined) {
                            let v = wares[i];
                            let duration = v.duration;
                            let playtime = v.playtime;
                            let percentage = (playtime / duration) * 100;

                            console.log(`${wares[i].name} 沒完成, 剩下: ${percentage.toFixed(2)}% ${new Date().toLocaleString()} #2`);

                            // Usage example
                            const progress_data2 = {
                                userId: userId,
                                userName: userName,
                                // examName: window.wares[i].name,
                                progress: percentage.toFixed(2),
                                examName: projectName + ': ' + playingVideoTitle || 'Sample Exam Title' // Replace with actual data
                            };

                            sendDataToServer(progress_data2);

                            var myElement2 = document.querySelector(`dd[title="${wares[i].name}"]`);

                            if (myElement2) {
                                // Trigger the click event on the element
                                console.log('found element 2');
                                if(playingVideoTitle !== wares[i].name) {
                                    console.log('found element 2 cliked');
                                    //myElement2.click();
                                }
                                break; // Exit the loop after the first click
                            } else {
                                console.log('Element not found');
                            }

                            //                             if (videoElement.readyState >= 1) { // Check if metadata is loaded
                            //                                 var duration = videoElement.duration;
                            //                                 var targetTime = duration * 0.95; // Calculate 95% of the total duration

                            //                                 console.log('Setting currentTime to: ', targetTime);
                            //                                 videoElement.currentTime = targetTime; // Set the video progress to 95%
                            //                                 videoElement.play()
                            //                                     .then(() => console.log("Video playback started at 95%"))
                            //                                     .catch((error) => console.error("Error attempting to play video:", error));
                            //                             } else {
                            //                                 // Wait for metadata to be loaded before setting currentTime
                            //                                 videoElement.addEventListener('loadedmetadata', function() {
                            //                                     var duration = videoElement.duration;
                            //                                     var targetTime = duration * 0.95; // Calculate 95% of the total duration

                            //                                     console.log('Setting currentTime to: ', targetTime);
                            //                                     videoElement.currentTime = targetTime; // Set the video progress to 95%
                            //                                     videoElement.play()
                            //                                         .then(() => console.log("Video playback started at 95%"))
                            //                                         .catch((error) => console.error("Error attempting to play video:", error));
                            //                                 });
                            //                             }
                        } else {

                            //                             try {
                            //                                 let v = window.wares[i];
                            //                                 let duration = v.duration;
                            //                                 let playtime = v.playtime;
                            //                                 let percentage = (playtime / duration) * 100;

                            //                                 console.log(`${window.wares[i].name} 已經完成, 剩下: ${percentage.toFixed(2)}%`);

                            //                                 // URL of the Cloud Function endpoint
                            //                                 const url = 'https://us-central1-exam-fc1f9.cloudfunctions.net/saveProgress';

                            //                                 // Data to be sent
                            //                                 const data = {
                            //                                     // userId: userId,
                            //                                     examName: window.wares[i].name,
                            //                                     progress: percentage.toFixed(2),
                            //                                     drink: 'mojito'
                            //                                 };

                            //                                 // Using GM.xmlHttpRequest to send a POST request with the data
                            //                                 GM.xmlHttpRequest({
                            //                                     method: 'POST',
                            //                                     url: url,
                            //                                     headers: {
                            //                                         'Content-Type': 'application/json'
                            //                                     },
                            //                                     data: JSON.stringify(data),
                            //                                     onload: function(response) {
                            //                                         // Parse the JSON response
                            //                                         const result = JSON.parse(response.responseText);
                            //                                         console.log('Success:', result);
                            //                                     },
                            //                                     onerror: function(error) {
                            //                                         console.error('Error:', error);
                            //                                     }
                            //                                 });
                            //                             }catch (error) {
                            //                                 console.log(error);
                            //                             }

                        }
                    }
                }
            }

        }
    }

    function setupVideoCheck() {
        const activeElement = document.querySelector('.breadcrumb .active');
        projectName = activeElement.textContent;

        //console.log('Page loaded, running script');
        setInterval(updateVideoProgress, 5000);

        // Function to observe DOM changes and click the "确定" button
        function observeDOMChanges() {
            const targetNode = document.body;
            const config = { childList: true, subtree: true };

            const callback = function(mutationsList, observer) {
                for (let mutation of mutationsList) {
                    if (mutation.type === 'childList') {
                        const confirmButton = document.querySelector('.layui-layer-btn0');
                        if (confirmButton) {
                            confirmButton.click();
                            console.log('Clicked "确定" button');
                            observer.disconnect(); // Stop observing after the button is clicked
                            break;
                        }
                    }
                }
            };

            const observer = new MutationObserver(callback);
            observer.observe(targetNode, config);
        }

        // Start observing for DOM changes
        observeDOMChanges();
    }



    function isVideoPlaying() {
        var videoElement = document.getElementById('realvideo_html5_api');
        if (videoElement && videoElement.tagName === 'VIDEO') {
            // console.log(videoElement);

            if(videoElement.src.indexOf("hdvideo") >= 0){
                //console.log("您正在播放的是高清版本的");

                var currentSrc = videoElement.src;

                var newSrc = currentSrc.replace('hdvideo', 'sdvideo');

                videoElement.muted = true;

                videoElement.src = newSrc;

                // Load the new video source and mute it
                //videoElement.load();
            }

            // Extract the src attribute
            var videoSrc = videoElement.getAttribute("src");

            // Extract the filename from the src URL
            var videoFilename = videoSrc.split('/').pop().split('.')[0];

            // Save the filename to the videoData object
            videoData.filename = videoFilename;

            // Map the videoFilename with wares if needed
            if (wares && wares.length > 0) {

                wares.forEach((ware, index) => {
                    videoData.waresMap.set(videoFilename, ware); // Example mapping
                });
            }

            // Output the filename or save it as needed
            if (videoData && videoData.waresMap) {
                const firstEntry = videoData.waresMap.entries().next().value;
                if (firstEntry) {
                    const [firstKey, firstValue] = firstEntry;

                    if(firstValue.isComplete === "Y") {
                        return true;

                    }
                } else {
                    console.log('Map is empty');


                }
            }

            return !videoElement.paused;
        } else {
            console.log('Video element not found or is not a video tag');
            return null;
        }
    }


    function startPlayingVideo() {
        var videoElement = document.getElementById('realvideo_html5_api');
        if (videoElement && videoElement.tagName === 'VIDEO') {
            videoElement.muted = true;
            videoElement.play()
                .then(() => console.log("Video playback started"))
                .catch((error) => console.error("Error attempting to play video:", error));

        } else {
            console.log('Video element not found or is not a video tag');
        }
    }

    // Define the function to send data using GM.xmlHttpRequest
    function sendDataToServer(data) {
        const url = 'https://us-central1-exam-fc1f9.cloudfunctions.net/saveProgress';
        const testUrl = 'http://127.0.0.1:5001/exam-fc1f9/us-central1/saveProgress';

        GM.xmlHttpRequest({
            method: 'POST',
            url: url,
            headers: {
                'Content-Type': 'application/json'
            },
            data: JSON.stringify(data), // JSON stringify the payload
            onload: function(response) {
                try {
                    // Parse the JSON response
                    const result = JSON.parse(response.responseText);
                    //console.log('Success:', result);
                } catch (e) {
                    console.error('Error parsing response:', e);
                }
            },
            onerror: function(error) {
                console.error('Request failed:', error);
            },
            ontimeout: function() {
                console.error('Request timed out');
            }
        });

        // GM.xmlHttpRequest({
        //     method: 'POST',
        //     url: testUrl,
        //     headers: {
        //         'Content-Type': 'application/json'
        //     },
        //     data: JSON.stringify(data), // JSON stringify the payload
        //     onload: function(response) {
        //         try {
        //             // Parse the JSON response
        //             const result = JSON.parse(response.responseText);
        //             //console.log('Success:', result);
        //         } catch (e) {
        //             console.error('Error parsing response:', e);
        //         }
        //     },
        //     onerror: function(error) {
        //         console.error('Request failed:', error);
        //     },
        //     ontimeout: function() {
        //         console.error('Request timed out');
        //     }
        // });
    }


    window.addEventListener('load', setupVideoCheck);

})();