1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
5#[serde(rename_all = "lowercase")]
6pub enum MediaType {
7 Audio,
8 Video,
9 Unknown,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14#[serde(rename_all = "lowercase")]
15pub enum OutputFormat {
16 Mp3,
17 Mp4,
18 Wav,
19 Aac,
20 M4a,
21 Aiff,
22 Caf,
23 Webm,
24 Ogg,
25 Flac,
26}
27
28impl OutputFormat {
29 pub fn extension(&self) -> &'static str {
30 match self {
31 OutputFormat::Mp3 => "mp3",
32 OutputFormat::Mp4 => "mp4",
33 OutputFormat::Wav => "wav",
34 OutputFormat::Aac => "aac",
35 OutputFormat::M4a => "m4a",
36 OutputFormat::Aiff => "aiff",
37 OutputFormat::Caf => "caf",
38 OutputFormat::Webm => "webm",
39 OutputFormat::Ogg => "ogg",
40 OutputFormat::Flac => "flac",
41 }
42 }
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, Default)]
47#[serde(rename_all = "lowercase")]
48pub enum AudioQuality {
49 Low,
50 #[default]
51 Medium,
52 High,
53 Lossless,
54}
55
56impl AudioQuality {
57 pub fn bitrate(&self) -> u32 {
58 match self {
59 AudioQuality::Low => 96_000,
60 AudioQuality::Medium => 192_000,
61 AudioQuality::High => 320_000,
62 AudioQuality::Lossless => 0, }
64 }
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize, Default)]
69#[serde(rename_all = "lowercase")]
70pub enum VideoQuality {
71 Low,
72 #[default]
73 Medium,
74 High,
75 Original,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
80#[serde(rename_all = "camelCase")]
81pub struct TrimConfig {
82 pub input_path: String,
84 pub output_path: String,
86 pub start_ms: u64,
88 pub end_ms: u64,
90 pub format: Option<OutputFormat>,
92 pub audio_quality: Option<AudioQuality>,
94 pub video_quality: Option<VideoQuality>,
96 #[serde(default)]
98 pub preserve_quality: bool,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103#[serde(rename_all = "camelCase")]
104pub struct ConvertConfig {
105 pub input_path: String,
107 pub output_path: String,
109 pub format: OutputFormat,
111 pub audio_quality: Option<AudioQuality>,
113 pub video_quality: Option<VideoQuality>,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
119#[serde(rename_all = "camelCase")]
120pub struct ExtractAudioConfig {
121 pub input_path: String,
123 pub output_path: String,
125 pub format: OutputFormat,
127 pub audio_quality: Option<AudioQuality>,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
133#[serde(rename_all = "camelCase")]
134pub struct MediaInfo {
135 pub path: String,
137 pub media_type: MediaType,
139 pub duration_ms: u64,
141 pub file_size: u64,
143 pub format: String,
145 pub has_audio: bool,
147 pub has_video: bool,
149 pub audio_codec: Option<String>,
151 pub video_codec: Option<String>,
153 pub sample_rate: Option<u32>,
155 pub channels: Option<u32>,
157 pub audio_bitrate: Option<u32>,
159 pub width: Option<u32>,
161 pub height: Option<u32>,
163 pub frame_rate: Option<f64>,
165 pub video_bitrate: Option<u32>,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171#[serde(rename_all = "camelCase")]
172pub struct OperationResult {
173 pub success: bool,
175 pub output_path: String,
177 pub duration_ms: u64,
179 pub file_size: u64,
181 pub warning: Option<String>,
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
187#[serde(rename_all = "lowercase")]
188pub enum PlaybackState {
189 Idle,
190 Playing,
191 Paused,
192 Stopped,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
197#[serde(rename_all = "camelCase")]
198pub struct PlaybackStatus {
199 pub state: PlaybackState,
201 pub position_ms: u64,
203 pub duration_ms: u64,
205 pub volume: f32,
207 pub file_path: Option<String>,
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize)]
213#[serde(rename_all = "camelCase")]
214pub struct PlayConfig {
215 pub file_path: String,
217 pub start_ms: Option<u64>,
219 pub volume: Option<f32>,
221 #[serde(default)]
223 pub loop_playback: bool,
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize)]
228#[serde(rename_all = "camelCase")]
229pub struct SeekConfig {
230 pub position_ms: u64,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
236#[serde(rename_all = "camelCase")]
237pub struct FileSelectionResult {
238 pub success: bool,
240 pub file_path: String,
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize)]
246#[serde(rename_all = "camelCase")]
247pub struct PermissionResponse {
248 pub granted: bool,
250 pub can_request: bool,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
256#[serde(rename_all = "camelCase")]
257pub struct CleanupResult {
258 pub success: bool,
260 pub files_deleted: u32,
262 pub bytes_freed: u64,
264}
265
266#[cfg(test)]
267mod tests {
268 use super::*;
269
270 #[test]
271 fn test_media_type_serialization() {
272 assert_eq!(
273 serde_json::to_string(&MediaType::Audio).unwrap(),
274 "\"audio\""
275 );
276 assert_eq!(
277 serde_json::to_string(&MediaType::Video).unwrap(),
278 "\"video\""
279 );
280 assert_eq!(
281 serde_json::to_string(&MediaType::Unknown).unwrap(),
282 "\"unknown\""
283 );
284 }
285
286 #[test]
287 fn test_media_type_deserialization() {
288 assert_eq!(
289 serde_json::from_str::<MediaType>("\"audio\"").unwrap(),
290 MediaType::Audio
291 );
292 assert_eq!(
293 serde_json::from_str::<MediaType>("\"video\"").unwrap(),
294 MediaType::Video
295 );
296 }
297
298 #[test]
299 fn test_output_format_extension() {
300 assert_eq!(OutputFormat::Mp3.extension(), "mp3");
301 assert_eq!(OutputFormat::Mp4.extension(), "mp4");
302 assert_eq!(OutputFormat::Wav.extension(), "wav");
303 assert_eq!(OutputFormat::Flac.extension(), "flac");
304 }
305
306 #[test]
307 fn test_audio_quality_bitrate() {
308 assert_eq!(AudioQuality::Low.bitrate(), 96_000);
309 assert_eq!(AudioQuality::Medium.bitrate(), 192_000);
310 assert_eq!(AudioQuality::High.bitrate(), 320_000);
311 assert_eq!(AudioQuality::Lossless.bitrate(), 0);
312 }
313
314 #[test]
315 fn test_trim_config_deserialization() {
316 let json = r#"{
317 "inputPath": "/path/to/input.mp4",
318 "outputPath": "/path/to/output",
319 "startMs": 1000,
320 "endMs": 5000
321 }"#;
322
323 let config: TrimConfig = serde_json::from_str(json).unwrap();
324 assert_eq!(config.input_path, "/path/to/input.mp4");
325 assert_eq!(config.output_path, "/path/to/output");
326 assert_eq!(config.start_ms, 1000);
327 assert_eq!(config.end_ms, 5000);
328 assert!(config.format.is_none());
329 }
330
331 #[test]
332 fn test_playback_state_serialization() {
333 assert_eq!(
334 serde_json::to_string(&PlaybackState::Playing).unwrap(),
335 "\"playing\""
336 );
337 assert_eq!(
338 serde_json::to_string(&PlaybackState::Paused).unwrap(),
339 "\"paused\""
340 );
341 }
342}