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.
This is GTK method, so it's not safe to call this off of the main thread.
This fix looks ugly, but I've got a PR to rework this code for more PNG support that will improve this. This will do until that gets merged, I think.
Instead of passing the extra-ids everwhere and hoping it lines up, we pass them to the installer to generate the InstallerFiles, but it provides the extra files separately.
We can then extract the download destination paths for each extra file we're downloading, and we can put those in the script.
This way, if there are more or fewer files than we expect, it will still work.
This may help with #4974, but it's hard to be sure.
The None result from get_cache_path() was leaking into the Preferences dialog, so now it never returns None - there's always ~/.cache/lutris/installer to fall back on, after all. A separate function checks if it is even configured.
Also, the sanity check for whether the custom dir even exists was inconsistently applied and would accept a file; it needs to be a directory. So now it checks with os.path.isdir().
Remove NoScreenDetected; this exception is just an if statement is disguise. We still need to handle GLib.Error though.
Rename ExtractFailure to ExtractError.
Rename AuthTokenExpired to AuthTokenExpiredError, provide a minimal message.
Replace InvalidPid with ValueError with the custom message. This is never caught, and it's misleading - it means the pid given isn't convertible to int, not that it's a valid PID.
Rename UnauthorizedAccess to UnauthorizedAccessError,
Remove FileNotAvailable; it's never used.
Rename MissingDependency to MissingGameDependencyError and ensure it has a message. We do put that message in the logs at least! It should be a LutrisError too.
This is really just an assertion and is pretty useless - we'd crash on the very next line anyway without it.
But for documentation I'll leave a RuntimeError.
This way we need not duplicate the __init__ function in each.
Most are just LutrisError subclasses now, but InvalidRunnerError is a MisconfigurationError. I can't see a bogus runner name coming from anywhere but the configuration.
We use game.runner in many places without checking, so returning None is a bad thing here. Better to raise.
For the few places that check, I've added game.has_runner. Also added a few defensing checks and an exception handler for safety.