Skip to content

feat(player): remote stream-client config - #461

Open
alltechdev wants to merge 10 commits into
mainfrom
feat/remote-stream-clients
Open

feat(player): remote stream-client config#461
alltechdev wants to merge 10 commits into
mainfrom
feat/remote-stream-clients

Conversation

@alltechdev

Copy link
Copy Markdown
Collaborator

Summary

The streaming-client chain becomes remote data, on the same model as the cipher player configs: YTPlayerUtils now resolves each playback against a per-resolution snapshot of the zemer-cipher stream_clients.json table (clients, flags, order, main designation), so adding/removing/reordering clients after a YouTube-side change is a config push, not an APK release. Companion PR: ZemerTeam/zemer-cipher#2 (must merge first; this PR bumps the submodule pointer onto it).

  • Flag-ification (behavior-preserving prerequisite): YouTubeClient gains a StreamProtocol enum (web_cipher_pot / direct) as the single source for useSignatureTimestamp/useWebPoTokens, plus skipHeadValidation replacing the WEB_REMIX name test; clientNeedsNTransform reads the protocol; webRemixFailedIds renamed mainClientFailedIds; the main-promotion/disable chain head extracted to the pure StreamClientChain.
  • Table wiring: StreamClientTable maps the store config onto YouTubeClient (compiled constants remain only as the floor when neither bundled asset nor cache loads); a resolution that exhausts every client fires the cooldown-gated table refresh, so a client kill self-heals mid-session.
  • Toggles are per-FAMILY dynamic keys (absent = enabled; prefix-scan derivation, no app-side registry) with a one-time migration from the six legacy keys, left in place for rollback.
  • Stream Sources screen renders rows, groups, and the order chips from the same table; the six known families keep their bespoke localized strings, a remotely-added family renders its config title with a generic description.
  • Harness: tests/clients.mjs becomes a loader of the same JSON (WEB stays hand-defined, browse-only); stream-clients.test.mjs runs the shared cross-language parity fixtures; validate-stream-clients.mjs is the pre-push gate (schema + whole-song CDN drain per client, candidate-file aware via STREAM_CLIENTS_JSON).
  • Docs: AGENTS.md gains the remote stream-client rulebook; generated docs regenerated; full design and failure-mode matrix in remote-stream-clients-plan.md.

Testing

  • 21 new JVM unit tests app-side (chain rules, def mapping, prefs migration, settings UI model) + 32 in the cipher submodule; all suites green (app, innertube, cipher).
  • ui-audit and download-unification scripts pass.
  • node --test tests/stream-clients.test.mjs green, including the parity sweep against the cipher fixtures.
  • Live CDN proof through the loader-fed chain: web-remix-stream.mjs drains a whole song (5741KB/5741KB, 206 throughout, sig + n-transform + pot applied).
  • Not yet done: on-device pass (toggle migration from an existing install, per-client playback) and the CI release/R8 build this PR triggers.

…names

- YouTubeClient gains a StreamProtocol enum (web_cipher_pot / direct) as the
  single source for useSignatureTimestamp/useWebPoTokens, plus a
  skipHeadValidation flag replacing the WEB_REMIX name test
- clientNeedsNTransform reads the protocol instead of a hardcoded name list
- webRemixFailedIds renamed to mainClientFailedIds (it marks the main slot,
  whoever occupies it)
- the main-promotion/disable chain head extracted to the pure StreamClientChain
  with JVM tests
- YTPlayerUtils resolves each playback against a per-resolution snapshot of the
  zemer-cipher stream_clients.json table (StreamClientTable), with the compiled
  constants as the floor when neither bundled asset nor cache loads
- a resolution that exhausts every client fires the cooldown-gated table
  refresh, so a YouTube-side client kill self-heals mid-session without an APK
- stream-source toggles become per-family dynamic keys (absent = enabled) with
  a one-time migration from the six legacy keys; MusicService publishes the
  disabled set by prefix scan
- Stream Sources screen renders rows/groups/order from the same table; known
  families keep bespoke strings, new ones use the config title
- tests/clients.mjs becomes a loader of the same file (WEB stays hand-defined);
  stream-clients.test.mjs runs the shared parity fixtures; a new
  validate-stream-clients.mjs gates pushes with schema + whole-song drains
- docs regenerated; AGENTS.md gains the remote stream-client rulebook
@alltechdev

Copy link
Copy Markdown
Collaborator Author

Testing setup: the cipher submodule is temporarily pinned to a commit whose REMOTE_URL fetches the FEATURE branch instead of master, so the full remote fetch/apply/update loop is testable on-device pre-merge (push a table tweak to feat/remote-stream-clients and watch devices pick it up). Both TEMPORARY commits (cipher 8a88e7a + this bump) get reverted before merge - do not merge while they are in.

Cleanup: the cipher submodule pointer moves past the reverted TEMPORARY
branch-pinned fetch (REMOTE_URL back to master) - both PRs are back to their
shipping state.
@alltechdev

Copy link
Copy Markdown
Collaborator Author

Both TEMPORARY commits are reverted: the cipher submodule now points past the revert (REMOTE_URL fetches master again) and the branch-pinned test setup is gone. On-device verification completed via the branch channel: remote client removal (VISIONOS benched -> gone from settings/chain, 'applied (5 entries, changed=true, epoch=1)') and restore both confirmed. Also added: the Stream Sources screen now shows the client-table last-sync time under 'Current order'. PR is back to shipping state - merge order still cipher #2 first.

- the all-clients-failed table refresh now fires only on client-kill shapes: a
  playability rejection (removed/region-blocked/age-gated), an explicit-rung
  quality miss, and cipher-side URL failures no longer trigger it, and an
  in-flight guard stops failing resolutions queueing coroutines behind a
  refresh that cannot complete on a filtered network
- harness scripts read the shared protocol predicate instead of re-deriving the
  retired client-name list (proven no behavior change across all 18 retired
  clients), and the whole-song drain defaults to the table's chain instead of a
  hand-kept copy that would skip newly added clients
- new test pins the bundled asset field-for-field against the compiled floor:
  the asset is what devices actually send, so a one-digit typo there previously
  shipped fleet-wide with every test green
- legacy-key comments now state what the code guarantees (migration source, not
  a mirror)
client-fulldownload.mjs is a report that always exits 0, so passing its status
through meant validate-stream-clients.mjs reported success even when no client
could stream. It now reads the per-client verdicts, calls out a failing MAIN
client as unpushable, notes that a fallback failure can be video-specific, and
exits non-zero.
They were untracked working-tree files that predate this work and got swept in
by an over-broad add; they are not part of the stream-client feature.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant