def get_installer_files(self, installer, installer_file_id): steam_uri = "$WINESTEAM:%s:." if installer.runner == "winesteam" else "$STEAM:%s:." appid = str(installer.script["game"]["appid"]) return [ InstallerFile(installer.game_slug, "steam_game", { "url": steam_uri % appid, "filename": appid }) ]
def get_installer_files(self, installer, installer_file_id): try: downloads = self.get_downloads(installer.service_appid) gog_installers = self.get_installers(downloads, installer.runner) if not gog_installers: return [] if len(gog_installers) > 1: logger.warning( "More than 1 GOG installer found, picking first.") _installer = gog_installers[0] links = self.query_download_links(_installer) except HTTPError: raise UnavailableGame( "Couldn't load the download links for this game") if not links: raise UnavailableGame("Could not fing GOG game") _installer_files = defaultdict(dict) # keyed by filename for link in links: filename = link["filename"] if filename.lower().endswith(".xml"): if filename != installer_file_id: filename = filename[:-4] _installer_files[filename]["checksum_url"] = link["url"] continue _installer_files[filename]["id"] = link["id"] _installer_files[filename]["url"] = link["url"] _installer_files[filename]["filename"] = filename _installer_files[filename]["total_size"] = link["total_size"] files = [] file_id_provided = False # Only assign installer_file_id once for _file_id in _installer_files: installer_file = _installer_files[_file_id] if "url" not in installer_file: raise ValueError("Invalid installer file %s" % installer_file) filename = installer_file["filename"] if filename.lower().endswith( (".exe", ".sh")) and not file_id_provided: file_id = installer_file_id file_id_provided = True else: file_id = _file_id files.append( InstallerFile( installer.game_slug, file_id, { "url": installer_file["url"], "filename": installer_file["filename"], "checksum_url": installer_file.get("checksum_url") })) if not file_id_provided: raise UnavailableGame( "Unable to determine correct file to launch installer") if self.selected_extras: for extra_file in self.get_extra_files(downloads, installer): files.append(extra_file) return files
def get_installer_files(self, installer, installer_file_id): if not self.is_connected(): self.login() if not self.is_connected(): logger.warning("Not connected to GOG, not returning any files") return [] try: downloads = self.get_downloads(installer.service_appid) gog_installers = self.get_installers(downloads, installer.runner) if not gog_installers: return [] if len(gog_installers) > 1: logger.warning( "More than 1 GOG installer found, picking first.") _installer = gog_installers[0] links = self.query_download_links(_installer) except HTTPError: raise UnavailableGame( "Couldn't load the download links for this game") if not links: raise UnavailableGame("Could not fing GOG game") files = [] file_id_provided = False # Only assign installer_file_id once for index, link in enumerate(links): if isinstance(link, dict): url = link["url"] else: url = link filename = link["filename"] if filename.lower().endswith( (".exe", ".sh")) and not file_id_provided: file_id = installer_file_id file_id_provided = True else: file_id = "gog_file_%s" % index files.append( InstallerFile(installer.game_slug, file_id, { "url": url, "filename": filename, })) if not file_id_provided: raise UnavailableGame( "Unable to determine correct file to launch installer") if self.selected_extras: for extra_file in self.get_extra_files(downloads, installer): files.append(extra_file) return files
def get_installer_files(self, installer, installer_file_id): """Replace the user provided file with download links from Humble Bundle""" try: link = get_humble_download_link(installer.service_appid, installer.runner) except Exception as ex: logger.exception("Failed to get Humble Bundle game: %s", ex) raise UnavailableGame if not link: raise UnavailableGame("No game found on Humble Bundle") filename = link.split("?")[0].split("/")[-1] return [ InstallerFile(installer.game_slug, installer_file_id, { "url": link, "filename": filename }) ]
def get_extra_files(self, downloads, installer): extra_files = [] for extra in downloads["bonus_content"]: if str(extra["id"]) not in self.selected_extras: continue links = self.query_download_links(extra) for link in links: if link["filename"].endswith(".xml"): # GOG gives a link for checksum XML files for bonus content # but downloading them results in a 404 error. continue extra_files.append( InstallerFile(installer.game_slug, str(extra["id"]), { "url": link["url"], "filename": link["filename"], })) return extra_files
def __init__(self, installer, interpreter, service, appid): self.interpreter = interpreter self.installer = installer self.version = installer["version"] self.slug = installer["slug"] self.year = installer.get("year") self.runner = installer["runner"] self.script = installer.get("script") self.game_name = self.script.get("custom-name") or installer["name"] self.game_slug = installer["game_slug"] self.service = self.get_service(initial=service) self.service_appid = self.get_appid(installer, initial=appid) self.files = [ InstallerFile(self.game_slug, file_id, file_meta) for file_desc in self.script.get("files", []) for file_id, file_meta in file_desc.items() ] self.requires = self.script.get("requires") self.extends = self.script.get("extends") self.game_id = self.get_game_id()
def _format_links(self, installer, installer_file_id, links): _installer_files = defaultdict(dict) # keyed by filename for link in links: try: filename = link["filename"] except KeyError: logger.error("Invalid link: %s", link) raise if filename.lower().endswith(".xml"): if filename != installer_file_id: filename = filename[:-4] _installer_files[filename]["checksum_url"] = link["url"] continue _installer_files[filename]["id"] = link["id"] _installer_files[filename]["url"] = link["url"] _installer_files[filename]["filename"] = filename _installer_files[filename]["total_size"] = link["total_size"] files = [] file_id_provided = False # Only assign installer_file_id once for _file_id in _installer_files: installer_file = _installer_files[_file_id] if "url" not in installer_file: raise ValueError("Invalid installer file %s" % installer_file) filename = installer_file["filename"] if filename.lower().endswith( (".exe", ".sh")) and not file_id_provided: file_id = installer_file_id file_id_provided = True else: file_id = _file_id files.append( InstallerFile( installer.game_slug, file_id, { "url": installer_file["url"], "filename": installer_file["filename"], "checksum_url": installer_file.get("checksum_url") })) if not file_id_provided: raise UnavailableGame( "Unable to determine correct file to launch installer") return files
def swap_humble_game_files(self): """Replace the user provided file with download links from Humble Bundle""" if not self.humbleid: raise UnavailableGame("This installer has no Humble Bundle ID ('humbleid' in the game section)") installer_file_id = self.pop_user_provided_file() if not installer_file_id: raise UnavailableGame("Installer has no user provided file") try: link = get_humble_download_link(self.humbleid, self.runner) except Exception as ex: logger.exception("Failed to get Humble Bundle game: %s", ex) raise UnavailableGame if not link: raise UnavailableGame("No game found on Humble Bundle") filename = link.split("?")[0].split("/")[-1] self.files.append( InstallerFile(self.game_slug, installer_file_id, { "url": link, "filename": filename }) )
def swap_gog_game_files(self): if not self.gogid: raise UnavailableGame("The installer has no GOG ID!") try: links = self.get_gog_download_links() except HTTPError: raise UnavailableGame( "Couldn't load the download links for this game") installer_file_id = None if links: for index, file in enumerate(self.files): file_id = file.id if file.url.startswith("N/A"): logger.debug("Removing file %s", file.id) self.files.pop(index) installer_file_id = file.id break if not installer_file_id: raise ScriptingError( "Could not match a GOG installer file in the files") file_id_provided = False # Only assign installer_file_id once for index, link in enumerate(links): filename = link.split("?")[0].split("/")[-1] if filename.lower().endswith( (".exe", ".sh")) and not file_id_provided: file_id = installer_file_id file_id_provided = True else: file_id = "gog_file_%s" % index logger.debug("Adding GOG file %s as %s", filename, file_id) self.files.append( InstallerFile(self.game_slug, file_id, { "url": link, "filename": filename, }))
def prepare_game_files(self, patch_version=None): """Gathers necessary files before iterating through them.""" if not self.files: logger.info("No files to prepare") return if not self.service: logger.debug("No service to retrieve files from") return if self.service.online and not self.service.is_connected(): logger.info("Not authenticated to %s", self.service.id) return installer_file_id = self.pop_user_provided_file() if not installer_file_id: logger.warning("Could not find a file for this service") return logger.info("Getting files for %s", installer_file_id) if self.service.has_extras: logger.info("Adding selected extras to downloads") self.service.selected_extras = self.interpreter.extras if patch_version: # 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: installer_files = self.service.get_installer_files( self, installer_file_id) for installer_file in installer_files: self.files.append(installer_file) if not installer_files: # Failed to get the service game, put back a user provided file logger.debug( "Unable to get files from service. Setting %s to manual.", installer_file_id) self.files.insert( 0, InstallerFile(self.game_slug, installer_file_id, { "url": "N/A: Provider installer file", "filename": "" }))
def __init__(self, installer, interpreter): self.interpreter = interpreter self.version = installer["version"] self.slug = installer["slug"] self.year = installer.get("year") self.runner = installer["runner"] self.script = installer.get("script") self.game_name = self.script.get("custom-name") or installer["name"] self.game_slug = installer["game_slug"] self.steamid = installer.get("steamid") game_config = self.script.get("game", {}) self.gogid = game_config.get("gogid") or installer.get("gogid") self.humbleid = game_config.get("humbleid") or installer.get("humblestoreid") self.files = [ InstallerFile(self.game_slug, file_id, file_meta) for file_desc in self.script.get("files", []) for file_id, file_meta in file_desc.items() ] self.requires = self.script.get("requires") self.extends = self.script.get("extends") self.game_id = self.get_game_id()
def swap_gog_game_files(self): """Replace user provided file with downloads from GOG""" logger.info("Swap GOG game files") if not self.gogid: raise UnavailableGame("The installer has no GOG ID!") try: links = get_gog_download_links(self.gogid, self.runner) except HTTPError: raise UnavailableGame( "Couldn't load the download links for this game") except MultipleInstallerError: raise UnavailableGame( "Don't know how to deal with multiple installers yet.") if not links: raise UnavailableGame("Could not fing GOG game") installer_file_id = self.pop_user_provided_file() if not installer_file_id: raise UnavailableGame("Installer has no user provided file") file_id_provided = False # Only assign installer_file_id once for index, link in enumerate(links): if isinstance(link, dict): url = link["url"] else: url = link filename = url.split("?")[0].split("/")[-1] if filename.lower().endswith( (".exe", ".sh")) and not file_id_provided: file_id = installer_file_id file_id_provided = True else: file_id = "gog_file_%s" % index self.files.append( InstallerFile(self.game_slug, file_id, { "url": url, "filename": filename, }))
def prepare_game_files(self): """Gathers necessary files before iterating through them.""" # If this is a GOG installer, download required files. version = self.version.lower() if version.startswith("gog"): logger.debug("GOG game detected") try: self.swap_gog_game_files() except UnavailableGame as ex: logger.error("Unable to get the game from GOG: %s", ex) if version.startswith("humble"): try: self.swap_humble_game_files() except UnavailableGame as ex: logger.error("Unable to get the game from GOG: %s", ex) if self.runner in ("steam", "winesteam"): steam_uri = "$WINESTEAM:%s:." if self.runner == "winesteam" else "$STEAM:%s:." appid = str(self.script["game"]["appid"]) self.files.append( InstallerFile(self.game_slug, "steam_game", { "url": steam_uri % appid, "filename": appid }))
def __init__(self, installer, parent): self.error = None self.errors = [] self.target_path = None self.parent = parent self.game_dir_created = False # Whether a game folder was created during the install self.game_files = {} self.game_disc = None self.cancelled = False self.abort_current_task = None self.user_inputs = [] self.steam_data = {} self.gog_data = {} self.script = installer.get("script") if not self.script: raise ScriptingError( "This installer doesn't have a 'script' section") self.script_pretty = json.dumps(self.script, indent=4) self.install_start_time = None # Time of the start of the install self.steam_poll = None # Reference to the Steam poller that checks if games are downloaded self.current_command = None # Current installer command when iterating through them self.current_file_id = None # Current file when downloading / gathering files self.runners_to_install = [] self.prev_states = [] # Previous states for the Steam installer self.version = installer["version"] self.slug = installer["slug"] self.year = installer.get("year") self.runner = installer["runner"] self.game_name = self.script.get("custom-name") or installer["name"] self.game_slug = installer["game_slug"] self.steamid = installer.get("steamid") self.gogid = installer.get("gogid") if not self.is_valid(): raise ScriptingError( "Invalid script: \n{}".format("\n".join(self.errors)), self.script) self.files = [ InstallerFile(self.game_slug, file_id, file_meta) for file_desc in self.script.get("files", []) for file_id, file_meta in file_desc.items() ] self.requires = self.script.get("requires") self.extends = self.script.get("extends") self.current_resolution = DISPLAY_MANAGER.get_current_resolution() self._check_binary_dependencies() self._check_dependency() if self.creates_game_folder: self.target_path = self.get_default_target() # If the game is in the library and uninstalled, the first installation # updates it existing_game = pga.get_game_by_field(self.game_slug, "slug") if existing_game and not existing_game["installed"]: self.game_id = existing_game["id"] else: self.game_id = None