190 lines
6.1 KiB
Rust
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");
|
|
}
|
|
}
|