use anyhow::{Context, Result}; use log::info; use std::io::Write; use crate::{ table::{list_table, JMTableEntry, TableExt}, util, }; use libjens::{api::Meme, JMClient}; pub async fn run( client: &JMClient, query: String, user: Option, category: Option, firsturl: bool, cat: bool, ) -> Result<()> { let (memes, ..) = tokio::try_join!( async { client.get_memes().await.map_err(|e| e.into()) }, async { if let Some(u) = user.as_ref() { util::assert_user_exists(client, u).await } else { Ok(()) } }, async { if let Some(c) = category.as_ref() { util::assert_category_exists(client, c).await } else { Ok(()) } } )?; let mut matches = vec![]; info!("Starting search with query '{}'", query); let memes = memes .iter() .filter(|m| category.as_ref().map(|c| &m.category == c).unwrap_or(true)) .filter(|m| user.as_ref().map(|u| &m.user == u).unwrap_or(true)); for meme in memes { let file_name = meme.file_name()?; if let Some(score) = fuzzy_matcher::clangd::fuzzy_match(file_name, &query) { info!("Found matching meme '{}' with score {}", file_name, score); matches.push((meme, score)); } } matches.sort_by(|a, b| b.1.cmp(&a.1)); let res = match (firsturl, cat) { (false, false) => list_table() .type_header::() .add_rows(matches.into_iter().map(|(m, _)| JMTableEntry(m.clone()))) .to_string() .into_bytes(), (true, _) => matches .first() .context("No matches found")? .0 .link .clone() .into_bytes(), (_, true) => { let url = &matches.first().context("No results found")?.0.link; client.http.get(url).send().await?.bytes().await?.to_vec() }, }; let stdout = std::io::stdout(); let mut handle = stdout.lock(); handle.write_all(&res)?; Ok(()) }