Files
pmomusic/pmoparadise/examples/extract_track.rs
2025-10-12 21:34:59 +02:00

111 lines
4.0 KiB
Rust

//! Example: Extract individual tracks from a FLAC block (requires `per-track` feature)
//!
//! This example demonstrates:
//! - Per-track extraction from FLAC blocks
//! - Exporting tracks to WAV files
//! - Alternative player-based seeking (recommended)
//!
//! **Warning**: This approach downloads and decodes entire blocks.
//! For most use cases, player-based seeking is more efficient.
//!
//! Run with: cargo run --example extract_track --features per-track
#[cfg(feature = "per-track")]
use pmoparadise::{RadioParadiseClient, Result};
#[cfg(feature = "per-track")]
use std::path::Path;
#[cfg(feature = "per-track")]
#[tokio::main]
async fn main() -> Result<()> {
// Initialize logging
#[cfg(feature = "logging")]
tracing_subscriber::fmt::init();
println!("Radio Paradise - Per-Track Extraction Demo");
println!("===========================================\n");
println!("WARNING: This feature downloads entire blocks (50-100MB)");
println!(" and performs CPU-intensive FLAC decoding.");
println!(" For most use cases, player-based seeking is better.\n");
// Create client
let client = RadioParadiseClient::new().await?;
// Get current block
let block = client.get_block(None).await?;
println!("Block Information:");
println!(" Event: {}", block.event);
println!(" Songs: {}", block.song_count());
println!(" URL: {}\n", block.url);
// Display all tracks
println!("Available Tracks:");
for (index, song) in block.songs_ordered() {
println!(" {}. {} - {} ({:.1}s)",
index,
song.artist,
song.title,
song.duration as f64 / 1000.0);
}
println!();
// Extract first track
let track_index = 0;
if let Some((_, song)) = block.songs_ordered().first() {
println!("Extracting Track {}:", track_index);
println!(" Artist: {}", song.artist);
println!(" Title: {}", song.title);
println!(" Album: {}\n", song.album);
println!("Downloading and decoding... (this may take a while)");
// Open track stream
let mut track_stream = client.open_track_stream(&block, track_index).await?;
println!("Track Metadata:");
println!(" Sample Rate: {} Hz", track_stream.metadata.sample_rate);
println!(" Channels: {}", track_stream.metadata.channels);
println!(" Bits Per Sample: {}", track_stream.metadata.bits_per_sample);
println!(" Total Samples: {}", track_stream.metadata.total_samples);
println!();
// Export to WAV
let output_path = Path::new("track.wav");
println!("Exporting to {:?}...", output_path);
track_stream.export_wav(output_path)?;
println!("✓ Export complete!\n");
}
// Show alternative: player-based seeking
println!("RECOMMENDED ALTERNATIVE: Player-Based Seeking");
println!("=============================================\n");
for (index, song) in block.songs_ordered().into_iter().take(3) {
let (start, duration) = client.track_position_seconds(&block, index)?;
println!("Track {}: {} - {}", index, song.artist, song.title);
println!(" mpv command:");
println!(" mpv --start={:.3} --length={:.3} '{}'", start, duration, block.url);
println!(" ffmpeg command (extract to file):");
println!(" ffmpeg -ss {:.3} -t {:.3} -i '{}' -c copy track_{}.flac",
start, duration, block.url, index);
println!();
}
println!("These methods are much more efficient as they:");
println!(" - Don't download the entire block");
println!(" - Use the player's optimized seeking");
println!(" - Start playback immediately");
println!(" - Preserve original quality (with -c copy)");
Ok(())
}
#[cfg(not(feature = "per-track"))]
fn main() {
eprintln!("ERROR: This example requires the 'per-track' feature.");
eprintln!("Run with: cargo run --example extract_track --features per-track");
std::process::exit(1);
}