Skip to content

Commit

Permalink
Merge pull request #227 from Tormak9970/dev
Browse files Browse the repository at this point in the history
chore: build v3.10.5
  • Loading branch information
Tormak9970 authored Nov 15, 2024
2 parents 6f31686 + 42ce7fb commit a2aa3b7
Show file tree
Hide file tree
Showing 14 changed files with 543 additions and 510 deletions.
103 changes: 103 additions & 0 deletions src-tauri/src/clean_grids.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use std::{collections::HashMap, fs, path::PathBuf};

use tauri::AppHandle;

use crate::{steam, utils::logger, zip_controller};


#[derive(Clone, serde::Serialize)]
#[allow(non_snake_case)]
struct CleanConflicts {
fileAName: String,
fileAPath: String,
fileBName: String,
fileBPath: String,
appid: String,
gridType: String
}

#[tauri::command]
/// Downloads a file from a url.
pub async fn clean_grids(app_handle: AppHandle, steam_path: String, steam_active_user_id: String, preset: String, all_appids: String, selected_game_ids: String) -> String {
logger::log_to_core_file(app_handle.to_owned(), format!("Starting {} grid cleaning.", preset).as_str(), 0);

let appids_arr: Vec<String> = serde_json::from_str(all_appids.as_str()).expect("Should have been able to deserialize appids array.");

let grids_dir_path: String = steam::get_grids_directory(app_handle.to_owned(), steam_path, steam_active_user_id);
let grids_dir_contents = fs::read_dir(grids_dir_path).unwrap();

let mut found_apps: HashMap<String, (String, String)> = HashMap::new();
let mut conflicts: Vec<CleanConflicts> = Vec::new();


if preset == String::from("clean") {
for dir_entry in grids_dir_contents {
let entry = dir_entry.expect("Should have been able to get directory entry.");

if !entry.file_type().unwrap().is_file() {
continue;
}

let full_file_path: PathBuf = entry.path();
let full_file_path_str: &str = full_file_path.to_str().unwrap();
let filename = entry.file_name();
let filename_str: &str = filename.to_str().unwrap();

let (id, grid_type) = zip_controller::get_id_from_grid_name(filename_str);
let id_type_str: String = format!("{}_{}", id, grid_type);

if !appids_arr.contains(&id) {
let remove_res = fs::remove_file(full_file_path);
if remove_res.is_err() {
let err = remove_res.err().unwrap();
return format!("{{ \"error\": \"{}\"}}", err.to_string());
}

logger::log_to_core_file(app_handle.to_owned(), format!("Deleted {}.", filename_str).as_str(), 0);
continue;
}

if found_apps.contains_key(&id_type_str) {
// ? There's a conflict
let (other_filename, other_full_path) = found_apps.get(&id_type_str).expect("Map should have contained the id_type_str.");

conflicts.push(CleanConflicts { fileAPath: other_full_path.to_owned(), fileAName: other_filename.to_owned(), fileBPath: String::from(full_file_path_str), fileBName: String::from(filename_str), appid: id.clone(), gridType: grid_type.clone() });

logger::log_to_core_file(app_handle.to_owned(), format!("Detected conflict between {} and {}.", filename_str, other_filename).as_str(), 0);
} else {
found_apps.insert(id_type_str, (String::from(filename_str), String::from(full_file_path_str)));
}
}
} else {
let game_ids_arr: Vec<String> = serde_json::from_str(selected_game_ids.as_str()).expect("Should have been able to deserialize selected appids array.");

for dir_entry in grids_dir_contents {
let entry = dir_entry.expect("Should have been able to get directory entry.");

if !entry.file_type().unwrap().is_file() {
continue;
}

let full_file_path: PathBuf = entry.path();
let filename = entry.file_name();
let filename_str: &str = filename.to_str().unwrap();

let (id, _) = zip_controller::get_id_from_grid_name(filename_str);

if game_ids_arr.contains(&id) {
let remove_res = fs::remove_file(full_file_path);
if remove_res.is_err() {
let err = remove_res.err().unwrap();
return format!("{{ \"error\": \"{}\"}}", err.to_string());
}

logger::log_to_core_file(app_handle.to_owned(), format!("Deleted {}.", filename_str).as_str(), 0);
}
}
}


logger::log_to_core_file(app_handle.to_owned(), format!("{} grid cleaning complete.", preset).as_str(), 0);

return serde_json::to_string(&conflicts).expect("Should have been able to serialize conflict array.");
}
257 changes: 257 additions & 0 deletions src-tauri/src/handle_changes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
use std::{path::PathBuf, collections::HashMap, fs};

use crate::parsers::shortcuts_vdf_parser::write_shortcuts_vdf;
use serde_json::{Map, Value};

use serde;
use crate::steam;
use tauri::{self, AppHandle};

use crate::logger;

type GridImageCache = HashMap<String, HashMap<String, String>>;

#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
#[allow(non_snake_case)]
struct ChangedPath {
appId: String,
gridType: String,
oldPath: String,
targetPath: String,
sourcePath: String
}

/// Checks if an appid belongs to a shortcut
fn is_appid_shortcut(appid: &str, shortcut_icons: &Map<String, Value>) -> bool {
return shortcut_icons.contains_key(appid);
}

/// Gets a grid's file name based on its type.
fn get_grid_filename(app_handle: &AppHandle, appid: &str, grid_type: &str, image_type: &str) -> String {
match grid_type {
"Capsule" => return format!("{}p{}", appid, image_type),
"Wide Capsule" => return format!("{}{}", appid, image_type),
"Hero" => return format!("{}_hero{}", appid, image_type),
"Logo" => return format!("{}_logo{}", appid, image_type),
"Icon" => return format!("{}_icon.jpg", appid),
_ => {
logger::log_to_core_file(app_handle.to_owned(), format!("Unexpected grid type {}", grid_type).as_str(), 2);
panic!("Unexpected grid type {}", grid_type);
}
}
}

/// Adjusts the path of a grid based on its type.
fn adjust_path(app_handle: &AppHandle, appid: &str, path: &str, grid_type: &str) -> String {
let format_start_index = path.rfind(".").expect("Path should have had a file extension.");
let image_type = &path[format_start_index..];
return get_grid_filename(app_handle, appid, grid_type, image_type);
}

/// Filters the grid paths based on which have change.
fn filter_paths(app_handle: &AppHandle, steam_path: String, steam_active_user_id: String, current_paths: &GridImageCache, original_paths: &GridImageCache, shortcut_icons: &Map<String, Value>) -> Vec<ChangedPath> {
let grids_dir = PathBuf::from(steam::get_grids_directory(app_handle.to_owned(), steam_path.to_owned(), steam_active_user_id));
let lib_cache_dir = PathBuf::from(steam::get_library_cache_directory(app_handle.to_owned(), steam_path.to_owned()));
let mut res:Vec<ChangedPath> = Vec::new();

for (appid, grids_map) in current_paths.into_iter() {
for (grid_type, source_path) in grids_map.into_iter() {
let mut grid_path: &String = &String::from("");

if original_paths.get(appid.as_str()).is_some() && original_paths.get(appid.as_str()).unwrap().get(grid_type.as_str()).is_some() {
grid_path = original_paths.get(appid.as_str()).unwrap().get(grid_type.as_str()).unwrap();
}

let grid_path_owned = grid_path.to_owned();
let source_path_owned = source_path.to_owned();

if source_path_owned != grid_path_owned {
let target_path;

if source_path != "REMOVE" {
let adjusted_path = adjust_path(app_handle, appid.as_str(), source_path_owned.as_str(), grid_type.as_str()).replace("\\", "/");
if grid_type == "Icon" && !is_appid_shortcut(&appid, shortcut_icons) {
target_path = String::from(lib_cache_dir.join(adjusted_path).to_str().unwrap()).replace("\\", "/");
} else {
target_path = String::from(grids_dir.join(adjusted_path).to_str().unwrap()).replace("\\", "/");
}
} else {
target_path = String::from("REMOVE");
}

let mut changed_path = ChangedPath {
appId: appid.to_owned(),
gridType: grid_type.to_owned(),
oldPath: grid_path_owned.replace("\\", "/"),
targetPath: target_path.to_owned(),
sourcePath: source_path_owned.replace("\\", "/")
};

if changed_path.targetPath.ends_with(".webp") {
let target: String = changed_path.targetPath;
let mut jpg_target: String = target[..target.len() - 5].to_owned();
jpg_target.push_str(".jpg");

changed_path.targetPath = String::from(jpg_target.to_owned());
}

res.push(changed_path);
}
}
}

return res;
}

/// Checks for shortcut grid changes.
fn check_for_shortcut_changes(shortcut_icons: &Map<String, Value>, original_shortcut_icons: &Map<String, Value>) -> bool {
for (shortcut_id, icon) in shortcut_icons.to_owned().into_iter() {
let icon: &str = icon.as_str().expect("Should have been able to convert icon to &str.");
let original_icon: &str = original_shortcut_icons.get(&shortcut_id).expect("Original hortcut should have had an icon.").as_str().expect("Should have been able to convert original icon to &str.");

if icon != original_icon {
return true;
}
}

return false;
}



#[tauri::command]
/// Applies the changes the user has made.
pub async fn save_changes(app_handle: AppHandle, steam_path: String, steam_active_user_id: String, current_art: String, original_art: String, shortcuts_str: String, shortcut_icons: Map<String, Value>, original_shortcut_icons: Map<String, Value>, changed_logo_positions: Map<String, Value>) -> String {
let current_art_dict: GridImageCache = serde_json::from_str(current_art.as_str()).unwrap();
let original_art_dict: GridImageCache = serde_json::from_str(original_art.as_str()).unwrap();

logger::log_to_core_file(app_handle.to_owned(), "Converting current path entries to grid paths...", 0);
let paths_to_set: Vec<ChangedPath> = filter_paths(&app_handle, steam_path.to_owned(), steam_active_user_id.clone(), &current_art_dict, &original_art_dict, &shortcut_icons);
let paths_id_map: HashMap<String, ChangedPath> = paths_to_set.clone().iter().map(| entry | (format!("{}_{}", entry.appId.to_owned(), entry.gridType.to_owned()).to_string(), entry.to_owned())).collect();
logger::log_to_core_file(app_handle.to_owned(), "Current path entries converted to grid paths.", 0);

for changed_path in (&paths_to_set).into_iter() {
let source = changed_path.sourcePath.to_owned();
let target = changed_path.targetPath.to_owned();

if target == String::from("REMOVE") {
if changed_path.oldPath.contains("grid") {
let remove_res = fs::remove_file(changed_path.oldPath.to_owned());
if remove_res.is_err() {
let err = remove_res.err().unwrap();
return format!("{{ \"error\": \"{}\"}}", err.to_string());
}

logger::log_to_core_file(app_handle.to_owned(), format!("Removed grid {}.", changed_path.oldPath.to_owned()).as_str(), 0);
}
} else {
if changed_path.oldPath.contains("grid") {
let remove_res = fs::remove_file(changed_path.oldPath.to_owned());
if remove_res.is_err() {
let err = remove_res.err().unwrap();
return format!("{{ \"error\": \"{}\"}}", err.to_string());
}
}

fs::File::create(target.clone()).unwrap();

let copy_res = fs::copy(source.clone(), target.clone());

if copy_res.is_err() {
logger::log_to_core_file(app_handle.to_owned(), format!("Failed to copy {} to {}.", source, target).as_str(), 2);
let err = copy_res.err().unwrap();
return format!("{{ \"error\": \"{}\"}}", err.to_string());
}

logger::log_to_core_file(app_handle.to_owned(), format!("Copied {} to {}.", source, target).as_str(), 0);
}
}

let grids_directory: PathBuf = PathBuf::from(steam::get_grids_directory(app_handle.to_owned(), steam_path.to_owned(), steam_active_user_id.clone()));
for (appid, steam_logo_str_val) in changed_logo_positions.into_iter() {
let steam_logo_str: &str = steam_logo_str_val.as_str().expect("Should have been able to convert steamLogo pos into str.");
let logo_config_path: PathBuf = grids_directory.join(format!("{}.json", appid));

if steam_logo_str == "REMOVE" {
let remove_res = fs::remove_file(logo_config_path);
if remove_res.is_err() {
let err = remove_res.err().unwrap();
return format!("{{ \"error\": \"{}\"}}", err.to_string());
}

logger::log_to_core_file(app_handle.to_owned(), format!("Removed logo position config for {}.", appid).as_str(), 0);
} else {
let write_res = fs::write(&logo_config_path, steam_logo_str);

if write_res.is_err() {
logger::log_to_core_file(app_handle.to_owned(), format!("Failed to write logo pos to config for {}.", appid).as_str(), 2);
let err = write_res.err().unwrap();
return format!("{{ \"error\": \"{}\"}}", err.to_string());
}

logger::log_to_core_file(app_handle.to_owned(), format!("Wrote logo pos to config for {}.", appid).as_str(), 0);
}
}

let should_change_shortcuts: bool = check_for_shortcut_changes(&shortcut_icons, &original_shortcut_icons);

if should_change_shortcuts {
logger::log_to_core_file(app_handle.to_owned(), "Changes to shortcuts detected. Writing shortcuts.vdf...", 0);
let mut shortcuts_data: Value = serde_json::from_str(shortcuts_str.as_str()).expect("Should have been able to parse json string.");

let shortcuts_obj_map: &mut Value = shortcuts_data.get_mut("shortcuts").expect("key: shortcuts should have existed.");
let shortcuts_map: &mut Map<String, Value> = shortcuts_obj_map.as_object_mut().expect("Should have been able to convert shortcuts to map");

for (_, shortcut) in shortcuts_map.into_iter() {
let shortcut_map: &mut Map<String, Value> = shortcut.as_object_mut().expect("should have been able to convert shortcut to map.");
let shortcut_appid_val: &Value = shortcut_map.get("appid").expect("shortcut should have had an appid");
let shortcut_appid_num: i64 = shortcut_appid_val.as_i64().expect("should have been able to convert shortcut appid to str.");
let shortcut_appid: String = shortcut_appid_num.to_string();

let path_key: String = format!("{}_icon", shortcut_appid.to_owned()).to_string();

if paths_id_map.contains_key(&path_key) {
let changed_path: &ChangedPath = paths_id_map.get(&path_key).expect("entry should have existed.");
shortcut_map.insert(String::from("icon"), Value::String(changed_path.targetPath.to_owned()));
}
}

let mut modified_shortcuts_data: Map<String, Value> = Map::new();
modified_shortcuts_data.insert(String::from("shortcuts"), shortcuts_obj_map.to_owned());
shortcuts_data = Value::Object(modified_shortcuts_data);

let shortcuts_vdf_path: PathBuf = PathBuf::from(steam::get_shortcuts_path(app_handle.to_owned(), steam_path.to_owned(), steam_active_user_id));
write_shortcuts_vdf(&shortcuts_vdf_path, shortcuts_data);
logger::log_to_core_file(app_handle.to_owned(), "Changes to shortcuts saved.", 0);
} else {
logger::log_to_core_file(app_handle.to_owned(), "No changes to shortcuts detected. Skipping...", 0);
}

let changed_res = serde_json::to_string::<Vec<ChangedPath>>(paths_to_set.as_ref());

if changed_res.is_err() {
let err = changed_res.err().unwrap();
logger::log_to_core_file(app_handle, format!("{}", err.to_string()).as_str(), 2);
return String::from("[]");
}

return changed_res.unwrap();
}

#[tauri::command]
/// Writes the user's shortcuts.vdf file.
pub async fn write_shortcuts(app_handle: AppHandle, steam_path: String, steam_active_user_id: String, shortcuts_str: String) -> bool {
logger::log_to_core_file(app_handle.to_owned(), "Writing shortcuts.vdf...", 0);
let shortcuts_vdf_path: PathBuf = PathBuf::from(steam::get_shortcuts_path(app_handle.to_owned(), steam_path, steam_active_user_id));
let shortcuts_data: Value = serde_json::from_str(shortcuts_str.as_str()).expect("Should have been able to parse json string.");

let success: bool = write_shortcuts_vdf(&shortcuts_vdf_path, shortcuts_data);

if success {
logger::log_to_core_file(app_handle.to_owned(), "Changes to shortcuts saved.", 0);
return true;
} else {
logger::log_to_core_file(app_handle.to_owned(), "Changes to shortcuts failed.", 0);
return false;
}
}
Loading

0 comments on commit a2aa3b7

Please sign in to comment.