yt_live_rs/
error.rs

1//! Error types for the yt-live-rs library.
2//!
3//! This module defines all error types that can occur when using the library.
4//! The main error type is [`Error`], and [`Result<T>`] is a type alias for
5//! `std::result::Result<T, Error>`.
6
7use thiserror::Error;
8
9/// Result type alias for the library.
10pub type Result<T> = std::result::Result<T, Error>;
11
12/// Error types that can occur when using the library.
13///
14/// This enum covers all possible errors from network requests, parsing,
15/// stream availability, and download operations.
16#[derive(Debug, Clone, Error)]
17pub enum Error {
18    /// HTTP request failed.
19    ///
20    /// This can occur due to network issues, timeouts, or server errors.
21    #[error("HTTP request failed: {0}")]
22    Http(String),
23
24    /// URL parsing failed.
25    ///
26    /// The provided URL could not be parsed as a valid URL.
27    #[error("Invalid URL: {0}")]
28    Url(String),
29
30    /// JSON parsing failed.
31    ///
32    /// The response from YouTube could not be parsed as valid JSON.
33    #[error("JSON parsing failed: {0}")]
34    Json(String),
35
36    /// XML parsing failed.
37    ///
38    /// The DASH manifest could not be parsed as valid XML.
39    #[error("XML parsing failed: {0}")]
40    Xml(String),
41
42    /// IO operation failed.
43    ///
44    /// File reading/writing or other IO operations failed.
45    #[error("IO error: {0}")]
46    Io(String),
47
48    /// Invalid YouTube URL format.
49    ///
50    /// The URL is not a recognized YouTube URL format.
51    /// Supported formats include:
52    /// - `https://youtube.com/watch?v=VIDEO_ID`
53    /// - `https://youtu.be/VIDEO_ID`
54    /// - `https://youtube.com/@channel/live`
55    #[error("Invalid YouTube URL: {0}")]
56    InvalidYouTubeUrl(String),
57
58    /// Video not found.
59    ///
60    /// The video ID does not exist or is not accessible.
61    #[error("Video not found: {0}")]
62    VideoNotFound(String),
63
64    /// The video is not a live stream.
65    ///
66    /// This library only supports live streams, not regular videos.
67    #[error("Stream is not a live stream")]
68    NotLiveStream,
69
70    /// Stream is currently offline.
71    ///
72    /// The live stream exists but is not currently broadcasting.
73    /// Check `scheduled_start` for when it might go live.
74    #[error("Stream is offline: {reason}")]
75    StreamOffline {
76        /// Reason the stream is offline.
77        reason: String,
78        /// Scheduled start time, if known.
79        scheduled_start: Option<String>,
80    },
81
82    /// Stream is unplayable.
83    ///
84    /// YouTube has blocked playback for some reason (geo-restriction, etc.).
85    #[error("Stream is unplayable: {0}")]
86    Unplayable(String),
87
88    /// Error in the player response from YouTube.
89    #[error("Player response error: {0}")]
90    PlayerResponseError(String),
91
92    /// No DASH manifest available.
93    ///
94    /// The stream doesn't have a DASH manifest, which is required for downloading.
95    #[error("No DASH manifest available")]
96    NoDashManifest,
97
98    /// Requested quality is not available.
99    ///
100    /// The stream doesn't offer the requested quality level.
101    #[error("Quality {0} not available")]
102    QualityNotAvailable(String),
103
104    /// Download operation failed.
105    #[error("Download failed: {0}")]
106    DownloadFailed(String),
107
108    /// Fragment download failed after retries.
109    #[error("Fragment {seq} download failed after {tries} tries")]
110    FragmentFailed {
111        /// Sequence number of the failed fragment.
112        seq: u64,
113        /// Number of retry attempts made.
114        tries: u32,
115    },
116
117    /// Cookie file parsing failed.
118    ///
119    /// The cookies file is not in valid Netscape format.
120    #[error("Cookie parsing failed: {0}")]
121    CookieParseFailed(String),
122
123    /// Required data is missing from the response.
124    #[error("Missing required data: {0}")]
125    MissingData(String),
126
127    /// PO Token is required for this stream.
128    ///
129    /// Some streams require a PO token for authentication.
130    /// Use [`ClientBuilder::po_token`](crate::ClientBuilder::po_token) to provide one.
131    #[error("PO Token is required for this stream")]
132    PoTokenRequired,
133
134    /// Login is required to access this stream.
135    ///
136    /// Provide cookies from a logged-in session using
137    /// [`ClientBuilder::cookies_file`](crate::ClientBuilder::cookies_file).
138    #[error("Login required - please provide cookies")]
139    LoginRequired,
140
141    /// This is a members-only stream.
142    ///
143    /// Access requires channel membership. Provide cookies from
144    /// a logged-in account with an active membership.
145    #[error("This is a members-only stream")]
146    MembersOnly,
147
148    /// Regex compilation or matching error.
149    #[error("Regex error: {0}")]
150    Regex(String),
151}
152
153impl From<reqwest::Error> for Error {
154    fn from(e: reqwest::Error) -> Self {
155        Error::Http(e.to_string())
156    }
157}
158
159impl From<url::ParseError> for Error {
160    fn from(e: url::ParseError) -> Self {
161        Error::Url(e.to_string())
162    }
163}
164
165impl From<serde_json::Error> for Error {
166    fn from(e: serde_json::Error) -> Self {
167        Error::Json(e.to_string())
168    }
169}
170
171impl From<quick_xml::DeError> for Error {
172    fn from(e: quick_xml::DeError) -> Self {
173        Error::Xml(e.to_string())
174    }
175}
176
177impl From<std::io::Error> for Error {
178    fn from(e: std::io::Error) -> Self {
179        Error::Io(e.to_string())
180    }
181}
182
183impl From<regex::Error> for Error {
184    fn from(e: regex::Error) -> Self {
185        Error::Regex(e.to_string())
186    }
187}