NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Funimation and Crunchyroll Timer // @namespace http://tampermonkey.net/ // @version 0.3 // @description Displays a timer synced with the video playing. // @author akuma06 // @license MIT // @downloadURL https://openuserjs.org/install/akuma06/Funimation_Timer.user.js // @updateURL https://openuserjs.org/meta/akuma06/Funimation_Timer.meta.js // @match https://www.funimation.com/* // @match https://static.crunchyroll.com/* // @grant none // ==/UserScript== (function () { 'use strict'; const defaultConfig = { color: '#FFFFFF', // Can be a color in RGB or a word like "white" background: 'rgba(0, 0, 0, 0)', // Background defined in RGB and an opacity value: rgba(red, green, blue, opacity) with opacity ranging from 0 to 1 and colors from 0 to 255 fontSize: '40px', // Size for the displayed timer (00:00:00) top: undefined, // To position the timer relative to the top border of the player, it can't be defined if bottom is defined (in pixels) left: undefined, // To position the timer relative to the left border of the player, it can't be defined if right is defined (in pixels) bottom: '30px', // To position the timer relative to the bottom border of the player (in pixels) right: '20px', // To position the timer relative to the right border of the player (in pixels) }; function createTimer(config) { const div = document.createElement("div"); div.innerText = "00:00:00"; div.style.position = "absolute"; if (config.bottom !== undefined && config.bottom != '') { div.style.bottom = config.bottom; } else if (config.top !== undefined && config.top != '') { div.style.top = config.top; } if (config.right !== undefined && config.right != '') { div.style.right = config.right; } else if (config.left !== undefined && config.left != '') { div.style.left = config.left; } div.style.zIndex = 100004; div.style.fontSize = config.fontSize; div.style.color = config.color; div.style.background = config.background; div.style.pointerEvents = "none"; // disabling events so control bar works on players return div; } function updateTimer(timer, elapsed) { const hours = Math.floor(elapsed / 3600).toFixed(); const minutes = Math.floor((elapsed - hours * 3600) / 60); const seconds = elapsed % 60; timer.innerText = `${(hours > 9) ? hours : "0" + hours}:${(minutes > 9) ? minutes : "0" + minutes}:${(seconds > 9) ? seconds : "0" + seconds}`; } function setupTimerFunimation(player, doc) { player.ready(() => { const timer = createTimer(defaultConfig); doc.querySelector("#brightcove-player").appendChild(timer); player.on("timeupdate", (e) => { const elapsed = player.currentTime().toFixed(); updateTimer(timer, elapsed); }); }, true); } function setupTimerCrunchyroll(player, doc) { const timer = createTimer(defaultConfig); doc.querySelector("#vilosRoot").appendChild(timer); player.addEventListener("timeupdate", (e) => { const elapsed = player.currentTime.toFixed(); updateTimer(timer, elapsed); }); } if (document.querySelector("#brightcove-player") !== null) { setupTimerFunimation(window.videojs("brightcove-player"), document); } else if (document.querySelector("#player") !== null) { document.querySelector("#player").addEventListener("load", () => { setupTimerFunimation(document.querySelector("#player").contentWindow.videojs("brightcove-player"), document.querySelector("#player").contentDocument); }); } else if (document.querySelector("#player0") !== null) { setupTimerCrunchyroll(document.querySelector("#player0"), document) } })();