Skip to content

Commit 9b18a59

Browse files
phantomptrclaude
andcommitted
Collection: per-game actions, select mode, copy checks, firmware and cheats awareness
- Card and row menu: install the newer update / missing DLC the PS5 lacks, Convert, Make it smaller (compressed image), Cheats, Backport (opens the panel in Ready to play), Check copies. - Cards show Cheats (from the shared session cheat index), play time, and Needs FW x when the game asks for newer firmware than the connected PS5 (engine now keeps min_fw per item; IDENTIFY_VERSION 5 re-reads items once). - Filters: Has cheats, Could be smaller (with "Queue them in Convert"), Needs newer firmware; sort: Recently played. - Select mode with a batch bar: send to one or more PS5s (each gets only what it lacks; an unread console still goes through the install queue's erase guard), queue in Convert, check copies. Convert accepts several sources via location state. - Copy checks: /api/collection/check runs one at a time in the background. PS5 debug pkgs are verified against their digests (now cancellable), archives decode every entry with its checksum (archive_extract::test), folders and images read every file back, anything else is read start to end. Only Collection paths are accepted. Game page shows progress and results. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JoFXdUvVCDAG8xRjtp52qt
1 parent c1a94c0 commit 9b18a59

46 files changed

Lines changed: 3690 additions & 127 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CHANGELOG.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ What's new in ps5upload, written for humans.
1111
then an archive) and opens Convert with it filled in.
1212
- **Cheats from the game page.** When a game has no cheats on the PS5 yet, its Cheats tab now
1313
has a button that opens Cheats with that game already selected, ready to download.
14+
- **More from each game in Collection.** The ⋯ menu on a game now also installs a newer update
15+
or missing DLC the PS5 lacks, opens its cheats, backports it when it is installed, and
16+
checks its copies. Cards show when the cheat repositories have cheats for a game, how long it
17+
has been played, and when it asks for newer firmware than the PS5 has.
18+
- **Select several games.** Select in Collection picks games, then sends them to one or more
19+
PS5s at once (each gets only what it lacks), queues them in Convert, or checks their copies.
20+
- **Check a copy.** A game's page can check any copy end to end: a debug package against its own
21+
digests, an archive's checksums, every file of a folder or image. It finds a copy that is
22+
damaged or cut short before you send it.
23+
- **Save space.** The new "Could be smaller" filter lists big PS5 game folders and plain images,
24+
and queues them all in Convert as compressed images (.ffpfsc).
25+
- New filters and sort: Has cheats, Needs newer firmware, and Recently played.
1426

1527
## 7.2.0
1628

‎client/src/api/collection.ts‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,35 @@ export interface CollectionPkg {
4747
kind_confident?: boolean;
4848
kind_reason?: string;
4949
complete?: boolean;
50+
/** The firmware the copy asks for ("7.00"). A PS4 copy names a PS4 firmware. */
51+
min_fw?: string;
5052
error?: string;
5153
}
5254

55+
/** One problem a copy check found: a file inside the copy, or "" for the copy as a whole. */
56+
export interface CopyProblem {
57+
file: string;
58+
error: string;
59+
}
60+
61+
/** A copy check (`/api/collection/check`). `method` says how far it could look: `package`
62+
* (verified against its own digests), `archive` (every entry's checksum), `files` (every file
63+
* read back) or `bytes` (read start to end: finds a cut-short or unreadable copy only). */
64+
export interface CopyCheck {
65+
path: string;
66+
state: "queued" | "running" | "ok" | "problems" | "failed" | "cancelled";
67+
method: "" | "package" | "archive" | "files" | "bytes";
68+
bytes_done: number;
69+
bytes_total: number;
70+
files_done: number;
71+
files_total: number;
72+
problems: CopyProblem[];
73+
problems_total: number;
74+
error: string | null;
75+
started_ms: number;
76+
finished_ms: number;
77+
}
78+
5379
export interface CollectionLocation {
5480
root: string;
5581
container: string;
@@ -361,6 +387,17 @@ export const collection = {
361387
method: "POST",
362388
body: JSON.stringify({ volume, action }),
363389
}),
390+
checks: () => call<{ checks: CopyCheck[] }>("/check"),
391+
check: (paths: string[]) =>
392+
call<{ checks: CopyCheck[] }>("/check", {
393+
method: "POST",
394+
body: JSON.stringify({ paths }),
395+
}),
396+
checkCancel: (path?: string) =>
397+
call<{ checks: CopyCheck[] }>("/check/cancel", {
398+
method: "POST",
399+
body: JSON.stringify({ path: path ?? null }),
400+
}),
364401
/** `version` (see coverVersion) makes a cover read again once its game changed. */
365402
coverUrl: (gameId: string, version?: string) =>
366403
`${getEngineUrl()}/api/collection/games/${encodeURIComponent(gameId)}/cover${

‎client/src/i18n/locales/ar.ts‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5215,6 +5215,63 @@ library_compressed_hint: "تحتاج الصور المضغوطة إلى ShadowMo
52155215
"disk_usage_skipped": "لم يُحتسب {count} مجلد: تعذرت قراءتها، أو تخص النظام، أو موجودة على محرك آخر.",
52165216
captures_sort_newest: "التاريخ: الأحدث أولاً",
52175217
captures_sort_oldest: "التاريخ: الأقدم أولاً",
5218+
"collection.backport": "Backport…",
5219+
"collection.backport_hint": "تتطلب البرنامج الثابت {need} وهذه الـPS5 على {have}. قد يتيح الـBackport تشغيلها.",
5220+
"collection.cheats": "Cheats…",
5221+
"collection.cheats_hint": "مستودعات الـCheats فيها Cheats لهذه اللعبة.",
5222+
"collection.cheats_tag": "Cheats",
5223+
"collection.check_copies": "فحص نسخها الـ{n}",
5224+
"collection.check_copy": "فحص النسخة",
5225+
"collection.check_hint": "يقرأ كل نسخة كاملة للعثور على النسخة التالفة أو المقطوعة. يعمل على هذا الكمبيوتر، نسخة واحدة في كل مرة.",
5226+
"collection.check_many": "جارٍ فحص {n} نسخ",
5227+
"collection.check_many_body": "واحدة تلو الأخرى، على هذا الكمبيوتر. صفحة كل لعبة تعرض ما تم العثور عليه.",
5228+
"collection.check_many_go": "فحص النسخ",
5229+
"collection.check_started": "جارٍ فحص {title}",
5230+
"collection.col.played": "آخر لعب",
5231+
"collection.console_firmware": "تحتاج برنامجًا ثابتًا أحدث",
5232+
"collection.convert_many": "Convert",
5233+
"collection.copy_fw": "FW {fw}+",
5234+
"collection.filter.cheats": "فيها Cheats",
5235+
"collection.filter.smaller": "يمكن أن تكون أصغر",
5236+
"collection.fw_badge": "تحتاج FW {need}",
5237+
"collection.fw_hint": "تتطلب البرنامج الثابت {need}؛ وهذه الـPS5 على {have}. قد لا تعمل ما لم يُجرَ لها Backport.",
5238+
"collection.played_hint": "الوقت الذي رأى فيه هذا التطبيق اللعبة تُلعب على هذه الـPS5",
5239+
"collection.select": "تحديد",
5240+
"collection.select_all": "تحديد الكل ({n})",
5241+
"collection.select_done": "تم",
5242+
"collection.select_none": "إلغاء التحديد",
5243+
"collection.selected_n": "{n} محددة",
5244+
"collection.send_many": "إرسال إلى PS5…",
5245+
"collection.send_many_body": "تحصل كل PS5 على ما ينقصها: حزمة اللعبة، أو مجلدها أو صورتها أو أرشيفها، إضافةً إلى أحدث التحديثات وDLC للألعاب الموجودة لديها. تُبث الحزم من هذا الكمبيوتر؛ ويُرفع الباقي إلى القرص المحدد في Upload، داخل مجلد homebrew.",
5246+
"collection.send_many_go": "إرسال إلى {n} PS5",
5247+
"collection.send_many_none": "لم يتم إعداد أي PS5 بعد. أضف واحدة في الاتصالات أولًا.",
5248+
"collection.send_many_title": "إرسال {n} ألعاب",
5249+
"collection.sent_installs": "{n} للتثبيت",
5250+
"collection.sent_nothing": "{n} لا شيء لإرساله",
5251+
"collection.sent_title": "تم الإرسال إلى {name}",
5252+
"collection.sent_unread": "تعذّرت قراءة هذه الـPS5، لذا أُضيفت إلى الطابور أيضًا ألعاب قد تكون موجودة لديها؛ ويُرفض أي تثبيت سيستبدل لعبة موجودة.",
5253+
"collection.sent_uploads": "{n} للرفع",
5254+
"collection.sent_uptodate": "{n} موجودة بالفعل",
5255+
"collection.shrink": "تصغيرها…",
5256+
"collection.shrink_hint": "افتحها في Convert مع تحديد صورة لعبة مضغوطة (.ffpfsc). مقدار المساحة الموفَّرة يعتمد على اللعبة.",
5257+
"collection.smaller_banner": "{n} من ألعاب PS5 محفوظة كمجلد أو كصورة غير مضغوطة. كصورة مضغوطة (.ffpfsc) تشغل مساحة أقل هنا وعلى الـPS5؛ والمقدار يعتمد على اللعبة.",
5258+
"collection.smaller_go": "أضفها إلى طابور Convert",
5259+
"collection.sort.played_desc": "الأحدث لعبًا",
5260+
"copycheck.again": "فحصها مرة أخرى",
5261+
"copycheck.all": "فحص كل النسخ",
5262+
"copycheck.cancelled": "توقف الفحص.",
5263+
"copycheck.failed": "تعذّر الفحص: {why}",
5264+
"copycheck.go": "فحص هذه النسخة",
5265+
"copycheck.how_archive": "فُحص المجموع الاختباري لكل ملف",
5266+
"copycheck.how_bytes": "قُرئت من البداية إلى النهاية (تكشف النسخة المقطوعة أو غير المقروءة، لا التي فيها بايتات خاطئة)",
5267+
"copycheck.how_files": "قُرئ كل ملف مرة أخرى",
5268+
"copycheck.how_package": "تم التحقق منها مقابل digests الخاصة بها",
5269+
"copycheck.more": "و{n} أخرى",
5270+
"copycheck.ok": "تم الفحص، لا مشاكل: {how}.",
5271+
"copycheck.problems": "عُثر على {n} مشكلة ({how}). قد لا تُثبَّت هذه النسخة أو لا تعمل؛ استبدلها بنسخة من مصدر سليم.",
5272+
"copycheck.queued": "بانتظار الفحص",
5273+
"copycheck.running": "جارٍ الفحص…",
5274+
"copycheck.running_pct": "جارٍ الفحص {pct}% ({done} من {total})",
52185275
};
52195276

52205277
export default ar;

‎client/src/i18n/locales/bn.ts‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5215,6 +5215,63 @@ library_compressed_hint: "সংকুচিত ইমেজ চালাতে
52155215
"disk_usage_skipped": "{count}টি ফোল্ডার গণনা করা হয়নি: সেগুলো পড়া যায়নি, সিস্টেমের, অথবা অন্য ড্রাইভে আছে।",
52165216
captures_sort_newest: "তারিখ: নতুন আগে",
52175217
captures_sort_oldest: "তারিখ: পুরোনো আগে",
5218+
"collection.backport": "Backport…",
5219+
"collection.backport_hint": "এটি ফার্মওয়্যার {need} চায়, আর এই PS5 আছে {have}-এ। Backport করলে এটি চালু হতে পারে।",
5220+
"collection.cheats": "Cheats…",
5221+
"collection.cheats_hint": "Cheat রিপোজিটরিতে এই গেমের জন্য cheat আছে।",
5222+
"collection.cheats_tag": "Cheats",
5223+
"collection.check_copies": "এর {n}টি কপি যাচাই করুন",
5224+
"collection.check_copy": "কপিটি যাচাই করুন",
5225+
"collection.check_hint": "ক্ষতিগ্রস্ত বা অসম্পূর্ণ কপি খুঁজে পেতে প্রতিটি কপি পুরোটা পড়ে দেখা হয়। এই কম্পিউটারে চলে, একবারে একটি কপি।",
5226+
"collection.check_many": "{n}টি কপি যাচাই হচ্ছে",
5227+
"collection.check_many_body": "একটি একটি করে, এই কম্পিউটারে। প্রতিটি গেমের পেজে কী পাওয়া গেছে দেখানো হয়।",
5228+
"collection.check_many_go": "কপি যাচাই করুন",
5229+
"collection.check_started": "{title} যাচাই হচ্ছে",
5230+
"collection.col.played": "খেলা হয়েছে",
5231+
"collection.console_firmware": "নতুন ফার্মওয়্যার লাগবে",
5232+
"collection.convert_many": "Convert",
5233+
"collection.copy_fw": "FW {fw}+",
5234+
"collection.filter.cheats": "Cheat আছে",
5235+
"collection.filter.smaller": "ছোট হতে পারে",
5236+
"collection.fw_badge": "FW {need} লাগবে",
5237+
"collection.fw_hint": "এটি ফার্মওয়্যার {need} চায়; এই PS5 আছে {have}-এ। Backport না করলে এটি চালু নাও হতে পারে।",
5238+
"collection.played_hint": "এই PS5-এ এই অ্যাপ যতক্ষণ গেমটি খেলতে দেখেছে",
5239+
"collection.select": "বাছাই",
5240+
"collection.select_all": "সব {n}টি বাছাই করুন",
5241+
"collection.select_done": "শেষ",
5242+
"collection.select_none": "কোনোটিই নয়",
5243+
"collection.selected_n": "{n}টি বাছাই করা হয়েছে",
5244+
"collection.send_many": "PS5-এ পাঠান…",
5245+
"collection.send_many_body": "প্রতিটি PS5 যা নেই তা পায়: গেমের প্যাকেজ, অথবা এর ফোল্ডার, ইমেজ বা আর্কাইভ, সঙ্গে যে গেমগুলো আছে সেগুলোর নতুন আপডেট ও DLC। প্যাকেজ এই কম্পিউটার থেকে স্ট্রিম হয়; বাকিগুলো Upload-এ ঠিক করা ড্রাইভের homebrew ফোল্ডারে আপলোড হয়।",
5246+
"collection.send_many_go": "{n}টি PS5-এ পাঠান",
5247+
"collection.send_many_none": "এখনও কোনো PS5 সেট আপ করা নেই। আগে সংযোগে একটি যোগ করুন।",
5248+
"collection.send_many_title": "{n}টি গেম পাঠান",
5249+
"collection.sent_installs": "{n}টি ইনস্টল হবে",
5250+
"collection.sent_nothing": "{n}টিতে পাঠানোর কিছু নেই",
5251+
"collection.sent_title": "{name}-এ পাঠানো হয়েছে",
5252+
"collection.sent_unread": "এই PS5 পড়া যায়নি, তাই যে গেমগুলো হয়তো আগেই আছে সেগুলোও সারিতে দেওয়া হয়েছে; কোনোটি প্রতিস্থাপন করবে এমন ইনস্টল প্রত্যাখ্যাত হয়।",
5253+
"collection.sent_uploads": "{n}টি আপলোড হবে",
5254+
"collection.sent_uptodate": "{n}টি আগেই আছে",
5255+
"collection.shrink": "ছোট করুন…",
5256+
"collection.shrink_hint": "সংকুচিত গেম ইমেজ (.ffpfsc) বেছে Convert-এ খুলুন। কতটা জায়গা বাঁচে তা গেমের ওপর নির্ভর করে।",
5257+
"collection.smaller_banner": "{n}টি PS5 গেম ফোল্ডার বা অসংকুচিত ইমেজ হিসেবে রাখা আছে। সংকুচিত ইমেজ (.ffpfsc) হিসেবে এগুলো এখানে ও PS5-এ কম জায়গা নেয়; কতটা তা গেমের ওপর নির্ভর করে।",
5258+
"collection.smaller_go": "Convert-এ সারিতে দিন",
5259+
"collection.sort.played_desc": "সম্প্রতি খেলা",
5260+
"copycheck.again": "আবার যাচাই করুন",
5261+
"copycheck.all": "সব কপি যাচাই করুন",
5262+
"copycheck.cancelled": "যাচাই থেমে গেছে।",
5263+
"copycheck.failed": "যাচাই করা যায়নি: {why}",
5264+
"copycheck.go": "এই কপি যাচাই করুন",
5265+
"copycheck.how_archive": "প্রতিটি ফাইলের চেকসাম যাচাই হয়েছে",
5266+
"copycheck.how_bytes": "শুরু থেকে শেষ পর্যন্ত পড়া হয়েছে (অসম্পূর্ণ বা অপাঠযোগ্য কপি ধরে, ভুল বাইটযুক্ত কপি নয়)",
5267+
"copycheck.how_files": "প্রতিটি ফাইল আবার পড়া হয়েছে",
5268+
"copycheck.how_package": "নিজস্ব digest-এর সঙ্গে মিলিয়ে যাচাই হয়েছে",
5269+
"copycheck.more": "আরও {n}টি",
5270+
"copycheck.ok": "যাচাই হয়েছে, কোনো সমস্যা নেই: {how}।",
5271+
"copycheck.problems": "{n}টি সমস্যা পাওয়া গেছে ({how})। এই কপি ইনস্টল বা চালু নাও হতে পারে; ভালো উৎস থেকে বদলে নিন।",
5272+
"copycheck.queued": "যাচাইয়ের অপেক্ষায়",
5273+
"copycheck.running": "যাচাই হচ্ছে…",
5274+
"copycheck.running_pct": "যাচাই হচ্ছে {pct}% ({done}/{total})",
52185275
};
52195276

52205277
export default bn;

‎client/src/i18n/locales/de.ts‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5223,6 +5223,63 @@ library_compressed_hint: "Komprimierte Images benötigen ShadowMount+ zum Spiele
52235223
"disk_usage_skipped": "{count} Ordner wurden nicht gezählt: Sie ließen sich nicht lesen, gehören zum System oder liegen auf einem anderen Laufwerk.",
52245224
captures_sort_newest: "Datum: Neueste zuerst",
52255225
captures_sort_oldest: "Datum: Älteste zuerst",
5226+
"collection.backport": "Backport…",
5227+
"collection.backport_hint": "Es verlangt Firmware {need}, diese PS5 hat {have}. Ein Backport kann den Start ermöglichen.",
5228+
"collection.cheats": "Cheats…",
5229+
"collection.cheats_hint": "Die Cheat-Repositories haben Cheats für dieses Spiel.",
5230+
"collection.cheats_tag": "Cheats",
5231+
"collection.check_copies": "Seine {n} Kopien prüfen",
5232+
"collection.check_copy": "Kopie prüfen",
5233+
"collection.check_hint": "Jede Kopie wird vollständig zurückgelesen, um beschädigte oder abgeschnittene zu finden. Läuft auf diesem Computer, eine Kopie nach der anderen.",
5234+
"collection.check_many": "{n} Kopien werden geprüft",
5235+
"collection.check_many_body": "Eine nach der anderen, auf diesem Computer. Die Seite jedes Spiels zeigt das Ergebnis.",
5236+
"collection.check_many_go": "Kopien prüfen",
5237+
"collection.check_started": "{title} wird geprüft",
5238+
"collection.col.played": "Gespielt",
5239+
"collection.console_firmware": "Braucht neuere Firmware",
5240+
"collection.convert_many": "Convert",
5241+
"collection.copy_fw": "FW {fw}+",
5242+
"collection.filter.cheats": "Mit Cheats",
5243+
"collection.filter.smaller": "Könnte kleiner sein",
5244+
"collection.fw_badge": "Braucht FW {need}",
5245+
"collection.fw_hint": "Es verlangt Firmware {need}; diese PS5 hat {have}. Es startet eventuell nicht, wenn es nicht per Backport angepasst wird.",
5246+
"collection.played_hint": "Spielzeit, die diese App auf dieser PS5 beobachtet hat",
5247+
"collection.select": "Auswählen",
5248+
"collection.select_all": "Alle {n} auswählen",
5249+
"collection.select_done": "Fertig",
5250+
"collection.select_none": "Keine auswählen",
5251+
"collection.selected_n": "{n} ausgewählt",
5252+
"collection.send_many": "An PS5 senden…",
5253+
"collection.send_many_body": "Jede PS5 bekommt, was ihr fehlt: das Paket des Spiels oder seinen Ordner, sein Image oder Archiv, dazu neuere Updates und DLC für vorhandene Spiele. Pakete werden von diesem Computer gestreamt; der Rest wird auf das in Upload gewählte Laufwerk in den Homebrew-Ordner hochgeladen.",
5254+
"collection.send_many_go": "An {n} PS5 senden",
5255+
"collection.send_many_none": "Noch keine PS5 eingerichtet. Füge zuerst unter Verbindungen eine hinzu.",
5256+
"collection.send_many_title": "{n} Spiele senden",
5257+
"collection.sent_installs": "{n} zu installieren",
5258+
"collection.sent_nothing": "{n} ohne etwas zu senden",
5259+
"collection.sent_title": "Gesendet an {name}",
5260+
"collection.sent_unread": "Diese PS5 konnte nicht gelesen werden, daher wurden auch Spiele eingereiht, die sie evtl. schon hat; eine Installation, die eines ersetzen würde, wird abgelehnt.",
5261+
"collection.sent_uploads": "{n} hochzuladen",
5262+
"collection.sent_uptodate": "{n} schon vorhanden",
5263+
"collection.shrink": "Kleiner machen…",
5264+
"collection.shrink_hint": "In Convert öffnen, eingestellt auf ein komprimiertes Spiel-Image (.ffpfsc). Wie viel Platz das spart, hängt vom Spiel ab.",
5265+
"collection.smaller_banner": "{n} PS5-Spiele liegen als Ordner oder unkomprimiertes Image vor. Als komprimiertes Image (.ffpfsc) brauchen sie weniger Platz hier und auf der PS5; wie viel, hängt vom Spiel ab.",
5266+
"collection.smaller_go": "In Convert einreihen",
5267+
"collection.sort.played_desc": "Zuletzt gespielt",
5268+
"copycheck.again": "Erneut prüfen",
5269+
"copycheck.all": "Alle Kopien prüfen",
5270+
"copycheck.cancelled": "Prüfung gestoppt.",
5271+
"copycheck.failed": "Konnte nicht geprüft werden: {why}",
5272+
"copycheck.go": "Diese Kopie prüfen",
5273+
"copycheck.how_archive": "Prüfsumme jeder Datei geprüft",
5274+
"copycheck.how_bytes": "von Anfang bis Ende gelesen (findet abgeschnittene oder unlesbare Kopien, nicht solche mit falschen Bytes)",
5275+
"copycheck.how_files": "jede Datei zurückgelesen",
5276+
"copycheck.how_package": "anhand der eigenen Digests verifiziert",
5277+
"copycheck.more": "und {n} weitere",
5278+
"copycheck.ok": "Geprüft, keine Probleme: {how}.",
5279+
"copycheck.problems": "{n} Problem(e) gefunden ({how}). Diese Kopie lässt sich evtl. nicht installieren oder spielen; ersetze sie aus einer guten Quelle.",
5280+
"copycheck.queued": "Wartet auf Prüfung",
5281+
"copycheck.running": "Wird geprüft…",
5282+
"copycheck.running_pct": "Prüfung {pct}% ({done} von {total})",
52265283
};
52275284

52285285
export default de;

0 commit comments

Comments
 (0)