1use serde::Deserialize;
2use std::fmt;
3
4#[derive(Debug, Deserialize)]
5pub struct CobaltError {
6 pub code: String,
7 #[serde(skip_serializing_if = "Option::is_none")]
8 pub context: Option<ErrorContext>,
9}
10
11#[derive(Debug, Deserialize)]
12pub struct ErrorContext {
13 #[serde(skip_serializing_if = "Option::is_none")]
14 pub service: Option<String>,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub limit: Option<u32>,
17}
18
19impl fmt::Display for CobaltError {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match self.code.to_ascii_lowercase().as_str() {
22 "error.api.unreachable" => f.write_str("API unreachable (try again later)"),
23 "error.api.timed_out" => f.write_str("API timeout (try again later)"),
24 "error.api.rate_exceeded" => f.write_str("Rate limited (try again later)"),
25 "error.api.capacity" => f.write_str("API busy (try again later)"),
26 "error.api.generic" => f.write_str("General API error (try again later)"),
27 "error.api.unknown_response" => f.write_str("Download failure. Make sure the link is valid. (unknown response)"),
28 "error.api.service.unsupported" => f.write_str("That service or website is not supported."),
29 "error.api.service.disabled" => f.write_str("Downloading from that service or website is temporarily disabled."),
30 "error.api.link.invalid" => f.write_str("That link is invalid. Make sure it is correct."),
31 "error.api.link.unsupported" => f.write_str("That link or format is unsupported."),
32 "error.api.fetch.fail" => f.write_str("Failed to fetch the media. Make sure the link is valid, or try again later."),
33 "error.api.fetch.critical" => f.write_str("Critical error fetching the media. Make sure the link is valid, or try again later."),
34 "error.api.fetch.empty" => f.write_str("The service or website returned no data. This may be caused by the site blocking the downloader (try again later)"),
35 "error.api.fetch.rate" => f.write_str("The service or website has rate limited the downloader (try again later)"),
36 "error.api.fetch.short_link" => f.write_str("Unable to resolve the shortlink. Try using the full link to the media."),
37 "error.api.content.too_long" => f.write_str("The requested content is too big."),
38 "error.api.content.video.unavailable" => f.write_str("That video is unavailable. Make sure it is not region or age restricted, and is not private."),
39 "error.api.content.video.live" => f.write_str("Live videos are unsupported."),
40 "error.api.content.video.private" => f.write_str("That video is private."),
41 "error.api.content.video.age" => f.write_str("That video is age restricted."),
42 "error.api.content.video.region" => f.write_str("That video is region restricted."),
43 "error.api.content.post.unavailable" => f.write_str("That post is unavailable. Make sure it is not region or age restricted, and is not private."),
44 "error.api.content.post.private" => f.write_str("That post is private."),
45 "error.api.content.post.age" => f.write_str("That post is age restricted."),
46 "error.api.youtube.codec" => f.write_str("Missing YouTube codec. This is a bug."),
47 "error.api.youtube.decipher" => f.write_str("Cannot decipher that video. Something probably broke."),
48 "error.api.youtube.login" => f.write_str("That video requires a logged in account, which we do not have."),
49 "error.api.youtube.token_expired" => f.write_str("Our YouTube token expired (try again later)"),
50 "error.api.youtube.temporary_disabled" => f.write_str("YouTube support is temporarily disabled. Try again later."),
51 _ => f.write_str(&self.code),
52 }
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn test_error_display() {
62 let error = CobaltError {
63 code: "error.api.unreachable".to_string(),
64 context: None,
65 };
66 assert_eq!(format!("{}", error), "API unreachable (try again later)");
67 }
68
69 #[test]
70 fn test_error_unknown() {
71 let error = CobaltError {
72 code: "error.api.unknown".to_string(),
73 context: None,
74 };
75 assert_eq!(format!("{}", error), "error.api.unknown");
76 }
77}