Changeset 4c9f29a in Klonkt for src/assets/js/embed-player.js

Timestamp:
06/15/2026 03:23:14 AM (3 months ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
3e86f1c
Parents:
650b601
git-author:
roboburr <roboburr@…> (06/15/2026 03:22:47 AM)
git-committer:
roboburr <roboburr@…> (06/15/2026 03:23:14 AM)
Message:

feat: on-brand media embeds via the real player APIs

Replaces bare platform iframes with on-brand cards, powered by the
official JS APIs so play/pause/progress are in our own hands:

  • YouTube (IFrame Player API) + SoundCloud (Widget API): fully custom controls, native chrome hidden.
  • Spotify (iFrame API): our frame around it + controls (their player UI remains; restyling not possible without Premium+OAuth).
  • Shared PlaybackRegistry: mutual exclusion -- only 1 thing plays at a time (incl. the site audio player). Replaces the focus/blur heuristic with real play events (blur stays as fallback for iframe-only embeds).
  • Progressive enhancement: if an ad-blocker blocks the platform API, falls back seamlessly to the bare platform iframe (autoplay). The resting-state card is our brand for everyone.

AudioEmbedService now renders a placeholder div (data-embed-*) for YT/SC/
Spotify instead of an iframe; embed-player.js builds the card client-side.
CSP scriptSrc extended with the player API hosts.

Adversarial review (workflow) -> 6 bugs fixed: HTMX swap leak (poll timers/
adapters -> MutationObserver teardown + adapter.destroy()), javascript: URL XSS
(scheme guard in detectProvider + safeHref client-side), Spotify ended
misdetection (no more reset-to-0), ytId/server regex on exact 11, blur scope
limited to .folio-embed.

Co-Authored-By: Claude <noreply@…>

File:
1 added

Note: See TracChangeset for help on using the changeset viewer.