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:
parent
376d3e0eba
commit
b0ec5c5fcb
5 changed files with 100 additions and 108 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue