def download(self): """Download DXVK to the local cache""" dxvk_url = self.base_url.format(self.version, self.version) if self.is_available(): logger.warning(self.base_name.upper()+" already available at %s", self.dxvk_path) dxvk_archive_path = os.path.join(self.base_dir, os.path.basename(dxvk_url)) downloader = Downloader(dxvk_url, dxvk_archive_path) downloader.start() while downloader.check_progress() < 1 and downloader.state != downloader.ERROR: time.sleep(0.3) if not system.path_exists(dxvk_archive_path): raise UnavailableDXVKVersion("Failed to download "+self.base_name.upper()+" %s" % self.version) if os.stat(dxvk_archive_path).st_size: extract_archive(dxvk_archive_path, self.dxvk_path, merge_single=True) os.remove(dxvk_archive_path) else: os.remove(dxvk_archive_path) raise UnavailableDXVKVersion("Failed to download "+self.base_name.upper()+" %s" % self.version)
def download(self): """Download DXVK to the local cache""" dxvk_url = self.base_url.format(self.version, self.version) if self.is_available(): logger.warning("DXVK already available at %s", self.dxvk_path) dxvk_archive_path = os.path.join(self.base_dir, os.path.basename(dxvk_url)) downloader = Downloader(dxvk_url, dxvk_archive_path) downloader.start() while downloader.check_progress() < 1: time.sleep(0.3) if not system.path_exists(dxvk_archive_path): logger.error("DXVK %s not downloaded") return if os.stat(dxvk_archive_path).st_size: extract_archive(dxvk_archive_path, self.dxvk_path, merge_single=True) os.remove(dxvk_archive_path) else: os.remove(dxvk_archive_path) raise UnavailableDXVKVersion("Failed to download DXVK %s" % self.version)
def prelaunch(self): if not self.game_config.get("main_file") and self.is_installed(): return True if os.path.exists(os.path.join(settings.RUNNER_DIR, "pico8/cartridges", "tmp.p8.png")): os.remove(os.path.join(settings.RUNNER_DIR, "pico8/cartridges", "tmp.p8.png")) # Don't download cartridge if using web backend and cart is url if self.is_native or not self.game_config.get("main_file").startswith("http"): if not os.path.exists(self.game_config.get("main_file")) and ( self.game_config.get("main_file").isdigit() or self.game_config.get("main_file").startswith("http") ): if not self.game_config.get("main_file").startswith("http"): pid = int(self.game_config.get("main_file")) num = math.floor(pid / 10000) downloadUrl = ("https://www.lexaloffle.com/bbs/cposts/" + str(num) + "/" + str(pid) + ".p8.png") else: downloadUrl = self.game_config.get("main_file") cartPath = self.cart_path system.create_folder(os.path.dirname(cartPath)) downloadCompleted = False def on_downloaded_cart(): nonlocal downloadCompleted # If we are offline we don't want an empty file to overwrite the cartridge if dl.downloaded_size: shutil.move(cartPath + ".download", cartPath) else: os.remove(cartPath + ".download") downloadCompleted = True dl = Downloader( downloadUrl, cartPath + ".download", True, callback=on_downloaded_cart, ) dl.start() # Wait for download to complete or continue if it exists (to work in offline mode) while not os.path.exists(cartPath): if downloadCompleted or dl.state == Downloader.ERROR: logger.error("Could not download cartridge from %s", downloadUrl) return False sleep(0.1) # Download js engine if not self.is_native and not os.path.exists(self.runner_config.get("engine")): enginePath = os.path.join( settings.RUNNER_DIR, "pico8/web/engines", self.runner_config.get("engine") + ".js", ) if not os.path.exists(enginePath): downloadUrl = ("https://www.lexaloffle.com/bbs/" + self.runner_config.get("engine") + ".js") system.create_folder(os.path.dirname(enginePath)) downloadCompleted = False def on_downloaded_engine(): nonlocal downloadCompleted downloadCompleted = True dl = Downloader(downloadUrl, enginePath, True, callback=on_downloaded_engine) dl.start() dl.thread.join() # Doesn't actually wait until finished # Waits for download to complete while not os.path.exists(enginePath): if downloadCompleted or dl.state == Downloader.ERROR: logger.error("Could not download engine from %s", downloadUrl) return False sleep(0.1) return True
class DownloadProgressBox(Gtk.VBox): """Progress bar used to monitor a file download.""" __gsignals__ = { 'complete': (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_PYOBJECT, )), 'cancel': (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_PYOBJECT, )), 'error': (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_PYOBJECT, )), } def __init__(self, params, cancelable=True, downloader=None): super(DownloadProgressBox, self).__init__() self.downloader = downloader self.url = params.get('url') self.dest = params.get('dest') self.referer = params.get('referer') title = params.get('title', "Downloading {}".format(self.url)) self.main_label = Gtk.Label(title) self.main_label.set_alignment(0, 0) self.main_label.set_property('wrap', True) self.main_label.set_margin_bottom(10) self.main_label.set_max_width_chars(70) self.main_label.set_selectable(True) self.main_label.set_property('ellipsize', Pango.EllipsizeMode.MIDDLE) self.pack_start(self.main_label, True, True, 0) progress_box = Gtk.Box() self.progressbar = Gtk.ProgressBar() self.progressbar.set_margin_top(5) self.progressbar.set_margin_bottom(5) self.progressbar.set_margin_right(10) progress_box.pack_start(self.progressbar, True, True, 0) self.cancel_button = Gtk.Button.new_with_mnemonic('_Cancel') self.cancel_button.connect('clicked', self.cancel) if not cancelable: self.cancel_button.set_sensitive(False) progress_box.pack_end(self.cancel_button, False, False, 0) self.pack_start(progress_box, False, False, 0) self.progress_label = Gtk.Label() self.progress_label.set_alignment(0, 0) self.pack_start(self.progress_label, True, True, 0) self.show_all() def start(self): """Start downloading a file.""" if not self.downloader: try: self.downloader = Downloader(self.url, self.dest, referer=self.referer, overwrite=True) except RuntimeError as ex: from lutris.gui.dialogs import ErrorDialog ErrorDialog(ex.args[0]) self.emit('cancel', {}) return timer_id = GLib.timeout_add(100, self._progress) self.cancel_button.set_sensitive(True) if not self.downloader.state == self.downloader.DOWNLOADING: self.downloader.start() return timer_id def cancel(self, _widget=None): """Cancel the current download.""" if self.downloader: self.downloader.cancel() self.cancel_button.set_sensitive(False) self.emit('cancel', {}) def _progress(self): """Show download progress.""" progress = min(self.downloader.check_progress(), 1) if self.downloader.state in [ self.downloader.CANCELLED, self.downloader.ERROR ]: self.progressbar.set_fraction(0) self._set_text("Download interrupted") if self.downloader.state == self.downloader.CANCELLED: self.emit('cancel', {}) return False self.progressbar.set_fraction(progress) megabytes = 1024 * 1024 progress_text = ("%0.2f / %0.2fMB (%0.2fMB/s), %s remaining" % (float(self.downloader.downloaded_size) / megabytes, float(self.downloader.full_size) / megabytes, float(self.downloader.average_speed) / megabytes, self.downloader.time_left)) self._set_text(progress_text) if self.downloader.state == self.downloader.COMPLETED: self.cancel_button.set_sensitive(False) self.emit('complete', {}) return False return True def _set_text(self, text): markup = u"<span size='10000'>{}</span>".format(text) self.progress_label.set_markup(markup)
class DownloadProgressBox(Gtk.Box): """Progress bar used to monitor a file download.""" __gsignals__ = { "complete": (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_PYOBJECT, )), "cancel": (GObject.SignalFlags.RUN_LAST, None, ()), "error": (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_PYOBJECT, )), } def __init__(self, params, cancelable=True, downloader=None): super().__init__(orientation=Gtk.Orientation.VERTICAL) self.downloader = downloader self.is_complete = False self.url = params.get("url") self.dest = params.get("dest") self.referer = params.get("referer") self.main_label = Gtk.Label(self.get_title()) self.main_label.set_alignment(0, 0) self.main_label.set_property("wrap", True) self.main_label.set_margin_bottom(10) # self.main_label.set_max_width_chars(70) self.main_label.set_selectable(True) self.main_label.set_property("ellipsize", Pango.EllipsizeMode.MIDDLE) self.pack_start(self.main_label, True, True, 0) progress_box = Gtk.Box() self.progressbar = Gtk.ProgressBar() self.progressbar.set_margin_top(5) self.progressbar.set_margin_bottom(5) self.progressbar.set_margin_right(10) progress_box.pack_start(self.progressbar, True, True, 0) self.cancel_button = Gtk.Button.new_with_mnemonic(_("_Cancel")) self.cancel_cb_id = self.cancel_button.connect("clicked", self.on_cancel_clicked) if not cancelable: self.cancel_button.set_sensitive(False) progress_box.pack_end(self.cancel_button, False, False, 0) self.pack_start(progress_box, False, False, 0) self.progress_label = Gtk.Label() self.progress_label.set_alignment(0, 0) self.pack_start(self.progress_label, True, True, 0) self.show_all() self.cancel_button.hide() def get_title(self): """Return the main label text for the widget""" parsed = urlparse(self.url) return "%s%s" % (parsed.netloc, parsed.path) def start(self): """Start downloading a file.""" if not self.downloader: try: self.downloader = Downloader(self.url, self.dest, referer=self.referer, overwrite=True) except RuntimeError as ex: from lutris.gui.dialogs import ErrorDialog ErrorDialog(ex.args[0]) self.emit("cancel") return None timer_id = GLib.timeout_add(500, self._progress) self.cancel_button.show() self.cancel_button.set_sensitive(True) if not self.downloader.state == self.downloader.DOWNLOADING: self.downloader.start() return timer_id def set_retry_button(self): """Transform the cancel button into a retry button""" self.cancel_button.set_label(_("Retry")) self.cancel_button.disconnect(self.cancel_cb_id) self.cancel_cb_id = self.cancel_button.connect("clicked", self.on_retry_clicked) self.cancel_button.set_sensitive(True) def on_retry_clicked(self, button): logger.debug("Retrying download") button.set_label(_("Cancel")) button.disconnect(self.cancel_cb_id) self.cancel_cb_id = button.connect("clicked", self.on_cancel_clicked) self.downloader.reset() self.start() def on_cancel_clicked(self, _widget=None): """Cancel the current download.""" logger.debug("Download cancel requested") if self.downloader: self.downloader.cancel() self.cancel_button.set_sensitive(False) self.emit("cancel") def _progress(self): """Show download progress.""" progress = min(self.downloader.check_progress(), 1) if self.downloader.state in [self.downloader.CANCELLED, self.downloader.ERROR]: self.progressbar.set_fraction(0) if self.downloader.state == self.downloader.CANCELLED: self._set_text(_("Download interrupted")) self.emit("cancel") else: self._set_text(str(self.downloader.error)[:80]) return False self.progressbar.set_fraction(progress) megabytes = 1024 * 1024 progress_text = _( "{downloaded:0.2f} / {size:0.2f}MB ({speed:0.2f}MB/s), {time} remaining" ).format( downloaded=float(self.downloader.downloaded_size) / megabytes, size=float(self.downloader.full_size) / megabytes, speed=float(self.downloader.average_speed) / megabytes, time=self.downloader.time_left, ) self._set_text(progress_text) if self.downloader.state == self.downloader.COMPLETED: self.cancel_button.set_sensitive(False) self.is_complete = True self.emit("complete", {}) return False return True def _set_text(self, text): markup = "<span size='10000'>{}</span>".format(gtk_safe(text)) self.progress_label.set_markup(markup)
class DownloadProgressBox(Gtk.Box): """Progress bar used to monitor a file download.""" __gsignals__ = { "complete": (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_PYOBJECT,)), "cancel": (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_PYOBJECT,)), "error": (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_PYOBJECT,)), } def __init__(self, params, cancelable=True, downloader=None): super().__init__(orientation=Gtk.Orientation.VERTICAL) self.downloader = downloader self.url = params.get("url") self.dest = params.get("dest") self.referer = params.get("referer") title = params.get("title", "Downloading {}".format(self.url)) self.main_label = Gtk.Label(title) self.main_label.set_alignment(0, 0) self.main_label.set_property("wrap", True) self.main_label.set_margin_bottom(10) self.main_label.set_max_width_chars(70) self.main_label.set_selectable(True) self.main_label.set_property("ellipsize", Pango.EllipsizeMode.MIDDLE) self.pack_start(self.main_label, True, True, 0) progress_box = Gtk.Box() self.progressbar = Gtk.ProgressBar() self.progressbar.set_margin_top(5) self.progressbar.set_margin_bottom(5) self.progressbar.set_margin_right(10) progress_box.pack_start(self.progressbar, True, True, 0) self.cancel_button = Gtk.Button.new_with_mnemonic("_Cancel") self.cancel_button.connect("clicked", self.cancel) if not cancelable: self.cancel_button.set_sensitive(False) progress_box.pack_end(self.cancel_button, False, False, 0) self.pack_start(progress_box, False, False, 0) self.progress_label = Gtk.Label() self.progress_label.set_alignment(0, 0) self.pack_start(self.progress_label, True, True, 0) self.show_all() def start(self): """Start downloading a file.""" if not self.downloader: try: self.downloader = Downloader( self.url, self.dest, referer=self.referer, overwrite=True ) except RuntimeError as ex: from lutris.gui.dialogs import ErrorDialog ErrorDialog(ex.args[0]) self.emit("cancel", {}) return None timer_id = GLib.timeout_add(500, self._progress) self.cancel_button.set_sensitive(True) if not self.downloader.state == self.downloader.DOWNLOADING: self.downloader.start() return timer_id def cancel(self, _widget=None): """Cancel the current download.""" if self.downloader: self.downloader.cancel() self.cancel_button.set_sensitive(False) self.emit("cancel", {}) def _progress(self): """Show download progress.""" progress = min(self.downloader.check_progress(), 1) if self.downloader.state in [self.downloader.CANCELLED, self.downloader.ERROR]: self.progressbar.set_fraction(0) if self.downloader.state == self.downloader.CANCELLED: self._set_text("Download interrupted") else: self._set_text(self.downloader.error) if self.downloader.state == self.downloader.CANCELLED: self.emit("cancel", {}) return False self.progressbar.set_fraction(progress) megabytes = 1024 * 1024 progress_text = "%0.2f / %0.2fMB (%0.2fMB/s), %s remaining" % ( float(self.downloader.downloaded_size) / megabytes, float(self.downloader.full_size) / megabytes, float(self.downloader.average_speed) / megabytes, self.downloader.time_left, ) self._set_text(progress_text) if self.downloader.state == self.downloader.COMPLETED: self.cancel_button.set_sensitive(False) self.emit("complete", {}) return False return True def _set_text(self, text): markup = u"<span size='10000'>{}</span>".format(text) self.progress_label.set_markup(markup)