PageSourceSearch

https://trevorlindenfitness.com/hero-video-playlist.js?v=1

js trevorlindenfitness.com collected 2026-10-03 22:15:01 UTC 3,339 bytes, 102 lines download raw bytes

1/* Club16 hero — smooth crossfade compilation of club-area clips.
2   Two stacked <video> elements crossfade into each other so the hero
3   plays a continuous tour of the club with no hard cuts or black flashes.
4   Reduced-motion: falls back to a single looping clip, no crossfade. */
5(function () {
6  var FADE_MS = 900;
7
8  function setup() {
9    var v1 = document.querySelector('.hero-video[data-video-playlist]');
10    if (!v1) return;
11
12    var clips = (v1.dataset.videoPlaylist || '')
13      .split('|')
14      .map(function (c) { return c.trim(); })
15      .filter(Boolean);
16    if (!clips.length) return;
17
18    var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
19
20    // Reduced-motion or single clip: just loop the first clip quietly.
21    if (reduce || clips.length < 2) {
22      v1.loop = true;
23      v1.muted = true;
24      v1.src = clips[0];
25      v1.load();
26      var p0 = v1.play && v1.play();
27      if (p0 && p0.catch) p0.catch(function () {});
28      return;
29    }
30
31    // Build the crossfade partner.
32    var v2 = v1.cloneNode(false);
33    v2.removeAttribute('data-video-playlist');
34    v2.removeAttribute('poster');
35    v1.parentNode.insertBefore(v2, v1.nextSibling);
36
37    [v1, v2].forEach(function (v) {
38      v.loop = false;
39      v.muted = true;
40      v.playsInline = true;
41      v.autoplay = true;
42      v.removeAttribute('loop');
43      // inline !important beats the stylesheet's `opacity:1 !important`
44      v.style.setProperty('transition', 'opacity ' + FADE_MS + 'ms ease', 'important');
45    });
46    v1.style.setProperty('opacity', '1', 'important');
47    v2.style.setProperty('opacity', '0', 'important');
48
49    var front = v1, back = v2;
50    var idx = 0;
51    var transitioning = false;
52
53    function load(v, i) {
54      if (v.getAttribute('data-clip') === String(i)) return;
55      v.setAttribute('data-clip', String(i));
56      v.src = clips[i];
57      v.load();
58    }
59
60    function play(v) {
61      var p = v.play && v.play();
62      if (p && p.catch) p.catch(function () {});
63    }
64
65    load(front, 0);
66    play(front);
67    load(back, 1 % clips.length); // preload next
68
69    function crossfade() {
70      if (transitioning) return;
71      transitioning = true;
72      var nextIdx = (idx + 1) % clips.length;
73      load(back, nextIdx);
74      try { back.currentTime = 0; } catch (e) {}
75      play(back);
76      back.style.setProperty('opacity', '1', 'important');
77      front.style.setProperty('opacity', '0', 'important');
78      var prevFront = front;
79      front = back;
80      back = prevFront;
81      idx = nextIdx;
82      setTimeout(function () {
83        try { back.pause(); } catch (e) {}
84        load(back, (idx + 1) % clips.length); // preload following clip
85        transitioning = false;
86      }, FADE_MS + 60);
87    }
88
89    function maybeFade() {
90      if (transitioning || !front.duration) return;
91      if (front.currentTime >= front.duration - (FADE_MS / 1000) - 0.05) crossfade();
92    }
93
94    v1.addEventListener('timeupdate', maybeFade);
95    v2.addEventListener('timeupdate', maybeFade);
96    v1.addEventListener('ended', function () { if (!transitioning) crossfade(); });
97    v2.addEventListener('ended', function () { if (!transitioning) crossfade(); });
98  }
99
100  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', setup);
101  else setup();
102})();

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.