|
Some checks failed
gitleaks / scan (push) Failing after 5s
Straw audit 2026-07-04. Three availability defects in the extraction core: - runtime.rs: cap the embedded QuickJS runtime (64 MiB mem / 2 MiB stack / 5s wall-clock interrupt) so a hostile or looping player.js can't hang the extraction thread or OOM the process. Previously Runtime::new() set no limits. - player_manager.rs: replace the never-cleared sticky-error flags with invalidate-on-failure. Any deobf/extract error now drops the cached player.js so the next call re-fetches fresh and retries, instead of one routine player.js rotation permanently wedging ALL extraction until app restart (clear_all_caches existed but was never called). - stream_extractor.rs: per-format graceful degradation. nsig-deobf failure falls back to the throttled original URL (YouTube still serves it, rate-limited); sig-cipher failure skips just that format. One bad format no longer aborts the whole video, and manifests/captions still populate. NPE parity. - Cargo.toml: release panic=unwind (inert as a straw dep; kept consistent for standalone builds/tests). 120 tests pass, clippy clean. |
||
|---|---|---|
| .forgejo/workflows | ||
| src | ||
| tests | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
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.