1
0
Fork 0
mirror of synced 2024-06-23 08:40:45 +12:00

Move all download preparations inside InstallDialog.

InstallDialog now returns a InstallQueueItemModel ready
to be downloaded or queued.

Renamed a few model attributes to match legendary's names.

InstallDialog can be run silently for auto-downloads.
This commit is contained in:
Stelios Tsampas 2021-05-23 15:15:36 +03:00
parent 376d3e0eba
commit b0ec5c5fcb
5 changed files with 100 additions and 108 deletions

View file

@ -1,4 +1,5 @@
import os
from multiprocessing import Queue as MPQueue
from PyQt5.QtCore import Qt, QObject, QRunnable, QThreadPool, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QDialog, QFileDialog, QCheckBox
@ -7,21 +8,22 @@ from custom_legendary.core import LegendaryCore
from custom_legendary.utils.selective_dl import games
from rare.ui.components.dialogs.install_dialog import Ui_InstallDialog
from rare.utils.extra_widgets import PathEdit
from rare.utils.models import InstallOptionsModel
from rare.utils.models import InstallDownloadModel, InstallQueueItemModel
from rare.utils.utils import get_size
class InstallDialog(QDialog, Ui_InstallDialog):
options = False
def __init__(self, app_name, core: LegendaryCore, update=False, parent=None):
def __init__(self, core: LegendaryCore, dl_item: InstallQueueItemModel, update=False, parent=None):
super(InstallDialog, self).__init__(parent)
self.setAttribute(Qt.WA_DeleteOnClose, True)
self.setupUi(self)
self.core = core
self.app_name = app_name
self.game = self.core.get_game(app_name)
self.dl_item = dl_item
self.dl_item.status_q = MPQueue()
self.app_name = self.dl_item.options.app_name
self.game = self.core.get_game(self.app_name)
self.update_game = update
self.threadpool = QThreadPool(self)
@ -54,12 +56,11 @@ class InstallDialog(QDialog, Ui_InstallDialog):
self.max_workers_spin.setValue(int(max_workers))
self.sdl_list_checks = list()
self.tags = ['']
try:
for key, info in games[app_name].items():
for key, info in games[self.app_name].items():
cb = QDataCheckBox(info['name'], info['tags'])
if key == '__required':
self.tags.extend(info['tags'])
self.dl_item.options.sdl_list.extend(info['tags'])
cb.setChecked(True)
cb.setDisabled(True)
self.sdl_list_layout.addWidget(cb)
@ -71,7 +72,8 @@ class InstallDialog(QDialog, Ui_InstallDialog):
self.sdl_list_frame.setVisible(False)
self.sdl_list_label.setVisible(False)
self.get_install_info(app_name, default_path, self.tags)
self.get_options()
self.get_download_info()
self.install_button.clicked.connect(self.on_install_button_clicked)
self.cancel_button.clicked.connect(self.on_cancel_button_clicked)
@ -79,13 +81,27 @@ class InstallDialog(QDialog, Ui_InstallDialog):
self.resize(self.minimumSize())
self.setFixedSize(self.size())
def get_install_options(self, path=None):
def get_options(self):
self.dl_item.options.path = self.install_dir_edit.text() if not self.update_game else None
self.dl_item.options.max_workers = self.max_workers_spin.value()
self.dl_item.options.force = self.force_download_check.isChecked()
self.dl_item.options.ignore_space_req = self.ignore_space_check.isChecked()
self.dl_item.options.dl_only = self.download_only_check.isChecked()
self.dl_item.options.sdl_list = ['']
for cb in self.sdl_list_checks:
if data := cb.isChecked():
self.dl_item.options.sdl_list.extend(data)
def get_download_item(self, path=None, silent=False):
if path:
self.install_dir_edit.setText(path)
self.exec_()
return self.options
if silent:
self.threadpool.waitForDone()
else:
self.exec_()
return self.dl_item
def get_install_info(self, app_name, path, tags):
def get_download_info(self):
message = self.tr("Updating...")
self.download_size_info_label.setText(message)
self.download_size_info_label.setStyleSheet("font-style: italic; font-weight: normal")
@ -93,44 +109,36 @@ class InstallDialog(QDialog, Ui_InstallDialog):
self.install_size_info_label.setStyleSheet("font-style: italic; font-weight: normal")
self.install_button.setEnabled(False)
self.sdl_list_frame.setEnabled(False)
info_worker = InstallInfoWorker(app_name, path, tags, self.core)
info_worker = InstallInfoWorker(self.core, self.dl_item)
info_worker.setAutoDelete(True)
info_worker.signals.finished.connect(self.on_worker_finished)
self.threadpool.start(info_worker)
def on_sdl_checkbox_changed(self):
self.tags = ['']
for cb in self.sdl_list_checks:
if data := cb.isChecked():
self.tags.extend(data)
self.get_install_info(self.app_name, self.install_dir_edit.text(), self.tags)
self.get_options()
self.get_download_info()
def on_install_dir_text_changed(self, path: str):
self.get_install_info(self.app_name, path, self.tags)
def on_install_dir_text_changed(self):
self.get_options()
self.get_download_info()
def on_install_button_clicked(self):
self.options = InstallOptionsModel(
app_name=self.app_name,
path=self.install_dir_edit.text() if not self.update_game else None,
max_workers=self.max_workers_spin.value(),
force=self.force_download_check.isChecked(),
ignore_free_space=self.ignore_space_check.isChecked(),
dl_only=self.download_only_check.isChecked(),
sdl_list=self.tags
)
self.threadpool.clear()
self.close()
def on_cancel_button_clicked(self):
self.dl_item = False
self.threadpool.clear()
self.close()
def on_worker_finished(self, info: tuple):
download_size, install_size = info
def on_worker_finished(self, dl_item: InstallQueueItemModel):
# TODO: Check available size and act accordingly
# TODO: (show message in label | color it | disable install unless ignore)
# TODO: Find a way to get the installation size delta and show it
if download_size is not None and install_size is not None:
if dl_item:
self.dl_item = dl_item
download_size = self.dl_item.download.analysis.dl_size
install_size = self.dl_item.download.analysis.install_size
if download_size:
self.download_size_info_label.setText("{}".format(get_size(download_size)))
self.download_size_info_label.setStyleSheet("font-style: normal; font-weight: bold")
@ -147,37 +155,58 @@ class InstallDialog(QDialog, Ui_InstallDialog):
class InstallInfoWorkerSignals(QObject):
finished = pyqtSignal(tuple)
finished = pyqtSignal(InstallQueueItemModel)
class InstallInfoWorker(QRunnable):
def __init__(self, app_name, path, tags, core: LegendaryCore):
def __init__(self, core: LegendaryCore, dl_item: InstallQueueItemModel):
super(InstallInfoWorker, self).__init__()
self.signals = InstallInfoWorkerSignals()
self.core = core
self.app_name = app_name
self.path = path
self.tags = tags
self.dl_item = dl_item
@pyqtSlot()
def run(self):
try:
dlm, analysis, game, igame, repair, repair_file = self.core.prepare_download(
app_name=self.app_name,
base_path=self.path,
sdl_prompt=lambda app_name, title: self.tags
)
self.signals.finished.emit((analysis.dl_size, analysis.install_size))
download = InstallDownloadModel(*self.core.prepare_download(
app_name=self.dl_item.options.app_name,
base_path=self.dl_item.options.path,
force=self.dl_item.options.force,
no_install=self.dl_item.options.dl_only,
status_q=self.dl_item.status_q,
# max_shm=,
max_workers=self.dl_item.options.max_workers,
# game_folder=,
# disable_patching=,
# override_manifest=,
# override_old_manifest=,
# override_base_url=,
# platform_override=,
# file_prefix_filter=,
# file_exclude_filter=,
# file_install_tag=,
# dl_optimizations=,
# dl_timeout=,
repair=self.dl_item.options.repair,
# repair_use_latest=,
ignore_space_req=self.dl_item.options.ignore_space_req,
# disable_delta=,
# override_delta_manifest=,
# reset_sdl=,
sdl_prompt=lambda app_name, title: self.dl_item.options.sdl_list
))
self.dl_item.download = download
except:
self.signals.finished.emit((None, None))
self.dl_item.download = None
self.signals.finished.emit(self.dl_item)
return
class QDataCheckBox(QCheckBox):
def __init__(self, text, data=None):
super(QDataCheckBox, self).__init__()
def __init__(self, text, data=None, parent=None):
super(QDataCheckBox, self).__init__(parent)
self.setText(text)
self.data = data

View file

@ -14,7 +14,7 @@ from rare.components.tabs.downloads import DownloadTab
from rare.components.tabs.games import GameTab
from rare.components.tabs.settings import SettingsTab
from rare.utils import legendary_utils
from rare.utils.models import InstallOptionsModel
from rare.utils.models import InstallQueueItemModel, InstallOptionsModel
class TabWidget(QTabWidget):
@ -96,11 +96,12 @@ class TabWidget(QTabWidget):
self.setIconSize(QSize(25, 25))
def install_game(self, app_name, disable_path=False):
dialog = InstallDialog(app_name, self.core, disable_path, parent=self)
options = dialog.get_install_options()
if options:
download_item = InstallQueueItemModel(options=InstallOptionsModel(app_name=app_name))
dialog = InstallDialog(self.core, download_item, update=disable_path, parent=self)
download_item = dialog.get_download_item()
if download_item:
self.setCurrentIndex(1)
self.start_download(options)
self.start_download(download_item)
def start_download(self, options):
downloads = len(self.downloadTab.dl_queue) + len(self.downloadTab.update_widgets.keys()) + 1

View file

@ -1,6 +1,5 @@
import datetime
from logging import getLogger
from multiprocessing import Queue as MPQueue
from PyQt5.QtCore import QThread, pyqtSignal, QSettings
from PyQt5.QtWidgets import QWidget, QMessageBox, QVBoxLayout, QLabel, QGridLayout, QProgressBar, QPushButton, \
@ -12,7 +11,7 @@ from custom_legendary.models.game import Game, InstalledGame
from rare.components.dialogs.install_dialog import InstallDialog
from rare.components.tabs.downloads.dl_queue_widget import DlQueueWidget
from rare.components.tabs.downloads.download_thread import DownloadThread
from rare.utils.models import InstallOptionsModel, InstallDownloadModel, InstallQueueItemModel
from rare.utils.models import InstallOptionsModel, InstallQueueItemModel
from rare.utils.utils import get_size
logger = getLogger("Download")
@ -96,44 +95,7 @@ class DownloadTab(QWidget):
def stop_download(self):
self.thread.kill()
def install_game(self, options: InstallOptionsModel):
status_queue = MPQueue()
try:
download = InstallDownloadModel(*self.core.prepare_download(
app_name=options.app_name,
base_path=options.path,
force=options.force,
no_install=options.dl_only,
status_q=status_queue,
# max_shm=,
max_workers=options.max_workers,
# game_folder=,
# disable_patching=,
# override_manifest=,
# override_old_manifest=,
# override_base_url=,
# platform_override=,
# file_prefix_filter=,
# file_exclude_filter=,
# file_install_tag=,
# dl_optimizations=,
# dl_timeout=,
repair=options.repair,
# repair_use_latest=,
ignore_space_req=options.ignore_free_space,
# disable_delta=,
# override_delta_manifest=,
# reset_sdl=,
sdl_prompt=lambda app_name, title: options.sdl_list
))
except Exception as e:
QMessageBox.warning(self, self.tr("Error preparing download"),
str(e))
return
queue_item = InstallQueueItemModel(status_queue, download, options)
def install_game(self, queue_item: InstallQueueItemModel):
if self.active_game is None:
self.start_installation(queue_item)
else:
@ -231,14 +193,11 @@ class DownloadTab(QWidget):
def update_game(self, app_name: str, auto=False):
logger.info("Update " + app_name)
if not auto:
dialog = InstallDialog(app_name, self.core, update=True, parent=self)
options = dialog.get_install_options()
else:
self.install_game(InstallOptionsModel(app_name=app_name))
return
if options:
self.install_game(options)
download_item = InstallQueueItemModel(options=InstallOptionsModel(app_name=app_name))
dialog = InstallDialog(self.core, download_item, update=True, parent=self)
download_item = dialog.get_download_item(silent=auto)
if download_item:
self.install_game(download_item)
else:
self.update_widgets[app_name].update_button.setDisabled(False)
self.update_widgets[app_name].update_with_settings.setDisabled(False)

View file

@ -23,10 +23,10 @@ class DownloadThread(QThread):
def __init__(self, core: LegendaryCore, queue_item: InstallQueueItemModel):
super(DownloadThread, self).__init__()
self.dlm = queue_item.download.dlmanager
self.core = core
self.dlm = queue_item.download.dlmanager
self.dl_only = queue_item.options.dl_only
self.status_queue = queue_item.queue
self.status_q = queue_item.status_q
self.igame = queue_item.download.igame
self.repair = queue_item.download.repair
self.repair_file = queue_item.download.repair_file
@ -103,7 +103,7 @@ class DownloadThread(QThread):
dl_stopped = True
try:
if not dl_stopped:
self.statistics.emit(self.status_queue.get(timeout=1))
self.statistics.emit(self.status_q.get(timeout=1))
except queue.Empty:
pass

View file

@ -4,20 +4,20 @@ import os
class InstallOptionsModel:
def __init__(self, app_name: str, path: str = os.path.expanduser("~/legendary"),
max_workers: int = os.cpu_count() * 2, repair: bool = False, dl_only: bool = False,
ignore_free_space: bool = False, force: bool = False, sdl_list: list = ['']
ignore_space_req: bool = False, force: bool = False, sdl_list: list = ['']
):
self.app_name = app_name
self.path = path
self.max_workers = max_workers
self.repair = repair
self.dl_only = dl_only
self.ignore_free_space = ignore_free_space
self.ignore_space_req = ignore_space_req
self.force = force
self.sdl_list = sdl_list
class InstallDownloadModel:
def __init__(self, dlmanager, analysis, game, igame, repair: bool = False, repair_file: str = None):
def __init__(self, dlmanager, analysis, game, igame, repair: bool, repair_file: str):
self.dlmanager = dlmanager
self.analysis = analysis
self.game = game
@ -27,7 +27,10 @@ class InstallDownloadModel:
class InstallQueueItemModel:
def __init__(self, queue, download: InstallDownloadModel, options: InstallOptionsModel):
self.queue = queue
def __init__(self, status_q=None, download: InstallDownloadModel = None, options: InstallOptionsModel = None):
self.status_q = status_q
self.download = download
self.options = options
def __bool__(self):
return (self.status_q is not None) and (self.download is not None) and (self.options is not None)