mod fetch; mod spotify_types; // Symlinked from server because I do not want to separate this into another // crate right now. // This is a stupid way to do this. use wasm_bindgen::prelude::*; use wasm_bindgen_futures::spawn_local; use web_sys::{Document, HtmlAnchorElement, HtmlImageElement}; use crate::spotify_types::*; // Convenience alias type TrackUserTuple = (TrackObject, UserProfile); fn main() { wasm_logger::init(wasm_logger::Config::default()); log::info!("wasm executing now :)"); spawn_local(app()); } async fn app() { let window = web_sys::window().expect("We have to have a window."); let document = window.document().expect("Window should have a document."); let body = document.body().expect("Document should have a body."); let outer_div = generate_outer_div(&document).unwrap(); body.append_child(&outer_div).unwrap(); let data = fetch::fetch().await; if data.is_err() { log::error!("Could not fetch data, nothing to do."); log::error!("{:?}", data.unwrap_err()); return (); // This is actually a graceful exit! } let data = data.unwrap(); // We know this is fine from above let rows = data.iter() .map(|row| generate_row(&document, &row)) .flatten(); // Intentionally not collecting--next step is to consume. for row in rows { outer_div.append_child(&row).unwrap(); } } fn generate_outer_div(document: &Document) -> Result { let outer_div = document.create_element("div")?; outer_div.set_class_name("outer-div"); Ok(outer_div) } fn generate_row(document: &Document, data: &TrackUserTuple) -> Result { let container = document.create_element("div")?; container.set_class_name("inner-div"); let track_info = generate_track_info(document, data)?; let user_info = generate_user_info(document, data)?; container.append_child(&track_info).unwrap(); container.append_child(&user_info).unwrap(); Ok(container) } fn generate_track_info(document: &Document, data: &TrackUserTuple) -> Result { let track_info = document.create_element("div")?; track_info.set_class_name("track-info"); // Scoping these to prevent accidentally referencing the wrong thing // and to free memory sooner maybe { let track_name = document.create_element("p")?; track_name.set_class_name("track_name"); let track_name_a: HtmlAnchorElement = document.create_element("a")?.dyn_into().unwrap(); track_name_a.set_text_content(Some(&data.0.name)); track_name_a.set_href(&create_track_link(&data.0.uri)); track_name.append_child(&track_name_a).unwrap(); track_info.append_child(&track_name).unwrap(); } if let Some(album) = &data.0.album { { let track_album = document.create_element("p")?; track_album.set_class_name("track_album"); let track_album_a: HtmlAnchorElement = document.create_element("a")?.dyn_into().unwrap(); track_album_a.set_text_content(Some(&album.name)); track_album_a.set_href(&create_album_link(&album.uri)); track_album.append_child(&track_album_a).unwrap(); track_info.append_child(&track_album).unwrap(); } if let Some(image) = &album.images.get(0) { let track_album_img: HtmlImageElement = document.create_element("img")?.dyn_into().unwrap(); track_album_img.set_alt("Album cover"); track_album_img.set_src(&image.url); track_info.append_child(&track_album_img).unwrap(); } } Ok(track_info) } fn generate_user_info(document: &Document, data: &TrackUserTuple) -> Result { let user_info = document.create_element("div")?; user_info.set_class_name("user-info"); { let user_name = document.create_element("p")?; user_name.set_class_name("user_name"); let user_name_a: HtmlAnchorElement = document.create_element("a")?.dyn_into().unwrap(); if let Some(display_name) = &data.1.display_name { user_name_a.set_text_content(Some(&display_name)); } else { user_name_a.set_text_content(Some(&data.1.id)); } user_name_a.set_href(&create_user_link(&data.1.id)); user_name.append_child(&user_name_a).unwrap(); user_info.append_child(&user_name).unwrap(); } if let Some(Some(image)) = data.1.images.as_ref().map(|imgs| imgs.get(0)) { let user_img: HtmlImageElement = document.create_element("img")?.dyn_into().unwrap(); user_img.set_alt("Profile picture"); user_img.set_src(&image.url); user_info.append_child(&user_img).unwrap(); } Ok(user_info) } fn create_track_link(uri: &Uri) -> String { "https://open.spotify.com/track/".to_owned() + &uri.get_suffix() } fn create_album_link(uri: &Uri) -> String { "https://open.spotify.com/album/".to_owned() + &uri.get_suffix() } fn create_user_link(id: &str) -> String { "https://open.spotify.com/user/".to_owned() + id }