Cloud catalog & streaming fixes#16
Conversation
…ary + ownership (Qt/iOS/Android) Reworks PlayStation Plus Cloud Play end to end so it works in English-only regions (e.g. Hungary), streams owned PS4 and PS5 titles correctly, shows cross-gen editions, and classifies ownership (full game vs trial vs add-on). Applied across the Qt (C++/QML), iOS (Swift) and Android (Kotlin) clients. Catalog / region - Store-locale fallback chain (lang-COUNTRY -> en-COUNTRY -> en-US) so the imagic catalog loads in every region; the validated locale persists. - Accept PS4 (not just PS5) cloud titles in the merge; capture streamingSupported=false subscription titles into the library-stream supplement from every subscription list (these stream via the legacy Kamaji/kratos path even though they are absent from public cloud browse). - Scope the views: Game Catalog = PS Plus subscription lists (plusCatalog tag); Library "all" = full streamable universe + owned; Library "owned" = owned. - Catalog falls back to the imagic catalog when the legacy PS Now /user/stores browse 404s (it does in many regions). - Dedupe per game per platform so cross-gen PS4/PS5 editions both appear. - Broaden the owned-games filter; match owned entitlements by conceptId in addition to product id / stable key. Owned-title streaming (entitlement resolution) - PS5 streams the owned PRODUCT id, not the entitlement id: a cross-gen upgrade (PS4 purchase + free PS5 copy) carries a stale original-SKU entitlement id that Gaikai's cloud catalog has no game for (-> noGameForEntitlementId); product_id is the current streamable SKU. (Fixed Alan Wake Remastered, Death Stranding DC.) - When several SKUs collapse to one edition (base game + bonus/upgrade/avatars), keep the canonical full-game entitlement -- the one whose entitlement id EQUALS its product_id. Package/feature flags don't disambiguate (Death Stranding DC's "Bonus Content" is also PSGD + feature_type 3), so the id==product_id signal is what selects the real game over a DLC product Gaikai can't stream. - PS4 streams the catalog's streamable variant (e.g. God of War's "...N" SKU whose Kamaji container holds the PS-Now license_type=4 SKU), not the owned download SKU; derive the streaming platform from the owned product (cross-gen catalog entries list the other generation). PS4 (CUSA) -> Kamaji/psnow; PS5 (PPSA) -> direct Gaikai (cronos). Datacenter ping no longer hard-fails on a measurement error (Qt). Ownership classification (feature_type) - feature_type 3/5 = full game owned, 1 = trial / free-to-play, 0 = add-on/DLC. - Drop feature_type==0 extras from the owned set (DLC/themes/avatars are never a base game). Keep trials and free-to-play; a trial is kept as its own card so the full version still shows separately as "Add Game" (a trial does not collapse into the full-game catalog entry). Cross-gen owned-library split - Key owned-edition identity on conceptId + PLATFORM (matching the catalog tab) in both the owned cross-reference dedupe and the library merge, so a title owned on PS4 and PS5 (e.g. Days Gone + Days Gone Remastered) shows two separate, independently-streamable cards. Platform labels - Derive PS4/PS5 from the title id (CUSA/PPSA) instead of the hard-coded platform="ps5" -- Android at display time (CloudGameAdapter), iOS in the parser/deserializer (self-correcting the cache); Qt already did. Catalog ownership UX - Cross-reference the catalog against owned entitlements (mark-only): owned -> "Stream", non-owned modern cloud titles -> "Add Game"; OWNED / NOT OWNED badge. Build - Remove the committed machine-specific org.gradle.java.home (an absolute Windows path that broke every non-Windows / CI Gradle build); document selecting the JDK 21 daemon per-machine via JAVA_HOME / ~/.gradle / the IDE Gradle JDK setting. Verified - Qt/macOS (Hungary / PS Plus Premium): catalog loads region-wide; owned PS4 (God of War) and PS5 (Alan Wake Remastered, Death Stranding DC) stream from Library and Catalog; cross-gen Days Gone shows + streams both editions; a trial (Cyberpunk) shows its own Stream card plus an "Add Game" card for the full version; adding the PS5 Remaster lets Spider-Man stream; labels and OWNED/NOT OWNED badges correct. - iOS: swiftc -parse clean. Android: compiles (compileDebugKotlin). Mobile not device-re-tested for the latest streaming/ownership pass. Upstream reconciliation (PR ForWard-Technologies-LLC#15) - Sits on top of the merged "PS5 cloud ownership matching" PR (ForWard-Technologies-LLC#15) and incorporates its useful additions: bundle-sibling expansion (a bundle entitlement, e.g. RE7 Gold, expands to its component games via componentIdsByProductId) and stable-key matching on the entitlement id. These are grafted onto our cross-reference as additive fallbacks (they only fire when our direct cascade finds no match), keeping our dedupe (conceptId+platform + canonical-entitlement rank), feature_type filtering and field convention where the two approaches differed. Known limitations - Some PS Plus titles are download-only (no cloud-streaming SKU, e.g. Far Cry 5, original Spider-Man PS4): indistinguishable in the catalog from streamable PS4 titles, so they appear but fail at sessions/start with noGameForEntitlementId. - PS5 catalog-only titles must be added to the library externally (PS App) first. - PS3 titles absent from the modern imagic API; PS5 HEVC video-decode freeze is a separate pipeline issue. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PS Plus Premium streams ~250-330 PS3 Classics that never appear in the
imagic/gameslist catalog the rest of cloud play uses. Source them from the
public pcnow ("Apollo") container API and stream them via the existing
Gaikai konan path.
- Catalog: new fetchPs3Catalog walks the public Apollo PS3 container (no auth),
paginated; surfaced in the Game Catalog and Library "all" views (not "owned").
PS3 cards always show "Stream Game".
- Region-generic: pcnow has two Classics id families -- Americas/SCEA
(store MSF192018, UP/NPUA/BLUS ids, child APOLLOPS3GAMES) and PAL/SCEE
(store MSF192014, EP/NPEA/NPEB/BLES ids, child APOLLOPS3). The account
region group selects the store; everything outside the Americas -> PAL.
- Streaming: for legacy (non-CUSA/PPSA) ids, resolve product->entitlement in
the region-group store, and skip the regional checkout/acquire on a 404
(Premium auto-authorizes at Gaikai; the checkout is unavailable in regions
without a pcnow storefront, e.g. Hungary).
- PS4 (CUSA) / PS5 (PPSA) paths unchanged.
Ported across macOS (Qt), iOS (Swift), Android (Kotlin). macOS + Android
verified streaming on a real PS Plus Premium account; iOS compile-verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Starting a cloud stream locks the activity to landscape via
requestedOrientation. On large tablets, portrait<->landscape also changes
screenLayout/smallestScreenSize, which MainActivity didn't declare in
configChanges -- so Android recreated the activity, detached
CloudPlayFragment, and the in-flight startCloudStreaming coroutine then
crashed on requireActivity() ("Fragment not attached to an activity").
Declare screenLayout|smallestScreenSize so MainActivity handles the rotation
itself instead of being recreated, keeping the fragment attached.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PS Plus disc-upgrade entitlements (feature_type 5, e.g. Horizon Forbidden
West EP9000-PPSA01521) are the SKU the imagic browse catalog binds the
concept to, but Gaikai refuses to cloud-stream them
("disc-upgrade-unsupported"). The owned streamable edition (e.g. the
Complete Edition PPSA17903) is a different title id that is absent from the
catalog and -- like every commerce-API entitlement -- carries no conceptId,
so the owned cross-reference never matches it and only the unstreamable
disc-upgrade SKU survives the dedupe.
Add a disc-upgrade rescue to the owned cross-reference on all platforms
(Qt/iOS/Android): when a concept's surviving owned SKU is a disc upgrade,
adopt the product id of a same-name full-game (feature_type 3) owned SKU so
the card streams the edition Gaikai accepts. Since the only in-data bridge
is the title name, it is guarded to stay safe: same platform only (a PS5
disc upgrade can never resolve to a PS4 CUSA SKU), prefer the canonical base
game (product_id == entitlement id), and bail on genuine ambiguity rather
than guess.
Verified on macOS: Horizon Forbidden West now streams PPSA17903 instead of
the rejected PPSA01521.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…cards The "all" library view merges owned entitlements into the browse catalog. For PS5 (PPSA) the override of the catalog card's product id was guarded (if (!existing.product_id)), so it applied only when the catalog card had no id. When the browse row carries a product id -- e.g. Horizon Forbidden West's concept is bound to the disc-upgrade SKU PPSA01521 -- the guard kept that unstreamable id even though the cross-reference had rescued the owned full game (PPSA17903), so Gaikai rejected it with "disc-upgrade-unsupported". Override unconditionally for PS5, matching the iOS and Android merges (which always copy the owned storeProductId). The owned PS5 product IS the streamable entitlement, so it must win over the catalog's fixed per-concept SKU. PS4 (CUSA) is unaffected (the whole block is PS5-only). Fixes Horizon Forbidden West failing to stream on the Steam Deck / Linux build while macOS and Android worked -- the guard only happened to pass on those when the catalog cache had a null product id (data-dependent). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ps5CloudPlatformToken() takes a GAME OBJECT (it reads game.productId / game.id),
but the "all"-view merge passed it the product-id STRING. A string has no
.productId/.id/.device, so it always returned "", the `=== "ps5"` test was never
true, and the block that copies the owned product id onto the matched catalog
card never executed -- for any game.
That left the catalog card's own (often unstreamable) SKU in place. For Horizon
Forbidden West the catalog binds the concept to the disc-upgrade SKU PPSA01521,
so the "all" filter streamed that and Gaikai rejected it
("disc-upgrade-unsupported"), while the "owned" filter worked (it uses the
cross-reference output directly, which already carries the rescued PPSA17903).
Pass the game object so the platform check resolves to "ps5" and the owned
product id wins. Pre-existing bug -- the earlier guard/un-guard edits were both
inside this dead block, which is why neither changed anything. iOS/Android were
unaffected (their merges copy storeProductId with no platform-token check).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@nyakaspeter Nice! I appreciate it, I will do some testing on my end with this then see if I can get it merged in here. In your tests, were there any issues you noticed? Any specific games that still didnt load etc? I will focus my testing on that if so. Thanks for the PR :) |
|
Hey, I haven't had time to try all games of course but with the fixes, I haven't run into any games I couldn't stream. Well, apart from the ones that aren't streamable on console either, but I couldn't exclude from the game catalog without hiding some other (streamable) games (Far Cry 5 for example). The biggest challenge as I understand is gathering all of the user's library from various sources and then choosing the correct streamable entitlement. The PlayStation APIs seem a bit all over the place (different APIs for listing PS3/4/5 games and different flows for getting the entitlement registered for the account) and they probably vary by region. Since I couldn't find any documentation for them, I relied on Claude to trial and error all the way through. To get the PS3 games list for my region for example, I had to sniff packets from the PS Plus windows app. It was especially tricky as for some reason the app doesn't work with a Hungarian account so I had to fall back to a UK one. Then I figured all European countries share the same IDs as well as the Americas. Though there are probably exceptions that's why I said regions other than mine may need other fixes. I tried games with various scenarios and all of them seems to stream now:
|
Hi, I downloaded Pylux for the cloud play capabilities, and I was delighted to see it works but while experimenting with it I faced numerous problems regarding the game catalog not loading, missing PS4 games in library etc.
I asked Claude to fix the issues and through a couple of hours of debugging it managed to fix most of them so I can say fairly confidently that with these changes the app shows both the PS Plus Game Catalog titles and my library items correctly and I can stream most of them without errors. My store region is Hungary so that's where I could confirm that the game catalog changes work, other regions may still need work/testing. I built the app for macOS, Android and Linux (Steam Deck) and tested the changes on all 3 platforms.
So I submit this PR as it probably contains some useful findings for further improving the app. Below is the summary of the changes generated by Claude:
Reworks PlayStation Plus Cloud Play end to end so it works in English-only regions (e.g. Hungary), streams owned PS4 and PS5 titles correctly, shows cross-gen editions, classifies ownership (full game vs trial vs add-on), and adds PS3 Classics cloud streaming. Applied across the Qt (C++/QML), iOS (Swift) and Android (Kotlin) clients.
Catalog / region
Owned-title streaming (entitlement resolution)
Ownership classification (feature_type)
Cross-gen owned-library split
Platform labels
Catalog ownership UX
"Stream", non-owned modern cloud titles -> "Add Game"; OWNED / NOT OWNED badge.
PS3 Classics cloud streaming
Android: portrait-mode stream-start crash
Build
Verified
Upstream reconciliation (PR #15)
Known limitations