//! Example demonstrating download after search functionality //! //! This example shows how to: //! 1. Search for available releases for a specific series/episode //! 2. Download the best quality release automatically //! 3. Handle different search scenarios use std::env; use yarr_api::{ApiError, SonarrClient}; #[tokio::main] async fn main() -> Result<(), ApiError> { // Initialize the client with environment variables let base_url = env::var("SONARR_URL").unwrap_or_else(|_| "http://localhost:8989".to_string()); let api_key = env::var("SONARR_API_KEY").expect("SONARR_API_KEY environment variable is required"); let client = SonarrClient::new(base_url, api_key); println!("šŸ” Sonarr Download After Search Example"); println!("========================================"); // Example 1: Search and download best release for a specific series println!("\nšŸ“ŗ Example 1: Search and download for series ID 1"); match search_and_download_for_series(&client, 1).await { Ok(success) => { if success { println!("āœ… Successfully found and downloaded a release!"); } else { println!("āŒ No suitable releases found for download"); } } Err(e) => println!("āŒ Error: {}", e), } // Example 2: Search releases for a specific episode println!("\nšŸŽ¬ Example 2: Search releases for episode ID 123"); match search_releases_for_episode(&client, 123).await { Ok(releases) => { println!("šŸ“‹ Found {} releases:", releases.len()); for (i, release) in releases.iter().enumerate().take(5) { println!( " {}. {} ({})", i + 1, release.title.as_deref().unwrap_or("Unknown"), format_size(release.size.unwrap_or(0)) ); } } Err(e) => println!("āŒ Error: {}", e), } // Example 3: Search and download best quality for a season println!("\nšŸ“€ Example 3: Search and download best for season 1 of series 1"); match search_and_download_best_for_season(&client, 1, 1).await { Ok(release_opt) => match release_opt { Some(release) => { println!( "āœ… Downloaded: {}", release.title.as_deref().unwrap_or("Unknown") ); println!(" Quality: {}", release.quality_weight.unwrap_or(0)); println!(" Size: {}", format_size(release.size.unwrap_or(0))); } None => println!("āŒ No suitable releases found"), }, Err(e) => println!("āŒ Error: {}", e), } // Example 4: Manual search and selective download println!("\nšŸŽÆ Example 4: Manual search and filter"); match manual_search_and_filter(&client, 1).await { Ok(()) => println!("āœ… Manual search completed"), Err(e) => println!("āŒ Error: {}", e), } Ok(()) } /// Search and download the first available release for a series async fn search_and_download_for_series( client: &SonarrClient, series_id: u32, ) -> Result { client .search_and_download(Some(series_id), None, None) .await } /// Search for releases for a specific episode (without downloading) async fn search_releases_for_episode( client: &SonarrClient, episode_id: u32, ) -> Result, ApiError> { client.search_releases(None, Some(episode_id), None).await } /// Search and download the best quality release for a season async fn search_and_download_best_for_season( client: &SonarrClient, series_id: u32, season_number: i32, ) -> Result, ApiError> { client .search_and_download_best(Some(series_id), None, Some(season_number)) .await } /// Manual search with custom filtering logic async fn manual_search_and_filter(client: &SonarrClient, series_id: u32) -> Result<(), ApiError> { let releases = client.search_releases(Some(series_id), None, None).await?; println!("šŸ” Found {} total releases", releases.len()); // Custom filtering: prefer releases with specific criteria let filtered_releases: Vec<_> = releases .into_iter() .filter(|r| { // Only downloadable releases if !r.download_allowed.unwrap_or(false) || r.rejected.unwrap_or(true) { return false; } // Prefer releases with higher seeds (for torrents) if let Some(seeders) = r.seeders { if seeders < 5 { return false; } } // Avoid very large files (over 10GB) if let Some(size) = r.size { if size > 10 * 1024 * 1024 * 1024 { return false; } } true }) .collect(); println!("šŸ“‹ {} releases match our criteria", filtered_releases.len()); if let Some(best_release) = filtered_releases.first() { println!( "šŸŽÆ Downloading: {}", best_release.title.as_deref().unwrap_or("Unknown") ); client.download_release(best_release).await?; println!("āœ… Download initiated successfully!"); } else { println!("āŒ No releases match our filtering criteria"); } Ok(()) } /// Format file size in human-readable format fn format_size(bytes: i64) -> String { const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"]; if bytes == 0 { return "0 B".to_string(); } let mut size = bytes as f64; let mut unit_index = 0; while size >= 1024.0 && unit_index < UNITS.len() - 1 { size /= 1024.0; unit_index += 1; } format!("{:.1} {}", size, UNITS[unit_index]) } #[cfg(test)] mod tests { use super::*; #[test] fn test_format_size() { assert_eq!(format_size(0), "0 B"); assert_eq!(format_size(1024), "1.0 KB"); assert_eq!(format_size(1536), "1.5 KB"); assert_eq!(format_size(1048576), "1.0 MB"); assert_eq!(format_size(1073741824), "1.0 GB"); } }