Files
yarr/yarr-api/examples/download_after_search.rs
2025-10-13 20:35:49 +05:30

190 lines
6.1 KiB
Rust

//! 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<bool, ApiError> {
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<Vec<yarr_api::ReleaseResource>, 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<Option<yarr_api::ReleaseResource>, 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");
}
}