You can have a GOG game off the Lutris website that does not download from GOG - you provide the installer file. "Alient Shooter" is one of these.
In this case, we have no appid and can get no extras, and we should not try to get them.
If you click Continue fas enough, you can trigger the prepare_game_files() method to run twice, on two threads concurrently. This results in doubled up files and a duplicate files page in the navigation stack.
This is hard to fix simply or without UI ugliness, so this commit tolerates it.
It adjusts prepare_game_files() to be thread-safer (!) by committing its changes only at the end. The GIL should make this atomic, probably, so the last preparation wins instead of being combined with the other.
The navigation stack will now refuse to add a duplicate page; it still exits the old and re-enters but does not put the second entry in the history, so you'll go back further when you click the Back button.
That should hide the problem with minimal code churn and risk.
I'm not really sure that this code actually runs - there's dead code here for sure, and I can't prove we can ever match an existing game with an api-provided service installer.
Buuut if it does run it can crash us. We can't emi 'game-updated' on a thread, it absolutely hits GTK.
This commit moves the signal to the main thread and adds some error handling to avoid a NoneType error here too.
Super ugly this. Asyncio could do some much better!
Now here's a place where asyncio would clearly have helped.
But, the problem is that the move-game logic runs on a thread and changes the game. It saves the game and *that* fires the 'game-updated' signal. Various bits of the UI handle this to update the UI.
But GTK is not thread-safe at all, and updating the UI from a thread will sometimes crash it.
This commit suppresses the signal, and then manually fires it after the moe completes on the main thread in the AsyncCall callback.
However, we handle the exception here and show a warning dialog about this. The user can choose to just set the location without moving or updating anything - they'll have to fix things up themselves.
Should help with #5223
DLCs you do not own are listed by the GOG api but are _not_ installable, and we will get 404s trying to download the extras for them.
So let's not offer them at all.
This is a bit painful; to do this we extract the downlink information when we pull the extras, and put that in the extras dict.
Then, InstallerWindow keeps the dict rather than just the ID from it; it passes the entire thing back into the service so that the GOG service can obtain the download subdict and it goes from there.
There are minimal changes for itch.io, the only other service with extras. The new code here just strips the IDs out and proceeds as before.
It's better to let users know this feature isn't going to be used. I'd use 'condition' here, but it does not support dynamic updates baed on config settings like the version.
This isn't perfect - a system provided Wine might not be detected at this point. But I think it is likely to be sufficient; the actual check against the Wine exe path remains anyway.
The rather gruff 'not supported' warning remains in any case.
This way the parse/format roundtrip will not be broken by translators getting creative, or forgetting some of the strings.
This does mean we'll lose the translations for playtimes in the next release. I'd hand-fix this, but @strcore has told me not to do this.
This extends sync_media() so it can download for a specific set of games, so we can download only the installed games, not games you had already.
Resolves#4545
We generally need them all, and pounding the database over and over for each game *even if it has no installed game counterpart* we cause nasty concurrency issues when reloading the service at the same time.
Instead, we load them and all preload the StoreItem - even if there's no installed game, if the StoreItem knows this, there's no need to fetch that data for that game.