1/* Copyright 2026 Maximillian Laumeister */ 2/* https://www.hideyt.com/ */ 3(function () { 4 "use strict"; 5 6 let DEBUG = false; 7 window.HIDEYT_VERSION = "2.3.0"; 8 9 const iframeInnerHTML = ` 10 <!doctype html> 11 <meta charset="utf-8"> 12 <title>HideYT Embedded Frame</title> 13 <script src="https://www.youtube.com/iframe_api"></script> 14 <style> 15 16 html, body { 17 margin: 0; 18 padding: 0; 19 width: 100vw; 20 height: 100vh; 21 font-size: 0; 22 overflow: hidden; 23 } 24 25 body, .hytWPOverlay.ended::after, .hytWPOverlay.fullHiding.paused, .hytWPOverlay.hidestart { 26 background-repeat: no-repeat; 27 background-position: center; 28 background-size: cover; 29 } 30 31 iframe { 32 position: absolute; 33 top: 0; 34 right: 0; 35 width: 100vw; 36 height: 100vh; 37 } 38 39 .hytWPOverlay { 40 position: absolute; 41 top: 0; 42 left: 0; 43 bottom: 0; 44 right: 0; 45 pointer-events: none; 46 } 47 48 .hytWPOverlay.ended::after { 49 content:""; 50 position: absolute; 51 top: 0; 52 left: 0; 53 bottom: 0; 54 right: 0; 55 } 56 57 .hytWPOverlay.paused::after, .hytWPOverlay.hidestart::after { 58 content:""; 59 pointer-events: auto; 60 position: absolute; 61 top: 70px; 62 left: 0; 63 bottom: 127px; 64 right: 0; 65 cursor: pointer; 66 background-color: #1b1b1b; 67 background-repeat: no-repeat; 68 background-position: center; 69 background-size: 70px 70px; 70 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1' width='400' height='400' viewBox='0 0 300 300'%3E%3Cg transform='translate(-.234 .173)'%3E%3Ccircle r='147.914' cy='149.827' cx='150.234' fill='%231b1b1b' fill-opacity='.818'/%3E%3Cpath d='M107.06 76.304l127.346 73.523L107.06 223.35z' fill='%23fff'/%3E%3C/g%3E%3C/svg%3E"); 71 } 72 73 @media (pointer: coarse) { 74 .hytWPOverlay.paused::after, .hytWPOverlay.hidestart::after { 75 bottom: 60px; 76 } 77 } 78 79 .hytWPOverlay.paused.fullHiding::after, .hytWPOverlay.hidestart::after { 80 bottom: 0; 81 top: 0; 82 background-color: transparent; 83 } 84 85 .hytWPPlayerWrapExpired { 86 position: absolute; 87 pointer-events: auto; 88 font-size: 14px; 89 top: 0; 90 left: 0; 91 right: 0; 92 padding: 10px; 93 background: darkred; 94 color: white; 95 font-family: sans-serif; 96 line-height: 1.1; 97 z-index: 1; 98 } 99 100 .hytWPPlayerWrapExpired p { 101 margin: 5px 0; 102 } 103 104 .hytWPPlayerWrapExpired a, .hytWPPlayerWrapExpired a:visited { 105 color: #ffa5a5 !important; 106 text-decoration: underline !important; 107 font-weight: bold; 108 } 109 110 .hytWPPlayerWrapExpired a:hover { 111 color: white !important; 112 } 113 114 </style> 115 <script> 116 (function () { 117 "use strict"; 118 119 let DEBUG = false; 120 if (DEBUG) console.log("inner document script parsed"); 121 122 let playerData; 123 124 function init() { 125 if (DEBUG) console.log("begin init"); 126 127 // Set background images in CSS 128 function addCss(cssCode) { 129 // https://stackoverflow.com/a/6211716/2234742 130 var styleElement = document.createElement("style"); 131 styleElement.type = "text/css"; 132 if (styleElement.styleSheet) { 133 styleElement.styleSheet.cssText = cssCode; 134 } else { 135 styleElement.appendChild(document.createTextNode(cssCode)); 136 } 137 document.getElementsByTagName("head")[0].appendChild(styleElement); 138 } 139 const styles = \` 140 body, .hytWPOverlay.ended::after, .hytWPOverlay.fullHiding.paused, .hytWPOverlay.hidestart { 141 background-image: url('https://img.youtube.com/vi/\${playerData.videoId}/0.jpg'); 142 } 143 \`; 144 addCss(styles); // TODO: Tear this down before new player init, avoid duplicate css 145 146 // Import options 147 let HIDING_OPTION = playerData.options.hideyt_field_appearance || "full"; 148 let EXPIRED = playerData.options.expired ? true : false;
149 let PAUSE_OPTION = playerData.options.hideyt_field_pausehiding || "partial"; 150 let START_HIDING = (playerData.options.hideyt_field_starthiding === "true"); 151 152 // Configure overlay 153 let overlay = document.querySelector(".hytWPOverlay"); 154 if (PAUSE_OPTION === "full") overlay.classList.add("fullHiding"); 155 156 // Reset overlay 157 overlay.classList.remove("ended"); 158 overlay.classList.remove("paused"); 159 if (START_HIDING) overlay.classList.add("hidestart"); 160 161 // Clean up from last instantiation 162 const prevFrame = document.querySelector("#player"); 163 if (prevFrame) prevFrame.remove(); 164 165 let surrogate = document.createElement("div"); 166 surrogate.id = "player"; 167 document.body.insertBefore(surrogate, overlay); 168 169 const ytplayer = new YT.Player('player', { 170 height: '390', 171 width: '640', 172 videoId: playerData.videoId, 173 playerVars: playerData.urlParameters, 174 events: { 175 'onReady': onPlayerReady 176 } 177 }); 178 const ytiframe = ytplayer.getIframe(); 179 180 if (DEBUG) console.log(ytiframe); 181 182 // Add enablejsapi on YouTube Embed 183 /*let url = new URL(ytiframe.src); 184 if (url.searchParams.get('enablejsapi') !== "1") { 185 url.searchParams.set('enablejsapi', "1"); 186 url.searchParams.set('rel', "0"); // Since the iframe needs to reload anyway... 187 ytiframe.src = url; 188 }*/ 189 190 // Init player 191 192 function resetClasses() { 193 overlay.classList.remove("ended"); 194 overlay.classList.remove("paused"); 195 } 196 197 let pauseTimeout; 198 function onPlayerStateChange(event) { 199 if (DEBUG) console.log("player state change: ", ytplayer); 200 if (EXPIRED) return; 201 if (event.data == YT.PlayerState.ENDED) { 202 if (DEBUG) console.log("player state ended: ", ytplayer); 203 if (HIDING_OPTION !== "none") { 204 window.clearTimeout(pauseTimeout); 205 resetClasses(); 206 if (START_HIDING) overlay.classList.add("hidestart"); 207 ytplayer.stopVideo(); 208 } 209 } else if (event.data == YT.PlayerState.PAUSED) { 210 if (DEBUG) console.log("player state paused: ", ytplayer); 211 if (HIDING_OPTION === "full") { 212 if (PAUSE_OPTION === "partial") { 213 resetClasses(); 214 overlay.classList.add("paused"); 215 } else { 216 // PAUSE_OPTION === "full" 217 pauseTimeout = window.setTimeout(function() { 218 // We need this timeout, otherwise the click event will get stuck in the overlay and not make it to the YouTube player. 219 resetClasses(); 220 overlay.classList.add("paused"); 221 }, 0); 222 } 223 } 224 } else if (event.data == YT.PlayerState.PLAYING || event.data == YT.PlayerState.BUFFERING) { 225 if (START_HIDING) overlay.classList.remove("hidestart"); 226 window.clearTimeout(pauseTimeout); 227 // We need this timeout so that the related videos don't flicker 228 pauseTimeout = window.setTimeout(function() { 229 resetClasses(); 230 }, 100); 231 } 232 }; 233
234 function onPlayerApiChange(ch) { 235 console.log("playerapichange:", ch); 236 } 237 function onPlayerError(error) { 238 console.log("playererror:", error); 239 } 240 function onPlayerReady(event) { 241 if (DEBUG) console.log("player ready: ", ytplayer); 242 // Register YouTube Player change 243 ytplayer.addEventListener('onStateChange', onPlayerStateChange); 244 if (DEBUG) ytplayer.addEventListener('onError', onPlayerError); 245 if (DEBUG) ytplayer.addEventListener('onApiChange', onPlayerApiChange); 246 // Register overlay click 247 overlay.addEventListener("click", function() { 248 ytplayer.playVideo(); 249 }); 250 }; 251 252 if (DEBUG) console.log("player created: ", ytplayer); 253 254 if (EXPIRED && playerData.options.has_plugin_privileges) { 255 let message = document.createElement("div"); 256 message.classList.add("hytWPPlayerWrapExpired"); 257 message.innerHTML = "<p><b>HideYT Plugin License Expired</b></p><p>To continue hiding YouTube related videos, please <a href='/wp-admin/options-general.php?page=hideyt'>renew your license</a>! (This message is shown only to WordPress admins, not users)."; 258 overlay.appendChild(message); 259 } 260 261 window.theplayer = ytplayer; 262 } 263 264 window.addEventListener("message", function(msg) { 265 if (msg.data.type === "hytInit") { 266 const msgdata = msg.data.data; 267 msgdata.urlParameters.rel = "0"; // Force rel=0 268 269 // Fullscreen 270 if (msgdata.options.hideyt_field_forcefullscreen === "forceon") { 271 msgdata.urlParameters.fs = "1"; 272 } else if (msgdata.options.hideyt_field_forcefullscreen === "forceoff") { 273 msgdata.urlParameters.fs = "0"; 274 } 275 276 playerData = msgdata; 277 // Init HideYT 278 init(); 279 } 280 }, false); 281 })(); 282 283 </script> 284 <div class="hytWPOverlay"></div> 285 `; 286 287 // Disable HideYT if Thrive Architect editor is open 288 if (new URL(window.location.href).searchParams.get("tve") === "true") return; 289 290 // Returns an array all elements from array "a" that are also in array "b" 291 function arrayDiff(a, b) { 292 return a.filter(function(i) {return b.indexOf(i) < 0;}); 293 }; 294 295 // Deduplicate an array 296 function arrayUnique(array) { 297 var a = array.concat(); 298 for(var i=0; i<a.length; ++i) { 299 for(var j=i+1; j<a.length; ++j) { 300 if(a[i] === a[j]) 301 a.splice(j--, 1); 302 } 303 } 304 return a; 305 } 306 307 let iframeList = []; 308 309 function initPlayer(playerFrame) { 310 // Replace the youtube iframe with the custom hideyt iframe 311 let src; 312 if (!playerFrame.src.includes(".com/embed/") && playerFrame.dataset.src.includes(".com/embed/")) { 313 src = new URL(playerFrame.dataset.src, new URL(window.location.href)); 314 } else { 315 src = new URL(playerFrame.src, new URL(window.location.href)); 316 } 317 const hideYTFrame = playerFrame.cloneNode(false); 318 delete hideYTFrame.dataset.src; 319 hideYTFrame.style.visibility = "visible"; 320 hideYTFrame.style.opacity = "1"; 321 hideYTFrame.removeAttribute("src"); 322 const supportsSrcdoc = !!("srcdoc" in document.createElement("iframe")); 323 if (supportsSrcdoc) { 324 hideYTFrame.setAttribute("srcdoc", iframeInnerHTML); 325 } else { 326 const blob = new Blob([iframeInnerHTML], 'text/html'); 327 const blobURL = URL.createObjectURL(blob); 328 hideYTFrame.setAttribute("src", blobURL); 329 } 330 // TODO: Force frameborder, allow, allowfullscreen 331 332 playerFrame.parentNode.insertBefore(hideYTFrame, playerFrame); 333 334 playerFrame.parentNode.removeChild(playerFrame); 335
336 const playerFrameHTML = playerFrame.outerHTML; 337 338 if (DEBUG) console.log("player replaced"); 339 340 hideYTFrame.addEventListener("load", function() { 341 if (DEBUG) console.log("iframe load"); 342 343 const videoId = src.pathname.split("/").slice(-1)[0]; 344 345 // Copy url parameters to js object 346 const urlParameters = {}; 347 src.searchParams.forEach((value, key) => { 348 urlParameters[key] = value; 349 }); 350 351 // Fix elementor autoplay 352 try { 353 const elementorWidget = hideYTFrame.closest(".elementor-widget-video"); 354 if (elementorWidget) { 355 const elementorSettings = JSON.parse(elementorWidget.dataset.settings); 356 if (elementorSettings.show_image_overlay === "yes") { 357 urlParameters.autoplay = 1; 358 } 359 } 360 } catch (error) { 361 // Bail on elementor fix 362 } 363 364 hideYTFrame.contentWindow.postMessage({ 365 type: "hytInit", 366 data: { 367 options: hideyt_options, 368 videoId: videoId, 369 urlParameters: urlParameters 370 } 371 }, "*"); 372 }); 373 } 374 375 function updatePlayers() { 376 let ytiframes = Array.from(document.querySelectorAll(` 377 378 iframe[src^="https://www.youtube.com/embed/"], 379 iframe[src^="http://www.youtube.com/embed/"], 380 iframe[src^="//www.youtube.com/embed/"], 381 382 iframe[src^="https://youtube.com/embed/"], 383 iframe[src^="http://youtube.com/embed/"], 384 iframe[src^="//youtube.com/embed/"], 385 386 iframe[src^="https://www.youtube-nocookie.com/embed/"], 387 iframe[src^="http://www.youtube-nocookie.com/embed/"], 388 iframe[src^="//www.youtube-nocookie.com/embed/"], 389 390 iframe[src^="https://youtube-nocookie.com/embed/"], 391 iframe[src^="http://youtube-nocookie.com/embed/"], 392 iframe[src^="//youtube-nocookie.com/embed/"], 393 394 iframe[data-src^="https://www.youtube.com/embed/"], 395 iframe[data-src^="http://www.youtube.com/embed/"], 396 iframe[data-src^="//www.youtube.com/embed/"], 397 398 iframe[data-src^="https://youtube.com/embed/"], 399 iframe[data-src^="http://youtube.com/embed/"], 400 iframe[data-src^="//youtube.com/embed/"], 401 402 iframe[data-src^="https://www.youtube-nocookie.com/embed/"], 403 iframe[data-src^="http://www.youtube-nocookie.com/embed/"], 404 iframe[data-src^="//www.youtube-nocookie.com/embed/"], 405 406 iframe[data-src^="https://youtube-nocookie.com/embed/"], 407 iframe[data-src^="http://youtube-nocookie.com/embed/"], 408 iframe[data-src^="//youtube-nocookie.com/embed/"] 409 410 `)); 411 ytiframes = ytiframes.filter(elem => { 412 // ThemePunch / Slider Revolution background video container. 413 if (elem.closest(".rs-background-video-layer") !== null) return false; 414 415 // Slider Revolution sometimes uses IDs like sr...video; skip those embeds. 416 let id = (elem.id || "").toLowerCase(); 417 let isSliderRevolutionVideo = id.startsWith("sr") && id.endsWith("video"); 418 return !isSliderRevolutionVideo; 419 }); 420 let newFrames = arrayDiff(ytiframes, iframeList); // Now ytiframes has only the NEW iframes. 421 iframeList = arrayUnique(iframeList.concat(newFrames)); 422 423 // Init all new YouTube players 424 for (let ytiframe of newFrames) { 425 initPlayer(ytiframe) 426 } 427 } 428 429 // The updatePlayers function benchmarks at 30 microseconds for a dry poll, 430 // so there will be no jank even at a high polling rate. 431 updatePlayers(); 432 setInterval(updatePlayers, 100); 433 434})();
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.