Rust port of NewPipeExtractor (YT-only). Plugs into Straw via UniFFI.
Find a file
Kayos a47e142ab7 Phase 4 (complete) — stream_extractor orchestrator
Wire the Android-primary fetch path + JSON-walking + URL post-processing
into a single stream_info(video_id) entry point. Mirrors NPE
YoutubeStreamExtractor.onFetchPage() per audit Track C §1.2.

src/youtube/stream_extractor.rs
  * stream_info(video_id) + stream_info_with(video_id, options)
  * fetch_android — reel endpoint (anonymous) OR /player (with po_token)
  * check_playability_status — maps to ContentUnavailable variants
    (AgeRestricted, GeoRestricted, Paid, Private, YoutubeMusicPremium,
    AccountTerminated, Other)
  * is_player_response_not_valid — decoy-video detection
  * populate_video_details + populate_microformat + populate_streams +
    populate_manifests + populate_captions
  * process_url — sig deobf path (signatureCipher → JS function call)
    + unconditional nsig deobf + cpn append + pot append
  * build_video_progressive / build_video_only / build_audio +
    push_*_dedup helpers (FIX: NPE bug — dedup by itag id, not by
    mediaFormat.id which collides 140/141)

Consolidated stream_helper's local ExtractionError into the crate-wide
exceptions::ExtractionError with a new DownloaderMissing variant.

Tests: 73 lib unit pass (+9 since Phase 3) + 7 new Phase 4 offline
integration tests = 80 lib green. Live YT end-to-end smoke deferred
to Straw integration; the code path is in place.
2026-05-24 17:08:04 -07:00
src Phase 4 (complete) — stream_extractor orchestrator 2026-05-24 17:08:04 -07:00
tests Phase 4 (complete) — stream_extractor orchestrator 2026-05-24 17:08:04 -07:00
.gitignore Initial commit 2026-05-24 16:26:57 -07:00
Cargo.lock Phase 2 — JS deobfuscator (rquickjs + ress) 2026-05-24 16:53:19 -07:00
Cargo.toml Phase 2 — JS deobfuscator (rquickjs + ress) 2026-05-24 16:53:19 -07:00
LICENSE Initial commit 2026-05-24 16:26:57 -07:00
README.md Phase 1 — Foundation 2026-05-24 16:32:36 -07:00

strawcore

Rust port of NewPipeExtractor (v0.26.2), YouTube-only. Plugs into Straw via UniFFI.

Why this exists

rustypipe regex-parses YouTube's player.js and reimplements the signature deobfuscator in Rust. Every YT player rotation breaks it. NPE embeds Mozilla Rhino and executes the JS function live — resilient by design, and that's the architecture we're mirroring.

The rustypipe-backed Straw build (vc=15..17) also routed playback through iOS-progressive URLs, which hit a server-side ~917 KiB end-byte cap. NPE uses the Android client + po_token → DASH manifest path, which doesn't see the cap. Same fix, different layer.

See memory/npe-audit-2026-05-24/SPEC.md in the workspace repo for the full plan.

Status

Phase Subsystem Status
1 Foundation (downloader + service spine) in progress
2 JS engine (rquickjs + ress) pending
3 InnerTube + itag table pending
4 Stream extractor + DASH pending
5 PoTokenProvider trait + Android JNI bridge pending
6 Search + Channel + Playlist + Kiosks pending
7 UniFFI surface swap pending
8 Delete rustypipe everywhere pending

Build + test

cargo build
cargo test --lib                          # offline unit tests
cargo test --features online-tests        # full smoke incl. live httpbin.org

License

GPL-3.0-or-later. NPE is GPL-3.0; this port inherits.