docs: move iframe player and backward seek to COMPLETED.md
This commit is contained in:
@@ -6,6 +6,35 @@ Newest entries at the top. Group by phase/wave header (mirroring `PLAN.md` / `CM
|
||||
|
||||
---
|
||||
|
||||
## Embeddable iframe player
|
||||
|
||||
**Status:** Feature complete on 2026-06-07 (commit `c83b132 feature: Embed Frame Player`, merged to dev).
|
||||
|
||||
A standalone, chrome-free player surface intended for embedding in an `<iframe>` on external pages (e.g. a Bandcamp-style "play this track here" widget on a third-party blog or the collective's socials). Distinct from the dock player, which lives inside the full site chrome.
|
||||
|
||||
**Shape as implemented:**
|
||||
|
||||
- `Layout/EmbedLayout.razor` — a minimal layout: `MudThemeProvider` + `AudioPlayerProvider` wrapping `@Body`, with no nav, menu, or marketing chrome. Reuses the dark-mode `PersistentComponentState` round-trip (`CONTEXT.md §3.6`) so an embedded player still honours the theme.
|
||||
- `Pages/FramePlayer.razor` — routed at `/FramePlayer`, uses `EmbedLayout`, renders a single `<AudioPlayerBar Fixed />`. Reads a `TrackEntryKey` from the query string and auto-selects that track on load.
|
||||
- `Services/ITrackDataService.cs` + `TrackClientDataService.cs` — a new track-metadata fetch seam (`GetPage` + `GetTrack(trackId)`) so a component can resolve a single track by key without the gallery VM. Render-mode-agnostic (one seam, SSR and WASM both served by it).
|
||||
|
||||
**Why it matters:** An embeddable player turns every external mention of a DeepDrft track into a play surface. It is the lightest-weight distribution lever the product has — no app install, no account, just a link that plays. Fits the collective's "get the music in front of people" posture.
|
||||
|
||||
**Deferred:** CORS for arbitrary external embedders — handle when a concrete external host requires it.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1.1 — Backward seek
|
||||
|
||||
**Status:** Landed on 2026-06-07 (commits `daa334a`, `8581103` on seek-fix branch, merged to dev).
|
||||
|
||||
- **What:** Seeking to a position *below* `playbackOffset` currently clamps silently to the start of the in-memory buffer segment instead of going to the user's chosen time. The forward "seek beyond buffer" path already exists in `WavOffsetService` + the client's offset-request path; backward seek is the missing mirror.
|
||||
- **Why it matters:** The single highest-impact missing feature in the player. Scrub-bar drags backward feel broken — they appear to seek but land in the wrong place.
|
||||
- **Shape:** Reuse the existing `GET api/track/{id}?offset=` pathway. The client decision becomes "is the target inside the decoded window?" — if yes, jump within the buffer (existing behaviour); if no (forward or backward), tear down the decoder and re-request from the byte-aligned offset.
|
||||
- **Implementation:** `WaveformSeeker` control supports both forward and backward seeking. The seek logic decides whether to jump within the decoded buffer or tear down and re-request from a byte-aligned offset regardless of direction. Backward seek observes the same `blockAlign` rounding-down as forward seek (enforced in `WavOffsetService.alignedOffset` and `StreamDecoder.calculateByteOffset`). Teardown/reinit respects the generation-counter pattern introduced by the concurrent-seek fix.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6 — Responsive home page (mobile layout)
|
||||
|
||||
**Status:** All six slices landed on 2026-06-07 (branches `home-mobile-grid`, `home-mobile-hero`, `home-mobile-cta`, merged to dev).
|
||||
|
||||
@@ -6,28 +6,6 @@ Organised by **theme**, not by date. Themes are roughly ordered by current produ
|
||||
|
||||
---
|
||||
|
||||
## In-flight — Embeddable iframe player
|
||||
|
||||
A standalone, chrome-free player surface intended for embedding in an `<iframe>` on external pages (e.g. a Bandcamp-style "play this track here" widget on a third-party blog or the collective's socials). Distinct from the dock player, which lives inside the full site chrome.
|
||||
|
||||
**Shape as it stands in the working tree (`[in-progress]`, code is partial and does not yet compile):**
|
||||
|
||||
- `Layout/EmbedLayout.razor` — a minimal layout: `MudThemeProvider` + `AudioPlayerProvider` wrapping `@Body`, with no nav, menu, or marketing chrome. Reuses the dark-mode `PersistentComponentState` round-trip (`CONTEXT.md §3.6`) so an embedded player still honours the theme.
|
||||
- `Pages/FramePlayer.razor` — routed at `/FramePlayer`, uses `EmbedLayout`, renders a single `<AudioPlayerBar Fixed />`. Reads a `TrackEntryKey` from the query string and is meant to auto-select that track on load.
|
||||
- `Services/ITrackDataService.cs` + `TrackClientDataService.cs` — a new track-metadata fetch seam (`GetPage` + a new `GetTrack(trackId)`) so a component can resolve a single track by key without the gallery VM. Intended to be render-mode-agnostic (one seam, SSR and WASM both served by it).
|
||||
|
||||
**Why it matters:** An embeddable player turns every external mention of a DeepDrft track into a play surface. It is the lightest-weight distribution lever the product has — no app install, no account, just a link that plays. Fits the collective's "get the music in front of people" posture.
|
||||
|
||||
**Open questions (unresolved — surface to Daniel before this lands):**
|
||||
- **Is this a committed direction or an experiment?** The code is a partial spike. Confirm before scoping the rest.
|
||||
- **Track addressing.** `FramePlayer` keys off `TrackEntryKey` (the FileDatabase entry key), but `ITrackDataService.GetTrack(string trackId)` is ambiguous about whether the argument is the SQL `Id` or the `EntryKey`. The two ID spaces (`CONTEXT.md §3.4`) need to be reconciled before the lookup is correct.
|
||||
- **`AudioPlayerBar` reuse vs. a dedicated embed control.** The `FramePlayer` TODO comment proposes "an iframe-compatible player using the AudioPlayerControl." Decide whether the embed reuses the full dock bar (current approach) or a stripped single-track control.
|
||||
- **Embedding security.** A public iframe surface implies decisions about `X-Frame-Options` / CSP `frame-ancestors`, and whether the unauthenticated `GET api/track/{id}` stream is acceptable to expose from arbitrary origins (it already is unauthenticated, but embedding makes the exposure explicit).
|
||||
|
||||
`[in-progress]` — capture the design decisions in a product note when Daniel confirms the direction.
|
||||
|
||||
---
|
||||
|
||||
## 0. Baseline — what just landed
|
||||
|
||||
A two-part audit (design + streaming) ran on 2026-05-17 and the fixes for Critical, Major, and Minor findings are now on `dev`. The remainder of this plan assumes that baseline. In summary the audit-pass fixed:
|
||||
@@ -45,14 +23,6 @@ What this means for the roadmap: the streaming substrate is solid. Future work c
|
||||
|
||||
These were flagged during the audit but classified as feature work, not defect fixes. They are listed in rough order of user-visible impact.
|
||||
|
||||
### 1.1 Backward seek
|
||||
|
||||
- **What:** Seeking to a position *below* `playbackOffset` currently clamps silently to the start of the in-memory buffer segment instead of going to the user's chosen time. The forward "seek beyond buffer" path already exists in `WavOffsetService` + the client's offset-request path; backward seek is the missing mirror.
|
||||
- **Why it matters:** The single highest-impact missing feature in the player. Scrub-bar drags backward feel broken — they appear to seek but land in the wrong place.
|
||||
- **Shape:** Reuse the existing `GET api/track/{id}?offset=` pathway. The client decision becomes "is the target inside the decoded window?" — if yes, jump within the buffer (existing behaviour); if no (forward or backward), tear down the decoder and re-request from the byte-aligned offset.
|
||||
- **Prerequisite:** None — the substrate exists.
|
||||
- **Constraint:** Backward seek must observe the same `blockAlign` rounding-down as forward seek (already enforced in `WavOffsetService.alignedOffset` and `StreamDecoder.calculateByteOffset`). The teardown/reinit must respect the generation-counter pattern introduced by the concurrent-seek fix.
|
||||
|
||||
### 1.2 Audio format diversity
|
||||
|
||||
- **What:** Today `AudioProcessor`, `WavOffsetService`, and the JS decoder are PCM/WAV-only. `MimeTypeExtensions` already maps MP3, FLAC, Ogg, AAC, M4A — none are wired.
|
||||
|
||||
Reference in New Issue
Block a user