feat: enrich Miruro URL playback metadata and timeline
This commit is contained in:
@@ -4,25 +4,38 @@
|
||||
|
||||
Terebi now supports resolved Miruro HTTP(S) sources with per-source headers, external WebVTT and stable episode progress. Direct **`ssub` / `sun`** playback was exercised with a freshly resolved source: native video/audio advanced, default English subtitles loaded, and the model's cue text matched expected subtitles after forward and backward acknowledged seeks. The user also reported that visible playback appears to work; this is not a comprehensive visual synchronization sign-off.
|
||||
|
||||
Tubular's existing source-file/progress-file handoff remains supported unchanged. Terebi also accepts explicit Miruro episode page URLs through Open Stream, drop, CLI and URL events; that path resolves into the same validated source representation without re-resolving externally supplied source files.
|
||||
Tubular launches native episode URLs. Terebi resolves fresh direct sources and independently acquires optional descriptive titles and opening/ending metadata. Metadata never gates source playback: missing or invalid enrichment retains a generic title and no bands.
|
||||
|
||||
## Ownership
|
||||
|
||||
- **Tubular:** discovery, episode/provider/language selection, fresh source resolution, source-document creation, session cleanup and watched-state decisions.
|
||||
- **Terebi:** native playback, Cast discovery/control and LAN delivery, request-header propagation, subtitle loading/selection/rendering, stable-identity bookmarks and acknowledged progress reporting.
|
||||
- **Tubular:** catalog/detail browsing, actual returned episode selection, collections, private reporting sessions, cleanup and watched-state decisions.
|
||||
- **Terebi:** episode-URL validation, fresh source resolution, headers/subtitles, titles, optional timeline bands, stable-identity resume and progress reporting.
|
||||
|
||||
Native episode URL resolution uses Miruro's source endpoint and the same direct ssub/Sun selection as Tubular. No catalog browsing, `strm.cx` embedding, cookies, impersonation or protection-bypass machinery is used.
|
||||
Native source resolution selects direct **`ssub` / `sun`**. Other providers, iframe embedding, cookies, impersonation and protection-bypass machinery are not supported.
|
||||
|
||||
## Launch contract
|
||||
|
||||
```sh
|
||||
terebi --new-instance --source-file '/private/session/source.json' \
|
||||
terebi --new-instance \
|
||||
--url 'https://barelystarted.miruro.tv/watch/OPAQUE_ID/episode?ep=1' \
|
||||
--progress-file '/private/session/progress.jsonl'
|
||||
```
|
||||
|
||||
`--source-file` requires `--new-instance`; `--progress-file` is optional and retains its existing behavior. Relative paths resolve against the invoking shell's directory. Each launch creates an independent player; the CLI passes absolute paths to the GUI, not media URLs/header values in arguments.
|
||||
The slug `episode` is deliberately non-identifying. Use the returned episode number, not the absolute episode, array index or an external catalog ID. Slug/title changes never change resume or progress identity.
|
||||
|
||||
Create a unique session directory with mode `0700`, write the source document with mode `0600`, and supply a **nonexistent** progress-file destination. Terebi exclusively creates the report with mode `0600`; it rejects existing destinations and symlinks. Keep the source file unchanged and present for the player session. CLI success means macOS accepted the launch, not that media opened or playback completed. Tubular owns session-file cleanup.
|
||||
Create a private reporting-session directory (`0700`) and supply a **nonexistent** progress-file destination. Terebi exclusively creates the report (`0600`), rejecting existing destinations and symlinks. CLI success means macOS accepted the launch, not that playback succeeded. Tubular consumes reporting independently of launcher lifetime; launcher exit, a final record or Tubular shutdown does not establish that the player stopped. Preserve retained sessions and restart/partial-line recovery.
|
||||
|
||||
### Optional native metadata
|
||||
|
||||
The native resolver requests watch-route data and safely follows bounded same-origin, same-ID, same-episode canonicalization envelopes, including HTTP-200 redirects. It accepts JSON and newline-delimited `text/sveltekit-data`, decoding only the needed response-local tables and episode promise. Bodies and traversal are bounded; unrelated source promises are not used for playback.
|
||||
|
||||
Titles come from returned series/selected-episode metadata. Only `op`/`mixed-op` and `ed`/`mixed-ed` become opening/ending bands. Bands retain fractional seconds, require positive player-reported duration, and reject nonfinite, negative, reversed, wrong-episode or out-of-bounds timings; an end equal to duration is valid. Duration changes revalidate raw intervals without trimming, shifting or scaling. Optional provenance/votes/reference-length checks follow the documented frontend evidence; missing fields are not invented. Highest-vote eligible opening and ending win, with response order breaking ties. Overlaps are not merged.
|
||||
|
||||
The controls label the bands **Opening** and **Ending**, with accessibility descriptions; neither automatic seeking nor skip buttons are added. Bounds do not prove synchronization across cuts. Metadata tasks are bound to identity and lifecycle generation; replacement clears intervals and rejects stale results, including A → B → A.
|
||||
|
||||
### External resolved-source compatibility
|
||||
|
||||
`--source-file PATH --new-instance` remains available for callers supplying already-resolved sources; it is not Tubular's current launch path and does not acquire URL metadata. Keep private source files unchanged and present for their player session. Their version-1 contract below is unchanged.
|
||||
|
||||
### Source document, version 1
|
||||
|
||||
@@ -60,21 +73,11 @@ All shown fields except `title` are required. `headers: {}` and `subtitles: []`
|
||||
|
||||
Limits: source document 1 MiB; 32 subtitle tracks; 64 headers per resource; Miruro media ID up to 512 ASCII letters/digits/`-`/`_`; episode integer 1–2147483647. Invalid URLs, HTTP header names, case-insensitive duplicate header names and control characters are rejected with sanitized errors. Header values are not trimmed or rewritten.
|
||||
|
||||
### Projection from Tubular's Miruro response
|
||||
### External source projection
|
||||
|
||||
Use the selected direct Sun server/provider from `src/miruro.rs`:
|
||||
External source-document producers must preserve selected direct stream URLs and complete server headers, use Miruro's opaque catalog ID and returned episode number for identity, and carry explicit per-subtitle headers. Subtitle headers **do not inherit** stream headers. The verified Sun path supplies server headers to its VTT resources; do not generalize this to other providers.
|
||||
|
||||
| Terebi field | Tubular resolved source |
|
||||
| --- | --- |
|
||||
| `url` | Selected `server.streams[].url`, unchanged |
|
||||
| `headers` | Selected server's header map, including Origin and Referer |
|
||||
| `identity.media_id` | Miruro opaque catalog ID, not AniList/MAL ID or slug |
|
||||
| `identity.episode` | Selected returned episode number used for source resolution, not absolute episode number or array index |
|
||||
| `subtitles[].url` | Selected provider subtitle's `file` |
|
||||
| `format`, `language`, `label`, `default` | Selected subtitle metadata; restrict this launch to VTT and at most one default |
|
||||
| `subtitles[].headers` | Explicit headers appropriate to that subtitle resource |
|
||||
|
||||
Subtitle headers **do not inherit** stream headers. The verified Sun smoke explicitly supplied its server headers to the English subtitle resource; do not assume this applies to other providers or resources. `identity.provider` is the catalog namespace `miruro`, not the playback provider `sun`.
|
||||
`identity.provider` is the catalog namespace `miruro`, not the stream provider `sun`. Titles, slugs and expiring CDN URLs are not identity. Tubular no longer projects source documents.
|
||||
|
||||
## Propagation and subtitle behavior
|
||||
|
||||
@@ -145,22 +148,30 @@ For only the actual Miruro launch scenario:
|
||||
TEREBI_CHECK_RESOLVED_ONLY=1 make check-startup
|
||||
```
|
||||
|
||||
Default checks use local fixtures and do not contact Miruro. For an **explicit live smoke**, resolve fresh in Tubular, project the private source document above, then run:
|
||||
Default checks use local fixtures and do not contact Miruro. Optional metadata protocol/security/normalization checks:
|
||||
|
||||
```sh
|
||||
make check-miruro-metadata
|
||||
make .build/resolved-playback-check
|
||||
.build/resolved-playback-check '/absolute/private/session/source.json'
|
||||
.build/resolved-playback-check --metadata-lifecycle
|
||||
```
|
||||
|
||||
This checks native decode and acknowledged subtitle/seek state, not visual appearance or perceived A/V synchronization. Use the production launch command for that human check. Tubular's existing `cargo run --locked --example miruro_probe` verifies source resolution/master/subtitle retrieval, not Terebi playback.
|
||||
Explicit live native URL smoke (contacts Miruro and media/subtitle resources):
|
||||
|
||||
## Remaining work and limits
|
||||
```sh
|
||||
.build/miruro-metadata-check --live 'https://barelystarted.miruro.tv/watch/OERe_a0YS4h-DlsBDOeXwX7HOO6316tw/episode?ep=1'
|
||||
.build/resolved-playback-check 'https://barelystarted.miruro.tv/watch/OERe_a0YS4h-DlsBDOeXwX7HOO6316tw/episode?ep=1'
|
||||
```
|
||||
|
||||
1. Tubular must create the source document, launch Terebi with it and implement v2 progress consumption; no Tubular implementation files were changed by this work.
|
||||
2. Confirm this identity/reporting contract on the Tubular side; external adoption is not yet agreement.
|
||||
3. For end-to-end release verification, check English subtitle appearance and synchronization in the visible app before/after seeking, using Tubular's actual launch path.
|
||||
4. Sources requiring media redirects or cross-origin HLS resources will fail explicitly under the current conservative policy. Expired sources must be freshly resolved by Tubular; Terebi does not refresh automatically.
|
||||
URL smoke expects a fixture episode with available title, bands and default subtitles. It checks native decode and acknowledged subtitle/seek state, not visual appearance or perceived A/V synchronization. Tubular's catalog probe does not run Terebi or retrieve sources.
|
||||
|
||||
Other providers' proxies/HLS rewrites, iframe providers, downloads, thumbnails, intro/outro controls, embedded captions and additional external-subtitle formats remain out of scope.
|
||||
Metadata implementation verification (2026-10-22): protocol/security/bounds checks, lifecycle replacement/A-B-A stale results/duration changes, stream resolver and CLI checks passed. The live placeholder resolved the descriptive title “The Apothecary Diaries Season 3 — Episode 1: Locusts,” opening 63.313–153.237 seconds and ending 1335.252–1425.384 seconds; native video/audio advanced, measured-duration bands appeared in model state, and default VTT plus forward/backward acknowledged cue seeks passed. FFmpeg emitted redacted diagnostics during this successful run; no visual synchronization or visible-band sign-off is claimed.
|
||||
|
||||
## Remaining limits
|
||||
|
||||
- Confirm title readability and labeled bands in normal/compact controls, buffer/playhead visibility and subtitle alignment in the visible app using Tubular's real launch path.
|
||||
- Tubular collection launches, retained-report recovery and watched decisions remain its acceptance responsibility; this implementation changes no collection or progress schema.
|
||||
- Media redirects/cross-origin HLS resources remain unsupported. Native URL launches resolve fresh; externally supplied source documents must be refreshed by their producer. Automatic expired-source refresh is not implemented.
|
||||
- Other providers' proxies/HLS rewrites, iframe providers, downloads, thumbnails, automatic skipping, embedded captions and additional external-subtitle formats remain out of scope.
|
||||
|
||||
The implementation and this handoff are local; no remote publication or Tubular issue/comment update was performed.
|
||||
|
||||
Reference in New Issue
Block a user