modio/request/mods/media/
add_mod_media.rs1use std::ffi::OsStr;
2use std::future::IntoFuture;
3use std::path::Path;
4
5use crate::client::Client;
6use crate::request::multipart::{Form, Part};
7use crate::request::{Output, RequestBuilder, Route};
8use crate::response::ResponseFuture;
9use crate::types::id::{GameId, ModId};
10use crate::types::Message;
11
12pub struct AddModMedia<'a> {
14 http: &'a Client,
15 game_id: GameId,
16 mod_id: ModId,
17 fields: AddModMediaFields<'a>,
18}
19
20struct AddModMediaFields<'a> {
21 sync: Option<bool>,
22 logo: Option<Part>,
23 images: Vec<Part>,
24 images_zip: Option<Part>,
25 youtube: Option<&'a [&'a str]>,
26 sketchfab: Option<&'a [&'a str]>,
27}
28
29impl<'a> AddModMedia<'a> {
30 pub(crate) const fn new(http: &'a Client, game_id: GameId, mod_id: ModId) -> Self {
31 Self {
32 http,
33 game_id,
34 mod_id,
35 fields: AddModMediaFields {
36 sync: None,
37 logo: None,
38 images: Vec::new(),
39 images_zip: None,
40 youtube: None,
41 sketchfab: None,
42 },
43 }
44 }
45
46 pub const fn sync(mut self, value: bool) -> Self {
47 self.fields.sync = Some(value);
48 self
49 }
50
51 pub fn logo<P: AsRef<Path>>(mut self, file: P) -> Self {
52 let part = Part::file(file, "logo.png").mime(mime::IMAGE_STAR);
53 self.fields.logo = Some(part);
54 self
55 }
56
57 pub fn images_zip<P: AsRef<Path>>(mut self, file: P) -> Self {
58 let part = Part::file(file, "images.zip").mime(mime::APPLICATION_OCTET_STREAM);
59 self.fields.images_zip = Some(part);
60 self
61 }
62
63 pub fn images<P: AsRef<Path>>(mut self, images: &'a [P]) -> Self {
64 self.fields.images = images
65 .iter()
66 .enumerate()
67 .map(|(i, file)| {
68 let file = file.as_ref();
69 let filename = file
70 .file_name()
71 .and_then(OsStr::to_str)
72 .map_or_else(|| format!("image{i}.png"), ToString::to_string);
73
74 Part::file(file, &filename).mime(mime::IMAGE_STAR)
75 })
76 .collect();
77 self
78 }
79
80 pub const fn youtube(mut self, youtube: &'a [&'a str]) -> Self {
81 self.fields.youtube = Some(youtube);
82 self
83 }
84
85 pub const fn sketchfab(mut self, sketchfab: &'a [&'a str]) -> Self {
86 self.fields.sketchfab = Some(sketchfab);
87 self
88 }
89}
90
91impl IntoFuture for AddModMedia<'_> {
92 type Output = Output<Message>;
93 type IntoFuture = ResponseFuture<Message>;
94
95 fn into_future(self) -> Self::IntoFuture {
96 let route = Route::AddModMedia {
97 game_id: self.game_id,
98 mod_id: self.mod_id,
99 };
100 let mut form = Form::new();
101
102 if let Some(sync) = self.fields.sync {
103 form = form.text("sync", sync.to_string());
104 }
105 if let Some(part) = self.fields.logo {
106 form = form.part("logo", part);
107 }
108 for (i, part) in self.fields.images.into_iter().enumerate() {
109 form = form.part(format!("image{i}"), part);
110 }
111 if let Some(part) = self.fields.images_zip {
112 form = form.part("images", part);
113 }
114 if let Some(youtube) = self.fields.youtube {
115 for part in youtube {
116 form = form.text("youtube[]", (*part).to_owned());
117 }
118 }
119 if let Some(sketchfab) = self.fields.sketchfab {
120 for part in sketchfab {
121 form = form.text("sketchfab[]", (*part).to_owned());
122 }
123 }
124
125 match RequestBuilder::from_route(&route).multipart(form) {
126 Ok(req) => self.http.request(req),
127 Err(err) => ResponseFuture::failed(err),
128 }
129 }
130}