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

7.8 KiB

Music Player Page — Nostr-Based Music Search & Play

Goal

Integrate the working greyscale PoC music search/playback into the client template system as music.html, matching the project's monochrome aesthetic (CSS variables, monospace fonts, grayscale images, .btn class, etc.).

Architecture

flowchart TB
    subgraph www - music.html
        HTML[music.html - template-based page]
        STYLE[page-specific style block]
        INLINE[inline module script - glue code]
    end
    subgraph www/js - reusable modules
        API[js/greyscale-api.mjs - search + streaming API]
        PLAYER[js/greyscale-player.mjs - audio + dash.js playback]
        NDK[js/init-ndk.mjs - auth + worker]
    end
    subgraph External
        CDN[dash.js CDN]
        TIDAL[Tidal API instances]
        UPTIME[Uptime workers - instance list]
    end
    subgraph Shared
        CSS[css/client.css - global styles + variables]
        NOSTR[nostr.bundle.js + nostr-lite.js]
    end
    HTML --> CSS
    HTML --> NOSTR
    HTML --> CDN
    INLINE --> API
    INLINE --> PLAYER
    INLINE --> NDK
    API -->|fetch| UPTIME
    API -->|fetch| TIDAL
    PLAYER -->|uses| CDN

Key Design Decisions

1. Copy api.js and player.js as .mjs modules into www/js/

The greyscale PoC files (greyscale/greyscale-app/js/api.js and player.js) are already self-contained ES modules with zero dependencies (except dash.js global for player). We copy them into www/js/ as:

  • www/js/greyscale-api.mjs — renamed to .mjs to match project convention
  • www/js/greyscale-player.mjs — renamed to .mjs to match project convention

No code changes needed to these files — they export GreyscaleAPI and SimplePlayer classes that work as-is.

2. Use the template layout, not the greyscale layout

The greyscale PoC has its own style.css with a different dark theme. We discard that entirely and use:

  • client.css global styles (CSS variables, .btn class, monospace fonts)
  • Page-specific <style> block in music.html for music-specific elements
  • All colors via CSS variables (--primary-color, --secondary-color, --accent-color, --muted-color, --border-color)
  • No hardcoded colors

The template already has a fixed #divFooter for relay status. The music player bar will be positioned at the bottom of #divBody using flexbox, keeping the standard footer intact. The #divBody layout will be overridden to flex-direction: column with the search area scrollable and the player bar pinned at the bottom.

4. Search UI follows project conventions

  • Search input uses var(--font-family), var(--border-color), etc.
  • Search button uses the .btn class from client.css
  • Results list uses var(--border-color) borders, var(--muted-color) for secondary text
  • Cover art images get the standard grayscale filter from client.css (img rule already applies globally)

Page Layout

┌─────────────────────────────────────────┐
│  ☰  [header]                            │  ← #divHeader (standard)
├─────────────────────────────────────────┤
│                                         │
│  [Search input...............] [Search] │  ← search form
│  Status: Ready.                         │  ← status text
│                                         │
│  ┌─────────────────────────────────┐    │
│  │ [img] Track Title        3:42   │    │  ← results list (scrollable)
│  │       Artist — Album            │    │
│  ├─────────────────────────────────┤    │
│  │ [img] Track Title        4:15   │    │
│  │       Artist — Album            │    │
│  └─────────────────────────────────┘    │
│                                         │
│─────────────────────────────────────────│
│ [img] Title    [◀][▶/❚❚][▶▶]          │  ← player bar (pinned bottom)
│       Artist   0:00 ═══════○═══ 3:42   │
├─────────────────────────────────────────┤
│  [relay dots]  [center]  [right] [sats] │  ← #divFooter (standard)
└─────────────────────────────────────────┘

Implementation Steps

Step 1: Copy greyscale modules to www/js/

Copy greyscale/greyscale-app/js/api.jswww/js/greyscale-api.mjs Copy greyscale/greyscale-app/js/player.jswww/js/greyscale-player.mjs

No modifications needed — these are already clean ES modules.

Step 2: Update music.html — Head section

  • Change <title> from "TEMPLATE" to "Music"
  • Add dash.js CDN script: <script src="https://cdn.dashjs.org/latest/dash.all.min.js"></script>

Step 3: Update music.html — Add <style> block

Page-specific styles following the CSS placement rules:

  • Override #divBody to flex-direction: column; flex-wrap: nowrap;
  • Style the search form (.music-search-form) — grid layout with input + .btn
  • Style the status text (.music-status)
  • Style the results list (.music-results) — bordered list with hover states
  • Style result items (.music-result-item) — grid: cover image + meta + duration
  • Style the player bar (.music-player-bar) — pinned to bottom of #divBody
  • Style player controls and progress bar
  • All colors use CSS variables only
  • Responsive: stack player bar vertically on narrow screens

Step 4: Update music.html — Add HTML content in #divBody

Add inside #divBody:

  1. Search section — form with input + .btn button + status paragraph
  2. Results section — scrollable <ul> for track results
  3. Player bar — cover image, track info, prev/play-pause/next buttons, progress slider with time displays
  4. Hidden audio element<audio id="music-audio" preload="metadata"></audio>

Step 5: Update music.html — Add inline module script

Wire everything together in the existing <script type="module"> block:

  1. Import GreyscaleAPI from ./js/greyscale-api.mjs
  2. Import SimplePlayer from ./js/greyscale-player.mjs
  3. After NDK init completes, initialize the greyscale API (api.initInstances())
  4. Create SimplePlayer instance bound to audio element and progress controls
  5. Set up search form submit handler → api.searchTracks() → render results
  6. Set up result click handler → player.setQueue() + player.playCurrent()
  7. Set up play/pause, next, prev button handlers
  8. Set up player.onTrackChanged callback to update player bar metadata

This is essentially the same logic as greyscale/greyscale-app/js/app.js but inlined into the template's module script, alongside the existing NDK/hamburger/sidenav/footer code.

Step 6: Test

  • Verify search works
  • Verify track playback works (both direct URL and DASH streams)
  • Verify player controls (play/pause, next, prev, progress scrubbing)
  • Verify light/dark mode theming
  • Verify responsive layout on narrow screens
  • Verify standard template features still work (hamburger, sidenav, relay status, logout)

Files Changed

File Action Description
www/js/greyscale-api.mjs New Copy of greyscale/greyscale-app/js/api.js
www/js/greyscale-player.mjs New Copy of greyscale/greyscale-app/js/player.js
www/music.html Modified Add title, styles, HTML content, dash.js CDN, music glue code