diff --git a/docs/app-developer-guide.md b/docs/app-developer-guide.md index a8464413..2f288263 100644 --- a/docs/app-developer-guide.md +++ b/docs/app-developer-guide.md @@ -831,3 +831,12 @@ verify its first launch from My Apps, app details, a browser tab and Companion: - Verify first launch, cancellation/retry, reload, owner/viewer authorization, and persisted data after app recreation. Use the shared browser-check suite outside the repository; record which nodes and browser engines were tested. + +## Native audio player and video integration + +Audio apps can integrate with the native bottom player while retaining their own +playback engine, queue and authenticated media. Follow the +[audio message protocol, manifest example and acceptance checklist](app-media-integration.md). +V4V is the reference implementation for close/reopen, artwork and queue controls. +That guide also tracks the separate companion Cloud video PiP work; audio bridge +support must not be advertised as already providing native video PiP. diff --git a/docs/app-media-integration.md b/docs/app-media-integration.md new file mode 100644 index 00000000..8407a553 --- /dev/null +++ b/docs/app-media-integration.md @@ -0,0 +1,144 @@ +# Audio playback and video picture-in-picture integration + +## Status and reference + +The `archipelago-v1` audio bridge is implemented in the dashboard. V4V is the +reference app; its updated real-node acceptance is tracked in +[v4v-native-player-20261006.md](v4v-native-player-20261006.md). Local tests are not +proof that a particular deployed app or companion version supports every feature. + +Cloud video picture-in-picture (PiP) in the Android companion is a separate open +implementation task. Do not advertise the audio bridge as a video/PiP API. Native +fullscreen support alone does not provide Android PiP. A versioned video contract +and examples must be added here when implementation and device tests pass. + +## Declare the audio integration + +Use the existing app manifest and normal signed-catalog installation process: + +```yaml +app: + # Other required manifest fields omitted here. + metadata: + launch: + requires_host_frame: true + media_controls: archipelago-v1 +``` + +Declare the app's normal authenticated UI interface and readiness check. Use a +pinned image and persistent data mounts. An initial route such as `/browse` belongs +in `interfaces.main.path`; opening the retained player must not navigate back to +that route or create another iframe. A node-only demo must remain in its signed, +audience-restricted catalog until separately approved for public distribution. + +Audio controls do not require Nostr signing. Apps needing Nostr login must follow +[the app developer guide](app-developer-guide.md) separately: explicit identity +selection, scoped consent, server-verified authentication and cancellation. Never +put signer permissions, wallet operations or signing keys into the media bridge. + +## Keep a single player and queue + +The app continues to own its audio element, queue, authorization and playback +position. The dashboard retains the same iframe when the app panel closes and +shows the native bar. Reopening reveals that frame. Stop, logout and frame disposal +must release playback. Starting another audio source must not leave two players +running. Do not give the dashboard a protected stream URL to play a second copy. + +Delegate previous, next and shuffle to the same actions used by the app's own +controls. Publish the resulting state back: do not optimistically maintain an +independent dashboard queue. For example, if Previous restarts a song after three +seconds in the app, it must do the same from the native bar. + +## Message protocol: version 1 + +All messages use `window.postMessage` with an exact target origin, never `*`. +The dashboard accepts messages only from the retained frame's `contentWindow` +and its exact loaded origin, for an app declaring the manifest opt-in above. +The app accepts messages only from `window.parent` at its approved dashboard +origin. An unrelated sibling app, a popup or a matching hostname on a different +unapproved port is not an authorized parent. + +Do not rely solely on `document.referrer`: an app-local login redirect changes +it. V4V's deployment uses the same hostname/scheme dashboard on its default port +and validates any supplied referrer against that topology. Apps deployed with a +different topology need an explicitly trusted installed parent origin, not an +origin accepted from a query parameter or the first message received. + +| Direction | Type | Fields beyond `type` and `version: 1` | +| --- | --- | --- | +| App → host | `archipelago:media-ready` | None; emit after the bridge is ready, including after login navigation. | +| Host → app | `archipelago:media-connect` | `session`: per-frame random handshake nonce. | +| App → host | `archipelago:media-state` | Same `session`, plus playback fields below. | +| Host → app | `archipelago:media-control` | Same `session`, `command`, and `position` for seek. | + +Only accept controls for the active handshake session. V4V validates session +format, checks origin and parent-window identity, and rejects controls while +locked. The nonce correlates this frame's messages; it is not a replacement for +origin/source validation or application authentication. + +Example state: + +```js +window.parent.postMessage({ + type: 'archipelago:media-state', version: 1, session, + available: true, + title: track.title, artist: track.artist, + artwork: track.cover, shuffle: player.shuffleEnabled, + playing: player.playing, + position: player.currentTime, duration: track.duration, +}, approvedDashboardOrigin); +``` + +- `title` and `artist`: strings, limited to 256 characters. +- `position` and `duration`: finite, nonnegative seconds; clamp seek to duration. +- `playing`, `shuffle` and `available`: booleans reflecting actual app state. +- `artwork`: optional cover URL, at most 2,048 characters. The host accepts HTTPS + or the app's own origin and rejects URL credentials. Do not include bearer + tokens or private signing material in cover URLs. The bar shades the artwork + to keep controls legible. Missing artwork must not prevent playback. +- Send `available: false` on logout, locked state or unavailable player, without + leaking the previous user's track details. + +Commands are `play`, `pause`, `seek`, `next`, `previous`, `shuffle` and `snapshot`. +`seek` carries `position` in seconds. Reject unknown commands and malformed fields. +Serialize actions that cannot overlap; publish a fresh snapshot after the action +settles. Register the message listener before emitting ready; release listeners, +subscriptions and timers on page disposal and restore them correctly on browser +back/forward-cache resume. + +## Required app qualification + +Use real installed metadata and signed catalogs as well as isolated unit fixtures. +The current host reference checks are +`tests/lifecycle/v4v-native-login.cjs` and `v4v-native-playback.cjs`. +They require explicit real-auth authorization and prohibit payment operations. +Adapt selectors and authentication proof validation to your app; never weaken +those guards merely to make a test pass. + +1. Fresh install and update preserve app data, login, readiness and launch route. +2. Login navigation and reload still establish the media handshake. Reject forged + origins, sibling frames, wrong sessions and malformed state/commands. +3. Play a real authorized test track, close the panel and prove its playback time + advances in the same frame. Pause/resume, seek, previous/next and shuffle must + match the app. Reopen without resetting the song or duplicating audio. +4. Verify correct title/artwork/shuffle after track changes, no stale state after + logout, and handoff to another audio source without simultaneous playback. +5. Check 320/360/390px and desktop widths, long titles, touch targets, safe-area + navigation, keyboard labels and reduced-motion preferences. +6. Test actual Android companion background/resume and exit behavior. A browser + viewport test cannot prove OS background playback or PiP support. Do not promise + playback after the operating system kills the process. + +## Cloud video PiP acceptance scope (not yet implemented) + +Start with Cloud's existing authorized video viewer and companion fullscreen host. +Provide an explicit PiP control when supported, with clear unavailable behavior. +Retain the same playback and authenticated connection; never put the entire node +management UI into a small PiP window. Preserve aspect ratio, play/pause, close, +return-to-viewer, background/resume, rotation, seek and completion behavior. + +Cover supported Android/API levels, system PiP disabled, unsupported devices, +logout/session expiry, FIPS disconnect/reconnect, and process recreation. Validate +on a physical companion with ordinary and FIPS-accessed Cloud videos before APK +publication. Document the proven video integration contract for other app authors +only after that implementation is qualified. diff --git a/docs/node-demo-catalog-and-media.md b/docs/node-demo-catalog-and-media.md index 478dba68..c1a8b4ce 100644 --- a/docs/node-demo-catalog-and-media.md +++ b/docs/node-demo-catalog-and-media.md @@ -163,3 +163,41 @@ controls and reopening the same frame before accepting the repair. The requested promotion uses the final intro cymatic still as its background, with a music/play graphic on the right or the app's For You banner treatment. The previously captured login background does not satisfy this updated request. + +Latest operator observation: the bottom-bar transition is now working; controls +and the artwork background are still missing. Preserve the working transition. +Add legible current-track artwork plus play/pause, previous/next and shuffle +synchronized with the app's actual queue/state. This observation narrows the +reported symptom; it does not replace automated login-boundary and playback tests. + +Mobile refinement requested: previous/next and the open-app action must fit neatly +at narrow widths with comfortable touch targets; prefer a compact app icon with +an accessible name. Fresh V4V launch should open Browse. Reopening the retained +playing iframe must preserve the current song, queue and session rather than +resetting it to the initial route. + + +### Session recovery and private distribution — 6 October, 22:24 UTC + +All three development worktrees survived the interrupted session. Private recovery +bundles, patches, untracked source and test logs were saved and verified under +`~/.local/state/archipelago/session-recovery/20261006T221806Z/`. + +At the operator's explicit request, the publicly downloadable original V4V demo +package version was deleted through the registry package API (204); authenticated +package enumeration confirms it is absent. Anonymous registry bearer-token pulls +of both its original tag and manifest digest now return404. This does not establish +that no one downloaded it before removal or that external copies can be recalled. + +The original image was first exported privately and its configuration digest +verified against the installed-image record. Yaya authenticated dashboard RPC +reports the managed app running/ui-ready both before and after removal. Existing +containers and data were not modified. A future fresh pull of the deleted public +reference will fail; retain the on-node image and private archive until the private +replacement delivery/update path is qualified. No updated demo image is authorized +for public publication. Native login/player update still awaits live deployment. + +The prior temporary SSH control connection no longer authenticates. Operator was +asked to restore access; dashboard RPC remains available. IndeeHub, V4V and wallet +recovery work have been reassigned to three active agents. Incomplete test runs are +being resumed, with heavy qualification staggered to avoid disk-pressure timeouts. diff --git a/docs/post-1.9.0-work-backlog.md b/docs/post-1.9.0-work-backlog.md index 2e02cc14..d7ef1d93 100644 --- a/docs/post-1.9.0-work-backlog.md +++ b/docs/post-1.9.0-work-backlog.md @@ -238,7 +238,10 @@ ahead of that work or as an untested addition to the current release. - After the current release, deploy/package the existing V4V Portainer deployment as a demo app on Yaya, showcasing how an ordinary third-party app works on a - node **without native Nostr signer integration**, as explicitly requested. + node. Updated operator instruction on6October supersedes the original + no-native-signer brief: use Nostr sign-in and the native signer, replacing the + alpha password gate for this demo. Preserve explicit signing consent and + cryptographic authentication; newly registered users gain no operator powers. - Inspect the actual existing Portainer source, branch/image revision, Compose stack, access/authentication and data before changes; retain the working V4V site, stack and persistent state. Do not confuse this with the public Archipelago @@ -246,7 +249,7 @@ ahead of that work or as an untested addition to the current release. - Follow the current app-development guide and supported app packaging/gate/ lifecycle conventions. Define the app card/icon/category, launch URL/readiness, network/auth boundaries, health, configuration and persistent mounts properly. - Do not expose the native signer or implicitly grant signing permissions. + Integrate the supported native signer without implicitly granting permissions. - Qualify fresh installation in isolation, then Yaya deployment, desktop/mobile/ companion launch, normal app functionality, restart, update/rollback and safe removal behavior. Verify the deployed app actually runs the intended V4V source @@ -260,8 +263,12 @@ ahead of that work or as an untested addition to the current release. - Source is on the existing Gitea on the146 server; locate the actual V4V repo, branch and deployment revision there rather than guessing a replacement source. - Add a **Sovereign Music** banner for V4V on Yaya, following the existing - Sovereign Streaming banner treatment and using the app's own login background. - Retrieve and inspect the real asset; do not invent a replacement illustration. + Sovereign Streaming banner treatment. Updated request: use the final intro + cymatic still as the background and a music/play graphic on the right, or adapt + the app's For You banner treatment. Inspect the actual intro ending and assets. +- Fix the reported real managed-app regression: closing V4V leaves playback + running without the native bottom player. Qualify against the signed catalog + and real installed app, not only browser-injected package fixtures. - Both demo app availability and its promotion must be confined to Yaya. Evaluate a signed per-node/DID-scoped demo catalog or existing supported node-specific candidate mechanism. Do not publish the demo to the global catalog or let @@ -273,6 +280,15 @@ ahead of that work or as an untested addition to the current release. from node-only demo to proper public app release without duplicate app IDs, conflicting state, lost configuration or automatic exposure before approval. +### Private demo distribution correction + +The operator authorized removal of the publicly downloadable V4V demo container +on 6 October. Preserve Yaya's working installed demo, its data, and a private +recovery image. V4V application source and images must remain private until the +operator explicitly approves publication. Audience restriction on a signed node +catalog does not make the referenced registry image private. Updated deployment +must use a qualified private delivery path; do not republish the demo image. + ### V4V persistent playback and existing demo music catalog - Use the demo song catalog from the existing V4V Portainer demo in the Gitea @@ -286,7 +302,7 @@ ahead of that work or as an untested addition to the current release. system termination/background restrictions require separate qualification. - Inspect supported app/player integration before choosing an implementation. Maintain one playback session, prevent duplicate audio on reopen, authenticate - app-to-shell messages, and preserve the requirement of no native Nostr signer. + app-to-shell messages, and support the updated native Nostr sign-in requirement. - Test navigation, repeated close/reopen, pause/resume/seek, track changes, disconnect/recovery and unavailable media on desktop and the actual companion. Check track, queue and position continuity, accessible compact controls and @@ -464,3 +480,27 @@ functional/UX review. These are additions to existing groups, not closed work. - Qualify real reciprocal removal/requests, offline and reconnect behavior, duplicate/replayed events, automatic UI convergence, notifications/deep links, map positioning and responsive card geometry before claiming acceptance. + +## 19. Reusable media developer guide and companion Cloud video PiP + +Added by the operator after the V4V player refinements. Preserve the earlier +instruction to complete the other work before the deferred final connection UX +review; this new media task is part of that preceding work. + +- Document the reusable audio manifest, handshake/state/control protocol, + security boundaries, login redirects, queue ownership, artwork, lifecycle, + mobile layout and reproducible test/deployment steps for developers and agents. + Use V4V as the reference; distinguish implemented source from live acceptance. +- Implement companion picture-in-picture for Cloud videos first. Investigate + viewer controls and native Android support together, preserving the same video + and authorized/FIPS transport rather than opening an unauthenticated second URL. +- Scope PiP to video, never expose the dashboard/management UI in the PiP window. + Test entry/exit, play/pause/close, return, aspect ratio, rotation, background, + completion, unsupported/disabled PiP, session expiry and network interruption. +- Require physical Android companion acceptance and signed APK distribution. + Document the supported video/PiP contract for other apps after qualification; + do not claim the audio postMessage bridge already implements video PiP. + +Source inspection so far: MainActivity declares no supportsPictureInPicture flag, +and the native sources contain no PiP entry/controller implementation. Existing +WebViewFullscreen handles fullscreen; this is not evidence of native PiP support. diff --git a/docs/v4v-native-player-20261006.md b/docs/v4v-native-player-20261006.md index 5d17ae72..f3bde6a0 100644 --- a/docs/v4v-native-player-20261006.md +++ b/docs/v4v-native-player-20261006.md @@ -41,3 +41,16 @@ native bar, and reopen the same iframe. Verify uninterrupted audio, matching song/cover/shuffle, and the app's actual queue. Repeat at mobile and desktop sizes and through the new Nostr login. Verify banner visually with the signed node-only catalog. This follow-up does not claim those live checks passed yet. + + +## Resumed dashboard deployment — 6 October + +The previously completed full dashboard suite passed 1,307 tests in 165 files; +the production build passed. Both logs survived the session interruption, and the +UI source remains unchanged from that build. The resulting dashboard was deployed +to the dev node with index SHA-256 +`a03f3e7a366613f82dd9fe014dc04301f223b9896f6684bf2ee5aa06aa59b2de`. +Served bytes match; backend, session key and app container identities/start times +were preserved. A rollback archive/script was saved in the node support directory. +Post-deployment browser checks are in progress. This is dashboard deployment only; +Yaya and the new private V4V app image still require deployment/acceptance.