2021-02-18 05:46:03 +13:00
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
import time
|
|
|
|
from logging import getLogger
|
|
|
|
|
|
|
|
from PyQt5.QtCore import QThread, pyqtSignal
|
2021-03-01 00:06:33 +13:00
|
|
|
from PyQt5.QtWidgets import QWidget, QMessageBox, QVBoxLayout, QLabel, QGridLayout, QProgressBar, QPushButton
|
2021-02-18 05:46:03 +13:00
|
|
|
from legendary.core import LegendaryCore
|
2021-02-27 07:28:54 +13:00
|
|
|
from legendary.models.game import Game
|
|
|
|
from notifypy import Notify
|
2021-02-18 05:46:03 +13:00
|
|
|
|
2021-02-18 22:22:15 +13:00
|
|
|
from Rare.Components.Dialogs.InstallDialog import InstallInfoDialog
|
2021-02-18 05:46:03 +13:00
|
|
|
|
|
|
|
logger = getLogger("Download")
|
|
|
|
|
|
|
|
|
|
|
|
class DownloadThread(QThread):
|
|
|
|
status = pyqtSignal(str)
|
|
|
|
|
|
|
|
def __init__(self, dlm, core: LegendaryCore, igame):
|
|
|
|
super(DownloadThread, self).__init__()
|
|
|
|
self.dlm = dlm
|
|
|
|
self.core = core
|
|
|
|
self.igame = igame
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
start_time = time.time()
|
|
|
|
try:
|
|
|
|
|
|
|
|
self.dlm.start()
|
|
|
|
self.dlm.join()
|
|
|
|
except:
|
|
|
|
logger.error(f"Installation failed after{time.time() - start_time:.02f} seconds.")
|
|
|
|
self.status.emit("error")
|
|
|
|
return
|
|
|
|
|
|
|
|
else:
|
|
|
|
self.status.emit("dl_finished")
|
|
|
|
end_t = time.time()
|
|
|
|
game = self.core.get_game(self.igame.app_name)
|
|
|
|
postinstall = self.core.install_game(self.igame)
|
|
|
|
if postinstall:
|
|
|
|
self._handle_postinstall(postinstall, self.igame)
|
|
|
|
dlcs = self.core.get_dlc_for_game(self.igame.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 = QMessageBox.question(self, "", "Do you want to install the prequisites", QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes
|
|
|
|
# TODO
|
|
|
|
if game.supports_cloud_saves and not game.is_dlc:
|
|
|
|
logger.info('This game supports cloud saves, syncing is handled by the "sync-saves" command.')
|
|
|
|
logger.info(f'To download saves for this game run "legendary sync-saves {game.app_name}"')
|
|
|
|
|
|
|
|
self.status.emit("finish")
|
|
|
|
|
|
|
|
def _handle_postinstall(self, postinstall, igame):
|
|
|
|
print('This game lists the following prequisites to be installed:')
|
|
|
|
print(f'- {postinstall["name"]}: {" ".join((postinstall["path"], postinstall["args"]))}')
|
|
|
|
if os.name == 'nt':
|
|
|
|
if QMessageBox.question(self, "", "Do you want to install the prequisites",
|
|
|
|
QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
|
|
|
|
self.core.prereq_installed(igame.app_name)
|
|
|
|
req_path, req_exec = os.path.split(postinstall['path'])
|
|
|
|
work_dir = os.path.join(igame.install_path, req_path)
|
|
|
|
fullpath = os.path.join(work_dir, req_exec)
|
|
|
|
subprocess.call([fullpath, postinstall['args']], cwd=work_dir)
|
|
|
|
else:
|
|
|
|
self.core.prereq_installed(self.igame.app_name)
|
|
|
|
|
|
|
|
else:
|
|
|
|
logger.info('Automatic installation not available on Linux.')
|
2021-02-10 23:48:25 +13:00
|
|
|
|
|
|
|
|
|
|
|
class DownloadTab(QWidget):
|
2021-02-18 05:46:03 +13:00
|
|
|
finished = pyqtSignal()
|
|
|
|
thread: QThread
|
|
|
|
|
2021-03-01 00:06:33 +13:00
|
|
|
def __init__(self, core: LegendaryCore, updates: list):
|
2021-02-10 23:48:25 +13:00
|
|
|
super(DownloadTab, self).__init__()
|
2021-02-18 05:46:03 +13:00
|
|
|
self.core = core
|
|
|
|
self.layout = QVBoxLayout()
|
2021-02-20 00:57:55 +13:00
|
|
|
self.active_game: Game = None
|
2021-02-18 05:46:03 +13:00
|
|
|
|
|
|
|
self.installing_game = QLabel("Installing Game: None")
|
|
|
|
self.dl_speed = QLabel("Download speed: 0MB/s")
|
|
|
|
self.cache_used = QLabel("Cache used: 0MB")
|
|
|
|
self.downloaded = QLabel("Downloaded: 0MB")
|
|
|
|
|
|
|
|
self.info_layout = QGridLayout()
|
|
|
|
|
|
|
|
self.info_layout.addWidget(self.installing_game, 0, 0)
|
|
|
|
self.info_layout.addWidget(self.dl_speed, 0, 1)
|
2021-02-27 07:28:54 +13:00
|
|
|
self.info_layout.addWidget(self.cache_used, 1, 0)
|
|
|
|
self.info_layout.addWidget(self.downloaded, 1, 1)
|
2021-02-18 05:46:03 +13:00
|
|
|
|
|
|
|
self.layout.addLayout(self.info_layout)
|
|
|
|
self.prog_bar = QProgressBar()
|
|
|
|
self.layout.addWidget(self.prog_bar)
|
2021-03-01 00:06:33 +13:00
|
|
|
label = QLabel(
|
|
|
|
"<b>WARNING</b>: The progress bar is not implemented. It is normal, if there is no progress. The "
|
|
|
|
"progress is visible in console, because Legendary prints output to console. A pull request is active to "
|
|
|
|
"get output")
|
|
|
|
label.setWordWrap(True)
|
|
|
|
self.layout.addWidget(label)
|
2021-02-18 05:46:03 +13:00
|
|
|
|
|
|
|
self.installing_game_widget = QLabel("No active Download")
|
|
|
|
self.layout.addWidget(self.installing_game_widget)
|
|
|
|
|
2021-03-01 00:06:33 +13:00
|
|
|
self.update_title = QLabel("<h2>Updates</h2>")
|
|
|
|
self.update_title.setStyleSheet("""
|
|
|
|
QLabel{
|
|
|
|
margin-top: 20px;
|
|
|
|
}
|
|
|
|
""")
|
|
|
|
self.layout.addWidget(self.update_title)
|
|
|
|
if not updates:
|
|
|
|
self.update_text = QLabel("No updates available")
|
|
|
|
self.layout.addWidget(self.update_text)
|
|
|
|
else:
|
|
|
|
for i in updates:
|
|
|
|
widget = UpdateWidget(core, i)
|
|
|
|
self.layout.addWidget(widget)
|
|
|
|
widget.update.connect(self.update_game)
|
|
|
|
|
2021-02-18 05:46:03 +13:00
|
|
|
self.layout.addStretch(1)
|
|
|
|
|
|
|
|
self.setLayout(self.layout)
|
|
|
|
|
|
|
|
def install_game(self, options: {}):
|
|
|
|
game = self.core.get_game(options["app_name"])
|
2021-02-18 06:19:37 +13:00
|
|
|
|
2021-02-18 05:46:03 +13:00
|
|
|
dlm, analysis, igame = self.core.prepare_download(
|
|
|
|
game=game,
|
|
|
|
base_path=options["options"]["path"],
|
|
|
|
max_workers=options["options"]["max_workers"])
|
|
|
|
if not analysis.dl_size:
|
|
|
|
QMessageBox.information(self, "Warning", "Download size is 0")
|
|
|
|
return
|
|
|
|
# Information
|
|
|
|
if not InstallInfoDialog(dl_size=analysis.dl_size, install_size=analysis.install_size).get_accept():
|
|
|
|
return
|
|
|
|
|
|
|
|
self.installing_game_widget.setText("")
|
2021-02-27 07:28:54 +13:00
|
|
|
self.installing_game.setText("Installing Game: " + game.app_title)
|
2021-02-18 05:46:03 +13:00
|
|
|
res = self.core.check_installation_conditions(analysis=analysis, install=igame, game=game,
|
|
|
|
updating=self.core.is_installed(options["app_name"]),
|
|
|
|
)
|
|
|
|
if res.warnings:
|
|
|
|
for w in sorted(res.warnings):
|
|
|
|
logger.warning(w)
|
|
|
|
if res.failures:
|
|
|
|
for msg in sorted(res.failures):
|
|
|
|
logger.error(msg)
|
|
|
|
logger.error('Installation cannot proceed, exiting.')
|
|
|
|
QMessageBox.warning(self, "Installation failed", "Installation failed. See logs for more information")
|
|
|
|
return
|
2021-02-20 00:57:55 +13:00
|
|
|
self.active_game = game
|
2021-02-18 05:46:03 +13:00
|
|
|
self.thread = DownloadThread(dlm, self.core, igame)
|
|
|
|
self.thread.status.connect(self.status)
|
|
|
|
self.thread.start()
|
|
|
|
|
|
|
|
def status(self, text):
|
|
|
|
if text == "dl_finished":
|
|
|
|
pass
|
|
|
|
elif text == "finish":
|
2021-02-20 00:57:55 +13:00
|
|
|
notification = Notify()
|
|
|
|
notification.title = "Installation finished"
|
|
|
|
notification.message = f"Download of game {self.active_game.app_title}"
|
|
|
|
notification.send()
|
2021-02-27 07:28:54 +13:00
|
|
|
# QMessageBox.information(self, "Info", "Download finished")
|
2021-02-18 05:46:03 +13:00
|
|
|
self.finished.emit()
|
|
|
|
self.installing_game.setText("Installing Game: No running download")
|
|
|
|
elif text == "error":
|
|
|
|
QMessageBox.warning(self, "warn", "Download error")
|
|
|
|
|
|
|
|
def update_game(self, app_name: str):
|
|
|
|
print("Update ", app_name)
|
2021-03-01 00:06:33 +13:00
|
|
|
|
|
|
|
|
|
|
|
class UpdateWidget(QWidget):
|
|
|
|
update = pyqtSignal(str)
|
|
|
|
|
|
|
|
def __init__(self, core: LegendaryCore, app_name):
|
|
|
|
super(UpdateWidget, self).__init__()
|
|
|
|
self.core = core
|
|
|
|
self.game = core.get_installed_game(app_name)
|
|
|
|
|
|
|
|
self.layout = QVBoxLayout()
|
|
|
|
self.title = QLabel(self.game.title)
|
|
|
|
self.layout.addWidget(self.title)
|
|
|
|
|
|
|
|
self.update_button = QPushButton("Update Game")
|
|
|
|
self.update_button.clicked.connect(lambda :self.update.emit(app_name))
|
|
|
|
self.layout.addWidget(self.update_button)
|
|
|
|
|
|
|
|
self.setLayout(self.layout)
|