mangofetch-core 0.5.5

Core download engine for MangoFetch
Documentation
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;

use crate::platforms::Platform;
use tokio_util::sync::CancellationToken;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MediaInfo {
    pub title: String,
    pub author: String,
    pub platform: String,
    pub duration_seconds: Option<f64>,
    pub thumbnail_url: Option<String>,
    pub available_qualities: Vec<VideoQuality>,
    pub media_type: MediaType,
    pub file_size_bytes: Option<u64>,
}

impl MediaInfo {
    pub fn get_closest_quality(&self, wanted_quality: &str) -> Option<&VideoQuality> {
        if self.available_qualities.is_empty() {
            return None;
        }
        if wanted_quality == "best" || wanted_quality == "highest" {
            return self.available_qualities.first();
        }

        let target_height = match wanted_quality
            .to_lowercase()
            .trim_end_matches('p')
            .parse::<u32>()
        {
            Ok(h) => h,
            Err(_) => return self.available_qualities.first(),
        };

        let mut closest = &self.available_qualities[0];
        let mut min_diff = (closest.height as i32 - target_height as i32).abs() as u32;

        for q in &self.available_qualities {
            let diff = (q.height as i32 - target_height as i32).abs() as u32;
            if diff < min_diff {
                min_diff = diff;
                closest = q;
            }
        }

        Some(closest)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum MediaType {
    Video,
    Audio,
    Photo,
    Gif,
    Carousel,
    Playlist,
    Course,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VideoQuality {
    pub label: String,
    pub width: u32,
    pub height: u32,
    pub url: String,
    pub format: String,
    #[serde(default)]
    pub filesize_bytes: Option<u64>,
}

#[derive(Clone)]
pub struct DownloadOptions {
    pub quality: Option<String>,
    pub output_dir: PathBuf,
    pub filename_template: Option<String>,
    pub download_subtitles: bool,
    pub include_auto_subtitles: bool,
    pub download_mode: Option<String>,
    pub format_id: Option<String>,
    pub referer: Option<String>,
    pub extra_headers: Option<HashMap<String, String>>,
    pub page_url: Option<String>,
    pub user_agent: Option<String>,
    pub cancel_token: CancellationToken,
    pub concurrent_fragments: u32,
    pub ytdlp_path: Option<PathBuf>,
    pub torrent_listen_port: Option<u16>,
    pub torrent_id_slot: Option<std::sync::Arc<tokio::sync::Mutex<Option<usize>>>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FormatInfo {
    pub format_id: String,
    pub ext: String,
    pub resolution: Option<String>,
    pub width: Option<u32>,
    pub height: Option<u32>,
    pub fps: Option<f64>,
    pub vcodec: Option<String>,
    pub acodec: Option<String>,
    pub filesize: Option<u64>,
    pub tbr: Option<f64>,
    pub has_video: bool,
    pub has_audio: bool,
    pub format_note: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DownloadResult {
    pub file_path: PathBuf,
    pub file_size_bytes: u64,
    pub duration_seconds: f64,
    /// Torrent ID within the shared librqbit session (magnet downloads only).
    #[serde(default)]
    pub torrent_id: Option<usize>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MediaItem {
    pub url: String,
    pub media_type: MediaType,
    pub thumbnail_url: Option<String>,
    pub width: Option<u32>,
    pub height: Option<u32>,
    pub duration_seconds: Option<f64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenericDownloadResult {
    pub platform: Platform,
    pub title: String,
    pub author: String,
    pub files: Vec<DownloadedFile>,
    pub total_bytes: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DownloadedFile {
    pub path: PathBuf,
    pub media_type: MediaType,
    pub size_bytes: u64,
}