2021-03-09 05:20:28 +13:00
|
|
|
import os
|
2021-06-20 02:22:30 +12:00
|
|
|
from dataclasses import field, dataclass
|
|
|
|
from multiprocessing import Queue
|
2021-11-04 06:33:01 +13:00
|
|
|
from typing import Union, List
|
2021-03-09 05:20:28 +13:00
|
|
|
|
2021-09-30 10:22:47 +13:00
|
|
|
from PyQt5.QtCore import QObject, pyqtSignal
|
|
|
|
|
2021-10-25 08:23:31 +13:00
|
|
|
from legendary.core import LegendaryCore
|
2021-09-07 07:10:18 +12:00
|
|
|
from legendary.downloader.mp.manager import DLManager
|
|
|
|
from legendary.models.downloading import AnalysisResult, ConditionCheckResult
|
|
|
|
from legendary.models.game import Game, InstalledGame
|
2021-08-17 08:50:31 +12:00
|
|
|
|
2021-03-09 05:20:28 +13:00
|
|
|
|
2021-08-18 01:09:46 +12:00
|
|
|
@dataclass
|
2021-05-23 07:56:13 +12:00
|
|
|
class InstallOptionsModel:
|
2021-06-20 02:22:30 +12:00
|
|
|
app_name: str
|
|
|
|
base_path: str = os.path.expanduser("~/legendary")
|
|
|
|
max_workers: int = os.cpu_count() * 2
|
|
|
|
repair: bool = False
|
|
|
|
no_install: bool = False
|
|
|
|
ignore_space_req: bool = False
|
|
|
|
force: bool = False
|
2021-08-18 03:35:02 +12:00
|
|
|
sdl_list: list = field(default_factory=lambda: [''])
|
2021-09-30 10:22:47 +13:00
|
|
|
update: bool = False
|
|
|
|
silent: bool = False
|
2021-12-04 13:11:20 +13:00
|
|
|
platform: str = ""
|
2021-05-23 07:56:13 +12:00
|
|
|
|
2021-10-25 08:23:31 +13:00
|
|
|
def set_no_install(self, enabled: bool) -> None:
|
|
|
|
self.no_install = enabled
|
|
|
|
|
2021-05-23 07:56:13 +12:00
|
|
|
|
2021-06-20 02:22:30 +12:00
|
|
|
@dataclass
|
2021-05-23 07:56:13 +12:00
|
|
|
class InstallDownloadModel:
|
2021-06-20 02:22:30 +12:00
|
|
|
dlmanager: DLManager
|
|
|
|
analysis: AnalysisResult
|
|
|
|
game: Game
|
|
|
|
igame: InstalledGame
|
|
|
|
repair: bool
|
|
|
|
repair_file: str
|
2021-08-18 02:05:00 +12:00
|
|
|
res: ConditionCheckResult
|
2021-05-23 07:56:13 +12:00
|
|
|
|
|
|
|
|
2021-06-20 02:22:30 +12:00
|
|
|
@dataclass
|
2021-05-23 07:56:13 +12:00
|
|
|
class InstallQueueItemModel:
|
2021-06-20 02:22:30 +12:00
|
|
|
status_q: Queue = None
|
|
|
|
download: InstallDownloadModel = None
|
|
|
|
options: InstallOptionsModel = None
|
2021-05-24 00:15:36 +12:00
|
|
|
|
|
|
|
def __bool__(self):
|
|
|
|
return (self.status_q is not None) and (self.download is not None) and (self.options is not None)
|
2021-09-30 10:22:47 +13:00
|
|
|
|
|
|
|
|
2021-10-25 08:23:31 +13:00
|
|
|
class PathSpec:
|
|
|
|
__egl_path_vars = {
|
|
|
|
'{appdata}': os.path.expandvars('%LOCALAPPDATA%'),
|
|
|
|
'{userdir}': os.path.expandvars('%USERPROFILE%/Documents'),
|
|
|
|
# '{userprofile}': os.path.expandvars('%userprofile%'), # possibly wrong
|
|
|
|
'{usersavedgames}': os.path.expandvars('%USERPROFILE%/Saved Games'),
|
|
|
|
}
|
|
|
|
egl_appdata: str = r'%LOCALAPPDATA%\EpicGamesLauncher\Saved\Config\Windows'
|
|
|
|
egl_programdata: str = r'%PROGRAMDATA%\Epic\EpicGamesLauncher\Data\Manifests'
|
|
|
|
wine_programdata: str = r'dosdevices/c:/ProgramData'
|
|
|
|
|
|
|
|
def __init__(self, core: LegendaryCore = None, app_name: str = 'default'):
|
|
|
|
if core is not None:
|
|
|
|
self.__egl_path_vars.update({'{epicid}': core.lgd.userdata['account_id']})
|
|
|
|
self.app_name = app_name
|
|
|
|
|
|
|
|
def cook(self, path: str) -> str:
|
|
|
|
cooked_path = [self.__egl_path_vars.get(p.lower(), p) for p in path.split('/')]
|
|
|
|
return os.path.join(*cooked_path)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def wine_egl_programdata(self):
|
|
|
|
return self.egl_programdata.replace('\\', '/').replace('%PROGRAMDATA%', self.wine_programdata)
|
|
|
|
|
|
|
|
def wine_egl_prefixes(self, results: int = 0) -> Union[List[str], str]:
|
|
|
|
possible_prefixes = [
|
|
|
|
os.path.expanduser("~/.wine"),
|
|
|
|
os.path.expanduser("~/Games/epic-games-store"),
|
|
|
|
]
|
|
|
|
prefixes = []
|
|
|
|
for prefix in possible_prefixes:
|
|
|
|
if os.path.exists(os.path.join(prefix, self.wine_egl_programdata)):
|
|
|
|
prefixes.append(prefix)
|
|
|
|
if not prefixes:
|
|
|
|
return str()
|
|
|
|
if not results:
|
|
|
|
return prefixes
|
|
|
|
elif results == 1:
|
|
|
|
return prefixes[0]
|
|
|
|
else:
|
|
|
|
return prefixes[:results]
|
|
|
|
|
|
|
|
|
2021-10-04 08:29:33 +13:00
|
|
|
@dataclass
|
|
|
|
class ApiResults:
|
|
|
|
game_list: list = None
|
2021-12-10 08:03:34 +13:00
|
|
|
dlcs: dict = None
|
2021-10-04 08:29:33 +13:00
|
|
|
bit32_games: list = None
|
|
|
|
mac_games: list = None
|
|
|
|
no_asset_games: list = None
|
2021-10-24 12:47:49 +13:00
|
|
|
saves: list = None
|
2021-10-04 08:29:33 +13:00
|
|
|
|
|
|
|
def __bool__(self):
|
|
|
|
return self.game_list is not None \
|
|
|
|
and self.dlcs is not None \
|
|
|
|
and self.bit32_games is not None \
|
|
|
|
and self.mac_games is not None \
|
2021-10-24 12:47:49 +13:00
|
|
|
and self.no_asset_games is not None \
|
|
|
|
and self.saves is not None
|
2021-10-15 10:05:00 +13:00
|
|
|
|
|
|
|
|
|
|
|
class Signals(QObject):
|
2021-11-04 06:33:01 +13:00
|
|
|
exit_app = pyqtSignal(int) # exit code
|
|
|
|
send_notification = pyqtSignal(str) # app_title
|
2021-10-15 10:05:00 +13:00
|
|
|
|
2021-11-04 06:33:01 +13:00
|
|
|
set_main_tab_index = pyqtSignal(int) # tab index
|
2021-10-15 10:05:00 +13:00
|
|
|
update_download_tab_text = pyqtSignal()
|
|
|
|
|
2021-11-04 06:33:01 +13:00
|
|
|
dl_progress = pyqtSignal(int) # 0-100
|
2021-10-15 10:05:00 +13:00
|
|
|
# set visibility of installing widget in games tab
|
2021-11-04 06:33:01 +13:00
|
|
|
installation_started = pyqtSignal(str) # app_name
|
2021-12-01 11:15:00 +13:00
|
|
|
add_download = pyqtSignal(str)
|
2021-10-15 10:05:00 +13:00
|
|
|
|
|
|
|
install_game = pyqtSignal(InstallOptionsModel)
|
|
|
|
installation_finished = pyqtSignal(bool, str)
|
|
|
|
|
2021-11-04 06:33:01 +13:00
|
|
|
update_gamelist = pyqtSignal(list)
|
2021-11-23 08:09:05 +13:00
|
|
|
game_uninstalled = pyqtSignal(str)
|
2021-10-15 10:05:00 +13:00
|
|
|
|
2021-11-04 06:33:01 +13:00
|
|
|
set_discord_rpc = pyqtSignal(str) # app_name of running game
|