Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions client/src-tauri/src/commands/saves_screenshots.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Tauri command wrappers for save data + screenshot listing.
//! Tauri command wrappers for save data + screenshot + video-clip listing.

use ps5upload_core::saves::{list_saves, list_screenshots};
use ps5upload_core::saves::{list_saves, list_screenshots, list_videos};
use serde_json::Value as JsonValue;

#[tauri::command]
Expand All @@ -21,3 +21,12 @@ pub async fn screenshots_list(addr: String) -> Result<JsonValue, String> {
.map(|s| serde_json::to_value(s).unwrap_or(serde_json::json!({})))
.map_err(|e| format!("screenshots: {e}"))
}

#[tauri::command]
pub async fn videos_list(addr: String) -> Result<JsonValue, String> {
tokio::task::spawn_blocking(move || list_videos(&addr))
.await
.map_err(|e| format!("videos task: {e}"))?
.map(|s| serde_json::to_value(s).unwrap_or(serde_json::json!({})))
.map_err(|e| format!("videos: {e}"))
}
1 change: 1 addition & 0 deletions client/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ pub fn run() {
// ── Save data + screenshot listing ──────────────────────
commands::saves_list,
commands::screenshots_list,
commands::videos_list,
commands::screenshot_convert,
// ── Save data .zip backup/restore ───────────────────────
// The Saves screen uses these to wrap a downloaded save
Expand Down
9 changes: 9 additions & 0 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const FirstRunScreen = lazy(() => import("./screens/FirstRun"));
const SavesScreen = lazy(() => import("./screens/Saves"));
const ProcessesScreen = lazy(() => import("./screens/Processes"));
const ScreenshotsScreen = lazy(() => import("./screens/Screenshots"));
const VideosScreen = lazy(() => import("./screens/Videos"));
const StatsScreen = lazy(() => import("./screens/Stats"));
const ShellScreen = lazy(() => import("./screens/Shell"));
const DiskUsageScreen = lazy(() => import("./screens/DiskUsage"));
Expand Down Expand Up @@ -212,6 +213,14 @@ export default function App() {
</Suspense>
}
/>
<Route
path="/videos"
element={
<Suspense fallback={<ScreenLoader />}>
<VideosScreen />
</Suspense>
}
/>
<Route
path="/stats"
element={
Expand Down
9 changes: 9 additions & 0 deletions client/src/api/ps5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1823,6 +1823,15 @@ export async function screenshotsList(addr: string): Promise<ScreenshotList> {
return invoke<ScreenshotList>("screenshots_list", { addr });
}

/** List gameplay video clips from the PS5 (`/user/av_contents/video`,
* `.webm`/`.mp4`). Same `{path,size,mtime}` shape as screenshots so the
* Videos screen reuses the row + generic download path. Video clips
* don't need the `.jxr → PNG` conversion screenshots do — they download
* as-is and play in any modern player. */
export async function videosList(addr: string): Promise<ScreenshotList> {
return invoke<ScreenshotList>("videos_list", { addr });
}

/** Convert a downloaded PS5 screenshot (`.jxr` / JPEG XR — HDR, not
* viewable in normal apps) into an SDR PNG. Decoding + HDR→SDR
* tone-mapping happen in-process in the Rust backend (jxrlib, no external
Expand Down
18 changes: 18 additions & 0 deletions client/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,23 @@ screenshots_no_payload: "Connect to your PS5 first.",
screenshots_select: "Toggle select",
screenshots_select_all: "Select all",
screenshots_title: "Screenshots",
videos_title: "Video clips",
videos_description:
"Gameplay video clips saved on the PS5 (Capture Gallery). Download to your computer, or delete via the File System tab. Clips download as-is — no conversion needed.",
videos_no_payload: "Connect to your PS5 first.",
videos_error: "Couldn't list video clips",
videos_empty: "No clips found — record a gameplay video on the PS5 first.",
videos_select: "Toggle select",
videos_select_all: "Select all",
videos_deselect_all: "Deselect all",
videos_download: "Download",
videos_preview: "Preview",
videos_preview_loading: "Downloading clip…",
videos_dest_pick: "Pick a folder to download into",
videos_bulk_dest: "Pick a folder for {n} clips",
videos_bulk_download: "Download {n}",
videos_bulk_partial:
"Downloaded {ok}; {failed} failed — failed ones stay selected to retry.",
search_export_csv: "Export CSV",
search_export_json: "Export JSON",
search_remove: "Remove saved search",
Expand Down Expand Up @@ -1506,6 +1523,7 @@ upload_dest_will_create: "If the destination folder doesn't exist yet on the PS5
dashboard: "Dashboard",
saves: "Save data",
screenshots: "Screenshots",
videos: "Video clips",
disk_usage: "Disk usage",
payloads: "Payloads",
stats: "Stats",
Expand Down
2 changes: 2 additions & 0 deletions client/src/layout/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
Globe,
Save,
Image as ImageIcon,
Video as VideoIcon,
Settings as SettingsIcon,
Info,
Sun,
Expand Down Expand Up @@ -144,6 +145,7 @@ const items: NavItem[] = [
fallback: "Screenshots",
icon: ImageIcon,
},
{ to: "/videos", key: "videos", fallback: "Video clips", icon: VideoIcon },

// ─ Browse PS5: navigate what's on the console ─
{
Expand Down
Loading