1use crate::{
4 parse_property, IntoRawCommandPart, LoopProperty, Mpv, MpvCommand, MpvDataType, MpvError,
5 Playlist, PlaylistAddOptions, Property, SeekOptions,
6};
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub enum NumberChangeOptions {
13 Absolute,
14 Increase,
15 Decrease,
16}
17
18impl IntoRawCommandPart for NumberChangeOptions {
19 fn into_raw_command_part(self) -> String {
20 match self {
21 NumberChangeOptions::Absolute => "absolute".to_string(),
22 NumberChangeOptions::Increase => "increase".to_string(),
23 NumberChangeOptions::Decrease => "decrease".to_string(),
24 }
25 }
26}
27
28#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
30pub enum Switch {
31 On,
32 Off,
33 Toggle,
34}
35
36#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
38pub enum PlaylistAddTypeOptions {
39 File,
40 Playlist,
41}
42
43#[allow(async_fn_in_trait)]
46pub trait MpvExt {
47 async fn seek(&self, seconds: f64, option: SeekOptions) -> Result<(), MpvError>;
51
52 async fn playlist_shuffle(&self) -> Result<(), MpvError>;
54
55 async fn playlist_remove_id(&self, id: usize) -> Result<(), MpvError>;
57
58 async fn playlist_play_next(&self, id: usize) -> Result<(), MpvError>;
60
61 async fn playlist_play_id(&self, id: usize) -> Result<(), MpvError>;
63
64 async fn playlist_move_id(&self, from: usize, to: usize) -> Result<(), MpvError>;
71
72 async fn playlist_clear(&self) -> Result<(), MpvError>;
74
75 async fn playlist_add(
77 &self,
78 file: &str,
79 file_type: PlaylistAddTypeOptions,
80 option: PlaylistAddOptions,
81 ) -> Result<(), MpvError>;
82
83 async fn restart(&self) -> Result<(), MpvError>;
85
86 async fn prev(&self) -> Result<(), MpvError>;
88
89 async fn observe_property(&self, id: u64, property: &str) -> Result<(), MpvError>;
92
93 async fn unobserve_property(&self, id: u64) -> Result<(), MpvError>;
96
97 async fn next(&self) -> Result<(), MpvError>;
99
100 async fn kill(&self) -> Result<(), MpvError>;
106
107 async fn stop(&self) -> Result<(), MpvError>;
110
111 async fn set_volume(
115 &self,
116 input_volume: f64,
117 option: NumberChangeOptions,
118 ) -> Result<(), MpvError>;
119
120 async fn set_speed(
122 &self,
123 input_speed: f64,
124 option: NumberChangeOptions,
125 ) -> Result<(), MpvError>;
126
127 async fn set_playback(&self, option: Switch) -> Result<(), MpvError>;
129
130 async fn set_mute(&self, option: Switch) -> Result<(), MpvError>;
132
133 async fn set_loop_playlist(&self, option: Switch) -> Result<(), MpvError>;
135
136 async fn set_loop_file(&self, option: Switch) -> Result<(), MpvError>;
138
139 async fn get_playlist(&self) -> Result<Playlist, MpvError>;
143
144 async fn get_metadata(&self) -> Result<HashMap<String, MpvDataType>, MpvError>;
146
147 async fn get_file_path(&self) -> Result<String, MpvError>;
149
150 async fn get_volume(&self) -> Result<f64, MpvError>;
152
153 async fn get_speed(&self) -> Result<f64, MpvError>;
155
156 async fn get_time_pos(&self) -> Result<Option<f64>, MpvError>;
158
159 async fn get_time_remaining(&self) -> Result<Option<f64>, MpvError>;
161
162 async fn get_duration(&self) -> Result<f64, MpvError>;
164
165 async fn get_playlist_pos(&self) -> Result<usize, MpvError>;
167
168 async fn is_muted(&self) -> Result<bool, MpvError>;
172
173 async fn is_playing(&self) -> Result<bool, MpvError>;
175
176 async fn playlist_is_looping(&self) -> Result<LoopProperty, MpvError>;
178
179 async fn file_is_looping(&self) -> Result<LoopProperty, MpvError>;
181}
182
183impl MpvExt for Mpv {
184 async fn seek(&self, seconds: f64, option: SeekOptions) -> Result<(), MpvError> {
187 self.run_command(MpvCommand::Seek { seconds, option }).await
188 }
189
190 async fn playlist_shuffle(&self) -> Result<(), MpvError> {
191 self.run_command(MpvCommand::PlaylistShuffle).await
192 }
193
194 async fn playlist_remove_id(&self, id: usize) -> Result<(), MpvError> {
195 self.run_command(MpvCommand::PlaylistRemove(id)).await
196 }
197
198 async fn playlist_play_next(&self, id: usize) -> Result<(), MpvError> {
199 let data = self.get_property("playlist-pos").await?;
200 let current_id = match parse_property("playlist-pos", data)? {
201 Property::PlaylistPos(Some(current_id)) => Ok(current_id),
202 prop => Err(MpvError::UnexpectedProperty(prop)),
203 }?;
204
205 self.run_command(MpvCommand::PlaylistMove {
206 from: id,
207 to: current_id + 1,
208 })
209 .await
210 }
211
212 async fn playlist_play_id(&self, id: usize) -> Result<(), MpvError> {
213 self.set_property("playlist-pos", id).await
214 }
215
216 async fn playlist_move_id(&self, from: usize, to: usize) -> Result<(), MpvError> {
217 self.run_command(MpvCommand::PlaylistMove { from, to })
218 .await
219 }
220
221 async fn playlist_clear(&self) -> Result<(), MpvError> {
222 self.run_command(MpvCommand::PlaylistClear).await
223 }
224
225 async fn playlist_add(
226 &self,
227 file: &str,
228 file_type: PlaylistAddTypeOptions,
229 option: PlaylistAddOptions,
230 ) -> Result<(), MpvError> {
231 match file_type {
232 PlaylistAddTypeOptions::File => {
233 self.run_command(MpvCommand::LoadFile {
234 file: file.to_string(),
235 option,
236 })
237 .await
238 }
239
240 PlaylistAddTypeOptions::Playlist => {
241 self.run_command(MpvCommand::LoadList {
242 file: file.to_string(),
243 option,
244 })
245 .await
246 }
247 }
248 }
249
250 async fn restart(&self) -> Result<(), MpvError> {
251 self.run_command(MpvCommand::Seek {
252 seconds: 0f64,
253 option: SeekOptions::Absolute,
254 })
255 .await
256 }
257
258 async fn prev(&self) -> Result<(), MpvError> {
259 self.run_command(MpvCommand::PlaylistPrev).await
260 }
261
262 async fn observe_property(&self, id: u64, property: &str) -> Result<(), MpvError> {
263 self.run_command(MpvCommand::Observe {
264 id,
265 property: property.to_string(),
266 })
267 .await
268 }
269
270 async fn unobserve_property(&self, id: u64) -> Result<(), MpvError> {
271 self.run_command(MpvCommand::Unobserve(id)).await
272 }
273
274 async fn next(&self) -> Result<(), MpvError> {
275 self.run_command(MpvCommand::PlaylistNext).await
276 }
277
278 async fn kill(&self) -> Result<(), MpvError> {
279 self.run_command(MpvCommand::Quit).await
280 }
281
282 async fn stop(&self) -> Result<(), MpvError> {
283 self.run_command(MpvCommand::Stop).await
284 }
285
286 async fn set_volume(
289 &self,
290 input_volume: f64,
291 option: NumberChangeOptions,
292 ) -> Result<(), MpvError> {
293 let volume = self.get_volume().await?;
294
295 match option {
296 NumberChangeOptions::Increase => {
297 self.set_property("volume", volume + input_volume).await
298 }
299 NumberChangeOptions::Decrease => {
300 self.set_property("volume", volume - input_volume).await
301 }
302 NumberChangeOptions::Absolute => self.set_property("volume", input_volume).await,
303 }
304 }
305
306 async fn set_speed(
307 &self,
308 input_speed: f64,
309 option: NumberChangeOptions,
310 ) -> Result<(), MpvError> {
311 let speed = self.get_speed().await?;
312
313 match option {
314 NumberChangeOptions::Increase => self.set_property("speed", speed + input_speed).await,
315 NumberChangeOptions::Decrease => self.set_property("speed", speed - input_speed).await,
316 NumberChangeOptions::Absolute => self.set_property("speed", input_speed).await,
317 }
318 }
319
320 async fn set_playback(&self, option: Switch) -> Result<(), MpvError> {
321 let enabled = match option {
322 Switch::On => "no",
323 Switch::Off => "yes",
324 Switch::Toggle => {
325 if self.is_playing().await? {
326 "yes"
327 } else {
328 "no"
329 }
330 }
331 };
332 self.set_property("pause", enabled).await
333 }
334
335 async fn set_mute(&self, option: Switch) -> Result<(), MpvError> {
336 let enabled = match option {
337 Switch::On => "yes",
338 Switch::Off => "no",
339 Switch::Toggle => {
340 if self.is_muted().await? {
341 "no"
342 } else {
343 "yes"
344 }
345 }
346 };
347 self.set_property("mute", enabled).await
348 }
349
350 async fn set_loop_playlist(&self, option: Switch) -> Result<(), MpvError> {
351 let enabled = match option {
352 Switch::On => "inf",
353 Switch::Off => "no",
354 Switch::Toggle => match self.playlist_is_looping().await? {
355 LoopProperty::Inf => "no",
356 LoopProperty::N(_) => "no",
357 LoopProperty::No => "inf",
358 },
359 };
360 self.set_property("loop-playlist", enabled).await
361 }
362
363 async fn set_loop_file(&self, option: Switch) -> Result<(), MpvError> {
364 let enabled = match option {
365 Switch::On => "inf",
366 Switch::Off => "no",
367 Switch::Toggle => match self.file_is_looping().await? {
368 LoopProperty::Inf => "no",
369 LoopProperty::N(_) => "no",
370 LoopProperty::No => "inf",
371 },
372 };
373 self.set_property("loop-file", enabled).await
374 }
375
376 async fn get_playlist(&self) -> Result<Playlist, MpvError> {
379 let data = self.get_property("playlist").await?;
380 match parse_property("playlist", data)? {
381 Property::Playlist(value) => Ok(Playlist(value)),
382 prop => Err(MpvError::UnexpectedProperty(prop)),
383 }
384 }
385
386 async fn get_metadata(&self) -> Result<HashMap<String, MpvDataType>, MpvError> {
387 let data = self.get_property("metadata").await?;
388 match parse_property("metadata", data)? {
389 Property::Metadata(Some(value)) => Ok(value),
390 prop => Err(MpvError::UnexpectedProperty(prop)),
391 }
392 }
393
394 async fn get_file_path(&self) -> Result<String, MpvError> {
395 let data = self.get_property("path").await?;
396 match parse_property("path", data)? {
397 Property::Path(Some(value)) => Ok(value),
398 prop => Err(MpvError::UnexpectedProperty(prop)),
399 }
400 }
401
402 async fn get_volume(&self) -> Result<f64, MpvError> {
403 let data = self.get_property("volume").await?;
404 match parse_property("volume", data)? {
405 Property::Volume(value) => Ok(value),
406 prop => Err(MpvError::UnexpectedProperty(prop)),
407 }
408 }
409
410 async fn get_speed(&self) -> Result<f64, MpvError> {
411 let data = self.get_property("speed").await?;
412 match parse_property("speed", data)? {
413 Property::Speed(value) => Ok(value),
414 prop => Err(MpvError::UnexpectedProperty(prop)),
415 }
416 }
417
418 async fn get_time_pos(&self) -> Result<Option<f64>, MpvError> {
419 let data = self.get_property("time-pos").await?;
420 match parse_property("time-pos", data)? {
421 Property::TimePos(value) => Ok(value),
422 prop => Err(MpvError::UnexpectedProperty(prop)),
423 }
424 }
425
426 async fn get_time_remaining(&self) -> Result<Option<f64>, MpvError> {
427 let data = self.get_property("time-remaining").await?;
428 match parse_property("time-remaining", data)? {
429 Property::TimeRemaining(value) => Ok(value),
430 prop => Err(MpvError::UnexpectedProperty(prop)),
431 }
432 }
433
434 async fn get_duration(&self) -> Result<f64, MpvError> {
435 let data = self.get_property("duration").await?;
436 match parse_property("duration", data)? {
437 Property::Duration(Some(value)) => Ok(value),
438 prop => Err(MpvError::UnexpectedProperty(prop)),
439 }
440 }
441
442 async fn get_playlist_pos(&self) -> Result<usize, MpvError> {
443 let data = self.get_property("playlist-pos").await?;
444 match parse_property("playlist-pos", data)? {
445 Property::PlaylistPos(Some(value)) => Ok(value),
446 prop => Err(MpvError::UnexpectedProperty(prop)),
447 }
448 }
449
450 async fn is_muted(&self) -> Result<bool, MpvError> {
453 let data = self.get_property("mute").await?;
454 match parse_property("mute", data)? {
455 Property::Mute(value) => Ok(value),
456 prop => Err(MpvError::UnexpectedProperty(prop)),
457 }
458 }
459
460 async fn is_playing(&self) -> Result<bool, MpvError> {
461 let data = self.get_property("pause").await?;
462 match parse_property("pause", data)? {
463 Property::Pause(value) => Ok(!value),
464 prop => Err(MpvError::UnexpectedProperty(prop)),
465 }
466 }
467
468 async fn playlist_is_looping(&self) -> Result<LoopProperty, MpvError> {
469 let data = self.get_property("loop-playlist").await?;
470 match parse_property("loop-playlist", data)? {
471 Property::LoopPlaylist(value) => Ok(value),
472 prop => Err(MpvError::UnexpectedProperty(prop)),
473 }
474 }
475
476 async fn file_is_looping(&self) -> Result<LoopProperty, MpvError> {
477 let data = self.get_property("loop-file").await?;
478 match parse_property("loop-file", data)? {
479 Property::LoopFile(value) => Ok(value),
480 prop => Err(MpvError::UnexpectedProperty(prop)),
481 }
482 }
483}