modio/request/mods/media/
add_mod_media.rs

1use 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
12/// Add images, sketchfab or youtube links to a mod profile.
13pub 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}