1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! `youtube-legend-cli` — a non-interactive Rust CLI for downloading
//! `YouTube` subtitles through third-party providers, using a native
//! Unix `stdin`/`stdout` interface.
//!
//! # Quickstart
//!
//! The fastest way to drive the crate is to construct a [`Cli`] with
//! `Cli::parse()` (as `main.rs` does) and forward it to [`run`]:
//!
//! ```no_run
//! use clap::Parser;
//! use youtube_legend_cli::{run, Cli};
//!
//! # async fn demo() -> Result<(), Box<dyn std::error::Error>> {
//! let cli = Cli::parse_from(["demo", "https://youtu.be/dQw4w9WgXcQ"]);
//! let exit_code = run(cli).await?;
//! # let _ = exit_code;
//! # Ok(()) }
//! ```
//!
//! # Architecture
//!
//! - [`cli`] — `clap`-derived argument parser and the [`Cli`] struct.
//! - [`commands`] — top-level dispatch between single-URL extract and
//! batch mode.
//! - `provider` — the `Provider` trait and the two concrete
//! implementations, plus the `ProviderChain` that walks
//! them with one-request-per-second throttling.
//! - [`parse`] — SRT text extraction and `YouTube` URL/video-id parsing.
//! - [`cache`] — TTL-based local file cache keyed on
//! `(video_id, language, format)`.
//! - [`retry`] — exponential backoff helper and in-memory circuit
//! breaker.
//! - [`io`] — `stdin`/`stdout`/TTY helpers.
//! - [`error`] — the [`error::AppError`] enum and the process exit-code
//! table.
//! - [`logging`] — initialiser for the global `tracing` subscriber.
//! - `text` — Unicode NFC normalisation.
//!
//! # Stream contracts
//!
//! - `stdout` is reserved exclusively for the subtitle body (or the
//! `--json` envelope).
//! - `stderr` is reserved exclusively for logs, progress, and human
//! error messages.
//! - `stdin` accepts a single URL, a batch of one-URL-per-line, or
//! `--batch` flag input.
//!
//! # Cancellation
//!
//! `SIGINT` and `SIGTERM` are wired through `tokio_util::CancellationToken`
//! in `main.rs`. In-flight requests are allowed to complete; the process
//! exits with code 130. The async API exposed by this crate is
//! cancellation-safe at every public await point.
//!
//! # Minimum supported Rust version (MSRV)
//!
//! `1.88.0` — declared in `Cargo.toml` `rust-version` field.
//! The local toolchain pinned via `rust-toolchain.toml` may be
//! newer; the MSRV in `Cargo.toml` is the contract with users.
// Lints centralizados em [lints.clippy]/[lints.rust]/[lints.rustdoc] no Cargo.toml (auditoria rules
// rust docs v0.2.9). Não duplicar aqui para evitar override warnings.
/// Cache subsystem: TTL-keyed local files for fetched subtitles.
/// Command-line argument parser (clap derive).
/// Top-level command dispatch: extract one URL, or batch many.
/// Error types and process exit-code table.
/// Stdin / stdout / TTY helpers.
/// `tracing` subscriber initialiser.
/// SRT text extraction and YouTube URL / video-id parsing.
/// Provider trait, two concrete implementations, and the provider chain
/// with throttling.
/// Exponential-backoff retry helper and in-memory circuit breaker.
/// Internal constants for provider hosts and paths. Gitignored;
/// never published.
pub
/// Unicode NFC normalisation.
pub
use ExitCode;
pub use ;
pub use ;
/// Top-level entry point that wires the parsed [`Cli`] to the command
/// dispatch. See `main.rs` for the binary that calls this.
///
/// # Errors
///
/// - [`error::AppError::InvalidUsage`] when the CLI was validated and
/// found to have a bad combination of flags.
/// - Any of the provider / network / cache / IO errors described in
/// [`error::AppError`].
///
/// # Cancel safety
///
/// This future is cancel-safe: dropping it before completion does not
/// leak cache writes or partial fetches; the in-flight HTTP request is
/// aborted at the next `await` point.
pub async