use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum MediaType {
Audio,
Video,
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum OutputFormat {
Mp3,
Mp4,
Wav,
Aac,
M4a,
Aiff,
Caf,
Webm,
Ogg,
Flac,
}
impl OutputFormat {
pub fn extension(&self) -> &'static str {
match self {
OutputFormat::Mp3 => "mp3",
OutputFormat::Mp4 => "mp4",
OutputFormat::Wav => "wav",
OutputFormat::Aac => "aac",
OutputFormat::M4a => "m4a",
OutputFormat::Aiff => "aiff",
OutputFormat::Caf => "caf",
OutputFormat::Webm => "webm",
OutputFormat::Ogg => "ogg",
OutputFormat::Flac => "flac",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum AudioQuality {
Low,
#[default]
Medium,
High,
Lossless,
}
impl AudioQuality {
pub fn bitrate(&self) -> u32 {
match self {
AudioQuality::Low => 96_000,
AudioQuality::Medium => 192_000,
AudioQuality::High => 320_000,
AudioQuality::Lossless => 0, }
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum VideoQuality {
Low,
#[default]
Medium,
High,
Original,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TrimConfig {
pub input_path: String,
pub output_path: String,
pub start_ms: u64,
pub end_ms: u64,
pub format: Option<OutputFormat>,
pub audio_quality: Option<AudioQuality>,
pub video_quality: Option<VideoQuality>,
#[serde(default)]
pub preserve_quality: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ConvertConfig {
pub input_path: String,
pub output_path: String,
pub format: OutputFormat,
pub audio_quality: Option<AudioQuality>,
pub video_quality: Option<VideoQuality>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ExtractAudioConfig {
pub input_path: String,
pub output_path: String,
pub format: OutputFormat,
pub audio_quality: Option<AudioQuality>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MediaInfo {
pub path: String,
pub media_type: MediaType,
pub duration_ms: u64,
pub file_size: u64,
pub format: String,
pub has_audio: bool,
pub has_video: bool,
pub audio_codec: Option<String>,
pub video_codec: Option<String>,
pub sample_rate: Option<u32>,
pub channels: Option<u32>,
pub audio_bitrate: Option<u32>,
pub width: Option<u32>,
pub height: Option<u32>,
pub frame_rate: Option<f64>,
pub video_bitrate: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct OperationResult {
pub success: bool,
pub output_path: String,
pub duration_ms: u64,
pub file_size: u64,
pub warning: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum PlaybackState {
Idle,
Playing,
Paused,
Stopped,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PlaybackStatus {
pub state: PlaybackState,
pub position_ms: u64,
pub duration_ms: u64,
pub volume: f32,
pub file_path: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PlayConfig {
pub file_path: String,
pub start_ms: Option<u64>,
pub volume: Option<f32>,
#[serde(default)]
pub loop_playback: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SeekConfig {
pub position_ms: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FileSelectionResult {
pub success: bool,
pub file_path: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PermissionResponse {
pub granted: bool,
pub can_request: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CleanupResult {
pub success: bool,
pub files_deleted: u32,
pub bytes_freed: u64,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_media_type_serialization() {
assert_eq!(
serde_json::to_string(&MediaType::Audio).unwrap(),
"\"audio\""
);
assert_eq!(
serde_json::to_string(&MediaType::Video).unwrap(),
"\"video\""
);
assert_eq!(
serde_json::to_string(&MediaType::Unknown).unwrap(),
"\"unknown\""
);
}
#[test]
fn test_media_type_deserialization() {
assert_eq!(
serde_json::from_str::<MediaType>("\"audio\"").unwrap(),
MediaType::Audio
);
assert_eq!(
serde_json::from_str::<MediaType>("\"video\"").unwrap(),
MediaType::Video
);
}
#[test]
fn test_output_format_extension() {
assert_eq!(OutputFormat::Mp3.extension(), "mp3");
assert_eq!(OutputFormat::Mp4.extension(), "mp4");
assert_eq!(OutputFormat::Wav.extension(), "wav");
assert_eq!(OutputFormat::Flac.extension(), "flac");
}
#[test]
fn test_audio_quality_bitrate() {
assert_eq!(AudioQuality::Low.bitrate(), 96_000);
assert_eq!(AudioQuality::Medium.bitrate(), 192_000);
assert_eq!(AudioQuality::High.bitrate(), 320_000);
assert_eq!(AudioQuality::Lossless.bitrate(), 0);
}
#[test]
fn test_trim_config_deserialization() {
let json = r#"{
"inputPath": "/path/to/input.mp4",
"outputPath": "/path/to/output",
"startMs": 1000,
"endMs": 5000
}"#;
let config: TrimConfig = serde_json::from_str(json).unwrap();
assert_eq!(config.input_path, "/path/to/input.mp4");
assert_eq!(config.output_path, "/path/to/output");
assert_eq!(config.start_ms, 1000);
assert_eq!(config.end_ms, 5000);
assert!(config.format.is_none());
}
#[test]
fn test_playback_state_serialization() {
assert_eq!(
serde_json::to_string(&PlaybackState::Playing).unwrap(),
"\"playing\""
);
assert_eq!(
serde_json::to_string(&PlaybackState::Paused).unwrap(),
"\"paused\""
);
}
}