d_id/endpoints/video/
clips.rs

1// File: clips.rs
2// Path: src/endpoints/video/clips.rs
3
4use super::*;
5
6const CLIPS_PATH: &str = "/clips";
7const PRESENTERS_PATH: &str = "/presenters";
8const DRIVERS_PATH: &str = "/drivers";
9
10#[derive(Serialize, Deserialize, Debug)]
11pub struct GetPresentersResponse {
12    presenters: Vec<Presenter>,
13}
14
15#[derive(Serialize, Deserialize, Debug)]
16pub struct Presenter {
17    presenter_id: String,
18    driver_id: String,
19    gender: String,
20    owner_id: String,
21    preview_url: String,
22    modified_at: String,
23    //video_url: String,
24}
25
26pub async fn get_presenters() -> Result<GetPresentersResponse> {
27    let c = ClientBuilder::new()?
28        .method(GET)?
29        .path(&format!("{}{}", CLIPS_PATH, PRESENTERS_PATH))?
30        .header(CONTENT_TYPE, APPLICATION_JSON)?
31        .build()?;
32
33    let resp = c.send_request(Empty::<Bytes>::new()).await?;
34
35    let presenters = serde_json::from_slice::<GetPresentersResponse>(&resp.as_ref())?;
36
37    Ok(presenters)
38}
39
40pub async fn get_presenter(id: &str) -> Result<Presenter> {
41    let c = ClientBuilder::new()?
42        .method(GET)?
43        .path(&format!("{}{}/{}", CLIPS_PATH, PRESENTERS_PATH, id))?
44        .header(CONTENT_TYPE, APPLICATION_JSON)?
45        .build()?;
46
47    let resp = c.send_request(Empty::<Bytes>::new()).await?;
48
49    let presenter = serde_json::from_slice::<Presenter>(&resp.as_ref())?;
50
51    Ok(presenter)
52}
53
54
55#[derive(Serialize, Deserialize, Debug)]
56pub struct ClipRequestBody {
57    presenter_id: String,
58    script: Script,
59    #[serde(skip_serializing_if = "String::is_empty")]
60    driver_id: String,
61    #[serde(skip_serializing_if = "Option::is_none")]
62    config: Option<Config>,
63    #[serde(skip_serializing_if = "String::is_empty")]
64    created_by: String,
65    #[serde(skip_serializing_if = "Option::is_none")]
66    presenter_config: Option<PresenterConfig>,
67    #[serde(skip_serializing_if = "Option::is_none")]
68    background: Option<Background>,
69    #[serde(skip_serializing_if = "String::is_empty")]
70    user_data: String,
71    #[serde(skip_serializing_if = "String::is_empty")]
72    name: String,
73    #[serde(skip_serializing_if = "String::is_empty")]
74    webhook: String,
75    #[serde(skip_serializing_if = "String::is_empty")]
76    result_url: String,
77    #[serde(skip_serializing_if = "String::is_empty")]
78    raw_result_url: String,
79    #[serde(skip_serializing_if = "Option::is_none")]
80    persist: Option<bool>
81}
82
83#[derive(Serialize, Deserialize, Debug)]
84pub struct PresenterConfig{
85    crop: Crop,
86}
87
88#[derive(Serialize, Deserialize, Debug)]
89pub struct Crop {
90    r#type: String,
91    rectangle: Rectangle,
92}
93
94#[derive(Serialize, Deserialize, Debug)]
95pub struct Rectangle {
96    bottom: i64,
97    left: i64,
98    right: i64,
99    top: i64,
100}
101
102#[derive(Serialize, Deserialize, Debug)]
103pub struct Background {
104    color: String,
105}
106
107impl ClipRequestBody {
108    pub async fn create(&self) -> Result<CreateClipResponse> {
109        let c = ClientBuilder::new()?
110            .method(POST)?
111            .path(CLIPS_PATH)?
112            .header(CONTENT_TYPE, APPLICATION_JSON)?
113            .header(ACCEPT, APPLICATION_JSON)?
114            .build()?;
115
116        let resp = c.send_request(Full::<Bytes>::new(serde_json::to_string(&self)?.into())).await?;
117
118        let clip_resp = serde_json::from_slice::<CreateClipResponse>(&resp.as_ref())?;
119
120        Ok(clip_resp)
121    }
122}
123
124#[derive(Serialize, Deserialize, Debug)]
125pub struct ClipRequestBodyBuilder {
126    presenter_id: Option<String>,
127    driver_id: Option<String>,
128    script: Option<Script>,
129    config: Option<Config>,
130    created_by: Option<String>,
131    presenter_config: Option<PresenterConfig>,
132    background: Option<Background>,
133    user_data: Option<String>,
134    name: Option<String>,
135    webhook: Option<String>,
136    result_url: Option<String>,
137    raw_result_url: Option<String>,
138    persist: Option<bool>,
139}
140
141
142impl ClipRequestBodyBuilder {
143    pub fn new() -> Self {
144        Self {
145            presenter_id: None,
146            driver_id: None,
147            script: None,
148            config: None,
149            created_by: None,
150            presenter_config: None,
151            background: None,
152            user_data: None,
153            name: None,
154            webhook: None,
155            result_url: None,
156            raw_result_url: None,
157            persist: None,
158        }
159    }
160
161    pub fn with_text_script(presenter_id: &str) -> Self {
162        let script = Script::Text {
163            r#type: "text".to_string(),
164            subtitles: false,
165            provider: Some(TTSProvider::MicrosoftTTS {
166                r#type: "microsoft".to_string(),
167                voice_id: "en-US-JennyNeural".to_string(),
168            }),
169            input: "".to_string(),
170            ssml: false,
171        };
172
173        Self {
174            presenter_id: Some(presenter_id.to_string()),
175            driver_id: None,
176            script: Some(script),
177            config: None,
178            created_by: None,
179            presenter_config: None,
180            background: None,
181            user_data: None,
182            name: None,
183            webhook: None,
184            result_url: None,
185            raw_result_url: None,
186            persist: None,
187        }
188    }
189
190    pub fn with_audio_script(presenter_id: &str) -> Self {
191        let script = Script::Audio {
192            r#type: "audio".to_string(),
193            subtitles: false,
194            audio_url: "".to_string(),
195            reduce_noise: false,
196        };
197
198        Self {
199            presenter_id: Some(presenter_id.to_string()),
200            script: Some(script),
201            config: None,
202            created_by: None,
203            presenter_config: None,
204            background: None,
205            user_data: None,
206            name: None,
207            webhook: None,
208            result_url: None,
209            persist: None,
210            driver_id: None,
211            raw_result_url: None,
212        }
213    }
214
215    pub fn presenter_id(mut self, presenter_id: &str) -> Self {
216        self.presenter_id = Some(presenter_id.to_string());
217        self
218    }
219
220    pub fn driver_id(mut self, driver_id: &str) -> Self {
221        self.driver_id = Some(driver_id.to_string());
222        self
223    }
224
225    pub fn script(mut self, script: Script) -> Self {
226        self.script = Some(script);
227        self
228    }
229
230    pub fn config(mut self, config: Config) -> Self {
231        self.config = Some(config);
232        self
233    }
234
235    pub fn created_by(mut self, created_by: &str) -> Self {
236        self.created_by = Some(created_by.to_string());
237        self
238    }
239
240    pub fn presenter_config(mut self, presenter_config: PresenterConfig) -> Self {
241        self.presenter_config = Some(presenter_config);
242        self
243    }
244
245    pub fn background(mut self, background: Background) -> Self {
246        self.background = Some(background);
247        self
248    }
249
250    pub fn user_data(mut self, user_data: &str) -> Self {
251        self.user_data = Some(user_data.to_string());
252        self
253    }
254
255    pub fn name(mut self, name: &str) -> Self {
256        self.name = Some(name.to_string());
257        self
258    }
259
260    pub fn webhook(mut self, webhook: &str) -> Self {
261        self.webhook = Some(webhook.to_string());
262        self
263    }
264
265    pub fn result_url(mut self, result_url: &str) -> Self {
266        self.result_url = Some(result_url.to_string());
267        self
268    }
269
270    pub fn raw_result_url(mut self, raw_result_url: &str) -> Self {
271        self.raw_result_url = Some(raw_result_url.to_string());
272        self
273    }
274
275    pub fn persist(mut self, persist: bool) -> Self {
276        self.persist = Some(persist);
277        self
278    }
279
280    pub fn audio_url(mut self, audio_url: &str) -> Result<Self> {
281        if let Some(Script::Audio { audio_url: a, .. }) = self.script.as_mut() {
282            *a = audio_url.to_string();
283        }
284        Ok(self)
285    }
286
287    pub fn input(mut self, input: &str) -> Self {
288        if let Some(Script::Text { input: i, .. }) = self.script.as_mut() {
289            *i = input.to_string();
290        }
291        self
292    }
293
294    pub fn ssml(mut self, ssml: bool) -> Result<Self> {
295        if let Some(Script::Text { ssml: s, .. }) = self.script.as_mut() {
296            *s = ssml;
297        }
298        Ok(self)
299    }
300
301    pub fn subtitles(mut self, subtitles: bool) -> Result<Self> {
302        if let Some(Script::Text { subtitles: s, .. }) = self.script.as_mut() {
303            *s = subtitles;
304        }
305        Ok(self)
306    }
307
308    pub fn provider(mut self, provider: TTSProvider) -> Result<Self> {
309        if let Some(Script::Text { provider: p, .. }) = self.script.as_mut() {
310            *p = Some(provider);
311        }
312        Ok(self)
313    }
314
315    pub fn reduce_noise(mut self, reduce_noise: bool) -> Result<Self> {
316        if let Some(Script::Audio { reduce_noise: r, .. }) = self.script.as_mut() {
317            *r = reduce_noise;
318        }
319        Ok(self)
320    }
321
322    pub fn build(self) -> Result<ClipRequestBody> {
323        let presenter_id = self.presenter_id.ok_or(RequestBodyBuildError::PresenterIdNotSet)?;
324        let script = self.script.ok_or(RequestBodyBuildError::ScriptNotSet)?;
325
326        Ok(ClipRequestBody {
327            presenter_id,
328            script,
329            driver_id: self.driver_id.unwrap_or_default(),
330            config: self.config,
331            created_by: self.created_by.unwrap_or_default(),
332            presenter_config: self.presenter_config,
333            background: self.background,
334            user_data: self.user_data.unwrap_or_default(),
335            name: self.name.unwrap_or_default(),
336            webhook: self.webhook.unwrap_or_default(),
337            result_url: self.result_url.unwrap_or_default(),
338            raw_result_url: self.raw_result_url.unwrap_or_default(),
339            persist: self.persist,
340        })
341    }
342}
343
344#[derive(Serialize, Deserialize, Debug)]
345pub struct CreateClipResponse {
346    id: String,
347    object: String,
348    created_at: String,
349    status: String,
350}
351
352pub async fn get_clips() -> Result<GetClipsResponse> {
353    let c = ClientBuilder::new()?
354        .method(GET)?
355        .path(CLIPS_PATH)?
356        .header(CONTENT_TYPE, APPLICATION_JSON)?
357        .build()?;
358
359    let resp = c.send_request(Empty::<Bytes>::new()).await?;
360
361    let clips = serde_json::from_slice::<GetClipsResponse>(&resp.as_ref())?;
362
363    Ok(clips)
364}
365
366#[derive(Serialize, Deserialize, Debug)]
367pub struct GetClipsResponse {
368    clips: Vec<Clip>,
369}
370
371#[derive(Serialize, Deserialize, Debug)]
372pub struct Clip {
373    id: String,
374    owner_id: String,
375    audio_url: String,
376    created_at: String,
377    created_by: String,
378    modified_at: String,
379    started_at: String,
380    completed_at: String,
381    status: String,
382    presenter_id: String,
383    driver_id: String,
384    config: Config,
385    name: String,
386    webhook: String,
387    result_url: String,
388    //metadata: Metadata,
389}
390
391pub async fn get_clip(id: &str) -> Result<Clip> {
392    let c = ClientBuilder::new()?
393        .method(GET)?
394        .path(&format!("{}/{}", CLIPS_PATH, id))?
395        .header(CONTENT_TYPE, APPLICATION_JSON)?
396        .build()?;
397
398    let resp = c.send_request(Empty::<Bytes>::new()).await?;
399
400    let clip = serde_json::from_slice::<Clip>(&resp.as_ref())?;
401
402    Ok(clip)
403}
404
405pub async fn delete_clip(id: &str) -> Result<()> {
406    let c = ClientBuilder::new()?
407        .method(DELETE)?
408        .path(&format!("{}/{}", CLIPS_PATH, id))?
409        .header(CONTENT_TYPE, APPLICATION_JSON)?
410        .build()?;
411
412    let _resp = c.send_request(Empty::<Bytes>::new()).await?;
413
414    Ok(())
415}
416
417pub async fn get_presenter_drivers(presenter_id: &str) -> Result<GetPresenterDriversResponse> {
418    let c = ClientBuilder::new()?
419        .method(GET)?
420        .path(&format!("{}{}/{}{}", CLIPS_PATH, PRESENTERS_PATH, presenter_id, DRIVERS_PATH))?
421        .header(CONTENT_TYPE, APPLICATION_JSON)?
422        .build()?;
423
424    let resp = c.send_request(Empty::<Bytes>::new()).await?;
425
426    let drivers = serde_json::from_slice::<GetPresenterDriversResponse>(&resp.as_ref())?;
427
428    Ok(drivers)
429}
430
431#[derive(Serialize, Deserialize, Debug)]
432pub struct GetPresenterDriversResponse {
433    clips_drivers: Vec<ClipDriver>,
434}
435
436#[derive(Serialize, Deserialize, Debug)]
437pub struct ClipDriver {
438    created_at: String,
439    driver_id: String,
440    driver_image_url: String,
441    gender: String,
442    modified_at: String,
443    name: String,
444    presenter_id: String,
445    preview_url: String,
446    thumbnail_url: String,
447    video_url: String,
448}
449