1
0
Fork 0
mirror of synced 2024-06-02 18:54:41 +12:00

Download queue; delete option

This commit is contained in:
Dummerle 2021-04-07 16:50:36 +02:00
parent 4237358909
commit d8aa6541b9
4 changed files with 232 additions and 119 deletions

View file

@ -0,0 +1,93 @@
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QGroupBox, QVBoxLayout, QLabel, QHBoxLayout, QPushButton, QWidget
from qtawesome import icon
class DlWidget(QWidget):
move_up = pyqtSignal(str) # app_name
move_down = pyqtSignal(str) # app_name
remove = pyqtSignal(str) # app_name
def __init__(self, index, item):
super(DlWidget, self).__init__()
self.app_name = item[1].app_name
self.layout = QHBoxLayout()
self.left_layout = QVBoxLayout()
self.move_up_button = QPushButton(icon("fa.arrow-up", color="white"), "")
if index == 0:
self.move_up_button.setDisabled(True)
self.move_up_button.clicked.connect(lambda: self.move_up.emit(self.app_name))
self.move_up_button.setFixedWidth(20)
self.left_layout.addWidget(self.move_up_button)
self.move_down_buttton = QPushButton(icon("fa.arrow-down", color="white"), "")
self.move_down_buttton.clicked.connect(lambda: self.move_down.emit(self.app_name))
self.left_layout.addWidget(self.move_down_buttton)
self.move_down_buttton.setFixedWidth(20)
self.layout.addLayout(self.left_layout)
self.right_layout = QVBoxLayout()
self.title = QLabel(item[1].app_title)
self.right_layout.addWidget(self.title)
dl_size = item[-1].dl_size
install_size = item[-1].install_size
self.size = QHBoxLayout()
self.size.addWidget(QLabel(self.tr("Download size: {} GB").format(dl_size/1024**3)))
self.size.addWidget(QLabel(self.tr("Install size: {} GB").format(install_size/1024**3)))
self.right_layout.addLayout(self.size)
self.delete = QPushButton(self.tr("Remove Download"))
self.delete.clicked.connect(lambda: self.remove.emit(self.app_name))
self.right_layout.addWidget(self.delete)
self.layout.addLayout(self.right_layout)
self.setLayout(self.layout)
class DlQueueWidget(QGroupBox):
update_list = pyqtSignal(list)
dl_queue = []
def __init__(self):
super(DlQueueWidget, self).__init__()
self.setTitle(self.tr("Download Queue"))
self.layout = QVBoxLayout()
self.setObjectName("group")
self.text = QLabel(self.tr("No downloads in queue"))
self.layout.addWidget(self.text)
self.setLayout(self.layout)
def update_queue(self, dl_queue: list):
self.dl_queue = dl_queue
self.setLayout(QVBoxLayout())
QWidget().setLayout(self.layout)
self.layout = QVBoxLayout()
if len(dl_queue) == 0:
self.layout.addWidget(QLabel(self.tr("No downloads in queue")))
self.setLayout(self.layout)
return
for index, item in enumerate(dl_queue):
widget = DlWidget(index, item)
widget.remove.connect(self.remove)
self.layout.addWidget(widget)
self.setLayout(self.layout)
def remove(self, app_name):
for index, i in enumerate(self.dl_queue):
if i[1].app_name == app_name:
self.dl_queue.pop(index)
break
else:
print("BUG! ", app_name)
return
self.update_list.emit(self.dl_queue)
self.update_queue(self.dl_queue)

View file

@ -1,19 +1,16 @@
import datetime
import os
import queue
import subprocess
import time
from logging import getLogger
from multiprocessing import Queue as MPQueue
from PyQt5.QtCore import QThread, pyqtSignal, Qt, QCoreApplication
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtWidgets import QWidget, QMessageBox, QVBoxLayout, QLabel, QGridLayout, QProgressBar, QPushButton, QDialog, \
QListWidget, QHBoxLayout
from Rare.Components.Dialogs.InstallDialog import InstallInfoDialog, InstallDialog
from Rare.utils.Models import InstallOptions, KillDownloadException
from Rare.Components.Tabs.Downloads.DlQueueWidget import DlQueueWidget
from Rare.Components.Tabs.Downloads.DownloadThread import DownloadThread
from Rare.utils.Models import InstallOptions
from custom_legendary.core import LegendaryCore
from custom_legendary.downloader.manager import DLManager
from custom_legendary.models.downloading import UIUpdate
from custom_legendary.models.game import Game, InstalledGame
from custom_legendary.utils.selective_dl import games
@ -21,105 +18,6 @@ from custom_legendary.utils.selective_dl import games
logger = getLogger("Download")
class DownloadThread(QThread):
status = pyqtSignal(str)
statistics = pyqtSignal(UIUpdate)
kill = False
def __init__(self, dlm: DLManager, core: LegendaryCore, status_queue: MPQueue, igame, repair=False,
repair_file=None):
super(DownloadThread, self).__init__()
self.dlm = dlm
self.core = core
self.status_queue = status_queue
self.igame = igame
self.repair = repair
self.repair_file = repair_file
def run(self):
start_time = time.time()
try:
self.dlm.start()
time.sleep(1)
while self.dlm.is_alive():
if self.kill:
# raise KillDownloadException()
# TODO kill download queue, workers
pass
try:
self.statistics.emit(self.status_queue.get(timeout=1))
except queue.Empty:
pass
self.dlm.join()
except KillDownloadException:
self.status.emit("stop")
logger.info("Downlaod can be continued later")
self.dlm.kill()
return
except Exception as e:
logger.error(f"Installation failed after {time.time() - start_time:.02f} seconds: {e}")
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}"')
old_igame = self.core.get_installed_game(game.app_name)
if old_igame and self.repair and os.path.exists(self.repair_file):
if old_igame.needs_verification:
old_igame.needs_verification = False
self.core.install_game(old_igame)
logger.debug('Removing repair file.')
os.remove(self.repair_file)
if old_igame and old_igame.install_tags != self.igame.install_tags:
old_igame.install_tags = self.igame.install_tags
self.logger.info('Deleting now untagged files.')
self.core.uninstall_tag(old_igame)
self.core.install_game(old_igame)
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.')
class DownloadTab(QWidget):
finished = pyqtSignal()
thread: QThread
@ -159,8 +57,9 @@ class DownloadTab(QWidget):
self.layout.addLayout(self.mini_layout)
self.queue_label = QLabel(self.tr("Download queue: Empty"))
self.layout.addWidget(self.queue_label)
self.queue_widget = DlQueueWidget()
self.layout.addWidget(self.queue_widget)
self.queue_widget.update_list.connect(self.update_dl_queue)
self.update_title = QLabel(f"<h2>{self.tr('Updates')}</h2>")
self.update_title.setStyleSheet("""
@ -184,6 +83,10 @@ class DownloadTab(QWidget):
self.setLayout(self.layout)
def update_dl_queue(self, dl_queue):
self.dl_queue = dl_queue
def stop_download(self):
self.thread.kill = True
@ -232,15 +135,13 @@ class DownloadTab(QWidget):
return
if self.active_game is None:
self.start_installation(dlm, game, status_queue, igame, repair_file, options)
self.start_installation(dlm, game, status_queue, igame, repair_file, options, analysis)
else:
self.dl_queue.append((dlm, game, status_queue, igame, repair_file, options))
self.queue_label.setText(
self.tr("Download queue: ") + ", ".join(
i[1].app_title for i in self.dl_queue) if self.dl_queue else self.tr("Empty"))
def start_installation(self, dlm, game, status_queue, igame, repair_file, options: InstallOptions):
self.dl_queue.append((dlm, game, status_queue, igame, repair_file, options, analysis))
self.queue_widget.update_queue(self.dl_queue)
def start_installation(self, dlm, game, status_queue, igame, repair_file, options: InstallOptions, analysis):
print("start installation", game.app_title)
self.active_game = game
self.thread = DownloadThread(dlm, self.core, status_queue, igame, options.repair, repair_file)
self.thread.status.connect(self.status)
@ -305,8 +206,10 @@ class DownloadTab(QWidget):
# QMessageBox.information(self, "Info", "Download finished")
logger.info("Download finished: " + self.active_game.app_title)
if self.dl_queue[0][1] == self.active_game.app_name:
self.dl_queue.pop(0)
if self.dl_queue:
if self.dl_queue[0][1] == self.active_game.app_name:
self.dl_queue.pop(0)
self.queue_widget.update_queue(self.dl_queue)
if self.active_game.app_name in self.update_widgets.keys():
self.update_widgets[self.active_game.app_name].setVisible(False)
@ -329,7 +232,7 @@ class DownloadTab(QWidget):
if len(self.dl_queue) != 0:
self.start_installation(*self.dl_queue[0])
else:
self.queue_label.setText(self.tr("Download queue: Empty"))
self.queue_widget.update_queue(self.dl_queue)
elif text == "error":
QMessageBox.warning(self, "warn", "Download error")

View file

@ -0,0 +1,117 @@
import os
import queue
import subprocess
import time
from logging import getLogger
from multiprocessing import Queue as MPQueue
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QMessageBox
from Rare.utils.Models import KillDownloadException
from custom_legendary.core import LegendaryCore
from custom_legendary.downloader.manager import DLManager
from custom_legendary.models.downloading import UIUpdate
logger = getLogger("Download")
class DownloadThread(QThread):
status = pyqtSignal(str)
statistics = pyqtSignal(UIUpdate)
kill = False
def __init__(self, dlm: DLManager, core: LegendaryCore, status_queue: MPQueue, igame, repair=False,
repair_file=None):
super(DownloadThread, self).__init__()
self.dlm = dlm
self.core = core
self.status_queue = status_queue
self.igame = igame
self.repair = repair
self.repair_file = repair_file
def run(self):
start_time = time.time()
try:
self.dlm.start()
time.sleep(1)
while self.dlm.is_alive():
if self.kill:
# raise KillDownloadException()
# TODO kill download queue, workers
pass
try:
self.statistics.emit(self.status_queue.get(timeout=1))
except queue.Empty:
pass
self.dlm.join()
except KillDownloadException:
self.status.emit("stop")
logger.info("Downlaod can be continued later")
self.dlm.kill()
return
except Exception as e:
logger.error(f"Installation failed after {time.time() - start_time:.02f} seconds: {e}")
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}"')
old_igame = self.core.get_installed_game(game.app_name)
if old_igame and self.repair and os.path.exists(self.repair_file):
if old_igame.needs_verification:
old_igame.needs_verification = False
self.core.install_game(old_igame)
logger.debug('Removing repair file.')
os.remove(self.repair_file)
if old_igame and old_igame.install_tags != self.igame.install_tags:
old_igame.install_tags = self.igame.install_tags
self.logger.info('Deleting now untagged files.')
self.core.uninstall_tag(old_igame)
self.core.install_game(old_igame)
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.')

View file

@ -45,7 +45,7 @@ class RareSettings(QGroupBox):
self.select_lang.currentIndexChanged.connect(self.update_lang)
self.layout.addWidget(self.lang_widget)
self.exit_to_sys_tray = QCheckBox("Hide to System Tray Icon")
self.exit_to_sys_tray = QCheckBox(self.tr("Hide to System Tray Icon"))
self.exit_to_sys_tray.setChecked(settings.value("sys_tray", True, bool))
self.exit_to_sys_tray.stateChanged.connect(self.update_sys_tray)
self.sys_tray_widget = SettingsWidget(self.tr("Exit to System Tray Icon"), self.exit_to_sys_tray)