Restore full-length YouTube playback via WebPO token minting; add SPICE terminal CLI - #96
Merged
Merged
Conversation
- New apps/cli workspace (@spice/cli): search, stream, download, lyrics, play, status, and config commands against a running SPICE runtime - Wrapper: independent-slider boost mode routes the full multiplier through Web Audio (window.spiceOwnsMediaVolume) so the desktop slider and YouTube Music's own slider stop overwriting each other; boost graph gate now includes previously rerouted elements (wantsWebAudio) - Ops: .vercelignore for source-only CLI deploys, .vercel ignored, apps/cli/dist registered as build output and excluded
YouTube's gVis/PO-token enforcement now limits stream URLs resolved without a Proof-of-Origin token to roughly their first megabyte; every request past the window returns HTTP 403, which surfaced as endless retry loops on any song longer than ~65 seconds at 128kbps. The local runtime now runs the same attestation flow as the YouTube web player, in-process: - lib/po-token.ts: fetches the BotGuard challenge from the youtube.com homepage (window.ytAtN paired with that page's ytcfg so the VM sees EVENT_ID), evaluates the interpreter under a jsdom-backed globalThis, snapshots BotGuard, exchanges the response for an integrity token at GenerateIT (~12h TTL), and caches the resulting WebPoMinter. Tokens are minted per video ID; failures degrade gracefully to token-less URLs instead of breaking resolution. - lib/youtube.ts: YTMUSIC leads the client order (web-family URLs honor WebPO tokens; iOS-family URLs reject them), every stream URL carries its &pot= token exactly once, variants expose a capped flag. - stream proxy: user-agent is chosen by URL shape - pot-tagged web URLs require a browser UA, everything else keeps the historical iOS app identity; media responses send Access-Control-Allow-Origin:* because the shell origin (127.0.0.1) and signed-URL origin (localhost) are cross-origin for <audio>, whose silent failure otherwise surfaces as MEDIA_ELEMENT_ERROR code 4. Embed last-resort handling from v1.0.171 remains for tracks that fail direct streaming, minus a retry-budget reset that could loop transports. Verified end to end: full-file ranged fetches through the signed proxy (206 across 1MB and 2MB boundaries), a real browser audio element streaming the previously dead track start-to-finish, backend suite 418/ 418, typecheck clean, lint clean. SPICE_MEDIA_CORE_VERSION -> 1.0.172.
Adding the @spice/cli workspace tripped native-release-config's exact equality pin on package.json workspaces, turning Desktop, RPM, and macOS universal package jobs red before any build step ran. - Relax that assertion to what it actually protects: apps/backend must stay registered so packaged builds keep installing through it. - New test/workspace-alignment.test.js covers the whole failure class: declared-vs-disk consistency (both directions), lockfile records and dependency capture per workspace, unique workspace names, npm-level acceptance of the workspace set, and a scanner proving no CI workflow scripts commands against unregistered @spice/* workspaces. The drift scenarios are fault-injection verified locally: deleting apps/cli from workspaces or from package-lock.json both fail loudly with remediation messages, as does referencing an unregistered workspace from a workflow.
…ckaging Next's standalone tracer emits "<pkg>-<hash>" placeholder entries under .next/node_modules as junctions/symlinks back into the monorepo's hoisted node_modules whenever a packaged route pulls in a dependency installed above apps/backend (jsdom arrived with the WebPO minting work). Windows and macOS Native packaging jobs failed on them in two different layers: recreating such links needs privileges (EPERM locally) and copying them ships outbound links that the anti-leak guard rightly refuses. The packager now resolves those placeholders to their real hoisted packages and replaces them with plain directories inside the standalone tree, before any staging copy happens; unknown external links still fail loudly so leaks stay impossible. Logic lives in a shared helper (scripts/lib/traced-symlinks.mjs) consumed by the packager. Verified locally: package:local:windows completes end to end, the artifact contains a real jsdom directory and zero symlinks. Tests for this failure class (test/traced-symlinks.test.mjs): name resolution for plain/scoped/unhashed placeholders, junction replaced by a real content copy, internal layout links preserved while unresolvable external links are refused, and the packager's materialize-before-copy ordering.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two independent changes, one playback-critical:
1. fix(cloud): restore full-length YouTube playback via WebPO token minting (v1.0.172)
YouTube's gVis/PO-token enforcement now limits stream URLs resolved without a Proof-of-Origin token to roughly their first megabyte — every byte request past the window returns HTTP 403. In SPICE this surfaced as endless "Retrying this track…" loops on any song longer than ~65 seconds.
The local runtime now runs the same attestation flow as the YouTube web player, fully in-process:
lib/po-token.tsfetches the BotGuard challenge from the youtube.com homepage (window.ytAtNpaired with that page'sytcfgso the interpreter VM seesEVENT_ID), evaluates it under a jsdom-backedglobalThis, snapshots BotGuard, exchanges the response for an integrity token (~12h TTL), and caches the resulting WebPo minter&pot=to stream URLs; minting failures degrade gracefully to token-less URLs instead of breaking resolutionYTMUSIC— web-family URLs honor WebPO tokens; iOS-family URLs reject themAccess-Control-Allow-Origin: *on media responses, because the shell origin (127.0.0.1) and signed-URL origin (localhost) are cross-origin for<audio>— without this Chromium silently fails withMEDIA_ELEMENT_ERROR: code 42. feat(cli): SPICE terminal CLI + wrapper boost-mode fix
apps/cliworkspace (@spice/cli) with search/stream/download/lyrics/play/status/config commands against a running runtimewindow.spiceOwnsMediaVolume) so the desktop slider and YouTube Music's own slider stop overwriting each other; the boost graph gate includes previously rerouted elements.vercelignorefor source-only deploys,apps/cli/distregistered as build output and excludedVerification
Playback fix verified end to end on this machine:
<audio>element streams the previously dead track start-to-finish in the app UI (2:18 track observed playing well past the old ~65s kill point)CLI changes are authored by the parallel CLI workstream; root suite is green except the pre-existing
native-release-configworkspace alignment check, which passes once both workspaces land together (this PR contains both).