refactor: delegate Miruro playback resolution to Terebi
This commit is contained in:
+9
-20
@@ -2,13 +2,13 @@
|
||||
|
||||
Investigated **2026-10-22**, scoped to **https://barelystarted.miruro.tv**. Investigation only: no production changes, media playback, playlist/segment/subtitle downloads, browser testing, or remote mutations.
|
||||
|
||||
**Conclusion:** Miruro supplies episode-relative opening/ending intervals, but **Terebi cannot consume them today**. Tubular retains them while browsing, then drops them before the source-file handoff; Terebi silently ignores an added `segments` property. Both sides need an explicit contract change. Availability is sparse, and timing must be checked against the selected stream's actual duration; alignment across different cuts remains unproven.
|
||||
**Conclusion (updated after the approved ownership split):** Miruro supplies optional episode-relative opening/ending intervals. Terebi must acquire and display them through its native episode-URL resolver; Tubular owns catalog/selection/collections/watched decisions only. Current Terebi does not display these intervals. The former source-file recommendation below is superseded by the [URL-playback handoff](terebi-url-playback-handoff.md). Availability is sparse; actual media-duration bounds are necessary but do not prove alignment across cuts.
|
||||
|
||||
Evidence labels: **Observed** = responses obtained today; **Frontend** = today's deployed first-party JavaScript, not a server guarantee; **Earlier** = the 2026-10-12 investigation in [miruro-api.md](miruro-api.md); **Recommendation** = proposed minimum behavior, not implemented.
|
||||
|
||||
## Live metadata
|
||||
|
||||
**Observed — native Tubular probe:** the actual `Client::detail`, `Client::sources`, and `SourceDocument::from_sources` path ran against the [detail route][detail] and [sources endpoint][sources]. The temporary example was removed afterward; `cargo run --locked --example miruro_segments_probe` describes that investigation, **not a permanent runnable command**. Safe output projection:
|
||||
**Observed — historical native Tubular probe before URL cutover:** the then-existing `Client::detail`, `Client::sources`, and `SourceDocument::from_sources` path ran against the [detail route][detail] and [sources endpoint][sources]. The temporary example was removed afterward; `cargo run --locked --example miruro_segments_probe` describes that investigation, **not a permanent runnable command**. Source resolution/projection has since been removed from Tubular. Safe output projection:
|
||||
|
||||
```text
|
||||
detail: 3 episodes
|
||||
@@ -74,23 +74,18 @@ Useful anchors in the minified [bundle][client]: `Cn=.05`, `function wn`, `provi
|
||||
|
||||
- **Observed:** metadata exists and is not tied to an expiring source URL. **Unknown:** coverage across the catalog, a stable/public metadata contract, how timings were generated, non-opening/ending availability, and alignment across providers/dubs/cuts. Merely being in bounds does not prove synchronization with a particular cut.
|
||||
- **Recommendation:** reuse the existing detail episode metadata; retain selected episode identity, optional raw kinds, and fractional second boundaries alongside it. Normalize only the four evidenced opening/ending kinds for initial intro/outro behavior. Do not relabel recap or unknown kinds as intro/outro or invent missing intervals.
|
||||
- **Recommendation:** use the existing Terebi source-session handoff if its contract can carry the metadata, validating finite/nonnegative/ordered intervals and actual media-duration bounds at the playback boundary. Preserve optional provenance/reference-length fields if they become available; do not claim the sample has them or that the deployed frontend's optional checks guarantee cross-provider synchronization. No new endpoint, media download, clock-based heuristic, or separate segment lookup service is justified by this evidence.
|
||||
- **Approved seam (supersedes the earlier source-session recommendation):** Terebi's existing episode-URL resolver owns optional metadata acquisition and validation against actual media duration. Direct and Tubular launches must use the same path. No source-document version change, separate segment file, new endpoint or Tubular metadata persistence is required. Preserve optional provenance/reference-length fields if available; do not invent fields absent from the sample or claim bounds prove synchronization.
|
||||
- **Recommendation:** address every launch path, including saved/watch-later/currently-watching reopening, rather than enriching only a currently open catalog episode.
|
||||
|
||||
## Tubular → Terebi boundary
|
||||
## Tubular → Terebi seam
|
||||
|
||||
### Where Tubular loses the metadata
|
||||
The approved implementation contract and acceptance scenarios are consolidated in [Terebi URL-playback handoff](terebi-url-playback-handoff.md). Tubular launches the stable opaque ID and returned episode number through `PlayerLaunch::start`, using a non-identifying `episode` watch slug. Old/offline snapshots need no new fields or migration. Terebi owns canonical-route resolution, title enrichment and optional timeline metadata; title text is not identity.
|
||||
|
||||
1. [`Client::detail`](../src/miruro.rs#L321) decodes raw episode records, including `skip_times`. [`series`](../src/miruro_browser.rs#L238) retains them in `Episode.metadata`; no additional upstream request is needed while browsing an already-loaded series.
|
||||
2. [`Episode::snapshot`](../src/miruro_browser.rs#L29) projects the selected episode into a generic `Video`, without segment metadata. [`Screen::selected_video`](../src/miruro_ui.rs#L145) uses that snapshot for series playback; offline collections already contain only `Video` snapshots.
|
||||
3. [`open`](../src/miruro_ui.rs#L522) submits `Request::Source(Video)`. The [worker](../src/miruro_browser.rs#L87) calls [`Client::source_document`](../src/miruro.rs#L362), which fetches only `/api/sources`. It cannot reconstruct the missing intervals from that response.
|
||||
4. [`SourceDocument`](../src/miruro.rs#L90) has no segment field. [`State::miruro_session`](../src/video_state.rs#L379) serializes it into the existing private `source.json`; that transport can be reused once both contracts change. No new CLI argument or separate segment file is needed.
|
||||
The requested UI is **intro/outro bands in the controls progress bar only**, not automatic skipping or skip buttons. Validate episode binding, finite ordered nonnegative times and actual-duration bounds; clear metadata on media replacement. Empty, unavailable or invalid metadata must not prevent ordinary playback, and unknown kinds must not be relabeled.
|
||||
|
||||
**Recommendation:** preserve episode-bound metadata through the shared source-resolution path, not a series-screen-only patch. Offline episode snapshots lack both skip metadata and a canonical route slug; adoption must retain enough metadata/route information to refresh them or deliberately store the episode metadata for those launches. Do not guess a slug from the combined episode display title or confuse `episode_number` with `absolute_number`.
|
||||
### Historical source-file decoder evidence (superseded transport)
|
||||
|
||||
### What Terebi needs
|
||||
|
||||
The current [source-v1 contract](../../terebi/docs/miruro-playback-handoff.md#source-document-version-1) contains no semantic intervals and explicitly lists intro/outro controls as out of scope. [`ResolvedSource.Document`](../../terebi/Sources/App/ResolvedSource.swift#L38) decodes only version, URL, headers, identity, title and subtitles. [`validated`](../../terebi/Sources/App/ResolvedSource.swift#L84) requires version 1 and constructs a runtime source without segments.
|
||||
Before this cutover, Tubular retained `skip_times` in browsing metadata but omitted it from generic `Video` snapshots and source documents. Terebi's source-v1 decoder did not retain intervals. The following isolated decoder observation explains why adding JSON fields alone would not have implemented timeline display; it is not a recommendation to restore source files.
|
||||
|
||||
**Observed — actual decoder smoke:** compiled the existing `ResolvedSource.swift` with a temporary Foundation-only harness, then called `ResolvedSource.load(from:)` on synthetic local source documents. No player/network/GUI was started.
|
||||
|
||||
@@ -102,13 +97,7 @@ version-2: rejected
|
||||
|
||||
Thus merely adding `segments` to a version-1 JSON file would silently discard it, even with a malformed value. Changing the version alone also does not work. This is a source-document version, independent of the existing version-2 progress records.
|
||||
|
||||
**Minimum implementation sequence — recommendation, not implemented:**
|
||||
|
||||
1. Agree and implement a new source-document version in Terebi with optional episode-relative intervals: kind and fractional-second start/end. Define missing/empty metadata, allowed kinds, limits and invalid-interval handling. A version gate prevents old players from silently claiming support; keep the existing private file and identity contract.
|
||||
2. Retain intervals in Terebi's resolved runtime source and playback lifecycle; clear them on media replacement and check them against actual duration. For skip controls, reuse existing acknowledged seeking rather than creating another playback clock. [`finishSeeking` and `seekRelative`](../../terebi/Sources/App/TerebiApp.swift#L690) already route seeks through native/Cast behavior; there is no semantic intro/outro action today. Automatic skipping is a separate behavior decision, not required to transport metadata.
|
||||
3. Update Tubular's projection/validation and every launch path to emit the agreed contract. Preserve unknown metadata without turning it into a skip action; empty intervals must not block ordinary playback. Add consumer-visible checks for wrong-episode metadata, invalid bounds and media replacement when implementing.
|
||||
|
||||
Terebi's own [episode-URL resolver](../../terebi/Sources/App/StreamResolver.swift#L103) also uses only `/api/sources` and would need metadata acquisition separately if that entry point is included in a future feature. External source-file support alone would not make native URL resolution segment-aware.
|
||||
The earlier recommendation to introduce a new source-document version and carry intervals through Tubular is **superseded**. No source-v2 or segment file is required. Terebi's native URL resolver already owns `/api/sources`; it must additionally acquire title and optional episode metadata via canonical route data for all callers. See the handoff for lifecycle and acceptance requirements. Existing source-v1 decoder observations above remain historical evidence only.
|
||||
|
||||
|
||||
## Fetch record
|
||||
|
||||
Reference in New Issue
Block a user