1
0
Fork 0
mirror of synced 2024-06-26 10:11:19 +12:00
Rare/rare/components/tabs/games/import_sync/egl_sync_widget.py

306 lines
13 KiB
Python
Raw Normal View History

import os
import platform
from glob import glob
from logging import getLogger
from PyQt5.QtCore import Qt, QThread
from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QLabel, QGroupBox, \
QCheckBox, QPushButton, QListWidgetItem, QDialog, QFileDialog
import rare.shared as shared
from rare.ui.components.tabs.games.import_sync.egl_sync_widget import Ui_EGLSyncGroup
from rare.utils.extra_widgets import PathEdit
from rare.utils.utils import WineResolver
logger = getLogger("EGLSync")
appdata_path_spec = \
r'%LOCALAPPDATA%\EpicGamesLauncher\Saved\Config\Windows'
programdata_path_spec = \
r'%PROGRAMDATA%\Epic\EpicGamesLauncher\Data\Manifests'
class EGLSyncGroup(QGroupBox, Ui_EGLSyncGroup):
importable_items = list()
exportable_items = list()
wine_resolver: QThread
def __init__(self, parent=None):
super(EGLSyncGroup, self).__init__(parent=parent)
self.setupUi(self)
self.export_list.setProperty("noBorder", 1)
self.import_list.setProperty("noBorder", 1)
if platform.system() == "Windows":
estimated_path = os.path.expandvars(programdata_path_spec)
else:
estimated_path = str()
self.wine_resolver = WineResolver(programdata_path_spec, 'default', shared.legendary_core)
self.wine_resolver.result_ready.connect(self.egl_path_info.setText)
self.wine_resolver.finished.connect(self.wine_resolver.quit)
self.wine_resolver.finished.connect(self.wine_resolver.deleteLater)
self.wine_resolver.start()
self.egl_path_info.setText(estimated_path)
egl_path = os.path.expanduser("~/")
if egl_path := shared.legendary_core.egl.programdata_path:
pass
elif egl_path := shared.legendary_core.lgd.config.get("default", "wine_prefix", fallback=""):
egl_data_path = os.path.join(
shared.legendary_core.lgd.config.get("default", "wine_prefix", fallback=""),
'drive_c/ProgramData/Epic/EpicGamesLauncher/Data')
egl_path = os.path.join(egl_data_path, 'Manifests')
else:
possible_wine_prefixes = [os.path.expanduser("~/.wine"),
os.path.expanduser("~/Games/epic-games-store")]
for i in possible_wine_prefixes:
if os.path.exists(p := os.path.join(i, "drive_c/ProgramData/Epic/EpicGamesLauncher/Data/Manifests")):
egl_path = p
self.egl_path_edit = PathEdit(
path=egl_path,
file_type=QFileDialog.DirectoryOnly,
edit_func=self.egl_path_edit_cb,
save_func=self.egl_path_save_cb,
parent=self
)
self.egl_path_layout.addWidget(self.egl_path_edit)
if platform.system() != "Windows":
shared.legendary_core.lgd.config.set('Legendary', 'egl_programdata', egl_path)
shared.legendary_core.egl.programdata_path = egl_path
if shared.legendary_core.egl_sync_enabled:
self.refresh_button.setText(self.tr("Disable sync"))
else:
self.refresh_button.setText(self.tr("Enable Sync"))
self.refresh_button.clicked.connect(self.sync)
# self.enable_sync_button.clicked.connect(self.enable_sync)
# self.sync_once_button.clicked.connect(shared.lgd_core.egl_sync)
self.export_list.itemDoubleClicked.connect(
lambda item:
item.setCheckState(Qt.Unchecked) if item.checkState() != Qt.Unchecked else item.setCheckState(Qt.Checked))
self.import_list.itemDoubleClicked.connect(
lambda item:
item.setCheckState(Qt.Unchecked) if item.checkState() != Qt.Unchecked else item.setCheckState(Qt.Checked))
self.export_select_all_button.clicked.connect(
lambda: self.select_items(self.exportable_items, Qt.Checked))
self.export_select_none_button.clicked.connect(
lambda: self.select_items(self.exportable_items, Qt.Unchecked))
self.import_select_all_button.clicked.connect(
lambda: self.select_items(self.importable_items, Qt.Checked))
self.import_select_none_button.clicked.connect(
lambda: self.select_items(self.importable_items, Qt.Unchecked))
self.export_button.clicked.connect(self.export_selected)
self.import_button.clicked.connect(self.import_selected)
def egl_path_edit_cb(self, path):
if platform.system() != "Windows":
if os.path.exists(os.path.join(path, "system.reg")) and os.path.exists(os.path.join(path, "dosdevices/c:")):
# path is a wine prefix
path = os.path.join(path, "dosdevices/c:", "ProgramData/Epic/EpicGamesLauncher/Data/Manifests")
if os.path.exists(path) and glob(f"{path}/*.item"):
return True, path
return False, path
def egl_path_save_cb(self, path):
shared.legendary_core.lgd.config.set("Legendary", "egl_programdata", path)
shared.legendary_core.egl.programdata_path = path
shared.legendary_core.lgd.save_config()
self.update_lists()
def update_export_list(self):
self.export_button.setDisabled(not bool(shared.legendary_core.egl.programdata_path))
self.export_select_all_button.setDisabled(not bool(shared.legendary_core.egl.programdata_path))
self.export_select_none_button.setDisabled(not bool(shared.legendary_core.egl.programdata_path))
self.export_list.clear()
self.exportable_items.clear()
exportable_games = shared.legendary_core.egl_get_exportable()
for igame in exportable_games:
ew = EGLSyncItem(igame, True, self.export_list)
self.exportable_items.append(ew)
self.export_list.addItem(ew)
self.export_group.setEnabled(bool(exportable_games))
self.export_button.setEnabled(bool(exportable_games))
self.export_label.setVisible(not bool(exportable_games))
def update_import_list(self):
self.import_button.setDisabled(not bool(shared.legendary_core.egl.programdata_path))
self.import_select_all_button.setDisabled(not bool(shared.legendary_core.egl.programdata_path))
self.import_select_none_button.setDisabled(not bool(shared.legendary_core.egl.programdata_path))
self.import_list.clear()
self.importable_items.clear()
importable_games = shared.legendary_core.egl_get_importable()
for game in importable_games:
iw = EGLSyncItem(game, False, self.import_list)
self.importable_items.append(iw)
self.import_list.addItem(iw)
self.import_group.setEnabled(bool(importable_games))
self.import_button.setEnabled(bool(importable_games))
self.import_label.setVisible(not bool(importable_games))
def update_lists(self):
self.export_list.setVisible(bool(shared.legendary_core.egl.programdata_path))
self.import_list.setVisible(bool(shared.legendary_core.egl.programdata_path))
if not shared.legendary_core.egl.programdata_path:
return
self.update_export_list()
self.update_import_list()
def enable_sync(self):
if not shared.legendary_core.egl.programdata_path:
if os.path.exists(path := self.egl_path_edit.text()):
shared.legendary_core.lgd.config.set("Legendary", "egl_programdata", path)
shared.legendary_core.lgd.save_config()
shared.legendary_core.egl.programdata_path = path
shared.legendary_core.lgd.config.set('Legendary', 'egl_sync', "true")
shared.legendary_core.egl_sync()
shared.legendary_core.lgd.save_config()
self.refresh_button.setText(self.tr("Disable Sync"))
self.enable_sync_button.setDisabled(True)
@staticmethod
def select_items(item_list, state):
for w in item_list:
w.setCheckState(state)
def export_selected(self):
for ew in self.exportable_items:
if ew.is_checked():
ew.export_game()
self.export_list.takeItem(self.export_list.row(ew))
self.update_export_list()
def import_selected(self):
for iw in self.importable_items:
if iw.is_checked:
iw.import_game()
self.import_list.takeItem(self.import_list.row(iw))
self.update_import_list()
def sync(self):
if shared.legendary_core.egl_sync_enabled:
# disable sync
info = DisableSyncDialog().get_information()
if info[0] == 0:
if info[1]:
shared.legendary_core.lgd.config.remove_option('Legendary', 'egl_sync')
else:
shared.legendary_core.lgd.config.remove_option('Legendary', 'egl_programdata')
shared.legendary_core.lgd.config.remove_option('Legendary', 'egl_sync')
# remove EGL GUIDs from all games, DO NOT remove .egstore folders because that would fuck things up.
for igame in shared.legendary_core.get_installed_list():
igame.egl_guid = ''
shared.legendary_core.install_game(igame)
shared.legendary_core.lgd.save_config()
self.refresh_button.setText(self.tr("Enable Sync"))
else:
# enable sync
# self.enable_sync_button.setDisabled(False)
self.update_lists()
class EGLSyncItem(QListWidgetItem):
def __init__(self, game, export: bool, parent=None):
super(EGLSyncItem, self).__init__(parent=parent)
self.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable)
self.setCheckState(Qt.Unchecked)
self.game = game
self.export = export
if export:
self.setText(game.title)
else:
self.setText(shared.legendary_core.get_game(game.app_name).app_title)
def is_checked(self):
return True if self.checkState() == Qt.Checked else False
def export_game(self):
shared.legendary_core.egl_export(self.game.app_name)
def import_game(self):
shared.legendary_core.egl_import(self.game.app_name)
class DisableSyncDialog(QDialog):
info = 1, False
def __init__(self, parent=None):
super(DisableSyncDialog, self).__init__(parent=parent)
self.layout = QVBoxLayout()
self.question = QLabel(self.tr("Do you really want to disable sync with Epic Games Store"))
self.layout.addWidget(self.question)
self.remove_metadata = QCheckBox(self.tr("Remove metadata from installed games"))
self.layout.addWidget(self.remove_metadata)
self.button_layout = QHBoxLayout()
self.button_layout.addStretch(1)
self.ok_button = QPushButton(self.tr("Ok"))
self.cancel_button = QPushButton(self.tr("Cancel"))
self.ok_button.clicked.connect(self.ok)
self.cancel_button.clicked.connect(self.cancel)
self.button_layout.addWidget(self.ok_button)
self.button_layout.addWidget(self.cancel_button)
self.layout.addStretch(1)
self.layout.addLayout(self.button_layout)
self.setLayout(self.layout)
def ok(self):
self.info = 0, self.remove_metadata.isChecked()
self.close()
def cancel(self):
self.close()
def get_information(self):
self.exec_()
return self.info
class EGLSyncItemWidget(QGroupBox):
def __init__(self, game, export: bool, parent=None):
super(EGLSyncItemWidget, self).__init__(parent=parent)
self.layout = QHBoxLayout()
self.export = export
self.game = game
if export:
self.app_title_label = QLabel(game.title)
else:
title = shared.legendary_core.get_game(game.app_name).app_title
self.app_title_label = QLabel(title)
self.layout.addWidget(self.app_title_label)
self.button = QPushButton(self.tr("Export") if export else self.tr("Import"))
if export:
self.button.clicked.connect(self.export_game)
else:
self.button.clicked.connect(self.import_game)
self.layout.addWidget(self.button)
self.setLayout(self.layout)
def export_game(self):
shared.legendary_core.egl_export(self.game.app_name)
# FIXME: on update_egl_widget this is going to crash because
# FIXME: the item is not removed from the list in the python's side
self.deleteLater()
def import_game(self):
shared.legendary_core.egl_import(self.game.app_name)
# FIXME: on update_egl_widget this is going to crash because
# FIXME: the item is not removed from the list in the python's side
self.deleteLater()