Last active
January 21, 2024 21:30
-
-
Save vogler/51d82f4887d75f718dddbcf45e8feb2f to your computer and use it in GitHub Desktop.
Tampermonkey: Video: show time left in title
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Video: show time left in title | |
// @namespace https://gist.github.com/vogler | |
// @downloadURL https://gist.github.com/vogler/51d82f4887d75f718dddbcf45e8feb2f/raw/video-time-left.tamper.js | |
// @version 0.1 | |
// @description Video: show time left in title | |
// @author Ralf Vogler | |
// @match https://*.zdf.de/* | |
// @grant window.onurlchange | |
// ==/UserScript== | |
// match all *://*/* | |
// options | |
const opt = { | |
onLoad: true, // false: only update title after video starts playing | |
position: 'start', // add to 'start' | 'end' of document.title | |
withRate: true, // true: divide time left by playback speed, false: ignore playback speed | |
} | |
const formatDuration = seconds => new Date(1000 * seconds).toISOString().substr(11, 8).replace(/^[0:]+/, ""); | |
const parseDuration = str => str.split(':').toReversed().reduce((a,x,i) => a + parseInt(x) * 60**i, 0); // to seconds | |
(async function() { | |
'use strict'; | |
// console.log('title onload:', document.title); | |
let originalTitle = document.title; | |
// update time left in title | |
const f = el => { | |
if (!el.getElementsByTagName) return; // Angular adds some weird #comment and #text elements which don't have this function... | |
const vs = el.tagName == 'VIDEO' ? [el] : [...el.getElementsByTagName('video')]; // find videos in element | |
if (vs.length < 1) return; | |
// console.log('video-time-left: found', vs.length, 'video(s)', vs, 'in', el); | |
vs.forEach(v => { | |
if (v.handled) return; | |
v.handled = true; | |
const update = e => { | |
let timeLeft = v.duration - v.currentTime; | |
// console.log('video-time-left:', 'duration:', v.duration, 'playbackRate:', v.playbackRate, 'timeLeft:', timeLeft, v); | |
if (!v.duration) return; | |
if (opt.withRate) timeLeft /= v.playbackRate; | |
timeLeft = formatDuration(timeLeft); | |
const sep = timeLeft ? ' - ' : ''; | |
if (opt.position == 'start') { | |
originalTitle = document.title.replace(/^(\d{1,2}:)*\d{1,2} - /, ''); // strip timeLeft: simpler and more reliable alternative to urlchange listener + MutationObserver on title | |
document.title = timeLeft + sep + originalTitle; | |
} else { | |
originalTitle = document.title.replace(/ - (\d{1,2}:)*\d{1,2}$/, ''); // same as above, but at the end | |
document.title = originalTitle + sep + timeLeft; | |
} | |
}; | |
if (opt.onLoad) update(); | |
v.addEventListener('timeupdate', update, { passive: true }); | |
}); | |
}; | |
f(document.body); // handle all videos | |
// setTimeout(() => f(document.body), 3000); // if our event listener gets removed, we add it again after 3s | |
// we also want to react to dynamically added videos, i.e., call f on any nodes added to document.body | |
(new MutationObserver((ms, ob) => ms.forEach(m => m.addedNodes.forEach(f)))).observe(document.body, { subtree: true , childList: true }); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment