Rust port of NewPipeExtractor (YT-only). Plugs into Straw via UniFFI.
Find a file
Cobb a21a6e14ab
Some checks failed
gitleaks / scan (push) Failing after 2s
youtube: S3 narrowed-$fields feed metadata + S7 player.js byte-release
Post-outage-review batch (Fable adversarially audited: SHIP-WITH-FIXES; the one
MED is folded below).

S3 — cheaper stream_metadata feed-enrich. On the anonymous reel path, ask
reel_item_watch for only playabilityStatus+videoDetails via a narrowed nested
$fields selector (~3-6 KB vs the full ~150-500 KB reel body). BEST-EFFORT with a
HARD fallback to the unchanged full fetch_android, so feed enrichment can never
regress: the narrowed response is trusted only when videoDetails.videoId equals
the requested id — a bare is_some() would accept a gutted videoDetails:{} or wave
through a videoId-stripped decoy, so the id binding also subsumes the decoy check
for this path (audit MED). Full extraction path untouched; po_token path skips
the narrowing.

S7 — reclaim the raw ~1.5 MB player.js once the hot-path snippets (signature
timestamp + nsig) are built, keeping player_url as the installed-generation
sentinel. memo_verdict is rekeyed off player_url (was player_code): under the
old lockstep invariant the two were equivalent, and decoupling is REQUIRED so a
byte-released generation is still "installed" for memo purposes. Release is
single-site, build-success-only, under the state lock; a build FAILURE keeps the
bytes so sibling artifacts still extract; the dead-in-android sig path re-fetches
on demand via ensure_player_code.

Also fixes three leftovers from the 2026-07-29 outage flip (23ab7ad) that the
fdroid CI never caught (it builds the APK but runs no cargo test/clippy): a test
still asserting the old visionOS-true default (cargo test was red on main), the
stale struct doc, and a derivable_impls lint (kept the manual impl explicit +
#[allow] so the load-bearing false default stays greppable). 161 tests, clippy clean.
2026-07-29 11:28:33 -07:00
.forgejo/workflows ci: add gitleaks workflow 2026-05-27 22:15:00 -07:00
src youtube: S3 narrowed-$fields feed metadata + S7 player.js byte-release 2026-07-29 11:28:33 -07:00
tests reliability+safety: nsig shape fixes, bounded self-heal, no url/id leaks, revived JS tests 2026-07-28 22:31:20 -07:00
.gitignore Initial commit 2026-05-24 16:26:57 -07:00
Cargo.lock chore(deps): update rust crate serde_json to v1.0.151 2026-07-23 07:06:15 +00:00
Cargo.toml reliability: bound the JS engine + self-heal on player.js rotation 2026-07-04 06:28:47 -07:00
LICENSE Initial commit 2026-05-24 16:26:57 -07:00
README.md docs: rewrite README for public release 2026-06-28 12:06:47 -07:00

strawcore

A Rust library for extracting YouTube stream URLs, metadata, search results, and channel listings — without the official Data API and without an API key. It is a Rust port of NewPipeExtractor (tracking v0.26.2), scoped to YouTube.

strawcore speaks YouTube's internal InnerTube endpoints directly and resolves the playback-URL signature the same way NewPipeExtractor does: by running YouTube's own player.js in an embedded JavaScript engine. The crate ships as a plain Rust rlib, so it can be embedded in a desktop app, a server, a CLI, or bridged into a mobile app over FFI.

Why an embedded JS engine

Most lightweight extractors regex-scrape player.js and re-implement the signature/n-parameter deobfuscator in their host language. That re-implementation breaks every time YouTube rotates the player. NewPipeExtractor instead embeds a JS engine and executes the deobfuscation function live, which survives rotations. strawcore mirrors that architecture using QuickJS via rquickjs, so the same resilience carries over to Rust.

Status

Early (0.1). YouTube only. The public surface covers:

  • Streams — resolve a video ID to its audio/video stream URLs, formats, and metadata.
  • Search — query with an optional content-type filter, plus continuation (pagination).
  • Channels — resolve a channel ID / @handle / legacy URL to channel info and its video list, plus continuation.
  • Localization — preferred language + content country are honored on InnerTube requests.

Installation

Not yet published to crates.io. Add it as a git dependency:

[dependencies]
strawcore-core = { git = "https://git.sulkta.com/Sulkta-OSS/strawcore" }

The library crate is imported as strawcore_core.

Quick start

You provide an HTTP client by implementing the Downloader trait, or use the bundled reqwest-based default. Install it once into the process-global service singleton, then call the extractors.

use std::sync::Arc;
use strawcore_core::downloader::ReqwestDownloader;
use strawcore_core::youtube::{stream_extractor, search_extractor, channel};
use strawcore_core::youtube::linkhandler::search::SearchFilter;
use strawcore_core::youtube::linkhandler::channel::ChannelIdentifier;
use strawcore_core::NewPipe;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Install a downloader (here, the bundled reqwest client).
    NewPipe::init(Arc::new(ReqwestDownloader::new()?));

    // Resolve a video's streams + metadata.
    let info = stream_extractor::stream_info("dQw4w9WgXcQ")?;
    println!("{}{} streams", info.name, info.video_streams.len());

    // Search for videos.
    let results = search_extractor::search("rust programming", SearchFilter::Videos)?;
    println!("{} results", results.videos.len());

    // Look up a channel by @handle.
    let ch = channel::channel_info(ChannelIdentifier::Handle("@rustlang".into()))?;
    println!("channel: {}", ch.name);

    Ok(())
}

Bring your own HTTP client

Downloader is a single-method trait (execute(Request) -> Result<Response, _>). Implement it over whatever HTTP stack you already have and pass your instance to NewPipe::init, instead of the bundled ReqwestDownloader.

PoTokens

Some YouTube requests can require a proof-of-origin token (po_token), which is minted by YouTube's BotGuard challenge and needs a real browser/WebView to solve. strawcore does not mint these itself; it exposes a PoTokenProvider trait so an embedder can supply one (for example by driving a headless browser). The default provider declines, which is fine for the code paths that do not require a token.

Build and test

cargo build
cargo test --lib                       # offline unit tests
cargo test --features online-tests     # also runs tests that hit the network

Network-dependent integration tests are gated behind the online-tests feature so offline and CI runs stay green.

License

GPL-3.0-or-later. NewPipeExtractor is GPL-3.0-licensed; this port inherits that license.

Acknowledgements

strawcore is a port of NewPipeExtractor by the NewPipe team, and follows its extraction architecture closely. All credit for the original design and the hard-won InnerTube/player reverse-engineering goes to that project.

Contributing

Issues and pull requests are welcome. Please keep changes focused, run cargo fmt, cargo clippy, and cargo test --lib before opening a PR, and add tests for new extraction logic where practical.