diff --git a/.gitignore b/.gitignore
index 3968dc7..92684da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,6 @@ dist/
target/
gen/
target-engine/
-public/mock/
src-tauri/binaries/
installer/src-tauri/payload/
*.bak
diff --git a/public/mock/icon.jpg b/public/mock/icon.jpg
new file mode 100644
index 0000000..9334661
Binary files /dev/null and b/public/mock/icon.jpg differ
diff --git a/public/mock/pic0.jpg b/public/mock/pic0.jpg
new file mode 100644
index 0000000..0176c5b
Binary files /dev/null and b/public/mock/pic0.jpg differ
diff --git a/src-tauri/icons/64x64.png b/src-tauri/icons/64x64.png
deleted file mode 100644
index 28d403a..0000000
Binary files a/src-tauri/icons/64x64.png and /dev/null differ
diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns
deleted file mode 100644
index ff84722..0000000
Binary files a/src-tauri/icons/icon.icns and /dev/null differ
diff --git a/src-tauri/src/ftp.rs b/src-tauri/src/ftp.rs
index f5f2581..e2bc8bc 100644
--- a/src-tauri/src/ftp.rs
+++ b/src-tauri/src/ftp.rs
@@ -288,8 +288,8 @@ mod tests {
#[test]
fn parses_ftpsrv_listing() {
assert_eq!(
- parse_list_line("-rw-rw-rw- 1 0 0 71733805056 Oct 10 13:53 PPSA05678.ffpfsc"),
- Some(Entry { name: "PPSA05678.ffpfsc".into(), size: 71733805056, is_dir: false })
+ parse_list_line("-rw-rw-rw- 1 0 0 71733805056 Oct 10 13:53 PPSA01234.ffpfsc"),
+ Some(Entry { name: "PPSA01234.ffpfsc".into(), size: 71733805056, is_dir: false })
);
assert_eq!(
parse_list_line("drwxrwxrwx 2 0 0 65536 Oct 09 19:48 My Game Folder"),
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index 5ce2e51..1eb377d 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -145,7 +145,6 @@ pub fn run() {
.plugin(tauri_plugin_updater::Builder::new().build())
.setup(|app| {
paths::init(app.path().app_config_dir()?, app.path().app_data_dir()?);
- settings::migrate_legacy();
let handle = app.handle().clone();
let emitter: Emitter = Arc::new(move |event, payload| {
let _ = handle.emit(event, payload);
diff --git a/src-tauri/src/paths.rs b/src-tauri/src/paths.rs
index 46e4a26..ae74263 100644
--- a/src-tauri/src/paths.rs
+++ b/src-tauri/src/paths.rs
@@ -32,12 +32,3 @@ pub fn data_dir() -> PathBuf {
.or_else(|| DATA.get().cloned())
.unwrap_or_else(|| home().join(".local/share/prospack"))
}
-
-/// Where the app lived while it was called Packer (Linux only).
-pub fn legacy_config_dir() -> PathBuf {
- home().join(".config/ps5-packer")
-}
-
-pub fn legacy_data_dir() -> PathBuf {
- home().join(".local/share/ps5-packer")
-}
diff --git a/src-tauri/src/ps5.rs b/src-tauri/src/ps5.rs
index 8fcfa04..68ced5d 100644
--- a/src-tauri/src/ps5.rs
+++ b/src-tauri/src/ps5.rs
@@ -346,23 +346,23 @@ mod tests {
#[test]
fn fnv_matches_game_compressor_file_names() {
- // Names Game Compressor actually wrote on the console.
- assert_eq!(format!("{:08x}", fnv1a32("/data/homebrew/PPSA05678.ffpfsc")), "17b59d6b");
+ // Same FNV-1a 32 Game Compressor uses for its validations/
-.json names.
assert_eq!(format!("{:08x}", fnv1a32("/data/homebrew/PPSA01234.ffpfsc")), "844067eb");
+ assert_eq!(format!("{:08x}", fnv1a32("/data/homebrew/PPSA05678.ffpfsc")), "17b59d6b");
}
#[test]
fn gc_record_has_the_fields_gc_reads() {
let r = GcRecord {
- title_id: "PPSA09012",
- image_remote: "/data/homebrew/PPSA09012.ffpfsc",
+ title_id: "PPSA01234",
+ image_remote: "/data/homebrew/PPSA01234.ffpfsc",
image_bytes: 53_800_000_000,
source_bytes: 86_900_000_000,
apr_indexed: true,
files_verified: 35,
};
let v: serde_json::Value = serde_json::from_str(&gc_record_json(&r, 1)).unwrap();
- assert_eq!(v["path"], "/data/homebrew/PPSA09012.ffpfsc");
+ assert_eq!(v["path"], "/data/homebrew/PPSA01234.ffpfsc");
assert_eq!(v["sourceSize"], 53_800_000_000u64);
assert_eq!(v["compressionSavedBytes"], 33_100_000_000u64);
assert_eq!(v["aprIndexed"], true);
@@ -372,13 +372,13 @@ mod tests {
#[test]
fn manual_list_replaces_same_title_entries() {
- let before = "/data/homebrew/PPSA05678.ffpfsc\n/data/homebrew/PPSA09012-app\n\n/data/homebrew/PPSA090120.ffpfsc\n";
- let after = manual_list_with(before, "PPSA09012", "/data/homebrew/PPSA09012.ffpfsc");
+ let before = "/data/homebrew/PPSA05678.ffpfsc\n/data/homebrew/PPSA01234-app\n\n/data/homebrew/PPSA012340.ffpfsc\n";
+ let after = manual_list_with(before, "PPSA01234", "/data/homebrew/PPSA01234.ffpfsc");
assert_eq!(
after,
- "/data/homebrew/PPSA05678.ffpfsc\n/data/homebrew/PPSA090120.ffpfsc\n/data/homebrew/PPSA09012.ffpfsc\n"
+ "/data/homebrew/PPSA05678.ffpfsc\n/data/homebrew/PPSA012340.ffpfsc\n/data/homebrew/PPSA01234.ffpfsc\n"
);
- assert_eq!(manual_list_with("", "PPSA09012", "/x/PPSA09012.ffpfsc"), "/x/PPSA09012.ffpfsc\n");
+ assert_eq!(manual_list_with("", "PPSA01234", "/x/PPSA01234.ffpfsc"), "/x/PPSA01234.ffpfsc\n");
}
#[test]
diff --git a/src-tauri/src/settings.rs b/src-tauri/src/settings.rs
index 6b9e129..1562520 100644
--- a/src-tauri/src/settings.rs
+++ b/src-tauri/src/settings.rs
@@ -1,6 +1,6 @@
use crate::paths;
use serde::{Deserialize, Serialize};
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, rename_all = "camelCase")]
@@ -82,94 +82,3 @@ pub fn save(s: &Settings) -> Result<(), String> {
std::fs::write(&tmp, serde_json::to_vec_pretty(s).unwrap()).map_err(|e| e.to_string())?;
std::fs::rename(&tmp, &path).map_err(|e| e.to_string())
}
-
-/// Carries settings and backups over from the app's earlier name ("Packer", ps5-packer dirs).
-/// Returns true when settings were written. Never touches the old folders.
-pub fn migrate_from(old_cfg: &Path, old_data: &Path, new_cfg: &Path, new_data: &Path) -> Result {
- let new_settings = new_cfg.join("settings.json");
- let mut wrote = false;
- if !new_settings.exists() {
- let old_settings = old_cfg.join("settings.json");
- let migrated = if let Ok(raw) = std::fs::read_to_string(&old_settings) {
- // They configured the old app on purpose, so the wizard isn't needed.
- let mut s: Settings = serde_json::from_str(&raw).map_err(|e| e.to_string())?;
- s.setup_done = true;
- Some(s)
- } else if old_data.is_dir() {
- // Used the old app with its built-in defaults: keep those, but show the wizard.
- let old_images = paths::home().join("PS5 Images");
- Some(Settings {
- ps5_host: "192.168.0.50".into(),
- output_dir: if old_images.is_dir() {
- old_images.to_string_lossy().into_owned()
- } else {
- default_output_dir().to_string_lossy().into_owned()
- },
- ..Settings::default()
- })
- } else {
- None
- };
- if let Some(s) = migrated {
- std::fs::create_dir_all(new_cfg).map_err(|e| e.to_string())?;
- std::fs::write(&new_settings, serde_json::to_vec_pretty(&s).unwrap()).map_err(|e| e.to_string())?;
- wrote = true;
- }
- }
- let (old_b, new_b) = (old_data.join("backups"), new_data.join("backups"));
- if old_b.is_dir() && !new_b.exists() {
- std::fs::create_dir_all(&new_b).map_err(|e| e.to_string())?;
- for e in std::fs::read_dir(&old_b).map_err(|e| e.to_string())?.flatten() {
- let _ = std::fs::copy(e.path(), new_b.join(e.file_name()));
- }
- }
- Ok(wrote)
-}
-
-pub fn migrate_legacy() {
- if let Err(e) = migrate_from(&paths::legacy_config_dir(), &paths::legacy_data_dir(), &config_dir(), &data_dir()) {
- eprintln!("settings migration failed: {e}");
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn migrates_old_ps5_packer_settings_once() {
- let t = tempfile::tempdir().unwrap();
- let (old_cfg, old_data) = (t.path().join("old/cfg"), t.path().join("old/data"));
- std::fs::create_dir_all(old_data.join("backups")).unwrap();
- std::fs::write(old_data.join("backups/1-config.ini"), "x").unwrap();
- std::fs::create_dir_all(&old_cfg).unwrap();
- std::fs::write(old_cfg.join("settings.json"), r#"{"ps5Host":"10.0.0.5","ftpPort":2121}"#).unwrap();
- let (new_cfg, new_data) = (t.path().join("new/cfg"), t.path().join("new/data"));
- assert!(migrate_from(&old_cfg, &old_data, &new_cfg, &new_data).unwrap());
- let s: Settings = serde_json::from_str(&std::fs::read_to_string(new_cfg.join("settings.json")).unwrap()).unwrap();
- assert_eq!(s.ps5_host, "10.0.0.5");
- assert!(s.setup_done, "people who configured Packer skip the wizard");
- assert!(new_data.join("backups/1-config.ini").is_file());
- assert!(!migrate_from(&old_cfg, &old_data, &new_cfg, &new_data).unwrap(), "second run is a no-op");
- }
-
- #[test]
- fn old_defaults_user_gets_old_host_and_the_wizard() {
- let t = tempfile::tempdir().unwrap();
- let old_data = t.path().join("old/data");
- std::fs::create_dir_all(&old_data).unwrap();
- let new_cfg = t.path().join("new/cfg");
- assert!(migrate_from(&t.path().join("old/cfg"), &old_data, &new_cfg, &t.path().join("new/data")).unwrap());
- let s: Settings = serde_json::from_str(&std::fs::read_to_string(new_cfg.join("settings.json")).unwrap()).unwrap();
- assert_eq!(s.ps5_host, "192.168.0.50");
- assert!(!s.setup_done);
- }
-
- #[test]
- fn fresh_install_writes_nothing() {
- let t = tempfile::tempdir().unwrap();
- let new_cfg = t.path().join("new/cfg");
- assert!(!migrate_from(&t.path().join("a"), &t.path().join("b"), &new_cfg, &t.path().join("c")).unwrap());
- assert!(!new_cfg.join("settings.json").exists());
- }
-}
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 1656179..3d5b9b1 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -40,7 +40,8 @@
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
- "icons/icon.png"
+ "icons/icon.png",
+ "icons/icon.ico"
],
"externalBin": [
"binaries/prospack-engine"
diff --git a/src/lib/mock.js b/src/lib/mock.js
index 8318299..b5fef0b 100644
--- a/src/lib/mock.js
+++ b/src/lib/mock.js
@@ -8,16 +8,16 @@ const STAGES = ["compress", "verify", "upload", "mount"];
let settings = {
setupDone: new URLSearchParams(location.search).has("setup") ? false : true,
ps5Host: "192.168.0.50", ftpPort: 2121, webPort: 8888, remoteDir: "/data/homebrew",
- outputDir: "/home/you/PS5 Images", compressionLevel: 7, cpuCount: 0, verifyWorkers: 0,
+ outputDir: "/home/you/Prospack Images", compressionLevel: 7, cpuCount: 0, verifyWorkers: 0,
autoUpload: true, writeSmpHints: true, markGcValidated: true, checkUpdates: true, deleteLocalAfterUpload: false,
};
const sample = {
path: "/games/PPSA01234-app", titleId: "PPSA01234", titleName: "Sample Game",
- version: "01.019.000", fileCount: 166733, totalBytes: 159841147026, apr: true, hasAmprIndex: true, accent: "#3d7bff",
+ version: "01.004.000", fileCount: 166733, totalBytes: 159841147026, apr: true, hasAmprIndex: true, accent: "#7b5cff",
};
-const flag = {
- path: "/games/PPSA05678-app0", titleId: "PPSA05678", titleName: "Another Game",
+const another = {
+ path: "/games/PPSA05678-app", titleId: "PPSA05678", titleName: "Another Game",
version: "01.000.000", fileCount: 299, totalBytes: 130982284503, apr: true, hasAmprIndex: true, accent: "#c9a46a",
};
@@ -28,7 +28,7 @@ let jobs = [
{
id: 1, dump: sample, status: "running", stage: 1, stages: blankStages(), pct: 0, doneBytes: 0, totalBytes: 0,
filesDone: 0, filesTotal: 166733, rate: 0, rateHistory: [], rateLabel: "verify", etaSecs: null, stageSecs: 0,
- imagePath: "/home/you/PS5 Images/PPSA01234.ffpfsc", imageBytes: 91_700_000_000, remotePath: null, mismatches: 0,
+ imagePath: "/home/you/Prospack Images/PPSA01234.ffpfsc", imageBytes: 91_700_000_000, remotePath: null, mismatches: 0,
problems: [], warnings: [], error: null,
log: [
log("Added " + sample.path, "hl"), log("Compress started", "hl"),
@@ -38,9 +38,9 @@ let jobs = [
],
},
{
- id: 2, dump: flag, status: "done", stage: 3, stages: blankStages(), pct: 100, doneBytes: 0, totalBytes: 0,
+ id: 2, dump: another, status: "done", stage: 3, stages: blankStages(), pct: 100, doneBytes: 0, totalBytes: 0,
filesDone: 0, filesTotal: 0, rate: 0, rateHistory: [], rateLabel: "", etaSecs: null, stageSecs: 0,
- imagePath: "/home/you/PS5 Images/PPSA05678.ffpfsc", imageBytes: 71_733_805_056,
+ imagePath: "/home/you/Prospack Images/PPSA05678.ffpfsc", imageBytes: 71_733_805_056,
remotePath: "/data/homebrew/PPSA05678.ffpfsc", mismatches: 0, problems: [], warnings: [], error: null,
log: [log("Finished", "ok")],
},
@@ -118,7 +118,7 @@ export const mock = {
installEngine: async () => { for (const l of ["Creating Python environment", "Installing MkPFS 1.1.0"]) { emit("engine-log", l); await delay(500); } return mock.engineStatus(); },
inspectDump: async () => { throw new Error("preview"); },
addJob: async () => { throw "Adding dumps needs the desktop app (this is a browser preview)"; },
- jobArt: async (path) => path.includes("SampleGame") ? { icon: "/mock/icon.jpg", hero: "/mock/pic0.jpg" } : { icon: null, hero: null },
+ jobArt: async () => ({ icon: null, hero: null }),
listJobs: async () => structuredClone(jobs),
cancelJob: async (id) => { const j = jobs.find((x) => x.id === id); if (j) { j.status = "cancelled"; j.stages[j.stage].state = "pending"; } emit("jobs", structuredClone(jobs)); },
removeJob: async (id) => { jobs = jobs.filter((x) => x.id !== id); emit("jobs", structuredClone(jobs)); },