1use std::fmt::Display;23mod json;45const NOW_PLAYING_URL: &str = "https://api.composer.nprstations.org/v1/widget/53877c98e1c80a130decb6c8/now?format=json&style=v2&show_song=true";67struct Track {8 name: String,9 composer: String,10}1112impl Display for Track {13 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {14 write!(f, "{}: {}", self.composer, self.name)15 }16}1718#[derive(Default)]19struct Current {20 // The current program or show. This may be unset during transitions.21 program: Option<String>,22 // The current song. This is expected to be unset for some programs (e.g. BSO livestreams) and23 // also during transitions.24 track: Option<Track>,25}2627impl Current {28 fn fetch(url: &str) -> Result<Current, anyhow::Error> {29 let body: json::Root = ureq::get(url).call()?.into_json()?;3031 Ok(Current {32 program: body.on_now.program.map(|p| p.name),33 track: body.on_now.song.map(|s| Track {34 name: s.track_name,35 composer: s.composer_name,36 }),37 })38 }39}4041impl Display for Current {42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {43 match (&self.track, &self.program) {44 (Some(track), _) => write!(f, "{track}"),45 (None, Some(program)) => write!(f, "{program}"),46 (None, None) => write!(f, "UNKNOWN"),47 }48 }49}5051fn main() {52 match Current::fetch(NOW_PLAYING_URL) {53 Ok(c) => println!("{c}"),54 Err(err) => {55 eprintln!("failed to fetch: {err}");56 std::process::exit(1)57 }58 }59}