use clap::Parser; use derive_more::From; use scraper::{Html, Selector}; use colored::Colorize; #[derive(Default, Parser)] #[clap(author, version, about)] struct Arguments { #[clap(help = "Plume Labs location ID. For example, https://air.plumelabs.com/air-quality-in-XXX")] location: String, #[clap(short, long, help = "Display raw Air Quality Index")] raw: bool, #[clap(short, long, help = "Display AccuWeather Air Quality Index description")] description: bool, } #[derive(From, Debug)] enum Error { ReqwestError(reqwest::Error), HttpError, InvalidResponse, } fn main() -> Result<(), Error> { let arguments = Arguments::parse(); let response = reqwest::blocking::get(format!("https://air.plumelabs.com/air-quality-in-{}", arguments.location))?; if !response.status().is_success() { return Err(Error::HttpError); } let content = response.text_with_charset("utf-8")?; let document = Html::parse_document(&content); let selector = Selector::parse("span[data-role=\"current-pi\"]").unwrap(); let aqi = match match document.select(&selector).next() { Some(element) => element, None => return Err(Error::InvalidResponse), }.inner_html().trim().parse::() { Ok(aqi) => aqi, Err(_) => return Err(Error::InvalidResponse), } as u32; if arguments.raw { println!("{}", aqi); return Ok(()); } println!("{} {}", match aqi { 250.. => "Dangerous".purple(), 150.. => "Very Unhealthy".purple(), 100.. => "Unhealthy".magenta(), 50.. => "Poor".red(), 20.. => "Fair".yellow(), 0.. => "Excellent".green(), }.bold(), match aqi { // 250.. => (no appropriate terminal color) // Dangerous 250+ 150.. => aqi.to_string().purple(), // Very Unhealthy 150-249 100.. => aqi.to_string().magenta(), // Unhealthy 100-149 50.. => aqi.to_string().red(), // Poor 50-99 20.. => aqi.to_string().yellow(), // Fair 20-49 0.. => aqi.to_string().green(), // Excellent 0-19 }.bold() ); if arguments.description { println!("{}", match aqi { 250.. => "Any exposure to the air, even for a few minutes, can lead to serious health effects on everybody. Avoid outdoor activities.", 150.. => "Health effects will be immediately felt by sensitive groups and should avoid outdoor activity. Healthy individuals are likely to experience difficulty breathing and throat irritation; consider staying indoors and rescheduling outdoor activities.", 100.. => "Health effects can be immediately felt by sensitive groups. Healthy individuals may experience difficulty breathing and throat irritation with prolonged exposure. Limit outdoor activity.", 50.. => "The air has reached a high level of pollution and is unhealthy for sensitive groups. Reduce time spent outside if you are feeling symptoms such as difficulty breathing or throat irritation.", 20.. => "The air quality is generally acceptable for most individuals. However, sensitive groups may experience minor to moderate symptoms from long-term exposure.", 0.. => "The air quality is ideal for most individuals; enjoy your normal outdoor activities.", }); } return Ok(()); }