diff --git a/lutris/gui/installerwindow.py b/lutris/gui/installerwindow.py index 6c0edf3f0..7c4cf6bbe 100644 --- a/lutris/gui/installerwindow.py +++ b/lutris/gui/installerwindow.py @@ -70,7 +70,7 @@ class InstallerWindow(ModelessDialog, self.set_default_size(740, 460) self.installers = installers self.config = {} - self.selected_extra_ids = [] + self.selected_extras = [] self.install_in_progress = False self.install_complete = False self.interpreter = None @@ -137,7 +137,7 @@ class InstallerWindow(ModelessDialog, self.extras_tree_store = Gtk.TreeStore( bool, # is selected? bool, # is inconsistent? - str, # id + object, # extras dict str, # label ) @@ -499,7 +499,7 @@ class InstallerWindow(ModelessDialog, for extra_source, extras in all_extras.items(): parent = self.extras_tree_store.append(None, (None, None, None, extra_source)) for extra in extras: - self.extras_tree_store.append(parent, (False, False, extra["id"], self.get_extra_label(extra))) + self.extras_tree_store.append(parent, (False, False, extra, self.get_extra_label(extra))) self.stack.navigate_to_page(self.present_extras_page) else: @@ -577,13 +577,13 @@ class InstallerWindow(ModelessDialog, selected_extras = [] def save_extra(store, path, iter_): - selected, _inconsistent, id_, _label = store[iter_] - if selected and id_: - selected_extras.append(id_) + selected, _inconsistent, extra, _label = store[iter_] + if selected and extra: + selected_extras.append(extra) extra_store.foreach(save_extra) - self.selected_extra_ids = selected_extras + self.selected_extras = selected_extras GLib.idle_add(self.on_extras_ready) def on_extras_ready(self, *args): @@ -602,7 +602,7 @@ class InstallerWindow(ModelessDialog, patch_version = None AsyncCall(self.interpreter.installer.prepare_game_files, - self.on_files_prepared, self.selected_extra_ids, patch_version) + self.on_files_prepared, self.selected_extras, patch_version) def on_files_prepared(self, _result, error): if error: diff --git a/lutris/installer/installer.py b/lutris/installer/installer.py index ea21b154d..b4170f8a3 100644 --- a/lutris/installer/installer.py +++ b/lutris/installer/installer.py @@ -148,7 +148,7 @@ class LutrisInstaller: # pylint: disable=too-many-instance-attributes errors.append("Scripts can't have both extends and requires") return errors - def prepare_game_files(self, extra_ids, patch_version=None): + def prepare_game_files(self, extras, patch_version=None): """Gathers necessary files before iterating through them.""" if not self.script_files: return @@ -177,7 +177,7 @@ class LutrisInstaller: # pylint: disable=too-many-instance-attributes # If a patch version is given download the patch files instead of the installer installer_files = self.service.get_patch_files(self, installer_file_id) else: - content_files, extra_files = self.service.get_installer_files(self, installer_file_id, extra_ids) + content_files, extra_files = self.service.get_installer_files(self, installer_file_id, extras) self.extra_file_paths = [path for f in extra_files for path in f.get_dest_files_by_id().values()] installer_files = content_files + extra_files except UnavailableGameError as ex: diff --git a/lutris/services/gog.py b/lutris/services/gog.py index 88b610ef5..f47cae894 100644 --- a/lutris/services/gog.py +++ b/lutris/services/gog.py @@ -289,7 +289,8 @@ class GOGService(OnlineService): return self.make_api_request(url) def get_download_info(self, downlink): - """Return file download information""" + """Return file download information, a list of dict containing the 'url' and + 'filename' for each file.""" logger.info("Getting download info for %s", downlink) try: response = self.make_api_request(downlink) @@ -298,12 +299,18 @@ class GOGService(OnlineService): raise UnavailableGameError(_("The download of '%s' failed.") % downlink) from ex if not response: raise UnavailableGameError(_("The download of '%s' failed.") % downlink) + + expanded = [] for field in ("checksum", "downlink"): field_url = response[field] parsed = urlparse(field_url) query = dict(parse_qsl(parsed.query)) - response[field + "_filename"] = os.path.basename(query.get("path") or parsed.path) - return response + filename = os.path.basename(query.get("path") or parsed.path) + expanded.append({ + "url": response[field], + "filename": filename + }) + return expanded def get_downloads(self, gogid): """Return all available downloads for a GOG ID""" @@ -333,6 +340,7 @@ class GOGService(OnlineService): "type": download.get("type", "").strip(), "total_size": download.get("total_size", 0), "id": str(download["id"]), + "downlinks": [f.get("downlink") for f in download.get("files") or []] } for download in product["downloads"].get("bonus_content") or [] ] if extras: @@ -382,25 +390,31 @@ class GOGService(OnlineService): if not downlink: logger.error("No download information for %s", game_file) continue - download_info = self.get_download_info(downlink) - for field in ('checksum', 'downlink'): + for info in self.get_download_info(downlink): download_links.append({ "name": download.get("name", ""), "os": download.get("os", ""), "type": download.get("type", ""), "total_size": download.get("total_size", 0), "id": str(game_file["id"]), - "url": download_info[field], - "filename": download_info[field + "_filename"] + "url": info["url"], + "filename": info["filename"] }) return download_links - def get_extra_files(self, downloads, installer, selected_extras): + def get_extra_files(self, installer, selected_extras): extra_files = [] - for extra in downloads["bonus_content"]: - if str(extra["id"]) not in selected_extras: - continue - links = self.query_download_links(extra) + for extra in selected_extras: + if extra.get("downlinks"): + links = [info for link in extra.get("downlinks") for info in self.get_download_info(link)] + elif str(extra["id"]) in selected_extras: + links = self.query_download_links(extra) + else: + links = [] + + if not links: + logger.error("No download link for bonus content '%s' could be obtained.", extra.get("name")) + for link in links: if link["filename"].endswith(".xml"): # GOG gives a link for checksum XML files for bonus content @@ -490,7 +504,7 @@ class GOGService(OnlineService): extra_files = [] if selected_extras: - for extra_file in self.get_extra_files(downloads, installer, selected_extras): + for extra_file in self.get_extra_files(installer, selected_extras): extra_files.append(extra_file) return files, extra_files diff --git a/lutris/services/itchio.py b/lutris/services/itchio.py index 06f9a163a..22d8ac772 100644 --- a/lutris/services/itchio.py +++ b/lutris/services/itchio.py @@ -529,6 +529,7 @@ class ItchIoService(OnlineService): extra_files = [] link = None filename = "setup.zip" + selected_extras_ids = set(x["id"] for x in selected_extras or []) file = next(_file.copy() for _file in installer.script_files if _file.id == installer_file_id) if not file.url.startswith("N/A"): @@ -542,9 +543,9 @@ class ItchIoService(OnlineService): "date": int(datetime.datetime.now().timestamp()) } - if not link or len(selected_extras) > 0: + if not link or len(selected_extras_ids) > 0: for upload in uploads["uploads"]: - if selected_extras and (upload["type"] in self.extra_types): + if selected_extras_ids and (upload["type"] in self.extra_types): extras.append(upload) continue # default = games/tools ("executables") @@ -594,7 +595,7 @@ class ItchIoService(OnlineService): ) for extra in extras: - if str(extra["id"]) not in selected_extras: + if str(extra["id"]) not in selected_extras_ids: continue link = self.get_download_link(extra["id"], key) extra_files.append(