diff --git a/legendary/core.py b/legendary/core.py index 0934e19..0950c8f 100644 --- a/legendary/core.py +++ b/legendary/core.py @@ -18,7 +18,8 @@ from typing import List, Dict from uuid import uuid4 from legendary.api.egs import EPCAPI -from legendary.downloader.manager import DLManager +#from legendary.downloader.manager import DLManager +from legendary.gui.manager2 import DLManager from legendary.lfs.egl import EPCLFS from legendary.lfs.lgndry import LGDLFS from legendary.utils.lfs import clean_filename, delete_folder, delete_filelist @@ -705,9 +706,10 @@ class LegendaryCore: dl_optimizations: bool = False, dl_timeout: int = 10, repair: bool = False, repair_use_latest: bool = False, disable_delta: bool = False, override_delta_manifest: str = '', - egl_guid: str = '', main_window="cli") -> (DLManager, AnalysisResult, ManifestMeta): + egl_guid: str = '', main_window = "cli") -> (DLManager, AnalysisResult, ManifestMeta): # load old manifest old_manifest = None + print("prepare",main_window.get_title()) # load old manifest if we have one if override_old_manifest: diff --git a/legendary/downloader/log_dlm.py b/legendary/downloader/log_dlm.py index 97deafc..4ebb0bc 100644 --- a/legendary/downloader/log_dlm.py +++ b/legendary/downloader/log_dlm.py @@ -1,10 +1,16 @@ +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + class log_dlm: - def create(main_window): + def create(self, main_window): if main_window == "cli": + print(main_window) return "cli" else: bar = Gtk.ProgressBar() main_window.login_vbox.pack_end(bar, False, False, 10) + print(main_window) return bar def update(self, perc, processed_chunks, num_chunk_tasks, rt_hours, rt_minutes, rt_seconds, hours, minutes, seconds, total_dl, total_write, total_used, dl_speed, dl_unc_speed, w_speed, r_speed, obj_out): @@ -50,6 +56,7 @@ class log_dlm: def update_gui(self, perc, processed_chunks, num_chunk_tasks, rt_hours, rt_minutes, rt_seconds, hours, minutes, seconds, total_dl, total_write, total_used, dl_speed, dl_unc_speed, w_speed, r_speed, bar): bar.set_fraction(perc) bar.set_text(f"{dl_speed / 1024 / 1024:.02f} MiB/s - {(perc*100):.02f}% - ETA: {hours:02d}:{minutes:02d}:{seconds:02d}") + print(bar.get_text()) def update_cli(self, perc, processed_chunks, num_chunk_tasks, rt_hours, rt_minutes, rt_seconds, hours, minutes, seconds, total_dl, total_write, total_used, dl_speed, dl_unc_speed, w_speed, r_speed): perc *= 100 @@ -67,36 +74,22 @@ class log_dlm: - def init(parent): - bar = Gtk.ProgressBar() - parent.login_vbox.pack_end(bar, False, False, 10) - return bar - def update(self, perc, processed_chunks, num_chunk_tasks, rt_hours, rt_minutes, rt_seconds, hours, minutes, seconds, total_dl, total_write, total_used, dl_speed, dl_unc_speed, w_speed, r_speed): - self. - f'= Progress: {perc:.02f}% ({processed_chunks}/{num_chunk_tasks}), ' - f'Running for {rt_hours:02d}:{rt_minutes:02d}:{rt_seconds:02d}, ' - f'ETA: {hours:02d}:{minutes:02d}:{seconds:02d}') - f' - Downloaded: {total_dl / 1024 / 1024:.02f} MiB, ' - f'Written: {total_write / 1024 / 1024:.02f} MiB') - f' - Cache usage: {total_used} MiB, active tasks: {self.active_tasks}') - f' + Download\t- {dl_speed / 1024 / 1024:.02f} MiB/s (raw) ' - f'/ {dl_unc_speed / 1024 / 1024:.02f} MiB/s (decompressed)') - f' + Disk\t- {w_speed / 1024 / 1024:.02f} MiB/s (write) / ' - f'{r_speed / 1024 / 1024:.02f} MiB/s (read)') - self.log.info(f'= Progress: {perc:.02f}% ({processed_chunks}/{num_chunk_tasks}), ' - f'Running for {rt_hours:02d}:{rt_minutes:02d}:{rt_seconds:02d}, ' - f'ETA: {hours:02d}:{minutes:02d}:{seconds:02d}') - self.log.info(f' - Downloaded: {total_dl / 1024 / 1024:.02f} MiB, ' - f'Written: {total_write / 1024 / 1024:.02f} MiB') - self.log.info(f' - Cache usage: {total_used} MiB, active tasks: {self.active_tasks}') - self.log.info(f' + Download\t- {dl_speed / 1024 / 1024:.02f} MiB/s (raw) ' - f'/ {dl_unc_speed / 1024 / 1024:.02f} MiB/s (decompressed)') - self.log.info(f' + Disk\t- {w_speed / 1024 / 1024:.02f} MiB/s (write) / ' - f'{r_speed / 1024 / 1024:.02f} MiB/s (read)') + +# +# self.log.info(f'= Progress: {perc:.02f}% ({processed_chunks}/{num_chunk_tasks}), ' +# f'Running for {rt_hours:02d}:{rt_minutes:02d}:{rt_seconds:02d}, ' +# f'ETA: {hours:02d}:{minutes:02d}:{seconds:02d}') +# self.log.info(f' - Downloaded: {total_dl / 1024 / 1024:.02f} MiB, ' +# f'Written: {total_write / 1024 / 1024:.02f} MiB') +# self.log.info(f' - Cache usage: {total_used} MiB, active tasks: {self.active_tasks}') +# self.log.info(f' + Download\t- {dl_speed / 1024 / 1024:.02f} MiB/s (raw) ' +# f'/ {dl_unc_speed / 1024 / 1024:.02f} MiB/s (decompressed)') +# self.log.info(f' + Disk\t- {w_speed / 1024 / 1024:.02f} MiB/s (write) / ' +# f'{r_speed / 1024 / 1024:.02f} MiB/s (read)') diff --git a/legendary/downloader/workers.py b/legendary/downloader/workers.py index 8f34e83..2e8ac49 100644 --- a/legendary/downloader/workers.py +++ b/legendary/downloader/workers.py @@ -138,6 +138,7 @@ class FileWorker(Process): logger = logging.getLogger(self.name) logger.setLevel(self.log_level) logger.debug(f'Download worker reporting for duty!') + print(f'Download worker reporting for duty! {self.name}') last_filename = '' current_file = None @@ -145,7 +146,9 @@ class FileWorker(Process): while True: try: try: - j = self.q.get(timeout=10.0) + print(f'j = self.q.get - {self.name}') + #j = self.q.get(timeout=10.0) + j = self.q.get(timeout=0.5) except Empty: logger.warning('Writer queue empty!') continue diff --git a/legendary/gui/gui.py b/legendary/gui/gui.py index 8a35261..21dda48 100755 --- a/legendary/gui/gui.py +++ b/legendary/gui/gui.py @@ -1,11 +1,21 @@ #!/usr/bin/env python3 -import gi +import sys +# insert at 1, 0 is the script path (or '' in REPL) +sys.path.insert(1, '../..') + import webbrowser +import time +from multiprocessing import freeze_support, Queue as MPQueue + +import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk + import legendary.core +import legendary.cli core = legendary.core.LegendaryCore() +cli = legendary.cli.LegendaryCLI() class args_obj: base_path = '' @@ -566,7 +576,7 @@ def install_gtk(app_name, app_title, parent): f"reset_sdl:\t\t {args.reset_sdl}", sep='\n' ) - return 1 + #return 1 # TODO: if install_dialog_response != Gtk.ResponseType.OK: @@ -577,7 +587,7 @@ def install_gtk(app_name, app_title, parent): if igame.needs_verification: repair_mode = True repair_file = None - if repair_mode: + if args.repair_mode: args.no_install = args.repair_and_update is False repair_file = os.path.join(core.lgd.get_tmp_path(), f'{app_name}.repair') @@ -643,7 +653,7 @@ def install_gtk(app_name, app_title, parent): # else: # args.install_tag = config_tags.split(',') - log_gtk('Preparing download...') + print('Preparing download...') # todo use status queue to print progress from CLI # This has become a little ridiculous hasn't it? dlm, analysis, igame = core.prepare_download(game=game, base_game=base_game, base_path=args.base_path, @@ -662,7 +672,7 @@ def install_gtk(app_name, app_title, parent): repair=args.repair_mode, repair_use_latest=args.repair_and_update, disable_delta=args.disable_delta, - override_delta_manifest=args.override_delta_manifest + override_delta_manifest=args.override_delta_manifest, main_window=parent) # game is either up to date or hasn't changed, so we have nothing to do @@ -680,21 +690,21 @@ def install_gtk(app_name, app_title, parent): # check if install tags have changed, if they did; try deleting files that are no longer required. if old_igame and old_igame.install_tags != igame.install_tags: old_igame.install_tags = igame.install_tags - self.log_gtk('Deleting now untagged files.') + log_gtk('Deleting now untagged files.') core.uninstall_tag(old_igame) core.install_game(old_igame) exit(0) - log_gtk(f'Install size: {analysis.install_size / 1024 / 1024:.02f} MiB') + print(f'Install size: {analysis.install_size / 1024 / 1024:.02f} MiB') compression = (1 - (analysis.dl_size / analysis.uncompressed_dl_size)) * 100 - log_gtk(f'Download size: {analysis.dl_size / 1024 / 1024:.02f} MiB ' + print(f'Download size: {analysis.dl_size / 1024 / 1024:.02f} MiB ' f'(Compression savings: {compression:.01f}%)') - log_gtk(f'Reusable size: {analysis.reuse_size / 1024 / 1024:.02f} MiB (chunks) / ' + print(f'Reusable size: {analysis.reuse_size / 1024 / 1024:.02f} MiB (chunks) / ' f'{analysis.unchanged / 1024 / 1024:.02f} MiB (unchanged / skipped)') res = core.check_installation_conditions(analysis=analysis, install=igame, game=game, - updating=self.core.is_installed(app_name), + updating=core.is_installed(app_name), ignore_space_req=args.ignore_space) if res.warnings or res.failures: @@ -710,16 +720,17 @@ def install_gtk(app_name, app_title, parent): log_gtk('Installation cannot proceed, exiting.') exit(1) - log_gtk('Downloads are resumable, you can interrupt the download with ' + print('Downloads are resumable, you can interrupt the download with ' 'CTRL-C and resume it using the same command later on.') start_t = time.time() try: # set up logging stuff (should be moved somewhere else later) - dlm.logging_queue = self.logging_queue + dlm.logging_queue = cli.logging_queue dlm.proc_debug = args.dlm_debug + #print("parent:",parent) dlm.start() dlm.join() except Exception as e: @@ -728,60 +739,60 @@ def install_gtk(app_name, app_title, parent): f'The following exception occurred while waiting for the downloader to finish: {e!r}. ' f'Try restarting the process, the resume file will be used to start where it failed. ' f'If it continues to fail please open an issue on GitHub.') - else: - end_t = time.time() - if not args.no_install: - # Allow setting savegame directory at install time so sync-saves will work immediately - if game.supports_cloud_saves and args.save_path: - igame.save_path = args.save_path + #else: + # end_t = time.time() + # if not args.no_install: + # # Allow setting savegame directory at install time so sync-saves will work immediately + # if game.supports_cloud_saves and args.save_path: + # igame.save_path = args.save_path - postinstall = self.core.install_game(igame) - if postinstall: - self._handle_postinstall(postinstall, igame, yes=args.yes) + # postinstall = self.core.install_game(igame) + # if postinstall: + # self._handle_postinstall(postinstall, igame, yes=args.yes) - dlcs = self.core.get_dlc_for_game(game.app_name) - if dlcs: - print('The following DLCs are available for this game:') - for dlc in dlcs: - print(f' - {dlc.app_title} (App name: {dlc.app_name}, version: {dlc.app_version})') - print('Manually installing DLCs works the same; just use the DLC app name instead.') + # dlcs = self.core.get_dlc_for_game(game.app_name) + # if dlcs: + # print('The following DLCs are available for this game:') + # for dlc in dlcs: + # print(f' - {dlc.app_title} (App name: {dlc.app_name}, version: {dlc.app_version})') + # print('Manually installing DLCs works the same; just use the DLC app name instead.') - install_dlcs = True - if not args.yes: - if not get_boolean_choice(f'Do you wish to automatically install DLCs?'): - install_dlcs = False + # install_dlcs = True + # if not args.yes: + # if not get_boolean_choice(f'Do you wish to automatically install DLCs?'): + # install_dlcs = False - if install_dlcs: - _yes, _app_name = args.yes, app_name - args.yes = True - for dlc in dlcs: - app_name = dlc.app_name - self.install_game(args) - args.yes, app_name = _yes, _app_name + # if install_dlcs: + # _yes, _app_name = args.yes, app_name + # args.yes = True + # for dlc in dlcs: + # app_name = dlc.app_name + # self.install_game(args) + # args.yes, app_name = _yes, _app_name - if game.supports_cloud_saves and not game.is_dlc: - # todo option to automatically download saves after the installation - # args does not have the required attributes for sync_saves in here, - # not sure how to solve that elegantly. - log_gtk(f'This game supports cloud saves, syncing is handled by the "sync-saves" command.To download saves for this game run "legendary sync-saves {app_name}"') + # if game.supports_cloud_saves and not game.is_dlc: + # # todo option to automatically download saves after the installation + # # args does not have the required attributes for sync_saves in here, + # # not sure how to solve that elegantly. + # log_gtk(f'This game supports cloud saves, syncing is handled by the "sync-saves" command.To download saves for this game run "legendary sync-saves {app_name}"') - old_igame = self.core.get_installed_game(game.app_name) - if old_igame and args.repair_mode and os.path.exists(repair_file): - if old_igame.needs_verification: - old_igame.needs_verification = False - self.core.install_game(old_igame) + # old_igame = self.core.get_installed_game(game.app_name) + # if old_igame and args.repair_mode and os.path.exists(repair_file): + # if old_igame.needs_verification: + # old_igame.needs_verification = False + # self.core.install_game(old_igame) - log_gtk('Removing repair file.') - os.remove(repair_file) + # log_gtk('Removing repair file.') + # os.remove(repair_file) - # check if install tags have changed, if they did; try deleting files that are no longer required. - if old_igame and old_igame.install_tags != igame.install_tags: - old_igame.install_tags = igame.install_tags - log_gtk('Deleting now untagged files.') - core.uninstall_tag(old_igame) - core.install_game(old_igame) + # # check if install tags have changed, if they did; try deleting files that are no longer required. + # if old_igame and old_igame.install_tags != igame.install_tags: + # old_igame.install_tags = igame.install_tags + # log_gtk('Deleting now untagged files.') + # core.uninstall_tag(old_igame) + # core.install_game(old_igame) - log_gtk(f'Finished installation process in {end_t - start_t:.02f} seconds.') + # log_gtk(f'Finished installation process in {end_t - start_t:.02f} seconds.') class main_window(Gtk.Window): def __init__(self): diff --git a/legendary/gui/manager2.py b/legendary/gui/manager2.py index 4164c2e..a994027 100644 --- a/legendary/gui/manager2.py +++ b/legendary/gui/manager2.py @@ -17,13 +17,17 @@ from threading import Condition, Thread from legendary.downloader.workers import DLWorker, FileWorker from legendary.models.downloading import * from legendary.models.manifest import ManifestComparison, Manifest +from legendary.downloader.log_dlm import log_dlm +log_dlm = log_dlm() class DLManager(Process): def __init__(self, download_dir, base_url, cache_dir=None, status_q=None, max_workers=0, update_interval=1.0, dl_timeout=10, resume_file=None, max_shared_memory=1024 * 1024 * 1024, main_window="cli"): super().__init__(name='DLManager') + print("plip",main_window.get_title()) + self.main_window = main_window self.log = logging.getLogger('DLM') self.proc_debug = False @@ -577,7 +581,7 @@ class DLManager(Process): self.log.info(f'Download Manager running with process-id: {os.getpid()}') try: - self.run_real(main_window) + self.run_real(self.main_window) except KeyboardInterrupt: self.log.warning('Immediate exit requested!') self.running = False @@ -616,6 +620,9 @@ class DLManager(Process): self.log.debug(f'Created {len(self.sms)} shared memory segments.') + obj_out = log_dlm.create(main_window) + print("created obj_out") + # Create queues self.dl_worker_queue = MPQueue(-1) self.writer_queue = MPQueue(-1) @@ -634,7 +641,9 @@ class DLManager(Process): writer_p = FileWorker(self.writer_queue, self.writer_result_q, self.dl_dir, self.shared_memory.name, self.cache_dir, self.logging_queue) self.children.append(writer_p) + print("created obj_ou1t") writer_p.start() + print("created obj_ou2t") num_chunk_tasks = sum(isinstance(t, ChunkTask) for t in self.tasks) num_dl_tasks = len(self.chunks_to_dl) @@ -660,8 +669,6 @@ class DLManager(Process): self.threads.append(Thread(target=self.dl_results_handler, args=(task_cond,))) self.threads.append(Thread(target=self.fw_results_handler, args=(shm_cond,))) - obj_out = log_dlm.create(main_window) - for t in self.threads: t.start() @@ -728,6 +735,7 @@ class DLManager(Process): r_speed, obj_out ) + print("updated obj_out") # send status update to back to instantiator (if queue exists) if self.status_queue: