1use core::fmt::{Debug, Display};
3pub use json_crawler::CrawlerError as JsonError;
4use std::hash::{Hash, Hasher};
5use std::io;
6use std::time::SystemTimeError;
7
8pub type Result<T> = core::result::Result<T, Error>;
10
11pub struct Error {
13 inner: Box<ErrorKind>,
16}
17
18#[non_exhaustive]
22pub enum ErrorKind {
23 JsonParsing(JsonError),
25 Web {
27 message: String,
28 },
29 Io(io::Error),
32 InvalidResponse {
35 response: String,
36 },
37 Header,
39 UnableToSerializeGoogleOAuthToken {
40 response: String,
41 err: serde_json::Error,
42 },
43 UnableToParseYtCfg {
45 ytcfg: String,
46 },
47 NoVisitorData,
49 InvalidUserAgent(String),
51 OAuthTokenExpired {
54 token_hash: u64,
55 },
56 OtherErrorCodeInResponse {
60 code: u64,
61 message: String,
62 },
63 ApiStatusFailed,
65 SystemTimeError {
67 message: String,
68 },
69 InvalidUploadFilename {
71 filename: String,
72 message: String,
73 },
74 MissingUploadUrl,
75}
76#[derive(Debug, Clone)]
78pub enum ParseTarget {
79 Array,
80 Other(String),
81}
82impl Error {
83 pub fn into_kind(self) -> ErrorKind {
85 *self.inner
86 }
87 pub(crate) fn invalid_user_agent<S: Into<String>>(user_agent: S) -> Self {
88 Self {
89 inner: Box::new(ErrorKind::InvalidUserAgent(user_agent.into())),
90 }
91 }
92 pub(crate) fn oauth_token_expired(token: &crate::auth::OAuthToken) -> Self {
93 let mut h = std::hash::DefaultHasher::new();
94 token.hash(&mut h);
95 let token_hash = h.finish();
96 Self {
97 inner: Box::new(ErrorKind::OAuthTokenExpired { token_hash }),
98 }
99 }
100 pub(crate) fn header() -> Self {
101 Self {
102 inner: Box::new(ErrorKind::Header),
103 }
104 }
105 pub(crate) fn ytcfg(ytcfg: impl Into<String>) -> Self {
106 Self {
107 inner: Box::new(ErrorKind::UnableToParseYtCfg {
108 ytcfg: ytcfg.into(),
109 }),
110 }
111 }
112 pub(crate) fn no_visitor_data() -> Self {
113 Self {
114 inner: Box::new(ErrorKind::NoVisitorData),
115 }
116 }
117 pub(crate) fn response<S: Into<String>>(response: S) -> Self {
118 let response = response.into();
119 Self {
120 inner: Box::new(ErrorKind::InvalidResponse { response }),
121 }
122 }
123 pub(crate) fn unable_to_serialize_oauth<S: Into<String>>(
124 response: S,
125 err: serde_json::Error,
126 ) -> Self {
127 let response = response.into();
128 Self {
129 inner: Box::new(ErrorKind::UnableToSerializeGoogleOAuthToken { response, err }),
130 }
131 }
132 pub(crate) fn other_code(code: u64, message: String) -> Self {
133 Self {
134 inner: Box::new(ErrorKind::OtherErrorCodeInResponse { code, message }),
135 }
136 }
137 pub(crate) fn status_failed() -> Self {
138 Self {
139 inner: Box::new(ErrorKind::ApiStatusFailed),
140 }
141 }
142 pub(crate) fn invalid_upload_filename(filename: String, message: String) -> Self {
143 Self {
144 inner: Box::new(ErrorKind::InvalidUploadFilename { filename, message }),
145 }
146 }
147 pub(crate) fn missing_upload_url() -> Self {
148 Self {
149 inner: Box::new(ErrorKind::MissingUploadUrl),
150 }
151 }
152 pub(crate) fn web(message: impl Into<String>) -> Self {
153 Self {
154 inner: Box::new(ErrorKind::Web {
155 message: message.into(),
156 }),
157 }
158 }
159}
160
161impl std::error::Error for Error {}
162impl Display for ErrorKind {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 match self {
165 ErrorKind::Web { message } => write!(f, "Web error <{message}> received."),
166 ErrorKind::Io(e) => write!(f, "IO error {e} recieved."),
167 ErrorKind::Header => write!(f, "Error parsing header."),
168 ErrorKind::InvalidResponse { response } => {
169 write!(
170 f,
171 "Response is invalid json - unable to deserialize. <{response}>"
172 )
173 }
174 ErrorKind::OtherErrorCodeInResponse { code, message } => {
175 write!(
176 f,
177 "Http error code {code} recieved in response. Message: <{message}>."
178 )
179 }
180 ErrorKind::ApiStatusFailed => write!(f, "Api returned STATUS_FAILED for the query"),
181 ErrorKind::OAuthTokenExpired { token_hash: _ } => write!(f, "OAuth token has expired"),
182 ErrorKind::InvalidUserAgent(u) => write!(f, "InnerTube rejected User Agent {u}"),
183 ErrorKind::UnableToSerializeGoogleOAuthToken { response, err } => write!(
184 f,
185 "Unable to serialize Google auth token {response}, received error {err}"
186 ),
187 ErrorKind::SystemTimeError { message } => write!(
188 f,
189 "Error obtaining system time to use in API query. <{message}>"
190 ),
191 ErrorKind::JsonParsing(e) => write!(f, "{e}"),
192 ErrorKind::UnableToParseYtCfg { ytcfg } => write!(
193 f,
194 "Unable to parse ytcfg - expected the function to exist and contain json. Received: {ytcfg}"
195 ),
196 ErrorKind::NoVisitorData => write!(f, "ytcfg didn't include VISITOR_DATA"),
197 ErrorKind::InvalidUploadFilename {
198 filename,
199 message: msg,
200 } => write!(
201 f,
202 "Invalid upload filename {filename}. Error message: {msg}"
203 ),
204 ErrorKind::MissingUploadUrl => {
205 write!(f, "expected an x-goog-upload-url but didn't get one")
206 }
207 }
208 }
209}
210impl Debug for Error {
213 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214 Display::fmt(&*self.inner, f)
216 }
217}
218impl Display for Error {
219 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220 Display::fmt(&*self.inner, f)
221 }
222}
223impl From<reqwest::Error> for Error {
224 fn from(err: reqwest::Error) -> Self {
225 let message = err.to_string();
226 Self {
227 inner: Box::new(ErrorKind::Web { message }),
228 }
229 }
230}
231impl From<io::Error> for Error {
232 fn from(err: io::Error) -> Self {
233 Self {
234 inner: Box::new(ErrorKind::Io(err)),
235 }
236 }
237}
238impl From<SystemTimeError> for Error {
239 fn from(err: SystemTimeError) -> Self {
240 let message = err.to_string();
241 Self {
242 inner: Box::new(ErrorKind::SystemTimeError { message }),
243 }
244 }
245}
246impl From<ErrorKind> for Error {
247 fn from(value: ErrorKind) -> Self {
248 Self {
249 inner: Box::new(value),
250 }
251 }
252}
253impl From<JsonError> for Error {
254 fn from(value: JsonError) -> Self {
255 let e = ErrorKind::JsonParsing(value);
256 Self { inner: Box::new(e) }
257 }
258}