Compare commits
No commits in common. "24cd3d2765fd072e15e82fe559468fd045ec6dad" and "10920719681f585d6a67fc2235c57e4a9c02fd3c" have entirely different histories.
24cd3d2765
...
1092071968
8 changed files with 32 additions and 241 deletions
64
Cargo.lock
generated
64
Cargo.lock
generated
|
|
@ -204,15 +204,6 @@ version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "colored"
|
|
||||||
version = "3.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys 0.61.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
version = "4.6.8"
|
version = "4.6.8"
|
||||||
|
|
@ -885,15 +876,12 @@ name = "mcsm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"colored",
|
|
||||||
"dialoguer",
|
"dialoguer",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"sha1",
|
"sha1",
|
||||||
"terminal_size",
|
|
||||||
"textwrap",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
@ -1140,7 +1128,6 @@ dependencies = [
|
||||||
"rustls-platform-verifier",
|
"rustls-platform-verifier",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
|
||||||
"sync_wrapper",
|
"sync_wrapper",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
|
|
@ -1278,12 +1265,6 @@ version = "1.0.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
|
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ryu"
|
|
||||||
version = "1.0.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
|
@ -1389,18 +1370,6 @@ dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_urlencoded"
|
|
||||||
version = "0.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
|
||||||
dependencies = [
|
|
||||||
"form_urlencoded",
|
|
||||||
"itoa",
|
|
||||||
"ryu",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
|
@ -1462,12 +1431,6 @@ version = "1.15.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
|
checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smawk"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e8e2fb0f499abb4d162f2bedad68f5ef91a1682b5a03596ddb67efd37768d100"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
|
|
@ -1572,27 +1535,6 @@ dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "terminal_size"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874"
|
|
||||||
dependencies = [
|
|
||||||
"rustix",
|
|
||||||
"windows-sys 0.61.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "textwrap"
|
|
||||||
version = "0.16.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
|
|
||||||
dependencies = [
|
|
||||||
"smawk",
|
|
||||||
"unicode-linebreak",
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "2.0.20"
|
version = "2.0.20"
|
||||||
|
|
@ -1820,12 +1762,6 @@ version = "1.0.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-linebreak"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,11 @@ edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.6.6", features = ["derive"] }
|
clap = { version = "4.6.6", features = ["derive"] }
|
||||||
colored = "3.1.1"
|
|
||||||
dialoguer = { version = "0.12.0", features = ["fuzzy-select"] }
|
dialoguer = { version = "0.12.0", features = ["fuzzy-select"] }
|
||||||
futures-util = "0.3.34"
|
futures-util = "0.3.34"
|
||||||
indicatif = "0.18.6"
|
indicatif = "0.18.6"
|
||||||
reqwest = { version = "0.13.4", features = ["json", "stream", "query"] }
|
reqwest = { version = "0.13.4", features = ["json", "stream"] }
|
||||||
serde = { version = "1.0.229", features = ["derive"] }
|
serde = { version = "1.0.229", features = ["derive"] }
|
||||||
sha1 = "0.11.0"
|
sha1 = "0.11.0"
|
||||||
terminal_size = "0.4.4"
|
|
||||||
textwrap = "0.16.2"
|
|
||||||
tokio = { version = "1.53.1", features = ["full"] }
|
tokio = { version = "1.53.1", features = ["full"] }
|
||||||
toml = "1.1.4"
|
toml = "1.1.4"
|
||||||
|
|
|
||||||
|
|
@ -101,22 +101,21 @@ impl LoaderDownloader for VanillaDownloader {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(version) = create.version.clone() {
|
if let Some(version) = create.version.clone() {
|
||||||
let version_exists = res.versions.iter().any(|v| v.id == version);
|
let version_exists = res
|
||||||
if !version_exists {
|
.versions
|
||||||
return Err("Invalid minecraft version specified".into());
|
.iter()
|
||||||
|
.any(|v| v.id == version);
|
||||||
|
if !version_exists { return Err("Invalid minecraft version specified".into()) }
|
||||||
}
|
}
|
||||||
} else {
|
else {
|
||||||
let versions = res
|
let versions = res
|
||||||
.versions
|
.versions
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|version| {
|
.filter(|version| {
|
||||||
version.version_type == VanillaVersionType::Release
|
version.version_type == VanillaVersionType::Release ||
|
||||||
|| (create.show_snapshots
|
(create.show_snapshots && version.version_type == VanillaVersionType::Snapshot) ||
|
||||||
&& version.version_type == VanillaVersionType::Snapshot)
|
(create.show_betas && version.version_type == VanillaVersionType::OldBeta) ||
|
||||||
|| (create.show_betas
|
(create.show_alphas && version.version_type == VanillaVersionType::OldAlpha)
|
||||||
&& version.version_type == VanillaVersionType::OldBeta)
|
|
||||||
|| (create.show_alphas
|
|
||||||
&& version.version_type == VanillaVersionType::OldAlpha)
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let version_names = versions
|
let version_names = versions
|
||||||
|
|
@ -141,7 +140,10 @@ impl LoaderDownloader for VanillaDownloader {
|
||||||
|
|
||||||
let version_detail: VanillaVersionDetail = with_spinner("", "", || async {
|
let version_detail: VanillaVersionDetail = with_spinner("", "", || async {
|
||||||
let version_detail: VanillaVersionDetail =
|
let version_detail: VanillaVersionDetail =
|
||||||
reqwest::get(version.url.clone()).await?.json().await?;
|
reqwest::get(version.url.clone())
|
||||||
|
.await?
|
||||||
|
.json()
|
||||||
|
.await?;
|
||||||
Ok(version_detail)
|
Ok(version_detail)
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
@ -213,11 +215,13 @@ impl LoaderDownloader for FabricDownloader {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(version) = create.version.clone() {
|
if let Some(version) = create.version.clone() {
|
||||||
let exists = res.game.iter().any(|game| game.version == version);
|
let exists = res
|
||||||
if !exists {
|
.game
|
||||||
return Err("Invalid minecraft version specified".into());
|
.iter()
|
||||||
|
.any(|game| game.version == version);
|
||||||
|
if !exists { return Err("Invalid minecraft version specified".into()) }
|
||||||
}
|
}
|
||||||
} else {
|
else {
|
||||||
let game_version_names = res
|
let game_version_names = res
|
||||||
.game
|
.game
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -239,10 +243,9 @@ impl LoaderDownloader for FabricDownloader {
|
||||||
.loader
|
.loader
|
||||||
.iter()
|
.iter()
|
||||||
.any(|loader| loader.version == loader_version);
|
.any(|loader| loader.version == loader_version);
|
||||||
if !exists {
|
if !exists { return Err(format!("Invalid {} loader version specified", Self::name()).into()) }
|
||||||
return Err(format!("Invalid {} loader version specified", Self::name()).into());
|
|
||||||
}
|
}
|
||||||
} else {
|
else {
|
||||||
let loader_version_names = res
|
let loader_version_names = res
|
||||||
.loader
|
.loader
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -280,10 +283,7 @@ impl LoaderDownloader for FabricDownloader {
|
||||||
with_spinner(&start_msg, "download finished", || async {
|
with_spinner(&start_msg, "download finished", || async {
|
||||||
let download_url = format!(
|
let download_url = format!(
|
||||||
"{}/loader/{}/{}/{}/server/jar",
|
"{}/loader/{}/{}/{}/server/jar",
|
||||||
URL,
|
URL, create.version.as_ref().unwrap(), create.loader_version.as_ref().unwrap(), installer_version
|
||||||
create.version.as_ref().unwrap(),
|
|
||||||
create.loader_version.as_ref().unwrap(),
|
|
||||||
installer_version
|
|
||||||
);
|
);
|
||||||
let res = reqwest::get(download_url).await?;
|
let res = reqwest::get(download_url).await?;
|
||||||
let mut file = tokio::fs::File::create("server.jar").await?;
|
let mut file = tokio::fs::File::create("server.jar").await?;
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
pub mod create;
|
pub mod create;
|
||||||
pub mod search;
|
|
||||||
|
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
use colored::Colorize;
|
|
||||||
use serde::Serialize;
|
|
||||||
use terminal_size;
|
|
||||||
use textwrap::{Options, fill};
|
|
||||||
use terminal_size::{terminal_size as get_terminal_size, Width};
|
|
||||||
|
|
||||||
use crate::models::{config::Config, search::SearchResult};
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct SearchQueryParams {
|
|
||||||
query: String,
|
|
||||||
facets: String,
|
|
||||||
offset: Option<u32>,
|
|
||||||
limit: Option<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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(¶ms)
|
|
||||||
.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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
30
src/main.rs
30
src/main.rs
|
|
@ -2,7 +2,7 @@ mod commands;
|
||||||
mod models;
|
mod models;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use crate::commands::{create::Create, search::Search};
|
use crate::commands::create::Create;
|
||||||
use clap::{
|
use clap::{
|
||||||
Parser, Subcommand,
|
Parser, Subcommand,
|
||||||
builder::styling::{self},
|
builder::styling::{self},
|
||||||
|
|
@ -53,21 +53,6 @@ enum Commands {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
show_alphas: bool,
|
show_alphas: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Search for mods on modrinth for project in current directory
|
|
||||||
/// automticallly filters mod loader, minecraft version from config file
|
|
||||||
Search {
|
|
||||||
/// Search term to look up, e.g. project name or keyword.
|
|
||||||
query: String,
|
|
||||||
|
|
||||||
/// Number of results to skip before returning matches.
|
|
||||||
#[arg(long)]
|
|
||||||
offset: Option<u32>,
|
|
||||||
|
|
||||||
/// Maximum number of results to return. [default: 10]
|
|
||||||
#[arg(long, value_parser = clap::value_parser!(u32).range(1..=100))]
|
|
||||||
limit: Option<u32>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
|
@ -92,19 +77,12 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
loader_version,
|
loader_version,
|
||||||
show_snapshots,
|
show_snapshots,
|
||||||
show_betas,
|
show_betas,
|
||||||
show_alphas,
|
show_alphas
|
||||||
)
|
).await?;
|
||||||
.await?;
|
if loader_is_unset { create.init_loader().await? }
|
||||||
if loader_is_unset {
|
|
||||||
create.init_loader().await?
|
|
||||||
}
|
|
||||||
let config = create.download_server().await?;
|
let config = create.download_server().await?;
|
||||||
create.save_config(config).await?;
|
create.save_config(config).await?;
|
||||||
}
|
}
|
||||||
Commands::Search { query, offset, limit } => {
|
|
||||||
let search = Search::new(query, offset, limit);
|
|
||||||
search.run().await?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod fabric;
|
pub mod fabric;
|
||||||
pub mod search;
|
|
||||||
pub mod vanilla;
|
pub mod vanilla;
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct SearchResult {
|
|
||||||
pub hits: Vec<SearchHit>,
|
|
||||||
pub total_hits: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct SearchHit {
|
|
||||||
pub slug: String,
|
|
||||||
pub author: String,
|
|
||||||
pub title: String,
|
|
||||||
pub description: String,
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue