# Handoff: Miruro playback in Terebi ## Status 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 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:** 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 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 \ --url 'https://barelystarted.miruro.tv/watch/OPAQUE_ID/episode?ep=1' \ --progress-file '/private/session/progress.jsonl' ``` 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 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 Example only: replace CDN URLs with freshly resolved resources, preserving complete addresses and tokens. ```json { "version": 1, "url": "https://cdn.example/master.m3u8?token=fresh", "headers": { "Origin": "https://ultracloud.cc", "Referer": "https://ultracloud.cc/" }, "identity": { "provider": "miruro", "media_id": "OERe_a0YS4h-DlsBDOeXwX7HOO6316tw", "episode": 1 }, "title": "The Apothecary Diaries — episode 1", "subtitles": [{ "url": "https://cdn.example/english.jpeg?token=fresh", "format": "vtt", "language": "en", "label": "English", "default": true, "headers": { "Origin": "https://ultracloud.cc", "Referer": "https://ultracloud.cc/" } }] } ``` All shown fields except `title` are required. `headers: {}` and `subtitles: []` are valid; at most one subtitle may be default. Only `vtt` is supported for external subtitles in this pass. 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. ### External source projection 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. `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 - Stream headers reach the master, nested variants, media segments, AES-128 keys and fMP4 init resources. Relative references use native HLS resolution. Existing query tokens are preserved; Terebi does not invent query inheritance or provider-specific URL rewrites. - Resolved media requests must stay on the initial stream's origin: scheme, host and effective port. **All media redirects, including same-origin redirects, are rejected before a second request.** This conservative policy prevents FFmpeg from forwarding supplied private headers to another destination. Cross-origin HLS resources are not supported in this contract. - Sun serves MPEG-TS segments as `.jpg` / `image/jpeg`. Resolved playback probes actual media content instead of enforcing filename-extension matching; it does not change the URLs. HTTP(S)-only, origin and redirect restrictions remain in force. - External VTT classification uses explicit format and content, not filename extension or MIME type. `.jpeg` subtitle URLs work. Labels/languages appear in the captions menu; the declared default is selected, and the user can choose Off or another track. - Cues follow acknowledged player position, including seeking backwards. Zero-duration cues are permanently inactive rather than invalidating the track. Rendering is plain text; WebVTT CSS, positioning and typographic styling are not applied. - Subtitle HTTP requests use their own headers. Same-origin redirects retain those headers; cross-origin redirects are rejected. Responses are capped at 4 MiB, with 15-second request and 20-second resource timeouts. - Media errors remain visible with the operation/native error. Subtitle failures appear separately beside the captions menu, including when other controls are hidden. FFmpeg diagnostics redact private details; source/subtitle errors do not interpolate URLs or header values. - Casting uses the same episode identity and progress schema; receiver-confirmed positions replace paused local-decoder facts. The Mac relays media/VTT without exposing source URLs or credentials to the receiver. See [Chromecast controls, transport limits and verification](../README.md#chromecast); physical receiver playback/captions remain unverified. YouTube's existing launch, version-1 progress and transport behavior remain supported. ## Progress contract and Tubular change YouTube records remain **version 1** with canonical `media_url`. Miruro records are **version 2**, with structured episode identity and no CDN address: ```json {"version":2,"event":"progress","media_identity":{"provider":"miruro","media_id":"OERe_a0YS4h-DlsBDOeXwX7HOO6316tw","episode":1},"position_seconds":123.5,"duration_seconds":1500.0,"completion_eligible":true} ``` `event` is `progress`, `ended` or `closed`. Position is finite, nonnegative and acknowledged by playback, not a pending seek/slider target. Duration is positive and finite or `null`. Completion eligibility remains false for live/non-seekable media, unknown duration and audio-only sources. Reporting includes ready state after restoration, approximately five-second playback intervals, acknowledged pause/seek transitions, the first eligible 95% crossing, native end and final close/quit snapshots. Launch success and window closure do not establish completion. Consumers must tolerate duplicates, partial trailing lines and abrupt termination; a `closed` record is not guaranteed. Tubular integration must retain canonical YouTube/version-1 validation, accept version-2 validation against the episode identity expected for that launched session, and key Miruro watched state by `(miruro, opaque media ID, episode)`. Never use stream URL, token, slug or selected playback provider as identity. Retain the current completion decision for matching identities: ```text completion_eligible && duration_seconds > 0 && position_seconds / duration_seconds >= 0.95 ``` Handle `null` duration as ineligible. This measures position, not viewing coverage; seeking near the end can satisfy it. Terebi also uses stable episode identity for its own resume bookmarks. ## Verification evidence | Scenario | Observed result | | --- | --- | | Explicit fresh direct Sun native smoke | Video/audio decode and advancing playback; default English VTT; expected cue text after forward/backward acknowledged seeks | | Live Sun audio continuity | Dragon Ball episode 1: actual Core Audio PCM diverged from FFmpeg after about 0.6 seconds before the fix; after tolerating millisecond-scale timestamp jitter, all 960,008 stereo frames compared across twenty seconds and multiple HLS segments matched exactly | | Audio regression | Deterministic AAC/MPEG-TS timestamp-jitter fixture failed before the shared continuity fix and matched FFmpeg exactly afterward; existing authored-gap, resampling, gain and stepped-resume checks passed | | Local resolved playback model | Independent stream/subtitle headers, nested playlist tokens, video/audio playback, cue timing and stable v2 progress | | Local native network checks | Encrypted MPEG-TS and fMP4; image-suffixed resources; headers on master/variant/segment/key/init; seeks/frame steps; redirect/foreign-origin isolation; diagnostic redaction; existing YouTube redirects | | Actual CLI-to-GUI handoff | Two independent Miruro episode windows; authenticated encrypted HLS; resource-specific default VTT; v2 progress and quit draining | | Full `make check-startup` rerun | Passed, including held-key suppression, YouTube progress/resume/quality/replacement/end and independent launches | | Other exercised checks | CLI, external subtitles, progress persistence, JSONL reporting, YouTube resolver and system playback passed | | Visible-app observation | User reported playback appears to work; comprehensive visual subtitle/seek synchronization sign-off remains limited | Earlier startup runs failed held-Space and YouTube end-transition assertions. The user reported possible manual interaction. The full rerun passed without playback-code changes; causality of the earlier failures was not established. No full aggregate `make check` pass is claimed. Streaming-input verification (2026-10-19): native URLSession resolved a live Miruro episode with nine VTT tracks; native URL-to-playback exercised video/audio, pause, default captions and forward/backward acknowledged subtitle seeks. Offline stream parsing/projection/security, CLI/config, resolved playback and YouTube resolver/adaptive checks passed. The actual source-file CLI launch emitted version-2 progress and ended records, but the startup check timed out waiting for GUI state snapshots; this run does not establish the complete two-window handoff scenario. The live probe's original synchronous wait blocked async resolution; yielding the actor fixed the probe without playback-code changes. ### Reproduction commands from Terebi ```sh make check-cli check-subtitles check-resolved check-network check-progress check-reporting make check-youtube check-media make check-startup ``` For only the actual Miruro launch scenario: ```sh TEREBI_CHECK_RESOLVED_ONLY=1 make check-startup ``` 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 --metadata-lifecycle ``` Explicit live native URL smoke (contacts Miruro and media/subtitle resources): ```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' ``` 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. 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.