mirror of
https://github.com/lutris/lutris
synced 2024-10-14 19:53:53 +00:00
Enable download of DLC extras from GOG.
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.
This commit is contained in:
parent
37d81a1cd6
commit
a3e36e1650
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue