PageSourceSearch

https://project-cult.digital/js/site-audio.js?v=cult192-exp02-polish2

js project-cult.digital collected 2026-10-06 13:36:25 UTC 5,922 bytes, 150 lines download raw bytes

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.