.json names.
diff --git a/src/lib/Focus.svelte b/src/lib/Focus.svelte
index 36ed023..c1ee716 100644
--- a/src/lib/Focus.svelte
+++ b/src/lib/Focus.svelte
@@ -79,7 +79,7 @@
{:else}
- Checking /user/app/{job.dump.titleId}/mount_img.lnk every 3 s
+ Waiting for ShadowMountPlus to register {job.dump.titleId}
{/if}
@@ -107,7 +107,7 @@
{:else if job.status === "done"}
{job.stages[3].state === "warn" ? "Uploaded" : "Done"}
- {job.stages[3].state === "warn" ? "On the PS5, not mounted yet" : "Ready to play"}
+ {job.stages[3].state === "warn" ? "On the PS5, but not registered yet" : "Ready to play"}
- Original
- {gb(job.dump.totalBytes)}
- Image
- {gb(job.imageBytes)}
@@ -116,8 +116,8 @@
{#if job.stages[3].state === "warn"}
- The image is on the PS5 and listed in ShadowMountPlus's manual.lst, but the mount wasn't confirmed in time.
- It often appears a little later; check the game list on the PS5.
+ The image is on the PS5, but ShadowMountPlus hasn't registered the game. The note at the top says why. Once
+ you've fixed that (usually by restarting ShadowMountPlus), use Check again.
{/if}
diff --git a/src/lib/Help.svelte b/src/lib/Help.svelte
index 0066508..e843f67 100644
--- a/src/lib/Help.svelte
+++ b/src/lib/Help.svelte
@@ -41,6 +41,13 @@
"If it keeps failing, the dump itself may be changing or damaged. Copy it again, or check the drive it's on.",
],
},
+ {
+ q: "ShadowMountPlus couldn't register the game",
+ a: [
+ "The image is on the PS5 and ShadowMountPlus mounted it, but it couldn't add the game to the home screen.",
+ "\"System hook was lost\" happens after rest mode in ShadowMountPlus 1.7beta4 and older. Update to 1.7beta5 or newer, or restart ShadowMountPlus, then use Check again.",
+ ],
+ },
{
q: "Mount not confirmed",
a: [
diff --git a/src/lib/Setup.svelte b/src/lib/Setup.svelte
index 3984126..809e348 100644
--- a/src/lib/Setup.svelte
+++ b/src/lib/Setup.svelte
@@ -256,7 +256,6 @@
.req li { display: flex; gap: 10px; align-items: center; color: var(--muted); }
.req li::before { content: ""; width: 12px; height: 12px; border-radius: 50%; border: 1.5px solid var(--faint); flex: none; }
.tips li { border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; color: var(--muted); }
- .tips b { color: var(--text); font-weight: 500; }
kbd { font: 500 11px var(--mono); border: 1px solid var(--line-strong); border-radius: 4px; padding: 1px 5px; color: var(--text); }
.scan { height: 2px; background: var(--line); border-radius: 2px; overflow: hidden; position: relative; margin-top: 8px; }
diff --git a/tests/fake_ps5.py b/tests/fake_ps5.py
index 53bbad5..f28bf93 100644
--- a/tests/fake_ps5.py
+++ b/tests/fake_ps5.py
@@ -11,23 +11,40 @@ cfg = os.path.join(root, "data/shadowmount/config.ini")
if not os.path.exists(cfg):
open(cfg, "w").write("# ShadowMountPlus\nmount_read_only=1\nimage_ro=OTHER.exfat\n")
open(os.path.join(root, "data/shadowmount/autotune.ini"), "w").write("image_sector=PPSA00001.ffpfsc:4096\n")
+ open(os.path.join(root, "data/shadowmount/debug.log"), "w").write("[00:00:00] ShadowMount+ (fake)\n")
def fake_smp():
+ """Mimics ShadowMountPlus 1.7: link files first, then registration, then manual.status.
+
+ Create data/shadowmount/.broken-hook to reproduce a lost ShellCore hook: the link files
+ are written but registration fails, so manual.status never says "installed".
+ """
+ smp = os.path.join(root, "data/shadowmount")
hb = os.path.join(root, "data/homebrew")
+ done = set()
while True:
- # Like the real one in practice: new images are only picked up once manual.lst lists them.
try:
- listed = open(os.path.join(root, "data/shadowmount/manual.lst")).read().split()
+ listed = open(os.path.join(smp, "manual.lst")).read().split()
except FileNotFoundError:
listed = []
for n in os.listdir(hb):
- if n.endswith(".ffpfsc") and not n.startswith(".") and f"/data/homebrew/{n}" in listed:
- tid = n[:9]
- d = os.path.join(root, "user/app", tid); os.makedirs(d, exist_ok=True)
- lnk = os.path.join(d, "mount_img.lnk")
- if not os.path.exists(lnk):
- time.sleep(4)
- open(lnk, "w").write(f"/data/homebrew/{n}\n/mnt/shadowmnt/pfsc/{tid}_deadbeef/{tid}.exfat\n")
+ path = f"/data/homebrew/{n}"
+ if not n.endswith(".ffpfsc") or n.startswith(".") or path not in listed or path in done:
+ continue
+ done.add(path)
+ tid = n[:9]
+ time.sleep(4)
+ d = os.path.join(root, "user/app", tid); os.makedirs(d, exist_ok=True)
+ open(os.path.join(d, "mount_img.lnk"), "w").write(f"{path}\n/mnt/shadowmnt/pfsc/{tid}_deadbeef/{tid}.exfat\n")
+ with open(os.path.join(smp, "debug.log"), "a") as log:
+ log.write(f"[00:00:00] [ACTION] Installing: Test Game ({tid})\n")
+ if os.path.exists(os.path.join(smp, ".broken-hook")):
+ log.write("[00:00:04] [REG] internal AppInstallTitleDir bridge unavailable\n")
+ log.write(f"[00:00:04] NOTIFY: Register failed: Test Game ({tid})\n")
+ continue
+ log.write("[00:00:04] [REG] Installed NEW!\n")
+ with open(os.path.join(smp, "manual.status"), "a") as st:
+ st.write(f"installed\t{tid}\t{path}\tTest Game\n")
time.sleep(1)
threading.Thread(target=fake_smp, daemon=True).start()