// ==UserScript==
// @name Focus always and replay if video is paused
// @name:zh-TW 始終保持焦點並在視頻暫停時自動播放
// @namespace http://tampermonkey.net/
// @version 0.4.1
// @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
// @license MIT
// ==/UserScript==
(function() {
'use strict';
window.onblur = null;
window.blurred = false;
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() {
console.log(window.wares);
if (!isVideoPlaying()) {
console.log('Video is not playing!');
startPlayingVideo();
} else {
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 (window.wares && window.wares.length > 0) {
//console.log(window.wares);
var i = 0;
for(i = 0; i < window.wares.length; i++) {
if(window.wares[i].isComplete === "N") {
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)}%`);
// Find the element by its title attribute
// var myElement = document.querySelector('dd[title="六西格玛项目定义"]');
var myElement = document.querySelector(`dd[title="${window.wares[i].name}"]`);
if (myElement) {
if(playingVideoTitle !== window.wares[i].name) {
myElement.click();
}
break; // Exit the loop after the first click
} else {
console.log('Element not found');
}
} else if(window.wares[i].isComplete === undefined) {
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)}%`);
var myElement2 = document.querySelector(`dd[title="${window.wares[i].name}"]`);
if (myElement2) {
// Trigger the click event on the element
console.log('found element 2');
if(playingVideoTitle !== window.wares[i].name) {
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() {
//console.log('Page loaded, running script');
setInterval(updateVideoProgress, 5000);
// Create and style the button
// const button = document.createElement('button');
// button.textContent = 'Change Start Time';
// button.style.position = 'fixed';
// button.style.right = '20px';
// button.style.bottom = '20px';
// button.style.padding = '10px 20px';
// button.style.backgroundColor = '#007bff';
// button.style.color = '#fff';
// button.style.border = 'none';
// button.style.borderRadius = '5px';
// button.style.cursor = 'pointer';
// // Add click event listener to the button
// button.addEventListener('click', changeStartTime);
// // Append the button to the body
// document.body.appendChild(button);
// 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 (window.wares && window.wares.length > 0) {
window.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');
// URL of the Cloud Function endpoint
const url = 'https://us-central1-exam-fc1f9.cloudfunctions.net/saveProgress';
// Data to be sent
const data = {
userId: userId,
userName: userName,
// examName: window.wares[i].name,
// progress: percentage.toFixed(2),
examName: playingVideoTitle,
};
// 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);
}
});
}
}
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');
}
}
window.addEventListener('load', setupVideoCheck);
})();