Rewrite
This commit is contained in:
parent
6f6c78d3ff
commit
56f659a182
95
Cargo.lock
generated
95
Cargo.lock
generated
@ -4,9 +4,9 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
@ -66,6 +66,12 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
@ -80,9 +86,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.71"
|
||||
version = "0.3.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
|
||||
checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
@ -169,7 +175,7 @@ version = "4.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
@ -197,6 +203,18 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "comfy-table"
|
||||
version = "7.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7"
|
||||
dependencies = [
|
||||
"crossterm 0.27.0",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
@ -229,6 +247,19 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"parking_lot",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.9.1"
|
||||
@ -364,9 +395,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.1"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
@ -393,6 +424,12 @@ version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@ -483,9 +520,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d8d52be92d09acc2e01dddb7fde3ad983fc6489c7db4837e605bc3fca4cb63e"
|
||||
checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@ -528,7 +565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fddf93031af70e75410a2511ec04d49e758ed2f26dad3404a934e0fb45cc12a"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"crossterm",
|
||||
"crossterm 0.25.0",
|
||||
"dyn-clone",
|
||||
"fuzzy-matcher",
|
||||
"fxhash",
|
||||
@ -670,9 +707,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.2"
|
||||
version = "0.35.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||
checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@ -731,13 +768,17 @@ dependencies = [
|
||||
name = "packium"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"colored",
|
||||
"comfy-table",
|
||||
"inquire",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"toml",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -911,6 +952,12 @@ version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
@ -1068,6 +1115,25 @@ version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.66"
|
||||
@ -1324,6 +1390,7 @@ dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1592,9 +1659,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d"
|
||||
checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -8,6 +8,10 @@ clap = { version = "4.5.4", features = [ "derive" ]}
|
||||
toml = "0.8.13"
|
||||
inquire = "0.7.5"
|
||||
serde = { version = "1.0.203", features = [ "derive" ]}
|
||||
serde_json = "1.0.117"
|
||||
colored = "2.1.0"
|
||||
reqwest = { version = "0.12.4", features = [ "json" ]}
|
||||
tokio = { version = "1.37.0", features = [ "full" ] }
|
||||
comfy-table = "7.1.1"
|
||||
url = { version = "2.5.0", features = [ "serde" ] }
|
||||
anyhow = "1.0.86"
|
||||
|
@ -20,10 +20,7 @@ pub enum Commands {
|
||||
Info,
|
||||
|
||||
/// Add a mod to the modpack
|
||||
Add {
|
||||
/// The name of the mod to add
|
||||
name: String,
|
||||
},
|
||||
Add,
|
||||
|
||||
/// Remove a mod from the modpack
|
||||
Remove,
|
||||
|
24
src/commands/add.rs
Normal file
24
src/commands/add.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use crate::config;
|
||||
use crate::modrinth::project::get_project_versions;
|
||||
use crate::modrinth::search::search;
|
||||
use inquire::{Select, Text};
|
||||
|
||||
pub async fn add() {
|
||||
let config = config::Config::get().unwrap();
|
||||
|
||||
let query = Text::new("Search").prompt().unwrap();
|
||||
|
||||
let response = search(&query, &config.game_version, &config.loader)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let project = Select::new("Select a mod", response.hits).prompt().unwrap();
|
||||
|
||||
let project_versions = get_project_versions(&project.project_id, &config.game_version)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let project_version = project_versions.get(0).unwrap();
|
||||
|
||||
config::Config::add(project.project_id, project_version.id.to_owned()).unwrap();
|
||||
}
|
33
src/commands/init.rs
Normal file
33
src/commands/init.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use crate::config;
|
||||
use crate::modrinth::tags;
|
||||
use inquire::Select;
|
||||
|
||||
pub async fn init(snaphots: bool) {
|
||||
let mut game_versions = tags::get_minecraft_versions().await.unwrap();
|
||||
|
||||
if snaphots {
|
||||
game_versions = game_versions
|
||||
.into_iter()
|
||||
.filter(|v| (&v.version_type == "snapshot" || &v.version_type == "release"))
|
||||
.collect()
|
||||
} else {
|
||||
game_versions = game_versions
|
||||
.into_iter()
|
||||
.filter(|v| &v.version_type == "release")
|
||||
.collect()
|
||||
}
|
||||
|
||||
let options = game_versions.iter().map(|v| &v.version).collect();
|
||||
|
||||
let game_version = Select::new("Select a Minecraft version", options)
|
||||
.prompt()
|
||||
.unwrap();
|
||||
|
||||
let options = vec!["fabric", "quilt", "forge", "neoforge"];
|
||||
|
||||
let loader = Select::new("Select a mod loader", options)
|
||||
.prompt()
|
||||
.unwrap();
|
||||
|
||||
config::Config::init(game_version.to_string(), loader.to_string()).unwrap();
|
||||
}
|
21
src/commands/list.rs
Normal file
21
src/commands/list.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use crate::{config, modrinth::project::get_multiple_projects};
|
||||
use colored::*;
|
||||
use comfy_table::{presets::NOTHING, Table};
|
||||
|
||||
pub async fn list() {
|
||||
let config = config::Config::get().unwrap();
|
||||
|
||||
let projects = get_multiple_projects(config.projects.keys().to_owned().collect())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let rows: Vec<Vec<ColoredString>> = projects
|
||||
.iter()
|
||||
.map(|p| vec![p.title.bold(), p.id.dimmed()])
|
||||
.collect();
|
||||
|
||||
let mut table = Table::new();
|
||||
table.load_preset(NOTHING).add_rows(rows);
|
||||
|
||||
println!("{table}");
|
||||
}
|
3
src/commands/mod.rs
Normal file
3
src/commands/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod add;
|
||||
pub mod init;
|
||||
pub mod list;
|
149
src/config.rs
149
src/config.rs
@ -1,139 +1,50 @@
|
||||
use crate::modrinth;
|
||||
use crate::pack;
|
||||
use inquire::Select;
|
||||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fmt::{Display, Formatter},
|
||||
fs,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
pub info: Info,
|
||||
pub mods: Vec<Mod>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Mod {
|
||||
pub id: String,
|
||||
pub version_id: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Info {
|
||||
loader: Modloader,
|
||||
minecraft_version: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||
pub enum Modloader {
|
||||
Fabric,
|
||||
Quilt,
|
||||
Forge,
|
||||
Neoforge,
|
||||
}
|
||||
|
||||
impl Modloader {
|
||||
const VARIANTS: &'static [Modloader] =
|
||||
&[Self::Fabric, Self::Quilt, Self::Forge, Self::Neoforge];
|
||||
}
|
||||
|
||||
impl Display for Modloader {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(f, "{self:?}")
|
||||
}
|
||||
pub game_version: String,
|
||||
pub loader: String,
|
||||
pub projects: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn get() -> Self {
|
||||
let pack_string = fs::read_to_string(".packium.toml").unwrap();
|
||||
pub fn get() -> Result<Self> {
|
||||
let config_raw = fs::read_to_string(".packium.toml")?;
|
||||
|
||||
toml::from_str(&pack_string).unwrap()
|
||||
let config = toml::from_str(&config_raw)?;
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub async fn mods(&self) -> Vec<modrinth::Project> {
|
||||
modrinth::get_multiple_project(self.mods.iter().map(|x| x.id.clone()).collect())
|
||||
.await
|
||||
.unwrap()
|
||||
pub fn save(&self) -> Result<()> {
|
||||
let config_toml = toml::to_string_pretty(&self)?;
|
||||
|
||||
fs::write(".packium.toml", &config_toml)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn init() {
|
||||
println!("Fetching Minecraft information...");
|
||||
|
||||
let versions = modrinth::get_minecraft_versions().await.unwrap();
|
||||
|
||||
let versions = versions
|
||||
.iter()
|
||||
.filter(|x| x.version_type == "release".to_string())
|
||||
.map(|x| &x.version)
|
||||
.collect();
|
||||
|
||||
let modloader = Select::new("Modloader?", Modloader::VARIANTS.to_vec())
|
||||
.prompt()
|
||||
.unwrap();
|
||||
|
||||
let version = Select::new("Minecraft version?", versions)
|
||||
.prompt()
|
||||
.unwrap();
|
||||
|
||||
let pack = Config {
|
||||
info: Info {
|
||||
minecraft_version: version.to_owned(),
|
||||
loader: modloader,
|
||||
},
|
||||
mods: vec![],
|
||||
pub fn init(game_version: String, loader: String) -> Result<Self> {
|
||||
let config = Self {
|
||||
game_version,
|
||||
loader,
|
||||
projects: HashMap::new(),
|
||||
};
|
||||
|
||||
let pack_toml = toml::to_string_pretty(&pack).unwrap();
|
||||
config.save()?;
|
||||
|
||||
std::fs::write(".packium.toml", pack_toml).unwrap();
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub async fn add(name: &String) {
|
||||
let mut config = Self::get();
|
||||
pub fn add(project_id: String, version_id: String) -> Result<Self> {
|
||||
let mut config = Self::get()?;
|
||||
|
||||
let mods = modrinth::search_projects(
|
||||
name.to_owned(),
|
||||
&config.info.minecraft_version,
|
||||
&config.info.loader.to_string().to_lowercase(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
config.projects.insert(project_id, version_id);
|
||||
config.save()?;
|
||||
|
||||
let project = Select::new("Choose a mod", mods).prompt().unwrap();
|
||||
|
||||
let versions = modrinth::get_project_versions(
|
||||
&project.project_id,
|
||||
&config.info.minecraft_version,
|
||||
&config.info.loader.to_string().to_lowercase(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let version = versions.get(0).unwrap();
|
||||
|
||||
config.mods.push(Mod {
|
||||
id: project.project_id.clone(),
|
||||
version_id: version.id.clone(),
|
||||
});
|
||||
|
||||
let config_toml = toml::to_string_pretty(&config).unwrap();
|
||||
|
||||
std::fs::write(".packium.toml", config_toml).unwrap();
|
||||
}
|
||||
|
||||
pub async fn remove() {
|
||||
let mut config = Self::get();
|
||||
let mods = config.mods().await;
|
||||
|
||||
let project = Select::new("Choose a mod to remove", mods)
|
||||
.prompt()
|
||||
.unwrap();
|
||||
|
||||
config.mods.retain(|x| x.id != project.id);
|
||||
|
||||
let config_toml = toml::to_string_pretty(&config).unwrap();
|
||||
|
||||
std::fs::write(".packium.toml", config_toml).unwrap();
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
13
src/main.rs
13
src/main.rs
@ -1,7 +1,7 @@
|
||||
mod cli;
|
||||
mod commands;
|
||||
mod config;
|
||||
mod modrinth;
|
||||
mod pack;
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
@ -11,13 +11,16 @@ async fn main() {
|
||||
|
||||
match &args.command {
|
||||
cli::Commands::Init => {
|
||||
config::Config::init().await;
|
||||
commands::init::init(false).await;
|
||||
}
|
||||
cli::Commands::Add { name } => {
|
||||
config::Config::add(name).await;
|
||||
cli::Commands::Add => {
|
||||
commands::add::add().await;
|
||||
}
|
||||
cli::Commands::Remove => {
|
||||
config::Config::remove().await;
|
||||
// config::Config::remove().await;
|
||||
}
|
||||
cli::Commands::List => {
|
||||
commands::list::list().await;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
|
101
src/modrinth.rs
101
src/modrinth.rs
@ -1,101 +0,0 @@
|
||||
use crate::config;
|
||||
use core::fmt;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct MinecraftVersion {
|
||||
pub version: String,
|
||||
pub version_type: String,
|
||||
pub date: String,
|
||||
pub major: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct SearchProject {
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub project_id: String,
|
||||
pub game_versions: Vec<String>,
|
||||
pub versions: Vec<String>,
|
||||
}
|
||||
|
||||
impl fmt::Display for SearchProject {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.title)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Project {
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub id: String,
|
||||
pub game_versions: Vec<String>,
|
||||
pub versions: Vec<String>,
|
||||
}
|
||||
|
||||
impl fmt::Display for Project {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.title)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Search {
|
||||
hits: Vec<SearchProject>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ProjectVersion {
|
||||
pub name: String,
|
||||
pub game_versions: Vec<String>,
|
||||
pub version_type: String,
|
||||
pub id: String,
|
||||
pub project_id: String,
|
||||
}
|
||||
|
||||
pub async fn get_minecraft_versions() -> Result<Vec<MinecraftVersion>, reqwest::Error> {
|
||||
reqwest::get("https://api.modrinth.com/v2/tag/game_version")
|
||||
.await?
|
||||
.json::<Vec<MinecraftVersion>>()
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn search_projects(
|
||||
query: String,
|
||||
version: &String,
|
||||
loader: &String,
|
||||
) -> Result<Vec<SearchProject>, reqwest::Error> {
|
||||
let url = format!("https://api.modrinth.com/v2/search?query={query}&facets=[[\"project_type:mod\"],[\"versions:{version}\"],[\"categories:{loader}\"]]");
|
||||
|
||||
let response = reqwest::get(url).await?.json::<Search>().await?;
|
||||
|
||||
Ok(response.hits)
|
||||
}
|
||||
|
||||
pub async fn get_project_versions(
|
||||
id: &String,
|
||||
version: &String,
|
||||
loader: &String,
|
||||
) -> Result<Vec<ProjectVersion>, reqwest::Error> {
|
||||
let url = format!("https://api.modrinth.com/v2/project/{id}/version?loaders=[\"{loader}\"]&game_versions=[\"{version}\"]");
|
||||
|
||||
let response = reqwest::get(url)
|
||||
.await?
|
||||
.json::<Vec<ProjectVersion>>()
|
||||
.await?;
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn get_multiple_project(
|
||||
project_ids: Vec<String>,
|
||||
) -> Result<Vec<Project>, reqwest::Error> {
|
||||
let ids = project_ids.join("\", \"");
|
||||
|
||||
let url = format!("https://api.modrinth.com/v2/projects?ids=[\"{ids}\"]");
|
||||
|
||||
let response = reqwest::get(url).await?.json::<Vec<Project>>().await?;
|
||||
|
||||
Ok(response)
|
||||
}
|
6
src/modrinth/mod.rs
Normal file
6
src/modrinth/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
pub mod project;
|
||||
pub mod search;
|
||||
pub mod tags;
|
||||
pub mod versions;
|
||||
|
||||
pub const API_BASE_URL: &str = "https://api.modrinth.com/v2";
|
51
src/modrinth/project.rs
Normal file
51
src/modrinth/project.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use super::versions::ProjectVersion;
|
||||
use super::API_BASE_URL;
|
||||
use anyhow::{bail, Result};
|
||||
use serde::Deserialize;
|
||||
|
||||
type ProjectVersionResponse = Vec<ProjectVersion>;
|
||||
|
||||
pub async fn get_project_versions(
|
||||
project_id: &str,
|
||||
game_version: &str,
|
||||
) -> Result<ProjectVersionResponse> {
|
||||
let url = format!(
|
||||
"{API_BASE_URL}/project/{}/version?game_versions=[\"{}\"]",
|
||||
project_id, game_version
|
||||
);
|
||||
|
||||
let response = reqwest::get(url)
|
||||
.await?
|
||||
.json::<ProjectVersionResponse>()
|
||||
.await;
|
||||
|
||||
match response {
|
||||
Ok(r) => Ok(r),
|
||||
Err(err) => bail!("Error with Modrinth API: {}", err.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
type ProjectResponse = Vec<Project>;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Project {
|
||||
slug: String,
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub downloads: i64,
|
||||
pub id: String,
|
||||
pub followers: i64,
|
||||
}
|
||||
|
||||
pub async fn get_multiple_projects(version_ids: Vec<&String>) -> Result<ProjectResponse> {
|
||||
let version_ids_json = serde_json::to_string(&version_ids)?;
|
||||
|
||||
let url = format!("{API_BASE_URL}/projects?ids={}", version_ids_json);
|
||||
|
||||
let response = reqwest::get(url).await?.json::<ProjectResponse>().await;
|
||||
|
||||
match response {
|
||||
Ok(r) => Ok(r),
|
||||
Err(err) => bail!("Error with Modrinth API: {}", err.to_string()),
|
||||
}
|
||||
}
|
70
src/modrinth/search.rs
Normal file
70
src/modrinth/search.rs
Normal file
@ -0,0 +1,70 @@
|
||||
use super::API_BASE_URL;
|
||||
use anyhow::{bail, Result};
|
||||
use serde::Deserialize;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Response {
|
||||
pub hits: Vec<SearchHit>,
|
||||
offset: i64,
|
||||
limit: i64,
|
||||
total_hits: i64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct SearchHit {
|
||||
pub slug: String,
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub client_side: String,
|
||||
pub server_side: String,
|
||||
pub project_type: String,
|
||||
pub downloads: i64,
|
||||
pub project_id: String,
|
||||
pub author: String,
|
||||
pub versions: Vec<String>,
|
||||
pub follows: i64,
|
||||
}
|
||||
|
||||
impl fmt::Display for SearchHit {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.title)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn search(query: &str, game_version: &str, loader: &str) -> Result<Response> {
|
||||
let game_version_facet = format!("versions:{game_version}");
|
||||
let loader_facet = format!("categories:{loader}");
|
||||
|
||||
let facets: Vec<Vec<&str>> = vec![
|
||||
vec!["project_type:mod"],
|
||||
vec![&game_version_facet],
|
||||
vec![&loader_facet],
|
||||
];
|
||||
|
||||
let facets_json = serde_json::to_string(&facets)?;
|
||||
|
||||
let url = format!(
|
||||
"{API_BASE_URL}/search?query={}&facets={}",
|
||||
query, facets_json
|
||||
);
|
||||
|
||||
let response = reqwest::get(url).await?.json::<Response>().await;
|
||||
|
||||
match response {
|
||||
Ok(r) => Ok(r),
|
||||
Err(err) => bail!("Error with Modrinth API: {}", err.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_search() {
|
||||
let response = search("Fabric API", "1.20.4", "fabric").await;
|
||||
|
||||
assert!(response.is_ok())
|
||||
}
|
||||
}
|
36
src/modrinth/tags.rs
Normal file
36
src/modrinth/tags.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use super::API_BASE_URL;
|
||||
use anyhow::{bail, Result};
|
||||
use serde::Deserialize;
|
||||
|
||||
type Response = Vec<MinecraftVersion>;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct MinecraftVersion {
|
||||
pub version: String,
|
||||
pub version_type: String,
|
||||
date: String,
|
||||
major: bool,
|
||||
}
|
||||
|
||||
pub async fn get_minecraft_versions() -> Result<Response> {
|
||||
let url = format!("{API_BASE_URL}/tag/game_version");
|
||||
|
||||
let response = reqwest::get(url).await?.json::<Response>().await;
|
||||
|
||||
match response {
|
||||
Ok(r) => Ok(r),
|
||||
Err(err) => bail!("Error with Modrinth API: {}", err.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_game_versions() {
|
||||
let response = get_minecraft_versions().await;
|
||||
|
||||
assert!(response.is_ok())
|
||||
}
|
||||
}
|
31
src/modrinth/versions.rs
Normal file
31
src/modrinth/versions.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use super::API_BASE_URL;
|
||||
use anyhow::{bail, Result};
|
||||
use serde::Deserialize;
|
||||
|
||||
type Response = Vec<ProjectVersion>;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ProjectVersion {
|
||||
pub name: String,
|
||||
pub version_number: String,
|
||||
game_versions: Vec<String>,
|
||||
version_type: String,
|
||||
loaders: Vec<String>,
|
||||
featured: bool,
|
||||
pub id: String,
|
||||
project_id: String,
|
||||
downloads: i64,
|
||||
}
|
||||
|
||||
pub async fn get_multiple_versions(version_ids: Vec<&String>) -> Result<Response> {
|
||||
let version_ids_json = serde_json::to_string(&version_ids)?;
|
||||
|
||||
let url = format!("{API_BASE_URL}/versions?ids={}", version_ids_json);
|
||||
|
||||
let response = reqwest::get(url).await?.json::<Response>().await;
|
||||
|
||||
match response {
|
||||
Ok(r) => Ok(r),
|
||||
Err(err) => bail!("Error with Modrinth API: {}", err.to_string()),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user