mirror of
https://github.com/lutris/lutris.git
synced 2026-06-21 20:30:04 -04:00
Merge
This commit is contained in:
113
lutris/api.py
113
lutris/api.py
@@ -5,9 +5,7 @@ import urllib2
|
||||
import socket
|
||||
|
||||
from lutris import settings
|
||||
from lutris import pga
|
||||
from lutris.util import http
|
||||
from lutris.util import resources
|
||||
from lutris.util.log import logger
|
||||
|
||||
|
||||
@@ -73,114 +71,3 @@ def get_games(slugs):
|
||||
game_set = ';'.join(slugs)
|
||||
url = settings.SITE_URL + "api/v1/game/set/%s/" % game_set
|
||||
return http.download_json(url, params="?format=json")['objects']
|
||||
|
||||
|
||||
def sync(caller=None):
|
||||
"""Synchronize from remote to local library.
|
||||
|
||||
:param caller: The LutrisWindow object
|
||||
:return: The synchronized games (slugs)
|
||||
:rtype: set of strings
|
||||
"""
|
||||
logger.debug("Syncing game library")
|
||||
# Get local library
|
||||
local_library = pga.get_games()
|
||||
local_slugs = set([game['slug'] for game in local_library])
|
||||
logger.debug("%d games in local library", len(local_slugs))
|
||||
# Get remote library
|
||||
remote_library = get_library()
|
||||
remote_slugs = set([game['slug'] for game in remote_library])
|
||||
logger.debug("%d games in remote library (inc. unpublished)",
|
||||
len(remote_slugs))
|
||||
|
||||
not_in_local = remote_slugs.difference(local_slugs)
|
||||
|
||||
added = sync_missing_games(not_in_local, remote_library, caller)
|
||||
updated = sync_game_details(remote_library, caller)
|
||||
return added.update(updated)
|
||||
|
||||
|
||||
def sync_missing_games(not_in_local, remote_library, caller=None):
|
||||
"""Get missing games in local library from remote library.
|
||||
|
||||
:param caller: The LutrisWindow object
|
||||
:return: The slugs of the added games
|
||||
:rtype: set
|
||||
"""
|
||||
if not not_in_local:
|
||||
return set()
|
||||
|
||||
for game in remote_library:
|
||||
slug = game['slug']
|
||||
# Sync
|
||||
if slug in not_in_local:
|
||||
logger.debug("Adding to local library: %s", slug)
|
||||
pga.add_game(
|
||||
game['name'], slug=slug, year=game['year'],
|
||||
updated=game['updated'], steamid=game['steamid']
|
||||
)
|
||||
if caller:
|
||||
caller.add_game_to_view(slug)
|
||||
else:
|
||||
not_in_local.discard(slug)
|
||||
logger.debug("%d games added", len(not_in_local))
|
||||
return not_in_local
|
||||
|
||||
|
||||
def sync_game_details(remote_library, caller):
|
||||
"""Update local game details,
|
||||
|
||||
:param caller: The LutrisWindow object
|
||||
:return: The slugs of the updated games.
|
||||
:rtype: set
|
||||
"""
|
||||
if not remote_library:
|
||||
return set()
|
||||
|
||||
updated = set()
|
||||
|
||||
# Get remote games (TODO: use this when switched API to DRF)
|
||||
# remote_games = get_games(sorted(local_slugs))
|
||||
# if not remote_games:
|
||||
# return set()
|
||||
|
||||
for game in remote_library:
|
||||
slug = game['slug']
|
||||
sync = False
|
||||
sync_icons = True
|
||||
local_game = pga.get_game_by_slug(slug)
|
||||
if not local_game:
|
||||
continue
|
||||
|
||||
# Sync updated
|
||||
if game['updated'] > local_game['updated']:
|
||||
sync = True
|
||||
# Sync new fields
|
||||
else:
|
||||
for key, value in local_game.iteritems():
|
||||
if value or not key in game:
|
||||
continue
|
||||
if game[key]:
|
||||
sync = True
|
||||
sync_icons = False
|
||||
if not sync:
|
||||
continue
|
||||
|
||||
logger.debug("Syncing details for %s" % slug)
|
||||
pga.add_or_update(
|
||||
local_game['name'], local_game['runner'], slug,
|
||||
year=game['year'], updated=game['updated'],
|
||||
steamid=game['steamid']
|
||||
)
|
||||
caller.view.update_row(game)
|
||||
|
||||
# Sync icons (TODO: Only update if icon actually updated)
|
||||
if sync_icons:
|
||||
resources.download_icon(slug, 'banner', overwrite=True,
|
||||
callback=caller.on_image_downloaded)
|
||||
resources.download_icon(slug, 'icon', overwrite=True,
|
||||
callback=caller.on_image_downloaded)
|
||||
updated.add(slug)
|
||||
|
||||
logger.debug("%d games updated", len(updated))
|
||||
return updated
|
||||
|
||||
@@ -155,7 +155,7 @@ class LutrisWindow(object):
|
||||
self.toggle_connection(False)
|
||||
sync = Sync()
|
||||
async_call(
|
||||
sync.sync_steam,
|
||||
sync.sync_steam_local,
|
||||
lambda r, e: async_call(self.sync_icons, None),
|
||||
caller=self
|
||||
)
|
||||
@@ -166,19 +166,6 @@ class LutrisWindow(object):
|
||||
if self.view.__class__.__name__ == "GameGridView" \
|
||||
else 'list'
|
||||
|
||||
def switch_splash_screen(self):
|
||||
if self.view.n_games == 0:
|
||||
self.splash_box.show()
|
||||
self.games_scrollwindow.hide()
|
||||
else:
|
||||
self.splash_box.hide()
|
||||
self.games_scrollwindow.show()
|
||||
|
||||
def sync_icons(self):
|
||||
game_list = pga.get_games()
|
||||
resources.fetch_icons([game_info['slug'] for game_info in game_list],
|
||||
callback=self.on_image_downloaded)
|
||||
|
||||
def connect_signals(self):
|
||||
"""Connect signals from the view with the main window.
|
||||
This must be called each time the view is rebuilt.
|
||||
@@ -209,6 +196,59 @@ class LutrisWindow(object):
|
||||
def get_size(self, widget, _):
|
||||
self.window_size = widget.get_size()
|
||||
|
||||
def switch_splash_screen(self):
|
||||
if self.view.n_games == 0:
|
||||
self.splash_box.show()
|
||||
self.games_scrollwindow.hide()
|
||||
else:
|
||||
self.splash_box.hide()
|
||||
self.games_scrollwindow.show()
|
||||
|
||||
def switch_view(self, view_type):
|
||||
"""Switch between grid view and list view."""
|
||||
logger.debug("Switching view")
|
||||
self.icon_type = self.get_icon_type(view_type)
|
||||
self.view.destroy()
|
||||
self.view = load_view(
|
||||
view_type,
|
||||
get_game_list(filter_installed=self.filter_installed),
|
||||
filter_text=self.search_entry.get_text(),
|
||||
icon_type=self.icon_type
|
||||
)
|
||||
self.view.contextual_menu = self.menu
|
||||
self.connect_signals()
|
||||
self.games_scrollwindow.add(self.view)
|
||||
self.view.show_all()
|
||||
self.view.check_resize()
|
||||
# Note: set_active(True *or* False) apparently makes ALL the menuitems
|
||||
# in the group send the activate signal...
|
||||
if self.icon_type == 'banner_small':
|
||||
self.banner_small_menuitem.set_active(True)
|
||||
if self.icon_type == 'icon':
|
||||
self.icon_menuitem.set_active(True)
|
||||
if self.icon_type == 'banner':
|
||||
self.banner_menuitem.set_active(True)
|
||||
|
||||
def sync_library(self):
|
||||
def set_library_synced(result, error):
|
||||
self.set_status("Library synced")
|
||||
self.switch_splash_screen()
|
||||
self.set_status("Syncing library")
|
||||
sync = Sync()
|
||||
async_call(
|
||||
sync.sync_all,
|
||||
lambda r, e: async_call(self.sync_icons, set_library_synced),
|
||||
caller=self
|
||||
)
|
||||
|
||||
def sync_icons(self):
|
||||
game_list = pga.get_games()
|
||||
resources.fetch_icons([game_info['slug'] for game_info in game_list],
|
||||
callback=self.on_image_downloaded)
|
||||
|
||||
def set_status(self, text):
|
||||
self.status_label.set_text(text)
|
||||
|
||||
def refresh_status(self):
|
||||
"""Refresh status bar."""
|
||||
if self.running_game:
|
||||
@@ -236,12 +276,28 @@ class LutrisWindow(object):
|
||||
"""Open the about dialog."""
|
||||
dialogs.AboutDialog()
|
||||
|
||||
def reset(self, *args):
|
||||
"""Reset the desktop to it's initial state."""
|
||||
if self.running_game:
|
||||
self.running_game.quit_game()
|
||||
self.status_label.set_text("Stopped %s" % self.running_game.name)
|
||||
self.running_game = None
|
||||
self.stop_button.set_sensitive(False)
|
||||
|
||||
# Callbacks
|
||||
def on_connect(self, *args):
|
||||
"""Callback when a user connects to his account."""
|
||||
login_dialog = dialogs.ClientLoginDialog()
|
||||
login_dialog.connect('connected', self.on_connect_success)
|
||||
|
||||
def on_connect_success(self, dialog, credentials):
|
||||
if isinstance(credentials, str):
|
||||
username = credentials
|
||||
else:
|
||||
username = credentials["username"]
|
||||
self.toggle_connection(True, username)
|
||||
self.sync_library()
|
||||
|
||||
def on_disconnect(self, *args):
|
||||
api.disconnect()
|
||||
self.toggle_connection(False)
|
||||
@@ -262,14 +318,6 @@ class LutrisWindow(object):
|
||||
logger.info(connection_status)
|
||||
connection_label.set_text(connection_status)
|
||||
|
||||
def on_connect_success(self, dialog, credentials):
|
||||
if isinstance(credentials, str):
|
||||
username = credentials
|
||||
else:
|
||||
username = credentials["username"]
|
||||
self.toggle_connection(True, username)
|
||||
self.sync_library()
|
||||
|
||||
def on_destroy(self, *args):
|
||||
"""Signal for window close."""
|
||||
view_type = 'grid' if 'GridView' in str(type(self.view)) else 'list'
|
||||
@@ -280,9 +328,6 @@ class LutrisWindow(object):
|
||||
Gtk.main_quit(*args)
|
||||
logger.debug("Quitting lutris")
|
||||
|
||||
def on_game_installed(self, view, slug):
|
||||
view.set_installed(Game(slug))
|
||||
|
||||
def on_runners_activate(self, _widget, _data=None):
|
||||
"""Callback when manage runners is activated."""
|
||||
RunnersDialog()
|
||||
@@ -302,10 +347,6 @@ class LutrisWindow(object):
|
||||
def on_pga_menuitem_activate(self, _widget, _data=None):
|
||||
dialogs.PgaSourceDialog()
|
||||
|
||||
def on_image_downloaded(self, game_slug):
|
||||
is_installed = Game(game_slug).is_installed
|
||||
self.view.update_image(game_slug, is_installed)
|
||||
|
||||
def on_search_entry_changed(self, widget):
|
||||
self.view.emit('filter-updated', widget.get_text())
|
||||
|
||||
@@ -325,29 +366,6 @@ class LutrisWindow(object):
|
||||
else:
|
||||
InstallerDialog(game_slug, self)
|
||||
|
||||
def set_status(self, text):
|
||||
self.status_label.set_text(text)
|
||||
|
||||
def sync_library(self):
|
||||
def set_library_synced(result, error):
|
||||
self.set_status("Library synced")
|
||||
self.switch_splash_screen()
|
||||
self.set_status("Syncing library")
|
||||
sync = Sync()
|
||||
async_call(
|
||||
sync.sync_all,
|
||||
lambda r, e: async_call(self.sync_icons, set_library_synced),
|
||||
caller=self
|
||||
)
|
||||
|
||||
def reset(self, *args):
|
||||
"""Reset the desktop to it's initial state."""
|
||||
if self.running_game:
|
||||
self.running_game.quit_game()
|
||||
self.status_label.set_text("Stopped %s" % self.running_game.name)
|
||||
self.running_game = None
|
||||
self.stop_button.set_sensitive(False)
|
||||
|
||||
def game_selection_changed(self, _widget):
|
||||
# Emulate double click to workaround GTK bug #484640
|
||||
# https://bugzilla.gnome.org/show_bug.cgi?id=484640
|
||||
@@ -363,6 +381,27 @@ class LutrisWindow(object):
|
||||
self.play_button.set_sensitive(sensitive)
|
||||
self.delete_button.set_sensitive(sensitive)
|
||||
|
||||
def on_game_installed(self, view, slug):
|
||||
view.set_installed(Game(slug))
|
||||
|
||||
def on_image_downloaded(self, game_slug):
|
||||
is_installed = Game(game_slug).is_installed
|
||||
self.view.update_image(game_slug, is_installed)
|
||||
|
||||
def add_manually(self, *args):
|
||||
game = Game(self.view.selected_game)
|
||||
add_game_dialog = AddGameDialog(self, game)
|
||||
add_game_dialog.run()
|
||||
if add_game_dialog.installed:
|
||||
self.view.set_installed(game)
|
||||
|
||||
def add_game(self, _widget, _data=None):
|
||||
"""Add a new game."""
|
||||
add_game_dialog = AddGameDialog(self)
|
||||
add_game_dialog.run()
|
||||
if add_game_dialog.runner_name and add_game_dialog.slug:
|
||||
self.add_game_to_view(add_game_dialog.slug)
|
||||
|
||||
def add_game_to_view(self, slug):
|
||||
if not slug:
|
||||
raise ValueError("Missing game slug")
|
||||
@@ -373,20 +412,6 @@ class LutrisWindow(object):
|
||||
self.switch_splash_screen()
|
||||
GLib.idle_add(do_add_game)
|
||||
|
||||
def add_game(self, _widget, _data=None):
|
||||
"""Add a new game."""
|
||||
add_game_dialog = AddGameDialog(self)
|
||||
add_game_dialog.run()
|
||||
if add_game_dialog.runner_name and add_game_dialog.slug:
|
||||
self.add_game_to_view(add_game_dialog.slug)
|
||||
|
||||
def add_manually(self, *args):
|
||||
game = Game(self.view.selected_game)
|
||||
add_game_dialog = AddGameDialog(self, game)
|
||||
add_game_dialog.run()
|
||||
if add_game_dialog.installed:
|
||||
self.view.set_installed(game)
|
||||
|
||||
def on_remove_game(self, _widget, _data=None):
|
||||
selected_game = self.view.selected_game
|
||||
UninstallGameDialog(slug=selected_game,
|
||||
@@ -439,31 +464,6 @@ class LutrisWindow(object):
|
||||
self.grid_view_menuitem.set_active(view_type == 'grid')
|
||||
self.list_view_menuitem.set_active(view_type == 'list')
|
||||
|
||||
def switch_view(self, view_type):
|
||||
"""Switch between grid view and list view."""
|
||||
logger.debug("Switching view")
|
||||
self.icon_type = self.get_icon_type(view_type)
|
||||
self.view.destroy()
|
||||
self.view = load_view(
|
||||
view_type,
|
||||
get_game_list(filter_installed=self.filter_installed),
|
||||
filter_text=self.search_entry.get_text(),
|
||||
icon_type=self.icon_type
|
||||
)
|
||||
self.view.contextual_menu = self.menu
|
||||
self.connect_signals()
|
||||
self.games_scrollwindow.add(self.view)
|
||||
self.view.show_all()
|
||||
self.view.check_resize()
|
||||
# Note: set_active(True *or* False) apparently makes ALL the menuitems
|
||||
# in the group send the activate signal...
|
||||
if self.icon_type == 'banner_small':
|
||||
self.banner_small_menuitem.set_active(True)
|
||||
if self.icon_type == 'icon':
|
||||
self.icon_menuitem.set_active(True)
|
||||
if self.icon_type == 'banner':
|
||||
self.banner_menuitem.set_active(True)
|
||||
|
||||
def on_icon_type_activate(self, menuitem):
|
||||
icon_type = menuitem.get_name()
|
||||
if icon_type == self.view.icon_type or not menuitem.get_active():
|
||||
|
||||
@@ -207,10 +207,10 @@ class GameView(object):
|
||||
"""Update a game row to show as installed"""
|
||||
row = self.get_row_by_slug(game.slug)
|
||||
if not row:
|
||||
logger.error("Can't find row for %s", game.slug)
|
||||
return
|
||||
row[COL_RUNNER] = game.runner_name
|
||||
self.update_image(game.slug, is_installed=True)
|
||||
self.add_game(game)
|
||||
else:
|
||||
row[COL_RUNNER] = game.runner_name
|
||||
self.update_image(game.slug, is_installed=True)
|
||||
|
||||
def set_uninstalled(self, game_slug):
|
||||
"""Update a game row to show as uninstalled"""
|
||||
|
||||
@@ -159,10 +159,13 @@ class ScriptInterpreter(object):
|
||||
"Downloading file %d of %d",
|
||||
len(self.game_files) + 1, len(self.script["files"])
|
||||
)
|
||||
file_index = len(self.game_files)
|
||||
try:
|
||||
self._download_file(self.script["files"][len(self.game_files)])
|
||||
current_file = self.script["files"][file_index]
|
||||
except KeyError:
|
||||
raise ScriptingError("Badly formatted script", self.script)
|
||||
raise ScriptingError("Error getting file %d in %s",
|
||||
file_index, self.script['files'])
|
||||
self._download_file(current_file)
|
||||
else:
|
||||
self.current_command = 0
|
||||
self._prepare_commands()
|
||||
@@ -553,7 +556,8 @@ class ScriptInterpreter(object):
|
||||
|
||||
def _append_steam_data_to_files(self, runner_class):
|
||||
steam_runner = runner_class()
|
||||
data_path = steam_runner.get_game_data_path(self.steam_data['appid'])
|
||||
data_path = steam_runner.get_game_path_from_appid(
|
||||
self.steam_data['appid'])
|
||||
if not data_path or not os.path.exists(data_path):
|
||||
raise ScriptingError("Unable to get Steam data for game")
|
||||
logger.debug("got data path: %s" % data_path)
|
||||
@@ -591,7 +595,7 @@ class ScriptInterpreter(object):
|
||||
def install_steam_game(self, runner_class):
|
||||
steam_runner = runner_class()
|
||||
appid = self.steam_data['appid']
|
||||
if not steam_runner.get_game_data_path(appid):
|
||||
if not steam_runner.get_game_path_from_appid(appid):
|
||||
logger.debug("Installing steam game %s" % appid)
|
||||
# Here the user must wait for the game to finish installing, a
|
||||
# better way to handle this would be to poll StateFlags on the
|
||||
|
||||
@@ -84,6 +84,10 @@ class dosbox(Runner):
|
||||
"x64": "dosbox-0.74-x86_64.tar.gz",
|
||||
}
|
||||
|
||||
@property
|
||||
def main_file(self):
|
||||
return self.settings.get('game', {}).get('main_file') or ''
|
||||
|
||||
@property
|
||||
def browse_dir(self):
|
||||
"""Return the path to open with the Browse Files action."""
|
||||
@@ -99,7 +103,7 @@ class dosbox(Runner):
|
||||
return os.path.join(settings.RUNNER_DIR, "dosbox/bin/dosbox")
|
||||
|
||||
def play(self):
|
||||
main_file = self.settings["game"]["main_file"]
|
||||
main_file = self.main_file
|
||||
if not os.path.exists(main_file):
|
||||
return {'error': "FILE_NOT_FOUND", 'file': main_file}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ class steam(Runner):
|
||||
|
||||
@property
|
||||
def game_path(self):
|
||||
appid = self.settings['game'].get('appid')
|
||||
appid = self.config['game'].get('appid')
|
||||
for apps_path in self.get_steamapps_dirs():
|
||||
game_path = get_path_from_appmanifest(apps_path, appid)
|
||||
if game_path:
|
||||
@@ -84,6 +84,14 @@ class steam(Runner):
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
def get_game_path_from_appid(self, appid):
|
||||
"""Return the game directory"""
|
||||
for apps_path in self.get_steamapps_dirs():
|
||||
game_path = get_path_from_appmanifest(apps_path, appid)
|
||||
if game_path:
|
||||
return game_path
|
||||
logger.warning("Data path for SteamApp %s not found.", appid)
|
||||
|
||||
def get_steamapps_dirs(self):
|
||||
"""Return a list of the Steam library main + custom folders."""
|
||||
dirs = []
|
||||
|
||||
@@ -69,12 +69,18 @@ class winesteam(wine.wine):
|
||||
{
|
||||
'option': 'appid',
|
||||
'type': 'string',
|
||||
'label': 'appid'
|
||||
'label': 'Application ID',
|
||||
'help': ("The application ID can be retrieved from the game's "
|
||||
"page at steampowered.com. Example: 235320 is the "
|
||||
"app ID for <i>Original War</i> in: \n"
|
||||
"http://store.steampowered.com/app/<b>235320</b>/")
|
||||
},
|
||||
{
|
||||
'option': 'args',
|
||||
'type': 'string',
|
||||
'label': 'arguments'
|
||||
'label': 'Arguments',
|
||||
'help': ("Windows command line arguments used when launching "
|
||||
"Steam")
|
||||
},
|
||||
{
|
||||
'option': 'prefix',
|
||||
@@ -173,6 +179,14 @@ class winesteam(wine.wine):
|
||||
apps = config['apps']
|
||||
return apps.keys()
|
||||
|
||||
def get_game_path_from_appid(self, appid):
|
||||
"""Return the game directory"""
|
||||
for apps_path in self.get_steamapps_dirs():
|
||||
game_path = get_path_from_appmanifest(apps_path, appid)
|
||||
if game_path:
|
||||
return game_path
|
||||
logger.warning("Data path for SteamApp %s not found.", appid)
|
||||
|
||||
def get_steamapps_dirs(self):
|
||||
"""Return a list of the Steam library main + custom folders."""
|
||||
dirs = []
|
||||
|
||||
124
lutris/sync.py
124
lutris/sync.py
@@ -2,11 +2,12 @@
|
||||
"""Synchronization of the game library with the server and other platforms."""
|
||||
import os
|
||||
|
||||
from lutris.util.log import logger
|
||||
from lutris import api, pga
|
||||
from lutris.game import Game
|
||||
from lutris.runners.steam import steam
|
||||
from lutris.runners.winesteam import winesteam
|
||||
from lutris.util import resources
|
||||
from lutris.util.log import logger
|
||||
|
||||
|
||||
class Sync(object):
|
||||
@@ -14,10 +15,120 @@ class Sync(object):
|
||||
self.library = pga.get_games()
|
||||
|
||||
def sync_all(self, caller):
|
||||
api.sync(caller)
|
||||
self.sync_steam(caller)
|
||||
self.sync_from_remote(caller)
|
||||
self.sync_steam_local(caller)
|
||||
|
||||
def sync_steam(self, caller):
|
||||
def sync_from_remote(self, caller=None):
|
||||
"""Synchronize from remote to local library.
|
||||
|
||||
:param caller: The LutrisWindow object
|
||||
:return: The synchronized games (slugs)
|
||||
:rtype: set of strings
|
||||
"""
|
||||
logger.debug("Syncing game library")
|
||||
# Get local library
|
||||
local_slugs = set([game['slug'] for game in self.library])
|
||||
logger.debug("%d games in local library", len(local_slugs))
|
||||
# Get remote library
|
||||
remote_library = api.get_library()
|
||||
remote_slugs = set([game['slug'] for game in remote_library])
|
||||
logger.debug("%d games in remote library (inc. unpublished)",
|
||||
len(remote_slugs))
|
||||
|
||||
not_in_local = remote_slugs.difference(local_slugs)
|
||||
|
||||
added = self.sync_missing_games(not_in_local, remote_library, caller)
|
||||
updated = self.sync_game_details(remote_library, caller)
|
||||
return added.update(updated)
|
||||
|
||||
@staticmethod
|
||||
def sync_missing_games(not_in_local, remote_library, caller=None):
|
||||
"""Get missing games in local library from remote library.
|
||||
|
||||
:param caller: The LutrisWindow object
|
||||
:return: The slugs of the added games
|
||||
:rtype: set
|
||||
"""
|
||||
if not not_in_local:
|
||||
return set()
|
||||
|
||||
for game in remote_library:
|
||||
slug = game['slug']
|
||||
# Sync
|
||||
if slug in not_in_local:
|
||||
logger.debug("Adding to local library: %s", slug)
|
||||
pga.add_game(
|
||||
game['name'], slug=slug, year=game['year'],
|
||||
updated=game['updated'], steamid=game['steamid']
|
||||
)
|
||||
if caller:
|
||||
caller.add_game_to_view(slug)
|
||||
else:
|
||||
not_in_local.discard(slug)
|
||||
logger.debug("%d games added", len(not_in_local))
|
||||
return not_in_local
|
||||
|
||||
@staticmethod
|
||||
def sync_game_details(remote_library, caller):
|
||||
"""Update local game details,
|
||||
|
||||
:param caller: The LutrisWindow object
|
||||
:return: The slugs of the updated games.
|
||||
:rtype: set
|
||||
"""
|
||||
if not remote_library:
|
||||
return set()
|
||||
updated = set()
|
||||
|
||||
# Get remote games (TODO: use this when switched API to DRF)
|
||||
# remote_games = get_games(sorted(local_slugs))
|
||||
# if not remote_games:
|
||||
# return set()
|
||||
|
||||
for game in remote_library:
|
||||
slug = game['slug']
|
||||
sync = False
|
||||
sync_icons = True
|
||||
local_game = pga.get_game_by_slug(slug)
|
||||
if not local_game:
|
||||
continue
|
||||
|
||||
# Sync updated
|
||||
if game['updated'] > local_game['updated']:
|
||||
sync = True
|
||||
# Sync new DB fields
|
||||
else:
|
||||
for key, value in local_game.iteritems():
|
||||
if value or not key in game:
|
||||
continue
|
||||
if game[key]:
|
||||
sync = True
|
||||
sync_icons = False
|
||||
if not sync:
|
||||
continue
|
||||
|
||||
logger.debug("Syncing details for %s" % slug)
|
||||
pga.add_or_update(
|
||||
local_game['name'], local_game['runner'], slug,
|
||||
year=game['year'], updated=game['updated'],
|
||||
steamid=game['steamid']
|
||||
)
|
||||
caller.view.update_row(game)
|
||||
|
||||
# Sync icons (TODO: Only update if icon actually updated)
|
||||
if sync_icons:
|
||||
resources.download_icon(slug, 'banner', overwrite=True,
|
||||
callback=caller.on_image_downloaded)
|
||||
resources.download_icon(slug, 'icon', overwrite=True,
|
||||
callback=caller.on_image_downloaded)
|
||||
updated.add(slug)
|
||||
|
||||
logger.debug("%d games updated", len(updated))
|
||||
return updated
|
||||
|
||||
def sync_steam_local(self, caller):
|
||||
"""Sync Steam games in library with Steam and Wine Steam"""
|
||||
logger.debug("Syncing local steam games")
|
||||
steam_ = steam()
|
||||
winesteam_ = winesteam()
|
||||
|
||||
@@ -33,19 +144,21 @@ class Sync(object):
|
||||
|
||||
# Set installed (steam linux only)
|
||||
if installed_in_steam and not game_info['installed']:
|
||||
logger.debug("Setting %s as installed" % game_info['name'])
|
||||
pga.add_or_update(game_info['name'], 'steam',
|
||||
game_info['slug'],
|
||||
installed=1)
|
||||
game.config.game_config.update({'game':
|
||||
{'appid': str(steamid)}})
|
||||
game.config.save()
|
||||
caller.view.set_installed(game)
|
||||
caller.view.set_installed(Game(game_info['slug']))
|
||||
continue
|
||||
|
||||
# Set uninstalled
|
||||
if not (installed_in_steam or installed_in_winesteam) \
|
||||
and game_info['installed'] \
|
||||
and game_info['runner'] in ['steam', 'winesteam']:
|
||||
logger.debug("Setting %s as uninstalled" % game_info['name'])
|
||||
pga.add_or_update(game_info['name'], '',
|
||||
game_info['slug'],
|
||||
installed=0)
|
||||
@@ -53,6 +166,7 @@ class Sync(object):
|
||||
|
||||
@staticmethod
|
||||
def _get_installed_steamapps(runner):
|
||||
"""Return a list of appIDs of the installed Steam games."""
|
||||
if not runner.is_installed():
|
||||
return []
|
||||
installed = []
|
||||
|
||||
Reference in New Issue
Block a user