User:Elominius/gadget/media timer.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
![]() | This user script seems to have a documentation page at User:Elominius/gadget/media timer. |
// == 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 media_symbol = {};
media_symbol.play = "▶︎ "; // thin space for alignment
media_symbol.pause="❚ ❚"; // instead of "⏸" due to Edge browser putting an immutable blue box around it.
media_symbol.stop="■";
// 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"]
};
// "replaceAll()" polyfill for pre-2020 browsers
// based on: https://stackoverflow.com/a/1144788
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
// renamed function to prevent interference with "replaceAll()" on browsers since 2020
function replaceAll_polyfill(str, find, replacement) {
return str.replace(new RegExp(escapeRegExp(find), 'g'), replacement);
}
// == 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.default_color = "rgb(49,136,255)"; // memorize default color
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");
}
if (timerUI.on) { timerUI.on = false; return false; } else { timerUI.on = true; return false; }
} 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");
}
if (timerUI.buffer_on) {
timerUI.buffer_on = false; return false;
} else {
timerUI.buffer_on = true; return 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");
}
if (timerUI.title_on) {
timerUI.title_on = false; return false;
} else {
timerUI.title_on = true; return 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;
// replace underscores with spaces
timerUI.newTitle = replaceAll_polyfill(timerUI.newTitle, "_"," ");
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 (media_element.videoWidth > 0) return "video";
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;
}
if (media_element.paused) {
timerUI.status.innerHTML=media_symbol.pause;
} else {
timerUI.status.innerHTML=media_symbol.play;
}
} 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) {
if (! timerUI.bar) {
/* prevent running function before timerUI is properly loaded into the DOM to prevent exception */
if (timerUI.debug_mode) console.debug("timerUI: setColor can not run before timerUI is properly loaded.");
return false;
}
timerUI.previous_color = timerUI.color; // memorize previous setting
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;
// colour all buffer segments
for (var count=0; count < timerUI.buffer_bar.childNodes.length; count++) {
timerUI.buffer_bar.childNodes[count].style.backgroundColor=timerUI.color;
}
if (timerUI.debug_mode) console.debug("timerUI: color changed from "+timerUI.previous_color+" to "+timerUI.color);
};
timerUI.setColor("default"); // prevent mixed colours if the code is run multiple times
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;
};
// light mode
timerUI.light_mode = false; // default
timerUI.light_mode_on = function() {
timerUI.light_mode = true;
timerUI.color_before_light_mode = timerUI.color;
// improves visibility:
if (timerUI.setColor) /* exists*/ {
timerUI.setColor("lightblue");
} else { return false; /* error */ }
if (timerUI.gradient_placeholder) /* exists*/ {
timerUI.gradient_placeholder.style.backgroundColor="rgba(0, 0, 0, 0.5)";
} else { return false; /* error */ }
};
timerUI.light_mode_off = function() {
timerUI.light_mode = false;
if (timerUI.setColor) /* exists*/ {
timerUI.setColor("lightblue");
} else { return false; /* error */ }
if (timerUI.gradient_placeholder) /* exists*/ {
timerUI.gradient_placeholder.style.backgroundColor=""; // fall back to default
} else { return false; /* error */ }
};
timerUI.toggle.light_mode = function() {
if ( ! timerUI.light_mode ) /* if light mode is deactivated */ {
timerUI.light_mode_on();
return true;
} else {
timerUI.light_mode_off();
return false;
}
};
// "stop" icon
timerUI.stop = function() {
timerUI.status.innerHTML=media_symbol.stop;
timerUI.bar.style.width=0;
timerUI.buffer_bar.style.width=0;
// appearance of stopped timer consistent with the show_remaining setting
if (timerUI.show_remaining == 2) {
timerUI.time.innerHTML=MStimer(undefined)+" / "+MStimer(undefined);
} else {
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();
// 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; padding:0; margin:0; } #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%; left:0; bottom:0; pointer-events: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
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%; left:0; 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%; left:0; bottom:0; opacity:0.4; } #timerUI .timerUI_buffer_segment { opacity:1; }", timerUI.div);
// 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);
// 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%; left:0; 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");
// 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;", timerUI.div);
timerUI.domainRules(); // load domain rules after initializing timer elements
// 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) - "clickPos" has no "timerUI." notation because it is inside the 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)
}
// activate light mode on wikis and Dailymotion due to bright backgrounds
if ( isDomain("wiki")
|| isDomain("dailymotion.com")
|| isDomain("ghostarchive.org")
|| is_archive_library() ) {
timerUI.light_mode_on();
}
// 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 and
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 ( is_archive_library() ) {
// 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)
timerUI.archive_org_title = document.title.substring(0,document.title.search(/:(?:.(?!:))+(?:.(?!:))+/)-1 );
if (timerUI.archive_org_title.length > 0) /* only append " - " if a title exists. */ {
/* only append " - " if a title exists. */
if (timerUI.newTitle != "") { timerUI.newTitle += " - "; }
timerUI.newTitle += timerUI.archive_org_title;
}
// 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_archive_library() {
// function to check if the current page is an Archive.org library page and not the Wayback Machine
return (isDomain(/^(www.)?archive.org/) && ! isDomain("web.archive.org") );
// automatically returns true if the condition is met and false otherwise
}
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();