diff --git a/src/main.rs b/src/main.rs index 7b8b911..90bdde1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ mod models; mod utils; -use crate::{models::vanilla::{VanillaVersionDetail, VanillaVersionType, VanillaVersions}, utils::{with_progressbar, with_spinner}}; +use crate::{models::{vanilla::{VanillaVersionDetail, VanillaVersionType, VanillaVersions}}, utils::{with_progressbar, with_spinner}}; +use crate::models::fabric::FabricVersions; use clap::{ Parser, Subcommand, builder::styling::{self}, @@ -9,7 +10,7 @@ use clap::{ use dialoguer::{FuzzySelect, Select, theme::ColorfulTheme}; use futures_util::StreamExt; use sha1::{Digest, Sha1}; -use std::error::Error; +use std::{error::Error, fmt::format}; use tokio::io::AsyncWriteExt; fn styles() -> styling::Styles { @@ -113,7 +114,68 @@ async fn main() -> Result<(), Box> { Ok(()) }).await?; } - 1 => {} + 1 => { + const URL: &str = "https://meta.fabricmc.net/v2/versions"; + let res = with_spinner("", "", || async { + let res: FabricVersions = reqwest::get(URL).await?.json().await?; + Ok(res) + }).await?; + + let game_version_names = res.game + .iter() + .filter(|game| game.stable) + .map(|game| game.version.clone()) + .collect::>(); + + let game_version_index = FuzzySelect::with_theme(&ColorfulTheme::default()) + .with_prompt("Select Game Version") + .items(&game_version_names) + .default(0) + .interact()?; + + let loader_version_names = res.loader + .iter() + .filter(|loader| loader.stable) + .map(|loader| loader.version.clone()) + .collect::>(); + + let loader_version_index = FuzzySelect::with_theme(&ColorfulTheme::default()) + .with_prompt("Select Loader Version") + .items(&loader_version_names) + .default(0) + .interact()?; + + let game_version = game_version_names[game_version_index].clone(); + let loader_version = loader_version_names[loader_version_index].clone(); + let installer_version = res.installer + .iter() + .find_map(|installer| { + if installer.stable { Some(installer.version.clone()) } + else { None } + }).ok_or("No Installer Version Found")?; + + let start_msg = format!( + "downloading server.jar for {} {}, {}", + loaders[loader_index], loader_version_names[loader_version_index], + game_version_names[game_version_index], + ); + with_spinner(&start_msg, "download finished", || async { + let download_url = format!( + "{}/loader/{}/{}/{}/server/jar", + URL, game_version, loader_version, installer_version + ); + let res = reqwest::get(download_url).await?; + let mut file = tokio::fs::File::create("server.jar").await?; + let mut stream = res.bytes_stream(); + + while let Some(chunk) = stream.next().await { + file.write_all(&chunk?).await?; + } + + Ok(()) + }).await?; + + } _ => return Err("Invalid selection".into()), } } diff --git a/src/models/fabric.rs b/src/models/fabric.rs new file mode 100644 index 0000000..e2c6910 --- /dev/null +++ b/src/models/fabric.rs @@ -0,0 +1,26 @@ +use serde::Deserialize; + +#[derive(Deserialize)] +pub struct FabricVersions { + pub game: Vec, + pub loader: Vec, + pub installer: Vec, +} + +#[derive(Deserialize)] +pub struct FabricGameVersion { + pub version: String, + pub stable: bool, +} + +#[derive(Deserialize)] +pub struct FabricLoaderVersion { + pub version: String, + pub stable: bool, +} + +#[derive(Deserialize)] +pub struct FabricInstallerVersion { + pub version: String, + pub stable: bool, +} diff --git a/src/models/mod.rs b/src/models/mod.rs index f0e7b58..16ff910 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1 +1,2 @@ pub mod vanilla; +pub mod fabric; diff --git a/src/models/vanilla.rs b/src/models/vanilla.rs index 133a463..88dc2db 100644 --- a/src/models/vanilla.rs +++ b/src/models/vanilla.rs @@ -2,15 +2,15 @@ use serde::Deserialize; #[derive(Deserialize)] pub struct VanillaVersions { - pub latest: VanillaLatestVersion, + // pub latest: VanillaLatestVersion, pub versions: Vec, } -#[derive(Deserialize)] -pub struct VanillaLatestVersion { - pub release: String, - pub snapshot: String, -} +// #[derive(Deserialize)] +// pub struct VanillaLatestVersion { +// pub release: String, +// pub snapshot: String, +// } #[derive(Deserialize, PartialEq)] #[serde(rename_all = "snake_case")] @@ -36,7 +36,7 @@ pub struct VanillaVersionDetail { #[derive(Deserialize)] pub struct VanillaVersionDownloads { - pub client: VanillaVersionDownloadItem, + // pub client: VanillaVersionDownloadItem, pub server: VanillaVersionDownloadItem, }