Last active
August 12, 2023 18:44
-
-
Save HT-7/2d28c6274c475d623c5556369435ea63 to your computer and use it in GitHub Desktop.
Web media timer
This file contains hidden or 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
// TimerUI – for home cinemas | |
// == Dependencies == | |
var mediaType; // for compatibility | |
var playerExists = false; // is set to true below if player exists | |
var checkMediaType_enabled = true; // for debugging purposes | |
var media_element = {}; // declaring as object | |
var tmp="",count=0; // initiating temporary variables used inside functions and loops | |
function checkMediaType() { | |
// checks whether it is a video or an audio tag | |
if ( checkMediaType_enabled ) { | |
var mediaTypeBeforeCheck = mediaType; | |
if (document.getElementsByTagName("video")[0]) { | |
playerExists = true; mediaType = "video"; | |
} | |
if (document.getElementsByTagName("audio")[0]) { | |
playerExists = true; mediaType = "audio"; | |
} | |
var mediaTypeAfterCheck = mediaType; | |
if (mediaTypeBeforeCheck != mediaTypeAfterCheck) | |
// Only show media type in console if it has changed. | |
console.log("Detected media type: " + mediaType); | |
media_element = document.getElementsByTagName(mediaType)[0]; | |
// Set back to false if no player is found after using customMediaElement. | |
media_element ? playerExists=true : playerExists=false; | |
} | |
} | |
function customMediaElement(custom_media_element) { | |
checkMediaType_enabled = false; | |
if (custom_media_element) { | |
playerExists = true; | |
media_element = custom_media_element; | |
console.log("customMediaElement: Custom media element set. Reset using checkMediaType_enabled=true."); | |
} else { console.error("customMediaElement: No such media element found."); } | |
} | |
var customTitleElement; | |
function checkFileExtension(ext) { | |
if (typeof(ext) == "string") { | |
ext = ext.toLowerCase(); // case-insensitive | |
// string | |
if (document.location.href.search(new RegExp(ext+"$", "i")) > -1) return true; else return false; | |
} else if (typeof(ext) == "object") { | |
// array – check against multiple strings | |
for (var count=0; count < ext.length; count++) { | |
if (document.location.href.search(new RegExp(ext[count]+"$", "i")) > -1) return true; | |
if (count == ext.length-1) return false; // if no matches after going through them all | |
} | |
} | |
} | |
function isDomain(domain) { | |
// Using .search() instead of .includes() to improve browser compatibility. | |
if (window.location.hostname.search(domain) >= 0) return true; else return false; | |
} | |
// symbols | |
var symbol_play = "▶︎ "; // thin space for alignment | |
var symbol_pause="❚ ❚"; // instead of "⏸" due to Edge browser putting an immutable blue box around it. | |
// mousedown status | |
var mousedown_status; | |
window.addEventListener("mousedown", function(){mousedown_status=true; } ); | |
window.addEventListener("mouseup", function(){mousedown_status=false; } ); | |
function appendChildWithID(tagName,tagID,parent_element) { | |
// default parent element to document.body if unspecified | |
if (parent_element === undefined) parent_element = document.body; | |
parent_element.appendChild(document.createElement(tagName)); // add div | |
parent_element.lastElementChild.id=tagID; // give it ID | |
} | |
function addStyle(new_style,parent_element) { | |
if (parent_element === undefined) parent_element = document.body; | |
parent_element.appendChild(document.createElement("style")); // add style | |
parent_element.lastElementChild.innerHTML = new_style; | |
} | |
// time variables | |
var media_time = {}; | |
// HH:MM:SS timer | |
function HMStimer_core(seconds) { | |
// hours | |
media_time.HH = Math.floor( seconds/3600 ); | |
// leading zero | |
if ( seconds < 36000 ) media_time.HH = "0" + media_time.HH; | |
// minutes | |
media_time.MM = Math.floor( seconds/60%60 ); | |
// leading zero | |
if ( seconds%3600 < 600 ) media_time.MM = "0" + media_time.MM; | |
// seconds | |
media_time.SS = Math.floor( seconds%60 ); | |
// leading zero | |
if ( seconds%60 < 10 ) media_time.SS = "0" + media_time.SS; | |
return media_time.HH+":"+media_time.MM+":"+media_time.SS; | |
} | |
function HMStimer(seconds) { | |
if (seconds >= 0) return HMStimer_core(seconds); // zero or positive | |
if (seconds < 0) // negative | |
{ | |
seconds = seconds * (-1); | |
return "-"+HMStimer_core(seconds); | |
} | |
if (seconds == undefined || isNaN(seconds) ) return "– –:– –:– –"; | |
} | |
// MM:SS timer | |
function MStimer_core(seconds) { | |
// minutes | |
media_time.MM = Math.floor( seconds/60 ); | |
// leading zero | |
if ( seconds%3600 < 600 ) media_time.MM = "0" + media_time.MM; | |
// seconds | |
media_time.SS = Math.floor( seconds%60 ); | |
// leading zero | |
if ( seconds%60 < 10 ) media_time.SS = "0" + media_time.SS; | |
return media_time.MM+":"+media_time.SS; | |
} | |
function MStimer(seconds) { | |
if (seconds >= 0) return MStimer_core(seconds); // zero or positive | |
if (seconds < 0) // negative | |
{ | |
seconds = seconds * (-1); | |
return "-"+MStimer_core(seconds); | |
} | |
if (seconds == undefined || isNaN(seconds) ) return "– –:– –"; | |
} | |
// implements togglePlay(); – deprecated due to compatibility issues on YouTube (broken site) and Dailymotion ("not a function" error through iframe'd player). | |
/* | |
Object.prototype.togglePlay = function togglePlay() { | |
return this.paused ? this.play() : this.pause(); | |
}; | |
*/ | |
// new function without object prototype for compatibility | |
function togglePlay(media_element) { | |
if (media_element) { // validate media element first to avoid errors | |
media_element.paused ? media_element.play() : media_element.pause(); | |
} | |
} | |
// media file extension list | |
var mediafileext = { | |
"video":[".mp4", ".mpg", ".mpeg", ".mts", ".mt2s", ".m4v", ".ts", ".ogv", ".wmv", ".3gp", ".3gpp", ".webm"], | |
"audio":[".mp3", ".wma", ".wav", ".ogg", ".opus", ".flac", ".oga", ".wma", ".aac", ".amr", ".alac", ".m4a"] | |
}; | |
// == Main code == | |
if (! timerUI) var timerUI = new Object({}); // create parent object if none exists | |
// default system variables | |
timerUI.debug_mode = false; | |
timerUI.override_check = false; | |
timerUI.on = true; | |
timerUI.buffer_on = true; | |
timerUI.multiBuffer = true; // multiple buffer segments | |
timerUI.div = {}; // unset yet, declaring to prevent reference errors | |
timerUI.interval = {}; | |
timerUI.show_remaining = 0; // 0: show elapsed time. 1: show remaining time. 2: show elapsed and total. | |
timerUI.update_during_seek = true; // update timer while dragging seek bar | |
timerUI.color = "rgb(49,136,255)"; // #38F – using RGB for compatibility. | |
timerUI.gradient = "rgba(0,0,0,0.9)"; // using RGBA instead of hexadecimal for compatibility. | |
timerUI.font_pack = "din, futura, 'noto sans', 'open sans', ubuntu, 'segoe ui', verdana, tahoma, roboto, 'roboto light', arial, helvetica, 'trebuchet ms' ,'bitstream vera sans', sans-serif, consolas, monospace"; | |
timerUI.width_breakpoint = 768; // pixels | |
// console notifications and warnings (possibly to be expanded) | |
timerUI.msg = { | |
"notimer": "timerUI: No timer found; checking for media element again. Please try again.", | |
"nomedia": "timerUI: no media element found on page. Stopping." | |
}; | |
// text containers (no const for compatibility) | |
var timer_linefeed = "<span class=timer_linefeed><br /></span>"; | |
var timer_slash = " <span class=timer_slash>/</span> "; | |
// functions | |
timerUI.toggle = {}; | |
timerUI.toggle.main = function() { | |
// show and hide | |
if (timerUI.div) { | |
timerUI.update(); | |
if (timerUI.on) { | |
timerUI.div.style.display = "none"; | |
console.log("timerUI off"); | |
} | |
if (! timerUI.on ) { | |
timerUI.div.style.display = "block"; | |
console.log("timerUI on"); | |
} | |
timerUI.on ? timerUI.on = false : timerUI.on = true; | |
} else { | |
console.warn(timerUI.msg.notimer); | |
timeUI(); | |
} | |
}; | |
timerUI.toggle.buffer = function() { | |
if (timerUI.div) { | |
timerUI.update(); timerUI.updateBufferBar(true); | |
if (timerUI.buffer_on) { | |
timerUI.buffer_bar.style.display = "none"; | |
console.log("timerUI buffer bar off"); | |
} | |
if (! timerUI.buffer_on ) { | |
timerUI.buffer_bar.style.display = "block"; | |
console.log("timerUI buffer bar on"); | |
} | |
timerUI.buffer_on ? timerUI.buffer_on = false : timerUI.buffer_on = true; | |
} else { | |
console.warn(timerUI.msg.notimer); | |
timeUI(); | |
} | |
}; | |
timerUI.toggle.title = function() { | |
if (timerUI.div) { | |
timerUI.update(); timerUI.updateBufferBar(true); | |
if (timerUI.title_on) { | |
timerUI.title.style.display = "none"; | |
console.log("timerUI title off"); | |
} | |
if (! timerUI.title_on ) { | |
timerUI.title.style.display = "block"; | |
console.log("timerUI title on"); | |
} | |
timerUI.title_on ? timerUI.title_on = false : timerUI.title_on = true; | |
} else { | |
console.warn(timerUI.msg.notimer); | |
timeUI(); | |
} | |
}; | |
timerUI.getTitle = function() { | |
if (! timerUI.domainRules_checked) /* only check domain rules once */ { | |
timerUI.domainRules(); | |
timerUI.domainRules_checked = true; | |
} | |
if (customTitleElement) timerUI.newTitle = customTitleElement.innerHTML; | |
else { // skipping this whole part if no custom title is specified | |
timerUI.newTitle = document.title; | |
timerUI.titleDomainRules(); | |
} | |
if (media_element) { | |
timerUI.updateFileIcon(); | |
return timerUI.file_icon+" "+timerUI.newTitle; | |
} else { | |
return "TimerUI – designed for home cinemas"; | |
} | |
}; | |
timerUI.guessMediaType = function() { | |
if (isDomain("youtube.com") || isDomain("dailymotion.com") ) return "video"; | |
if (document.location.pathname.search(/^\/video\//) > -1) return "video"; | |
if (! media_element.videoWidth) return "audio"; // Detects files that only contain audio, even if they have a video file extension. | |
if (checkFileExtension(mediafileext.video) ) return "video"; | |
if (checkFileExtension(mediafileext.audio) ) return "audio"; | |
return "unknown"; // if nothing detected | |
}; | |
timerUI.updateFileIcon = function() { | |
timerUI.file_icon = timerUI.guessMediaType(); | |
switch(timerUI.file_icon) { | |
case "video": timerUI.file_icon = "🎞️"; break; | |
case "audio": timerUI.file_icon = "♫"; break; | |
case "unknown": timerUI.file_icon = "📄"; break; | |
} | |
}; | |
timerUI.adaptTitleWidth = function() { | |
if (media_element.duration > 3600 && timerUI.show_remaining == 2 && window.innerWidth > timerUI.width_breakpoint) | |
timerUI.title.style.maxWidth = "calc(100% - 670px)"; | |
else | |
timerUI.title.style.maxWidth = "calc(100% - 400px)"; | |
}; | |
window.addEventListener('resize', function() { | |
if (window.innerWidth < timerUI.width_breakpoint) timerUI.title.removeAttribute("style"); | |
} ); | |
timerUI.update = function() { | |
if (media_element) { | |
timerUI.bar.style.width=media_element.currentTime / media_element.duration * 100 + "%"; | |
// buffer bar update formerly located here; removed from the scope of this function | |
switch(timerUI.show_remaining) { | |
// 0: "HH:MM:SS" 1: "-HH:MM:SS" 2: "MM:SS / MM:SS" or "HH:MM:SS / HH:MM:SS" | |
case 0: timerUI.time.innerHTML=HMStimer(media_element.currentTime); break; | |
case 1: timerUI.time.innerHTML=HMStimer(media_element.currentTime-media_element.duration); break; | |
case 2: | |
if (media_element.duration < 3600 || isNaN(media_element.duration) ) { | |
// show hours if duration exceeds one hour | |
timerUI.time.innerHTML= | |
MStimer(media_element.currentTime) | |
+ timer_linefeed | |
+ timer_slash | |
+ MStimer(media_element.duration); | |
} else { | |
timerUI.time.innerHTML= | |
HMStimer(media_element.currentTime) | |
+ timer_linefeed | |
+ timer_slash | |
+ HMStimer(media_element.duration); | |
} | |
break; | |
} | |
media_element.paused == false ? | |
timerUI.status.innerHTML=symbol_play | |
: timerUI.status.innerHTML=symbol_pause; | |
} else { timerUI.stop(); console.warn(timerUI.msg.nomedia); } | |
}; | |
timerUI.updateTitle = function() { if (timerUI.title) timerUI.title.innerHTML = timerUI.getTitle(); }; | |
// update title on URL change | |
addEventListener('popstate', timerUI.updateTitle); | |
// update title fallback | |
timerUI.interval.updateTitle = setInterval(timerUI.updateTitle, 2000); | |
// buffer bar | |
timerUI.updateBufferBar = function(override_paused) { | |
if (media_element && timerUI.buffer_on && (!media_element.paused || override_paused) ) { | |
timerUI.multiBuffer ? timerUI.update_multi_buffer() : timerUI.single_segment_buffer(); | |
} | |
}; | |
// single-segment buffer bar | |
timerUI.single_segment_buffer = function() { | |
if (timerUI.buffer_bar.innerHTML!="") { timerUI.buffer_bar.style=""; timerUI.buffer_bar.innerHTML=""; } // reset after switching from multi-segment buffer bar | |
// find out first buffer segment after current playback position | |
media_element.buffered.length > 0 ? timerUI.buffer_segment=media_element.buffered.length-1 : timerUI.buffer_segment=0; | |
// media_element.buffered.length is zero until player is initialized | |
// prevent timerUI.buffer_segment from going negative, as it would cause a DOMException error | |
if ( timerUI.buffer_segment > 0) { | |
while (media_element.buffered.end(timerUI.buffer_segment-1) > media_element.currentTime && timerUI.buffer_segment > 1 ) { | |
timerUI.update_single_buffer(); | |
timerUI.buffer_segment-- ; | |
} | |
} | |
}; | |
timerUI.update_single_buffer = function() { | |
if (media_element.buffered.length > 0) { | |
// prevent "DOMException: Index or size is negative or greater than the allowed amount" | |
timerUI.buffer_bar.style.width=media_element.buffered.end(timerUI.buffer_segment) / media_element.duration * 100 + "%"; | |
} else { timerUI.buffer_bar.style.width="0%"; } | |
}; | |
// multi-segment buffer bar – highlight all buffered parts | |
timerUI.update_multi_buffer = function() { | |
if (timerUI.buffer_bar.style.length < 1) { | |
timerUI.buffer_bar.style.width="100%"; | |
timerUI.buffer_bar.style.backgroundColor="rgba(0,0,0,0)"; | |
} | |
if (media_element.buffered.length > 0) { | |
timerUI.generate_buffer_segments(); | |
} else { timerUI.buffer_bar.style.width="0%"; } | |
}; | |
timerUI.generate_buffer_segments = function() { | |
timerUI.buffer_bar.innerHTML=""; // reset to re-generate segments | |
for (count=0; count < media_element.buffered.length; count++) { | |
timerUI.append_buffer_segment( | |
timerUI.get_buffer_range(count).start_pos, | |
timerUI.get_buffer_range(count).end_pos | |
); | |
} | |
timerUI.select_segments = timerUI.buffer_bar.getElementsByClassName("timerUI_buffer_segment"); | |
timerUI.segment_count = timerUI.select_segments.length; | |
}; | |
timerUI.append_buffer_segment = function(start_pos,end_pos) { | |
timerUI.buffer_bar.appendChild(document.createElement("div") ); | |
timerUI.buffer_bar.lastElementChild.classList.add("timerUI_buffer_segment"); | |
timerUI.buffer_bar.lastElementChild.style="left:"+start_pos+"%;width:"+(end_pos-start_pos)+"%;background-color:"+timerUI.color+";"; | |
}; | |
timerUI.get_buffer_range = function(segment_number) { | |
return { | |
start_pos: media_element.buffered.start(segment_number) / media_element.duration * 100, | |
end_pos: media_element.buffered.end(segment_number) / media_element.duration * 100 | |
}; // object with start and end percentages | |
}; | |
timerUI.set_buffer_segment = function(segment_number,start_pos,end_pos) { | |
var selection=timerUI.buffer_bar.getElementsByClassName("timerUI_buffer_segment"); | |
selection[segment_number].style.left = start_pos / media_element.duration * 100 + "%"; | |
selection[segment_number].style.width = (end_pos-start_pos) / media_element.duration * 100 + "%"; | |
}; | |
// colors | |
timerUI.setColor = function(newColor) { | |
newColor == "default" ? timerUI.color="rgb(49,136,255)" /* #38F */ : timerUI.color = newColor; | |
timerUI.bar.style.backgroundColor=timerUI.color; | |
timerUI.buffer_bar.style.backgroundColor=timerUI.color; | |
timerUI.bar.style.boxShadow="0 0 30px 0 "+timerUI.color; | |
// (deprecated due to new buffer bar) timerUI.bar_placeholder.style.backgroundColor=timerUI.color; | |
timerUI.time.style.color=timerUI.color; | |
timerUI.status.style.color=timerUI.color; | |
timerUI.title.style.color=timerUI.color; | |
}; | |
timerUI.setGradient = function(newGradient) { | |
newGradient == "default" ? timerUI.gradient="rgba(0,0,0,0.9)" : timerUI.gradient = newGradient; | |
timerUI.gradient_placeholder.style.backgroundImage="linear-gradient(to top,"+timerUI.gradient+", rgba(0,0,0,0) )"; | |
}; | |
timerUI.setFont = function(newFont) { | |
timerUI.time.style.fontFamily=newFont; | |
timerUI.title.style.fontFamily=newFont; | |
}; | |
timerUI.stop = function() { | |
timerUI.status.innerHTML="■"; | |
timerUI.bar.style.width=0; | |
timerUI.buffer_bar.style.width=0; | |
timerUI.time.innerHTML=HMStimer(undefined); | |
}; | |
// Additional checks to ensure the player is detected | |
window.onclick = function() { checkMediaType();timeUI(); }; | |
window.addEventListener("keydown", function() { checkMediaType();timeUI(); } ); | |
function timeUI() { | |
// slightly different name to prevent naming collision with timerUI object | |
checkMediaType(); | |
timerUI.domainRules(); // load domain rules | |
// add timerUI if it does not already exist | |
if ( ( ! document.getElementById("timerUI") ) && playerExists || timerUI.override_check ) { | |
// Adding elements | |
// parent element | |
appendChildWithID("div","timerUI"); | |
timerUI.div = document.getElementById("timerUI"); | |
// button styling | |
addStyle("#timerUI button { background:none; border:none; outline:none; line-height:unset; } #timerUI button:hover { filter: brightness(1.2); } #timerUI button:active { filter: brightness(0.6); }", timerUI.div); | |
// to suppress button background and border on earlier browser versions | |
timerUI.div.lastElementChild.classList.add("timerUI_buttons"); // label to improve visibility in page inspector | |
// background gradient | |
appendChildWithID("div","timerUI_bottom_gradient",timerUI.div ); | |
timerUI.gradient_placeholder = document.getElementById("timerUI_bottom_gradient"); | |
addStyle("#timerUI #timerUI_bottom_gradient { display:block; position:fixed; background-image:linear-gradient(to top,"+timerUI.gradient+", rgba(0,0,0,0) ); opacity:1; height:80pt; width:100%; bottom:0; pointer-events:none; }", timerUI.div); | |
// progress bar | |
appendChildWithID("div","timerUI_progress_bar",timerUI.div ); | |
timerUI.bar = document.getElementById("timerUI_progress_bar"); | |
addStyle("#timerUI #timerUI_progress_bar { display:block; position:fixed; background-color:"+timerUI.color+"; box-shadow: 0 0 30px 0px "+timerUI.color+"; height:8pt; width:50%; bottom:0; }", timerUI.div); | |
// buffer bar | |
appendChildWithID("div","timerUI_buffer_bar",timerUI.div ); | |
timerUI.buffer_bar = document.getElementById("timerUI_buffer_bar"); | |
addStyle("#timerUI #timerUI_buffer_bar, #timerUI .timerUI_buffer_segment { display:block; position:fixed; background-color:"+timerUI.color+"; height:8pt; width:75%; bottom:0; opacity:0.4; } #timerUI .timerUI_buffer_segment { opacity:1; }", timerUI.div); | |
// media title | |
appendChildWithID("div","timerUI_media_title",timerUI.div ); | |
timerUI.title = document.getElementById("timerUI_media_title"); | |
timerUI.title.innerHTML = timerUI.getTitle(); | |
addStyle("#timerUI #timerUI_media_title { position:fixed; text-shadow: 0 0 5px black; display:inline; display:-webkit-box; bottom:15pt; left:2pt; color:"+timerUI.color+"; font-family:"+timerUI.font_pack+"; font-size:20pt; width:60%; max-width:calc(100% - 500px); text-overflow: ellipsis; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2; vertical-align: bottom;"); | |
// timer | |
appendChildWithID("button","timerUI_media_timer",timerUI.div ); | |
timerUI.time = document.getElementById("timerUI_media_timer"); | |
timerUI.time.innerHTML="00:00:00"; | |
addStyle("#timerUI #timerUI_media_timer { display:block; color:"+timerUI.color+"; position:fixed; cursor:pointer; font-size:50pt; text-shadow: 0 0 20px black; line-height:60pt; bottom:10pt; right:30pt; text-align:right; font-weight:400; font-family:"+timerUI.font_pack+"; } #timerUI #timerUI_media_timer .timer_linefeed { display:none; }", timerUI.div); | |
// play/pause symbol | |
appendChildWithID("button","timerUI_playback_status",timerUI.div ); | |
timerUI.status = document.getElementById("timerUI_playback_status"); | |
timerUI.status.innerHTML="■"; | |
addStyle("#timerUI #timerUI_playback_status { display:block; position:fixed; cursor:pointer; color:"+timerUI.color+"; font-size:24pt; line-height:40pt; bottom:30pt; right:3pt; font-family:none; }", timerUI.div); | |
// progress bar placeholder – put last to be at the top in stacking context | |
appendChildWithID("div","timerUI_progress_placeholder",timerUI.div ); | |
timerUI.bar_placeholder = document.getElementById("timerUI_progress_placeholder"); | |
addStyle("#timerUI #timerUI_progress_placeholder { display:block; position:fixed; cursor:pointer; background-color:grey; height:8pt; width:100%; bottom:0; opacity:0.2; }", timerUI.div); | |
// responsive - at bottom to be able to override CSS properties without !important flag. | |
addStyle("@media (max-width:"+timerUI.width_breakpoint+"px) { #timerUI #timerUI_media_timer { font-size:30pt; line-height:24pt; bottom:15pt; } #timerUI #timerUI_playback_status { bottom:10pt; } } @media (max-width:500px) { #timerUI #timerUI_media_timer .timer_linefeed { display:inline; } #timerUI #timerUI_media_timer .timer_slash { display:none; } } @media (max-width:"+timerUI.width_breakpoint+"px) { #timerUI #timerUI_buffer_bar { font-size:10pt; -webkit-line-clamp: 3; max-width:60%;} } @media (max-width:480px) { #timerUI #timerUI_buffer_bar { display: none; } } ", timerUI.div); | |
timerUI.div.lastElementChild.classList.add("timerUI_responsive"); | |
// update timer during playback every fifteenth of a second and while mouse is dragging progress bar | |
timerUI.interval.update = setInterval( | |
function() { if ( | |
( media_element /* exists? */ && timerUI.update_during_seek && mousedown_status ) | |
|| ( media_element && timerUI.on && ! media_element.paused ) | |
) timerUI.update(); }, 1000/15 | |
); | |
// Longer interval for buffer bar to minimize CPU usage | |
timerUI.interval.buffer = setInterval(timerUI.updateBufferBar, 1000); | |
// play and pause toggle | |
timerUI.status.onclick = function() { togglePlay(media_element); timerUI.update(); timerUI.updateBufferBar(true); }; | |
// former code with object prototype caused compatibility issues on various sites: media_element.togglePlay(); | |
// toggle between elapsed, remaining, and elapsed/total time | |
timerUI.time.onclick = function() { | |
switch(timerUI.show_remaining) { | |
case 0: timerUI.show_remaining = 1; break; | |
case 1: timerUI.show_remaining = 2; timerUI.adaptTitleWidth(); break; | |
case 2: timerUI.show_remaining = 0; timerUI.adaptTitleWidth(); break; | |
} | |
timerUI.update(); timerUI.updateBufferBar(true); | |
}; | |
// clickable progress bar (experimental) - no "timerUI." notation because inside main function | |
timerUI.clickSeekBar = function(m){ | |
if (media_element) { | |
var clickPos = m.clientX / timerUI.bar_placeholder.offsetWidth; | |
// go to beginning if clicked in first percentile | |
if (clickPos < 0.01 ) media_element.currentTime = 0; | |
else media_element.currentTime = media_element.duration * clickPos; | |
timerUI.update(); timerUI.updateBufferBar(true); | |
} | |
}; | |
function dragSeekBar(m){ // currently unused | |
m = m || window.event; | |
var clickPos = m.pageX / timerUI.bar_placeholder.offsetWidth; | |
var dragSeekBarInterval = setInterval( function() { | |
media_element.currentTime = media_element.duration * clickPos; | |
timerUI.update(); | |
if (! mousedown_status) { clearInterval(dragSeekBarInterval); return; } | |
}, 200); | |
} | |
timerUI.bar_placeholder.addEventListener("mousedown", timerUI.clickSeekBar ); | |
// (incomplete) timerUI.bar_placeholder.addEventListener("mousemove", dragSeekBar ); | |
// (obsolete) timerUI.bar_placeholder.addEventListener("mouseup", clickSeekBar ); | |
timerUI.update(); | |
// == Patches == | |
// prevent missing out on pausing from inside a site's existing player | |
window.addEventListener("mouseup", function() { setTimeout(timerUI.update, 200); } ); | |
window.addEventListener("keyup", function() { setTimeout(timerUI.update, 200); } ); | |
// prevent detaching from player on sites with playlists such as Internet Archive | |
timerUI.interval.checkMedia = setInterval( checkMediaType,1000 ); | |
// prevent indicating "▶" after playback finished | |
timerUI.interval.checkPaused = setInterval( function() { | |
if ( media_element /* exists? */ && media_element.paused && ! timerUI.pause_checked) { | |
timerUI.update(); timerUI.pause_checked = true; | |
if (timerUI.debug_mode) console.debug("timerUI: checking paused status: "+media_element.paused); | |
} else if ( media_element && ! media_element.paused ) { timerUI.pause_checked = false; } | |
// to avoid redundant checks while paused | |
},1000 ); | |
} else { | |
// warn in console that no player exists; prevent repetition | |
if (! playerExists && ! timerUI.noMediaWarned) { | |
console.warn(timerUI.msg.nomedia); timerUI.noMediaWarned = true; | |
} | |
} | |
} | |
// == Custom domain rules == | |
timerUI.domainRules = function() { | |
if (isDomain("dailymotion.com") && document.location.pathname.search(/^\/embed\//) < 0 ) { | |
// Dailymotion watch page, excluding embed page. | |
customMediaElement( | |
document.getElementById("player-body").contentWindow.document.getElementsByTagName("video")[0] | |
); | |
customTitleElement = document.getElementById("media-title"); // for unlisted videos (Dailymotion only displays the video title in the HTML page title for public videos) | |
} | |
// media embedded on Wayback Machine | |
if ( is_WaybackEmbed() ) { | |
tmp = document.getElementsByTagName("iframe")[0]; // iframe in temporary variable to deduplicate code | |
customMediaElement( | |
tmp.contentWindow.document.getElementsByTagName("video")[0] | |
); | |
// dark background for improved video visibility | |
tmp.contentWindow.document.body.style.backgroundColor="#222"; | |
} | |
}; | |
timerUI.titleDomainRules = function() { | |
// custom domain rules for title | |
if ( isDomain("youtube.com") || isDomain("dailymotion.com") | |
|| isDomain("wikimedia.org") || isDomain("wikipedia.org") | |
|| isDomain("wikiversity.org") || isDomain("wikibooks.org") | |
|| isDomain("mediawiki.org") | |
) { | |
// negative lookahead regular expression – trim after last dash | |
// Match both normal dash "-" and ndash "–", since the German-language wikis use the latter. | |
timerUI.newTitle = decodeURI(timerUI.newTitle.substring(0,timerUI.newTitle.search(/(-|–)(?:.(?!(-|–)))+$/)-1 ) ); | |
} | |
// remove "File:" prefix on wikis | |
if ( isDomain("wiki") ) { | |
if (document.title.search(/^File:/) == 0 ) timerUI.newTitle = timerUI.newTitle.substring(5); | |
if (document.title.search(/^Datei:/) == 0 ) timerUI.newTitle = timerUI.newTitle.substring(6); | |
} | |
// Internet Archive library only, not Wayback Machine | |
if ( isDomain("archive.org") && ! isDomain("web.archive.org") ) { | |
// get media title from page title before first colon | |
timerUI.newTitle = (document.location.href+"").substring((document.location.href+" ").search(/\/(?:.(?!\/))+\/?$/)+1 ); | |
// after last slash (additional space prevents full URL from being matched) | |
if (timerUI.newTitle != "") { timerUI.newTitle += " - "; } | |
timerUI.newTitle += document.title.substring(0,document.title.search(/:(?:.(?!:))+(?:.(?!:))+/)-1 ); | |
// trim after second-last colon, -1 to remove space at end | |
timerUI.newTitle=decodeURI(timerUI.newTitle); // prevent spaces from turning into "%20". | |
} | |
if ( is_WaybackEmbed() ) { | |
// Already generated by the browser inside the iframe. How convenient. Otherwise, a regular expression that matches the part after the last slash in the URL, and a decodeURI would have to be used. | |
timerUI.newTitle = tmp.contentWindow.document.title; | |
} | |
}; | |
function is_WaybackEmbed() { | |
// checks if the current page is media embedded on the Wayback Machine, for code deduplication. | |
if ( isDomain("web.archive.org") || isDomain("wayback.archive.org") && document.title=="Wayback Machine" && document.getElementsByTagName("iframe")[0] ) { | |
// separate check for ID of iframe to avoid reference error | |
if (document.getElementsByTagName("iframe")[0].id=="playback") { | |
return true; | |
} | |
} else { | |
return false; | |
} | |
} | |
// == Master function == | |
timeUI(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment