Files
client/plans/vj-playlist-page.md
2026-04-17 16:52:51 -04:00

6.2 KiB

VJ Playlist Page Plan

Overview

Add playlist browsing functionality to www/vj-playlist.html (duplicated from template). The page will query Nostr events to discover past livestream shows and display their episode playlists (tracklists).

Data Model (Existing Events from vj-stream.mjs)

graph TD
    A[Show - kind 30311] -->|d tag = show slug| B[Episode]
    B -->|episode tag = timestamp ID| C[Playlist - kind 30078]
    C -->|d tag = show-playlist:slug:episodeId| D[Track Tags]
    C -->|viewers tags| E[Viewer Snapshots]
    A -->|a tag coordinate| F[30311:pubkey:slug]
    C -->|a tag = stream coordinate| F

Kind 30311 — Stream/Show Metadata

  • d tag: show slug (e.g. my-show)
  • title: show title
  • status: planned / live / ended
  • episode: episode ID (unix timestamp string)
  • episode_description: episode description
  • image: show image URL
  • streaming: HLS playlist URL
  • web: viewer page URL

Kind 30078 — Playlist Event

  • d tag: show-playlist:{slug}:{episodeId}
  • show tag: show slug
  • episode tag: episode ID
  • a tag: stream coordinate (30311:{pubkey}:{slug})
  • title tag: e.g. My Show Playlist
  • status tag: live or ended
  • episode_description tag: optional
  • track tags: [track, trackNumber, artist, title, nostrRef, isoTimestamp]
  • viewers tags: [viewers, isoTimestamp, count, variant:count...]

Architecture

The page keeps all existing template functionality (auth, sidenav, hamburger, relay UI, etc.) and adds playlist browsing in the #divBody area.

Query Strategy

  1. Discover shows: Subscribe to kind 30311 events authored by the target pubkey to find all shows
  2. Fetch playlists: Query kind 30078 events authored by the target pubkey, filtering by #show tag when a show is selected
  3. Parse and display: Extract track tags from playlist events and render as tracklists grouped by episode

Auth Mode

  • Default to optional auth mode (supports ?npub= or ?pubkey= URL params for viewing other users' playlists)
  • If no target pubkey in URL, use the logged-in user's pubkey
  • Public browsing works without login

UI Layout

┌─────────────────────────────────────────────┐
│ HEADER: VJ PLAYLISTS                        │
├─────────────────────────────────────────────┤
│                                             │
│  [Show Selector Dropdown ▼]                 │
│                                             │
│  ┌─ Episode Card ─────────────────────────┐ │
│  │ Episode: 2026-04-06 • Status: ended    │ │
│  │ Description: Saturday night session    │ │
│  │ 12 tracks • 45 viewers peak            │ │
│  │                                         │ │
│  │  # │ Artist        │ Title      │ Time  │ │
│  │ 001│ Artist Name   │ Song Title │ 20:15 │ │
│  │ 002│ Artist Name   │ Song Title │ 20:19 │ │
│  │ 003│ Artist Name   │ Song Title │ 20:23 │ │
│  │  ...                                    │ │
│  └─────────────────────────────────────────┘ │
│                                             │
│  ┌─ Episode Card ─────────────────────────┐ │
│  │ Episode: 2026-04-05 • Status: ended    │ │
│  │ (collapsed - click to expand)           │ │
│  └─────────────────────────────────────────┘ │
│                                             │
├─────────────────────────────────────────────┤
│ FOOTER                                      │
└─────────────────────────────────────────────┘

Implementation Steps

1. HTML Structure (in divBody)

Add to #divBody:

  • Show selector dropdown
  • Loading indicator
  • Container for episode playlist cards
  • Empty state message

2. Imports

Add to the existing module script:

  • queryCache and ndkFetchEvents from init-ndk.mjs (for fetching events)
  • subscribe is already imported

3. Show Discovery Logic

  • On page load, determine target pubkey (from URL params or logged-in user)
  • Query kind 30311 events for that pubkey
  • Populate show selector dropdown with discovered shows
  • Auto-select if only one show exists

4. Playlist Fetch Logic

  • When a show is selected, query kind 30078 events with authors: [targetPubkey]
  • Filter client-side by show tag matching selected show slug
  • Group by episode (from d tag pattern show-playlist:{slug}:{episodeId})
  • Sort episodes by created_at descending (newest first)
  • For addressable events (kind 30078), only the latest version per d tag is kept

5. Playlist Rendering

  • Render each episode as a collapsible card
  • Parse track tags into a table: track number, artist, title, timestamp
  • Parse viewers tags to show peak viewer count
  • Show episode metadata: episode ID (formatted as date), status, description
  • First/newest episode expanded by default, rest collapsed

6. Styling

  • Episode cards styled consistently with existing app design (border, border-radius, secondary-color background)
  • Track table with monospace numbering
  • Responsive: stack on mobile
  • Dark mode compatible via CSS variables

7. URL Parameter Support

  • ?npub=... or ?pubkey=... — view another user's playlists
  • ?show=... — pre-select a specific show slug
  • Auth mode defaults to optional when target pubkey is in URL

Files Modified

File Changes
www/vj-playlist.html Add HTML structure, styles, and JS logic for playlist browsing

No new JS modules needed — all logic fits inline in the page script, using existing init-ndk.mjs exports (subscribe, queryCache, ndkFetchEvents).