Steam, GOG and Battle.net detect uninstalled games - is it possible to do the same for UPlay and Origin?
I guess your hands may be tied by their platforms making it impossible - but just wanted to raise it nonetheless.
Thanks :D
Origin already supports uninstalled games. UPlay is currently not technically possible, maybe in future when Ubisoft changes the platform.
Origin only appears to detect games that are installed or those that have been uninstalled since the installation of Playnite. I have over 15 games on Origin, but the only 2 showing in PlayNite is the one I've installed and the one I've installed and uninstalled since I installed PlayNite. Expected behavior or bug?
Are you sure you have full library sync enabled for Origin and are you logged in? If so then please go to "About Playnite..." menu and upload diagnostics package. Thanks
My bad - hadn't done a manual login. Working now.
I was wondering if you have tried to use a man-in-the middle proxy to see how uplay application gets its data ? I Guess there is a hidden service that might be accessible once found no ? I have tried on computer and on android app but till now uplay launcher seems to crash while others app are correctly sniffed. Don't know why though. I might try some other options however(Transparent Proxy).
Yes I have tried that, but they push everything though https and they refuse all connections not using their SSL certificate.
What might be a better way start is to look at Uplay web and their account pages. I implemented Origin that way, they use the same APIs on web as in Origin client and it was super easy to debug via browser.
However last time I checked (like a 6 months ago), Uplay doesn't server any web page with your account library that would actually use any kind of API we could use. But it's worth looking into it again.
for information there is an api I have been able to discover while reading the code of the ubisoftclub android application.
Il already discover how to authenticate on that service and get some precious information:
A simple POST on https://public-ubiservices.ubi.com/v2/profiles/sessions will bring you interesting data.
POST /v2/profiles/sessions HTTP/1.1
Host: public-ubiservices.ubi.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Accept: *
Ubi-AppId: 46f0b36b-b947-4d9c-b9dc-9a34b52ab59a
Authorization: Basic XXXXXX
Cache-Control: no-cache
Postman-Token: aa4601af-809f-111c-1cea-8d98e4b8e341
Authorization is classic BASE64 encoded username:password
Ubi-AppId is constant depending of the platform. Here are the value:
UBI_APP_ID: {
PS4 : "1dad8b87-bd58-4dee-88e9-295c931ec148",
XONE : "79ab7c02-65e4-40a5-81c9-3580642eb911",
PC : "1dad8b87-bd58-4dee-88e9-295c931ec148",
IOS : "de726b45-417f-476f-a3ba-d0c032a9ef2e",
WP : "de726b45-417f-476f-a3ba-d0c032a9ef2e",
ANDROID : "46f0b36b-b947-4d9c-b9dc-9a34b52ab59a"
}
You'll get with this call:
{
"token": null,
"ticket": "XXXXXX",
"twoFactorAuthenticationTicket": null,
"expiration": "2018-06-02T14:43:30.8260500Z",
"platformType": "uplay",
"profileId": "XXXX",
"userId": "XXXXX",
"username": "thetrueavatar",
"nameOnPlatform": "thetrueavatar",
"initializeUser": true,
"spaceId": "XXXXX",
"environment": "Prod",
"hasAcceptedLegalOptins": true,
"accountIssues": null,
"sessionId": "XXXX",
"clientIp": "XXXX",
"clientIpCountry": "BE",
"serverTime": "2018-06-02T11:43:30.8797611Z",
"rememberMeTicket": null
}
userId and profile id are used for other service. With those one and ticket representing session you should be able to get all information uplay is providing.
I'm still looking to find the exact URI+Parameter to get the list of data but should be quite easy...
And here it is:
GET /v3/profiles/{profileId}/applications HTTP/1.1
Host: msr-public-ubiservices.ubi.com
Authorization: Ubi_v1 t={ticketNumber}
Cache-Control: no-cache
return
{
"applications": [
{
"profileId": "XXXX",
"applicationId": "19ba479c-b658-4b7e-8ffd-88f2c85b79e6",
"firstSessionDate": "2016-12-17T20:56:34.421Z",
"lastSessionDate": "2018-06-01T12:01:33.907Z",
"sessionsCount": 13
},
{
"profileId": "XXXX",
"applicationId": "314d4fef-e568-454a-ae06-43e3bece12a6",
"firstSessionDate": "2016-11-30T21:55:51.617Z",
"lastSessionDate": "2018-01-08T13:07:33.153Z",
"sessionsCount": 6
},
{
"profileId": "XXXXX",
"applicationId": "4c2582ee-ec9e-420c-9ba2-ba401f2eacce",
"firstSessionDate": "2017-02-05T09:21:18.014Z",
"lastSessionDate": "2017-02-15T12:53:29.664Z",
"sessionsCount": 9
}
]
}
And here we are !!!.
To sum up things:
1) Post on the url https://public-ubiservices.ubi.com/v2/profiles/sessions with http headers:
a) Authorization which contains "BASIC BASE64ENCODER(username:password)"
b) Ubi-AppId: 1dad8b87-bd58-4dee-88e9-295c931ec148
You'll get your profileId and ticket
2) Get all application list by doing a GET on
https://msr-public-ubiservices.ubi.com/v3/profiles/{profileId}/applications with profile id found in previous request and with http headers:
Authorization: Ubi_v1 t={ticketNumber}
Ticket found from previous request.
3) parse JSON response and find correspondance between applicationId and game. I have seen that those uid where used on ubisoft store so should be quite simple.
Now it's up to you ! As a java developer it would take me too much time to set up dev environnement on .Net so I let you integrate this functionnality instead of submitting a pull request.
Best Regards
Thanks @thetrueavatar One thing I'm a bit worried about is that we will have to store user's password (or ask for it every time user would want to sync their library). There are safe ways to do it, but until now I successfully managed to avoid handling user's credentials directly.
Well, You don't need. You'll ask username/password during configuration to get profileId and "token"(named as ticket here) but won't have to store it(maybe username but not password). In the end, you'll only need to store profileId and token such as most of the android app does to avoid asking username/password on every app start. Token as a lifetime. I don't know how long does it last before it expires but since ubisoft club never ask my username/password for a week I guess it's quite long enough. Once it's expire you'll just have to prompt username/password form and ask user to fill in the form. Then you'll get a new token and never store password.
Right, if the token lasts at least couple of days then it shouldn't be a problem.
Since there is no messaging on github I ask you by message on this issue.
Do you have by any chance a docker that I could use to develop and contribute to playnite. As explained, I'm a java dev but it's the same paradigm(OO) and from what I have seen in your github repo, the code structure is well designed so it won't be a problem to jump in the other side with playnite :p.
I don't commit myself to be an active contributor due to the lack of time but if I have some I could help you for the other library integration.
There's no docker version for supporting service, but you don't need it if you don't want to mess around with stuff like metadata download. See development environment page on wiki. The building script part is a bit outdated since last update (I'll update it as soon as possible), but if you build Playnite directly from Visual Studio then everything should work just fine without additional setup.
Just make sure you set ThrowAllErrors in App.Debug.config file to False and you should be able to run directly from VS with additional dependencies.
For features like Steam import, metadata download and auto-update you'll have to deploy the API service, there's no docker version, but I will write something to make it easier for people to deploy it in future. Right now you have to follow the tutorial on wiki if you want to deploy your own instance for development.
@JosefNemec May I ask you, if there's any progression of the uplay integration?
No progress, I didn't have time to work on this. API info provided by thetrueavatar can't be used because it doesn't provide necessary information that Uplay desktop client needs (local game Ids). Plus I'm not sure we can use that approach for accounts that have two factor authentication enabled (but I haven't tested that).
If anybody wants to help with this then we need solution that:
uplay:// browser protocol)Alright, I want to sort this API out too!
Thanks @JosefNemec for your awesome API discovery, let me just recap this for my other fellow curl users :
curl -X POST https://public-ubiservices.ubi.com/v2/profiles/sessions -H 'Ubi-AppId: 1dad8b4dee-88e9-295c931ec148' -H 'Authorization: Basic <xxx>' -v -d "" -H 'Content-Type: application/json' # xxx is base64(user:pass)
curl https://msr-public-ubiservices.ubi.com/v3/profiles/<ppp>/applications -H 'Authorization: Ubi_v1 t=<ttt>' # ppp is your profile id, ttt your token
twoFactorAuthenticationTicket param, but the token seems short lived with an expiration of only some hours./v3/profiles/x/applications) only returns your Ubisoft Club Games. I have more than 20 games but this call only returns me 7 entries. And 7 is the same numbers I see here.So I'm trying to explore this API, this page is a good starting point : https://club.ubisoft.com/fr-FR/games. I found something interesting too, those query parameters seems to work on multiples API calls :
?offset=2&limit=5
Inside the folder <Path-to-UPlay>\cache\configuration I found a file name configurations, which is in plain text (looks like YAML) and it contains data about all the games and the dlc in your account, even the ones you have not installed yet, though it does not seem to contain the game ids.
Yeah the ids are the problem. Actually getting content of your library is not that hard (the worst case scenario we could scrape library data from Ubisoft website). The problem is getting that information with Uplay relevant data.
Could you use one of the above methods to populate the 'uninstalled games' section, and just have the 'install game' button launch uPlay so the user can manually install the game, and then the ID would be picked up so the user can at least launch the game directly through PlayNite? Not perfect admittedly, but that's what the Epic one seems to do and it's not the end of the world, certainly better than not having uninstalled games at all.
When we'll be able to authenticate with Uplay without having to download the launcher? Thanks.
Hello, I don't know where anybody is on this subject but Gog Galaxy 2 can do this and it's working pretty well.
What is cool is that the plugin is free to look at ( https://github.com/FriendsOfGalaxy/galaxy-integration-uplay ).
I don't have the time to implement this but maybe somebody is interested.
I've done more research into this and here's my result:
c:\Program Files (x86)\Ubisoft\Ubisoft Game Launcher\cache\configuration\configurations file. This includes every game (including old ones), including DLCs.Parsing the configurations cache file looks like the only reliable option to me right now. The file is most probably encoded protobuf (at least I get some valid results when running general decoder on it). If somebody wants to help me with this, then writing parser for that configurations file would be a great start.
Interesting that it potentially uses ProtoBuf. I dumped the proto definitions from its dlls here, but I haven't tried to read anything from the cache yet.
https://gist.github.com/psychonic/d294b9ceef1d4a662ab9e720121012cb
That's great! The cache is a list of objects that contains minimum of this:
There are definitely some other fields, but I didn't have much time to dig deeper.
I inspected the file as a generic protobuf encoded file and saw the fields you mentioned. It doesn't seem to line up with any of the proto definitions dumped from the binaries, but that's inconsequential.
I did some quick prototyping with protobuf-net and it seems to work fine just manually defining the structure. I haven't looked into parsing the YAML, but I assume that won't be too bad since YamlDotNet is already used in Playnite
using System;
using System.Collections.Generic;
using System.IO;
using ProtoBuf;
namespace ConsoleApp2
{
[ProtoContract]
class UplayGame
{
[ProtoMember(1)]
public uint UplayId { get; set; }
[ProtoMember(2)]
public uint InstallId { get; set; }
[ProtoMember(3)]
public string GameInfo { get; set; }
}
[ProtoContract]
class UplayGameCollection
{
[ProtoMember(1)]
public List<UplayGame> Games { get; set; }
}
class Program
{
static void Main(string[] args)
{
UplayGameCollection games;
using (var file = File.OpenRead(@"G:\Program Files (x86)\Ubisoft\Ubisoft Game Launcher\cache\configuration\configurations"))
{
Serializer.Deserialize<UplayGameCollection>(file).Games.ForEach(g =>
{
Console.Write("Found Game {0} ({1})\r\n{2}\r\n\r\n", g.UplayId, g.InstallId, g.GameInfo);
});
}
Console.ReadLine();
}
}
}
For some reason that doesn't work for me. I'm getting ProtoBuf.ProtoException: 'Invalid wire-type exception. I'm attaching my configurations file if you want to investigate it.
Ignore my last comment. The cache was damaged for some reason, I've let Uplay create a new one and it works. That also explains why I was unable to reverse it properly, I was seeing some weird varint types (7+, while 5 is maximum in protobuf 3). Well that was two hours wasted, thanks Ubisoft.
Anyways the question is how many other people will have that cache damaged too. I'll will have to add some notification about it, but that shouldn't be a problem.
Thanks for looking into it.
P.S. Just out of interest I looked at how GOG does it in Galaxy 2 and oh boy, they sure didn't figure out that it's protobuf. That could have make their lives easier.
Done in 6.1
Most helpful comment
Done in 6.1