youtube-legend-cli 0.4.0

Non-interactive Rust CLI that downloads YouTube subtitles through third-party providers, using a native Unix stdin/stdout interface.
//! Network layer: WAF classification and session/fingerprint
//! management.
//!
//! # Why this module exists
//!
//! CORRECTED on 2026-09-04. This header used to open by saying the CLI
//! drives a real Chromium instance, and to list four submodules. Two of
//! them, `intercept` and `observe`, were deleted with the browser
//! subsystem on 2026-09-04 under GAP-2026-218, and the six intra-doc
//! links pointing at them turned `cargo doc` red under
//! `rustdoc::broken_intra_doc_links = "deny"`. The four local gates that
//! run on every change — `fmt`, `clippy`, `build`, `test` — do not build
//! documentation, so the breakage survived them all.
//!
//! Every provider in the chain now speaks plain HTTP. What remains here
//! are the two concerns that outlive the browser, because a protected
//! site answers an HTTP client the same way it answered a browser:
//!
//! - [`waf`] — classifies which protection vendor is in front of a
//!   host, by header and by cookie, and decides when to stop retrying.
//! - [`session`] — a persistent cookie jar plus a Chrome-coherent
//!   request-header fingerprint.
//!
//! # Testability
//!
//! Every classification, redaction and ordering decision in this module
//! is a pure function over plain data, and no test here opens a socket.
//! That property predates the removal: it was written when a browser
//! still existed, and it is the reason the removal cost this module
//! nothing but a header.
//!
//! # Stream contract
//!
//! `stdout` is reserved for the subtitle payload, and nothing in this
//! module ever writes to it.

/// Session cookie jar and Chrome-coherent header fingerprint.
pub mod session;

/// Web-application-firewall classification and escalation policy.
pub mod waf;

pub use session::{
    ChromeFingerprint, ChromePlatform, CookieJar, FetchMetadata, RequestContext, StoredCookie,
};
pub use waf::{
    detect as detect_waf, is_challenge_cookie, EscalationPolicy, EscalationVerdict, WafDetection,
    WafSignal, WafVendor,
};

/// User-Agent this crate sends when the operator sets none.
///
/// It is a compile-time string, so it can never drift from the version
/// in the manifest. Until 2026-08-31 the same `concat!` was written out
/// in four provider modules, and the `user_agent` config key that was
/// supposed to govern them reached none of them.
pub const DEFAULT_USER_AGENT: &str =
    concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));

/// Effective User-Agent for outbound HTTP.
///
/// Reads through the tuning registry, so it observes the documented
/// precedence: `--user-agent`, then the `user_agent` key of the XDG
/// file, then [`DEFAULT_USER_AGENT`]. The command dispatcher publishes
/// the merged flag value, which is what lets a provider that never sees
/// the parsed `Cli` still honour the command line.
pub fn user_agent() -> String {
    crate::config::tuning_string_or("user_agent", DEFAULT_USER_AGENT)
}

#[cfg(test)]
mod user_agent_tests {
    use super::{user_agent, DEFAULT_USER_AGENT};

    /// With nothing installed in the tuning registry the resolver
    /// answers the compiled default, which is the fallback every
    /// provider used to hard-code for itself.
    #[test]
    fn falls_back_to_the_compiled_default() {
        assert_eq!(user_agent(), DEFAULT_USER_AGENT);
    }

    /// The compiled default carries the crate name and the manifest
    /// version, so it cannot drift from the released artefact.
    #[test]
    fn the_default_names_the_crate_and_its_version() {
        let (name, version) = DEFAULT_USER_AGENT
            .split_once('/')
            .expect("the default is name/version");
        assert_eq!(name, env!("CARGO_PKG_NAME"));
        assert_eq!(version, env!("CARGO_PKG_VERSION"));
    }
}