use { crate::week::DAYS_OF_WEEK, std::collections::HashMap, thirtyfour::prelude::{ElementQueryable, ElementWaitable}, tokio::io::AsyncWriteExt, }; pub type MarkdownMap = HashMap>; pub async fn to_markdown( driver: &thirtyfour::WebDriver, ) -> Result { let schedule = driver .query(thirtyfour::By::Id("schedule")) .first() .await .expect("failed to find schedule"); schedule .wait_until() .displayed() .await .expect("failed to wait for schedule to be displayed"); let mut markdown = html2md::parse_html( &schedule.inner_html().await.expect("failed to get schedule inner html"), ); markdown = markdown .lines() .map(|mut line| { if line.contains("") { line = line.split("").collect::>()[1]; line = line.split("").collect::>()[0]; format!("# {line}") } else { line.to_string() } }) .filter(|line| { !line.starts_with("") }) .collect::>() .join("\n"); Ok(markdown) } pub async fn print_markdown_pipe_markdown( markdown: &str, ) -> Result<(), std::io::Error> { let mut child = tokio::process::Command::new("mdcat") .env( "TERM", std::env::var("TERM").unwrap_or_else(|_| "xterm-256color".to_string()), ) .stdin(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped()) .spawn() .expect("failed to spawn mdcat"); child .stdin .as_mut() .unwrap() .write_all(markdown.as_bytes()) .await .expect("failed to write to mdcat"); let child_output = child.wait_with_output().await.unwrap(); let output = String::from_utf8_lossy(&child_output.stdout).to_string(); println!(); for line in output.lines() { println!(" {line}"); } println!(); Ok(()) } pub fn markdown_to_map(markdown: &str) -> MarkdownMap { let mut schedule = HashMap::new(); let mut current_day = String::new(); for line in markdown.lines() { if line.starts_with("# ") { current_day = line.replace("# ", "").to_string(); schedule.insert(current_day.clone(), Vec::new()); } else if !line.is_empty() { schedule.get_mut(¤t_day).unwrap().push(line.to_string()); } } schedule } #[allow(clippy::future_not_send)] pub async fn render_markdown(schedule: &MarkdownMap) { let mut args = std::env::args(); args.next(); let mut day = args.next().unwrap_or_default(); if !day.is_empty() && !DAYS_OF_WEEK.contains(&day.as_str()) { if "today".contains(&day.to_lowercase()) { day = chrono::Local::now().format("%A").to_string(); } else { let mut closest_match = String::new(); for day_of_week in DAYS_OF_WEEK { if day_of_week.to_lowercase().starts_with(&day.to_lowercase()) { closest_match = day_of_week.to_string(); break; } } if closest_match.is_empty() { day = String::new(); } else { day = closest_match; } } } let mut days = Vec::new(); for (day, media) in schedule { days.push(crate::week::Day::new(day.to_string(), media.clone())); } days.sort_by(|a, b| { DAYS_OF_WEEK .iter() .position(|&day| day == a.name()) .unwrap() .cmp(&DAYS_OF_WEEK.iter().position(|&day| day == b.name()).unwrap()) }); let today = chrono::Local::now().format("%A").to_string(); if let Some(index) = days.iter().position(|day| day.name() == today) { days.rotate_left(index); } days.reverse(); if day.is_empty() { for d in days { let mut lines = String::new(); lines.push_str(&format!("{}\n", d.name())); for line in d.media() { lines.push_str(line); lines.push('\n'); } print_markdown_pipe_markdown(&lines).await.unwrap(); } } else { let mut lines = String::new(); lines.push_str(&format!("{day}\n\n")); for line in schedule .iter() .map(|(k, v)| (k.to_lowercase(), v.clone())) .collect::() .get(&day.to_lowercase()) .unwrap() { lines.push_str(line); lines.push('\n'); } print_markdown_pipe_markdown(&lines).await.unwrap(); } }