mcsm/src/commands/search.rs

103 lines
2.8 KiB
Rust

use std::error::Error;
use colored::Colorize;
use terminal_size;
use terminal_size::{Width, terminal_size as get_terminal_size};
use textwrap::{Options, fill};
use crate::models::{
config::Config,
search::{SearchQueryParams, SearchResult},
};
pub struct Search {
query: String,
offset: Option<u32>,
limit: Option<u32>,
}
impl Search {
const BASE_URL: &str = "https://api.modrinth.com/v2";
pub fn new(query: String, offset: Option<u32>, limit: Option<u32>) -> Self {
Search {
query,
offset,
limit,
}
}
pub async fn run(&self) -> Result<(), Box<dyn Error>> {
let file_res = tokio::fs::read_to_string("mcsm.toml").await;
if file_res.is_err() {
return Err("current directory is not a mcsm project".into());
}
let config: Config = toml::from_str(&file_res.unwrap())?;
if config.server.loader == "Vanilla" {
return Err("cannot search for mods on Vanilla server".into());
}
let client = reqwest::Client::new();
let search = format!("{}/search", Self::BASE_URL);
let facets = format!(
r#"[["project_type:mod"],["environment!=client_only"],["environment!=singleplayer_only"],["environment!=unknown"],["categories:{}"],["versions:{}"]]"#,
config.server.loader.to_lowercase(),
config.server.version,
);
let params = SearchQueryParams {
query: self.query.clone(),
facets: facets.into(),
offset: self.offset,
limit: self.limit,
};
let res: SearchResult = client
.get(search)
.query(&params)
.send()
.await?
.json()
.await?;
self.print_results(&res);
Ok(())
}
fn print_results(&self, res: &SearchResult) {
println!(
"{}\n",
format!(
"Found {} result{}",
res.total_hits,
if res.total_hits == 1 { "" } else { "s" }
)
.green()
.bold()
);
let width = get_terminal_size()
.map(|(Width(w), _)| w as usize)
.unwrap_or(80);
for (i, hit) in res.hits.iter().enumerate() {
let wrapped = fill(
&hit.description,
Options::new(width.saturating_sub(3))
.initial_indent(" ")
.subsequent_indent(" "),
);
println!(
"{} {} {}\n by {}\n{}\n",
format!("{}.", i + 1).bold(),
hit.title.bold(),
format!("({})", hit.slug).cyan(),
hit.author.yellow(),
wrapped,
);
}
}
}