use lastfm_edit::{ClientEvent, LastFmEditClientImpl};
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
let username =
env::var("LASTFM_EDIT_USERNAME").expect("Set LASTFM_EDIT_USERNAME environment variable");
let password =
env::var("LASTFM_EDIT_PASSWORD").expect("Set LASTFM_EDIT_PASSWORD environment variable");
let http_client = http_client::native::NativeClient::new();
println!("Logging in as {username}...");
let client =
LastFmEditClientImpl::login_with_credentials(Box::new(http_client), &username, &password)
.await?;
let mut events = client.subscribe();
let event_monitor = tokio::spawn(async move {
println!("🔍 Monitoring client events...");
while let Ok(event) = events.recv().await {
match event {
ClientEvent::RequestStarted { request } => {
println!("🚀 Starting request: {}", request.short_description());
}
ClientEvent::RequestCompleted {
request,
status_code,
duration_ms,
} => {
println!(
"✅ Completed request: {} - {} ({} ms)",
request.short_description(),
status_code,
duration_ms
);
}
ClientEvent::RateLimited {
delay_seconds,
request,
rate_limit_type,
rate_limit_timestamp,
} => {
let req_desc = request
.as_ref()
.map(|r| r.short_description())
.unwrap_or_else(|| "unknown request".to_string());
println!(
"⏳ Rate limited ({rate_limit_type:?})! {req_desc} - Waiting {delay_seconds} seconds (at timestamp {rate_limit_timestamp})"
);
}
ClientEvent::RateLimitEnded {
request,
rate_limit_type,
total_rate_limit_duration_seconds,
} => {
println!(
"🎉 Rate limiting ended ({rate_limit_type:?}) after {total_rate_limit_duration_seconds} seconds - {}",
request.short_description()
);
}
ClientEvent::Delaying {
delay_ms,
reason,
request,
delay_timestamp,
} => {
let req_desc = request
.as_ref()
.map(|r| r.short_description())
.unwrap_or_else(|| "unknown request".to_string());
println!(
"⏳ Delaying ({reason:?}): waiting {delay_ms}ms for {req_desc} (at timestamp {delay_timestamp})"
);
}
ClientEvent::EditAttempted {
edit,
success,
error_message,
duration_ms,
} => {
if success {
println!(
"✅ Edit succeeded: '{}' -> '{}' ({duration_ms} ms)",
edit.track_name_original, edit.track_name
);
} else {
let error_msg = error_message
.as_ref()
.map(|s| format!(" - {s}"))
.unwrap_or_default();
println!(
"❌ Edit failed: '{}' -> '{}' ({duration_ms} ms){error_msg}",
edit.track_name_original, edit.track_name
);
}
}
}
}
});
println!("✅ Successfully logged in as: {}", client.username());
if let Some(event) = client.latest_event() {
match event {
ClientEvent::RequestStarted { request } => {
println!(
"📊 Latest event: Started request {}",
request.short_description()
);
}
ClientEvent::RequestCompleted {
request,
status_code,
duration_ms,
} => {
println!(
"📊 Latest event: Completed request {} - {} ({} ms)",
request.short_description(),
status_code,
duration_ms
);
}
ClientEvent::RateLimited {
delay_seconds,
request,
rate_limit_type,
rate_limit_timestamp,
} => {
let req_desc = request
.as_ref()
.map(|r| r.short_description())
.unwrap_or_else(|| "unknown request".to_string());
println!(
"📊 Latest event: Rate limited ({rate_limit_type:?}) for {delay_seconds} seconds - {req_desc} (at timestamp {rate_limit_timestamp})"
);
}
ClientEvent::RateLimitEnded {
request,
rate_limit_type,
total_rate_limit_duration_seconds,
} => {
println!(
"📊 Latest event: Rate limiting ended ({rate_limit_type:?}) after {total_rate_limit_duration_seconds} seconds - {}",
request.short_description()
);
}
ClientEvent::Delaying {
delay_ms,
reason,
request,
delay_timestamp,
} => {
let req_desc = request
.as_ref()
.map(|r| r.short_description())
.unwrap_or_else(|| "unknown request".to_string());
println!(
"📊 Latest event: Delaying ({reason:?}) for {delay_ms}ms - {req_desc} (at timestamp {delay_timestamp})"
);
}
ClientEvent::EditAttempted {
edit,
success,
error_message,
duration_ms,
} => {
if success {
println!(
"📊 Latest event: Edit succeeded '{}' -> '{}' ({duration_ms} ms)",
edit.track_name_original, edit.track_name
);
} else {
let error_msg = error_message
.as_ref()
.map(|s| format!(" - {s}"))
.unwrap_or_default();
println!(
"📊 Latest event: Edit failed '{}' -> '{}' ({duration_ms} ms){error_msg}",
edit.track_name_original, edit.track_name
);
}
}
}
} else {
println!("📊 No events have occurred yet");
}
println!("🎵 Fetching recent tracks to potentially trigger rate limiting...");
for page in 1..=3 {
println!("📄 Fetching page {page}...");
match client.get_recent_scrobbles(page).await {
Ok(tracks) => {
println!("✅ Got {} tracks from page {page}", tracks.len());
}
Err(e) => {
println!("❌ Error on page {page}: {e}");
}
}
if let Some(ClientEvent::RateLimited { delay_seconds, .. }) = client.latest_event() {
println!(
"🛑 Currently rate limited for {delay_seconds} seconds according to latest event"
);
}
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
}
println!("🏁 Done! Event monitor will continue running...");
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
event_monitor.abort();
Ok(())
}