vidsage-core 0.1.0

Core functionality for VidSage video processing and AI commentary generation
Documentation
//! Video metadata definitions

use chrono::{DateTime, Duration, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;

/// Video format enumeration
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum VideoFormat {
    #[serde(rename = "mp4")]
    MP4,
    #[serde(rename = "webm")]
    WebM,
    #[serde(rename = "avi")]
    AVI,
    #[serde(rename = "mov")]
    MOV,
    #[serde(rename = "mkv")]
    MKV,
    #[serde(rename = "flv")]
    FLV,
    #[serde(rename = "other")]
    Other,
}

/// Video quality settings
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
pub enum VideoQuality {
    #[serde(rename = "low")]
    Low,
    #[serde(rename = "medium")]
    Medium,
    #[serde(rename = "high")]
    High,
    #[serde(rename = "ultra")]
    Ultra,
    #[serde(rename = "custom")]
    Custom(u32), // Bitrate in kbps
}

/// Video metadata structure
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VideoMetadata {
    /// Unique identifier for the video
    pub id: String,

    /// Video title
    pub title: String,

    /// Video duration
    pub duration: Duration,

    /// Video resolution (width, height)
    pub resolution: (u32, u32),

    /// Video format
    pub format: VideoFormat,

    /// Video file size in bytes
    pub file_size: u64,

    /// Video bitrate in kbps
    pub bitrate: u32,

    /// Video frame rate
    pub frame_rate: f64,

    /// Number of audio tracks
    pub audio_tracks: u32,

    /// Audio bitrate in kbps
    pub audio_bitrate: u32,

    /// Video codec
    pub video_codec: String,

    /// Audio codec
    pub audio_codec: String,

    /// Creation timestamp
    pub created_at: DateTime<Utc>,

    /// Last updated timestamp
    pub updated_at: DateTime<Utc>,
}

impl VideoMetadata {
    /// Create a new VideoMetadata instance
    pub fn new(
        title: String,
        duration: Duration,
        resolution: (u32, u32),
        format: VideoFormat,
    ) -> Self {
        let now = Utc::now();
        Self {
            id: Uuid::new_v4().to_string(),
            title,
            duration,
            resolution,
            format,
            file_size: 0,
            bitrate: 0,
            frame_rate: 0.0,
            audio_tracks: 0,
            audio_bitrate: 0,
            video_codec: String::new(),
            audio_codec: String::new(),
            created_at: now,
            updated_at: now,
        }
    }

    /// Update the updated_at timestamp
    pub fn update_timestamp(&mut self) {
        self.updated_at = Utc::now();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json;

    #[test]
    fn test_video_format_serialization() {
        // Test serialization
        let format = VideoFormat::MP4;
        let json = serde_json::to_string(&format).unwrap();
        assert_eq!(json, "\"mp4\"");

        // Test deserialization
        let deserialized: VideoFormat = serde_json::from_str(&json).unwrap();
        assert_eq!(deserialized, VideoFormat::MP4);

        // Test deserialization from string
        let deserialized: VideoFormat = serde_json::from_str("\"webm\"").unwrap();
        assert_eq!(deserialized, VideoFormat::WebM);
    }

    #[test]
    fn test_video_quality_serialization() {
        // Test serialization for predefined qualities
        let quality = VideoQuality::High;
        let json = serde_json::to_string(&quality).unwrap();
        assert_eq!(json, "\"high\"");

        // Test serialization for custom quality
        let quality = VideoQuality::Custom(5000);
        let json = serde_json::to_string(&quality).unwrap();
        assert_eq!(json, "{\"custom\":5000}");

        // Test deserialization
        let deserialized: VideoQuality = serde_json::from_str("\"medium\"").unwrap();
        assert_eq!(deserialized, VideoQuality::Medium);

        let deserialized: VideoQuality = serde_json::from_str("{\"custom\":3000}").unwrap();
        assert_eq!(deserialized, VideoQuality::Custom(3000));
    }

    #[test]
    fn test_video_metadata_creation() {
        let duration = Duration::seconds(3600);
        let resolution = (1920, 1080);
        let format = VideoFormat::MP4;

        let metadata = VideoMetadata::new("Test Video".to_string(), duration, resolution, format);

        assert_eq!(metadata.title, "Test Video");
        assert_eq!(metadata.duration, duration);
        assert_eq!(metadata.resolution, resolution);
        assert_eq!(metadata.format, format);
        assert_eq!(metadata.file_size, 0);
        assert_eq!(metadata.bitrate, 0);
        assert_eq!(metadata.created_at, metadata.updated_at);
    }

    #[test]
    fn test_video_metadata_update_timestamp() {
        let duration = Duration::seconds(3600);
        let resolution = (1920, 1080);
        let format = VideoFormat::MP4;

        let mut metadata =
            VideoMetadata::new("Test Video".to_string(), duration, resolution, format);
        let old_updated_at = metadata.updated_at;

        // Wait a bit to ensure time difference
        std::thread::sleep(std::time::Duration::from_millis(10));

        metadata.update_timestamp();

        assert!(metadata.updated_at > old_updated_at);
    }

    #[test]
    fn test_video_metadata_serialization() {
        let duration = Duration::seconds(3600);
        let resolution = (1920, 1080);
        let format = VideoFormat::MP4;

        let metadata = VideoMetadata::new("Test Video".to_string(), duration, resolution, format);

        let json = serde_json::to_string(&metadata).unwrap();
        let deserialized: VideoMetadata = serde_json::from_str(&json).unwrap();

        assert_eq!(deserialized.title, metadata.title);
        assert_eq!(deserialized.duration, metadata.duration);
        assert_eq!(deserialized.resolution, metadata.resolution);
        assert_eq!(deserialized.format, metadata.format);
        assert_eq!(deserialized.id, metadata.id);
    }
}