feat: enqueue streams in running player

This commit is contained in:
2026-10-22 16:03:56 +02:00
parent ac8e284d80
commit 6a4afc9f0e
17 changed files with 416 additions and 61 deletions
+8 -4
View File
@@ -29,6 +29,8 @@ Create a private reporting-session directory (`0700`) and supply a **nonexistent
```sh
terebi --new-instance --queue-file '/absolute/private/session/queue.json'
# Append to the running player, or launch and play if none is running:
terebi --enqueue --queue-file '/absolute/private/session/queue.json'
```
The manifest is bounded to 8 MiB, version 1, and 1–4096 entries in playback order:
@@ -43,15 +45,17 @@ The manifest is bounded to 8 MiB, version 1, and 1–4096 entries in playback or
}
```
Use canonical YouTube video pages or supported Miruro episode pages, never expiring source addresses. Stable identities must be unique even across alternate YouTube forms or different Miruro slugs. Reports must have distinct absolute nonexistent destinations, each under a canonical, nonsymlink, user-owned `0700` directory. Tubular retains each item's existing identity registration/session and stores the manifest in the first session. The CLI validates the complete document before launching; the GUI validates it again before opening any media. Invalid queues fail rather than falling back to a single stream. Queue launch requires `--new-instance`, accepts `--no-config`, and cannot combine with `--url`, `--source-file` or `--progress-file`.
Use canonical YouTube video pages or supported Miruro episode pages, never expiring source addresses. Stable identities must be unique even across alternate YouTube forms or different Miruro slugs. Reports must have distinct absolute nonexistent destinations, each under a canonical, nonsymlink, user-owned `0700` directory. Tubular retains each item's existing identity registration/session and stores the manifest in the first session. The CLI validates the complete document before launching; the GUI validates it again before opening any media. Invalid queues fail rather than falling back to a single stream. Queue launch requires either `--new-instance` (replace in a separate player) or `--enqueue` (append to the running player), accepts `--no-config`, and cannot combine with `--url`, `--source-file` or `--progress-file`. `--enqueue` and `--new-instance` are mutually exclusive.
The supplied order is preserved (local-file batches still use natural filename order). Existing sidebar reorder/remove/play and previous/next navigation apply. Natural end advances without clearing the queue. Sources resolve only when selected, resolve afresh on revisits, and canceled/stale results cannot replace a newer selection. Labels start with descriptive page information and update from resolved titles/optional metadata.
Each report is immutably bound to its stable identity in the native decoder. Switching entries drains/closes the previous writer before beginning the next; revisits append only after verifying the original private report inode, owner, permissions and link count. An unrelated or replaced file is never reopened as an owned session, and an unregistered identity is never written to the previously selected report. Only the active item owns a running writer/open report descriptor. A reporting failure is shown separately without rerouting facts or changing acknowledged playback/completion semantics. Single-stream `--progress-file` remains unchanged.
Enqueue uses native macOS URL-open delivery to the explicit application, not launch arguments: repeated requests reach the existing process. Both one-item and multi-item requests use the same manifest. The current selection, playback/pause state, timeline, pending resolution and metadata stay intact; an empty player selects and starts the first entry. Original single-file, single-stream and resolved-source playback remain navigable when items are appended. Enqueue never silently deduplicates: any identity already in the queue or retained report registrations, or any report-path collision, rejects the complete batch with an error in the player. Removed items retain their report registrations for the process lifetime; at most 4096 report identities may be registered. Existing files are never adopted as reporting sessions. Keep manifests and private sessions available until delivery; CLI success acknowledges macOS delivery, not GUI acceptance or playback.
Runnable queue checks: `make check-cli check-queue check-reporting check-resolved`. The existing `check-resolved` local HTTP/HLS/VTT harness also drives a real native `PlayerModel` through a mixed YouTube/Miruro queue with injected fixture resolution, stale-result cancellation, manual navigation, natural-end advancement, fresh revisits/resume and isolated v1/v2 reports. Run `TEREBI_CHECK_STREAM_QUEUE_ONLY=1 make check-startup` for focused actual CLI→LaunchServices→GUI queue delivery, native decode, manual previous/next, natural-end advancement and per-item report revisits using the existing bundled-extractor/local-media fixture. These checks require no browser or live streaming service. Full `make check-startup` includes this queue scenario too.
Each report is immutably bound to its stable identity in the native decoder. Registration is atomic for a complete batch and can occur during playback without redirecting its current report. Switching entries drains/closes the previous writer before beginning the next; revisits append only after verifying the original private report inode, owner, permissions and link count. An unrelated or replaced file is never reopened as an owned session, and an unregistered identity is never written to a previously selected queue report. Only the active item owns a running writer/open report descriptor. A reporting failure is shown separately without rerouting facts or changing acknowledged playback/completion semantics. An original single-stream `--progress-file` keeps its destination when navigating back from appended queue entries.
Current local verification: `make check-cli check-queue check-reporting check-resolved all` passed. The packaged queue GUI smoke did not complete because native state snapshots stalled; no complete GUI pass is claimed. Temporary tracing was removed, and further UI testing is deferred to the user at their request. Tubular's handoff document records its terminal/capture and Rust checks separately.
Runnable headless queue checks: `make check-cli check-queue check-reporting check-resolved`. The existing `check-resolved` local HTTP/HLS/VTT harness drives a real native `PlayerModel` through mixed YouTube/Miruro queues with injected fixture resolution, stale-result cancellation, manual navigation, natural-end advancement, fresh revisits/resume and isolated v1/v2 reports. It also delivers repeated enqueue URLs while paused and playing, checks original standalone selection/timeline preservation, lazy append ordering, atomic invalid/conflicting requests, independent single/queue report revisits and empty-player startup. These checks require no browser or live streaming service. Actual LaunchServices/UI delivery remains a separate user-owned verification step; no GUI smoke result is claimed for enqueue.
Enqueue verification: `check-cli`, `check-queue`, `check-reporting` and `make all` passed. An added reporting regression failed before protecting the original single-video identity from rebinding and passed afterward; unknown identities also cannot leak into that report after queue registration. The full `check-resolved` run stopped in the older mixed-queue natural-end scenario with `Could not start Core Audio (560227702)`, before enqueue ran. A focused `.build/resolved-playback-check /absolute/source.json --enqueue-only` smoke using local video-only HLS passed paused/playing append, unchanged current revision/selection, lazy ordering, natural-end advancement, navigation/revisits, atomic conflicts/rollback, isolated reports and empty-player startup. The source document still requires `headers` and `subtitles` (empty values are valid). No full A/V-suite or packaged-GUI/LaunchServices pass is claimed; the app was built, not installed. Actual UI confirmation remains user-owned; temporary fixture/server files were removed. Tubular's handoff document records its terminal/capture and Rust checks separately.
### Optional native metadata