1window.YoutubeWidget = (function() { 2 'use strict'; 3 4 var ytApiLoading = false; 5 var pendingCallbacks = []; 6 7 function loadYtApi(callback) { 8 if (window.YT && window.YT.Player) { 9 callback(); 10 return; 11 } 12 pendingCallbacks.push(callback); 13 if (!ytApiLoading) { 14 ytApiLoading = true; 15 var tag = document.createElement('script'); 16 tag.src = 'https://www.youtube.com/iframe_api'; 17 var firstScript = document.getElementsByTagName('script')[0]; 18 if (firstScript && firstScript.parentNode) { 19 firstScript.parentNode.insertBefore(tag, firstScript); 20 } else { 21 (document.head || document.documentElement).appendChild(tag); 22 } 23 var prevReady = window.onYouTubeIframeAPIReady; 24 window.onYouTubeIframeAPIReady = function() { 25 if (typeof prevReady === 'function') { 26 prevReady(); 27 } 28 while (pendingCallbacks.length > 0) { 29 var cb = pendingCallbacks.shift(); 30 try { cb(); } catch (e) {} 31 } 32 }; 33 } 34 } 35 36 function bindPlayerState(iframeEl, container) { 37 loadYtApi(function() { 38 try { 39 new window.YT.Player(iframeEl, { 40 events: { 41 'onStateChange': function(event) { 42 if (event && event.data === window.YT.PlayerState.PLAYING) { 43 container.classList.add('is-playing'); 44 } else if (event && (event.data === window.YT.PlayerState.PAUSED || event.data === window.YT.PlayerState.ENDED)) { 45 container.classList.remove('is-playing'); 46 } 47 } 48 } 49 }); 50 } catch (e) { 51 // Fallback: hover and focus CSS filters remain active 52 } 53 }); 54 } 55 56 function render(element, videoId, playlistId, embedType) { 57 if (!element) return; 58 var container = element.querySelector('.youtube-player-container'); 59 if (!container) { 60 container = document.createElement('div'); 61 container.className = 'youtube-player-container video-container'; 62 element.appendChild(container); 63 } 64 65 var iframeSrc = ''; 66 if (embedType === 'playlist' && playlistId) { 67 if (videoId) { 68 iframeSrc = 'https://www.youtube-nocookie.com/embed/' + videoId + '?list=' + playlistId; 69 } else { 70 iframeSrc = 'https://www.youtube-nocookie.com/embed/videoseries?list=' + playlistId; 71 } 72 } else if (videoId) { 73 iframeSrc = 'https://www.youtube-nocookie.com/embed/' + videoId; 74 if (playlistId) { 75 iframeSrc += '?list=' + playlistId; 76 } 77 } else if (playlistId) { 78 iframeSrc = 'https://www.youtube-nocookie.com/embed/videoseries?list=' + playlistId; 79 } 80 81 if (iframeSrc) { 82 var delimiter = iframeSrc.indexOf('?') >= 0 ? '&' : '?'; 83 iframeSrc += delimiter + 'enablejsapi=1'; 84 var playerUniqueId = 'yt-player-' + Math.random().toString(36).substring(2, 9); 85 container.innerHTML = '<iframe id="' + playerUniqueId + '" src="' + iframeSrc + '" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen credentialless></iframe>'; 86 var iframeEl = container.querySelector('iframe'); 87 if (iframeEl) { 88 bindPlayerState(iframeEl, container); 89 } 90 } 91 } 92 93 function init() { 94 var elements = document.querySelectorAll('[data-youtube-id], [data-youtube-playlist-id]'); 95 elements.forEach(function(el) { 96 if (el.classList.contains('fav-collection-item-chip') || (el.closest && el.closest('.fav-collection-item-chip'))) return; 97 var videoId = el.getAttribute('data-youtube-id'); 98 var playlistId = el.getAttribute('data-youtube-playlist-id'); 99 var embedType = el.getAttribute('data-youtube-embed-type'); 100 if (videoId || playlistId) { 101 render(el, videoId, playlistId, embedType); 102 } 103 }); 104 } 105 106 return { init: init, render: render }; 107})();
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.