mirror of
https://github.com/manos555555/PS5-Suite.git
synced 2026-10-13 18:01:07 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6501452103 | ||
|
|
367e57ca1f | ||
|
|
80b75d30eb | ||
|
|
1f80816b5a | ||
|
|
fa4635cadb | ||
|
|
49faaf1ba6 | ||
|
|
b2261ee5f8 | ||
|
|
6dce564861 | ||
|
|
05315d6966 | ||
|
|
33d44f429d |
No files matched your search
@@ -4,6 +4,31 @@ All notable changes to **PS5 Suite** (client app + on-console payload).
|
||||
|
||||
---
|
||||
|
||||
## v7.3.0 (October 2026)
|
||||
|
||||
### New Features
|
||||
- **Unmount All button** — removes every mounted game in one action, with confirmation dialog and per-title progress. Only suite-mounted games are touched (verified by `mount.lnk` marker or active `/system_ex/app` overlay) — real installed titles are never affected.
|
||||
|
||||
### Major Improvements
|
||||
- **Full k-stuff compatibility** — every feature previously gated behind etaHEN now works on k-stuff too: mount/unmount, launch game, controller info + lightbar, PKG installs, suspend/resume/kill.
|
||||
- **Mount/unmount no longer kills the home screen** — on kstuff firmwares 12.00+, game registration now runs through SceShellCore's own `installTitleDir` via an injected code-cave bridge (offsets verified per-firmware). The daemon writes the registry rows and notifies the UI itself, so icons appear and disappear instantly with zero renderer restarts.
|
||||
- **Unregister via `sceAppInstUtilAppUnInstall`** — official daemon IPC removes the icon live; direct SQLite writes remain only as a watchdog-guarded fallback.
|
||||
- **Launch Game works on k-stuff** — removed the etaHEN-only gate. `sceLncUtilLaunchApp` error codes are now handled correctly: the daemon launches asynchronously, so the payload polls for the target's `eboot.bin` process (up to ~8s) and reports real success with the actual app_id. If another game holds the foreground, it is closed via `sceLncUtilKillApp` and the launch is retried — same as the PS5 UI's "close game?" flow.
|
||||
- **Power actions use official daemon paths** — reboot/shutdown no longer call the raw `reboot()` syscall (which halted the kernel but left the console in a zombie state that needed a power-plug pull). Reboot now goes through `sceSystemServiceRequestReboot`; shutdown through `sceSystemStateMgrTurnOff` with `sceShellCoreUtilRequestShutdown`/`RequestPowerOff` fallbacks. Raw syscall kept only as last resort.
|
||||
- **Controller info + lightbar on k-stuff** — removed the etaHEN gate; the ShellCore/ShellUI remote pad bridge (ptrace + remote calls inside a process that owns a real pad session) works on both loaders. Verified live with real analog/button data.
|
||||
|
||||
### Bug Fixes
|
||||
- Fixed mounted-game icons landing past the visible edge of the home row (`lastAccessIndex` now uses MAX+1 like real installs; stale index-0 rows are healed automatically).
|
||||
- Fixed `proc_find_name` ENOMEM race that could fail process lookups.
|
||||
- Stale ShellCore bridge hooks are detected and recovered instead of failing the registration.
|
||||
- Fixed launch kill-heuristic matching system daemons with numeric title IDs — a running game is now identified strictly by `comm == "eboot.bin"`; system processes (SceCdlgApp, ShellUI) are never touched.
|
||||
- Trophy unlock/re-lock fixes from v7.2.x verified under k-stuff (fixes issue #11).
|
||||
|
||||
### Removed
|
||||
- **Capture Screen** — removed from payload and both clients. `sceScreenShotCapture` requires a registered app-thread context the payload cannot satisfy: local calls return `0x80C1B001` and remote calls inside ShellUI/ShellCore/capture daemons/`eboot.bin` all return `0x80BE0001`. Rather than a button that can never work, the feature is gone; browsing/downloading/deleting existing captures in the Screenshots tab is unaffected.
|
||||
|
||||
---
|
||||
|
||||
## v7.2.4 (October 2026)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -10,8 +10,11 @@ All-in-one management suite for jailbroken PS5 consoles. One app — on **Window
|
||||
|
||||
**This project is built for the PS5 scene, for free — if it saved you time or you just like what we do, consider buying us a coffee. Every cup goes straight back into new features, fixes and payload wizardry.** 🍻
|
||||
|
||||
[](https://buymeacoffee.com/manos555555)
|
||||
**Got questions, ideas or found a bug? Join the community on Discord — we hang out there!**
|
||||
|
||||
[](https://ko-fi.com/manosmourtzakis)
|
||||
[](https://x.com/manos_moyrtzis)
|
||||
[](https://discord.gg/eRXG2Csmpy)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -46,8 +49,8 @@ All-in-one management suite for jailbroken PS5 consoles. One app — on **Window
|
||||
|
||||
## 🚀 Setup (2 minutes)
|
||||
|
||||
1. Load a jailbreak / payload loader on the PS5 — tested with **etaHEN** and **Kstuff** (any payload loader that accepts ELFs works).
|
||||
2. Open the app → expand **⚙️ Payload Settings** → **📂 Browse** → pick `payload/ps5_suite_server.elf` → **📤 Send Payload** (default port 9020).
|
||||
1. Load a jailbreak / payload loader on the PS5 — **fully compatible with both etaHEN and Kstuff** (any payload loader that accepts ELFs works). All features including mount/unmount, launch game and DualSense control work on k-stuff.
|
||||
2. Open the app → expand **⚙️ Payload Settings** → **📂 Browse** → pick `payload/ps5_suite_server.elf` → **📤 Send Payload** (default port 9021).
|
||||
3. The payload installs itself and starts the suite server (ports 9113–9116).
|
||||
4. Press **🔍** to auto-discover the console on your LAN, or type its IP → **🔌 Connect**.
|
||||
5. Done. Future payload updates go through **🔄 Self-Update Payload** (pushes the new ELF through the running server) or **⬆️ Update from GitHub**.
|
||||
@@ -63,8 +66,8 @@ All-in-one management suite for jailbroken PS5 consoles. One app — on **Window
|
||||
- **Auto-discover (🔍)** — broadcasts on the LAN and finds the PS5 automatically.
|
||||
- **Profiles** — save multiple consoles by name, delete them, reconnect instantly.
|
||||
- **Storage Info panel** — free/total space on the console's drive, **🔄 Refresh Storage** button.
|
||||
- **Payload Settings** — pick the ELF, set the injection port (default 9020), **Send Payload**, **Self-Update Payload** (updates the running server in place), **Update from GitHub** (checks for new suite releases).
|
||||
- **Buy Me a Coffee** link in the header. ❤️
|
||||
- **Payload Settings** — pick the ELF, set the injection port (default 9021), **Send Payload**, **Self-Update Payload** (updates the running server in place), **Update from GitHub** (checks for new suite releases).
|
||||
- **Ko-fi support link** in the header. ❤️
|
||||
|
||||
---
|
||||
|
||||
@@ -104,7 +107,7 @@ Two side-by-side panes: your PC on the left, the PS5 on the right.
|
||||
|
||||
---
|
||||
|
||||
### � GAMES → Homebrew Store
|
||||
### 🛍️ GAMES → Homebrew Store
|
||||
|
||||
- Built-in **pkg-zone.com** catalog: browse/search every public PS5 homebrew package.
|
||||
- Covers, version + author info, one-tap **📥 Install** — the package streams straight to the console installer.
|
||||
@@ -123,7 +126,6 @@ Two side-by-side panes: your PC on the left, the PS5 on the right.
|
||||
- Lists every trophy set on the console (per game) with real data parsed from TRPTITLE.DAT — names, descriptions, grades (bronze/silver/gold/platinum), icons, hidden status and earned timestamps.
|
||||
- **🔓 Unlock** — awards a trophy live through the running game (the matching title must be running — the app tells you if it isn't).
|
||||
- **🔒 Lock** — re-locks a trophy by rewriting the set's unlock bitmasks in place (group masks, row flags and timestamps cleared) — as if it was never earned.
|
||||
- **📥 Unlock All** — batch-unlock every trophy in the set in one click.
|
||||
- Search/filter across sets, live refresh after every change.
|
||||
|
||||
> ⚠️ **Warning:** unlocking many trophies with unrealistically short/identical timestamps can look suspicious if the console ever syncs to PSN. **I take no responsibility for any ban on your account or console** — use this feature offline and at your own risk.
|
||||
@@ -131,7 +133,7 @@ Two side-by-side panes: your PC on the left, the PS5 on the right.
|
||||
---
|
||||
|
||||
|
||||
### �💾 SAVES & MEDIA → Saves
|
||||
### 💾 SAVES & MEDIA → Saves
|
||||
|
||||
- Enumerates all save data on the console (per user, per title) with size/type badges.
|
||||
- **🔓 Mount (decrypt)** — mounts the save decrypted on the PS5 so its files are readable.
|
||||
@@ -183,7 +185,7 @@ Everything is read **live from the console** — nothing hardcoded; values the c
|
||||
- **🎮 Controller (DualSense)** — live pad state + controller info read through a remote bridge into `SceShellUI` (the payload gets no pad session of its own, so it resolves the real logged-in user remotely — nothing hardcoded). **Lightbar**: set any RGB color.
|
||||
- **💡 Console LED** — real `/dev/icc_indicator` interface with three hardware channels (blue `0x01` / white `0x11` / amber `0x21` — verified on hardware): pick a color, run effects (breathe, sunrise, blink, chase…), `auto` hands control back to the system.
|
||||
- **🔔 Notify** — push a custom notification to the PS5 screen.
|
||||
- ** Beeper** — console beep / mute.
|
||||
- **🔊 Beeper** — console beep / mute.
|
||||
|
||||
---
|
||||
|
||||
@@ -261,7 +263,7 @@ Everything is read **live from the console** — nothing hardcoded; values the c
|
||||
| On-console payload | C, built with the **PS5 Payload SDK** (`prospero-clang`) |
|
||||
| FPKG engine | **LibProsperoPkg** (bundled) — CNT/PFS/PFSC/PFSv3/FIH build, read & verify |
|
||||
| Transfer protocol | Raw TCP, chunked + parallel streams |
|
||||
| Suite server ports | 9113–9116 |
|
||||
| Suite server ports | 9113–9118 (scans until it finds the live server) |
|
||||
| Local PKG streamer ports | 18990–19009 |
|
||||
| Payload proxy port | 13801+ |
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<SupportedOSPlatformVersion>23</SupportedOSPlatformVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ApplicationId>com.manos.ps5suite</ApplicationId>
|
||||
<ApplicationVersion>8</ApplicationVersion>
|
||||
<ApplicationDisplayVersion>7.2.4</ApplicationDisplayVersion>
|
||||
<ApplicationVersion>9</ApplicationVersion>
|
||||
<ApplicationDisplayVersion>7.3.0</ApplicationDisplayVersion>
|
||||
<ApplicationTitle>PS5 Suite</ApplicationTitle>
|
||||
<AndroidPackageFormat>apk</AndroidPackageFormat>
|
||||
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Version>7.2.4</Version>
|
||||
<Version>7.3.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -85,7 +85,6 @@ namespace PS5Upload
|
||||
PowerAction = 0x77,
|
||||
UsbList = 0x78,
|
||||
PadInfo = 0x79,
|
||||
Screenshot = 0x7B,
|
||||
Notify = 0x7C,
|
||||
PadAction = 0x7D,
|
||||
IccControl = 0x7E,
|
||||
@@ -2623,26 +2622,6 @@ namespace PS5Upload
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool success, string message)> CaptureScreenshotAsync()
|
||||
{
|
||||
await _commandLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
await SendCommandAsync(Command.Screenshot);
|
||||
var (response, data) = await ReceiveResponseAsync(20000);
|
||||
string msg = data.Length > 0 ? Encoding.UTF8.GetString(data).TrimEnd('\0', '\n', '\r') : response.ToString();
|
||||
return (response == Response.Ok, msg);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_commandLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public Task<(bool success, string message)> NotifyAsync(string text)
|
||||
=> SendTextCommandAsync(Command.Notify, text);
|
||||
|
||||
|
||||
@@ -278,18 +278,16 @@ public partial class MainView
|
||||
}
|
||||
if (found == null)
|
||||
{
|
||||
set.EarnedFallback = unionPop;
|
||||
if (rowState.Count == 0) return;
|
||||
foreach (var t in set.Trophies)
|
||||
if (rowState.TryGetValue(t.Id, out var rs))
|
||||
{
|
||||
t.StateKnown = true;
|
||||
t.IsUnlocked = rs.unlocked;
|
||||
t.UnlockedTime = rs.when == default ? null : rs.when;
|
||||
}
|
||||
return;
|
||||
// Multi-group sets: no single window carries the union, so the
|
||||
// popcount scan misses. The union of the 0x700 group masks IS
|
||||
// the authoritative per-trophy state — apply it directly
|
||||
// instead of rows-only (which made list disagree with sidebar).
|
||||
mask = unionMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = found;
|
||||
}
|
||||
mask = found;
|
||||
}
|
||||
|
||||
set.UnlockMask = mask;
|
||||
|
||||
@@ -415,8 +415,6 @@
|
||||
<TextBlock Text="📸 Screenshots" Foreground="#0E9CFF" FontWeight="Bold" FontSize="14" VerticalAlignment="Center"/>
|
||||
<Button Grid.Column="1" Content="🔄" Background="#3E3E42" Padding="8" Click="ScreenshotsRefreshButton_Click"/>
|
||||
</Grid>
|
||||
<Button Content="📸 Capture Screenshot" Background="#007ACC" Foreground="White"
|
||||
Padding="12" HorizontalAlignment="Stretch" Click="CaptureScreenshotButton_Click"/>
|
||||
<ListBox x:Name="ScreenshotsListBox" Background="#1E1E1E" MaxHeight="260">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
|
||||
@@ -644,19 +644,6 @@ public partial class MainView : UserControl
|
||||
catch (Exception ex) { UpdateStatus($"Screenshots error: {ex.Message}"); }
|
||||
}
|
||||
|
||||
private async void CaptureScreenshotButton_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!RequireConnection()) return;
|
||||
UpdateStatus("Capturing screenshot on PS5...");
|
||||
try
|
||||
{
|
||||
var (ok, msg) = await _protocol!.CaptureScreenshotAsync();
|
||||
UpdateStatus(ok ? $"📸 {msg}" : $"Screenshot failed: {msg}");
|
||||
if (ok) await Task.Delay(1500).ContinueWith(_ => Dispatcher.UIThread.Post(() => ScreenshotsRefreshButton_Click(null, null!)));
|
||||
}
|
||||
catch (Exception ex) { UpdateStatus($"Screenshot error: {ex.Message}"); }
|
||||
}
|
||||
|
||||
private async void ScreenshotDeleteButton_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!RequireConnection()) return;
|
||||
|
||||
@@ -318,7 +318,7 @@ namespace PS5Upload
|
||||
else
|
||||
{
|
||||
Log("❌ Failed to send payload");
|
||||
await ShowMessageAsync($"Failed to send payload to {ipAddress}:{_payloadPort}\n\nMake sure GoldHEN is running.", "Connection Failed");
|
||||
await ShowMessageAsync($"Failed to send payload to {ipAddress}:{_payloadPort}\n\nMake sure a payload loader (etaHEN/GoldHEN) is listening on that port.", "Connection Failed");
|
||||
}
|
||||
SendPayloadButton.IsEnabled = true;
|
||||
}
|
||||
@@ -639,13 +639,13 @@ namespace PS5Upload
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// BUY ME A COFFEE
|
||||
// KO-FI SUPPORT LINK
|
||||
// ============================================================
|
||||
private void BuyMeCoffeeButton_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo { FileName = "https://buymeacoffee.com/manos555555", UseShellExecute = true });
|
||||
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo { FileName = "https://ko-fi.com/manosmourtzakis", UseShellExecute = true });
|
||||
Log("☕ Thank you for your support!");
|
||||
}
|
||||
catch (Exception ex) { Log($"❌ Failed to open link: {ex.Message}"); }
|
||||
@@ -1559,7 +1559,7 @@ namespace PS5Upload
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// LIGHT BAR / VIBRATION / SCREENSHOT / NOTIFY / LED / BEEPER
|
||||
// LIGHT BAR / VIBRATION / NOTIFY / LED / BEEPER
|
||||
// ============================================================
|
||||
private async void LightBar_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
@@ -1573,20 +1573,6 @@ namespace PS5Upload
|
||||
catch (Exception ex) { Log($"❌ Light bar error: {ex.Message}"); }
|
||||
}
|
||||
|
||||
private async void Screenshot_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_protocol.IsConnected) { await ShowMessageAsync("Not connected to PS5", "Error"); return; }
|
||||
try
|
||||
{
|
||||
Log("📸 Requesting screenshot...");
|
||||
var (success, message) = await _protocol.CaptureScreenshotAsync();
|
||||
Log(success
|
||||
? $"✅ Screenshot captured ({message}) — find it under Saves & Media → Screenshots"
|
||||
: $"❌ Screenshot failed: {message}");
|
||||
}
|
||||
catch (Exception ex) { Log($"❌ Screenshot error: {ex.Message}"); }
|
||||
}
|
||||
|
||||
private async void SendNotify_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_protocol.IsConnected) { await ShowMessageAsync("Not connected to PS5", "Error"); return; }
|
||||
|
||||
@@ -497,6 +497,28 @@ namespace PS5Upload
|
||||
}
|
||||
}
|
||||
|
||||
private async void UnmountAllGamesButton_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_protocol.IsConnected) { await ShowMessageAsync("Not connected to PS5", "Error"); return; }
|
||||
if (!await ShowConfirmAsync("Unmount ALL games?\n\nEvery mounted game will be removed from the PS5 home screen.")) return;
|
||||
|
||||
UnmountAllGamesButton.IsEnabled = false;
|
||||
UnmountAllGamesButton.Content = "⏳ Unmounting...";
|
||||
Log("🗑️ Unmount All: Starting...");
|
||||
try
|
||||
{
|
||||
var (success, message) = await _protocol.UnmountAllGamesAsync(msg =>
|
||||
Dispatcher.UIThread.Post(() => Log($" {msg}")));
|
||||
if (success) { Log($"✅ {message}"); await RefreshGameListAsync(); }
|
||||
else { Log($"❌ Failed: {message}"); await ShowMessageAsync($"Unmount all failed:\n{message}", "Error"); }
|
||||
}
|
||||
finally
|
||||
{
|
||||
UnmountAllGamesButton.Content = "🗑️ Unmount All";
|
||||
UnmountAllGamesButton.IsEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async void OpenGamePathMenuItem_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (MountedGamesListBox.SelectedItem is PS5MountedGame game)
|
||||
|
||||
@@ -309,21 +309,18 @@ namespace PS5Upload
|
||||
}
|
||||
if (found == null)
|
||||
{
|
||||
// Counts known, per-trophy flags unknown — keep "—" per row.
|
||||
set.EarnedFallback = unionPop;
|
||||
// Still apply verified per-row flags from the 0x800 table
|
||||
// where present (Witcher file: flags matched the mask 100%).
|
||||
if (rowState.Count == 0) return;
|
||||
foreach (var t in set.Trophies)
|
||||
if (rowState.TryGetValue(t.Id, out var rs))
|
||||
{
|
||||
t.StateKnown = true;
|
||||
t.IsUnlocked = rs.unlocked;
|
||||
t.UnlockedTime = rs.when == default ? null : rs.when;
|
||||
}
|
||||
return;
|
||||
// Multi-group sets: no single window carries the union, so
|
||||
// the popcount scan misses. The union of the 0x700 group
|
||||
// masks IS the authoritative per-trophy state (it is what
|
||||
// the console reads) — apply it directly instead of
|
||||
// falling back to rows-only, which made the list disagree
|
||||
// with the sidebar count (sidebar=unionPop, list=rows).
|
||||
mask = unionMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = found;
|
||||
}
|
||||
mask = found;
|
||||
}
|
||||
|
||||
set.UnlockMask = mask;
|
||||
|
||||
@@ -161,11 +161,11 @@
|
||||
|
||||
<!-- Bottom Actions -->
|
||||
<StackPanel Grid.Row="3" Margin="10,10,10,15">
|
||||
<Button x:Name="BuyMeCoffeeButton" Background="#FFDD00" Foreground="#000000"
|
||||
<Button x:Name="BuyMeCoffeeButton" Background="#FF5E5B" Foreground="#FFFFFF"
|
||||
Click="BuyMeCoffeeButton_Click" HorizontalAlignment="Stretch" Padding="8,6" FontSize="12">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<TextBlock Text="☕" FontSize="14" Margin="0,0,6,0"/>
|
||||
<TextBlock Text="Buy me a coffee" FontSize="12" Foreground="#000000"/>
|
||||
<TextBlock Text="Support me on Ko-fi" FontSize="12" Foreground="#FFFFFF"/>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
@@ -390,6 +390,7 @@
|
||||
<TextBlock x:Name="GameCountText" Text="(0 games)" FontSize="12" Foreground="#999999" VerticalAlignment="Center" Margin="0,0,15,0"/>
|
||||
<Button x:Name="RefreshGameListButton" Content="🔄 Refresh" Click="RefreshGameListButton_Click" Padding="10,5" Margin="0,0,8,0"/>
|
||||
<Button x:Name="MountGamesFromListButton" Content="📥 Mount All" Click="MountGamesButton_Click" Padding="10,5" Background="#28A745"/>
|
||||
<Button x:Name="UnmountAllGamesButton" Content="🗑️ Unmount All" Click="UnmountAllGamesButton_Click" Padding="10,5" Margin="8,0,0,0" Background="#8B0000"/>
|
||||
</WrapPanel>
|
||||
</Border>
|
||||
|
||||
@@ -1320,13 +1321,9 @@
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<TextBlock Text="📸 Screenshot & 🔔 Notification" FontWeight="Bold" FontSize="16" Foreground="#0E9CFF" Margin="0,0,0,15"/>
|
||||
<TextBlock Text="🔔 Notification" FontWeight="Bold" FontSize="16" Foreground="#0E9CFF" Margin="0,0,0,15"/>
|
||||
<Border Background="#252526" BorderBrush="#3E3E42" BorderThickness="1" CornerRadius="6" Padding="15" Margin="0,0,0,15">
|
||||
<StackPanel>
|
||||
<WrapPanel Margin="0,0,0,10">
|
||||
<Button Content="📸 Capture Screen" Click="Screenshot_Click" Padding="12,6" Background="#007ACC" Margin="0,0,10,0"/>
|
||||
<TextBlock Text="Saved to PS5 — grab it from Saves & Media" Foreground="#707070" FontSize="11" VerticalAlignment="Center"/>
|
||||
</WrapPanel>
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBox x:Name="NotifyTextBox" PlaceholderText="Notification text..." Padding="8,6" Margin="0,0,10,0"/>
|
||||
<Button Grid.Column="1" Content="🔔 Send" Click="SendNotify_Click" Padding="12,6" Background="#28A745"/>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<AssemblyName>PS5Suite</AssemblyName>
|
||||
<RootNamespace>PS5Upload</RootNamespace>
|
||||
<ApplicationIcon>ps5_logo.ico</ApplicationIcon>
|
||||
<Version>7.2.4</Version>
|
||||
<Version>7.3.0</Version>
|
||||
<Authors>Manos</Authors>
|
||||
<Description>PS5 Suite - Complete PS5 Management Platform</Description>
|
||||
<Copyright>Copyright © 2026 Manos</Copyright>
|
||||
|
||||
+38
-21
@@ -80,6 +80,7 @@ namespace PS5Upload
|
||||
MemRegions = 0x6B,
|
||||
MemSearch = 0x6C,
|
||||
KlogRead = 0x6D,
|
||||
UnmountAll = 0x6E,
|
||||
MountGame = 0x6F,
|
||||
// App Manager v2
|
||||
AppListV2 = 0x70,
|
||||
@@ -92,7 +93,6 @@ namespace PS5Upload
|
||||
PowerAction = 0x77,
|
||||
UsbList = 0x78,
|
||||
PadInfo = 0x79,
|
||||
Screenshot = 0x7B,
|
||||
Notify = 0x7C,
|
||||
PadAction = 0x7D,
|
||||
IccControl = 0x7E,
|
||||
@@ -1257,26 +1257,6 @@ namespace PS5Upload
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(bool success, string message)> CaptureScreenshotAsync()
|
||||
{
|
||||
await _commandLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
await SendCommandAsync(Command.Screenshot);
|
||||
var (response, data) = await ReceiveResponseAsync(20000);
|
||||
string msg = data.Length > 0 ? Encoding.UTF8.GetString(data).TrimEnd('\0', '\n', '\r') : response.ToString();
|
||||
return (response == Response.Ok, msg);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_commandLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public Task<(bool success, string message)> NotifyAsync(string text)
|
||||
=> SendTextCommandAsync(Command.Notify, text);
|
||||
|
||||
@@ -1551,6 +1531,43 @@ namespace PS5Upload
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Unmount every mounted game (same async worker pipeline).</summary>
|
||||
public async Task<(bool success, string message)> UnmountAllGamesAsync(Action<string>? onProgress = null)
|
||||
{
|
||||
await _commandLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
await SendCommandAsync(Command.UnmountAll);
|
||||
|
||||
var deadline = DateTime.UtcNow + TimeSpan.FromMinutes(10);
|
||||
while (true)
|
||||
{
|
||||
int remainingMs = (int)(deadline - DateTime.UtcNow).TotalMilliseconds;
|
||||
if (remainingMs <= 0) return (false, "Unmount-all timed out after 10 minutes");
|
||||
|
||||
var (response, respData) = await ReceiveResponseAsync(remainingMs);
|
||||
string message = respData != null ? Encoding.UTF8.GetString(respData).TrimEnd('\0') : "";
|
||||
|
||||
if (response == Response.Progress)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(message)) onProgress?.Invoke(message);
|
||||
continue;
|
||||
}
|
||||
if (response == Response.Ok) return (true, message);
|
||||
if (response == Response.Error) return (false, message);
|
||||
return (false, $"Unexpected response: {response}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_commandLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
// NEW: Launch a game by title ID
|
||||
public async Task<(bool success, string message)> LaunchGameAsync(string titleId)
|
||||
{
|
||||
|
||||
+102
-102
@@ -1,102 +1,102 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Builds standalone single-file executables of PS5Suite for all major platforms.
|
||||
|
||||
.DESCRIPTION
|
||||
Produces self-contained, single-file binaries (no .NET runtime required on target machine) for:
|
||||
- Windows x64 -> dist/win-x64/PS5Suite.exe
|
||||
- Linux x64 -> dist/linux-x64/PS5Suite
|
||||
- Linux ARM64 -> dist/linux-arm64/PS5Suite
|
||||
- macOS x64 (Intel) -> dist/osx-x64/PS5Suite
|
||||
- macOS ARM64 (M1+) -> dist/osx-arm64/PS5Suite
|
||||
|
||||
.PARAMETER Targets
|
||||
Optional list of RIDs to build. Defaults to all 5.
|
||||
Example: .\publish.ps1 -Targets win-x64,linux-x64
|
||||
|
||||
.PARAMETER Clean
|
||||
Wipe the dist/ folder before building.
|
||||
|
||||
.EXAMPLE
|
||||
.\publish.ps1
|
||||
.\publish.ps1 -Targets win-x64
|
||||
.\publish.ps1 -Clean
|
||||
#>
|
||||
|
||||
param(
|
||||
[string[]] $Targets = @('win-x64', 'linux-x64', 'linux-arm64', 'osx-x64', 'osx-arm64'),
|
||||
[switch] $Clean
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProjectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$Project = Join-Path $ProjectRoot 'PS5Suite.csproj'
|
||||
$DistRoot = Join-Path $ProjectRoot 'dist'
|
||||
|
||||
if (-not (Test-Path $Project)) {
|
||||
Write-Error "Project file not found: $Project"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($Clean -and (Test-Path $DistRoot)) {
|
||||
Write-Host "Cleaning $DistRoot ..." -ForegroundColor Yellow
|
||||
Remove-Item $DistRoot -Recurse -Force
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $DistRoot -Force | Out-Null
|
||||
|
||||
$summary = @()
|
||||
|
||||
foreach ($rid in $Targets) {
|
||||
$outDir = Join-Path $DistRoot $rid
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
Write-Host " Publishing $rid" -ForegroundColor Cyan
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
|
||||
$args = @(
|
||||
'publish', $Project,
|
||||
'-c', 'Release',
|
||||
'-r', $rid,
|
||||
'--self-contained', 'true',
|
||||
'-p:PublishSingleFile=true',
|
||||
'-p:IncludeNativeLibrariesForSelfExtract=true',
|
||||
'-p:EnableCompressionInSingleFile=true',
|
||||
'-p:DebugType=None',
|
||||
'-p:DebugSymbols=false',
|
||||
'-o', $outDir
|
||||
)
|
||||
|
||||
& dotnet @args
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Publish failed for $rid"
|
||||
$summary += [pscustomobject]@{ RID = $rid; Status = 'FAILED'; Path = '-'; SizeMB = '-' }
|
||||
continue
|
||||
}
|
||||
|
||||
# Locate the produced binary
|
||||
$exeName = if ($rid -like 'win-*') { 'PS5Suite.exe' } else { 'PS5Suite' }
|
||||
$exePath = Join-Path $outDir $exeName
|
||||
|
||||
if (Test-Path $exePath) {
|
||||
$sizeMB = [math]::Round((Get-Item $exePath).Length / 1MB, 2)
|
||||
Write-Host (" -> {0} ({1} MB)" -f $exePath, $sizeMB) -ForegroundColor Green
|
||||
$summary += [pscustomobject]@{ RID = $rid; Status = 'OK'; Path = $exePath; SizeMB = $sizeMB }
|
||||
} else {
|
||||
Write-Warning "Binary not found at expected path: $exePath"
|
||||
$summary += [pscustomobject]@{ RID = $rid; Status = 'NO BINARY'; Path = $outDir; SizeMB = '-' }
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
Write-Host " Build summary" -ForegroundColor Cyan
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
$summary | Format-Table -AutoSize
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Notes:" -ForegroundColor Yellow
|
||||
Write-Host " - Linux/macOS users may need: chmod +x ./PS5Suite"
|
||||
Write-Host " - macOS may also need: xattr -dr com.apple.quarantine ./PS5Suite"
|
||||
Write-Host " - All builds are self-contained; no .NET runtime needed on the target system."
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Builds standalone single-file executables of PS5Suite for all major platforms.
|
||||
|
||||
.DESCRIPTION
|
||||
Produces self-contained, single-file binaries (no .NET runtime required on target machine) for:
|
||||
- Windows x64 -> dist/win-x64/PS5Suite.exe
|
||||
- Linux x64 -> dist/linux-x64/PS5Suite
|
||||
- Linux ARM64 -> dist/linux-arm64/PS5Suite
|
||||
- macOS x64 (Intel) -> dist/osx-x64/PS5Suite
|
||||
- macOS ARM64 (M1+) -> dist/osx-arm64/PS5Suite
|
||||
|
||||
.PARAMETER Targets
|
||||
Optional list of RIDs to build. Defaults to all 5.
|
||||
Example: .\publish.ps1 -Targets win-x64,linux-x64
|
||||
|
||||
.PARAMETER Clean
|
||||
Wipe the dist/ folder before building.
|
||||
|
||||
.EXAMPLE
|
||||
.\publish.ps1
|
||||
.\publish.ps1 -Targets win-x64
|
||||
.\publish.ps1 -Clean
|
||||
#>
|
||||
|
||||
param(
|
||||
[string[]] $Targets = @('win-x64', 'linux-x64', 'linux-arm64', 'osx-x64', 'osx-arm64'),
|
||||
[switch] $Clean
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProjectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$Project = Join-Path $ProjectRoot 'PS5Suite.csproj'
|
||||
$DistRoot = Join-Path $ProjectRoot 'dist'
|
||||
|
||||
if (-not (Test-Path $Project)) {
|
||||
Write-Error "Project file not found: $Project"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($Clean -and (Test-Path $DistRoot)) {
|
||||
Write-Host "Cleaning $DistRoot ..." -ForegroundColor Yellow
|
||||
Remove-Item $DistRoot -Recurse -Force
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $DistRoot -Force | Out-Null
|
||||
|
||||
$summary = @()
|
||||
|
||||
foreach ($rid in $Targets) {
|
||||
$outDir = Join-Path $DistRoot $rid
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
Write-Host " Publishing $rid" -ForegroundColor Cyan
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
|
||||
$args = @(
|
||||
'publish', $Project,
|
||||
'-c', 'Release',
|
||||
'-r', $rid,
|
||||
'--self-contained', 'true',
|
||||
'-p:PublishSingleFile=true',
|
||||
'-p:IncludeNativeLibrariesForSelfExtract=true',
|
||||
'-p:EnableCompressionInSingleFile=true',
|
||||
'-p:DebugType=None',
|
||||
'-p:DebugSymbols=false',
|
||||
'-o', $outDir
|
||||
)
|
||||
|
||||
& dotnet @args
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Publish failed for $rid"
|
||||
$summary += [pscustomobject]@{ RID = $rid; Status = 'FAILED'; Path = '-'; SizeMB = '-' }
|
||||
continue
|
||||
}
|
||||
|
||||
# Locate the produced binary
|
||||
$exeName = if ($rid -like 'win-*') { 'PS5Suite.exe' } else { 'PS5Suite' }
|
||||
$exePath = Join-Path $outDir $exeName
|
||||
|
||||
if (Test-Path $exePath) {
|
||||
$sizeMB = [math]::Round((Get-Item $exePath).Length / 1MB, 2)
|
||||
Write-Host (" -> {0} ({1} MB)" -f $exePath, $sizeMB) -ForegroundColor Green
|
||||
$summary += [pscustomobject]@{ RID = $rid; Status = 'OK'; Path = $exePath; SizeMB = $sizeMB }
|
||||
} else {
|
||||
Write-Warning "Binary not found at expected path: $exePath"
|
||||
$summary += [pscustomobject]@{ RID = $rid; Status = 'NO BINARY'; Path = $outDir; SizeMB = '-' }
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
Write-Host " Build summary" -ForegroundColor Cyan
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
$summary | Format-Table -AutoSize
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Notes:" -ForegroundColor Yellow
|
||||
Write-Host " - Linux/macOS users may need: chmod +x ./PS5Suite"
|
||||
Write-Host " - macOS may also need: xattr -dr com.apple.quarantine ./PS5Suite"
|
||||
Write-Host " - All builds are self-contained; no .NET runtime needed on the target system."
|
||||
+32
-32
@@ -1,32 +1,32 @@
|
||||
# PS5 Suite Server - Makefile
|
||||
# Uses the maintained ps5-payload-dev/sdk (2026 release, v0.43+)
|
||||
|
||||
PS5_PAYLOAD_SDK ?= /opt/ps5-payload-sdk
|
||||
PS5_IP ?= 192.168.0.160
|
||||
|
||||
CC := $(PS5_PAYLOAD_SDK)/bin/prospero-clang
|
||||
CXX := $(PS5_PAYLOAD_SDK)/bin/prospero-clang++
|
||||
LD := $(PS5_PAYLOAD_SDK)/bin/prospero-lld
|
||||
DEPLOY := $(PS5_PAYLOAD_SDK)/bin/prospero-deploy
|
||||
|
||||
ELF := ps5_suite_server.elf
|
||||
CFLAGS := -Wall -O3
|
||||
|
||||
all: $(ELF)
|
||||
|
||||
# Static link like the proven game_mounter/working-v6 model — libkernel_sys
|
||||
# (NOT kernel_web: externs like sceKernelGetCpuTemperature don't exist in the
|
||||
# runtime web variant and would make the ELF fail to launch).
|
||||
$(ELF): main.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lkernel_sys -lSceSystemService -lSceUserService -lSceAppInstUtil -lSceNetCtl -lScePad -lsqlite3
|
||||
$(PS5_PAYLOAD_SDK)/bin/llvm-strip $@
|
||||
|
||||
# Push the freshly built payload straight to the console (elfldr must be
|
||||
# running; uses the http:// URI support added in SDK v0.36.1).
|
||||
deploy: $(ELF)
|
||||
$(DEPLOY) http://$(PS5_IP):9021 $(ELF)
|
||||
|
||||
clean:
|
||||
rm -f $(ELF)
|
||||
|
||||
.PHONY: all clean deploy
|
||||
# PS5 Suite Server - Makefile
|
||||
# Uses the maintained ps5-payload-dev/sdk (2026 release, v0.43+)
|
||||
|
||||
PS5_PAYLOAD_SDK ?= /opt/ps5-payload-sdk
|
||||
PS5_IP ?= 192.168.0.160
|
||||
|
||||
CC := $(PS5_PAYLOAD_SDK)/bin/prospero-clang
|
||||
CXX := $(PS5_PAYLOAD_SDK)/bin/prospero-clang++
|
||||
LD := $(PS5_PAYLOAD_SDK)/bin/prospero-lld
|
||||
DEPLOY := $(PS5_PAYLOAD_SDK)/bin/prospero-deploy
|
||||
|
||||
ELF := ps5_suite_server.elf
|
||||
CFLAGS := -Wall -O3
|
||||
|
||||
all: $(ELF)
|
||||
|
||||
# Static link like the proven game_mounter/working-v6 model — libkernel_sys
|
||||
# (NOT kernel_web: externs like sceKernelGetCpuTemperature don't exist in the
|
||||
# runtime web variant and would make the ELF fail to launch).
|
||||
$(ELF): main.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lkernel_sys -lSceSystemService -lSceUserService -lSceAppInstUtil -lSceNetCtl -lScePad -lsqlite3
|
||||
$(PS5_PAYLOAD_SDK)/bin/llvm-strip $@
|
||||
|
||||
# Push the freshly built payload straight to the console (elfldr must be
|
||||
# running; uses the http:// URI support added in SDK v0.36.1).
|
||||
deploy: $(ELF)
|
||||
$(DEPLOY) http://$(PS5_IP):9021 $(ELF)
|
||||
|
||||
clean:
|
||||
rm -f $(ELF)
|
||||
|
||||
.PHONY: all clean deploy
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
export PS5_PAYLOAD_SDK=/opt/ps5-payload-sdk
|
||||
export PATH=/opt/ps5-payload-sdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
cd "$(dirname "$0")"
|
||||
make clean
|
||||
make
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
[
|
||||
"EP0700-PPSA10737_00-LITTLENIGHTMARES",
|
||||
"UP0700-PPSA10738_00-LITTLENIGHTMARES",
|
||||
"HP5028-PPSA10740_00-LITTLENIGHTMARES",
|
||||
"JP0700-PPSA10739_00-LITTLENIGHTMARES"
|
||||
[
|
||||
"EP0700-PPSA10737_00-LITTLENIGHTMARES",
|
||||
"UP0700-PPSA10738_00-LITTLENIGHTMARES",
|
||||
"HP5028-PPSA10740_00-LITTLENIGHTMARES",
|
||||
"JP0700-PPSA10739_00-LITTLENIGHTMARES"
|
||||
]
|
||||
+2164
-2164
File diff suppressed because it is too large.
Load diff
+1162
-125
File diff suppressed because it is too large.
Load diff
+137
-137
@@ -1,137 +1,137 @@
|
||||
{
|
||||
"addcont": {
|
||||
"serviceIdForSharing": [
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" "
|
||||
]
|
||||
},
|
||||
"ageLevel": {
|
||||
"AE": 16,
|
||||
"AR": 13,
|
||||
"AT": 16,
|
||||
"AU": 15,
|
||||
"BE": 16,
|
||||
"BG": 16,
|
||||
"BH": 16,
|
||||
"BO": 13,
|
||||
"BR": 14,
|
||||
"CA": 13,
|
||||
"CH": 16,
|
||||
"CL": 13,
|
||||
"CO": 13,
|
||||
"CR": 13,
|
||||
"CY": 16,
|
||||
"CZ": 16,
|
||||
"DE": 12,
|
||||
"DK": 16,
|
||||
"EC": 13,
|
||||
"ES": 16,
|
||||
"FI": 16,
|
||||
"FR": 16,
|
||||
"GB": 16,
|
||||
"GR": 16,
|
||||
"GT": 13,
|
||||
"HN": 13,
|
||||
"HR": 16,
|
||||
"HU": 16,
|
||||
"IE": 16,
|
||||
"IL": 16,
|
||||
"IN": 16,
|
||||
"IS": 16,
|
||||
"IT": 16,
|
||||
"JP": 15,
|
||||
"KR": 15,
|
||||
"KW": 16,
|
||||
"LB": 16,
|
||||
"LU": 16,
|
||||
"MT": 16,
|
||||
"MX": 13,
|
||||
"NI": 13,
|
||||
"NL": 16,
|
||||
"NO": 16,
|
||||
"NZ": 15,
|
||||
"OM": 16,
|
||||
"PA": 13,
|
||||
"PE": 13,
|
||||
"PL": 16,
|
||||
"PT": 16,
|
||||
"PY": 13,
|
||||
"QA": 16,
|
||||
"RO": 16,
|
||||
"RU": 16,
|
||||
"SA": 16,
|
||||
"SE": 16,
|
||||
"SI": 16,
|
||||
"SK": 16,
|
||||
"SV": 13,
|
||||
"TR": 16,
|
||||
"TW": 15,
|
||||
"UA": 16,
|
||||
"US": 13,
|
||||
"UY": 13,
|
||||
"ZA": 16,
|
||||
"default": 16
|
||||
},
|
||||
"applicationCategoryType": 0,
|
||||
"applicationDrmType": "standard",
|
||||
"attribute": 0,
|
||||
"attribute2": 0,
|
||||
"attribute3": 4194304,
|
||||
"conceptId": "223059",
|
||||
"contentBadgeType": 1,
|
||||
"contentId": "EP0700-PPSA10737_00-LITTLENIGHTMARES",
|
||||
"contentVersion": "01.004.000",
|
||||
"downloadDataSize": 0,
|
||||
"gameIntent": {
|
||||
"permittedIntents": [
|
||||
{
|
||||
"intentType": "launchActivity"
|
||||
}
|
||||
]
|
||||
},
|
||||
"localizedParameters": {
|
||||
"de-DE": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"defaultLanguage": "en-US",
|
||||
"en-US": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"es-ES": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"fr-FR": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"it-IT": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"pl-PL": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"ru-RU": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"sv-SE": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
}
|
||||
},
|
||||
"masterVersion": "01.00",
|
||||
"originContentVersion": "01.000.000",
|
||||
"pubtools": {
|
||||
"creationDate": "2025-11-24 11:19:04",
|
||||
"submission": true,
|
||||
"toolVersion": "3.13"
|
||||
},
|
||||
"requiredSystemSoftwareVersion": "0x1240000000000000",
|
||||
"sdkVersion": "0x0900000000000000",
|
||||
"targetContentVersion": "01.003.000",
|
||||
"titleId": "PPSA10737",
|
||||
"userDefinedParam1": 0,
|
||||
"versionFileUri": "https://sgst.prod.dl.playstation.net/sgst/prod/00/np/PPSA10737_00/f530dd33-21e0-48c9-8816-878774f65d8d-version.xml "
|
||||
}
|
||||
{
|
||||
"addcont": {
|
||||
"serviceIdForSharing": [
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" "
|
||||
]
|
||||
},
|
||||
"ageLevel": {
|
||||
"AE": 16,
|
||||
"AR": 13,
|
||||
"AT": 16,
|
||||
"AU": 15,
|
||||
"BE": 16,
|
||||
"BG": 16,
|
||||
"BH": 16,
|
||||
"BO": 13,
|
||||
"BR": 14,
|
||||
"CA": 13,
|
||||
"CH": 16,
|
||||
"CL": 13,
|
||||
"CO": 13,
|
||||
"CR": 13,
|
||||
"CY": 16,
|
||||
"CZ": 16,
|
||||
"DE": 12,
|
||||
"DK": 16,
|
||||
"EC": 13,
|
||||
"ES": 16,
|
||||
"FI": 16,
|
||||
"FR": 16,
|
||||
"GB": 16,
|
||||
"GR": 16,
|
||||
"GT": 13,
|
||||
"HN": 13,
|
||||
"HR": 16,
|
||||
"HU": 16,
|
||||
"IE": 16,
|
||||
"IL": 16,
|
||||
"IN": 16,
|
||||
"IS": 16,
|
||||
"IT": 16,
|
||||
"JP": 15,
|
||||
"KR": 15,
|
||||
"KW": 16,
|
||||
"LB": 16,
|
||||
"LU": 16,
|
||||
"MT": 16,
|
||||
"MX": 13,
|
||||
"NI": 13,
|
||||
"NL": 16,
|
||||
"NO": 16,
|
||||
"NZ": 15,
|
||||
"OM": 16,
|
||||
"PA": 13,
|
||||
"PE": 13,
|
||||
"PL": 16,
|
||||
"PT": 16,
|
||||
"PY": 13,
|
||||
"QA": 16,
|
||||
"RO": 16,
|
||||
"RU": 16,
|
||||
"SA": 16,
|
||||
"SE": 16,
|
||||
"SI": 16,
|
||||
"SK": 16,
|
||||
"SV": 13,
|
||||
"TR": 16,
|
||||
"TW": 15,
|
||||
"UA": 16,
|
||||
"US": 13,
|
||||
"UY": 13,
|
||||
"ZA": 16,
|
||||
"default": 16
|
||||
},
|
||||
"applicationCategoryType": 0,
|
||||
"applicationDrmType": "standard",
|
||||
"attribute": 0,
|
||||
"attribute2": 0,
|
||||
"attribute3": 4194304,
|
||||
"conceptId": "223059",
|
||||
"contentBadgeType": 1,
|
||||
"contentId": "EP0700-PPSA10737_00-LITTLENIGHTMARES",
|
||||
"contentVersion": "01.004.000",
|
||||
"downloadDataSize": 0,
|
||||
"gameIntent": {
|
||||
"permittedIntents": [
|
||||
{
|
||||
"intentType": "launchActivity"
|
||||
}
|
||||
]
|
||||
},
|
||||
"localizedParameters": {
|
||||
"de-DE": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"defaultLanguage": "en-US",
|
||||
"en-US": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"es-ES": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"fr-FR": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"it-IT": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"pl-PL": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"ru-RU": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"sv-SE": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
}
|
||||
},
|
||||
"masterVersion": "01.00",
|
||||
"originContentVersion": "01.000.000",
|
||||
"pubtools": {
|
||||
"creationDate": "2025-11-24 11:19:04",
|
||||
"submission": true,
|
||||
"toolVersion": "3.13"
|
||||
},
|
||||
"requiredSystemSoftwareVersion": "0x1240000000000000",
|
||||
"sdkVersion": "0x0900000000000000",
|
||||
"targetContentVersion": "01.003.000",
|
||||
"titleId": "PPSA10737",
|
||||
"userDefinedParam1": 0,
|
||||
"versionFileUri": "https://sgst.prod.dl.playstation.net/sgst/prod/00/np/PPSA10737_00/f530dd33-21e0-48c9-8816-878774f65d8d-version.xml "
|
||||
}
|
||||
+137
-137
@@ -1,137 +1,137 @@
|
||||
{
|
||||
"addcont": {
|
||||
"serviceIdForSharing": [
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" "
|
||||
]
|
||||
},
|
||||
"ageLevel": {
|
||||
"AE": 16,
|
||||
"AR": 13,
|
||||
"AT": 16,
|
||||
"AU": 15,
|
||||
"BE": 16,
|
||||
"BG": 16,
|
||||
"BH": 16,
|
||||
"BO": 13,
|
||||
"BR": 14,
|
||||
"CA": 13,
|
||||
"CH": 16,
|
||||
"CL": 13,
|
||||
"CO": 13,
|
||||
"CR": 13,
|
||||
"CY": 16,
|
||||
"CZ": 16,
|
||||
"DE": 12,
|
||||
"DK": 16,
|
||||
"EC": 13,
|
||||
"ES": 16,
|
||||
"FI": 16,
|
||||
"FR": 16,
|
||||
"GB": 16,
|
||||
"GR": 16,
|
||||
"GT": 13,
|
||||
"HN": 13,
|
||||
"HR": 16,
|
||||
"HU": 16,
|
||||
"IE": 16,
|
||||
"IL": 16,
|
||||
"IN": 16,
|
||||
"IS": 16,
|
||||
"IT": 16,
|
||||
"JP": 15,
|
||||
"KR": 15,
|
||||
"KW": 16,
|
||||
"LB": 16,
|
||||
"LU": 16,
|
||||
"MT": 16,
|
||||
"MX": 13,
|
||||
"NI": 13,
|
||||
"NL": 16,
|
||||
"NO": 16,
|
||||
"NZ": 15,
|
||||
"OM": 16,
|
||||
"PA": 13,
|
||||
"PE": 13,
|
||||
"PL": 16,
|
||||
"PT": 16,
|
||||
"PY": 13,
|
||||
"QA": 16,
|
||||
"RO": 16,
|
||||
"RU": 16,
|
||||
"SA": 16,
|
||||
"SE": 16,
|
||||
"SI": 16,
|
||||
"SK": 16,
|
||||
"SV": 13,
|
||||
"TR": 16,
|
||||
"TW": 15,
|
||||
"UA": 16,
|
||||
"US": 13,
|
||||
"UY": 13,
|
||||
"ZA": 16,
|
||||
"default": 16
|
||||
},
|
||||
"applicationCategoryType": 0,
|
||||
"applicationDrmType": "standard",
|
||||
"attribute": 0,
|
||||
"attribute2": 0,
|
||||
"attribute3": 4194304,
|
||||
"conceptId": "223059",
|
||||
"contentBadgeType": 1,
|
||||
"contentId": "EP0700-PPSA10737_00-LITTLENIGHTMARES",
|
||||
"contentVersion": "01.004.000",
|
||||
"downloadDataSize": 0,
|
||||
"gameIntent": {
|
||||
"permittedIntents": [
|
||||
{
|
||||
"intentType": "launchActivity"
|
||||
}
|
||||
]
|
||||
},
|
||||
"localizedParameters": {
|
||||
"de-DE": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"defaultLanguage": "en-US",
|
||||
"en-US": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"es-ES": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"fr-FR": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"it-IT": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"pl-PL": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"ru-RU": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"sv-SE": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
}
|
||||
},
|
||||
"masterVersion": "01.00",
|
||||
"originContentVersion": "01.000.000",
|
||||
"pubtools": {
|
||||
"creationDate": "2025-11-24 11:19:04",
|
||||
"submission": true,
|
||||
"toolVersion": "3.13"
|
||||
},
|
||||
"requiredSystemSoftwareVersion": "0x1240000000000000",
|
||||
"sdkVersion": "0x0900000000000000",
|
||||
"targetContentVersion": "01.003.000",
|
||||
"titleId": "PPSA10737",
|
||||
"userDefinedParam1": 0,
|
||||
"versionFileUri": "https://sgst.prod.dl.playstation.net/sgst/prod/00/np/PPSA10737_00/f530dd33-21e0-48c9-8816-878774f65d8d-version.xml "
|
||||
}
|
||||
{
|
||||
"addcont": {
|
||||
"serviceIdForSharing": [
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" "
|
||||
]
|
||||
},
|
||||
"ageLevel": {
|
||||
"AE": 16,
|
||||
"AR": 13,
|
||||
"AT": 16,
|
||||
"AU": 15,
|
||||
"BE": 16,
|
||||
"BG": 16,
|
||||
"BH": 16,
|
||||
"BO": 13,
|
||||
"BR": 14,
|
||||
"CA": 13,
|
||||
"CH": 16,
|
||||
"CL": 13,
|
||||
"CO": 13,
|
||||
"CR": 13,
|
||||
"CY": 16,
|
||||
"CZ": 16,
|
||||
"DE": 12,
|
||||
"DK": 16,
|
||||
"EC": 13,
|
||||
"ES": 16,
|
||||
"FI": 16,
|
||||
"FR": 16,
|
||||
"GB": 16,
|
||||
"GR": 16,
|
||||
"GT": 13,
|
||||
"HN": 13,
|
||||
"HR": 16,
|
||||
"HU": 16,
|
||||
"IE": 16,
|
||||
"IL": 16,
|
||||
"IN": 16,
|
||||
"IS": 16,
|
||||
"IT": 16,
|
||||
"JP": 15,
|
||||
"KR": 15,
|
||||
"KW": 16,
|
||||
"LB": 16,
|
||||
"LU": 16,
|
||||
"MT": 16,
|
||||
"MX": 13,
|
||||
"NI": 13,
|
||||
"NL": 16,
|
||||
"NO": 16,
|
||||
"NZ": 15,
|
||||
"OM": 16,
|
||||
"PA": 13,
|
||||
"PE": 13,
|
||||
"PL": 16,
|
||||
"PT": 16,
|
||||
"PY": 13,
|
||||
"QA": 16,
|
||||
"RO": 16,
|
||||
"RU": 16,
|
||||
"SA": 16,
|
||||
"SE": 16,
|
||||
"SI": 16,
|
||||
"SK": 16,
|
||||
"SV": 13,
|
||||
"TR": 16,
|
||||
"TW": 15,
|
||||
"UA": 16,
|
||||
"US": 13,
|
||||
"UY": 13,
|
||||
"ZA": 16,
|
||||
"default": 16
|
||||
},
|
||||
"applicationCategoryType": 0,
|
||||
"applicationDrmType": "standard",
|
||||
"attribute": 0,
|
||||
"attribute2": 0,
|
||||
"attribute3": 4194304,
|
||||
"conceptId": "223059",
|
||||
"contentBadgeType": 1,
|
||||
"contentId": "EP0700-PPSA10737_00-LITTLENIGHTMARES",
|
||||
"contentVersion": "01.004.000",
|
||||
"downloadDataSize": 0,
|
||||
"gameIntent": {
|
||||
"permittedIntents": [
|
||||
{
|
||||
"intentType": "launchActivity"
|
||||
}
|
||||
]
|
||||
},
|
||||
"localizedParameters": {
|
||||
"de-DE": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"defaultLanguage": "en-US",
|
||||
"en-US": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"es-ES": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"fr-FR": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"it-IT": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"pl-PL": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"ru-RU": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
},
|
||||
"sv-SE": {
|
||||
"titleName": "Little Nightmares Enhanced Edition"
|
||||
}
|
||||
},
|
||||
"masterVersion": "01.00",
|
||||
"originContentVersion": "01.000.000",
|
||||
"pubtools": {
|
||||
"creationDate": "2025-11-24 11:19:04",
|
||||
"submission": true,
|
||||
"toolVersion": "3.13"
|
||||
},
|
||||
"requiredSystemSoftwareVersion": "0x1240000000000000",
|
||||
"sdkVersion": "0x0900000000000000",
|
||||
"targetContentVersion": "01.003.000",
|
||||
"titleId": "PPSA10737",
|
||||
"userDefinedParam1": 0,
|
||||
"versionFileUri": "https://sgst.prod.dl.playstation.net/sgst/prod/00/np/PPSA10737_00/f530dd33-21e0-48c9-8816-878774f65d8d-version.xml "
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
"""FTP-stage + self-update + probe + run a trophy command on the PS5 suite."""
|
||||
import socket, ftplib, sys, time, struct
|
||||
|
||||
IP = "192.168.0.53"
|
||||
DIR = "/mnt/c/Users/HACKMAN/Desktop/ps5 test/my_projects/ps5_upload_suite/payload"
|
||||
ELF = f"{DIR}/ps5_suite_server.elf"
|
||||
|
||||
CMD_SELF_UPDATE = 0x68
|
||||
CMD_TROPHY_UNLOCK = 0x82
|
||||
CMD_PING = 0x01
|
||||
|
||||
def rpc(cmd, payload=b"", timeout=20, port=None):
|
||||
for p in ([port] if port else range(9113, 9145)):
|
||||
try:
|
||||
s = socket.create_connection((IP, p), timeout=4)
|
||||
s.settimeout(timeout)
|
||||
s.sendall(bytes([cmd]) + struct.pack("<I", len(payload)) + payload)
|
||||
hdr = s.recv(5)
|
||||
if len(hdr) < 5:
|
||||
s.close(); continue
|
||||
ln = struct.unpack("<I", hdr[1:5])[0]
|
||||
data = b""
|
||||
while len(data) < ln:
|
||||
c = s.recv(min(65536, ln - len(data)))
|
||||
if not c: break
|
||||
data += c
|
||||
s.close()
|
||||
return p, hdr[0], data
|
||||
except OSError:
|
||||
continue
|
||||
return None, None, b""
|
||||
|
||||
def find_server():
|
||||
for p in range(9113, 9145):
|
||||
try:
|
||||
s = socket.create_connection((IP, p), timeout=2)
|
||||
s.settimeout(4)
|
||||
s.sendall(bytes([CMD_PING]) + struct.pack("<I", 0))
|
||||
hdr = s.recv(5)
|
||||
if len(hdr) == 5:
|
||||
ln = struct.unpack("<I", hdr[1:5])[0]
|
||||
data = s.recv(min(ln, 512)) if ln else b""
|
||||
s.close()
|
||||
return p, data
|
||||
s.close()
|
||||
except OSError:
|
||||
continue
|
||||
return None, b""
|
||||
|
||||
def ftp_put(local, remote):
|
||||
ftp = ftplib.FTP()
|
||||
ftp.connect(IP, 1337, timeout=15)
|
||||
try:
|
||||
ftp.login('anonymous', 'anonymous')
|
||||
except Exception:
|
||||
ftp.login('', '')
|
||||
with open(local, 'rb') as f:
|
||||
ftp.storbinary(f"STOR {remote}", f)
|
||||
ftp.quit()
|
||||
|
||||
if __name__ == "__main__":
|
||||
op = sys.argv[1] if len(sys.argv) > 1 else "full"
|
||||
|
||||
if op in ("full", "deploy"):
|
||||
print("[1] ftp stage...")
|
||||
ftp_put(ELF, "/data/ps5suite/update.elf")
|
||||
print(" staged")
|
||||
print("[2] self-update cmd...")
|
||||
port, typ, d = rpc(CMD_SELF_UPDATE, b"/data/ps5suite/update.elf", timeout=30)
|
||||
print(" ->", port, hex(typ or 0), d[:200])
|
||||
if op == "deploy":
|
||||
sys.exit(0)
|
||||
print("[3] wait for new server...")
|
||||
time.sleep(5)
|
||||
|
||||
if op in ("full", "probe"):
|
||||
for i in range(6):
|
||||
p, d = find_server()
|
||||
if p:
|
||||
print(" ALIVE on", p, "->", d[:80])
|
||||
SRV = p
|
||||
break
|
||||
time.sleep(4)
|
||||
else:
|
||||
print(" NO SERVER"); sys.exit(1)
|
||||
|
||||
if op == "full" and len(sys.argv) > 2:
|
||||
arg = sys.argv[2].encode()
|
||||
p, typ, d = rpc(CMD_TROPHY_UNLOCK, arg, timeout=90, port=SRV)
|
||||
print("[cmd]", arg.decode(), "->", hex(typ or 0), d[:1500])
|
||||
elif op == "cmd":
|
||||
p, _ = find_server()
|
||||
arg = " ".join(sys.argv[2:]).encode()
|
||||
p, typ, d = rpc(CMD_TROPHY_UNLOCK, arg, timeout=90, port=p)
|
||||
print("->", hex(typ or 0), d[:1500])
|
||||
@@ -1414,7 +1414,7 @@ static int handle_fan_set_threshold(int sock, int temp_c) {
|
||||
// 2. Try AppInstallTitleDir first (handles duplicates internally)
|
||||
// 3. Fallback to AppInstallAll for FW 12.00+
|
||||
// Note: v7.2.4 removed pre-mount Initialize+UnInstall calls — they caused
|
||||
// home screen refresh. the mount bridge doesn't use them either.
|
||||
// home screen refresh and aren't needed.
|
||||
|
||||
// install_app - dump_installer style registration
|
||||
// Returns 0 on success, negative on failure
|
||||
@@ -3520,7 +3520,7 @@ static int process_game(const char* game_path, char* game_name_out, size_t name_
|
||||
// v7.2.4: Removed pre-mount Initialize + UnInstall calls.
|
||||
// These daemon IPC calls triggered ShellCore to refresh the home screen,
|
||||
// causing visible flicker even when mounting a single game.
|
||||
// the mount bridge doesn't use them — AppInstallTitleDir handles duplicates
|
||||
// They're unnecessary — AppInstallTitleDir handles duplicates
|
||||
// internally, and our direct SQLite path already DELETEs before INSERT.
|
||||
// The old calls were:
|
||||
// sceAppInstUtilInitialize()
|
||||
|
||||
Reference in new issue
Block a user