Skip to content

Commit 8315c1c

Browse files
committed
Finished CurseForge implementation for Add screen
1 parent 2ae14dc commit 8315c1c

File tree

5 files changed

+392
-17
lines changed

5 files changed

+392
-17
lines changed

core/src/cli.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use clap::{Parser, Subcommand};
2-
use std::{fmt::Display, path::PathBuf};
3-
use strum::EnumIter;
2+
use itertools::Itertools;
3+
use std::{fmt::Display, path::PathBuf, sync::LazyLock};
4+
use strum::{EnumIter, IntoEnumIterator};
45

56
use crate::ModLoader;
6-
7+
pub static SOURCES: LazyLock<Vec<Source>> = LazyLock::new(|| Source::iter().collect_vec());
78
/// Modder is a tool for managing mods for Minecraft.
89
/// It can add mods from Modrinth and Github.
910
/// Other features include bulk-updating a directory of mods to a specified version

core/src/curseforge_wrapper/mod.rs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use reqwest::{
1414
use serde_json::json;
1515
use std::{fs, path::PathBuf, sync::LazyLock};
1616
pub use structs::*;
17+
use tracing::debug;
1718
use url::Url;
1819

1920
type Result<T> = color_eyre::Result<T, CurseForgeError>;
@@ -68,19 +69,25 @@ impl CurseForgeAPI {
6869
game_version: &str,
6970
loader: ModLoader,
7071
search: &str,
72+
page_size: u32,
7173
) -> Result<Vec<Mod>> {
7274
let params = [
7375
("gameId", GAME_ID.to_string()),
74-
("gameVersion", game_version.to_string()),
76+
("index", 0.to_string()),
7577
("searchFilter", search.to_string()),
76-
("modLoaderType", loader.as_num().to_string()),
78+
("gameVersion", game_version.to_string()),
79+
("pageSize", page_size.to_string()),
80+
("sortField", 6.to_string()),
81+
("gameFlavors[0]", loader.as_num().to_string()),
82+
("sortOrder", "desc".to_string()),
7783
];
7884
let params_str = params
7985
.iter()
8086
.map(|(k, v)| format!("{}={}", k, v))
8187
.collect::<Vec<String>>()
8288
.join("&");
8389
let url = format!("{}/mods/search?{params_str}", BASE_URL);
90+
debug!(url = ?url);
8491
let headers = HEADERS.clone();
8592
let response = self
8693
.client
@@ -90,7 +97,9 @@ impl CurseForgeAPI {
9097
.await?;
9198
let response = response.error_for_status()?;
9299
let body = response.text().await?;
100+
debug!(body = ?body);
93101
let root: Root = serde_json::from_str(&body)?;
102+
debug!(root_data = ?root.data);
94103
Ok(root.data)
95104
}
96105
pub async fn get_mods<T>(&self, mod_ids: T) -> Result<Vec<Mod>>
@@ -120,6 +129,35 @@ impl CurseForgeAPI {
120129
let root: Root = serde_json::from_str(&body)?;
121130
Ok(root.data)
122131
}
132+
pub async fn get_mod_files(
133+
&self,
134+
mod_id: u32,
135+
game_version: &str,
136+
mod_loader: ModLoader,
137+
) -> Result<Vec<File>> {
138+
let params = [
139+
("index", 0.to_string()),
140+
("gameVersion", game_version.to_string()),
141+
("pageSize", 1.to_string()),
142+
("modLoaderType", mod_loader.as_num().to_string()),
143+
];
144+
let params_str = params
145+
.iter()
146+
.map(|(k, v)| format!("{}={}", k, v))
147+
.collect::<Vec<String>>()
148+
.join("&");
149+
let url = format!("{BASE_URL}/mods/{mod_id}/files?{params_str}");
150+
let response = self
151+
.client
152+
.request(Method::GET, Url::parse(&url)?)
153+
.headers(HEADERS.clone())
154+
.send()
155+
.await?;
156+
let response = response.error_for_status()?;
157+
let body = response.text().await?;
158+
let root = serde_json::from_str::<FileSearchRoot>(&body)?;
159+
Ok(root.data)
160+
}
123161
pub async fn download_mod(&self, mod_id: u32, file_id: u32, dir: PathBuf) -> Result<()> {
124162
let url = format!(
125163
"{}/mods/{}/files/{}/download-url",
@@ -138,7 +176,6 @@ impl CurseForgeAPI {
138176
let file_data = reqwest::get(url).await?;
139177
let file_name = file_data.url().path_segments().unwrap().last().unwrap();
140178
let file_name = percent_decode(file_name.as_bytes()).decode_utf8_lossy();
141-
println!("{}", file_name);
142179
let path = dir.join(file_name.to_string());
143180
fs::create_dir_all(path.parent().unwrap())?;
144181
fs::write(&path, file_data.bytes().await?)?;
@@ -218,7 +255,6 @@ mod tests {
218255
let api = CurseForgeAPI::new(API_KEY.to_string());
219256
let loader = ModLoader::Fabric;
220257
let mods = api.search_mods("1.21.4", loader, "Carpet").await.unwrap();
221-
println!("{:#?}", mods);
222258
assert_eq!(!mods.is_empty(), true);
223259
}
224260
#[tokio::test]

core/src/curseforge_wrapper/structs.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ pub struct Root {
3232
pub pagination: Option<Pagination>,
3333
}
3434

35+
#[derive(Debug, Deserialize)]
36+
#[serde(rename_all = "camelCase")]
37+
pub struct FileSearchRoot {
38+
pub data: Vec<File>,
39+
pub pagination: Option<Pagination>,
40+
}
41+
3542
#[derive(Debug, Deserialize, Clone)]
3643
#[serde(rename_all = "camelCase")]
3744
pub struct Mod {
@@ -251,7 +258,6 @@ pub trait CurseForgeMod {
251258

252259
impl CurseForgeMod for Mod {
253260
fn get_version_and_loader(&self, game_version: &str) -> Option<FileIndex> {
254-
println!("{:#?}", game_version);
255261
self.latest_files_indexes
256262
.iter()
257263
.find(|file_index| file_index.game_version == game_version)

tui/README.md

Lines changed: 163 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,165 @@
1-
# tui
1+
# Modder TUI
22

3-
[![CI](https://github.com//tui/workflows/CI/badge.svg)](https://github.com//tui/actions)
3+
A Terminal User Interface for Modder-rs, a command-line Minecraft mod manager.
44

5-
TUI Wrapper for Modder-rs
5+
## Features
6+
7+
* List installed mods
8+
* Enable and disable mods
9+
* Add new mods from Modrinth or GitHub
10+
* Search for mods
11+
* View mod details
12+
13+
## Installation
14+
15+
1. Clone the repository:
16+
```bash
17+
git clone https://github.com/JayanAXHF/modder-rs.git
18+
```
19+
2. Navigate to the `tui` directory:
20+
```bash
21+
cd modder-rs/tui
22+
```
23+
3. Build the project:
24+
```bash
25+
cargo build --release
26+
```
27+
4. Run the application:
28+
```bash
29+
./target/release/tui --dir /path/to/your/mods
30+
```
31+
32+
## Usage
33+
34+
The application is divided into several modes, each with its own set of keybindings and functionality.
35+
36+
### Home
37+
38+
The default mode, which displays a menu of available actions.
39+
40+
### List
41+
42+
Displays a list of all installed mods in the specified directory. You can view details for each mod.
43+
44+
### Toggle
45+
46+
Allows you to enable or disable mods by renaming the mod files (e.g., `mod.jar` to `mod.jar.disabled`).
47+
48+
### Add
49+
50+
Search for and download new mods from Modrinth or GitHub.
51+
52+
## Keybindings
53+
54+
### Global
55+
56+
* `Ctrl-c`, `Ctrl-d`, `q`: Quit the application
57+
* `Ctrl-z`: Suspend the application
58+
59+
### Home
60+
61+
* `j` or `Down Arrow`: Select next item
62+
* `k` or `Up Arrow`: Select previous item
63+
* `g` or `Home`: Select first item
64+
* `G` or `End`: Select last item
65+
* `Enter`: Select the highlighted mode and switch to it
66+
67+
### List
68+
69+
* `h` or `Left Arrow`: Deselect item
70+
* `j` or `Down Arrow`: Select next item
71+
* `k` or `Up Arrow`: Select previous item
72+
* `g` or `Home`: Select first item
73+
* `G` or `End`: Select last item
74+
* `/`: Enter Search mode
75+
* `Esc`: Go back to Home
76+
77+
#### Search Mode
78+
79+
* `Tab` or `Esc`: Exit Search mode
80+
* Any other key: Updates the search query
81+
82+
### Toggle
83+
84+
* `h` or `Left Arrow`: Deselect item
85+
* `j` or `Down Arrow`: Select next item
86+
* `k` or `Up Arrow`: Select previous item
87+
* `g` or `Home`: Select first item
88+
* `G` or `End`: Select last item
89+
* `Space`: Toggle whether a mod is enabled or disabled
90+
* `Enter`: Apply the changes (rename files)
91+
* `/`: Enter Search mode
92+
* `Esc`: Go back to Home
93+
94+
#### Search Mode
95+
96+
* `Tab` or `Esc`: Exit Search mode
97+
* Any other key: Updates the search query
98+
99+
### Add
100+
101+
* `h` or `Left Arrow`: Deselect item in the current mods list
102+
* `j` or `Down Arrow`: Select next item in the current mods list
103+
* `k` or `Up Arrow`: Select previous item in the current mods list
104+
* `g` or `Home`: Select first item in the current mods list
105+
* `G` or `End`: Select last item in the current mods list
106+
* `S`: Change source (Modrinth/Github)
107+
* `R`: View search results
108+
* `V`: Enter version
109+
* `/`: Enter search mode
110+
* `l`: View search results
111+
* `J` or `s`: View selected mods
112+
* `L`: Change loader
113+
* `Esc`: Go back to Home
114+
115+
#### Search Mode
116+
117+
* `Tab` or `Esc`: Exit search mode
118+
* `Enter`: Perform search
119+
* Any other key: Updates the search query
120+
121+
#### Toggle Source Mode
122+
123+
* `h` or `Left Arrow`: Deselect source
124+
* `j` or `Down Arrow`: Select next source
125+
* `k` or `Up Arrow`: Select previous source
126+
* `g` or `Home`: Select first source
127+
* `G` or `End`: Select last source
128+
* `Enter`: Perform search if version, search query and loader are set
129+
* `Esc`: Go back to Normal mode
130+
131+
#### Change Loader Mode
132+
133+
* `Tab` or `Esc`: Go back to Normal mode
134+
* `Enter`: Perform search if version and search query are set, otherwise go to search mode
135+
* `h` or `Left Arrow`: Deselect loader
136+
* `j` or `Down Arrow`: Select next loader
137+
* `k` or `Up Arrow`: Select previous loader
138+
* `g` or `Home`: Select first loader
139+
* `G` or `End`: Select last loader
140+
141+
#### Version Input Mode
142+
143+
* `Tab` or `Esc`: Go back to Normal mode
144+
* `Enter`: Perform search if version, search query and loader are set, otherwise go to search mode
145+
* Any other key: Updates the version input
146+
147+
#### Search Result List Mode
148+
149+
* `h` or `Left Arrow`: Deselect item
150+
* `j` or `Down Arrow`: Select next item
151+
* `k` or `Up Arrow`: Select previous item
152+
* `g` or `Home`: Select first item
153+
* `G` or `End`: Select last item
154+
* `Space`: Toggle selection of a mod
155+
* `Enter`: Download selected mods
156+
* `Esc`: Go back to Normal mode
157+
158+
#### Selected List Mode
159+
160+
* `j` or `Down Arrow`: Select next item
161+
* `k` or `Up Arrow`: Select previous item
162+
* `g` or `Home`: Select first item
163+
* `G` or `End`: Select last item
164+
* `J`: Go to Version Input mode
165+
* `Esc`: Go back to Normal mode

0 commit comments

Comments
 (0)