mirror of
https://github.com/Grasscutters/Cultivation.git
synced 2025-12-14 16:14:48 +01:00
potentially gather installed mods
This commit is contained in:
@@ -1,4 +1,9 @@
|
|||||||
|
use crate::file_helpers;
|
||||||
use crate::web;
|
use crate::web;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::read_dir;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
static API_URL: &str = "https://api.gamebanana.com";
|
static API_URL: &str = "https://api.gamebanana.com";
|
||||||
static SITE_URL: &str = "https://gamebanana.com";
|
static SITE_URL: &str = "https://gamebanana.com";
|
||||||
@@ -16,3 +21,62 @@ pub async fn list_submissions(mode: String) -> String {
|
|||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn list_mods(path: String) -> HashMap<String, String> {
|
||||||
|
let mut path_buf = PathBuf::from(path);
|
||||||
|
|
||||||
|
// If the path includes a file, remove it
|
||||||
|
if path_buf.file_name().is_some() {
|
||||||
|
path_buf.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we are in the Mods folder
|
||||||
|
path_buf.push("Mods");
|
||||||
|
|
||||||
|
// Check if dir is empty
|
||||||
|
if file_helpers::dir_is_empty(path_buf.to_str().unwrap()) {
|
||||||
|
return HashMap::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut mod_info_files = vec![];
|
||||||
|
let mut mod_info_strings = HashMap::new();
|
||||||
|
|
||||||
|
for entry in read_dir(path_buf).unwrap() {
|
||||||
|
let entry = entry.unwrap();
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
// Check each dir for a modinfo.json file
|
||||||
|
if path.is_dir() {
|
||||||
|
let mut mod_info_path = path.clone();
|
||||||
|
mod_info_path.push("modinfo.json");
|
||||||
|
if mod_info_path.exists() {
|
||||||
|
// Push path AND file contents into the hashmap using path as key
|
||||||
|
mod_info_files.push(mod_info_path.to_str().unwrap().to_string());
|
||||||
|
} else {
|
||||||
|
// No modinfo, but we can still push a JSON obj with the folder name
|
||||||
|
mod_info_strings.insert(
|
||||||
|
path.to_str().unwrap().to_string(),
|
||||||
|
format!(
|
||||||
|
"{{ name: \"{}\" }}",
|
||||||
|
path.file_name().unwrap().to_str().unwrap()
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read each modinfo.json file
|
||||||
|
for mod_info_file in mod_info_files {
|
||||||
|
let mut mod_info_string = String::new();
|
||||||
|
|
||||||
|
// It is safe to unwrap here since we *know* that the file exists
|
||||||
|
let mut file = std::fs::File::open(&mod_info_file).unwrap();
|
||||||
|
file.read_to_string(&mut mod_info_string).unwrap();
|
||||||
|
|
||||||
|
// Push into hashmap using path as key
|
||||||
|
mod_info_strings.insert(mod_info_file, mod_info_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_info_strings
|
||||||
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ fn main() {
|
|||||||
web::valid_url,
|
web::valid_url,
|
||||||
web::web_get,
|
web::web_get,
|
||||||
gamebanana::list_submissions,
|
gamebanana::list_submissions,
|
||||||
|
gamebanana::list_mods,
|
||||||
metadata_patcher::patch_metadata
|
metadata_patcher::patch_metadata
|
||||||
])
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { getMods, ModData } from '../../../utils/gamebanana'
|
import { getInstalledMods, getMods, ModData } from '../../../utils/gamebanana'
|
||||||
import { LoadingCircle } from './LoadingCircle'
|
import { LoadingCircle } from './LoadingCircle'
|
||||||
|
|
||||||
import './ModList.css'
|
import './ModList.css'
|
||||||
@@ -11,7 +11,13 @@ interface IProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
modList: ModData[]
|
modList: ModData[] | null
|
||||||
|
installedList:
|
||||||
|
| {
|
||||||
|
path: string
|
||||||
|
info: unknown
|
||||||
|
}[]
|
||||||
|
| null
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ModList extends React.Component<IProps, IState> {
|
export class ModList extends React.Component<IProps, IState> {
|
||||||
@@ -20,11 +26,26 @@ export class ModList extends React.Component<IProps, IState> {
|
|||||||
|
|
||||||
console.log('Getting')
|
console.log('Getting')
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
modList: null,
|
||||||
|
installedList: null,
|
||||||
|
}
|
||||||
|
|
||||||
this.downloadMod = this.downloadMod.bind(this)
|
this.downloadMod = this.downloadMod.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
if (this.props.mode === 'installed') return
|
if (this.props.mode === 'installed') {
|
||||||
|
const installedMods = await getInstalledMods()
|
||||||
|
|
||||||
|
console.log(installedMods)
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
installedList: installedMods,
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const mods = await getMods(this.props.mode)
|
const mods = await getMods(this.props.mode)
|
||||||
|
|
||||||
@@ -40,11 +61,14 @@ export class ModList extends React.Component<IProps, IState> {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="ModList">
|
<div className="ModList">
|
||||||
{this.state && this.state.modList ? (
|
{(this.state.modList && this.props.mode !== 'installed') ||
|
||||||
|
(this.state.installedList && this.props.mode === 'installed') ? (
|
||||||
<div className="ModListInner">
|
<div className="ModListInner">
|
||||||
{this.state.modList.map((mod: ModData) => (
|
{this.props.mode === 'installed'
|
||||||
<ModTile mod={mod} key={mod.id} onClick={this.downloadMod} />
|
? this.state.installedList?.map((mod) => <></>)
|
||||||
))}
|
: this.state.modList?.map((mod: ModData) => (
|
||||||
|
<ModTile mod={mod} key={mod.id} onClick={this.downloadMod} />
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<LoadingCircle />
|
<LoadingCircle />
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { invoke } from '@tauri-apps/api'
|
import { invoke } from '@tauri-apps/api'
|
||||||
|
import { getConfigOption } from './configuration'
|
||||||
|
|
||||||
// Generated with https://transform.tools/json-to-typescript I'm lazy cry about it
|
// Generated with https://transform.tools/json-to-typescript I'm lazy cry about it
|
||||||
export interface GamebananaResponse {
|
export interface GamebananaResponse {
|
||||||
@@ -115,3 +116,21 @@ export async function formatGamebananaData(obj: GamebananaResponse[]) {
|
|||||||
})
|
})
|
||||||
.filter((itm) => itm.type === 'Mod')
|
.filter((itm) => itm.type === 'Mod')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getInstalledMods() {
|
||||||
|
const migotoPath = await getConfigOption('migoto_path')
|
||||||
|
|
||||||
|
if (!migotoPath) return []
|
||||||
|
|
||||||
|
const mods = (await invoke('list_mods', {
|
||||||
|
path: migotoPath,
|
||||||
|
})) as Record<string, string>
|
||||||
|
|
||||||
|
// These are returned as JSON strings, so we have to parse them
|
||||||
|
return Object.keys(mods).map((path) => {
|
||||||
|
return {
|
||||||
|
path,
|
||||||
|
info: JSON.parse(mods[path]),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user