diff --git a/frontend/src/pages/GameDetail.svelte b/frontend/src/pages/GameDetail.svelte index 31fde93..e6c6f83 100644 --- a/frontend/src/pages/GameDetail.svelte +++ b/frontend/src/pages/GameDetail.svelte @@ -243,6 +243,13 @@ ๐ŸชŸ Requires Windows 3.1 โ€” may not work in browser {:else} ๐Ÿ’พ DOS + {#if game.bundle_size} + ยท {game.bundle_size >= 1073741824 + ? (game.bundle_size / 1073741824).toFixed(1) + ' GB' + : game.bundle_size >= 1048576 + ? Math.round(game.bundle_size / 1048576) + ' MB' + : Math.round(game.bundle_size / 1024) + ' KB'} + {/if} {/if} {/if} @@ -410,6 +417,10 @@ background: #1a3a5c; color: #6ab0ff; } + .size-badge { + font-weight: 400; + opacity: 0.8; + } .meta { display: flex; gap: 8px; margin-bottom: 8px; } .meta-item { background: var(--surface-hover); color: var(--phosphor-dim); padding: 4px 12px; border-radius: 12px; font-size: 0.85rem; } .meta-link { cursor: pointer; text-decoration: none; transition: all 0.15s; display: inline-block; } diff --git a/frontend/src/pages/Library.svelte b/frontend/src/pages/Library.svelte index 6b58cce..73b68a8 100644 --- a/frontend/src/pages/Library.svelte +++ b/frontend/src/pages/Library.svelte @@ -28,9 +28,14 @@ let fileInput; - // When header upload button is clicked, trigger the hidden file input + // When header upload button is clicked, trigger the hidden file input. + // Uses a previous-value guard to prevent re-firing on component remount. + let prevUploadTrigger = $state(uploadTriggered); $effect(() => { - if (uploadTriggered > 0) fileInput?.click(); + if (uploadTriggered > 0 && uploadTriggered !== prevUploadTrigger) { + prevUploadTrigger = uploadTriggered; + fileInput?.click(); + } }); // Derive filter options from the loaded games diff --git a/src/main/java/com/dostalgia/Game.java b/src/main/java/com/dostalgia/Game.java index 8f14843..b4709ac 100644 --- a/src/main/java/com/dostalgia/Game.java +++ b/src/main/java/com/dostalgia/Game.java @@ -23,6 +23,9 @@ public class Game { private String setupExe; // relative path to SETUP.EXE (null if none) + /** Game bundle file size in bytes. Populated dynamically at load time (not persisted). */ + private Long bundleSize; + /** Currently selected main executable (relative path inside the bundle, e.g. "FALLOUT.EXE" or "FALLOUT/FALLOUT.EXE"). */ private String executable; @@ -91,6 +94,9 @@ public class Game { public String getSetupExe() { return setupExe; } public void setSetupExe(String setupExe) { this.setupExe = setupExe; } + public Long getBundleSize() { return bundleSize; } + public void setBundleSize(Long bundleSize) { this.bundleSize = bundleSize; } + public String getExecutable() { return executable; } public void setExecutable(String executable) { this.executable = executable; } diff --git a/src/main/java/com/dostalgia/GameService.java b/src/main/java/com/dostalgia/GameService.java index 01c6c48..ddfe632 100644 --- a/src/main/java/com/dostalgia/GameService.java +++ b/src/main/java/com/dostalgia/GameService.java @@ -67,8 +67,14 @@ public class GameService { Files.exists(gameDir(id).resolve("cover.png")) || Files.exists(gameDir(id).resolve("cover.webp")) ); + // Detect bundle size + try { + Path bundlePath = gamesDir.resolve(game.getBundleFile()); + if (bundlePath != null && Files.exists(bundlePath)) { + game.setBundleSize(Files.size(bundlePath)); + } + } catch (IOException ignored) {} return game; - } /** Save game metadata to disk. */ public void save(Game game) throws IOException {