Added a download command

This commit is contained in:
Warren Hood 2024-08-18 23:25:01 +02:00
parent 9105596c87
commit 9700206b02
4 changed files with 98 additions and 26 deletions

View file

@ -74,6 +74,11 @@ enum Commands {
/// Name of the mod to remove from the modpack /// Name of the mod to remove from the modpack
name: String, name: String,
}, },
/// Download the mods in the pack to a specified folder
Download {
/// Mods directory
mods_dir: PathBuf,
},
} }
#[tokio::main(flavor = "multi_thread")] #[tokio::main(flavor = "multi_thread")]
@ -236,6 +241,12 @@ async fn main() -> Result<(), Box<dyn Error>> {
} }
}; };
} }
Commands::Download { mods_dir } => {
let pack_lock =
resolver::PinnedPackMeta::load_from_current_directory(false).await?;
pack_lock.download_mods(&mods_dir).await?;
println!("Mods updated");
}
} }
}; };

View file

@ -6,15 +6,15 @@ pub mod modrinth;
pub mod raw; pub mod raw;
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
enum FileSource { pub enum FileSource {
Download { url: String, sha1: String, sha512: String}, Download { url: String, sha1: String, sha512: String, filename: String},
Local { path: PathBuf, sha1: String, sha512: String }, Local { path: PathBuf, sha1: String, sha512: String, filename: String },
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct PinnedMod { pub struct PinnedMod {
/// Source of the files for the mod /// Source of the files for the mod
source: Vec<FileSource>, pub source: Vec<FileSource>,
/// Version of mod /// Version of mod
pub version: String, pub version: String,
/// Pinned dependencies of a pinned mod /// Pinned dependencies of a pinned mod

View file

@ -12,27 +12,6 @@ pub struct Modrinth {
client: reqwest::Client, client: reqwest::Client,
} }
#[derive(Serialize, Deserialize)]
struct DonationUrls1 {
id: String,
platform: String,
url: String,
}
#[derive(Serialize, Deserialize)]
struct Gallery1 {
created: String,
description: String,
featured: bool,
ordering: i64,
title: String,
url: String,
}
#[derive(Serialize, Deserialize)]
struct License1 {
id: String,
name: String,
url: String,
}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct ModrinthProject { struct ModrinthProject {
slug: String, slug: String,
@ -65,7 +44,7 @@ struct VersionFiles {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
struct ModrinthProjectVersion { struct ModrinthProjectVersion {
// author_id: String, // author_id: String,
// date_published: String, date_published: String,
dependencies: Option<Vec<VersionDeps>>, dependencies: Option<Vec<VersionDeps>>,
// downloads: i64, // downloads: i64,
files: Vec<VersionFiles>, files: Vec<VersionFiles>,
@ -188,6 +167,7 @@ impl Modrinth {
url: f.url.clone(), url: f.url.clone(),
sha1: f.hashes.sha1.clone(), sha1: f.hashes.sha1.clone(),
sha512: f.hashes.sha512.clone(), sha512: f.hashes.sha512.clone(),
filename: f.filename.clone()
}) })
.collect(), .collect(),
version: package.version_number.clone(), version: package.version_number.clone(),

View file

@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize};
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
error::Error, error::Error,
ffi::OsStr,
path::PathBuf, path::PathBuf,
}; };
@ -28,6 +29,86 @@ impl PinnedPackMeta {
} }
} }
/// Clears out anything not in the mods list, and then downloads anything in the mods list not present
pub async fn download_mods(&self, mods_dir: &PathBuf) -> Result<(), Box<dyn Error>> {
let files = std::fs::read_dir(mods_dir)?;
for file in files.into_iter() {
let file = file?;
if file.file_type()?.is_file() {
println!("Checking if file {:#?} exists in pinned mods...", file.file_name());
let filename = file.file_name();
if !self.file_is_pinned(&filename) {
println!(
"Deleting file {:#?} as it is not in the pinned mods",
filename
);
tokio::fs::remove_file(file.path()).await?;
}
}
}
for (_, pinned_mod) in self.mods.iter() {
for filesource in pinned_mod.source.iter() {
match filesource {
crate::providers::FileSource::Download {
url,
sha1,
sha512,
filename,
} => {
if mods_dir.join(PathBuf::from(filename)).exists() {
println!("Found existing mod {}", filename);
continue;
}
println!("Downloading {} from {}", filename, url);
let file_contents = reqwest::get(url).await?.bytes().await?;
// TODO: Check hash
tokio::fs::write(mods_dir.join(filename), file_contents).await?;
},
crate::providers::FileSource::Local {
path,
sha1,
sha512,
filename,
} => unimplemented!(),
}
}
}
Ok(())
}
pub fn file_is_pinned(&self, file_name: &OsStr) -> bool {
for (pinned_mod_name, pinned_mod) in self.mods.iter() {
for filesource in pinned_mod.source.iter() {
match filesource {
crate::providers::FileSource::Download {
url,
sha1,
sha512,
filename,
} => {
if OsStr::new(filename) == file_name {
return true
}
},
crate::providers::FileSource::Local {
path,
sha1,
sha512,
filename,
} => {
if OsStr::new(filename) == file_name {
return true
}
},
}
}
}
return false
}
pub async fn pin_mod_and_deps( pub async fn pin_mod_and_deps(
&mut self, &mut self,
mod_metadata: &ModMeta, mod_metadata: &ModMeta,