1/** 2 * Yoober() 3 * Description: Loop YouTube video as a background or as a standalone video player without audio output. 4 * Version: 1.2 5 * Published Date: 2020-04-22 6 * Author: Max Chau 7 * Ownership: Andzen Pty Ltd 8 */ 9(function(){ 10 var tag = document.createElement('script'); 11 tag.src = "https://www.youtube.com/player_api"; 12 var firstScriptTag = document.getElementsByTagName('script')[0]; 13 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 14 15 if (!NodeList.prototype.forEach) { NodeList.prototype.forEach = function(callback){ var T, k; if (this == null) { throw new TypeError('this is null or not defined'); } var O = Object(this); var len = O.length >>> 0; if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } if (arguments.length > 1) { T = arguments[1]; } k = 0; while (k < len) { var kValue; if (k in O) { kValue = O[k]; callback.call(T, kValue, k, O); } k++; } }; } 16})(); 17 18function Yoober(yt_video_id, target_els, isBackgroundVideo){ 19 if(typeof yt_video_id !== 'string') { console.error('Yoober: The first element must be a string.'); return false; } 20 if(typeof target_els !== 'string') { console.error('Yoober: The second element must be a string.'); return false; } 21 22 var youtubePlayer = null; 23 var isBackgroundVideo = isBackgroundVideo || false; 24 var bg_v_margin = 60; 25 26 /** 27 * Resize the video player to fit the entire surface of the container 28 */ 29 var video_resize = function(){ 30 if( ! isBackgroundVideo ) { 31 return false; } 32 33 document.querySelectorAll(target_els).forEach(function(target_el){ 34 var target_width = target_el.clientWidth; 35 var target_height = target_el.clientHeight; 36 var container_el = target_el.querySelector('.yoober-container'); 37 var video_el = target_el.querySelector('.yoober-video'); 38 var video_ratio = video_el.offsetHeight / video_el.offsetWidth; 39 var container_height = (target_width * video_ratio) - (bg_v_margin * 2); 40 41 if( container_height > target_height ) { 42 container_el.style.marginTop = ((container_height - target_height) / -2) + "px"; 43 container_el.style.marginLeft = 0; 44 container_el.style.marginRight = 0; 45 } else if ( container_height < target_height ) { 46 var container_horizontal_margin = (target_height - container_height) * -1; 47 container_el.style.marginLeft = container_horizontal_margin+"px"; 48 container_el.style.marginRight = container_horizontal_margin+"px"; 49 container_el.style.marginTop = 0; 50 } else { 51 container_el.style.marginTop = 0; 52 container_el.style.marginLeft = 0; 53 container_el.style.marginRight = 0; 54 } 55 }); 56 }; // END video_resize() 57 58 /** 59 * Make the iframe overlay visible. 60 */ 61 var iframeOverlayShow = function(iframe_node){ 62 iframe_node.parentNode.parentNode.querySelector('.yoober-overlay').style.visibility = 'visible'; }; 63 64 /** 65 * Make the iframe overlay hidden. 66 */ 67 var iframeOverlayHide = function(iframe_node){ 68 iframe_node.parentNode.parentNode.querySelector('.yoober-overlay').style.visibility = 'hidden'; }; 69 70 /** 71 * Function to execute when each player is ready 72 */ 73 var onPlayerReady = function(event){ 74 var player = event.target; 75 var video_duration = 0, 76 video_max_play_length = 0; 77 78 // Make sure the video mutes and plays with the highest quality posible 79 player.setPlaybackQuality('highres').mute().playVideo(); 80 81 iframeOverlayShow(player.getIframe()); 82 83 playerDurationInterval = setInterval(function(){ 84 video_duration = player.getDuration(); 85 86 if(video_duration){ 87 clearInterval(playerDurationInterval); 88 89 video_max_play_length = video_duration * 1000 - 500; 90 91 // 1. Play next / Reload video to improve its playback quality 92 player.nextVideo(); 93 94 // 2. Keep looping the video before it ends 95 setInterval(function(){ 96 player.seekTo(0).playVideo(); 97 }, video_max_play_length); 98 } 99 }, 100); 100 }; 101 102 /** 103 * Function to execute when the state each player has changed 104 */ 105 var onPlayerStateChange = function(event){ 106 switch(event.data){ 107 case 0: // ended 108 iframeOverlayShow(event.target.getIframe()); 109 event.target.seekTo(0).playVideo(); 110 break; 111 case 1: // playing 112 iframeOverlayHide(event.target.getIframe()); 113 break; 114 default: 115 iframeOverlayShow(event.target.getIframe()); 116 break; 117 } 118 }; 119 120 /** 121 * Initiate Yoober 122 */ 123 var yoober_init = function(){
124 document.querySelectorAll(target_els).forEach(function(target_el){ 125 var container_el = document.createElement('div'); 126 container_el.className = 'yoober-container'; 127 var video_el = document.createElement('div'); 128 video_el.className = 'yoober-video'; 129 var overlay_el = document.createElement('div'); 130 overlay_el.className = 'yoober-overlay'; 131 overlay_el.style.background = 'url(https://img.youtube.com/vi/'+yt_video_id+'/maxresdefault.jpg) center/cover no-repeat'; 132 var player_id = 'yoober-video-' + Math.floor(Date.now() * Math.random()); 133 134 target_el.appendChild(container_el); 135 container_el.appendChild(overlay_el); 136 container_el.appendChild(video_el); 137 video_el.innerHTML = '<div id="'+player_id+'"></div>'; 138 139 if(isBackgroundVideo){ 140 target_classname = target_el.getAttribute('class') || ""; 141 target_classname = target_classname + " yoober-background"; 142 target_el.setAttribute('class', target_classname.trim() ); 143 144 var parent_el = target_el.parentNode; 145 parent_classname = parent_el.getAttribute('class') || ""; 146 parent_classname = parent_classname + " yoober-parent"; 147 parent_el.setAttribute('class', parent_classname.trim() ); 148 149 video_el.style.marginTop = (bg_v_margin * -1) + "px"; 150 video_el.style.marginBottom = (bg_v_margin * -1) + "px"; 151 } 152 153 var ytIframeAPIReadyInterval = setInterval(function(){ 154 var ytIframeAPIReady = ( window['YT'] && typeof YT.Player !== 'undefined' ); 155 if( ytIframeAPIReady ){ 156 var player_vars = { 157 autoplay: 0, 158 cc_lang_pref: 0, 159 cc_load_policy: 0, 160 controls: 0, 161 disablekb: 1, 162 enablejsapi: 1, 163 fs: 0, 164 iv_load_policy: 3, 165 loop: 1, 166 modestbranding: 1, 167 playlist: yt_video_id, 168 playsinline: 1, 169 rel: 0, 170 showinfo: 0 171 }; 172 173 if( window.location.hostname){ 174 player_vars.origin = window.location.hostname; } 175 176 youtubePlayer = new YT.Player(player_id, { 177 height: '390', 178 width: '640', 179 videoId: yt_video_id, 180 playerVars: player_vars, 181 events: { 182 'onReady': onPlayerReady, 183 'onStateChange': onPlayerStateChange 184 } 185 }); 186 187 clearInterval(ytIframeAPIReadyInterval); 188 } 189 }, 100); 190 }); 191 }; // END yoober_init() 192 193 yoober_init(); 194 195 window.addEventListener("DOMContentLoaded", video_resize); 196 window.addEventListener("load", video_resize); 197 window.addEventListener("resize", video_resize); 198}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.