/* Build-local classic-script loader. The inert manifest precedes this head script. */ (function (root) { 'use strict'; const doc = root.document; let manifest; try { manifest = JSON.parse(doc.getElementById('ytp-assets').textContent); } catch { return; } // Native/static shells retain their eager script path. const assets = new Map(), groups = new Map(), hooks = new Map(); const css = new Set([...doc.querySelectorAll('link[data-lazy-css]')].map(link => link.dataset.lazyCss)); const selected = new Map(); const url = path => selected.get(path) || (manifest.files[path]?.h ? path + '?v=' + manifest.files[path].h : path); function reloadRequired(name) { api.reloadRequired = true; if (root.CustomEvent) root.dispatchEvent?.(new root.CustomEvent('ytp-reload-required', { detail: { group: name } })); } async function select(name) { if (!root.caches) return; try { const cache = await root.caches.open('ytplayer-assets'); const response = await cache.match('/__ytp_asset_state'); const current = response && (await response.json()).current; const built = manifest.groups[name], newer = current?.groups[name]; if (!newer || current.buildTag === manifest.buildTag) return; if (newer.contract !== built.contract) { reloadRequired(name); return; } for (const path of built.files) { // Membership and contract must both match the running core's expectation. if (!newer.files.includes(path) || !current.files[path]) continue; const key = path + '?v=' + current.files[path].h; const held = await cache.match(key); if (held?.headers.get('X-Asset-Hash') === current.files[path].h) selected.set(path, key); } } catch { /* Private browsing/cache eviction: keep the embedded build-local map. */ } } function inject(path) { if (assets.has(path)) return assets.get(path); const style = /\.css$/.test(path); if (style && css.has(path)) return Promise.resolve(); if (!style && !/\.js$/.test(path)) return Promise.resolve(); // workers/imports/fonts are not page scripts const task = new Promise((resolve, reject) => { const node = doc.createElement(style ? 'link' : 'script'); if (style) { node.rel = 'stylesheet'; node.href = url(path); } else { node.async = false; node.src = url(path); } node.onload = resolve; node.onerror = () => reject(new Error('Unable to load ' + path)); doc.head.append(node); }); assets.set(path, task); task.catch(() => assets.delete(path)); return task; } function load(name) { if (groups.has(name)) return groups.get(name); const group = manifest.groups[name]; if (!group) return Promise.reject(new Error('Unknown asset group: ' + name)); const task = (async () => { for (const dependency of group.dependencies || []) await load(dependency); await select(name); for (const path of group.files) if (!/-worker\.js$/.test(path)) await inject(path); for (const fn of hooks.get(name) || []) await fn(); group.executed = true; })(); groups.set(name, task); task.catch(error => { groups.delete(name); if (root.CustomEvent) root.dispatchEvent?.(new root.CustomEvent('ytp-lazy-error', { detail: { group: name, error } })); }); return task; } const api = { load, prefetch: load, loaded: name => !!manifest.groups[name]?.executed, url, manifest, layout: 'classic', reloadRequired: false, onLoad(name, fn) { const list = hooks.get(name) || []; list.push(fn); hooks.set(name, list); }, proxy(name, methods, globalName) { return Object.fromEntries(methods.map(method => [method, async (...args) => { await load(name); const target = root[globalName || name.split(':')[1]]; if (typeof target?.[method] !== 'function') throw new Error('Missing lazy method: ' + method); return target[method](...args); }])); }, intent(element, name) { if (!element) return; for (const type of ['pointerenter', 'focus', 'touchstart']) element.addEventListener(type, () => load(name).catch(() => {}), { once: true, passive: true }); }, }; root.Lazy = api; try { api.layout = JSON.parse(root.localStorage.getItem('_ytpdata') || '{}').settings?.layout || 'classic'; } catch {} doc.documentElement.dataset.layout = api.layout; const layout = manifest.groups['layout:' + api.layout] || manifest.groups['layout:classic']; if (doc.readyState === 'loading') for (const path of layout?.files || []) { if (!/\.css$/.test(path) || css.has(path)) continue; // Parser-inserted CSS blocks rendering; dynamic head links do not on all WebKit versions. css.add(path); doc.write(''); } })(typeof window !== 'undefined' ? window : globalThis);