- // ==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);
-
- })();
-
-