1use reqwest::{Url, header, header::HeaderMap};
2use failure::{Error, bail};
3use serde::{Serialize, Deserialize};
4
5use crate::{
6 plugin_conf, config::Rtd,
7 plugins::{TitlePlugin, PluginConfig},
8};
9
10#[derive(Serialize, Deserialize, Default, Clone)]
12#[serde(default)]
13pub struct Config {
14 api_key: String,
15}
16
17pub struct ImgurPlugin {}
19
20#[cfg(not(test))]
21static REQUEST_URL: &str = "https://api.imgur.com/3/";
22
23impl TitlePlugin for ImgurPlugin {
24 fn name(&self) -> &'static str { "imgur" }
25
26 fn check(&self, config: &PluginConfig, url: &Url) -> bool {
27 if config.imgur.api_key.is_empty() {
28 false
29 } else {
30 url.domain() == Some("imgur.com") && url.path().starts_with("/gallery/")
31 }
32 }
33
34 fn evaluate(&self, rtd: &Rtd , url: &Url) -> Result<String, Error> {
35 let mut headers = HeaderMap::new();
36
37 let req_url = Url::parse(REQUEST_URL)?
38 .join(&url.path()[1..])? .into_string();
40 let header_content = format!("Client-ID {}", &plugin_conf!(rtd, imgur).api_key);
41
42 headers.insert(header::AUTHORIZATION, header_content.parse()?);
43
44 let client = match rtd.get_client() {
45 Ok(c) => c,
46 _ => bail!("Can't get http client"),
47 };
48
49 let res = client
50 .request_with_headers(&req_url, headers)?
51 .json::<Resp>()?;
52
53 Ok(res.data.title)
54 }
55}
56
57#[derive(Debug, Deserialize)]
60struct Resp {
61 data: Data,
62}
63
64#[derive(Debug, Deserialize)]
65struct Data {
66 title: String,
67}
68
69#[cfg(test)]
72static REQUEST_URL: &str = "http://127.0.0.1:28284/3/";
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use std::{
78 thread,
79 time::Duration,
80 };
81 use tiny_http::Response;
82
83 #[test]
84 fn name() {
85 let plugin = ImgurPlugin {};
86 assert_eq!(plugin.name(), "imgur");
87 }
88
89 #[test]
90 fn check() {
91 let plugin = ImgurPlugin {};
92 let mut config = PluginConfig::default();
93 let url = Url::parse("https://imgur.com/gallery/foo").unwrap();
94 let bad_url = Url::parse("https://i.imgur.com/foo").unwrap();
95
96 assert_eq!(plugin.check(&config, &url), false);
98 assert_eq!(plugin.check(&config, &bad_url), false);
99
100 config.imgur.api_key = String::from("bar");
102 assert_eq!(plugin.check(&config, &url), true);
103 assert_eq!(plugin.check(&config, &bad_url), false);
104 }
105
106 #[test]
107 fn evaluate_no_client() {
108 let plugin = ImgurPlugin {};
109 let rtd = Rtd::new();
110 let url = "https://imgur.com/gallery/0pVuZq8";
111 let res = plugin.evaluate(&rtd, &url.parse().unwrap());
112 assert!(res.is_err());
113 if let Err(e) = res { assert_eq!(&format!("{}", e), "Can't get http client"); }
114 }
115
116 #[test]
117 fn evaluate() {
118 let plugin = ImgurPlugin {};
119 let rtd = Rtd::new().init_http_client().unwrap();
120 let bind = "127.0.0.1:28284";
121 let url = "https://imgur.com/gallery/0pVuZq8";
122 let response = r#"{"data":{"id":"0pVuZq8","title":"Ducks and Dog","description":null,"datetime":1594707178,"cover":"0EDF1TX","cover_width":640,"cover_height":611,"account_url":"s3krit","account_id":123456789,"privacy":"hidden","layout":"blog","views":20291,"link":"https://imgur.com/a/0pVuZq8","ups":402,"downs":6,"points":396,"score":406,"is_album":true,"vote":null,"favorite":false,"nsfw":false,"section":"","comment_count":11,"favorite_count":65,"topic":"No Topic","topic_id":29,"images_count":1,"in_gallery":true,"is_ad":false,"tags":[],"ad_type":0,"ad_url":"","in_most_viral":true,"include_album_ads":false,"images":[{"id":"0EDF1TX","title":null,"description":null,"datetime":1594707145,"type":"image/jpeg","animated":false,"width":640,"height":611,"size":120730,"views":11965,"bandwidth":1444534450,"vote":null,"favorite":false,"nsfw":null,"section":null,"account_url":null,"account_id":null,"is_ad":false,"in_most_viral":false,"has_sound":false,"tags":[],"ad_type":0,"ad_url":"","edited":"0","in_gallery":false,"link":"https://i.imgur.com/0EDF1TX.jpg","comment_count":null,"favorite_count":null,"ups":null,"downs":null,"points":null,"score":null}],"ad_config":{"safeFlags":["in_gallery","sixth_mod_safe","gallery","album"],"highRiskFlags":[],"unsafeFlags":[],"wallUnsafeFlags":[],"showsAds":true}},"success":true,"status":200}"#;
123
124 let server_thread = thread::spawn(move || {
125 let server = tiny_http::Server::http(bind).unwrap();
126 let rq = server.recv().unwrap();
127 if rq.url().to_string().starts_with("/3/") {
128 let resp = Response::from_string(response);
129 thread::sleep(Duration::from_millis(10));
130 rq.respond(resp).unwrap();
131 }
132 });
133
134 thread::sleep(Duration::from_millis(1000));
135
136 let res = plugin.evaluate(&rtd, &url.parse().unwrap()).unwrap();
137 assert_eq!(res, String::from("Ducks and Dog"));
138
139 server_thread.join().unwrap();
140 }
141}