1'use strict'; 2(function () { 3 if (window.CultAudioRedirecting) return; 4 var host = null; 5 try { if (window.parent !== window) host = window.parent.CultPageHost; } catch (e) {} 6 if (host) { 7 var join = function () { host.bindPage(window); }; 8 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', join); 9 else join(); 10 return; 11 } 12 var KEY = 'cult-background-audio-v1'; 13 var saved = {}; 14 try { saved = JSON.parse(sessionStorage.getItem(KEY) || '{}') || {}; } catch (e) {} 15 // A pagehide ticket resumes this tab's navigation/reload, not a newly opened 16 // tab that happens to inherit a copy of sessionStorage from its opener. 17 var wanted = saved.on === true && saved.resume === true; 18 var resumeAt = Math.max(0, Number(saved.time) || 0); 19 var positioned = false; 20 var leaving = false; 21 var staleRestore = false; 22 var blocked = false; 23 var playPending = false; 24 var playGeneration = 0; 25 var lastSave = 0; 26 var controls = []; 27 var connectedDocument = null; 28 var audio = document.createElement('audio'); 29 audio.id = 'cult-background-audio'; 30 audio.hidden = true; 31 audio.loop = true; 32 audio.preload = wanted ? 'auto' : 'none'; 33 audio.setAttribute('playsinline', ''); 34 audio.src = '/music/Kanye%20West%20-%20On%20Sight.mp3'; 35 36 function save(resume) { 37 if (staleRestore) return; 38 try { 39 sessionStorage.setItem(KEY, JSON.stringify({ 40 on: wanted, time: positioned ? audio.currentTime : resumeAt, 41 resume: !!resume, savedAt: Date.now() 42 })); 43 } catch (e) {} 44 } 45 function update() { 46 controls.forEach(function (control) { 47 control.textContent = blocked && wanted ? '[play]' : wanted ? '[on]' : '[off]'; 48 control.setAttribute('aria-pressed', String(wanted && !blocked)); 49 control.setAttribute('aria-label', blocked && wanted ? 'Resume music' : wanted ? 'Pause music' : 'Play music'); 50 }); 51 } 52 function position() { 53 if (positioned || audio.readyState < 1) return; 54 try { 55 audio.currentTime = Number.isFinite(audio.duration) && audio.duration > 0 ? resumeAt % audio.duration : resumeAt; 56 positioned = true; 57 } catch (e) {} 58 } 59 function play() { 60 if (!wanted || leaving || playPending) return; 61 position(); 62 audio.preload = 'auto'; 63 // Call play() synchronously inside a user gesture when one is available. 64 playPending = true; 65 var generation = ++playGeneration; 66 var promise = audio.play(); 67 if (promise && promise.then) promise.then(function () { 68 if (generation !== playGeneration) return; 69 playPending = false; 70 if (!wanted || leaving) { audio.pause(); return; } 71 blocked = false; update(); save(false); 72 }, function () { 73 if (generation !== playGeneration) return; 74 playPending = false; 75 if (wanted && !leaving) { blocked = true; update(); } 76 }); 77 else { playPending = false; blocked = false; update(); } 78 } 79 function toggle() { 80 if (wanted && !blocked) { 81 wanted = false; blocked = false; 82 playGeneration++; playPending = false; 83 audio.pause(); update(); save(false); 84 } else { 85 wanted = true; blocked = false; 86 update(); save(false); play(); 87 } 88 } 89 audio.addEventListener('loadedmetadata', function () { position(); }); 90 audio.addEventListener('timeupdate', function () { 91 if (!leaving && performance.now() - lastSave > 1000) { lastSave = performance.now(); save(false); } 92 }); 93 audio.addEventListener('error', function () { if (wanted) { blocked = true; update(); } }); 94 window.addEventListener('pagehide', function () { save(true); leaving = true; }); 95 window.addEventListener('pageshow', function (event) { 96 if (event.persisted && window.CultPageHost) { 97 leaving = false; 98 if (wanted) play(); 99 return; 100 } 101 // The existing pageshow handlers reload bfcache restores. Do not overwrite 102 // the latest page's resume position with this old document's position. 103 if (event.persisted) { staleRestore = true; leaving = true; audio.pause(); } 104 }); 105 document.addEventListener('visibilitychange', function () { if (document.hidden && !leaving) save(false); }); 106 107 function retryOnGesture(event) { 108 if (!event.isTrusted || !wanted || !blocked || leaving) return; 109 var target = event.target; 110 if (target && target.closest && target.closest('[data-cult-sound]')) return; 111 play(); 112 } 113 function connect(doc) { 114 if (doc === connectedDocument) return; 115 if (connectedDocument) { 116 ['pointerdown', 'touchend', 'click', 'keydown'].forEach(function (type) { 117 connectedDocument.removeEventListener(type, retryOnGesture); 118 }); 119 } 120 connectedDocument = doc; 121 ['pointerdown', 'touchend', 'click', 'keydown'].forEach(function (type) { 122 doc.addEventListener(type, retryOnGesture, { passive: true }); 123 }); 124 controls = Array.from(doc.querySelectorAll('[data-cult-sound]'));
125 controls.forEach(function (control) { 126 control.setAttribute('role', 'button'); 127 control.addEventListener('click', function (event) { event.preventDefault(); toggle(); }); 128 control.addEventListener('keydown', function (event) { 129 if (event.key === ' ') { event.preventDefault(); toggle(); } 130 }); 131 }); 132 doc.querySelectorAll('[data-home-reload]').forEach(function (link) { 133 link.addEventListener('click', function (event) { 134 if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return; 135 event.preventDefault(); 136 doc.defaultView.location.reload(); 137 }); 138 }); 139 update(); 140 } 141 window.CultBackgroundAudio = { connect: connect, warm: function () { audio.preload = 'auto'; } }; 142 function init() { 143 document.body.appendChild(audio); 144 connect(document); 145 update(); save(false); 146 if (wanted) play(); 147 } 148 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init); 149 else init(); 150})();
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.