@uln/hls 0.3.1 / examples / carousel/vanilla

carousel/vanilla HLS MP4

The same strip without React, on attach + set

examples/carousel/vanilla/main.ts

import { createPlayer, type Player, playFullscreen, preload } from "@uln/hls";
import { type Film, fetchFilms, saveProgress } from "../../films";

/** The carousel without React: the same calls, wired by hand. */
const strip = document.getElementById("strip") as HTMLUListElement;
const films: Film[] = [];
const clips: Player[] = [];

const centered = new IntersectionObserver(
  (entries) => {
    for (const entry of entries) {
      // The first callback reports every card, a neighbour peeking at the edge included.
      if (entry.intersectionRatio < 0.6) continue;
      const index = [...strip.children].indexOf(entry.target);
      for (const [i, clip] of clips.entries()) {
        if (i === index) clip.play();
        else clip.pause();
      }
      preload([films[index + 1]?.clip?.url, films[index - 1]?.clip?.url, films[index + 2]?.clip?.url]);
      // Endless: three from the end, fetch the next page.
      if (index === films.length - 3) void loadMore();
    }
  },
  { root: strip, threshold: 0.6 },
);

function addCard(f: Film) {
  const card = document.createElement("li");
  card.className = "card";
  card.innerHTML = `<button type="button"><video></video><h2></h2></button>`;
  (card.querySelector("h2") as HTMLElement).textContent = f.title;
  strip.append(card);

  const clip = createPlayer();
  const filmTime = () => (f.clip ? f.clip.start + clip.state.currentTime : 0);
  if (f.clip) {
    const video = card.querySelector("video") as HTMLVideoElement;
    clip.attach({ video, src: f.clip.url, poster: f.poster });
    clip.set({ muted: true, loop: true, onPlay: () => preload(f.hls, { start: filmTime() }) });
  }
  clips.push(clip);
  card.querySelector("button")?.addEventListener("click", () => {
    playFullscreen(f.hls, { start: filmTime(), onClose: (time) => saveProgress(f.id, time) });
  });
  centered.observe(card);
}

async function loadMore() {
  const more = await fetchFilms(films.length / 10);
  films.push(...more);
  for (const f of more) addCard(f);
}

void loadMore();