achievements-app/psn-api

Retrieving all user games, including purchases listed on Account Library

TheYuriG opened this issue · 5 comments

Housekeeping job for pending requests.
Requested by eljenso on Feb 15, 2023, here.

Reference: none.

Question: Is this even possible? If possible, does Sony give this information only to the logged user or for any user? I wonder because of privacy reasons.
If they provide this information for external users, then it would be possible to cross reference purchase times with price tags on a website like PSPrices and while that could be a really cool project to make, it would also be very dangerous data to have public.

So as it turns out, it is possible by slightly adjusting the GraphQL URL that @evanshortiss found for PR #134.
You can filter by PS+ games only or all purchases, sort direction asc (first to last purchase) or desc (last to first purchase), offset and limit the request just as with basically any other endpoint.

URL and methods, for reference:

const baseGraphqlURL = 'https://web.np.playstation.com/api/graphql/v1/op';

// This is only here for readability purposes
const decodedGraphqlString =
	baseGraphqlURL +
	'?operationName=getPurchasedGameList&variables={"isActive"=true,"platform"=["ps4","ps5"],"size"=24,"start"=24,"sortBy"="ACTIVE_DATE","sortDirection"="desc","subscriptionService"="NONE"}&extensions={"persistedQuery"={"version"=1,"sha256Hash"="2c045408b0a4d0264bb5a3edfed4efd49fb4749cf8d216be9043768adff905e2"}}';

// This is what actually gets sent out. You can edit the parameters.
const encodedGraphqlString =
	baseGraphqlURL +
	'?operationName=getPurchasedGameList&variables={"isActive"%3Atrue%2C"platform"%3A["ps4"%2C"ps5"]%2C"size"%3A24%2C"start"%3A24%2C"sortBy"%3A"ACTIVE_DATE"%2C"sortDirection"%3A"desc"%2C"subscriptionService"%3A"NONE"}&extensions={"persistedQuery"%3A{"version"%3A1%2C"sha256Hash"%3A"2c045408b0a4d0264bb5a3edfed4efd49fb4749cf8d216be9043768adff905e2"}}';

function decodeString(string) {
	return decodeURI(string.replace(/%2C/g, ',').replace(/%3A/g, '='));
}

function encodeString(string) {
	return encodeURI(string.replace(/,/g, '%2C').replace(/=/g, '%3A'));
}

Just like every other endpoint I've experienced, this is on my Postman collection if you want to fork it and poke around quickly.
Run in Postman
Folder: GraphQL Requests (Only self)

Here is an example of data returned (there is nothing linking this data back to the related user):

{
		"__typename": "GameLibraryTitle",
		"conceptId": null,
		"entitlementId": "UP0700-CUSA10410_00-CODEVEIN00000000",
		"image": {
			"__typename": "Media",
			"url": "https://image.api.playstation.com/gs2-sec/appkgo/prod/CUSA10410_00/2/i_b0afbd729d451429a45edf10e597d7b5af1a5f2a333fde963615e7a62d4d8174/i/icon0.png"
		},
		"isActive": true,
		"isDownloadable": true,
		"isPreOrder": false,
		"name": "CODE VEIN",
		"platform": "PS4",
		"productId": "UP0700-CUSA10410_00-CODEVEIN00000000",
		"subscriptionService": "PS_PLUS",
		"titleId": "CUSA10410_00"
	},
	{
		"__typename": "GameLibraryTitle",
		"conceptId": null,
		"entitlementId": "UP4433-CUSA18779_00-DUNGEONSPS400000",
		"image": {
			"__typename": "Media",
			"url": "https://image.api.playstation.com/gs2-sec/appkgo/prod/CUSA18779_00/4/i_c7b0467e8d83d7fa53d63d40a50e65e5da0edc39e07306e356cf5a6f2aba1977/i/icon0.png"
		},
		"isActive": true,
		"isDownloadable": true,
		"isPreOrder": false,
		"name": "Minecraft Dungeons",
		"platform": "PS4",
		"productId": "UP4433-CUSA18779_00-DUNGEONSPS400000",
		"subscriptionService": "PS_PLUS",
		"titleId": "CUSA18779_00"
	},
	{
		"__typename": "GameLibraryTitle",
		"conceptId": null,
		"entitlementId": "UP0006-CUSA23249_00-KINGSTONGAME0000",
		"image": {
			"__typename": "Media",
			"url": "https://image.api.playstation.com/gs2-sec/appkgo/prod/CUSA23249_00/1/i_44ffa732014f55366235e530a14a191f31fbfb075c58dc12f548ff4dbed6fae2/i/icon0_01.png"
		},
		"isActive": true,
		"isDownloadable": true,
		"isPreOrder": false,
		"name": "Battlefield™ 2042",
		"platform": "PS4",
		"productId": "UP0006-PPSA01464_00-KINGSTONGAME0000",
		"subscriptionService": "PS_PLUS",
		"titleId": "CUSA23249_00"
	},
	{
		"__typename": "GameLibraryTitle",
		"conceptId": null,
		"entitlementId": "UP0006-PPSA01464_00-KINGSTONGAME0000",
		"image": {
			"__typename": "Media",
			"url": "https://image.api.playstation.com/sgst/prod/00/PPSA01464_00/app/info/51/fi_e3679eacf91d9ea7ae8b54601a80229aaf3a726f7b6dc42e6b36b6b4d5e1ed8b/icon0.png"
		},
		"isActive": true,
		"isDownloadable": true,
		"isPreOrder": false,
		"name": "Battlefield™ 2042",
		"platform": "PS5",
		"productId": "UP0006-PPSA01464_00-KINGSTONGAME0000",
		"subscriptionService": "PS_PLUS",
		"titleId": "PPSA01464_00"
	},
	{
		"__typename": "GameLibraryTitle",
		"conceptId": null,
		"entitlementId": "UP0102-CUSA18254_00-GAAT12FULLGAME00",
		"image": {
			"__typename": "Media",
			"url": "https://image.api.playstation.com/gs2-sec/appkgo/prod/CUSA18254_00/3/i_af32cf9c508e36d6fc66a1d2352f191eac4efbd92d9f01df96e36d7f5fda7019/i/icon0.png"
		},
		"isActive": true,
		"isDownloadable": true,
		"isPreOrder": false,
		"name": "The Great Ace Attorney Chronicles",
		"platform": "PS4",
		"productId": "UP0102-CUSA18254_00-GAAT12FULLGAME00",
		"subscriptionService": "NONE",
		"titleId": "CUSA18254_00"
	},
	{
		"__typename": "GameLibraryTitle",
		"conceptId": null,
		"entitlementId": "UP3763-CUSA30889_00-ROAD96GEN8GAME00",
		"image": {
			"__typename": "Media",
			"url": "https://image.api.playstation.com/gs2-sec/appkgo/prod/CUSA30889_00/5/i_ece92c574116652da3c701d92fce92d8387727a042057722619f6c1e6a17ad68/i/icon0.png"
		},
		"isActive": true,
		"isDownloadable": true,
		"isPreOrder": false,
		"name": "Road 96",
		"platform": "PS4",
		"productId": "UP3763-PPSA05593_00-ROAD96GEN9GAME00",
		"subscriptionService": "NONE",
		"titleId": "CUSA30889_00"
	},
	{
		"__typename": "GameLibraryTitle",
		"conceptId": null,
		"entitlementId": "UP3763-PPSA05593_00-ROAD96GEN9GAME00",
		"image": {
			"__typename": "Media",
			"url": "https://image.api.playstation.com/sgst/prod/00/PPSA05593_00/app/info/5/f_99168d0b7f7c4a984c2d613a0d7a70310ceb5f1aa479983d994acd17bcd35d81/icon0.png"
		},
		"isActive": true,
		"isDownloadable": true,
		"isPreOrder": false,
		"name": "Road 96",
		"platform": "PS5",
		"productId": "UP3763-PPSA05593_00-ROAD96GEN9GAME00",
		"subscriptionService": "NONE",
		"titleId": "PPSA05593_00"
	},
	{
		"__typename": "GameLibraryTitle",
		"conceptId": null,
		"entitlementId": "UP2764-CUSA19611_00-WARSAWGAME000000",
		"image": {
			"__typename": "Media",
			"url": "https://image.api.playstation.com/gs2-sec/appkgo/prod/CUSA19611_00/3/i_c70763b175e11b949297b29b2c16eaca6236dc16ce1266145b21d2baaf16114e/i/icon0.png"
		},
		"isActive": true,
		"isDownloadable": true,
		"isPreOrder": false,
		"name": "Warsaw",
		"platform": "PS4",
		"productId": "UP2764-CUSA19611_00-WARSAWGAME000000",
		"subscriptionService": "NONE",
		"titleId": "CUSA19611_00"
	},
	{
		"__typename": "GameLibraryTitle",
		"conceptId": null,
		"entitlementId": "UP7389-PPSA13853_00-0582097360101182",
		"image": {
			"__typename": "Media",
			"url": "https://image.api.playstation.com/sgst/prod/00/PPSA13853_00/app/info/21/fi_8f987e75c708f166e7b2fb58b5a8afd1e3a47fcd2da11395d6ed2684564ae827/icon0.png"
		},
		"isActive": true,
		"isDownloadable": true,
		"isPreOrder": false,
		"name": "Kayak VR: Mirage",
		"platform": "PS5",
		"productId": "UP7389-PPSA13853_00-0582097360101182",
		"subscriptionService": "NONE",
		"titleId": "PPSA13853_00"
	},
	{
		"__typename": "GameLibraryTitle",
		"conceptId": null,
		"entitlementId": "UP4497-PPSA10407_00-00000000000000N2",
		"image": {
			"__typename": "Media",
			"url": "https://image.api.playstation.com/sgst/prod/00/PPSA10407_00/app/info/18/fi_0c448ed97e1be8c417dd5ea6122f93b2d8c792dd68eef00349d7013b53b472c3/icon0.png"
		},
		"isActive": true,
		"isDownloadable": true,
		"isPreOrder": false,
		"name": "The Witcher 3: Wild Hunt",
		"platform": "PS5",
		"productId": "UP4497-PPSA10407_00-00000000000000N2",
		"subscriptionService": "NONE",
		"titleId": "PPSA10407_00"
	},

Regarding my previous concern about privacy: Nope, you can only request the data for the logged in account, can't see anyone else's.

@TheYuriG As suggested by you in #120 I'd like to contribute to the project by working on this task if I may.

@TheYuriG As suggested by you in #120 I'd like to contribute to the project by working on this task if I may.

All contributions are welcome, please feel free to contribute a PR if you think you can add value to the library 😊

@TheYuriG As suggested by you in #120 I'd like to contribute to the project by working on this task if I may.

Yeah, go ahead. Postman already has the request completely setup so you can use it as guidance so you are not working completely from scratch with this. Link in my post above.

Thanks @wescopeland and @TheYuriG! I forked the Postman collection and went through some of the existing code and tests to familiarise myself with the code itself and your conventions.
Will start the development soon.