1(function () { 2 // --- util: esperar a que existan selectores (hasta timeout) --- 3 function waitForSelectors(selectors, interval = 120, timeout = 8000) { 4 return new Promise((resolve) => { 5 const stopAt = Date.now() + timeout; 6 (function check() { 7 const results = selectors.map(s => Array.from(document.querySelectorAll(s))); 8 const allFound = results.every(nodes => nodes.length > 0); 9 if (allFound) { 10 resolve(results); 11 } else if (Date.now() > stopAt) { 12 resolve(results); 13 } else { 14 setTimeout(check, interval); 15 } 16 })(); 17 }); 18 } 19 20 // --- util: cargar API de YouTube --- 21 function loadYouTubeIframeAPI() { 22 return new Promise((resolve, reject) => { 23 if (window.YT && window.YT.Player) return resolve(window.YT); 24 25 if (!document.querySelector('script[src="https://www.youtube.com/iframe_api"]')) { 26 const tag = document.createElement('script'); 27 tag.src = "https://www.youtube.com/iframe_api"; 28 tag.async = true; 29 tag.onerror = () => reject(new Error('Error cargando YouTube Iframe API')); 30 document.head.appendChild(tag); 31 } 32 33 const previous = window.onYouTubeIframeAPIReady; 34 window.onYouTubeIframeAPIReady = function () { 35 if (typeof previous === 'function') { 36 try { previous(); } catch (e) { console.warn('previous onYouTubeIframeAPIReady failed', e); } 37 } 38 resolve(window.YT); 39 }; 40 41 setTimeout(() => { 42 if (window.YT && window.YT.Player) resolve(window.YT); 43 }, 1000); 44 }); 45 } 46 47 // --- Variables globales --- 48 let currentIndex = 0; 49 let ytPlayer = null; 50 let container = null; 51 52 function destroyYTPlayer() { 53 if (ytPlayer && typeof ytPlayer.destroy === 'function') { 54 try { ytPlayer.destroy(); } catch (e) { console.warn('Error destruyendo YT player', e); } 55 ytPlayer = null; 56 } 57 } 58 59 // --- reproducir video por ÃÆÃâÃâÃÂndice --- 60 function playVideo(index) { 61 const playlistItems = Array.from(document.querySelectorAll('.playlist')); 62 if (index < 0 || index >= playlistItems.length) return; 63 currentIndex = index; 64 65 const item = playlistItems[index]; 66 const videoId = item.getAttribute('data-video-id'); 67 const type = item.getAttribute('data-type') || 'local'; 68 69 if (!container) container = document.getElementById('video-container'); 70 if (!container) return; 71 container.innerHTML = ""; 72 73 destroyYTPlayer(); 74 75 if (type === "youtube") { 76 const div = document.createElement("div"); 77 div.id = "yt-player"; 78 div.style.cssText = "width:100%;height:100%;border-radius:1.5em;overflow:hidden;"; 79 container.appendChild(div); 80 81 if (window.YT && window.YT.Player) { 82 ytPlayer = new YT.Player("yt-player", { 83 height: "100%", 84 width: "100%", 85 videoId: videoId, 86 playerVars: { autoplay: 1, controls: 1, rel: 0 }, 87 events: { 88 'onReady': (e) => { try { e.target.playVideo(); } catch (err) {} }, 89 'onStateChange': (event) => { 90 if (event.data === YT.PlayerState.ENDED) playVideo(currentIndex + 1); 91 } 92 } 93 }); 94 } 95 } else { 96 const video = document.createElement("video"); 97 video.src = videoId; 98 video.controls = true; 99 video.autoplay = true; 100 video.playsInline = true; 101 video.style.cssText = "width:100%;height:80vh;border-radius:1.5em;background:#000;"; 102 video.addEventListener("ended", () => playVideo(currentIndex + 1)); 103 container.appendChild(video); 104 105 const playPromise = video.play(); 106 if (playPromise !== undefined) { 107 playPromise.catch(() => { 108 video.muted = true; 109 video.play().catch(() => { 110 console.warn('Autoplay bloqueado en video local ̢̢̮ââ¬Å¡Ã¬Ã¢ââ¬Ã el usuario deberÃÆÃâÃâá pulsar play'); 111 }); 112 }); 113 } 114 } 115 } 116 117 // --- Inicializar playlist --- 118 function initializePlaylist() { 119 container = document.getElementById('video-container'); 120 const playlistItems = Array.from(document.querySelectorAll('.playlist'));
121 const intro = document.getElementById('intro-video'); 122 123 if (!container || playlistItems.length === 0) { 124 console.warn('initializePlaylist: elementos necesarios no encontrados'); 125 return; 126 } 127 128 if (!window.__playlist_click_delegated) { 129 document.addEventListener('click', (e) => { 130 const item = e.target.closest('.playlist'); 131 if (!item) return; 132 const items = Array.from(document.querySelectorAll('.playlist')); 133 const idx = items.indexOf(item); 134 if (idx >= 0) playVideo(idx); 135 }); 136 window.__playlist_click_delegated = true; 137 } 138 139 if (intro && !intro.__playlistBound) { 140 intro.addEventListener('ended', () => { 141 playVideo(0); 142 }); 143 intro.__playlistBound = true; 144 } 145 146 if (!window.__video_click_delegated) { 147 document.addEventListener('click', (e) => { 148 const v = e.target.closest('.video'); 149 if (!v) return; 150 try { if (v.paused) v.play(); } catch (err) {} 151 }); 152 window.__video_click_delegated = true; 153 } 154 155 console.log('Playlist inicializada con', playlistItems.length, 'items'); 156 } 157 158 // --- Punto de entrada --- 159 async function start() { 160 try { 161 if (document.readyState === 'loading') { 162 await new Promise(res => document.addEventListener('DOMContentLoaded', res)); 163 } 164 const apiPromise = loadYouTubeIframeAPI(); 165 const [containers, playlists] = await waitForSelectors(['#video-container', '.playlist'], 120, 7000); 166 167 if ((containers.length === 0) || (playlists.length === 0)) { 168 const obs = new MutationObserver((mutations, observer) => { 169 const c = document.getElementById('video-container'); 170 const p = document.querySelectorAll('.playlist'); 171 if (c && p && p.length > 0) { 172 observer.disconnect(); 173 initializePlaylist(); 174 } 175 }); 176 obs.observe(document.body, { childList: true, subtree: true }); 177 } else { 178 await apiPromise.catch(err => console.warn('YouTube API fallo:', err)); 179 initializePlaylist(); 180 } 181 } catch (err) { 182 console.error('Error en start():', err); 183 } 184 } 185 186 start(); 187 188 189document.querySelectorAll(".tab_inf_in").forEach(el => { 190 el.addEventListener("click", function() { 191 const destino = document.querySelector(".btn_despl_hero"); 192 if (destino) { 193 // scroll inicial al destino 194 destino.scrollIntoView({ behavior: "smooth", block: "start" }); 195 196 // aplicar desplazamiento suave hacia arriba luego 197 setTimeout(() => { 198 window.scrollTo({ 199 top: window.scrollY - 100, // sube 100px, ajusta a tu gusto 200 behavior: "smooth" 201 }); 202 }, 0); 203 } 204 205 // re-inicializar el contenido del tab 206 setTimeout(() => { initializePlaylist(); }, 600); 207 }); 208}); 209 210 document.querySelectorAll('.tab_inf_in.active').forEach(el => { 211 el.classList.remove('active'); 212 }); 213 214 215})(); 216 217(function(c,l,a,r,i,t,y){ 218 c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)}; 219 t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; 220 y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); 221 })(window, document, "clarity", "script", "r478otvvis");
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.