1use anyhow::{anyhow, Context, Result};
2use reqwest::blocking::multipart;
3use serde::{Deserialize, Serialize};
4const API_BASE: &str = "https://api.awau.moe";
5const USER_AGENT: &str = "WhatsThisClient (https://owo.codes/okashi/owo-rs, 0.4.0)";
6
7#[derive(Debug, Serialize, Deserialize)]
8pub struct UploadResponse {
9 pub success: bool,
10 pub files: Vec<File>,
11}
12
13#[derive(Debug, Serialize, Deserialize)]
14pub struct File {
15 pub success: bool,
16 pub hash: String,
17 pub name: String,
18 pub url: String,
19 pub size: Option<i64>,
20}
21
22#[derive(Debug, Serialize, Deserialize)]
23pub struct DeleteResponse {
24 pub success: bool,
25 pub data: FileListData,
26}
27
28#[derive(Debug, Serialize, Deserialize)]
29pub struct FileListResponse {
30 pub success: bool,
31 pub total_objects: i64,
32 pub data: Vec<FileListData>,
33}
34
35#[derive(Debug, Serialize, Deserialize)]
36pub struct FileListData {
37 pub bucket: String,
38 pub key: String,
39 pub dir: String,
40 pub r#type: i64,
41 pub dest_url: Option<String>,
42 pub content_type: Option<String>,
43 pub content_length: Option<i64>,
44 pub created_at: String,
45 pub deleted_at: Option<String>,
46 pub delete_reason: Option<String>,
47 pub md5_hash: Option<String>,
48 pub sha256_hash: Option<String>,
49 pub associated_with_current_user: bool,
50}
51
52pub fn list_files(key: &str, entries: &i64, offset: &i64) -> Result<FileListResponse> {
65 let url = format!("{API_BASE}/objects?limit={entries}&offset={offset}");
66
67 let client = reqwest::blocking::Client::new();
68
69 let resp = client
70 .get(url)
71 .header(reqwest::header::AUTHORIZATION, key)
72 .header(reqwest::header::USER_AGENT, USER_AGENT)
73 .send()?;
74
75 match resp.status() {
76 reqwest::StatusCode::OK => Ok(resp.json::<FileListResponse>()?),
77 i => Err(anyhow!(i)),
78 }
79}
80
81pub fn delete_file(key: &str, object: &str) -> Result<DeleteResponse> {
93 let url = format!("{API_BASE}/objects/{object}");
94
95 let client = reqwest::blocking::Client::new();
96
97 let resp = client
98 .delete(url)
99 .header(reqwest::header::AUTHORIZATION, key)
100 .header(reqwest::header::USER_AGENT, USER_AGENT)
101 .send()?;
102
103 match resp.status() {
104 reqwest::StatusCode::OK => Ok(resp.json::<DeleteResponse>()?),
105 i => Err(anyhow!(i)),
106 }
107}
108
109pub fn shorten(key: &str, s_url: &str) -> Result<String> {
117 let url = format!("{API_BASE}/shorten/polr");
118
119 let client = reqwest::blocking::Client::new();
120 let params = [("action", "shorten"), ("url", s_url)];
121 let url = reqwest::Url::parse_with_params(&url, params)?;
122
123 let resp = client
124 .get(url)
125 .header(reqwest::header::AUTHORIZATION, key)
126 .header(reqwest::header::USER_AGENT, USER_AGENT)
127 .send()?;
128
129 match resp.status() {
130 reqwest::StatusCode::OK => Ok(resp.text()?),
131 i => Err(anyhow!(i)),
132 }
133}
134
135pub fn upload<
150 R: std::io::Read + std::marker::Send + 'static,
151 S: Into<String> + std::fmt::Display,
152>(
153 key: &str,
154 in_file: R,
155 mime_type: S,
156 file_name: S,
157 associated: &bool,
158) -> Result<UploadResponse> {
159 let mime_type = mime_type.into();
160 let file_name = file_name.into();
161
162 let url = match associated {
163 true => format!("{}/upload/pomf/associated", API_BASE),
164 false => format!("{}/upload/pomf", API_BASE),
165 };
166
167 let file_part = multipart::Part::reader(in_file)
168 .file_name(file_name)
169 .mime_str(&mime_type)
170 .expect("Error creating Multiform Part!");
171
172 let multi_form = multipart::Form::new()
173 .text("type", mime_type)
174 .part("files[]", file_part);
175
176 let client = reqwest::blocking::Client::new();
177 let resp = client
178 .post(url)
179 .header(reqwest::header::AUTHORIZATION, key)
180 .header(reqwest::header::USER_AGENT, USER_AGENT)
181 .multipart(multi_form)
182 .send()
183 .context("Failed to get request")?;
184
185 match resp.status() {
186 reqwest::StatusCode::OK => match resp.json::<UploadResponse>() {
187 Ok(i) => Ok(i),
188 Err(e) => Err(anyhow!(e)),
189 },
190 i => Err(anyhow!(i)),
191 }
192}