Classify yt-dlp failures into actionable buckets (2.3)
When a job fails, today the user sees a raw stderr line — often something like "ERROR: [youtube] dQw4w9WgXcQ: Sign in to confirm you're not a bot" that doesn't tell a non-expert what to do. New src/error_class.rs scans the failed job's log buffer for the nine well-known yt-dlp fingerprints and returns: - an ErrorClass enum (rate-limited, members-only, geo-blocked, not-found, codec-missing, disk-full, network-error, bad-cookies, other) - a one-line human-readable suggested action paired with each class Auto-populated in Job::drain when state transitions to Failed. Exposed on JobSnapshot as error_class + error_hint. Rendered in the web UI Downloads modal (red badge + hint box) and the desktop downloads panel (colored label + hint text). Other (no fingerprint matched) is filtered out of the badge so the existing raw last_line keeps doing the talking for unknown failures. Includes 10 unit tests covering each pattern + the walks-from-end priority case. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
a8b14f250a
commit
d9a7007f34
6 changed files with 365 additions and 8 deletions
17
src/web.rs
17
src/web.rs
|
|
@ -61,6 +61,17 @@ pub struct JobSnapshot {
|
|||
pub state: &'static str,
|
||||
pub progress: f32,
|
||||
pub last_line: String,
|
||||
/// Classification of the failure, if `state == "failed"`. One of
|
||||
/// `rate-limited`, `members-only`, `geo-blocked`, `not-found`,
|
||||
/// `codec-missing`, `disk-full`, `network-error`, `bad-cookies`, `other`,
|
||||
/// or `null` while still running / on success. Drives the suggested
|
||||
/// action hint in the UI.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub error_class: Option<crate::error_class::ErrorClass>,
|
||||
/// Human-readable one-line suggested action paired with `error_class`.
|
||||
/// Empty when `error_class` is `Other` or `None`.
|
||||
#[serde(skip_serializing_if = "str::is_empty")]
|
||||
pub error_hint: &'static str,
|
||||
}
|
||||
|
||||
/// All mutable state shared across axum handlers via `Arc<WebState>`.
|
||||
|
|
@ -145,6 +156,12 @@ impl WebState {
|
|||
},
|
||||
progress: j.progress,
|
||||
last_line: j.log.back().cloned().unwrap_or_default(),
|
||||
// Skip `Other` so the badge doesn't get a useless generic
|
||||
// label — the raw log line is still shown for that case.
|
||||
error_class: j.failure_class.filter(|c|
|
||||
*c != crate::error_class::ErrorClass::Other
|
||||
),
|
||||
error_hint: j.failure_class.map(|c| c.hint()).unwrap_or(""),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue