Advertisement
Guest User

timerUI build 2022-06-02

a guest
Jun 8th, 2022
11
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // TimerUI – for home cinemas
  2.  
  3. // == Dependencies ==
  4.  
  5. var mediaType; // for compatibility
  6. var playerExists = false; // is set to true below if player exists
  7. var checkMediaType_enabled = true; // for debugging purposes
  8. var media_element = {}; // declaring as object
  9.  
  10. function checkMediaType() {
  11.     // checks whether it is a video or an audio tag
  12.     if ( checkMediaType_enabled ) {
  13.             var mediaTypeBeforeCheck = mediaType;
  14.             if (document.getElementsByTagName("video")[0]) { playerExists = true; mediaType = "video"; }
  15.             if (document.getElementsByTagName("audio")[0]) { playerExists = true; mediaType = "audio"; }
  16.             var mediaTypeAfterCheck = mediaType;
  17.                if (mediaTypeBeforeCheck != mediaTypeAfterCheck)
  18.                   // Only show media type in console if it has changed.
  19.                   console.log("Detected media type: " + mediaType);
  20.         media_element = document.getElementsByTagName(mediaType)[0];
  21.         // Set back to false if no player is found after using customMediaElement.
  22.         media_element ? playerExists=true : playerExists=false;
  23.     }
  24. }
  25.  
  26. function customMediaElement(custom_media_element) {
  27.     checkMediaType_enabled = false;
  28.     if (custom_media_element) {
  29.         playerExists = true;
  30.         media_element = custom_media_element;
  31.         console.log("customMediaElement: Custom media element set. Reset using checkMediaType_enabled=true.");
  32.     } else { console.error("customMediaElement: No such media element found."); }
  33. }
  34. var customTitleElement;
  35.  
  36. function checkFileExtension(ext) {
  37.     if (typeof(ext) == "string") {
  38.         ext = ext.toLowerCase(); // case-insensitive
  39.         // string
  40.         if (document.location.toString().search(new RegExp(ext+"$", "i")) > -1) return true; else return false;
  41.     } else if (typeof(ext) == "object") {
  42.         // array – check against multiple strings
  43.         for (var count=0; count < ext.length; count++) {
  44.             if (document.location.toString().search(new RegExp(ext[count]+"$", "i")) > -1) return true;
  45.             if (count == ext.length-1) return false; // if no matches after going through them all
  46.         }
  47.     }
  48. }
  49.  
  50. function isDomain(domain) {
  51.     // Using .search() instead of .includes() to improve browser compatibility.
  52.     if (window.location.hostname.search(domain) >= 0) return true; else return false;
  53. }
  54.  
  55. // symbols
  56. var symbol_play = "▶&#xFE0E;&thinsp;"; // thin space for alignment
  57. var symbol_pause="&#10074;&thinsp;&#10074;"; // instead of "⏸" due to Edge browser putting an immutable blue box around it.
  58.  
  59. // mousedown status
  60. var mousedown_status;
  61. window.addEventListener("mousedown", function(){mousedown_status=true; } );
  62. window.addEventListener("mouseup", function(){mousedown_status=false; } );
  63.  
  64. function appendChildWithID(tagName,tagID,parent_element) {
  65.     // default parent element to document.body if unspecified
  66.     if (parent_element === undefined) parent_element = document.body;
  67.     parent_element.appendChild(document.createElement(tagName)); // add div
  68.     parent_element.lastElementChild.id=tagID; // give it ID
  69. }
  70.  
  71. function addStyle(new_style,parent_element) {
  72.     if (parent_element === undefined) parent_element = document.body;
  73.     parent_element.appendChild(document.createElement("style")); // add style
  74.     parent_element.lastElementChild.innerHTML = new_style;
  75. }
  76.  
  77. // time variables
  78. var media_time = {};
  79.  
  80. // HH:MM:SS timer
  81. function HMStimer_core(seconds) {
  82.  
  83.         // hours
  84.         media_time.HH = Math.floor( seconds/3600 );
  85.         // leading zero
  86.         if ( seconds < 36000 ) media_time.HH = "0" + media_time.HH;
  87.  
  88.         // minutes
  89.         media_time.MM = Math.floor( seconds/60%60 );
  90.         // leading zero
  91.         if ( seconds%3600 < 600 ) media_time.MM = "0" + media_time.MM;
  92.  
  93.         // seconds
  94.         media_time.SS = Math.floor( seconds%60 );
  95.         // leading zero
  96.         if ( seconds%60 < 10 ) media_time.SS = "0" + media_time.SS;
  97.  
  98.     return media_time.HH+":"+media_time.MM+":"+media_time.SS;
  99. }
  100.  
  101. function HMStimer(seconds) {
  102.     if (seconds >= 0) return HMStimer_core(seconds); // zero or positive
  103.     if (seconds < 0) // negative
  104.         {
  105.          seconds = seconds * (-1);
  106.          return "-"+HMStimer_core(seconds);
  107.         }
  108.     if (seconds == undefined || isNaN(seconds) ) return "–&thinsp;–:–&thinsp;–:–&thinsp;–";
  109.  
  110. }
  111.  
  112. // MM:SS timer
  113. function MStimer_core(seconds) {
  114.  
  115.         // minutes
  116.         media_time.MM = Math.floor( seconds/60 );
  117.         // leading zero
  118.         if ( seconds%3600 < 600 ) media_time.MM = "0" + media_time.MM;
  119.  
  120.         // seconds
  121.         media_time.SS = Math.floor( seconds%60 );
  122.         // leading zero
  123.         if ( seconds%60 < 10 ) media_time.SS = "0" + media_time.SS;
  124.  
  125.     return media_time.MM+":"+media_time.SS;
  126. }
  127.  
  128. function MStimer(seconds) {
  129.     if (seconds >= 0) return MStimer_core(seconds); // zero or positive
  130.     if (seconds < 0) // negative
  131.         {
  132.          seconds = seconds * (-1);
  133.          return "-"+MStimer_core(seconds);
  134.         }
  135.     if (seconds == undefined || isNaN(seconds) ) return "–&thinsp;–:–&thinsp;–";
  136.  
  137. }
  138.  
  139.  
  140. // implements togglePlay(); – deprecated due to compatibility issues on YouTube (broken site) and Dailymotion ("not a function" error through iframe'd player).
  141. /*
  142. Object.prototype.togglePlay = function togglePlay() {
  143.   return this.paused ? this.play() : this.pause();
  144. };
  145. */
  146.  
  147. // new function without object prototype for compatibility
  148. function togglePlay(media_element) {
  149.     if (media_element) { // validate media element first to avoid errors
  150.         media_element.paused ? media_element.play() : media_element.pause();
  151.     }
  152. }
  153.  
  154. // media file extension list
  155. var mediafileext = {
  156.     "video":[".mp4",".mpg",".mpeg",".mts",".mt2s",".m4v",".ts",".ogv",".wmv",".3gp",".3gpp"],
  157.     "audio":[".mp3",".wma",".wav",".ogg",".opus",".flac",".oga",".wma",".aac",".amr",".alac",".m4a"]
  158. };
  159.  
  160. // == Main code ==
  161. if (! timerUI) var timerUI = new Object({}); // create parent object if none exists
  162.  
  163.     // default system variables
  164. timerUI.debug_mode = false;
  165. timerUI.override_check = false;
  166.  
  167. timerUI.on = true;
  168. timerUI.buffer_on = true;
  169. timerUI.multiBuffer = true; // multiple buffer segments
  170. timerUI.div = {}; // unset yet, declaring to prevent reference errors
  171. timerUI.interval = {};
  172. timerUI.show_remaining = 0; // 0: show elapsed time. 1: show remaining time. 2: show elapsed and total.
  173. timerUI.update_during_seek = true; // update timer while dragging seek bar
  174. timerUI.color = "rgb(49,136,255)"; // #38F – using RGB for compatibility.
  175. timerUI.gradient = "rgba(0,0,0,0.9)"; // using RGBA instead of hexadecimal for compatibility.
  176. timerUI.font_pack = "din,futura,'noto sans',ubuntu,'segoe ui',verdana,tahoma,roboto,'roboto light',arial,helvetica,'trebuchet ms',sans-serif,consolas,monospace";
  177. timerUI.width_breakpoint = 768; // pixels
  178.  
  179.     // console notifications and warnings (possibly to be expanded)
  180. timerUI.msg = {
  181.     "notimer": "timerUI: No timer found; checking for media element again. Please try again.",
  182.     "nomedia": "timerUI: no media element found on page. Stopping."
  183. }
  184.  
  185.     // text containers (no const for compatibility)
  186. var timer_linefeed = "<span class=timer_linefeed><br /></span>";
  187. var timer_slash = " <span class=timer_slash>/</span> ";
  188.  
  189.     // functions
  190. timerUI.toggle = {};
  191. timerUI.toggle.main = function() {
  192.     if (timerUI.div) {
  193.         timerUI.update();
  194.         if (timerUI.on) {  
  195.             timerUI.div.style.display = "none";
  196.             console.log("timerUI off");
  197.         }
  198.         if (! timerUI.on ) {  
  199.             timerUI.div.style.display = "block";
  200.             console.log("timerUI on");
  201.         }
  202.         timerUI.on ? timerUI.on = false : timerUI.on = true;
  203.     } else {
  204.         console.warn(timerUI.msg.notimer);
  205.         timeUI();
  206.     }
  207. };
  208.  
  209. timerUI.toggle.buffer = function() {
  210.     if (timerUI.div) {
  211.         timerUI.update(); timerUI.updateBufferBar(true);
  212.         if (timerUI.buffer_on) {  
  213.             timerUI.buffer_bar.style.display = "none";
  214.             console.log("timerUI buffer bar off");
  215.         }
  216.         if (! timerUI.buffer_on ) {  
  217.             timerUI.buffer_bar.style.display = "block";
  218.             console.log("timerUI buffer bar on");
  219.         }
  220.         timerUI.buffer_on ? timerUI.buffer_on = false : timerUI.buffer_on = true;
  221.     } else {
  222.         console.warn(timerUI.msg.notimer);
  223.         timeUI();
  224.     }
  225. };
  226.  
  227. timerUI.toggle.title = function() {
  228.     if (timerUI.div) {
  229.         timerUI.update(); timerUI.updateBufferBar(true);
  230.         if (timerUI.title_on) {  
  231.             timerUI.title.style.display = "none";
  232.             console.log("timerUI title off");
  233.         }
  234.         if (! timerUI.title_on ) {  
  235.             timerUI.title.style.display = "block";
  236.             console.log("timerUI title on");
  237.         }
  238.         timerUI.title_on ? timerUI.title_on = false : timerUI.title_on = true;
  239.     } else {
  240.         console.warn(timerUI.msg.notimer);
  241.         timeUI();
  242.     }
  243. };
  244.  
  245. timerUI.getTitle = function() {
  246.         timerUI.domainRules();
  247.     if (customTitleElement) timerUI.newTitle = customTitleElement.innerHTML;
  248.     else { // skipping this whole part if no custom title is specified
  249.         timerUI.newTitle = document.title;
  250.         timerUI.titleDomainRules();
  251.     }
  252.     if (media_element) {
  253.         timerUI.updateFileIcon();
  254.         return timerUI.fileIcon+"&nbsp;"+timerUI.newTitle;
  255.     } else {
  256.         return "TimerUI – designed for home cinemas";
  257.     }
  258. }
  259.  
  260. timerUI.guessMediaType = function() {
  261.     if (isDomain("youtube.com") || isDomain("dailymotion.com") ) return "video";
  262.     if (document.location.pathname.toString().search(/^\/video\//) > -1) return "video";
  263.     if (checkFileExtension(mediafileext.video) ) return "video";
  264.     if (checkFileExtension(mediafileext.audio) ) return "audio";
  265.     return "unknown"; // if nothing detected
  266. }
  267.  
  268. timerUI.updateFileIcon = function() {
  269.     timerUI.fileIcon = timerUI.guessMediaType();
  270.     switch(timerUI.fileIcon) {
  271.         case "video": timerUI.fileIcon = "🎞️"; break;
  272.         case "audio": timerUI.fileIcon = "♫"; break;
  273.         case "unknown": timerUI.fileIcon = "📄"; break;
  274.     }
  275. }
  276.  
  277.  
  278. timerUI.adaptTitleWidth = function() {
  279.     if (media_element.duration > 3600 && timerUI.show_remaining == 2 && window.innerWidth > timerUI.width_breakpoint)
  280.         timerUI.title.style.maxWidth = "calc(100% - 670px)";
  281.     else
  282.         timerUI.title.style.maxWidth = "calc(100% - 400px)";
  283. }
  284.  
  285. window.addEventListener('resize', function() {
  286.     if (window.innerWidth < timerUI.width_breakpoint) timerUI.title.removeAttribute("style");
  287. } );
  288.  
  289. timerUI.update = function() {
  290.     if (media_element) {
  291.         timerUI.bar.style.width=media_element.currentTime / media_element.duration * 100 + "%";
  292.  
  293.         // buffer bar update formerly located here; removed from the scope of this function
  294.  
  295.         switch(timerUI.show_remaining) {
  296.             // 0: "HH:MM:SS"  1: "-HH:MM:SS"  2: "MM:SS / MM:SS" or "HH:MM:SS / HH:MM:SS"
  297.             case 0: timerUI.time.innerHTML=HMStimer(media_element.currentTime); break;
  298.             case 1: timerUI.time.innerHTML=HMStimer(media_element.currentTime-media_element.duration); break;
  299.             case 2:
  300.                 if (media_element.duration < 3600 || isNaN(media_element.duration) ) {
  301.                 // show hours if duration exceeds one hour
  302.                     timerUI.time.innerHTML=
  303.                         MStimer(media_element.currentTime)
  304.                         + timer_linefeed
  305.                         + timer_slash
  306.                         + MStimer(media_element.duration);
  307.                 } else {
  308.                     timerUI.time.innerHTML=
  309.                         HMStimer(media_element.currentTime)
  310.                         + timer_linefeed
  311.                         + timer_slash
  312.                         + HMStimer(media_element.duration);
  313.                 }
  314.                 break;
  315.         }
  316.  
  317.         media_element.paused == false ?
  318.             timerUI.status.innerHTML=symbol_play
  319.           : timerUI.status.innerHTML=symbol_pause;
  320.  
  321.   } else { timerUI.stop(); console.warn(timerUI.msg.nomedia) }
  322. };
  323. timerUI.updateTitle = function() { if (timerUI.title) timerUI.title.innerHTML = timerUI.getTitle(); }
  324.  
  325. // update title on URL change
  326. addEventListener('popstate', timerUI.updateTitle);
  327.  
  328. // update title fallback
  329. timerUI.interval.updateTitle = setInterval(timerUI.updateTitle, 2000);
  330.  
  331.  
  332. // buffer bar
  333. timerUI.updateBufferBar = function(override_paused) {
  334.     if (media_element && timerUI.buffer_on && (!media_element.paused || override_paused) ) {
  335.     timerUI.multiBuffer ? timerUI.update_multi_buffer() : timerUI.single_segment_buffer();
  336.   }
  337. };
  338.  
  339. // single-segment buffer bar
  340. timerUI.single_segment_buffer = function() {
  341.     if (timerUI.buffer_bar.innerHTML!="") { timerUI.buffer_bar.style=""; timerUI.buffer_bar.innerHTML=""; } // reset after switching from multi-segment buffer bar
  342.     // find out first buffer segment after current playback position
  343.     media_element.buffered.length > 0 ? timerUI.buffer_segment=media_element.buffered.length-1 : timerUI.buffer_segment=0;
  344.     // media_element.buffered.length is zero until player is initialized
  345.     // prevent timerUI.buffer_segment from going negative, as it would cause a DOMException error
  346.     if  ( timerUI.buffer_segment > 0) {
  347.         while (media_element.buffered.end(timerUI.buffer_segment-1) > media_element.currentTime && timerUI.buffer_segment > 1 ) {
  348.             timerUI.update_single_buffer();
  349.             timerUI.buffer_segment-- ;
  350.         }
  351.     }
  352. };
  353.  
  354. timerUI.update_single_buffer = function() {
  355.     if (media_element.buffered.length > 0) {
  356.     // prevent "DOMException: Index or size is negative or greater than the allowed amount"
  357.         timerUI.buffer_bar.style.width=media_element.buffered.end(timerUI.buffer_segment) / media_element.duration * 100 + "%";
  358.     } else { timerUI.buffer_bar.style.width="0%"; }
  359. };
  360.  
  361. // multi-segment buffer bar – highlight all buffered parts
  362. timerUI.update_multi_buffer = function() {
  363.     if (timerUI.buffer_bar.style.length < 1) {
  364.         timerUI.buffer_bar.style.width="100%";
  365.         timerUI.buffer_bar.style.backgroundColor="rgba(0,0,0,0)";
  366.     }
  367.     if (media_element.buffered.length > 0) {
  368.         timerUI.generate_buffer_segments();
  369.     } else { timerUI.buffer_bar.style.width="0%"; }
  370. };
  371.  
  372. timerUI.generate_buffer_segments = function() {
  373.     timerUI.buffer_bar.innerHTML=""; // reset to re-generate segments
  374.     for (count=0; count < media_element.buffered.length; count++) {
  375.         timerUI.append_buffer_segment(timerUI.get_buffer_range(count) );
  376.     }
  377.     timerUI.select_segments = timerUI.buffer_bar.getElementsByClassName("timerUI_buffer_segment");
  378.     timerUI.segment_count = timerUI.select_segments.length;
  379. };
  380.  
  381. timerUI.append_buffer_segment = function([start_pos,end_pos]) {
  382.     // array function
  383.     timerUI.buffer_bar.appendChild(document.createElement("div"));
  384.     timerUI.buffer_bar.lastElementChild.classList.add("timerUI_buffer_segment");
  385.     timerUI.buffer_bar.lastElementChild.style="left:"+start_pos+"%;width:"+(end_pos-start_pos)+"%;";
  386. };
  387.  
  388. timerUI.get_buffer_range = function(segment_number) {
  389.     return [
  390.     media_element.buffered.start(segment_number) / media_element.duration * 100,
  391.     media_element.buffered.end(segment_number) / media_element.duration * 100
  392.     ]; // array with start and end percentages
  393. };
  394.  
  395. timerUI.set_buffer_segment = function(segment_number,start_pos,end_pos) {
  396.     var selection=timerUI.buffer_bar.getElementsByClassName("timerUI_buffer_segment");
  397.     selection[segment_number].style.left = start_pos / media_element.duration * 100 + "%";
  398.     selection[segment_number].style.width = (end_pos-start_pos) / media_element.duration * 100 + "%";
  399. };
  400.  
  401.  
  402.  
  403. // colors
  404. timerUI.setColor = function(newColor) {
  405.     newColor == "default" ? timerUI.color="rgb(49,136,255)" /* #38F */ : timerUI.color = newColor;
  406.  
  407.     timerUI.bar.style.backgroundColor=timerUI.color;
  408.     timerUI.buffer_bar.style.backgroundColor=timerUI.color;
  409.     timerUI.bar.style.boxShadow="0 0 30px 0 "+timerUI.color;
  410.     // (deprecated due to new buffer bar) timerUI.bar_placeholder.style.backgroundColor=timerUI.color;
  411.     timerUI.time.style.color=timerUI.color;
  412.     timerUI.status.style.color=timerUI.color;
  413.     timerUI.title.style.color=timerUI.color;
  414. };
  415.  
  416. timerUI.setGradient = function(newGradient) {
  417.     newGradient == "default" ? timerUI.gradient="rgba(0,0,0,0.9)" : timerUI.gradient = newGradient;
  418.     timerUI.gradient_placeholder.style.backgroundImage="linear-gradient(to top,"+timerUI.gradient+", rgba(0,0,0,0) )";
  419. };
  420.  
  421. timerUI.setFont = function(newFont) {
  422.     timerUI.time.style.fontFamily=newFont;
  423.     timerUI.title.style.fontFamily=newFont;
  424. };
  425.  
  426. timerUI.stop = function() {
  427.     timerUI.status.innerHTML="■";
  428.     timerUI.bar.style.width=0;
  429.     timerUI.buffer_bar.style.width=0;
  430.     timerUI.time.innerHTML=HMStimer(undefined);
  431. };
  432.  
  433. // Additional checks to ensure the player is detected
  434. window.onclick = function() { checkMediaType();timeUI(); };
  435. window.addEventListener("keydown", function() { checkMediaType();timeUI(); } );
  436.  
  437.  
  438. function timeUI() {
  439. // slightly different name to prevent naming collision with timerUI object
  440.  
  441.     checkMediaType();
  442.     timerUI.domainRules(); // load domain rules
  443.     // add timerUI if it does not already exist
  444.     if ( ( ! document.getElementById("timerUI") ) && playerExists || timerUI.override_check ) {
  445.  
  446.     // Adding elements
  447.  
  448.         // parent element
  449.         appendChildWithID("div","timerUI");
  450.         timerUI.div = document.getElementById("timerUI");
  451.  
  452.         // button styling
  453.         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);
  454.             // to suppress button background and border on earlier browser versions
  455.         timerUI.div.lastElementChild.classList.add("timerUI_buttons"); // label to improve visibility in page inspector
  456.  
  457.         // background gradient
  458.         appendChildWithID("div","timerUI_bottom_gradient",timerUI.div );
  459.         timerUI.gradient_placeholder = document.getElementById("timerUI_bottom_gradient");
  460.         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);
  461.  
  462.         // progress bar
  463.         appendChildWithID("div","timerUI_progress_bar",timerUI.div );
  464.         timerUI.bar = document.getElementById("timerUI_progress_bar");
  465.         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);
  466.  
  467.         // buffer bar
  468.         appendChildWithID("div","timerUI_buffer_bar",timerUI.div );
  469.         timerUI.buffer_bar = document.getElementById("timerUI_buffer_bar");
  470.         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);
  471.  
  472.         // media title
  473.         appendChildWithID("div","timerUI_media_title",timerUI.div );
  474.         timerUI.title = document.getElementById("timerUI_media_title");
  475.         timerUI.title.innerHTML = timerUI.getTitle();
  476.         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;")
  477.  
  478.         // timer
  479.         appendChildWithID("button","timerUI_media_timer",timerUI.div );
  480.         timerUI.time = document.getElementById("timerUI_media_timer");
  481.         timerUI.time.innerHTML="00:00:00";
  482.         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);
  483.  
  484.         // play/pause symbol
  485.         appendChildWithID("button","timerUI_playback_status",timerUI.div );
  486.         timerUI.status = document.getElementById("timerUI_playback_status");
  487.         timerUI.status.innerHTML="■";
  488.         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);
  489.  
  490.         // progress bar placeholder – put last to be at the top in stacking context
  491.         appendChildWithID("div","timerUI_progress_placeholder",timerUI.div );
  492.         timerUI.bar_placeholder = document.getElementById("timerUI_progress_placeholder");
  493.         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);
  494.  
  495.         // responsive - at bottom to be able to override CSS properties without !important flag.
  496.         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);
  497.         timerUI.div.lastElementChild.classList.add("timerUI_responsive");
  498.  
  499.  
  500.     // update timer during playback every fifteenth of a second and while mouse is dragging progress bar
  501.     timerUI.interval.update = setInterval(
  502.         function() { if (
  503.                 ( media_element /* exists? */ && timerUI.update_during_seek && mousedown_status )
  504.              || ( media_element && timerUI.on && ! media_element.paused )
  505.     ) timerUI.update(); }, 1000/15
  506.     );
  507.  
  508.     // Longer interval for buffer bar to minimize CPU usage
  509.     timerUI.interval.buffer = setInterval(timerUI.updateBufferBar, 1000);
  510.  
  511.  
  512.     // play and pause toggle
  513.     timerUI.status.onclick = function() { togglePlay(media_element); timerUI.update(); timerUI.updateBufferBar(true); };
  514.         // former code with object prototype caused compatibility issues on various sites: media_element.togglePlay();
  515.  
  516.     // toggle between elapsed, remaining, and elapsed/total time
  517.     timerUI.time.onclick = function() {
  518.         switch(timerUI.show_remaining) {
  519.             case 0: timerUI.show_remaining = 1; break;
  520.             case 1: timerUI.show_remaining = 2; timerUI.adaptTitleWidth(); break;
  521.             case 2: timerUI.show_remaining = 0; timerUI.adaptTitleWidth(); break;
  522.         }
  523.         timerUI.update(); timerUI.updateBufferBar(true);
  524.     };
  525.  
  526.     // clickable progress bar (experimental) - no "timerUI." notation because inside main function
  527.     timerUI.clickSeekBar = function(m){
  528.         if (media_element) {
  529.             var clickPos = m.clientX / timerUI.bar_placeholder.offsetWidth;
  530.             media_element.currentTime = media_element.duration * clickPos;
  531.             timerUI.update(); timerUI.updateBufferBar(true);
  532.         }
  533.     }
  534.     function dragSeekBar(m){ // currently unused
  535.         m = m || window.event;
  536.         var clickPos = m.pageX / timerUI.bar_placeholder.offsetWidth;
  537.         var dragSeekBarInterval = setInterval( function() {
  538.             media_element.currentTime = media_element.duration * clickPos;
  539.             timerUI.update();
  540.             if (! mousedown_status) { clearInterval(dragSeekBarInterval); return; }
  541.         }, 200);
  542.     }
  543.     timerUI.bar_placeholder.addEventListener("mousedown", timerUI.clickSeekBar );
  544.     // (incomplete) timerUI.bar_placeholder.addEventListener("mousemove", dragSeekBar );
  545.     // (obsolete) timerUI.bar_placeholder.addEventListener("mouseup", clickSeekBar );
  546.  
  547.     timerUI.update();
  548.  
  549.     // == Patches ==
  550.  
  551.         // prevent missing out on pausing from inside a site's existing player
  552.         window.addEventListener("mouseup", function() { setTimeout(timerUI.update, 200); } );
  553.         window.addEventListener("keyup", function() { setTimeout(timerUI.update, 200); } );
  554.  
  555.         // prevent detaching from player on sites with playlists such as Internet Archive
  556.         timerUI.interval.checkMedia = setInterval( checkMediaType,1000 );
  557.  
  558.         // prevent indicating "▶" after playback finished
  559.         timerUI.interval.checkPaused = setInterval( function() {
  560.                 if ( media_element /* exists? */ && media_element.paused && ! timerUI.pause_checked) {
  561.                     timerUI.update(); timerUI.pause_checked = true;
  562.                     if (timerUI.debug_mode) console.debug("timerUI: checking paused status: "+media_element.paused);
  563.                 } else if ( media_element && ! media_element.paused ) { timerUI.pause_checked = false; }
  564.                 // to avoid redundant checks while paused
  565.         },1000 );
  566.  
  567.     } else {
  568.     // warn in console that no player exists; prevent repetition
  569.         if (! playerExists && ! timerUI.noMediaWarned) {
  570.                 console.warn(timerUI.msg.nomedia); timerUI.noMediaWarned = true;
  571.         }
  572.     }
  573. }
  574.  
  575. // == Custom domain rules ==
  576. timerUI.domainRules = function() {
  577.     if (isDomain("dailymotion.com") && document.location.pathname.toString().search(/^\/embed\//) < 0 ) {
  578.         // Dailymotion watch page, excluding embed page.
  579.         customMediaElement(document.getElementById("player-body").contentWindow.document.getElementsByTagName("video")[0]);
  580.         customTitleElement = document.getElementById("media-title"); // for unlisted
  581.     }
  582. };
  583.  
  584. timerUI.titleDomainRules = function() {
  585. // custom domain rules for title
  586.         if ( isDomain("youtube.com") || isDomain("dailymotion.com")
  587.             || isDomain("wikimedia.org") || isDomain("wikipedia.org")
  588.             || isDomain("wikiversity.org") || isDomain("wikibooks.org")
  589.             || isDomain("mediawiki.org")
  590.             ) {
  591.             // negative lookahead regular expression – trim after last dash
  592.             // Match both normal dash "-" and ndash "–", since the German-language wikis use the latter.
  593.             timerUI.newTitle = decodeURI(timerUI.newTitle.substring(0,timerUI.newTitle.search(/(-|–)(?:.(?!(-|–)))+$/)-1 ) );
  594.         }
  595.         // remove "File:" prefix on wikis
  596.         if ( isDomain("wiki") ) {
  597.             if (document.title.search(/^File:/)  == 0 ) timerUI.newTitle = timerUI.newTitle.substring(5);
  598.             if (document.title.search(/^Datei:/) == 0 ) timerUI.newTitle = timerUI.newTitle.substring(6);
  599.         }
  600.  
  601.         if ( isDomain("archive.org") && ! isDomain("web.archive.org") ) {
  602.             timerUI.newTitle = (document.location.toString()+"").substring((document.location.toString()+" ").search(/\/(?:.(?!\/))+\/?$/)+1 );
  603.             // after last slash (additional space prevents full URL from being matched)
  604.             if (timerUI.newTitle != "") { timerUI.newTitle += " - " };
  605.             timerUI.newTitle += document.title.toString().substring(0,document.title.toString().search(/:(?:.(?!:))+(?:.(?!:))+/)-1 );
  606.             // trim after second-last colon, -1 to remove space at end
  607.         }
  608. };
  609.  
  610. // == Master function ==
  611. timeUI();
Advertisement
RAW Paste Data Copied
Advertisement