diff --git a/generate_manifests.py b/GenerateManifests.py
similarity index 100%
rename from generate_manifests.py
rename to GenerateManifests.py
diff --git a/Libs/ConnectionCheck.py b/Libs/ConnectionCheck.py
deleted file mode 100644
index 9b8edcb..0000000
--- a/Libs/ConnectionCheck.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import requests
-from PyQt5.QtCore import QThread, pyqtSignal
-
-class ConnectionCheckThread(QThread):
- github_status_checked = pyqtSignal(bool)
- server_status_checked = pyqtSignal(bool)
-
- def __init__(self, server_url, github_api_url):
- super().__init__()
- self.server_url = server_url
- self.github_api_url = github_api_url
-
- def run(self):
- try:
- response = requests.get(self.github_api_url, timeout=5)
- if response.status_code == 200:
- self.github_status_checked.emit(True)
- else:
- self.github_status_checked.emit(False)
- except:
- self.github_status_checked.emit(False)
-
- try:
- if self.server_url:
- response = requests.get(f'https://{self.server_url}', timeout=10)
- if response.status_code == 200:
- self.server_status_checked.emit(True)
- else:
- self.server_status_checked.emit(False)
- else:
- self.server_status_checked.emit(False)
- except:
- self.server_status_checked.emit(False)
\ No newline at end of file
diff --git a/Libs/CreamApiMaker.py b/Libs/CreamApiMaker.py
deleted file mode 100644
index a5fbcec..0000000
--- a/Libs/CreamApiMaker.py
+++ /dev/null
@@ -1,97 +0,0 @@
-from idlelib.iomenu import errors
-
-from requests import get
-from time import sleep
-from PyQt5 import QtCore
-import os
-
-
-class CreamAPI(QtCore.QThread):
- progress_signal = QtCore.pyqtSignal(int)
-
- def __init__(self):
- super().__init__()
- # self.dlc_callback = dlc_callback
- # self.progress_callback = progress_callback
- self.parent_directory = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
- def get_dlc_name(self, dlc_id, errors=0):
- print('CreamApi creating...')
- url = f"https://api.steamcmd.net/v1/info/{dlc_id}"
- headers = {
- "User-Agent": "Mozilla/5.0",
- "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
- "Accept-Encoding": "gzip, deflate, br",
- "Accept-Language": "en-US,en;q=0.9",
- "Cache-Control": "max-age=0",
- "Connection": "keep-alive",
- "Host": "api.steamcmd.net",
- "Upgrade-Insecure-Requests": "1"
- }
- try:
- response = get(url, headers=headers, timeout=3)
- print(response)
- if response.status_code == 200:
- data = response.json()
- dlc_name = data['data'][str(dlc_id)]['common']['name']
- print(dlc_name)
- return dlc_name
- else:
- return None
- except Exception:
- if errors >= 3:
- return False
- errors += 1
- print('Cant connect steamcmd. Rertying...')
- return self.get_dlc_name(dlc_id)
-
- def get_dlc_list(self, app_id, errors=0):
- url = f"https://api.steamcmd.net/v1/info/{app_id}"
- headers = {
- "User-Agent": "Mozilla/5.0",
- "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
- "Accept-Encoding": "gzip, deflate, br",
- "Accept-Language": "en-US,en;q=0.9",
- "Cache-Control": "max-age=0",
- "Connection": "keep-alive",
- "Host": "api.steamcmd.net",
- "Upgrade-Insecure-Requests": "1"
- }
- try:
- response = get(url, headers=headers, timeout=8)
- data = response.json()
- dlc_list_json = data['data'][str(app_id)]['extended']['listofdlc']
- dlc_list = dlc_list_json.split(',')
- return dlc_list
- except Exception:
- if errors >= 3:
- return False
- errors += 1
- print('Cant connect steamcmd. Rertying...')
- return self.get_dlc_list(app_id, errors)
-
- def run(self):
- print('Cream api creating...')
- dlc_list = self.get_dlc_list(281990)
- print(f"DLC list for Cream api {dlc_list}")
- if dlc_list:
- self.check_and_update_dlc_list(dlc_list,
- os.path.join(self.parent_directory, 'creamapi_steam_files', 'cream_api.ini'))
- self.check_and_update_dlc_list(dlc_list,
- os.path.join(self.parent_directory, 'creamapi_launcher_files', 'cream_api.ini'))
- # self.launcher_creamapi(dlcs)
- self.progress_signal.emit(100)
- else:
- print('SteamCmd unavailable. Skipped')
- self.progress_signal.emit(100)
- return
-
-
- def check_and_update_dlc_list(self, dlc_list, path):
- with open(path, 'r+') as file:
- content = file.read()
- for dlc_id in dlc_list:
- if str(dlc_id) not in content:
- dlc_name = self.get_dlc_name(dlc_id)
- file.write(f"\n{dlc_id} = {dlc_name}")
- print('CreamApi writed')
\ No newline at end of file
diff --git a/Libs/DownloadThread.py b/Libs/DownloadThread.py
deleted file mode 100644
index c3d884c..0000000
--- a/Libs/DownloadThread.py
+++ /dev/null
@@ -1,63 +0,0 @@
-import urllib.request
-from os import remove, path
-from PyQt5 import QtCore
-from time import time
-
-
-class DownloaderThread(QtCore.QThread):
- progress_signal = QtCore.pyqtSignal(int, bool)
- progress_signal_2 = QtCore.pyqtSignal(int)
- # text_signal = QtCore.pyqtSignal(str)
- error_signal = QtCore.pyqtSignal(Exception)
- speed_signal = QtCore.pyqtSignal(float)
- finished = QtCore.pyqtSignal()
-
- def __init__(self, file_url, save_path, dlc_downloaded, dlc_count):
- super().__init__()
- self.file_url = file_url
- self.save_path = save_path
- self.cancelled = False
- self.downloaded_bytes = 0
- self.dlc_downloaded = dlc_downloaded
- self.dlc_count = dlc_count
-
- def run(self):
- request = urllib.request.Request(self.file_url, headers={"User-Agent": "Mozilla/5.0"})
- request.add_header('Range', f'bytes={self.downloaded_bytes}-')
- try:
- with urllib.request.urlopen(request, timeout=25) as response:
- total_size = int(response.headers.get('content-length', 0)) + self.downloaded_bytes
- start_time = time()
-
- with open(self.save_path, 'ab') as file:
- while True:
- if self.cancelled:
- remove(self.save_path)
- return
- data = response.read(1024)
- if not data:
- break
- file.write(data)
- self.downloaded_bytes += len(data)
- elapsed_time = time() - start_time
- if elapsed_time > 0:
- speed = round(self.downloaded_bytes / (1024 * 1024 * elapsed_time), 1)
- else:
- speed = 0
- progress_percentage_2 = int((self.downloaded_bytes / total_size) * 100)
- self.speed_signal.emit(speed)
- self.progress_signal_2.emit(progress_percentage_2)
-
- file.close()
-
- except Exception as e:
- self.cancelled = True
- self.error_signal.emit(e)
- finally:
- progress_percentage = int((self.dlc_downloaded / self.dlc_count) * 100)
- self.progress_signal.emit(progress_percentage, True)
- # self.text_signal.emit(path.basename(self.save_path))
- self.finished.emit()
-
- def cancel(self):
- self.cancelled = True
diff --git a/Libs/GamePath.py b/Libs/GamePath.py
deleted file mode 100644
index 43661d3..0000000
--- a/Libs/GamePath.py
+++ /dev/null
@@ -1,99 +0,0 @@
-import os.path
-import winreg
-from vdf import loads
-import subprocess
-
-
-def get_powershell_path():
- candidates = [
- r"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe",
- r"C:\Program Files\PowerShell\7\pwsh.exe"
- ]
- for path in candidates:
- if os.path.exists(path):
- return path
- return None
-
-def get_user_logon_name():
- ps = "(Get-CimInstance -ClassName Win32_ComputerSystem).Username"
- powershell = get_powershell_path()
- if not powershell:
- raise RuntimeError("PowerShell not found on this system")
-
- startupinfo = subprocess.STARTUPINFO()
- startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
- startupinfo.wShowWindow = subprocess.SW_HIDE
-
- res = subprocess.check_output(
- [powershell, "-NoProfile", "-Command", ps],
- universal_newlines=True,
- startupinfo=startupinfo
- ).strip()
-
- if "\\" in res:
- res = res.rsplit("\\", 1)[1]
- return res
-
-
-def get_steam_path():
- return reg_search(r"Software\Valve\Steam", "SteamPath")
-
-
-def stellaris_path():
- try:
- vdf_file_path = os.path.join(get_steam_path(), "steamapps", "libraryfolders.vdf")
- with open(vdf_file_path, 'r', encoding='utf-8') as vdf_file:
- vdf_data = loads(vdf_file.read())
-
- if "libraryfolders" in vdf_data:
- libraryfolders = vdf_data["libraryfolders"]
- for key, value in libraryfolders.items():
- if "apps" in value and "281990" in value["apps"]:
- return os.path.join(value["path"], "steamapps", "common", "Stellaris")
- else:
- return 0
- else:
- return 0
- except Exception:
- return 0
-
-
-def is_drive_root(path: str) -> bool:
- if not path:
- return False
- norm = os.path.normpath(path)
- drive, tail = os.path.splitdrive(norm)
- return bool(drive) and (tail in ("", os.sep))
-
-
-def launcher_path():
- try:
- user_logon_name = get_user_logon_name()
- except:
- user_logon_name = os.getlogin()
-
- user_home = os.path.join("C:\\Users", user_logon_name)
-
- launcher_path_1 = reg_search(r"Software\Paradox Interactive\Paradox Launcher v2", "LauncherInstallation")
- launcher_path_2 = reg_search(r"Software\Paradox Interactive\Paradox Launcher v2", "LauncherPathFolder")
-
- if (launcher_path_1 and is_drive_root(launcher_path_1)) or not launcher_path_1:
- launcher_path_1 = os.path.join(user_home, "AppData", "Local", "Programs", "Paradox Interactive", "launcher")
- if (launcher_path_2 and is_drive_root(launcher_path_2)) or not launcher_path_2:
- launcher_path_2 = os.path.join(user_home, "AppData", "Local", "Paradox Interactive")
-
-
- launcher_path_3 = os.path.join(user_home, "AppData", "Roaming", "Paradox Interactive")
- launcher_path_4 = os.path.join(user_home, "AppData", "Roaming", "paradox-launcher-v2")
-
- return launcher_path_1, launcher_path_2, launcher_path_3, launcher_path_4
-
-
-def reg_search(vaule_data, vaule_name):
- try:
- key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, vaule_data)
- launcher_path, _ = winreg.QueryValueEx(key, vaule_name)
- winreg.CloseKey(key)
- return launcher_path
- except:
- return 0
diff --git a/Libs/LauncherReinstall.py b/Libs/LauncherReinstall.py
deleted file mode 100644
index 23e0758..0000000
--- a/Libs/LauncherReinstall.py
+++ /dev/null
@@ -1,137 +0,0 @@
-import os
-from shutil import rmtree, move
-from subprocess import Popen
-from PyQt5 import QtCore
-from time import sleep
-from glob import glob
-from re import search
-from pathlib import Path
-
-
-class ReinstallThread(QtCore.QThread):
- # progress_signal = QtCore.pyqtSignal(int)
- error_signal = QtCore.pyqtSignal(Exception)
- continue_reinstall = QtCore.pyqtSignal(str)
-
- def __init__(self, msi_path, paradox_folder1, paradox_folder2, paradox_folder3, paradox_folder4,
- launcher_downloaded, downloaded_launcher_dir, user_logon_name):
- super().__init__()
- self.msi_path = msi_path
- self.user_logon_name = user_logon_name
- self.paradox_folder1 = paradox_folder1
- self.paradox_folder2 = paradox_folder2
- self.paradox_folder3 = paradox_folder3
- self.paradox_folder4 = paradox_folder4
- self.launcher_downloaded = launcher_downloaded
- self.downloaded_launcher_dir = downloaded_launcher_dir
-
- def run(self):
- user_home = os.path.join("C:\\Users", self.user_logon_name)
- if Path(self.paradox_folder1) == Path(self.msi_path):
- self.paradox_folder1 = os.path.join(user_home, "AppData", "Local", "Programs", "Paradox Interactive",
- "launcher")
- latest_file = None
- latest_version = (0, 0)
-
- def extract_version(filename):
- match = search(r'launcher-installer-windows_(\d+\.\d+)', filename)
- if match:
- return tuple(map(int, match.group(1).split('.')))
- return None
-
- msi_files = glob(os.path.join(self.msi_path, "launcher-installer-windows_*.msi"))
- if self.launcher_downloaded:
- print('Alt unlock. Deleting all other launches')
- msi_files = glob(os.path.join(self.msi_path, "launcher-installer-windows*.msi"))
- try:
- for file_path in msi_files:
- try:
- os.remove(file_path)
- print(f"Delete {file_path}")
- except Exception as e:
- print(f"Unable to delete {file_path}: {e}")
- except:
- pass
- try:
- move(self.downloaded_launcher_dir, self.msi_path)
- print(f"Launcher moved: {self.msi_path}")
- except Exception as e:
- print(f"Unable to move launcher: {e}")
- self.error_signal.emit(e)
- msi_files = glob(os.path.join(self.msi_path, "launcher-installer-windows_*.msi"))
-
- if msi_files:
- msi_path = msi_files[0]
-
- else:
- msi_path = os.path.join(self.msi_path, "launcher-installer-windows.msi")
- if os.path.exists(msi_path):
- pass
- else:
- self.error_signal.emit('launcher_installer not found!')
- print(f'Game path: {self.msi_path}')
- print(f'Launcher Path: {msi_path}\nPath exists: {os.path.exists(msi_path)}')
- print(f'Deleting launcher...')
- try:
-
- self.paradox_remove(self.paradox_folder1, self.paradox_folder2, self.paradox_folder3, self.paradox_folder4)
-
- uninstall = Popen(['cmd.exe', '/c', 'msiexec', '/uninstall',
- msi_path, '/quiet'], shell=True)
- # output, error = uninstall.communicate()
- # if uninstall.returncode != 0:
- # print("Произошла ошибка при удалении:", error.decode())
-
- uninstall.wait()
- # self.progress_signal.emit(33)
- sleep(1)
- print(f'Installing launcher...')
- install = Popen(
- ['cmd.exe', '/c', 'msiexec', '/package', msi_path,
- '/quiet', 'CREATE_DESKTOP_SHORTCUT=0'], shell=True)
- # output, error = install.communicate()
- # if uninstall.returncode != 0:
- # print("Произошла ошибка при установке:", error.decode())
- install.wait()
- self.continue_reinstall.emit(self.paradox_folder1)
- except Exception as e:
- self.error_signal.emit(e)
-
- @staticmethod
- def paradox_remove(paradox_folder1, paradox_folder2, paradox_folder3, paradox_folder4):
- # user_home = os.path.expanduser("~")
- # paradox_folder1 = os.path.join(user_home, "AppData", "Local", "Programs", "Paradox Interactive")
- # paradox_folder2 = os.path.join(user_home, "AppData", "Local", "Paradox Interactive")
- # paradox_folder3 = os.path.join(user_home, "AppData", "Roaming", "Paradox Interactive")
- # paradox_folder4 = os.path.join(user_home, "AppData", "Roaming", "paradox-launcher-v2")
- try:
- if os.path.exists(paradox_folder1):
- print(f'Removing {paradox_folder1}')
- rmtree(paradox_folder1)
- except Exception as e:
- print(f'Cant delete {e}')
- pass
-
- try:
- if os.path.exists(paradox_folder2):
- print(f'Removing {paradox_folder2}')
- rmtree(paradox_folder2)
- except Exception as e:
- print(f'Cant delete {e}')
- pass
-
- try:
- if os.path.exists(paradox_folder3):
- print(f'Removing {paradox_folder3}')
- rmtree(paradox_folder3)
- except Exception as e:
- print(f'Cant delete {e}')
- pass
-
- try:
- if os.path.exists(paradox_folder4):
- print(f'Removing {paradox_folder4}')
- rmtree(paradox_folder4)
- except Exception as e:
- print(f'Cant delete {e}')
- pass
diff --git a/Libs/MD5Check.py b/Libs/MD5Check.py
deleted file mode 100644
index b4a8818..0000000
--- a/Libs/MD5Check.py
+++ /dev/null
@@ -1,58 +0,0 @@
-import os
-import hashlib
-import requests
-
-class MD5:
- def __init__(self, game_path, url):
- self.game_path = game_path
- self.url = url
- self.prefix_to_remove = f"files/www/{url}/unlocker/files/"
- self.hashes_url = f"https://{url}/unlocker/hashes.txt"
- self.server_hashes = self._load_server_hashes()
-
- def _load_server_hashes(self):
- try:
- response = requests.get(self.hashes_url, timeout=10)
- response.raise_for_status()
- if not response.text.strip():
- return None
-
- lines = response.text.splitlines()
- hashes = {}
- for line in lines:
- server_hash, file_path = line.split()
- clean_path = file_path.replace(self.prefix_to_remove, "")
- hashes[clean_path] = server_hash
- return hashes
- except (requests.RequestException, ValueError):
- return None
-
- def calculate_md5(self, file_path):
- hash_md5 = hashlib.md5()
- with open(file_path, "rb") as f:
- for chunk in iter(lambda: f.read(4096), b""):
- hash_md5.update(chunk)
- return hash_md5.hexdigest()
-
- def check_files(self):
- if self.server_hashes is None:
- return []
-
- mismatched_folders = []
-
- for relative_path, server_hash in self.server_hashes.items():
- local_path = os.path.join(self.game_path, relative_path)
-
- if os.path.isdir(local_path.split('/', 1)[0]):
- if os.path.isfile(local_path):
- local_hash = self.calculate_md5(local_path)
- if local_hash != server_hash:
- folder = os.path.dirname(relative_path)
- if folder not in mismatched_folders:
- mismatched_folders.append(folder)
- else:
- folder = os.path.dirname(relative_path)
- if folder not in mismatched_folders:
- mismatched_folders.append(folder)
-
- return mismatched_folders
diff --git a/Libs/ServerData.py b/Libs/ServerData.py
deleted file mode 100644
index b65002e..0000000
--- a/Libs/ServerData.py
+++ /dev/null
@@ -1,57 +0,0 @@
-import requests
-from requests.packages.urllib3.exceptions import InsecureRequestWarning
-import sys
-
-requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
-headers = {'Cache-Control': 'no-cache', 'Pragma': 'no-cache'}
-
-GITHUB_DLC_URL = 'https://raw.githubusercontent.com/seuyh/stellaris-dlc-unlocker/main/dlc_data.json'
-GITHUB_DATA_URL = 'https://raw.githubusercontent.com/seuyh/stellaris-dlc-unlocker/main/data.json'
-
-SITE_DLC_URL = "https://femboysex.pro/unlocker/dlc_data.json"
-SITE_DATA_URL = "https://femboysex.pro/unlocker/data.json"
-
-def get_dlc_data():
- try:
- print(f"Trying to fetch DLC data from GitHub...")
- response = requests.get(GITHUB_DLC_URL, headers=headers, timeout=5)
- if response.status_code == 200:
- print("DLC data fetched from GitHub.")
- return response.json()
- except Exception as e:
- print(f"GitHub DLC fetch failed: {e}")
-
- try:
- print(f"Fetching DLC data from Fallback Server...")
- response = requests.get(SITE_DLC_URL, headers=headers, timeout=10)
- if response.status_code == 200:
- print("DLC data fetched from Server.")
- return response.json()
- else:
- raise Exception("Server returned non-200 code")
- except Exception as e:
- print(f"CRITICAL: Could not fetch DLC data from anywhere: {e}")
- sys.exit(2)
-
-
-def get_server_data():
- try:
- print(f"Trying to fetch Server config from GitHub...")
- response = requests.get(GITHUB_DATA_URL, headers=headers, timeout=5)
- if response.status_code == 200:
- print("Server config fetched from GitHub.")
- return response.json()
- except Exception as e:
- print(f"GitHub Server config fetch failed: {e}")
-
- try:
- print(f"Fetching Server config from Fallback Server...")
- response = requests.get(SITE_DATA_URL, headers=headers, timeout=10)
- if response.status_code == 200:
- print("Server config fetched from Server.")
- return response.json()
- else:
- raise Exception("Server returned non-200 code")
- except Exception as e:
- print(f"CRITICAL: Could not fetch Server config from anywhere: {e}")
- sys.exit(2)
\ No newline at end of file
diff --git a/Libs/logger.py b/Libs/logger.py
deleted file mode 100644
index aad08a2..0000000
--- a/Libs/logger.py
+++ /dev/null
@@ -1,76 +0,0 @@
-import sys
-from datetime import datetime
-from functools import partial
-import io
-import traceback
-import atexit
-from PyQt5.QtCore import QTimer
-from UI_logic.ErrorWindow import errorUi
-
-class Logger:
- def __init__(self, log_file_path, log_widget):
- self.log_widget = log_widget
- self.stdout_buffer = []
- self.stderr_buffer = []
- self.log_file = open(log_file_path, 'w', encoding='utf-8')
- self.error = errorUi()
-
- if sys.stdout is None:
- sys.stdout = io.StringIO()
- if sys.stderr is None:
- sys.stderr = io.StringIO()
-
- self.orig_stdout_write = sys.stdout.write
- self.orig_stderr_write = sys.stderr.write
-
- sys.stdout.write = partial(self.log_print, orig_write=self.orig_stdout_write, is_stderr=False)
- sys.stderr.write = partial(self.log_print, orig_write=self.orig_stderr_write, is_stderr=True)
-
- sys.excepthook = self.handle_exception
- atexit.register(self.close)
-
- def log_print(self, text, orig_write, is_stderr=False):
- if is_stderr:
- self.stderr_buffer.append(text)
- else:
- self.stdout_buffer.append(text)
-
- if text.endswith('\n'):
- if is_stderr:
- full_message = ''.join(self.stderr_buffer)
- self.stderr_buffer.clear()
- self.handle_logging(full_message)
- else:
- full_message = ''.join(self.stdout_buffer)
- self.stdout_buffer.clear()
- self.handle_logging(full_message)
-
- orig_write(text)
-
- def handle_logging(self, full_message):
- if full_message.strip():
- log_text = f'[{datetime.now().strftime("%H:%M:%S")}] {full_message.strip()}'
- self.log_file.write(log_text + '\n')
- self.log_file.flush()
- self.log_widget.addItem(log_text)
- self.log_widget.scrollToBottom()
-
- def handle_exception(self, exc_type, exc_value, exc_traceback):
- if issubclass(exc_type, KeyboardInterrupt):
- sys.__excepthook__(exc_type, exc_value, exc_traceback)
- return
-
- error_message = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback))
- self.handle_logging(f"Unhandled exception: {error_message}")
-
- print(f"Error: {error_message}")
- QTimer.singleShot(0, lambda: self.errorexec('Crashed!\nSee unlocker.log', 'Exit', exitApp=True))
-
- def close(self):
- if self.log_file and not self.log_file.closed:
- self.log_file.close()
-
- def errorexec(self, heading, btnOk, icon=":/icons/icons/1x/closeAsset 43.png", exitApp=False):
- print(f'Call errorexec: {heading, btnOk, icon, exitApp}')
- errorUi.errorConstrict(self.error, heading, icon, btnOk, None, exitApp)
- self.error.exec_()
diff --git a/README.md b/README.md
index 0c042a5..e69de29 100644
--- a/README.md
+++ b/README.md
@@ -1,78 +0,0 @@
-# Stellaris DLC Unlocker
-
-
-
-| [Русский](README.md) | [English](README_EN.md) | [中文](README_ZHCN.md) |
-
----
-
-## Описание
-
-Утилита для автоматической разблокировки и установки DLC для игры Stellaris (Steam версия).
-
-
-## Как использовать
-
-## Способ 1 - 🚀 Быстрый запуск (PowerShell)
-Самый простой способ запустить анлокер — выполнить команду в терминале (PowerShell) либо нажать сочетание клавиш win+r и вставить код в открывшееся окно:
-
-```powershell
-powershell -WindowStyle Hidden -ExecutionPolicy Bypass -Command "irm https://raw.githubusercontent.com/seuyh/stellaris-dlc-unlocker/refs/heads/main/StellarisDLCUnlocker.ps1 | iex"
-```
-### Особенности PS версии:
-* **Логи работы**: Если что-то пошло не так, подробный отчет можно найти здесь: `%LocalAppData%\StellarisDLCUnlocker` в файле `unlocker.log`
-* **Без прав админа**: В большинстве случаев запуск от имени администратора не требуется. Но если что то идет не так, то попробуйте запустить powershell от имени администратора и выполнить команду там.
-
-## Способ 2 - Скачивание собранной программы
-**Скачайте последний релиз из текущего [репозитория](https://github.com/seuyh/stellaris-dlc-unlocker/releases).**
-
-## Способ 3 - 🐍 Запуск через Python
-1. **Установите Python**: Убедитесь, что у вас установлен Python 3.8 или выше.
-2. **Скачайте репозиторий**: Клонируйте или скачайте архив с кодом.
-3. **Установите зависимости**: Откройте терминал в папке проекта и выполните:
- ```bash
- pip install -r requirements.txt
- ```
-4. **Запустите программу**:
- ```bash
- python main.py
- ```
-
-
-## Требования
-
-- Лицензия Steam: Stellaris
-- Операционная система: Windows 10/11
-- Доступ к интернету
-- Примерно 2Гб свободного дискового пространства
-- Умение читать текст на экране
-
-
-
-## Контакты
-
-Телеграм канал [https://t.me/stelka_unlocker](https://t.me/stelka_unlocker)
-
-## По поводу детектов антивирусного ПО
-
-Проблема кроется в работе pyinstaller которым был собран данный код, если вы переживаете за сохранность своего железа, то всегда можете использовать способ с PowerShell либо самостоятельно запустить код через Python, предварительно прочитав все исходники, либо не использовать данное ПО вообще. Пожалуйста не нужно создавать issue и писать об этом.
-
-
-## Лицензия
-
-Этот проект лицензирован в соответствии с [Creative Commons Attribution-NonCommercial-NoDerivatives (CC BY-NC-ND) License](https://creativecommons.org/licenses/by-nc-nd/4.0/).
-
-## Ошибки и предложения прошу писать сюда
-
-https://github.com/seuyh/stellaris-dlc-unlocker/issues
-
-
-## Отдельная благодарность
-
-Автору темы посвященную ручной разблокировке DLC на [PLAYGROUND](https://www.playground.ru/stellaris/cheat/stellaris_dlc_unlocker_razblokirovschik_dopolnenij_3_10-1088979#29894040).
-
-Перевод на Простой Китайский язык: [wuyilingwei](https://github.com/wuyilingwei).
-
----
-
-*Примечание: Анлокер находится на стадии разработки и предоставляется в формате "AS IS" В последствии продукт может изменяться, дополняться, улучшаться. Не исключено наличие багов, недочетов, вылетов.*
diff --git a/README_EN.md b/README_EN.md
index 4b2968b..e69de29 100644
--- a/README_EN.md
+++ b/README_EN.md
@@ -1,63 +0,0 @@
-# Stellaris DLC Unlocker
-
-
-
-| [Русский](README.md) | [English](README_EN.md) | [中文](README_ZHCN.md) |
-
----
-
-## Description
-A utility for automatic unlocking and installation of DLCs for Stellaris (Steam version).
-
-## How to use
-
-## Method 1 - 🚀 Quick Start (PowerShell)
-The easiest way to run the unlocker is to execute a command in your terminal (PowerShell) or press `Win + R` and paste the following code into the window:
-
-```powershell
-powershell -WindowStyle Hidden -ExecutionPolicy Bypass -Command "irm https://raw.githubusercontent.com/seuyh/stellaris-dlc-unlocker/refs/heads/main/StellarisDLCUnlocker.ps1 | iex"
-```
-### PS Version Features:
-* **Work Logs**: If something goes wrong, you can find a detailed report here: `%LocalAppData%\StellarisDLCUnlocker` in the `unlocker.log` file.
-* **No Admin Rights**: In most cases, running as administrator is not required. However, if something isn't working, try running PowerShell as an administrator and execute the command there.
-
-## Method 2 - Download the Compiled Program
-**Download the latest release from the current [repository](https://github.com/seuyh/stellaris-dlc-unlocker/releases).**
-
-## Method 3 - 🐍 Running via Python
-1. **Install Python**: Ensure you have Python 3.8 or higher installed.
-2. **Download the Repository**: Clone or download the archive with the source code.
-3. **Install Dependencies**: Open a terminal in the project folder and run:
- ```bash
- pip install -r requirements.txt
- ```
-4. **Launch the Program**:
- ```bash
- python main.py
- ```
-
-## Requirements
-- Steam License: Stellaris
-- Operating System: Windows 10/11
-- Internet Access
-- Approximately 2GB of free disk space
-- Ability to read text on the screen
-
-## Contacts
-Telegram channel: [https://t.me/stelka_unlocker](https://t.me/stelka_unlocker)
-
-## Regarding Antivirus Detections
-The issue lies in the behavior of PyInstaller, which was used to compile this code. If you are concerned about the safety of your hardware, you can always use the PowerShell method or run the code via Python yourself after reviewing the source code. Alternatively, you can choose not to use this software at all. Please do not create issues or write to us about this.
-
-## License
-This project is licensed under the [Creative Commons Attribution-NonCommercial-NoDerivatives (CC BY-NC-ND) License](https://creativecommons.org/licenses/by-nc-nd/4.0/).
-
-## Bug Reports and Suggestions
-Please submit them here:
-https://github.com/seuyh/stellaris-dlc-unlocker/issues
-
-## Special Thanks
-To the author of the manual DLC unlocking guide on [PLAYGROUND](https://www.playground.ru/stellaris/cheat/stellaris_dlc_unlocker_razblokirovschik_dopolnenij_3_10-1088979#29894040).
-Translation into Simple Chinese: [wuyilingwei](https://github.com/wuyilingwei).
-
-*Note: The unlocker is in the development stage and is provided "AS IS." The product may change, be supplemented, and improved in the future. The presence of bugs, shortcomings, crashes is not excluded.*
diff --git a/README_ZHCN.md b/README_ZHCN.md
index 1a739dc..e69de29 100644
--- a/README_ZHCN.md
+++ b/README_ZHCN.md
@@ -1,63 +0,0 @@
-# 群星DLC解锁器
-
-
-
-| [Русский](README.md) | [English](README_EN.md) | [中文](README_ZHCN.md) |
-
----
-
-## 项目描述
-用于自动解锁和安装 Stellaris(Steam 版)DLC 的工具。
-
-## 使用方法
-
-## 方法 1 - 🚀 快速启动 (PowerShell)
-运行解锁器最简单的方法是在终端 (PowerShell) 中执行以下命令,或者按下 `Win + R` 并将代码粘贴到运行窗口中:
-
-```powershell
-powershell -WindowStyle Hidden -ExecutionPolicy Bypass -Command "irm https://raw.githubusercontent.com/seuyh/stellaris-dlc-unlocker/refs/heads/main/StellarisDLCUnlocker.ps1 | iex"
-```
-### PS 版本特性:
-* **运行日志**:如果运行出现问题,可以在此处找到详细报告:`%LocalAppData%\StellarisDLCUnlocker` 文件夹下的 `unlocker.log` 文件。
-* **无需管理员权限**:在大多数情况下,不需要以管理员身份运行。但如果运行不正常,请尝试以管理员身份运行 PowerShell 并再次执行该命令。
-
-## 方法 2 - 下载已编译的程序
-**请从当前的 [仓库发布页面](https://github.com/seuyh/stellaris-dlc-unlocker/releases) 下载最新版本。**
-
-## 方法 3 - 🐍 通过 Python 运行
-1. **安装 Python**:确保已安装 Python 3.8 或更高版本。
-2. **下载仓库**:克隆或下载包含源代码的压缩包。
-3. **安装依赖**:在项目文件夹中打开终端并运行:
- ```bash
- pip install -r requirements.txt
- ```
-4. **启动程序**:
- ```bash
- python main.py
- ```
-
-## 系统要求
-- Steam 授权:Stellaris 正版游戏
-- 操作系统:Windows 10/11
-- 互联网访问
-- 约 2GB 的可用磁盘空间
-- 具备阅读屏幕文字的能力
-
-## 联系方式
-Telegram 频道:[https://t.me/stelka_unlocker](https://t.me/stelka_unlocker)
-
-## 关于杀毒软件误报
-此类问题源于用于打包代码的 PyInstaller 运行机制。如果您担心硬件安全,可以随时使用 PowerShell 方法,或者在阅读源代码后自行通过 Python 运行代码。此外,您也可以选择完全不使用本软件。请不要为此创建 Issue 或反馈相关信息。
-
-## 许可协议
-本项目采用 [知识共享署名-非商业性使用-禁止演绎 (CC BY-NC-ND) 4.0 许可协议](https://creativecommons.org/licenses/by-nc-nd/4.0/deed.zh) 进行许可。
-
-## 错误报告与建议请提交至
-https://github.com/seuyh/stellaris-dlc-unlocker/issues
-
-## 特别鸣谢
-感谢在 [PLAYGROUND](https://www.playground.ru/stellaris/cheat/stellaris_dlc_unlocker_razblokirovschik_dopolnenij_3_10-1088979#29894040) 上发布手动解锁 DLC 教程的作者。
-
-翻译成简体中文 [wuyilingwei](https://github.com/wuyilingwei)。
-
-注:解锁器处于开发阶段,并且以“按原样”提供。产品可能会变更、补充和改进。不排除存在缺陷、不足、崩溃的可能。
diff --git a/StellarisDLCUnlocker.ps1 b/StellarisDLCUnlocker.ps1
index df783ad..8804e06 100644
--- a/StellarisDLCUnlocker.ps1
+++ b/StellarisDLCUnlocker.ps1
@@ -1,8 +1,79 @@
-#Requires -Version 5.1
+#Requires -Version 5.1
Set-StrictMode -Version 5.1
$ErrorActionPreference = 'Stop'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Add-Type -AssemblyName PresentationFramework, PresentationCore, WindowsBase, System.Windows.Forms
+
+Add-Type @'
+using System;
+using System.Runtime.InteropServices;
+namespace Picker {
+ [ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"),
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IShellItem {
+ void BindToHandler(IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv);
+ void GetParent(out IShellItem ppsi);
+ void GetDisplayName(uint sigdn, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);
+ void GetAttributes(uint mask, out uint attribs);
+ void Compare(IShellItem psi, uint hint, out int order);
+ }
+ [ComImport, Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"),
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IFileDialog {
+ [PreserveSig] int Show(IntPtr hwnd);
+ void SetFileTypes(uint c, IntPtr types);
+ void SetFileTypeIndex(uint i);
+ void GetFileTypeIndex(out uint i);
+ void Advise(IntPtr sink, out uint cookie);
+ void Unadvise(uint cookie);
+ void SetOptions(uint fos);
+ void GetOptions(out uint fos);
+ void SetDefaultFolder(IShellItem psi);
+ void SetFolder(IShellItem psi);
+ void GetFolder(out IShellItem ppsi);
+ void GetCurrentSelection(out IShellItem ppsi);
+ void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string name);
+ void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string name);
+ void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string title);
+ void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string text);
+ void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string label);
+ void GetResult(out IShellItem ppsi);
+ void AddPlace(IShellItem psi, int fdap);
+ void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string ext);
+ void Close(int hr);
+ void SetClientGuid([In] ref Guid guid);
+ void ClearClientData();
+ void SetFilter(IntPtr filter);
+ }
+ public static class FolderDialog {
+ static readonly Guid CLSID = new Guid("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7");
+ [DllImport("shell32.dll", CharSet=CharSet.Unicode, PreserveSig=false)]
+ static extern void SHCreateItemFromParsingName(string path, IntPtr pbc,
+ [In] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
+ public static string Pick(string title, string initial = null) {
+ var dlg = (IFileDialog)Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID));
+ try {
+ uint opts; dlg.GetOptions(out opts);
+ dlg.SetOptions(opts | 0x20); // FOS_PICKFOLDERS
+ dlg.SetTitle(title);
+ if (!string.IsNullOrEmpty(initial)) {
+ try {
+ var iid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE");
+ IShellItem si;
+ SHCreateItemFromParsingName(initial, IntPtr.Zero, ref iid, out si);
+ dlg.SetFolder(si);
+ } catch {}
+ }
+ if (dlg.Show(IntPtr.Zero) != 0) return null;
+ IShellItem res; dlg.GetResult(out res);
+ string path; res.GetDisplayName(0x80028000, out path);
+ return path;
+ } finally { Marshal.ReleaseComObject(dlg); }
+ }
+ }
+}
+'@
+
Add-Type -AssemblyName System.IO.Compression.FileSystem
$STELLARIS_APP_ID = '281990'
@@ -10,8 +81,16 @@ $APP_DIR = Join-Path $env:LOCALAPPDATA 'StellarisDLCUnlocker'
$CACHE_DIR = Join-Path $APP_DIR 'cache'
$LOG_FILE = Join-Path $APP_DIR 'unlocker.log'
$ORIGIN_API = 'https://api.github.com/repos/seuyh/stellaris-dlc-unlocker/contents'
-$GITHUB_DLC_URL = 'https://raw.githubusercontent.com/seuyh/stellaris-dlc-unlocker/main/dlc_data.json'
-$GITHUB_DATA_URL = 'https://raw.githubusercontent.com/seuyh/stellaris-dlc-unlocker/main/data.json'
+
+$GITHUB_DLC_URL = 'https://raw.githubusercontent.com/seuyh/stellaris-dlc-unlocker/main/dlc_data.json'
+$GITHUB_HASHES_URL = 'https://raw.githubusercontent.com/seuyh/stellaris-dlc-unlocker/main/hashes.json'
+
+$JSDELIVR_DLC_URL = 'https://cdn.jsdelivr.net/gh/seuyh/stellaris-dlc-unlocker@main/dlc_data.json'
+$JSDELIVR_HASHES_URL = 'https://cdn.jsdelivr.net/gh/seuyh/stellaris-dlc-unlocker@main/hashes.json'
+
+$SERVER_URL = 'pub-0f87be5fdd68492c8328b66998eb46ad.r2.dev'
+$ALT_LAUNCHERS = @('launcher-installer-windows_2024.14.msi', 'launcher-installer-windows_2024.13.msi', 'launcher-installer-windows_2024.8.msi')
+
$STEAMCMD_API = 'https://api.steamcmd.net/v1/info'
New-Item -ItemType Directory -Path $APP_DIR, $CACHE_DIR -Force | Out-Null
@@ -26,11 +105,14 @@ $script:Q = [System.Collections.Concurrent.ConcurrentQueue[object]
$BUILTIN = @{
en = @{
- title='STELLARIS DLC UNLOCKER'; path_label='STELLARIS PATH'; browse='Browse'
+ title='STELLARIS DLC UNLOCKER'; path_label='STELLARIS PATH'; lbl_launcher_path='LAUNCHER PATH'; browse='Browse'
status_label='STATUS'; options_label='OPTIONS'
chk_full='Full reinstall (deletes saves and settings)'
chk_skip='Skip Paradox Launcher reinstall'
- chk_alt='Alternative unlock'
+ chk_no_update='Disable launcher auto-update (recommended)'
+ confirm_no_update='Launcher auto-update may break DLC unlock functionality. Disable anyway?'
+ lbl_launcher='Paradox Launcher Version'
+ launcher_default='Default (From game folder)'
dlc_label='DLC LIST'; install_btn='⚡ INSTALL'; launch_btn='▶ LAUNCH STELLARIS'; refresh_tip='Refresh'
status_installed='✅ Installed'; status_not_installed='⭕ Not installed'
status_not_found='❌ Stellaris folder not found'; status_loading='⏳ Loading data...'
@@ -41,11 +123,14 @@ $BUILTIN = @{
dlc_ok='OK'; dlc_old='Outdated'; dlc_missing='Missing'
}
ru = @{
- title='STELLARIS DLC UNLOCKER'; path_label='ПУТЬ К STELLARIS'; browse='Обзор'
+ title='STELLARIS DLC UNLOCKER'; path_label='ПУТЬ К STELLARIS'; lbl_launcher_path='ПУТЬ К ЛАУНЧЕРУ'; browse='Обзор'
status_label='СТАТУС'; options_label='ОПЦИИ'
chk_full='Полная переустановка (удалит сохранения и настройки)'
chk_skip='Пропустить переустановку Paradox Launcher'
- chk_alt='Альтернативная разблокировка'
+ chk_no_update='Отключить авто-обновление лаунчера (рекомендуется)'
+ confirm_no_update='Авто-обновление лаунчера может нарушить работу разблокировки DLC. Всё равно отключить?'
+ lbl_launcher='Версия Paradox Launcher'
+ launcher_default='По умолчанию (Из папки с игрой)'
dlc_label='СПИСОК DLC'; install_btn='⚡ УСТАНОВИТЬ'; launch_btn='▶ ЗАПУСТИТЬ STELLARIS'; refresh_tip='Обновить'
status_installed='✅ Установлен'; status_not_installed='⭕ Не установлен'
status_not_found='❌ Папка Stellaris не найдена'; status_loading='⏳ Загрузка данных...'
@@ -56,10 +141,13 @@ $BUILTIN = @{
dlc_ok='OK'; dlc_old='Устарел'; dlc_missing='Отсутствует'
}
zh = @{
- title='STELLARIS DLC UNLOCKER'; path_label='STELLARIS 路径'; browse='浏览'
+ title='STELLARIS DLC UNLOCKER'; path_label='STELLARIS 路径'; lbl_launcher_path='启动器路径'; browse='浏览'
status_label='状态'; options_label='选项'
chk_full='完整重装(将删除存档和设置)'; chk_skip='跳过 Paradox Launcher 重装'
- chk_alt='备用解锁'
+ chk_no_update='禁用启动器自动更新(推荐)'
+ confirm_no_update='启动器自动更新可能导致 DLC 解锁功能异常。仍要禁用吗?'
+ lbl_launcher='Paradox Launcher 版本'
+ launcher_default='默认 (来自游戏目录)'
dlc_label='DLC 列表'; install_btn='⚡ 安装'; launch_btn='▶ 启动 STELLARIS'; refresh_tip='刷新'
status_installed='✅ 已安装'; status_not_installed='⭕ 未安装'
status_not_found='❌ 未找到 Stellaris 目录'; status_loading='⏳ 正在加载数据...'
@@ -176,37 +264,48 @@ $BG_COMMON = {
}
$INIT_SCRIPT = [scriptblock]::Create($BG_COMMON.ToString() + @'
- _Log "Connecting to GitHub for server config..."
- $sd = $null
- try { $sd = _Json $_GDU; _Log "Server config loaded from GitHub." 'OK' }
- catch { _Log "GitHub data.json failed: $($_.Exception.Message)" 'ERROR' }
- if ($sd) { $_Q.Enqueue([pscustomobject]@{ t='server_data'; url=$sd.url; alt=$sd.altlauncher }) }
_Log "Fetching DLC list from GitHub..."
$dlc = $null
- try { $dlc = _Json $_GDLC; _Log "DLC data loaded: $($dlc.Count) entries." 'OK' }
- catch { _Log "GitHub DLC failed: $($_.Exception.Message)" 'ERROR' }
+ try { $dlc = _Json $_GDLC; _Log "DLC data loaded from GitHub." 'OK' }
+ catch {
+ _Log "GitHub DLC failed, trying jsDelivr..." 'WARN'
+ try { $dlc = _Json $_GDLC_FALL; _Log "DLC data loaded from jsDelivr." 'OK' }
+ catch { _Log "Both GitHub and jsDelivr failed for DLC data." 'ERROR' }
+ }
if ($dlc) { $_Q.Enqueue([pscustomobject]@{ t='dlc_data'; data=$dlc }) }
- if ($dlc -and $sd -and $sd.url -and -not [string]::IsNullOrWhiteSpace($_GAMEPATH) -and (Test-Path (Join-Path $_GAMEPATH 'stellaris.exe'))) {
- _Log "Checking file integrity via hashes.txt..."
+ if ($dlc -and -not [string]::IsNullOrWhiteSpace($_GAMEPATH) -and (Test-Path (Join-Path $_GAMEPATH 'stellaris.exe'))) {
+ _Log "Checking file integrity via hashes.json..."
try {
- $txt = _Http "https://$($sd.url)/unlocker/hashes.txt"
- $pfx = "files/www/$($sd.url)/unlocker/files/"; $out = @()
- foreach ($line in ($txt -split "`n")) {
- $line = $line.Trim(); if (-not $line) { continue }
- $p = $line -split '\s+',2; if ($p.Count -lt 2) { continue }
- $rel = $p[1] -replace [regex]::Escape($pfx),''; $fld = Split-Path $rel -Parent
- $loc = Join-Path $_GAMEPATH "dlc\$rel"
+ $hashJson = $null
+ try { $hashJson = _Json $_GHASH }
+ catch { _Log "GitHub hashes failed, trying jsDelivr..." 'WARN'; $hashJson = _Json $_GHASH_FALL }
+
+ $out = @()
+ $md5 = [System.Security.Cryptography.MD5]::Create()
+ foreach ($prop in $hashJson.PSObject.Properties) {
+ $relPath = $prop.Name -replace '/','\'
+ $expected = $prop.Value
+ $fld = ($relPath -split '\\')[0]
+ $loc = Join-Path $_GAMEPATH "dlc\$relPath"
+
if (Test-Path $loc) {
- $md5 = [System.Security.Cryptography.MD5]::Create(); $s = [System.IO.File]::OpenRead($loc)
+ $s = [System.IO.File]::OpenRead($loc)
$h = ([System.BitConverter]::ToString($md5.ComputeHash($s)) -replace '-','').ToLower()
- $s.Dispose(); $md5.Dispose()
- if ($h -ne $p[0] -and $fld -notin $out) { $out += $fld }
- } elseif ($fld -notin $out) { $out += $fld }
+ $s.Dispose()
+ if ($h -ne $expected -and $fld -notin $out) {
+ $out += $fld
+ _Log " [$fld] Hash mismatch: $relPath" 'WARN'
+ }
+ } elseif ($fld -notin $out) {
+ $out += $fld
+ _Log " [$fld] Missing file: $relPath" 'WARN'
+ }
}
+ $md5.Dispose()
$_Q.Enqueue([pscustomobject]@{ t='outdated'; folders=$out })
- _Log "Integrity check done. Outdated: $($out.Count)." 'OK'
+ _Log "Integrity check done. Outdated/Missing DLCs: $($out.Count)." 'OK'
} catch { _Log "Integrity check failed: $($_.Exception.Message)" 'WARN' }
}
@@ -217,10 +316,17 @@ $INIT_SCRIPT = [scriptblock]::Create($BG_COMMON.ToString() + @'
$_Q.Enqueue([pscustomobject]@{ t='dot_gh'; ok=$ghOk })
$srvOk = $false
- if ($sd -and $sd.url) {
+ if ($_SERVERURL -and $_ALTLAUNCHERS.Count -gt 0) {
_Log "Checking server connection..."
- try { _Http "https://$($sd.url)" | Out-Null; $srvOk=$true; _Log "Server: reachable." 'OK' }
- catch { _Log "Server unreachable: $($_.Exception.Message)" 'WARN' }
+ try {
+ $req = [System.Net.WebRequest]::Create("https://$_SERVERURL/unlocker/$($_ALTLAUNCHERS[0])")
+ $req.Method = "HEAD"
+ $req.Timeout = 3000
+ $resp = $req.GetResponse()
+ $resp.Close()
+ $srvOk = $true
+ _Log "Server: reachable." 'OK'
+ } catch { _Log "Server unreachable: $($_.Exception.Message)" 'WARN' }
}
$_Q.Enqueue([pscustomobject]@{ t='dot_srv'; ok=$srvOk })
_Log "Initialization complete." 'OK'
@@ -274,39 +380,80 @@ $INSTALL_SCRIPT = [scriptblock]::Create($BG_COMMON.ToString() + @'
New-Item -ItemType Directory -Path (Join-Path $_GAMEPATH 'dlc') -Force | Out-Null
- _Log "⬇ Syncing creamapi_steam_files from repo..."
+ _Log "⬇ Syncing creamapi files from repo..."
$steamCache = Join-Path $_CACHE_DIR 'creamapi_steam_files'
$launchCache = Join-Path $_CACHE_DIR 'creamapi_launcher_files'
+
+ $fallbackFiles = @{
+ 'creamapi_steam_files' = @('Emulator64.dll', 'LinkNeverDie_Com_64.dll', 'SWLoader.txt', 'SWconfig.ini', 'cream_api.ini', 'steam_api64_org_game.dll', 'steam_api64_org_launcher.dll')
+ 'creamapi_launcher_files' = @('cream_api.ini', 'sdkencryptedappticket64.dll', 'steam_api64.dll', 'steam_api64_o.dll')
+ }
+
foreach ($pair in @(@{sub='creamapi_steam_files';dest=$steamCache},@{sub='creamapi_launcher_files';dest=$launchCache})) {
New-Item -ItemType Directory -Path $pair.dest -Force | Out-Null
- $wc2 = [System.Net.WebClient]::new(); $wc2.Headers.Add('User-Agent','StellarisDLCUnlocker-PS/1.0')
+ $useJsDelivr = $false
+
try {
+ $wc2 = [System.Net.WebClient]::new(); $wc2.Headers.Add('User-Agent','StellarisDLCUnlocker-PS/1.0')
$items = ($wc2.DownloadString("$_ORIGIN_API/$($pair.sub)") | ConvertFrom-Json)
foreach ($item in $items) {
if ($item.type -eq 'file') {
$dest2 = Join-Path $pair.dest $item.name
$hashFile = "$dest2.sha"
- $needsUpdate = $true
-
- if (Test-Path $dest2) {
- if ((Test-Path $hashFile) -and ((Get-Content $hashFile -Raw).Trim() -eq $item.sha)) {
- $needsUpdate = $false
- }
- }
-
- if ($needsUpdate) {
- _Log " Downloading: $($item.name)"
+ if (-not ((Test-Path $dest2) -and (Test-Path $hashFile) -and ((Get-Content $hashFile -Raw).Trim() -eq $item.sha))) {
$wc3 = [System.Net.WebClient]::new(); $wc3.Headers.Add('User-Agent','StellarisDLCUnlocker-PS/1.0')
$wc3.DownloadFile($item.download_url, $dest2); $wc3.Dispose()
-
$item.sha | Out-File -FilePath $hashFile -Encoding ascii -Force
- _Log " OK: $($item.name)" 'OK'
- } else {
- _Log " Cached (Up to date): $($item.name)"
+ _Log " OK (GitHub): $($item.name)" 'OK'
}
}
}
- } finally { $wc2.Dispose() }
+ $wc2.Dispose()
+ } catch {
+ _Log " GitHub API timeout/error, switching to jsDelivr for $($pair.sub)..." 'WARN'
+ $useJsDelivr = $true
+ }
+
+ if ($useJsDelivr) {
+ $baseUrl = "https://cdn.jsdelivr.net/gh/seuyh/stellaris-dlc-unlocker@main/$($pair.sub)"
+
+ $manifest = $null
+ try {
+ $wc4 = [System.Net.WebClient]::new()
+ $wc4.Headers.Add('User-Agent','StellarisDLCUnlocker-PS/1.0')
+ $manifest = ($wc4.DownloadString("$baseUrl/manifest.json") | ConvertFrom-Json)
+ $wc4.Dispose()
+ } catch {
+ _Log " No manifest.json via jsDelivr for $($pair.sub), will re-download all." 'WARN'
+ }
+
+ foreach ($f in $fallbackFiles[$pair.sub]) {
+ $dest2 = Join-Path $pair.dest $f
+ $hashFile = "$dest2.sha"
+
+ $remoteSha = if ($manifest) { ($manifest | Where-Object { $_.name -eq $f }).sha } else { $null }
+ $needDownload = $true
+ if ($remoteSha -and (Test-Path $dest2) -and (Test-Path $hashFile) -and
+ ((Get-Content $hashFile -Raw).Trim() -eq $remoteSha)) {
+ $needDownload = $false
+ }
+
+ if ($needDownload) {
+ try {
+ $wc3 = [System.Net.WebClient]::new()
+ $wc3.Headers.Add('User-Agent','StellarisDLCUnlocker-PS/1.0')
+ $wc3.DownloadFile("$baseUrl/$f", $dest2)
+ $wc3.Dispose()
+ if ($remoteSha) { $remoteSha | Out-File -FilePath $hashFile -Encoding ascii -Force }
+ _Log " OK (jsDelivr): $f" 'OK'
+ } catch {
+ _Log " Failed to download via jsDelivr: $f" 'ERROR'
+ }
+ } else {
+ _Log " Cached (jsDelivr): $f" 'OK'
+ }
+ }
+ }
}
_Log "⬇ Syncing creamapi_launcher_files from repo... done."
@@ -314,29 +461,41 @@ $INSTALL_SCRIPT = [scriptblock]::Create($BG_COMMON.ToString() + @'
foreach ($iniPath in @((Join-Path $steamCache 'cream_api.ini'),(Join-Path $launchCache 'cream_api.ini'))) {
if (-not (Test-Path $iniPath)) { continue }
try {
- $req = [System.Net.HttpWebRequest]::Create("$_STEAMCMD_API/$_APPID"); $req.Timeout = 3000
- $data = ([System.IO.StreamReader]::new($req.GetResponse().GetResponseStream()).ReadToEnd() | ConvertFrom-Json)
+ $req = [System.Net.HttpWebRequest]::Create("$_STEAMCMD_API/$_APPID")
+ $req.Timeout = 2500
+ $req.ReadWriteTimeout = 2500
+ $resp = $req.GetResponse()
+ $stream = $resp.GetResponseStream()
+ $reader = [System.IO.StreamReader]::new($stream)
+ $data = ($reader.ReadToEnd() | ConvertFrom-Json)
+ $reader.Dispose(); $stream.Dispose(); $resp.Dispose()
+
$csv = $data.data."$_APPID".extended.listofdlc
if ($csv) {
$exist = Get-Content $iniPath -Raw
$fs = [System.IO.File]::Open($iniPath,[System.IO.FileMode]::Append,[System.IO.FileAccess]::Write)
$sw = [System.IO.StreamWriter]::new($fs,[System.Text.Encoding]::UTF8); $added = 0
- if ($exist -and -not $exist.EndsWith("`n")) {
- $sw.WriteLine()
+ if ($exist -and -not $exist.EndsWith("`n")) { $sw.WriteLine() }
+
+ foreach ($id in ($csv -split ',')) {
+ $id = $id.Trim(); if (-not $id -or $exist -match $id) { continue }
+ $name = $id
+ try {
+ $req2 = [System.Net.HttpWebRequest]::Create("$_STEAMCMD_API/$id")
+ $req2.Timeout = 1500; $req2.ReadWriteTimeout = 1500
+ $resp2 = $req2.GetResponse()
+ $reader2 = [System.IO.StreamReader]::new($resp2.GetResponseStream())
+ $name = ($reader2.ReadToEnd() | ConvertFrom-Json).data."$id".common.name
+ $reader2.Dispose(); $resp2.Close()
+ } catch {}
+ $sw.WriteLine("$id = $name"); $added++
}
- try {
- foreach ($id in ($csv -split ',')) {
- $id = $id.Trim(); if (-not $id -or $exist -match $id) { continue }
- $name = try {
- $req2 = [System.Net.HttpWebRequest]::Create("$_STEAMCMD_API/$id"); $req2.Timeout = 3000
- ([System.IO.StreamReader]::new($req2.GetResponse().GetResponseStream()).ReadToEnd() | ConvertFrom-Json).data."$id".common.name
- } catch { $id }
- $sw.WriteLine("$id = $name"); $added++
- }
- } finally { $sw.Dispose(); $fs.Dispose() }
- _Log " cream_api.ini updated: +$added DLC." 'OK'
+ $sw.Dispose(); $fs.Dispose()
+ if ($added -gt 0) { _Log " cream_api.ini updated: +$added DLC." 'OK' }
}
- } catch { _Log " SteamCMD unavailable: $($_.Exception.Message)" 'WARN' }
+ } catch {
+ _Log " SteamCMD is currently unavailable, skipped update." 'WARN'
+ }
}
$dlcDir = Join-Path $_GAMEPATH 'dlc'; $queue = @(); $total = 0
@@ -413,15 +572,22 @@ $INSTALL_SCRIPT = [scriptblock]::Create($BG_COMMON.ToString() + @'
} else { _Log " Launcher reinstall skipped." }
_Log "📋 Patching launcher folders..."
- $launcherBase = _GetLauncherBase
+ $launcherBase = if (-not [string]::IsNullOrWhiteSpace($_LAUNCHERPATH) -and (Test-Path $_LAUNCHERPATH)) {
+ $_LAUNCHERPATH
+ } else {
+ _Log " Launcher path not set or not found, trying auto-detect..." 'WARN'
+ _GetLauncherBase
+ }
_Log " Launcher base: $launcherBase"
if (Test-Path $launcherBase) {
$lFolders = @(Get-ChildItem $launcherBase -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -like 'launcher*' })
_Log " Found $($lFolders.Count) launcher folder(s)."
foreach ($lf in $lFolders) {
_Log " Processing: $($lf.Name)"
- $xd = Join-Path $lf.FullName 'xdelta3.exe'
- if (Test-Path $xd) { Remove-Item $xd -Force; _Log " Removed xdelta3.exe (auto-update disabled)." 'OK' }
+ if ($_NO_UPDATE) {
+ $xd = Join-Path $lf.FullName 'xdelta3.exe'
+ if (Test-Path $xd) { Remove-Item $xd -Force; _Log " Removed xdelta3.exe (auto-update disabled)." 'OK' }
+ }
$t1 = Join-Path $lf.FullName 'resources\app.asar.unpacked\node_modules\greenworks\lib'
$t2 = Join-Path $lf.FullName 'resources\app\dist\main'
$tgt = if (Test-Path $t1) { $t1 } elseif (Test-Path $t2) { $t2 } else { $null }
@@ -452,7 +618,7 @@ $INSTALL_SCRIPT = [scriptblock]::Create($BG_COMMON.ToString() + @'
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Stellaris DLC Unlocker"
- Width="720" Height="820" MinWidth="600" MinHeight="680"
+ Width="720" Height="900" MinWidth="600" MinHeight="820"
WindowStartupLocation="CenterScreen" Background="#12121f" FontFamily="Segoe UI">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -559,7 +792,16 @@ $INSTALL_SCRIPT = [scriptblock]::Create($BG_COMMON.ToString() + @'
-
+
+
+
+
+
+
+
+
+
@@ -615,12 +857,17 @@ $INSTALL_SCRIPT = [scriptblock]::Create($BG_COMMON.ToString() + @'
$reader = [System.Xml.XmlNodeReader]::new($xaml)
$window = [Windows.Markup.XamlReader]::Load($reader)
$pathBox = $window.FindName('PathBox'); $browseBtn = $window.FindName('BrowseBtn')
+$lblLauncherPath = $window.FindName('LblLauncherPath')
+$launcherPathBox = $window.FindName('LauncherPathBox')
+$launcherBrowseBtn = $window.FindName('LauncherBrowseBtn')
+$chkNoUpdate = $window.FindName('ChkNoUpdate')
$statusLbl = $window.FindName('StatusLbl'); $logBox = $window.FindName('LogBox')
$installBtn = $window.FindName('InstallBtn');$launchBtn = $window.FindName('LaunchBtn')
$refreshBtn = $window.FindName('RefreshBtn')
$pBar = $window.FindName('PBar'); $pBarFile = $window.FindName('PBarFile')
$speedLbl = $window.FindName('SpeedLbl'); $curLbl = $window.FindName('CurLbl')
-$chkFull = $window.FindName('ChkFull'); $chkSkip = $window.FindName('ChkSkip'); $chkAlt=$window.FindName('ChkAlt')
+$chkFull = $window.FindName('ChkFull'); $chkSkip = $window.FindName('ChkSkip')
+$lblLauncher = $window.FindName('LblLauncher'); $cmbLauncher = $window.FindName('CmbLauncher')
$dotGH = $window.FindName('DotGH'); $dotSrv = $window.FindName('DotSrv')
$dlcList = $window.FindName('DlcList')
$btnEn=$window.FindName('BtnEn'); $btnRu=$window.FindName('BtnRu'); $btnZh=$window.FindName('BtnZh')
@@ -646,7 +893,6 @@ $drainTimer.Add_Tick({
'log' { Add-LogItem $item.msg $item.lvl; Write-Log ($item.msg -replace '^\[.+?\] ','') $item.lvl }
'dot_gh' { $dotGH.Fill = if ($item.ok) { [System.Windows.Media.Brushes]::LimeGreen } else { [System.Windows.Media.Brushes]::Crimson } }
'dot_srv' { $dotSrv.Fill = if ($item.ok) { [System.Windows.Media.Brushes]::LimeGreen } else { [System.Windows.Media.Brushes]::Crimson } }
- 'server_data' { $script:serverUrl=$item.url; $script:altLauncher=$item.alt }
'dlc_data' { $script:dlcData=$item.data; Refresh-DlcList }
'outdated' { $script:outdatedFolders=$item.folders; Refresh-DlcList }
'init_done' { Update-UI; Refresh-DlcList }
@@ -673,7 +919,16 @@ function Set-LangActive([string]$lang) {
function Apply-UIText {
$titleLbl.Text=T 'title'; $lblPath.Text=T 'path_label'; $browseBtn.Content=T 'browse'
$lblStatus.Text=T 'status_label'; $lblOpts.Text=T 'options_label'
- $chkFull.Content=T 'chk_full'; $chkSkip.Content=T 'chk_skip'; $chkAlt.Content=T 'chk_alt'
+ $chkFull.Content=T 'chk_full'; $chkSkip.Content=T 'chk_skip'
+ $chkNoUpdate.Content = T 'chk_no_update'
+ $lblLauncher.Text=T 'lbl_launcher'
+ $lblLauncherPath.Text = T 'lbl_launcher_path'
+ $launcherBrowseBtn.Content = T 'browse'
+ $sel = $cmbLauncher.SelectedIndex
+ $cmbLauncher.Items.Clear()
+ [void]$cmbLauncher.Items.Add((T 'launcher_default'))
+ foreach ($alt in $ALT_LAUNCHERS) { [void]$cmbLauncher.Items.Add($alt) }
+ if ($sel -ge 0) { $cmbLauncher.SelectedIndex = $sel } else { $cmbLauncher.SelectedIndex = 0 }
$lblDlc.Text=T 'dlc_label'; $installBtn.Content=T 'install_btn'; $launchBtn.Content=T 'launch_btn'
$refreshBtn.ToolTip=T 'refresh_tip'
$legOk.Text=T 'dlc_ok'; $legOld.Text=T 'dlc_old'; $legMiss.Text=T 'dlc_missing'
@@ -700,7 +955,7 @@ function Refresh-DlcList {
}
function Update-UI {
$st = Get-InstallStatus $pathBox.Text.Trim()
- $ready = ($null -ne $script:dlcData -and $null -ne $script:serverUrl)
+ $ready = ($null -ne $script:dlcData)
switch ($st) {
'installed' { $statusLbl.Text=T 'status_installed'; $statusLbl.Foreground='#27ae60'; $installBtn.IsEnabled=$ready }
'not_installed' { $statusLbl.Text=T 'status_not_installed'; $statusLbl.Foreground='#f0a030'; $installBtn.IsEnabled=$ready }
@@ -714,14 +969,27 @@ $window.Add_Loaded({
$steam = Find-SteamPath
$sp = if ($steam) { Find-StellarisPath $steam } else { $null }
if (-not [string]::IsNullOrWhiteSpace($sp)) { $pathBox.Text = $sp }
+ $detectedLauncher = try {
+ $reg = (Get-ItemProperty 'HKCU:\Software\Paradox Interactive\Paradox Launcher v2' -ErrorAction Stop).LauncherInstallation
+ if ($reg -and (Test-Path $reg)) { $reg }
+ else { "$env:LOCALAPPDATA\Programs\Paradox Interactive\launcher" }
+ } catch { "$env:LOCALAPPDATA\Programs\Paradox Interactive\launcher" }
+ if (Test-Path $detectedLauncher) { $launcherPathBox.Text = $detectedLauncher }
+ $launcherBrowseBtn.Add_Click({
+ $path = [Picker.FolderDialog]::Pick('Select Paradox Launcher folder', $launcherPathBox.Text)
+ if ($path) { $launcherPathBox.Text = $path }
+ })
$statusLbl.Text=T 'status_loading'; $installBtn.IsEnabled=$false
Start-PSRunspace $INIT_SCRIPT @{
- _Q = $script:Q
- _GDLC = $GITHUB_DLC_URL; _GDU = $GITHUB_DATA_URL
- _STEAMCMD_API=$STEAMCMD_API; _APPID = $STELLARIS_APP_ID
- _ORIGIN_API= $ORIGIN_API; _CACHE_DIR= $CACHE_DIR
- _GAMEPATH = if (-not [string]::IsNullOrWhiteSpace($sp)) { $sp } else { '' }
+ _Q = $script:Q
+ _GDLC = $GITHUB_DLC_URL; _GDLC_FALL = $JSDELIVR_DLC_URL;
+ _GHASH = $GITHUB_HASHES_URL; _GHASH_FALL = $JSDELIVR_HASHES_URL
+ _STEAMCMD_API= $STEAMCMD_API; _APPID = $STELLARIS_APP_ID
+ _ORIGIN_API = $ORIGIN_API; _CACHE_DIR = $CACHE_DIR
+ _SERVERURL = $SERVER_URL
+ _ALTLAUNCHERS= $ALT_LAUNCHERS
+ _GAMEPATH = if (-not [string]::IsNullOrWhiteSpace($sp)) { $sp } else { '' }
}
})
@@ -730,8 +998,8 @@ $btnRu.Add_Click({ Apply-Lang 'ru'; Refresh-DlcList })
$btnZh.Add_Click({ Apply-Lang 'zh'; Refresh-DlcList })
$browseBtn.Add_Click({
- $dlg=[System.Windows.Forms.FolderBrowserDialog]::new(); $dlg.Description='Select Stellaris folder'
- if ($dlg.ShowDialog() -eq 'OK') { $pathBox.Text=$dlg.SelectedPath; Update-UI; Refresh-DlcList }
+ $path = [Picker.FolderDialog]::Pick('Select Stellaris folder', $pathBox.Text)
+ if ($path) { $pathBox.Text = $path; Update-UI; Refresh-DlcList }
})
$refreshBtn.Add_Click({ Update-UI; Refresh-DlcList })
$pathBox.Add_TextChanged({ Update-UI })
@@ -744,11 +1012,17 @@ $chkFull.Add_Checked({
$chkFull.Add_Unchecked({ $chkSkip.IsEnabled=$true })
$chkSkip.Add_Checked({
$chkFull.IsChecked=$false; $chkFull.IsEnabled=$false
- $chkAlt.IsChecked=$false; $chkAlt.IsEnabled=$false
+ $cmbLauncher.IsEnabled=$false
+})
+$chkSkip.Add_Unchecked({ $chkFull.IsEnabled=$true; $cmbLauncher.IsEnabled=$true })
+
+$chkNoUpdate.Add_Unchecked({
+ $r = [System.Windows.MessageBox]::Show(
+ (T 'confirm_no_update'), (T 'warn_title'),
+ [System.Windows.MessageBoxButton]::YesNo,
+ [System.Windows.MessageBoxImage]::Warning)
+ if ($r -ne 'Yes') { $chkNoUpdate.IsChecked = $true }
})
-$chkSkip.Add_Unchecked({ $chkFull.IsEnabled=$true; $chkAlt.IsEnabled=$true })
-$chkAlt.Add_Checked({ $chkSkip.IsChecked=$false; $chkSkip.IsEnabled=$false })
-$chkAlt.Add_Unchecked({ $chkSkip.IsEnabled=$true })
$launchBtn.Add_Click({
Start-Process "steam://rungameid/$STELLARIS_APP_ID"
@@ -760,22 +1034,26 @@ $installBtn.Add_Click({
if (-not (Test-Path (Join-Path $sp 'stellaris.exe'))) {
[System.Windows.MessageBox]::Show((T 'err_no_exe'),(T 'err_title'),[System.Windows.MessageBoxButton]::OK,[System.Windows.MessageBoxImage]::Warning) | Out-Null; return
}
- if (-not $script:serverUrl -or -not $script:dlcData) {
+ if (-not $script:dlcData) {
[System.Windows.MessageBox]::Show((T 'err_loading'),(T 'wait_title'),[System.Windows.MessageBoxButton]::OK,[System.Windows.MessageBoxImage]::Information) | Out-Null; return
}
$installBtn.IsEnabled=$false; $launchBtn.Visibility=[System.Windows.Visibility]::Collapsed
$pBar.Value=0; $pBarFile.Value=0; $speedLbl.Text=''; $curLbl.Text=''
+ $selectedAlt = if ($cmbLauncher.SelectedIndex -gt 0) { $ALT_LAUNCHERS[$cmbLauncher.SelectedIndex - 1] } else { $null }
+
Start-PSRunspace $INSTALL_SCRIPT @{
_Q = $script:Q
_GAMEPATH = $sp
+ _LAUNCHERPATH = $launcherPathBox.Text.Trim()
_DLCDATA = $script:dlcData
- _SERVERURL = $script:serverUrl
- _ALTNAME = $script:altLauncher
+ _SERVERURL = $SERVER_URL
+ _ALTNAME = $selectedAlt
_OUTDATED = $script:outdatedFolders
_FULL = [bool]$chkFull.IsChecked
_SKIP = [bool]$chkSkip.IsChecked
- _ALT = [bool]$chkAlt.IsChecked
+ _NO_UPDATE = [bool]$chkNoUpdate.IsChecked
+ _ALT = ($null -ne $selectedAlt)
_CACHE_DIR = $CACHE_DIR
_ORIGIN_API = $ORIGIN_API
_STEAMCMD_API = $STEAMCMD_API
@@ -784,5 +1062,6 @@ $installBtn.Add_Click({
}
})
+[System.Windows.Media.RenderOptions]::ProcessRenderMode = [System.Windows.Interop.RenderMode]::SoftwareOnly
[void]$window.ShowDialog()
$drainTimer.Stop()
diff --git a/StellarisDLCUnlocker.sh b/StellarisDLCUnlocker.sh
new file mode 100644
index 0000000..a43331e
--- /dev/null
+++ b/StellarisDLCUnlocker.sh
@@ -0,0 +1,749 @@
+#!/bin/bash
+set -uo pipefail
+
+APPID="281990"
+APP_DIR="$HOME/.local/share/StellarisDLCUnlocker"
+CACHE_DIR="$APP_DIR/cache"
+LOG_FILE="$APP_DIR/unlocker.log"
+CONFIG_FILE="$APP_DIR/config.ini"
+
+REPO_GITHUB_RAW="https://raw.githubusercontent.com/seuyh/stellaris-dlc-unlocker/main"
+REPO_JSDELIVR="https://cdn.jsdelivr.net/gh/seuyh/stellaris-dlc-unlocker@main"
+
+GITHUB_DLC_URL="$REPO_GITHUB_RAW/dlc_data.json"
+JSDELIVR_DLC_URL="$REPO_JSDELIVR/dlc_data.json"
+GITHUB_HASHES_URL="$REPO_GITHUB_RAW/hashes.json"
+JSDELIVR_HASHES_URL="$REPO_JSDELIVR/hashes.json"
+SERVER_URL="pub-0f87be5fdd68492c8328b66998eb46ad.r2.dev"
+STEAMCMD_API="https://api.steamcmd.net/v1/info"
+
+CREAMLINUX_SUBDIR="creamlinux"
+CREAMLINUX_FILES=(cream.sh lib32Creamlinux.so lib64Creamlinux.so cream_api.ini)
+
+mkdir -p "$APP_DIR" "$CACHE_DIR"
+
+C_RESET=$'\e[0m'; C_BOLD=$'\e[1m'; C_DIM=$'\e[2m'
+C_RED=$'\e[31m'; C_GREEN=$'\e[32m'; C_YELLOW=$'\e[33m'
+C_BLUE=$'\e[34m'; C_MAGENTA=$'\e[35m'; C_CYAN=$'\e[36m'; C_WHITE=$'\e[97m'
+
+LANGUAGE="en"
+
+t() {
+ local key="$1"
+ case "$LANGUAGE" in
+ ru) _t_ru "$key" ;;
+ zh) _t_zh "$key" ;;
+ *) _t_en "$key" ;;
+ esac
+}
+
+_t_en() {
+ case "$1" in
+ title) echo "Stellaris DLC Unlocker — Linux Edition" ;;
+ menu_header) echo "MAIN MENU" ;;
+ m_status) echo "Status & paths" ;;
+ m_install) echo "Install / Update DLC unlocker" ;;
+ m_steam_launch) echo "Patch Steam launch options" ;;
+ m_lang) echo "Change language" ;;
+ m_log) echo "Show log" ;;
+ m_exit) echo "Exit" ;;
+ choose) echo "Choose an option: " ;;
+ detect_steam) echo "Detecting Steam installation..." ;;
+ steam_found) echo "Steam found:" ;;
+ steam_not_found) echo "Steam installation not found." ;;
+ detect_game) echo "Detecting Stellaris installation..." ;;
+ game_found) echo "Stellaris found:" ;;
+ game_not_found) echo "Stellaris installation not found." ;;
+ native_build) echo "Native Linux build detected — CreamLinux is compatible." ;;
+ not_native) echo "Native Linux build NOT detected (no 'stellaris' ELF binary). CreamLinux requires the native build, not Proton/Wine." ;;
+ downloading) echo "Downloading" ;;
+ fetching_dlc_list) echo "Fetching DLC list..." ;;
+ dlc_list_ok) echo "DLC list loaded." ;;
+ dlc_list_fail) echo "Failed to fetch DLC list from GitHub and jsDelivr." ;;
+ fetching_creamlinux) echo "Downloading CreamLinux..." ;;
+ creamlinux_ok) echo "CreamLinux files ready." ;;
+ copying_files) echo "Copying CreamLinux files into game folder..." ;;
+ checking_hashes) echo "Checking file integrity (hashes.json)..." ;;
+ to_download) echo "DLC archives to download:" ;;
+ unpacking) echo "Unpacking archives..." ;;
+ updating_ini) echo "Updating cream_api.ini via SteamCMD API..." ;;
+ ini_updated) echo "cream_api.ini updated, added DLC:" ;;
+ ini_skip) echo "SteamCMD API unavailable, skipped." ;;
+ install_done) echo "Installation complete!" ;;
+ patch_launch_header) echo "Patching Steam launch options" ;;
+ patch_userdata_not_found) echo "Could not find Steam userdata folder." ;;
+ patch_localconfig_not_found) echo "localconfig.vdf not found for any user." ;;
+ patch_backup) echo "Backup created:" ;;
+ patch_done) echo "Launch options set to: sh ./cream.sh %command%" ;;
+ patch_already) echo "Launch options already set correctly." ;;
+ patch_steam_running_warn) echo "WARNING: Steam appears to be running. Close Steam fully before/after patching, otherwise it may overwrite the change." ;;
+ press_enter) echo "Press Enter to continue..." ;;
+ enter_game_path) echo "Enter Stellaris game path manually (or press Enter to skip): " ;;
+ invalid_choice) echo "Invalid choice." ;;
+ lang_set) echo "Language set to English." ;;
+ log_empty) echo "Log is empty." ;;
+ confirm_install) echo "Proceed with installation? [y/N]: " ;;
+ cancelled) echo "Cancelled." ;;
+ no_dlc_to_download) echo "All DLC are up to date." ;;
+ flatpak_steam) echo "(Flatpak)" ;;
+ *) echo "$1" ;;
+ esac
+}
+
+_t_ru() {
+ case "$1" in
+ title) echo "Stellaris DLC Unlocker — версия для Linux" ;;
+ menu_header) echo "ГЛАВНОЕ МЕНЮ" ;;
+ m_status) echo "Статус и пути" ;;
+ m_install) echo "Установить / обновить разблокировщик DLC" ;;
+ m_steam_launch) echo "Прописать параметры запуска в Steam" ;;
+ m_lang) echo "Сменить язык" ;;
+ m_log) echo "Показать лог" ;;
+ m_exit) echo "Выход" ;;
+ choose) echo "Выберите пункт: " ;;
+ detect_steam) echo "Поиск установки Steam..." ;;
+ steam_found) echo "Steam найден:" ;;
+ steam_not_found) echo "Установка Steam не найдена." ;;
+ detect_game) echo "Поиск установки Stellaris..." ;;
+ game_found) echo "Stellaris найден:" ;;
+ game_not_found) echo "Установка Stellaris не найдена." ;;
+ native_build) echo "Обнаружена нативная Linux-версия — CreamLinux подходит." ;;
+ not_native) echo "Нативная Linux-версия не обнаружена (нет ELF-файла 'stellaris'). CreamLinux работает только с нативной версией, не с Proton/Wine." ;;
+ downloading) echo "Скачивание" ;;
+ fetching_dlc_list) echo "Получение списка DLC..." ;;
+ dlc_list_ok) echo "Список DLC загружен." ;;
+ dlc_list_fail) echo "Не удалось получить список DLC ни с GitHub, ни с jsDelivr." ;;
+ fetching_creamlinux) echo "Скачивание CreamLinux..." ;;
+ creamlinux_ok) echo "Файлы CreamLinux готовы." ;;
+ copying_files) echo "Копирование файлов CreamLinux в папку игры..." ;;
+ checking_hashes) echo "Проверка целостности файлов (hashes.json)..." ;;
+ to_download) echo "Архивов DLC к скачиванию:" ;;
+ unpacking) echo "Распаковка архивов..." ;;
+ updating_ini) echo "Обновление cream_api.ini через SteamCMD API..." ;;
+ ini_updated) echo "cream_api.ini обновлён, добавлено DLC:" ;;
+ ini_skip) echo "SteamCMD API недоступен, пропущено." ;;
+ install_done) echo "Установка завершена!" ;;
+ patch_launch_header) echo "Прописывание параметров запуска Steam" ;;
+ patch_userdata_not_found) echo "Не удалось найти папку userdata Steam." ;;
+ patch_localconfig_not_found) echo "Файл localconfig.vdf не найден ни для одного пользователя." ;;
+ patch_backup) echo "Создана резервная копия:" ;;
+ patch_done) echo "Параметры запуска установлены: sh ./cream.sh %command%" ;;
+ patch_already) echo "Параметры запуска уже выставлены верно." ;;
+ patch_steam_running_warn) echo "ВНИМАНИЕ: похоже, Steam запущен. Полностью закройте Steam до/после патчинга, иначе он может перезаписать изменение." ;;
+ press_enter) echo "Нажмите Enter для продолжения..." ;;
+ enter_game_path) echo "Введите путь к игре Stellaris вручную (или Enter, чтобы пропустить): " ;;
+ invalid_choice) echo "Неверный выбор." ;;
+ lang_set) echo "Язык переключён на русский." ;;
+ log_empty) echo "Лог пуст." ;;
+ confirm_install) echo "Продолжить установку? [y/N]: " ;;
+ cancelled) echo "Отменено." ;;
+ no_dlc_to_download) echo "Все DLC актуальны." ;;
+ flatpak_steam) echo "(Flatpak)" ;;
+ *) echo "$1" ;;
+ esac
+}
+
+_t_zh() {
+ case "$1" in
+ title) echo "Stellaris DLC 解锁器 — Linux 版" ;;
+ menu_header) echo "主菜单" ;;
+ m_status) echo "状态与路径" ;;
+ m_install) echo "安装 / 更新 DLC 解锁器" ;;
+ m_steam_launch) echo "设置 Steam 启动选项" ;;
+ m_lang) echo "切换语言" ;;
+ m_log) echo "查看日志" ;;
+ m_exit) echo "退出" ;;
+ choose) echo "请选择: " ;;
+ detect_steam) echo "正在检测 Steam 安装..." ;;
+ steam_found) echo "已找到 Steam:" ;;
+ steam_not_found) echo "未找到 Steam 安装。" ;;
+ detect_game) echo "正在检测 Stellaris 安装..." ;;
+ game_found) echo "已找到 Stellaris:" ;;
+ game_not_found) echo "未找到 Stellaris 安装。" ;;
+ native_build) echo "检测到原生 Linux 版本 — CreamLinux 兼容。" ;;
+ not_native) echo "未检测到原生 Linux 版本(缺少 'stellaris' ELF 文件)。CreamLinux 仅支持原生版本,不支持 Proton/Wine。" ;;
+ downloading) echo "下载中" ;;
+ fetching_dlc_list) echo "正在获取 DLC 列表..." ;;
+ dlc_list_ok) echo "DLC 列表已加载。" ;;
+ dlc_list_fail) echo "从 GitHub 和 jsDelivr 获取 DLC 列表均失败。" ;;
+ fetching_creamlinux) echo "正在下载 CreamLinux..." ;;
+ creamlinux_ok) echo "CreamLinux 文件已就绪。" ;;
+ copying_files) echo "正在将 CreamLinux 文件复制到游戏目录..." ;;
+ checking_hashes) echo "正在校验文件完整性 (hashes.json)..." ;;
+ to_download) echo "待下载的 DLC 压缩包:" ;;
+ unpacking) echo "正在解压..." ;;
+ updating_ini) echo "正在通过 SteamCMD API 更新 cream_api.ini..." ;;
+ ini_updated) echo "cream_api.ini 已更新,新增 DLC:" ;;
+ ini_skip) echo "SteamCMD API 不可用,已跳过。" ;;
+ install_done) echo "安装完成!" ;;
+ patch_launch_header) echo "设置 Steam 启动选项" ;;
+ patch_userdata_not_found) echo "未找到 Steam userdata 目录。" ;;
+ patch_localconfig_not_found) echo "未找到任何用户的 localconfig.vdf。" ;;
+ patch_backup) echo "已创建备份:" ;;
+ patch_done) echo "启动选项已设置为: sh ./cream.sh %command%" ;;
+ patch_already) echo "启动选项已正确设置。" ;;
+ patch_steam_running_warn) echo "警告: Steam 似乎正在运行。请在修改前后完全关闭 Steam,否则更改可能被覆盖。" ;;
+ press_enter) echo "按 Enter 继续..." ;;
+ enter_game_path) echo "请手动输入 Stellaris 游戏路径(直接按 Enter 跳过): " ;;
+ invalid_choice) echo "无效选择。" ;;
+ lang_set) echo "语言已切换为中文。" ;;
+ log_empty) echo "日志为空。" ;;
+ confirm_install) echo "是否继续安装?[y/N]: " ;;
+ cancelled) echo "已取消。" ;;
+ no_dlc_to_download) echo "所有 DLC 均为最新。" ;;
+ flatpak_steam) echo "(Flatpak)" ;;
+ *) echo "$1" ;;
+ esac
+}
+
+log() {
+ local level="$1"; shift
+ local msg="$*"
+ local color="$C_WHITE"
+ case "$level" in
+ OK) color="$C_GREEN" ;;
+ WARN) color="$C_YELLOW" ;;
+ ERROR) color="$C_RED" ;;
+ INFO) color="$C_CYAN" ;;
+ esac
+ echo -e "${color}[$level]${C_RESET} $msg"
+ echo "$(date '+%Y-%m-%d %H:%M:%S') [$level] $msg" >> "$LOG_FILE"
+}
+
+hr() { printf "${C_DIM}%s${C_RESET}\n" "------------------------------------------------------------"; }
+
+header() {
+ clear
+ echo -e "${C_BOLD}${C_MAGENTA}=============================================================${C_RESET}"
+ echo -e "${C_BOLD}${C_WHITE} $(t title)${C_RESET}"
+ echo -e "${C_BOLD}${C_MAGENTA}=============================================================${C_RESET}"
+ echo
+}
+
+pause() {
+ echo
+ ask "$(t press_enter)" _dummy
+}
+
+progress_bar() {
+ local current="$1" total="$2" label="$3"
+ local width=30
+ local pct=0
+ [ "$total" -gt 0 ] && pct=$(( current * 100 / total ))
+ local filled=$(( pct * width / 100 ))
+ local empty=$(( width - filled ))
+ printf "\r${C_CYAN}[%-${width}s]${C_RESET} %3d%% %s" \
+ "$(printf '#%.0s' $(seq 1 $filled) 2>/dev/null)$(printf '.%.0s' $(seq 1 $empty) 2>/dev/null)" \
+ "$pct" "$label"
+}
+
+download_file() {
+ local url="$1" dest="$2" label="${3:-$1}"
+ mkdir -p "$(dirname "$dest")"
+ echo -e "${C_CYAN}$(t downloading):${C_RESET} $label"
+ if ! curl -L --fail --retry 3 --connect-timeout 15 -o "$dest" \
+ --progress-bar "$url"; then
+ log ERROR "Failed to download: $url"
+ return 1
+ fi
+ return 0
+}
+
+http_get() {
+ curl -sL --fail --retry 2 --connect-timeout 10 -A "StellarisDLCUnlocker-sh/1.0" "$1"
+}
+
+download_with_fallback() {
+ local rel="$1" dest="$2" label="${3:-$1}"
+ mkdir -p "$(dirname "$dest")"
+ if curl -fsSL --retry 2 --connect-timeout 10 -o "$dest" "$REPO_GITHUB_RAW/$rel" 2>>"$LOG_FILE"; then
+ log OK " (GitHub) $label"
+ return 0
+ fi
+ log WARN " GitHub failed for $label, trying jsDelivr..."
+ if curl -fsSL --retry 2 --connect-timeout 10 -o "$dest" "$REPO_JSDELIVR/$rel" 2>>"$LOG_FILE"; then
+ log OK " (jsDelivr) $label"
+ return 0
+ fi
+ log ERROR " Failed to fetch $label from GitHub and jsDelivr."
+ return 1
+}
+
+ask() {
+ local prompt="$1" __var="$2" __val=""
+ if [ -r /dev/tty ]; then
+ read -rp "$prompt" __val /dev/null)
+ fi
+
+ for lib in "${libs[@]}"; do
+ local candidate="$lib/steamapps/common/Stellaris"
+ if [ -d "$candidate" ]; then
+ GAME_DIR="$candidate"
+ return 0
+ fi
+ done
+ return 1
+}
+
+is_native_build() {
+ [ -f "$GAME_DIR/stellaris" ] && file "$GAME_DIR/stellaris" 2>/dev/null | grep -qi "ELF"
+}
+
+DLC_DATA_JSON=""
+
+fetch_dlc_data() {
+ log INFO "$(t fetching_dlc_list)"
+ DLC_DATA_JSON=$(http_get "$GITHUB_DLC_URL" 2>/dev/null) || true
+ if [ -z "$DLC_DATA_JSON" ]; then
+ log WARN "GitHub failed, trying jsDelivr..."
+ DLC_DATA_JSON=$(http_get "$JSDELIVR_DLC_URL" 2>/dev/null) || true
+ fi
+ if [ -z "$DLC_DATA_JSON" ]; then
+ log ERROR "$(t dlc_list_fail)"
+ return 1
+ fi
+ log OK "$(t dlc_list_ok)"
+ return 0
+}
+
+dlc_folders() {
+ if command -v jq >/dev/null 2>&1; then
+ echo "$DLC_DATA_JSON" | jq -r '.[].dlc_folder // empty'
+ else
+ echo "$DLC_DATA_JSON" | grep -oP '"dlc_folder"\s*:\s*"\K[^"]+'
+ fi
+}
+
+fetch_creamlinux() {
+ local dest_dir="$CACHE_DIR/$CREAMLINUX_SUBDIR"
+ log INFO "$(t fetching_creamlinux)"
+ local ok=1
+ for f in "${CREAMLINUX_FILES[@]}"; do
+ download_with_fallback "$CREAMLINUX_SUBDIR/$f" "$dest_dir/$f" "$f" || ok=0
+ done
+ if [ "$ok" -eq 1 ]; then
+ log OK "$(t creamlinux_ok)"
+ return 0
+ fi
+ return 1
+}
+
+copy_creamlinux_to_game() {
+ local src_dir="$CACHE_DIR/$CREAMLINUX_SUBDIR"
+ log INFO "$(t copying_files)"
+ for f in cream.sh lib32Creamlinux.so lib64Creamlinux.so; do
+ if [ -f "$src_dir/$f" ]; then
+ cp -f "$src_dir/$f" "$GAME_DIR/$f"
+ else
+ log WARN "Missing in CreamLinux package: $f"
+ fi
+ done
+ chmod +x "$GAME_DIR/cream.sh" 2>/dev/null
+ log OK "CreamLinux files copied to: $GAME_DIR"
+}
+
+update_cream_ini() {
+ local ini_path="$GAME_DIR/cream_api.ini"
+ local cached_ini="$CACHE_DIR/$CREAMLINUX_SUBDIR/cream_api.ini"
+
+ if [ -f "$cached_ini" ]; then
+ cp -f "$cached_ini" "$ini_path"
+ sed -i 's/\r$//' "$ini_path"
+ else
+ : > "$ini_path"
+ fi
+
+ log INFO "$(t updating_ini)"
+ local info
+ info=$(http_get "$STEAMCMD_API/$APPID" 2>/dev/null) || true
+ if [ -z "$info" ]; then
+ log WARN "$(t ini_skip)"
+ return 0
+ fi
+
+ local csv
+ if command -v jq >/dev/null 2>&1; then
+ csv=$(echo "$info" | jq -r ".data[\"$APPID\"].extended.listofdlc // empty")
+ else
+ csv=$(echo "$info" | grep -oP '"listofdlc"\s*:\s*"\K[^"]+')
+ fi
+ if [ -z "$csv" ]; then
+ log WARN "$(t ini_skip)"
+ return 0
+ fi
+
+ if [ -s "$ini_path" ] && [ -n "$(tail -c1 "$ini_path")" ]; then
+ printf '\n' >> "$ini_path"
+ fi
+
+ local added=0
+ IFS=',' read -ra ids <<< "$csv"
+ for id in "${ids[@]}"; do
+ id="$(echo "$id" | xargs)"
+ [ -z "$id" ] && continue
+ grep -q "^$id " "$ini_path" 2>/dev/null && continue
+ local name="$id"
+ local dlc_info
+ dlc_info=$(http_get "$STEAMCMD_API/$id" 2>/dev/null) || true
+ if [ -n "$dlc_info" ]; then
+ if command -v jq >/dev/null 2>&1; then
+ local n
+ n=$(echo "$dlc_info" | jq -r ".data[\"$id\"].common.name // empty")
+ [ -n "$n" ] && name="$n"
+ else
+ local n
+ n=$(echo "$dlc_info" | grep -oP '"name"\s*:\s*"\K[^"]+' | head -1)
+ [ -n "$n" ] && name="$n"
+ fi
+ fi
+ echo "$id = $name" >> "$ini_path"
+ added=$((added+1))
+ done
+
+ if [ "$added" -gt 0 ]; then
+ log OK "$(t ini_updated) +$added"
+ fi
+}
+
+download_dlc_content() {
+ local dlc_dir="$GAME_DIR/dlc"
+ mkdir -p "$dlc_dir"
+
+ local folders=()
+ while IFS= read -r f; do
+ [ -n "$f" ] && folders+=("$f")
+ done < <(dlc_folders)
+
+ local total=${#folders[@]}
+ local queue=()
+ for f in "${folders[@]}"; do
+ local dir="$dlc_dir/$f"
+ local zip="$dlc_dir/$f.zip"
+ if [ -d "$dir" ]; then continue; fi
+ if [ -f "$zip" ]; then
+ unzip -tq "$zip" >/dev/null 2>&1 && continue
+ rm -f "$zip"
+ fi
+ queue+=("$f")
+ done
+
+ if [ ${#queue[@]} -eq 0 ]; then
+ log OK "$(t no_dlc_to_download)"
+ return 0
+ fi
+
+ log INFO "$(t to_download) ${#queue[@]} / $total"
+ local i=0
+ for f in "${queue[@]}"; do
+ i=$((i+1))
+ local url="https://$SERVER_URL/unlocker/$f.zip"
+ local dest="$dlc_dir/$f.zip"
+ echo
+ log INFO "[$i/${#queue[@]}] $f"
+ download_file "$url" "$dest" "$f" || continue
+ done
+
+ log INFO "$(t unpacking)"
+ for z in "$dlc_dir"/*.zip; do
+ [ -f "$z" ] || continue
+ local base
+ base="$(basename "$z" .zip)"
+ if unzip -oq "$z" -d "$dlc_dir"; then
+ rm -f "$z"
+ log OK "Unpacked: $base"
+ else
+ log ERROR "Unzip error: $base"
+ fi
+ done
+}
+
+patch_launch_options() {
+ header
+ echo -e "${C_BOLD}$(t patch_launch_header)${C_RESET}"
+ hr
+
+ if [ -z "$STEAM_DIR" ]; then
+ find_steam_dir || { log ERROR "$(t steam_not_found)"; pause; return 1; }
+ fi
+
+ if pgrep -x steam >/dev/null 2>&1 || pgrep -f "com.valvesoftware.Steam" >/dev/null 2>&1; then
+ log WARN "$(t patch_steam_running_warn)"
+ fi
+
+ local userdata_dir="$STEAM_DIR/userdata"
+ if [ ! -d "$userdata_dir" ]; then
+ log ERROR "$(t patch_userdata_not_found)"
+ pause; return 1
+ fi
+
+ local patched_any=0
+ for user_dir in "$userdata_dir"/*/; do
+ local vdf="${user_dir}config/localconfig.vdf"
+ [ -f "$vdf" ] || continue
+
+ local backup="${vdf}.bak.$(date +%Y%m%d%H%M%S)"
+ cp -f "$vdf" "$backup"
+ log INFO "$(t patch_backup) $backup"
+
+ local desired='sh ./cream.sh %command%'
+ local tmp
+ tmp=$(mktemp)
+
+ awk -v appid="\"$APPID\"" -v opt="$desired" '
+ BEGIN { in_block=0; depth=0; done=0 }
+ {
+ line=$0
+ trimmed=line
+ gsub(/^[ \t]+|[ \t]+$/, "", trimmed)
+
+ if (!in_block && trimmed == appid) {
+ in_block=1
+ print line
+ next
+ }
+
+ if (in_block && depth==0 && trimmed == "{") {
+ depth=1
+ print line
+ next
+ }
+
+ if (in_block && depth==1) {
+ if (trimmed ~ /^"LaunchOptions"/) {
+ sub(/"LaunchOptions".*/, "\"LaunchOptions\"\t\t\"" opt "\"", line)
+ print line
+ done=1
+ next
+ }
+ if (trimmed == "{") { depth++; print line; next }
+ if (trimmed == "}") {
+ if (!done) {
+ print "\t\t\t\"LaunchOptions\"\t\t\"" opt "\""
+ done=1
+ }
+ in_block=0
+ depth=0
+ print line
+ next
+ }
+ }
+
+ if (in_block && depth>1) {
+ if (trimmed == "{") depth++
+ if (trimmed == "}") depth--
+ }
+
+ print line
+ }
+ ' "$vdf" > "$tmp"
+
+ if grep -q "$APPID" "$tmp"; then
+ mv "$tmp" "$vdf"
+ patched_any=1
+ log OK "$(t patch_done) ($user_dir)"
+ else
+ rm -f "$tmp"
+ log WARN "AppID $APPID not found in $vdf (game never launched from this Steam account?)"
+ fi
+ done
+
+ if [ "$patched_any" -eq 0 ]; then
+ log ERROR "$(t patch_localconfig_not_found)"
+ fi
+
+ pause
+}
+
+do_install() {
+ header
+ echo -e "${C_BOLD}$(t m_install)${C_RESET}"
+ hr
+
+ find_steam_dir
+ if [ -z "$STEAM_DIR" ]; then
+ log ERROR "$(t steam_not_found)"
+ pause; return 1
+ fi
+ log OK "$(t steam_found) $STEAM_DIR $([ "$IS_FLATPAK_STEAM" = 1 ] && t flatpak_steam)"
+
+ find_game_dir
+ if [ -z "$GAME_DIR" ]; then
+ log WARN "$(t game_not_found)"
+ ask "$(t enter_game_path)" manual_path
+ if [ -n "$manual_path" ] && [ -d "$manual_path" ]; then
+ GAME_DIR="$manual_path"
+ else
+ pause; return 1
+ fi
+ fi
+ log OK "$(t game_found) $GAME_DIR"
+
+ if is_native_build; then
+ log OK "$(t native_build)"
+ else
+ log ERROR "$(t not_native)"
+ pause; return 1
+ fi
+
+ echo
+ ask "$(t confirm_install)" confirm
+ if [[ ! "$confirm" =~ ^[yYдД]$ ]]; then
+ log INFO "$(t cancelled)"
+ pause; return 0
+ fi
+
+ fetch_dlc_data || { pause; return 1; }
+ fetch_creamlinux || { pause; return 1; }
+ copy_creamlinux_to_game
+ mkdir -p "$GAME_DIR/dlc"
+ update_cream_ini
+ download_dlc_content
+
+ echo
+ log OK "$(t install_done)"
+ echo -e "${C_DIM}sh ./cream.sh %command%${C_RESET}"
+ pause
+}
+
+show_status() {
+ header
+ echo -e "${C_BOLD}$(t m_status)${C_RESET}"
+ hr
+
+ find_steam_dir
+ if [ -n "$STEAM_DIR" ]; then
+ echo -e "${C_GREEN}$(t steam_found)${C_RESET} $STEAM_DIR $([ "$IS_FLATPAK_STEAM" = 1 ] && t flatpak_steam)"
+ else
+ echo -e "${C_RED}$(t steam_not_found)${C_RESET}"
+ fi
+
+ find_game_dir
+ if [ -n "$GAME_DIR" ]; then
+ echo -e "${C_GREEN}$(t game_found)${C_RESET} $GAME_DIR"
+ if is_native_build; then
+ echo -e "${C_GREEN}$(t native_build)${C_RESET}"
+ else
+ echo -e "${C_RED}$(t not_native)${C_RESET}"
+ fi
+ if [ -f "$GAME_DIR/cream.sh" ]; then
+ echo -e "${C_GREEN}cream.sh:${C_RESET} installed"
+ else
+ echo -e "${C_YELLOW}cream.sh:${C_RESET} not installed"
+ fi
+ if [ -f "$GAME_DIR/cream_api.ini" ]; then
+ local cnt
+ cnt=$(grep -c "=" "$GAME_DIR/cream_api.ini" 2>/dev/null || echo 0)
+ echo -e "${C_GREEN}cream_api.ini:${C_RESET} $cnt DLC entries"
+ fi
+ else
+ echo -e "${C_RED}$(t game_not_found)${C_RESET}"
+ fi
+ pause
+}
+
+show_log() {
+ header
+ echo -e "${C_BOLD}$(t m_log)${C_RESET}"
+ hr
+ if [ -s "$LOG_FILE" ]; then
+ tail -n 50 "$LOG_FILE"
+ else
+ echo "$(t log_empty)"
+ fi
+ pause
+}
+
+change_language() {
+ header
+ echo "1) English"
+ echo "2) Русский"
+ echo "3) 中文"
+ ask "$(t choose)" l
+ case "$l" in
+ 1) LANGUAGE="en" ;;
+ 2) LANGUAGE="ru" ;;
+ 3) LANGUAGE="zh" ;;
+ esac
+ echo "$LANGUAGE" > "$CONFIG_FILE"
+ log OK "$(t lang_set)"
+ pause
+}
+
+check_deps() {
+ local missing=()
+ for c in curl unzip grep awk; do
+ command -v "$c" >/dev/null 2>&1 || missing+=("$c")
+ done
+ if [ ${#missing[@]} -gt 0 ]; then
+ echo -e "${C_RED}Missing required tools: ${missing[*]}${C_RESET}"
+ echo "Install them with your package manager, e.g.: sudo apt install ${missing[*]}"
+ exit 1
+ fi
+ command -v jq >/dev/null 2>&1 || log WARN "jq not found — falling back to grep/sed JSON parsing (less robust). Install jq for best reliability."
+}
+
+main_menu() {
+ while true; do
+ header
+ echo -e "${C_BOLD}$(t menu_header)${C_RESET}"
+ hr
+ echo -e " ${C_CYAN}1)${C_RESET} $(t m_status)"
+ echo -e " ${C_CYAN}2)${C_RESET} $(t m_install)"
+ echo -e " ${C_CYAN}3)${C_RESET} $(t m_steam_launch)"
+ echo -e " ${C_CYAN}4)${C_RESET} $(t m_lang)"
+ echo -e " ${C_CYAN}5)${C_RESET} $(t m_log)"
+ echo -e " ${C_CYAN}0)${C_RESET} $(t m_exit)"
+ hr
+ ask "$(t choose)" choice
+ case "$choice" in
+ 1) show_status ;;
+ 2) do_install ;;
+ 3) patch_launch_options ;;
+ 4) change_language ;;
+ 5) show_log ;;
+ 0) exit 0 ;;
+ *) log WARN "$(t invalid_choice)"; sleep 1 ;;
+ esac
+ done
+}
+
+[ -f "$CONFIG_FILE" ] && LANGUAGE="$(cat "$CONFIG_FILE")"
+check_deps
+main_menu
diff --git a/StellarisDLCUnlocker2.ps1 b/StellarisDLCUnlocker2.ps1
deleted file mode 100644
index 8804e06..0000000
--- a/StellarisDLCUnlocker2.ps1
+++ /dev/null
@@ -1,1067 +0,0 @@
-#Requires -Version 5.1
-Set-StrictMode -Version 5.1
-$ErrorActionPreference = 'Stop'
-[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
-Add-Type -AssemblyName PresentationFramework, PresentationCore, WindowsBase, System.Windows.Forms
-
-Add-Type @'
-using System;
-using System.Runtime.InteropServices;
-namespace Picker {
- [ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"),
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- public interface IShellItem {
- void BindToHandler(IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv);
- void GetParent(out IShellItem ppsi);
- void GetDisplayName(uint sigdn, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);
- void GetAttributes(uint mask, out uint attribs);
- void Compare(IShellItem psi, uint hint, out int order);
- }
- [ComImport, Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"),
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- public interface IFileDialog {
- [PreserveSig] int Show(IntPtr hwnd);
- void SetFileTypes(uint c, IntPtr types);
- void SetFileTypeIndex(uint i);
- void GetFileTypeIndex(out uint i);
- void Advise(IntPtr sink, out uint cookie);
- void Unadvise(uint cookie);
- void SetOptions(uint fos);
- void GetOptions(out uint fos);
- void SetDefaultFolder(IShellItem psi);
- void SetFolder(IShellItem psi);
- void GetFolder(out IShellItem ppsi);
- void GetCurrentSelection(out IShellItem ppsi);
- void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string name);
- void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string name);
- void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string title);
- void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string text);
- void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string label);
- void GetResult(out IShellItem ppsi);
- void AddPlace(IShellItem psi, int fdap);
- void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string ext);
- void Close(int hr);
- void SetClientGuid([In] ref Guid guid);
- void ClearClientData();
- void SetFilter(IntPtr filter);
- }
- public static class FolderDialog {
- static readonly Guid CLSID = new Guid("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7");
- [DllImport("shell32.dll", CharSet=CharSet.Unicode, PreserveSig=false)]
- static extern void SHCreateItemFromParsingName(string path, IntPtr pbc,
- [In] ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
- public static string Pick(string title, string initial = null) {
- var dlg = (IFileDialog)Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID));
- try {
- uint opts; dlg.GetOptions(out opts);
- dlg.SetOptions(opts | 0x20); // FOS_PICKFOLDERS
- dlg.SetTitle(title);
- if (!string.IsNullOrEmpty(initial)) {
- try {
- var iid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE");
- IShellItem si;
- SHCreateItemFromParsingName(initial, IntPtr.Zero, ref iid, out si);
- dlg.SetFolder(si);
- } catch {}
- }
- if (dlg.Show(IntPtr.Zero) != 0) return null;
- IShellItem res; dlg.GetResult(out res);
- string path; res.GetDisplayName(0x80028000, out path);
- return path;
- } finally { Marshal.ReleaseComObject(dlg); }
- }
- }
-}
-'@
-
-Add-Type -AssemblyName System.IO.Compression.FileSystem
-
-$STELLARIS_APP_ID = '281990'
-$APP_DIR = Join-Path $env:LOCALAPPDATA 'StellarisDLCUnlocker'
-$CACHE_DIR = Join-Path $APP_DIR 'cache'
-$LOG_FILE = Join-Path $APP_DIR 'unlocker.log'
-$ORIGIN_API = 'https://api.github.com/repos/seuyh/stellaris-dlc-unlocker/contents'
-
-$GITHUB_DLC_URL = 'https://raw.githubusercontent.com/seuyh/stellaris-dlc-unlocker/main/dlc_data.json'
-$GITHUB_HASHES_URL = 'https://raw.githubusercontent.com/seuyh/stellaris-dlc-unlocker/main/hashes.json'
-
-$JSDELIVR_DLC_URL = 'https://cdn.jsdelivr.net/gh/seuyh/stellaris-dlc-unlocker@main/dlc_data.json'
-$JSDELIVR_HASHES_URL = 'https://cdn.jsdelivr.net/gh/seuyh/stellaris-dlc-unlocker@main/hashes.json'
-
-$SERVER_URL = 'pub-0f87be5fdd68492c8328b66998eb46ad.r2.dev'
-$ALT_LAUNCHERS = @('launcher-installer-windows_2024.14.msi', 'launcher-installer-windows_2024.13.msi', 'launcher-installer-windows_2024.8.msi')
-
-$STEAMCMD_API = 'https://api.steamcmd.net/v1/info'
-
-New-Item -ItemType Directory -Path $APP_DIR, $CACHE_DIR -Force | Out-Null
-
-$script:dlcData = $null
-$script:serverUrl = $null
-$script:altLauncher = $null
-$script:outdatedFolders = @()
-$script:L = $null
-$script:curLang = 'en'
-$script:Q = [System.Collections.Concurrent.ConcurrentQueue[object]]::new()
-
-$BUILTIN = @{
- en = @{
- title='STELLARIS DLC UNLOCKER'; path_label='STELLARIS PATH'; lbl_launcher_path='LAUNCHER PATH'; browse='Browse'
- status_label='STATUS'; options_label='OPTIONS'
- chk_full='Full reinstall (deletes saves and settings)'
- chk_skip='Skip Paradox Launcher reinstall'
- chk_no_update='Disable launcher auto-update (recommended)'
- confirm_no_update='Launcher auto-update may break DLC unlock functionality. Disable anyway?'
- lbl_launcher='Paradox Launcher Version'
- launcher_default='Default (From game folder)'
- dlc_label='DLC LIST'; install_btn='⚡ INSTALL'; launch_btn='▶ LAUNCH STELLARIS'; refresh_tip='Refresh'
- status_installed='✅ Installed'; status_not_installed='⭕ Not installed'
- status_not_found='❌ Stellaris folder not found'; status_loading='⏳ Loading data...'
- err_no_exe='stellaris.exe not found in selected folder.'
- err_loading='Server data is still loading. Please wait.'
- err_title='Error'; warn_title='Warning'; wait_title='Please wait'; confirm_title='Confirm'
- confirm_full='This will delete ALL Stellaris saves and settings. Continue?'
- dlc_ok='OK'; dlc_old='Outdated'; dlc_missing='Missing'
- }
- ru = @{
- title='STELLARIS DLC UNLOCKER'; path_label='ПУТЬ К STELLARIS'; lbl_launcher_path='ПУТЬ К ЛАУНЧЕРУ'; browse='Обзор'
- status_label='СТАТУС'; options_label='ОПЦИИ'
- chk_full='Полная переустановка (удалит сохранения и настройки)'
- chk_skip='Пропустить переустановку Paradox Launcher'
- chk_no_update='Отключить авто-обновление лаунчера (рекомендуется)'
- confirm_no_update='Авто-обновление лаунчера может нарушить работу разблокировки DLC. Всё равно отключить?'
- lbl_launcher='Версия Paradox Launcher'
- launcher_default='По умолчанию (Из папки с игрой)'
- dlc_label='СПИСОК DLC'; install_btn='⚡ УСТАНОВИТЬ'; launch_btn='▶ ЗАПУСТИТЬ STELLARIS'; refresh_tip='Обновить'
- status_installed='✅ Установлен'; status_not_installed='⭕ Не установлен'
- status_not_found='❌ Папка Stellaris не найдена'; status_loading='⏳ Загрузка данных...'
- err_no_exe='stellaris.exe не найден в указанной папке.'
- err_loading='Данные сервера ещё загружаются. Подождите.'
- err_title='Ошибка'; warn_title='Предупреждение'; wait_title='Подождите'; confirm_title='Подтверждение'
- confirm_full='Это удалит ВСЕ сохранения и настройки Stellaris. Продолжить?'
- dlc_ok='OK'; dlc_old='Устарел'; dlc_missing='Отсутствует'
- }
- zh = @{
- title='STELLARIS DLC UNLOCKER'; path_label='STELLARIS 路径'; lbl_launcher_path='启动器路径'; browse='浏览'
- status_label='状态'; options_label='选项'
- chk_full='完整重装(将删除存档和设置)'; chk_skip='跳过 Paradox Launcher 重装'
- chk_no_update='禁用启动器自动更新(推荐)'
- confirm_no_update='启动器自动更新可能导致 DLC 解锁功能异常。仍要禁用吗?'
- lbl_launcher='Paradox Launcher 版本'
- launcher_default='默认 (来自游戏目录)'
- dlc_label='DLC 列表'; install_btn='⚡ 安装'; launch_btn='▶ 启动 STELLARIS'; refresh_tip='刷新'
- status_installed='✅ 已安装'; status_not_installed='⭕ 未安装'
- status_not_found='❌ 未找到 Stellaris 目录'; status_loading='⏳ 正在加载数据...'
- err_no_exe='在所选文件夹中未找到 stellaris.exe。'
- err_loading='服务器数据仍在加载中,请稍候。'
- err_title='错误'; warn_title='警告'; wait_title='请稍候'; confirm_title='确认'
- confirm_full='这将删除所有 Stellaris 存档和设置。是否继续?'
- dlc_ok='OK'; dlc_old='已过时'; dlc_missing='缺失'
- }
-}
-
-function Write-Log([string]$msg, [string]$level = 'INFO') {
- Add-Content -Path $LOG_FILE -Value "[$(Get-Date -Format 'HH:mm:ss')][$level] $msg" -Encoding UTF8 -ErrorAction SilentlyContinue
-}
-function T([string]$key) { if ($script:L -and $script:L.ContainsKey($key)) { return $script:L[$key] }; return $key }
-function Get-SystemLang {
- $ui = [System.Globalization.CultureInfo]::CurrentUICulture.Name.ToLower()
- if ($ui.StartsWith('ru')) { return 'ru' }
- if ($ui.StartsWith('zh')) { return 'zh' }
- return 'en'
-}
-function Set-LangBuiltin([string]$lang) {
- $script:curLang = $lang
- $script:L = if ($BUILTIN.ContainsKey($lang)) { $BUILTIN[$lang] } else { $BUILTIN['en'] }
-}
-function Find-SteamPath {
- foreach ($h in 'HKCU:\Software\Valve\Steam','HKLM:\SOFTWARE\Valve\Steam','HKLM:\SOFTWARE\WOW6432Node\Valve\Steam') {
- $prop = Get-ItemProperty $h -ErrorAction SilentlyContinue
- $v = if ($null -ne $prop) { $prop.SteamPath } else { $null }
- if ($v -and (Test-Path $v)) { return $v }
- }
- foreach ($d in "$env:ProgramFiles(x86)\Steam","$env:ProgramFiles\Steam") { if (Test-Path $d) { return $d } }
- return $null
-}
-function Find-StellarisPath([string]$steamPath) {
- if (-not $steamPath) { return $null }
- $roots = @($steamPath)
- $vdf = Join-Path $steamPath 'steamapps\libraryfolders.vdf'
- if (Test-Path $vdf) {
- [regex]::Matches((Get-Content $vdf -Raw -ErrorAction SilentlyContinue), '"path"\s+"([^"]+)"') | ForEach-Object {
- $p = $_.Groups[1].Value -replace '\\\\','\'
- if (Test-Path $p) { $roots += $p }
- }
- }
- foreach ($r in $roots) { $c = Join-Path $r 'steamapps\common\Stellaris'; if (Test-Path $c) { return $c } }
- return $null
-}
-function Get-InstallStatus([string]$gp) {
- if ([string]::IsNullOrWhiteSpace($gp)) { return 'not_found' }
- try {
- if (-not (Test-Path (Join-Path $gp 'stellaris.exe'))) { return 'not_found' }
- if (Test-Path (Join-Path $gp 'cream_api.ini')) { return 'installed' }
- return 'not_installed'
- } catch { return 'not_found' }
-}
-function Start-PSRunspace([scriptblock]$scr, [hashtable]$vars) {
- $rs = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
- $rs.ApartmentState = [System.Threading.ApartmentState]::STA
- $rs.ThreadOptions = [System.Management.Automation.Runspaces.PSThreadOptions]::UseNewThread
- $rs.Open()
- foreach ($kv in $vars.GetEnumerator()) { $rs.SessionStateProxy.SetVariable($kv.Key, $kv.Value) }
- $ps = [System.Management.Automation.PowerShell]::Create()
- $ps.Runspace = $rs; $ps.AddScript($scr) | Out-Null; $ps.BeginInvoke() | Out-Null
-}
-
-$BG_COMMON = {
- [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
- function _Log([string]$msg, [string]$lvl='INFO') {
- $_Q.Enqueue([pscustomobject]@{ t='log'; msg="[$(Get-Date -Format 'HH:mm:ss')] $msg"; lvl=$lvl })
- }
- function _Http([string]$url) {
- $wc = [System.Net.WebClient]::new(); $wc.Headers.Add('User-Agent','StellarisDLCUnlocker-PS/1.0')
- try { return $wc.DownloadString($url) } finally { $wc.Dispose() }
- }
- function _Json([string]$url) { return (_Http $url) | ConvertFrom-Json }
-
- function _DownloadFile([string]$url, [string]$dest, [string]$label) {
- $req = [System.Net.HttpWebRequest]::Create($url)
- $req.UserAgent = 'Mozilla/5.0'
- $req.Timeout = 30000
- $resp = $req.GetResponse()
- $total = $resp.ContentLength
- $stream = $resp.GetResponseStream()
- $fs = [System.IO.File]::OpenWrite($dest)
- $buf = New-Object byte[] 65536
- $downloaded = 0L
- $startT = [DateTime]::Now
- try {
- while ($true) {
- $read = $stream.Read($buf, 0, $buf.Length)
- if ($read -le 0) { break }
- $fs.Write($buf, 0, $read)
- $downloaded += $read
- $el = ([DateTime]::Now - $startT).TotalSeconds
- $spd = if ($el -gt 0) { [Math]::Round($downloaded/1MB/$el,1) } else { 0 }
- $pct = if ($total -gt 0) { [Math]::Min(100,[int]($downloaded*100/$total)) } else { 0 }
- $_Q.Enqueue([pscustomobject]@{ t='progress'; pfile=$pct; speed="${spd} MB/s"; cur=$label })
- }
- } finally { $fs.Close(); $stream.Close(); $resp.Close() }
- }
-
- function _GetLauncherBase {
- $h = "C:\Users\$env:USERNAME"
- $reg = try { (Get-ItemProperty 'HKCU:\Software\Paradox Interactive\Paradox Launcher v2' -ErrorAction Stop).LauncherInstallation } catch { $null }
- if ($reg -and [System.IO.Path]::GetPathRoot($reg+'') -ne $reg -and (Test-Path $reg)) { return $reg }
- return "$h\AppData\Local\Programs\Paradox Interactive\launcher"
- }
- function _GetLauncherDataFolders {
- $h = "C:\Users\$env:USERNAME"
- $lp2 = try { (Get-ItemProperty 'HKCU:\Software\Paradox Interactive\Paradox Launcher v2' -ErrorAction Stop).LauncherPathFolder } catch { $null }
- if (-not $lp2 -or [System.IO.Path]::GetPathRoot($lp2+'') -eq $lp2) { $lp2 = "$h\AppData\Local\Paradox Interactive" }
- return @($lp2, "$h\AppData\Roaming\Paradox Interactive", "$h\AppData\Roaming\paradox-launcher-v2")
- }
-}
-
-$INIT_SCRIPT = [scriptblock]::Create($BG_COMMON.ToString() + @'
-
- _Log "Fetching DLC list from GitHub..."
- $dlc = $null
- try { $dlc = _Json $_GDLC; _Log "DLC data loaded from GitHub." 'OK' }
- catch {
- _Log "GitHub DLC failed, trying jsDelivr..." 'WARN'
- try { $dlc = _Json $_GDLC_FALL; _Log "DLC data loaded from jsDelivr." 'OK' }
- catch { _Log "Both GitHub and jsDelivr failed for DLC data." 'ERROR' }
- }
- if ($dlc) { $_Q.Enqueue([pscustomobject]@{ t='dlc_data'; data=$dlc }) }
-
- if ($dlc -and -not [string]::IsNullOrWhiteSpace($_GAMEPATH) -and (Test-Path (Join-Path $_GAMEPATH 'stellaris.exe'))) {
- _Log "Checking file integrity via hashes.json..."
- try {
- $hashJson = $null
- try { $hashJson = _Json $_GHASH }
- catch { _Log "GitHub hashes failed, trying jsDelivr..." 'WARN'; $hashJson = _Json $_GHASH_FALL }
-
- $out = @()
- $md5 = [System.Security.Cryptography.MD5]::Create()
- foreach ($prop in $hashJson.PSObject.Properties) {
- $relPath = $prop.Name -replace '/','\'
- $expected = $prop.Value
- $fld = ($relPath -split '\\')[0]
- $loc = Join-Path $_GAMEPATH "dlc\$relPath"
-
- if (Test-Path $loc) {
- $s = [System.IO.File]::OpenRead($loc)
- $h = ([System.BitConverter]::ToString($md5.ComputeHash($s)) -replace '-','').ToLower()
- $s.Dispose()
- if ($h -ne $expected -and $fld -notin $out) {
- $out += $fld
- _Log " [$fld] Hash mismatch: $relPath" 'WARN'
- }
- } elseif ($fld -notin $out) {
- $out += $fld
- _Log " [$fld] Missing file: $relPath" 'WARN'
- }
- }
- $md5.Dispose()
- $_Q.Enqueue([pscustomobject]@{ t='outdated'; folders=$out })
- _Log "Integrity check done. Outdated/Missing DLCs: $($out.Count)." 'OK'
- } catch { _Log "Integrity check failed: $($_.Exception.Message)" 'WARN' }
- }
-
- _Log "Checking GitHub connection..."
- $ghOk = $false
- try { _Http 'https://api.github.com/repos/seuyh/stellaris-dlc-unlocker' | Out-Null; $ghOk=$true; _Log "GitHub: reachable." 'OK' }
- catch { _Log "GitHub unreachable: $($_.Exception.Message)" 'WARN' }
- $_Q.Enqueue([pscustomobject]@{ t='dot_gh'; ok=$ghOk })
-
- $srvOk = $false
- if ($_SERVERURL -and $_ALTLAUNCHERS.Count -gt 0) {
- _Log "Checking server connection..."
- try {
- $req = [System.Net.WebRequest]::Create("https://$_SERVERURL/unlocker/$($_ALTLAUNCHERS[0])")
- $req.Method = "HEAD"
- $req.Timeout = 3000
- $resp = $req.GetResponse()
- $resp.Close()
- $srvOk = $true
- _Log "Server: reachable." 'OK'
- } catch { _Log "Server unreachable: $($_.Exception.Message)" 'WARN' }
- }
- $_Q.Enqueue([pscustomobject]@{ t='dot_srv'; ok=$srvOk })
- _Log "Initialization complete." 'OK'
- $_Q.Enqueue([pscustomobject]@{ t='init_done' })
-'@)
-
-$INSTALL_SCRIPT = [scriptblock]::Create($BG_COMMON.ToString() + @'
- function _FileLog([string]$msg, [string]$lvl='INFO') {
- try { Add-Content -Path $_LOG_FILE -Value "[$(Get-Date -Format 'HH:mm:ss')][$lvl] $msg" -Encoding UTF8 -ErrorAction SilentlyContinue } catch {}
- }
- try {
- _Log "▶ Installation started."
- _Log " Game folder: $_GAMEPATH"
- _Log " Server: $_SERVERURL"
- _FileLog "▶ Installation started. Game: $_GAMEPATH Server: $_SERVERURL"
-
- foreach ($p in @('stellaris','Paradox Launcher')) {
- try { Get-Process -Name $p -ErrorAction Stop | Stop-Process -Force; _Log " Killed process: $p" 'WARN' } catch {}
- }
-
- _Log " Removing stellaris.exe compatibility flags..."
- try {
- $regPath = 'HKCU:\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers'
- $exePath = Join-Path $_GAMEPATH 'stellaris.exe'
- if (Test-Path $regPath) {
- $prop = Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue
- if ($prop -and $prop.PSObject.Properties.Name -contains $exePath) {
- Remove-ItemProperty -Path $regPath -Name $exePath -Force -ErrorAction SilentlyContinue
- _Log " Compat flags removed." 'OK'
- } else { _Log " No compat flags found on stellaris.exe." }
- }
- } catch { _Log " Could not remove compat flags: $($_.Exception.Message)" 'WARN' }
-
- if ($_FULL) {
- _Log " Full reinstall: removing Paradox Interactive Stellaris documents..." 'WARN'
- $doc = "C:\Users\$env:USERNAME\Documents\Paradox Interactive\Stellaris"
- if (Test-Path $doc) { Remove-Item $doc -Recurse -Force; _Log " Removed: $doc" 'OK' }
- $dd = Join-Path $_GAMEPATH 'dlc'
- if (Test-Path $dd) { Remove-Item $dd -Recurse -Force; _Log " Removed dlc\ folder." 'OK' }
- }
-
- $altPath = $null
- if ($_ALT -and $_ALTNAME -and $_SERVERURL) {
- _Log "⬇ Downloading alternative launcher..."
- $altPath = Join-Path $_CACHE_DIR $_ALTNAME
- if (-not (Test-Path $altPath)) {
- _DownloadFile "https://$_SERVERURL/unlocker/$_ALTNAME" $altPath $_ALTNAME
- _Log " Alt launcher downloaded." 'OK'
- } else { _Log " Alt launcher cached: $_ALTNAME" 'OK' }
- }
-
- New-Item -ItemType Directory -Path (Join-Path $_GAMEPATH 'dlc') -Force | Out-Null
-
- _Log "⬇ Syncing creamapi files from repo..."
- $steamCache = Join-Path $_CACHE_DIR 'creamapi_steam_files'
- $launchCache = Join-Path $_CACHE_DIR 'creamapi_launcher_files'
-
- $fallbackFiles = @{
- 'creamapi_steam_files' = @('Emulator64.dll', 'LinkNeverDie_Com_64.dll', 'SWLoader.txt', 'SWconfig.ini', 'cream_api.ini', 'steam_api64_org_game.dll', 'steam_api64_org_launcher.dll')
- 'creamapi_launcher_files' = @('cream_api.ini', 'sdkencryptedappticket64.dll', 'steam_api64.dll', 'steam_api64_o.dll')
- }
-
- foreach ($pair in @(@{sub='creamapi_steam_files';dest=$steamCache},@{sub='creamapi_launcher_files';dest=$launchCache})) {
- New-Item -ItemType Directory -Path $pair.dest -Force | Out-Null
- $useJsDelivr = $false
-
- try {
- $wc2 = [System.Net.WebClient]::new(); $wc2.Headers.Add('User-Agent','StellarisDLCUnlocker-PS/1.0')
- $items = ($wc2.DownloadString("$_ORIGIN_API/$($pair.sub)") | ConvertFrom-Json)
- foreach ($item in $items) {
- if ($item.type -eq 'file') {
- $dest2 = Join-Path $pair.dest $item.name
- $hashFile = "$dest2.sha"
- if (-not ((Test-Path $dest2) -and (Test-Path $hashFile) -and ((Get-Content $hashFile -Raw).Trim() -eq $item.sha))) {
- $wc3 = [System.Net.WebClient]::new(); $wc3.Headers.Add('User-Agent','StellarisDLCUnlocker-PS/1.0')
- $wc3.DownloadFile($item.download_url, $dest2); $wc3.Dispose()
- $item.sha | Out-File -FilePath $hashFile -Encoding ascii -Force
- _Log " OK (GitHub): $($item.name)" 'OK'
- }
- }
- }
- $wc2.Dispose()
- } catch {
- _Log " GitHub API timeout/error, switching to jsDelivr for $($pair.sub)..." 'WARN'
- $useJsDelivr = $true
- }
-
- if ($useJsDelivr) {
- $baseUrl = "https://cdn.jsdelivr.net/gh/seuyh/stellaris-dlc-unlocker@main/$($pair.sub)"
-
- $manifest = $null
- try {
- $wc4 = [System.Net.WebClient]::new()
- $wc4.Headers.Add('User-Agent','StellarisDLCUnlocker-PS/1.0')
- $manifest = ($wc4.DownloadString("$baseUrl/manifest.json") | ConvertFrom-Json)
- $wc4.Dispose()
- } catch {
- _Log " No manifest.json via jsDelivr for $($pair.sub), will re-download all." 'WARN'
- }
-
- foreach ($f in $fallbackFiles[$pair.sub]) {
- $dest2 = Join-Path $pair.dest $f
- $hashFile = "$dest2.sha"
-
- $remoteSha = if ($manifest) { ($manifest | Where-Object { $_.name -eq $f }).sha } else { $null }
- $needDownload = $true
- if ($remoteSha -and (Test-Path $dest2) -and (Test-Path $hashFile) -and
- ((Get-Content $hashFile -Raw).Trim() -eq $remoteSha)) {
- $needDownload = $false
- }
-
- if ($needDownload) {
- try {
- $wc3 = [System.Net.WebClient]::new()
- $wc3.Headers.Add('User-Agent','StellarisDLCUnlocker-PS/1.0')
- $wc3.DownloadFile("$baseUrl/$f", $dest2)
- $wc3.Dispose()
- if ($remoteSha) { $remoteSha | Out-File -FilePath $hashFile -Encoding ascii -Force }
- _Log " OK (jsDelivr): $f" 'OK'
- } catch {
- _Log " Failed to download via jsDelivr: $f" 'ERROR'
- }
- } else {
- _Log " Cached (jsDelivr): $f" 'OK'
- }
- }
- }
- }
- _Log "⬇ Syncing creamapi_launcher_files from repo... done."
-
- _Log "🔄 Updating cream_api.ini via steamcmd..."
- foreach ($iniPath in @((Join-Path $steamCache 'cream_api.ini'),(Join-Path $launchCache 'cream_api.ini'))) {
- if (-not (Test-Path $iniPath)) { continue }
- try {
- $req = [System.Net.HttpWebRequest]::Create("$_STEAMCMD_API/$_APPID")
- $req.Timeout = 2500
- $req.ReadWriteTimeout = 2500
- $resp = $req.GetResponse()
- $stream = $resp.GetResponseStream()
- $reader = [System.IO.StreamReader]::new($stream)
- $data = ($reader.ReadToEnd() | ConvertFrom-Json)
- $reader.Dispose(); $stream.Dispose(); $resp.Dispose()
-
- $csv = $data.data."$_APPID".extended.listofdlc
- if ($csv) {
- $exist = Get-Content $iniPath -Raw
- $fs = [System.IO.File]::Open($iniPath,[System.IO.FileMode]::Append,[System.IO.FileAccess]::Write)
- $sw = [System.IO.StreamWriter]::new($fs,[System.Text.Encoding]::UTF8); $added = 0
- if ($exist -and -not $exist.EndsWith("`n")) { $sw.WriteLine() }
-
- foreach ($id in ($csv -split ',')) {
- $id = $id.Trim(); if (-not $id -or $exist -match $id) { continue }
- $name = $id
- try {
- $req2 = [System.Net.HttpWebRequest]::Create("$_STEAMCMD_API/$id")
- $req2.Timeout = 1500; $req2.ReadWriteTimeout = 1500
- $resp2 = $req2.GetResponse()
- $reader2 = [System.IO.StreamReader]::new($resp2.GetResponseStream())
- $name = ($reader2.ReadToEnd() | ConvertFrom-Json).data."$id".common.name
- $reader2.Dispose(); $resp2.Close()
- } catch {}
- $sw.WriteLine("$id = $name"); $added++
- }
- $sw.Dispose(); $fs.Dispose()
- if ($added -gt 0) { _Log " cream_api.ini updated: +$added DLC." 'OK' }
- }
- } catch {
- _Log " SteamCMD is currently unavailable, skipped update." 'WARN'
- }
- }
-
- $dlcDir = Join-Path $_GAMEPATH 'dlc'; $queue = @(); $total = 0
- foreach ($dlc in $_DLCDATA) {
- $f = $dlc.dlc_folder; if (-not $f) { continue }; $total++
- $zip = Join-Path $dlcDir "$f.zip"; $dir = Join-Path $dlcDir $f
- if (Test-Path $dir) {
- if ($f -in $_OUTDATED) {
- _Log " Removing outdated DLC for re-download: $f" 'WARN'
- Remove-Item $dir -Recurse -Force
- } else { continue }
- }
- if (Test-Path $zip) { try { [System.IO.Compression.ZipFile]::OpenRead($zip).Dispose(); continue } catch { Remove-Item $zip -Force } }
- $queue += @{ folder=$f; zip=$zip; url="https://$_SERVERURL/unlocker/$f.zip" }
- }
-
- _Log "📦 To download: $($queue.Count) of $total DLC"
- $doneD = 0
- foreach ($item in $queue) {
- _Log "⬇ [$($doneD+1)/$($queue.Count)] $($item.folder)"
- $_Q.Enqueue([pscustomobject]@{ t='cur'; text=$item.folder })
- _DownloadFile $item.url $item.zip $item.folder
- $doneD++
- $_Q.Enqueue([pscustomobject]@{ t='pbar'; val=[Math]::Round($doneD/$queue.Count*100) })
- _Log " Downloaded: $($item.folder)" 'OK'
- }
-
- _Log "📂 Unpacking archives..."
- foreach ($z in (Get-ChildItem $dlcDir -Filter '*.zip' -ErrorAction SilentlyContinue)) {
- try {
- [System.IO.Compression.ZipFile]::ExtractToDirectory($z.FullName,$dlcDir)
- Remove-Item $z.FullName -Force
- _Log " Unpacked: $($z.BaseName)" 'OK'
- } catch { _Log " Unzip error $($z.Name): $($_.Exception.Message)" 'ERROR' }
- }
-
- if (-not $_SKIP) {
- _Log "🔧 Reinstalling Paradox Launcher..."
- $msiPath = $null
- if ($altPath -and (Test-Path $altPath)) {
- $msiPath = $altPath
- _Log " Using alt launcher: $(Split-Path $msiPath -Leaf)"
- } else {
- $msiFiles = @(Get-ChildItem $_GAMEPATH -Filter 'launcher-installer-windows*.msi' -ErrorAction SilentlyContinue)
- if ($msiFiles.Count -gt 0) {
- $msiPath = ($msiFiles | Sort-Object {
- if ($_.Name -match 'launcher-installer-windows[_.](\d+)[._](\d+)') {
- [long]("$($Matches[1])$($Matches[2].PadLeft(6,'0'))")
- } else { 0L }
- } -Descending)[0].FullName
- _Log " MSI selected (latest): $(Split-Path $msiPath -Leaf)"
- if ($msiFiles.Count -gt 1) { _Log " ($($msiFiles.Count) MSI files found, using newest)" 'WARN' }
- }
- }
- if ($msiPath) {
- $launcherBase = _GetLauncherBase
- foreach ($lp in @($launcherBase) + (_GetLauncherDataFolders)) {
- if ($lp -and (Test-Path $lp)) {
- try { Remove-Item $lp -Recurse -Force; _Log " Removed: $lp" }
- catch { _Log " Could not remove $lp" 'WARN' }
- }
- }
- _Log " Running msiexec /uninstall..."
- $psi = [System.Diagnostics.ProcessStartInfo]::new('msiexec.exe', "/uninstall `"$msiPath`" /quiet /norestart")
- $psi.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden; $psi.CreateNoWindow = $true
- $proc = [System.Diagnostics.Process]::Start($psi); $proc.WaitForExit()
- Start-Sleep -Seconds 1
- _Log " Running msiexec /package..."
- $psi2 = [System.Diagnostics.ProcessStartInfo]::new('msiexec.exe', "/package `"$msiPath`" /quiet /norestart CREATE_DESKTOP_SHORTCUT=0")
- $psi2.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden; $psi2.CreateNoWindow = $true
- $proc2 = [System.Diagnostics.Process]::Start($psi2); $proc2.WaitForExit()
- _Log " Launcher reinstalled." 'OK'
- } else { _Log " No MSI found in game folder — skipping launcher reinstall." 'WARN' }
- } else { _Log " Launcher reinstall skipped." }
-
- _Log "📋 Patching launcher folders..."
- $launcherBase = if (-not [string]::IsNullOrWhiteSpace($_LAUNCHERPATH) -and (Test-Path $_LAUNCHERPATH)) {
- $_LAUNCHERPATH
- } else {
- _Log " Launcher path not set or not found, trying auto-detect..." 'WARN'
- _GetLauncherBase
- }
- _Log " Launcher base: $launcherBase"
- if (Test-Path $launcherBase) {
- $lFolders = @(Get-ChildItem $launcherBase -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -like 'launcher*' })
- _Log " Found $($lFolders.Count) launcher folder(s)."
- foreach ($lf in $lFolders) {
- _Log " Processing: $($lf.Name)"
- if ($_NO_UPDATE) {
- $xd = Join-Path $lf.FullName 'xdelta3.exe'
- if (Test-Path $xd) { Remove-Item $xd -Force; _Log " Removed xdelta3.exe (auto-update disabled)." 'OK' }
- }
- $t1 = Join-Path $lf.FullName 'resources\app.asar.unpacked\node_modules\greenworks\lib'
- $t2 = Join-Path $lf.FullName 'resources\app\dist\main'
- $tgt = if (Test-Path $t1) { $t1 } elseif (Test-Path $t2) { $t2 } else { $null }
- if ($tgt) { Copy-Item "$launchCache\*" $tgt -Recurse -Force; _Log " Patched: $tgt" 'OK' }
- else { _Log " No patchable resources folder found." 'WARN' }
- }
- } else { _Log " Launcher base not found: $launcherBase" 'WARN' }
-
- _Log "📋 Copying CreamAPI steam files to game folder..."
- Copy-Item "$steamCache\*" $_GAMEPATH -Recurse -Force
- _Log " Steam files copied." 'OK'
- $_Q.Enqueue([pscustomobject]@{ t='speed_reset' })
- _Log ''
- _Log "✅ Done! Launch Stellaris via Steam." 'OK'
- _FileLog "✅ Installation completed successfully."
- $_Q.Enqueue([pscustomobject]@{ t='install_done' })
-
- } catch {
- $errMsg = "❌ Unhandled error: $($_.Exception.Message)`n$($_.ScriptStackTrace)"
- _Log $errMsg 'ERROR'
- _FileLog $errMsg 'ERROR'
- $_Q.Enqueue([pscustomobject]@{ t='install_done' })
- }
-'@)
-
-[xml]$xaml = @'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-'@
-
-$reader = [System.Xml.XmlNodeReader]::new($xaml)
-$window = [Windows.Markup.XamlReader]::Load($reader)
-$pathBox = $window.FindName('PathBox'); $browseBtn = $window.FindName('BrowseBtn')
-$lblLauncherPath = $window.FindName('LblLauncherPath')
-$launcherPathBox = $window.FindName('LauncherPathBox')
-$launcherBrowseBtn = $window.FindName('LauncherBrowseBtn')
-$chkNoUpdate = $window.FindName('ChkNoUpdate')
-$statusLbl = $window.FindName('StatusLbl'); $logBox = $window.FindName('LogBox')
-$installBtn = $window.FindName('InstallBtn');$launchBtn = $window.FindName('LaunchBtn')
-$refreshBtn = $window.FindName('RefreshBtn')
-$pBar = $window.FindName('PBar'); $pBarFile = $window.FindName('PBarFile')
-$speedLbl = $window.FindName('SpeedLbl'); $curLbl = $window.FindName('CurLbl')
-$chkFull = $window.FindName('ChkFull'); $chkSkip = $window.FindName('ChkSkip')
-$lblLauncher = $window.FindName('LblLauncher'); $cmbLauncher = $window.FindName('CmbLauncher')
-$dotGH = $window.FindName('DotGH'); $dotSrv = $window.FindName('DotSrv')
-$dlcList = $window.FindName('DlcList')
-$btnEn=$window.FindName('BtnEn'); $btnRu=$window.FindName('BtnRu'); $btnZh=$window.FindName('BtnZh')
-$titleLbl=$window.FindName('TitleLbl'); $lblPath=$window.FindName('LblPath')
-$lblStatus=$window.FindName('LblStatus'); $lblOpts=$window.FindName('LblOpts'); $lblDlc=$window.FindName('LblDlc')
-$legOk=$window.FindName('LegOk'); $legOld=$window.FindName('LegOld'); $legMiss=$window.FindName('LegMiss')
-
-function Add-LogItem([string]$text, [string]$level) {
- $color = switch ($level) { 'ERROR' {'#e74c3c'} 'WARN' {'#f39c12'} 'OK' {'#27ae60'} default {'#6a7a9a'} }
- $tb = [System.Windows.Controls.TextBlock]::new()
- $tb.Text = $text; $tb.TextWrapping = [System.Windows.TextWrapping]::Wrap
- $tb.Foreground = [System.Windows.Media.SolidColorBrush][System.Windows.Media.ColorConverter]::ConvertFromString($color)
- $li = [System.Windows.Controls.ListBoxItem]::new(); $li.Content = $tb
- $logBox.Items.Add($li) | Out-Null; $logBox.ScrollIntoView($li)
-}
-
-$drainTimer = [System.Windows.Threading.DispatcherTimer]::new()
-$drainTimer.Interval = [TimeSpan]::FromMilliseconds(50)
-$drainTimer.Add_Tick({
- $item = [object]$null
- while ($script:Q.TryDequeue([ref]$item)) {
- switch ($item.t) {
- 'log' { Add-LogItem $item.msg $item.lvl; Write-Log ($item.msg -replace '^\[.+?\] ','') $item.lvl }
- 'dot_gh' { $dotGH.Fill = if ($item.ok) { [System.Windows.Media.Brushes]::LimeGreen } else { [System.Windows.Media.Brushes]::Crimson } }
- 'dot_srv' { $dotSrv.Fill = if ($item.ok) { [System.Windows.Media.Brushes]::LimeGreen } else { [System.Windows.Media.Brushes]::Crimson } }
- 'dlc_data' { $script:dlcData=$item.data; Refresh-DlcList }
- 'outdated' { $script:outdatedFolders=$item.folders; Refresh-DlcList }
- 'init_done' { Update-UI; Refresh-DlcList }
- 'install_done'{
- $script:outdatedFolders = @()
- Update-UI; Refresh-DlcList
- $launchBtn.Visibility=[System.Windows.Visibility]::Visible
- }
- 'speed_reset' { $speedLbl.Text=''; $curLbl.Text='' }
- 'progress' { $pBarFile.Value=$item.pfile; if ($item.speed) {$speedLbl.Text=$item.speed}; if ($item.cur) {$curLbl.Text=$item.cur} }
- 'pbar' { $pBar.Value=$item.val }
- 'cur' { $curLbl.Text=$item.text }
- }
- }
-})
-$drainTimer.Start()
-
-function Set-LangActive([string]$lang) {
- $off = [System.Windows.Media.SolidColorBrush][System.Windows.Media.Color]::FromRgb(0x2a,0x2a,0x45)
- $on = [System.Windows.Media.SolidColorBrush][System.Windows.Media.Color]::FromRgb(0x1a,0x5a,0x9a)
- $btnEn.Background=$off; $btnRu.Background=$off; $btnZh.Background=$off
- switch ($lang) { 'ru' {$btnRu.Background=$on} 'zh' {$btnZh.Background=$on} default {$btnEn.Background=$on} }
-}
-function Apply-UIText {
- $titleLbl.Text=T 'title'; $lblPath.Text=T 'path_label'; $browseBtn.Content=T 'browse'
- $lblStatus.Text=T 'status_label'; $lblOpts.Text=T 'options_label'
- $chkFull.Content=T 'chk_full'; $chkSkip.Content=T 'chk_skip'
- $chkNoUpdate.Content = T 'chk_no_update'
- $lblLauncher.Text=T 'lbl_launcher'
- $lblLauncherPath.Text = T 'lbl_launcher_path'
- $launcherBrowseBtn.Content = T 'browse'
- $sel = $cmbLauncher.SelectedIndex
- $cmbLauncher.Items.Clear()
- [void]$cmbLauncher.Items.Add((T 'launcher_default'))
- foreach ($alt in $ALT_LAUNCHERS) { [void]$cmbLauncher.Items.Add($alt) }
- if ($sel -ge 0) { $cmbLauncher.SelectedIndex = $sel } else { $cmbLauncher.SelectedIndex = 0 }
- $lblDlc.Text=T 'dlc_label'; $installBtn.Content=T 'install_btn'; $launchBtn.Content=T 'launch_btn'
- $refreshBtn.ToolTip=T 'refresh_tip'
- $legOk.Text=T 'dlc_ok'; $legOld.Text=T 'dlc_old'; $legMiss.Text=T 'dlc_missing'
-}
-function Apply-Lang([string]$lang) { Set-LangBuiltin $lang; Set-LangActive $lang; Apply-UIText; Update-UI }
-
-function Refresh-DlcList {
- $dlcList.Items.Clear()
- if (-not $script:dlcData) { return }
- $gp = $pathBox.Text.Trim()
- if ([string]::IsNullOrWhiteSpace($gp)) { return }
- try { if (-not (Test-Path (Join-Path $gp 'stellaris.exe'))) { return } } catch { return }
- $dlcBase = Join-Path $gp 'dlc'
- foreach ($dlc in $script:dlcData) {
- $name=$dlc.dlc_name; $f=$dlc.dlc_folder
- if (-not $name -or -not $f) { continue }
- $exists = try { Test-Path (Join-Path $dlcBase $f) } catch { $false }
- $color = if (-not $exists) {'#e74c3c'} elseif ($f -in $script:outdatedFolders) {'#f39c12'} else {'#27ae60'}
- $tb=[System.Windows.Controls.TextBlock]::new(); $tb.Text=$name; $tb.FontSize=12
- $tb.Foreground=[System.Windows.Media.SolidColorBrush][System.Windows.Media.ColorConverter]::ConvertFromString($color)
- $li=[System.Windows.Controls.ListBoxItem]::new(); $li.Content=$tb
- $dlcList.Items.Add($li) | Out-Null
- }
-}
-function Update-UI {
- $st = Get-InstallStatus $pathBox.Text.Trim()
- $ready = ($null -ne $script:dlcData)
- switch ($st) {
- 'installed' { $statusLbl.Text=T 'status_installed'; $statusLbl.Foreground='#27ae60'; $installBtn.IsEnabled=$ready }
- 'not_installed' { $statusLbl.Text=T 'status_not_installed'; $statusLbl.Foreground='#f0a030'; $installBtn.IsEnabled=$ready }
- 'not_found' { $statusLbl.Text=T 'status_not_found'; $statusLbl.Foreground='#e74c3c'; $installBtn.IsEnabled=$false }
- }
-}
-
-$window.Add_Loaded({
- Write-Log "=== Stellaris DLC Unlocker started ==="
- Set-LangBuiltin (Get-SystemLang); Set-LangActive $script:curLang; Apply-UIText
- $steam = Find-SteamPath
- $sp = if ($steam) { Find-StellarisPath $steam } else { $null }
- if (-not [string]::IsNullOrWhiteSpace($sp)) { $pathBox.Text = $sp }
- $detectedLauncher = try {
- $reg = (Get-ItemProperty 'HKCU:\Software\Paradox Interactive\Paradox Launcher v2' -ErrorAction Stop).LauncherInstallation
- if ($reg -and (Test-Path $reg)) { $reg }
- else { "$env:LOCALAPPDATA\Programs\Paradox Interactive\launcher" }
- } catch { "$env:LOCALAPPDATA\Programs\Paradox Interactive\launcher" }
- if (Test-Path $detectedLauncher) { $launcherPathBox.Text = $detectedLauncher }
- $launcherBrowseBtn.Add_Click({
- $path = [Picker.FolderDialog]::Pick('Select Paradox Launcher folder', $launcherPathBox.Text)
- if ($path) { $launcherPathBox.Text = $path }
- })
- $statusLbl.Text=T 'status_loading'; $installBtn.IsEnabled=$false
-
- Start-PSRunspace $INIT_SCRIPT @{
- _Q = $script:Q
- _GDLC = $GITHUB_DLC_URL; _GDLC_FALL = $JSDELIVR_DLC_URL;
- _GHASH = $GITHUB_HASHES_URL; _GHASH_FALL = $JSDELIVR_HASHES_URL
- _STEAMCMD_API= $STEAMCMD_API; _APPID = $STELLARIS_APP_ID
- _ORIGIN_API = $ORIGIN_API; _CACHE_DIR = $CACHE_DIR
- _SERVERURL = $SERVER_URL
- _ALTLAUNCHERS= $ALT_LAUNCHERS
- _GAMEPATH = if (-not [string]::IsNullOrWhiteSpace($sp)) { $sp } else { '' }
- }
-})
-
-$btnEn.Add_Click({ Apply-Lang 'en'; Refresh-DlcList })
-$btnRu.Add_Click({ Apply-Lang 'ru'; Refresh-DlcList })
-$btnZh.Add_Click({ Apply-Lang 'zh'; Refresh-DlcList })
-
-$browseBtn.Add_Click({
- $path = [Picker.FolderDialog]::Pick('Select Stellaris folder', $pathBox.Text)
- if ($path) { $pathBox.Text = $path; Update-UI; Refresh-DlcList }
-})
-$refreshBtn.Add_Click({ Update-UI; Refresh-DlcList })
-$pathBox.Add_TextChanged({ Update-UI })
-
-$chkFull.Add_Checked({
- $r=[System.Windows.MessageBox]::Show((T 'confirm_full'),(T 'warn_title'),[System.Windows.MessageBoxButton]::YesNo,[System.Windows.MessageBoxImage]::Warning)
- if ($r -ne 'Yes') { $chkFull.IsChecked=$false; return }
- $chkSkip.IsChecked=$false; $chkSkip.IsEnabled=$false
-})
-$chkFull.Add_Unchecked({ $chkSkip.IsEnabled=$true })
-$chkSkip.Add_Checked({
- $chkFull.IsChecked=$false; $chkFull.IsEnabled=$false
- $cmbLauncher.IsEnabled=$false
-})
-$chkSkip.Add_Unchecked({ $chkFull.IsEnabled=$true; $cmbLauncher.IsEnabled=$true })
-
-$chkNoUpdate.Add_Unchecked({
- $r = [System.Windows.MessageBox]::Show(
- (T 'confirm_no_update'), (T 'warn_title'),
- [System.Windows.MessageBoxButton]::YesNo,
- [System.Windows.MessageBoxImage]::Warning)
- if ($r -ne 'Yes') { $chkNoUpdate.IsChecked = $true }
-})
-
-$launchBtn.Add_Click({
- Start-Process "steam://rungameid/$STELLARIS_APP_ID"
- $window.Close()
-})
-
-$installBtn.Add_Click({
- $sp=$pathBox.Text.Trim()
- if (-not (Test-Path (Join-Path $sp 'stellaris.exe'))) {
- [System.Windows.MessageBox]::Show((T 'err_no_exe'),(T 'err_title'),[System.Windows.MessageBoxButton]::OK,[System.Windows.MessageBoxImage]::Warning) | Out-Null; return
- }
- if (-not $script:dlcData) {
- [System.Windows.MessageBox]::Show((T 'err_loading'),(T 'wait_title'),[System.Windows.MessageBoxButton]::OK,[System.Windows.MessageBoxImage]::Information) | Out-Null; return
- }
- $installBtn.IsEnabled=$false; $launchBtn.Visibility=[System.Windows.Visibility]::Collapsed
- $pBar.Value=0; $pBarFile.Value=0; $speedLbl.Text=''; $curLbl.Text=''
-
- $selectedAlt = if ($cmbLauncher.SelectedIndex -gt 0) { $ALT_LAUNCHERS[$cmbLauncher.SelectedIndex - 1] } else { $null }
-
- Start-PSRunspace $INSTALL_SCRIPT @{
- _Q = $script:Q
- _GAMEPATH = $sp
- _LAUNCHERPATH = $launcherPathBox.Text.Trim()
- _DLCDATA = $script:dlcData
- _SERVERURL = $SERVER_URL
- _ALTNAME = $selectedAlt
- _OUTDATED = $script:outdatedFolders
- _FULL = [bool]$chkFull.IsChecked
- _SKIP = [bool]$chkSkip.IsChecked
- _NO_UPDATE = [bool]$chkNoUpdate.IsChecked
- _ALT = ($null -ne $selectedAlt)
- _CACHE_DIR = $CACHE_DIR
- _ORIGIN_API = $ORIGIN_API
- _STEAMCMD_API = $STEAMCMD_API
- _APPID = $STELLARIS_APP_ID
- _LOG_FILE = $LOG_FILE
- }
-})
-
-[System.Windows.Media.RenderOptions]::ProcessRenderMode = [System.Windows.Interop.RenderMode]::SoftwareOnly
-[void]$window.ShowDialog()
-$drainTimer.Stop()
diff --git a/UI/icons/stellaris.png b/UI/icons/stellaris.png
deleted file mode 100644
index 0cdbad4..0000000
Binary files a/UI/icons/stellaris.png and /dev/null differ
diff --git a/UI/recources_rc.py b/UI/recources_rc.py
deleted file mode 100644
index dfe2b5a..0000000
--- a/UI/recources_rc.py
+++ /dev/null
@@ -1,1004 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Resource object code
-#
-# Created by: The Resource Compiler for PyQt5 (Qt v5.15.2)
-#
-# WARNING! All changes made in this file will be lost!
-
-from PyQt5 import QtCore
-
-qt_resource_data = b"\
-\x00\x00\x02\x11\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x0d\x00\x00\x00\x0d\x08\x04\x00\x00\x00\xd8\xe2\x2c\xf7\
-\x00\x00\x00\x20\x63\x48\x52\x4d\x00\x00\x7a\x26\x00\x00\x80\x84\
-\x00\x00\xfa\x00\x00\x00\x80\xe8\x00\x00\x75\x30\x00\x00\xea\x60\
-\x00\x00\x3a\x98\x00\x00\x17\x70\x9c\xba\x51\x3c\x00\x00\x00\x02\
-\x62\x4b\x47\x44\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09\x70\x48\
-\x59\x73\x00\x00\x0e\xc4\x00\x00\x0e\xc4\x01\x95\x2b\x0e\x1b\x00\
-\x00\x00\x07\x74\x49\x4d\x45\x07\xe8\x02\x1a\x0b\x04\x00\x1b\x9e\
-\xfd\x31\x00\x00\x00\xbb\x49\x44\x41\x54\x18\xd3\x75\xd0\xb1\x4a\
-\x42\x61\x00\xc5\xf1\x9f\x16\xde\x4d\x72\xb4\x92\xc0\x07\x90\x06\
-\x97\xb6\x06\x1d\xa2\x17\xb8\xf4\x00\x42\x53\xcf\xe0\x2b\xdc\xb5\
-\xdd\xa9\x37\xe8\xce\x42\xe1\xd2\x56\x11\xcd\x8e\x1f\xf8\x0d\x21\
-\x72\x3f\x07\xcb\x8a\xec\x9c\xed\xc0\x7f\x38\x7f\x20\x93\x2b\x05\
-\x95\xa0\x94\xcb\x7c\xa6\xa5\x10\xa5\x6d\xa3\x42\x6b\x43\x14\x3f\
-\xe6\xaf\x16\x32\xf2\x5f\x44\x12\xcd\x25\x51\x4e\xb9\x1d\x2b\x6f\
-\x6e\x5d\xba\x51\x49\xca\x7d\x7d\x24\xc1\xa3\x3b\xcf\x0e\x4c\x9d\
-\xa9\xa1\x5f\xd7\xc4\xbb\x91\x2b\x73\x43\xaf\xa2\x53\xd0\x24\x48\
-\x3e\x3c\xb9\x37\x71\x84\x43\x2f\x92\x24\xd4\xcd\x90\xe9\x19\x78\
-\xd0\xd1\xd0\xd1\x06\xb3\x3d\x4b\x17\x1a\xa8\x1c\xbb\x76\xa2\xeb\
-\x5c\x4d\x34\xfe\xfb\x6b\xf5\xfd\x6b\x63\x63\xb1\xcb\xc6\xbf\x0e\
-\xd7\x75\xe3\x60\x86\xfc\x81\x54\x73\x00\x00\x00\x25\x74\x45\x58\
-\x74\x64\x61\x74\x65\x3a\x63\x72\x65\x61\x74\x65\x00\x32\x30\x32\
-\x34\x2d\x30\x32\x2d\x32\x36\x54\x31\x31\x3a\x30\x33\x3a\x35\x35\
-\x2b\x30\x30\x3a\x30\x30\x12\x52\xa8\x13\x00\x00\x00\x25\x74\x45\
-\x58\x74\x64\x61\x74\x65\x3a\x6d\x6f\x64\x69\x66\x79\x00\x32\x30\
-\x32\x34\x2d\x30\x32\x2d\x32\x36\x54\x31\x31\x3a\x30\x33\x3a\x35\
-\x35\x2b\x30\x30\x3a\x30\x30\x63\x0f\x10\xaf\x00\x00\x00\x28\x74\
-\x45\x58\x74\x64\x61\x74\x65\x3a\x74\x69\x6d\x65\x73\x74\x61\x6d\
-\x70\x00\x32\x30\x32\x34\x2d\x30\x32\x2d\x32\x36\x54\x31\x31\x3a\
-\x30\x34\x3a\x30\x30\x2b\x30\x30\x3a\x30\x30\xcc\x1e\x0b\xca\x00\
-\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\x74\x77\x61\x72\x65\x00\
-\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\
-\x9b\xee\x3c\x1a\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\
-\x00\x00\x02\x1d\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x0c\x00\x00\x00\x0c\x08\x06\x00\x00\x00\x56\x75\x5c\xe7\
-\x00\x00\x00\x20\x63\x48\x52\x4d\x00\x00\x7a\x26\x00\x00\x80\x84\
-\x00\x00\xfa\x00\x00\x00\x80\xe8\x00\x00\x75\x30\x00\x00\xea\x60\
-\x00\x00\x3a\x98\x00\x00\x17\x70\x9c\xba\x51\x3c\x00\x00\x00\x09\
-\x70\x48\x59\x73\x00\x00\x0e\xc2\x00\x00\x0e\xc2\x01\x15\x28\x4a\
-\x80\x00\x00\x00\x02\x62\x4b\x47\x44\x00\xff\x87\x8f\xcc\xbf\x00\
-\x00\x00\x07\x74\x49\x4d\x45\x07\xe8\x02\x1a\x0b\x10\x17\xb6\xe3\
-\xaf\xa3\x00\x00\x00\x25\x74\x45\x58\x74\x64\x61\x74\x65\x3a\x63\
-\x72\x65\x61\x74\x65\x00\x32\x30\x32\x34\x2d\x30\x32\x2d\x32\x36\
-\x54\x31\x31\x3a\x31\x36\x3a\x31\x35\x2b\x30\x30\x3a\x30\x30\xb1\
-\xbf\xb2\x6d\x00\x00\x00\x25\x74\x45\x58\x74\x64\x61\x74\x65\x3a\
-\x6d\x6f\x64\x69\x66\x79\x00\x32\x30\x32\x34\x2d\x30\x32\x2d\x32\
-\x36\x54\x31\x31\x3a\x31\x36\x3a\x31\x35\x2b\x30\x30\x3a\x30\x30\
-\xc0\xe2\x0a\xd1\x00\x00\x00\x28\x74\x45\x58\x74\x64\x61\x74\x65\
-\x3a\x74\x69\x6d\x65\x73\x74\x61\x6d\x70\x00\x32\x30\x32\x34\x2d\
-\x30\x32\x2d\x32\x36\x54\x31\x31\x3a\x31\x36\x3a\x32\x33\x2b\x30\
-\x30\x3a\x30\x30\x7a\xa8\x19\xd7\x00\x00\x00\xec\x49\x44\x41\x54\
-\x28\x53\x9d\xd1\x3b\x4b\x82\x61\x18\xc6\xf1\xc7\xd3\x22\x0a\x9e\
-\x40\xc4\xc1\x29\x48\x44\x89\x20\x90\xec\x5b\x38\x58\xb4\xe4\xd0\
-\xe7\xa9\xa9\xc1\xd3\x37\x70\xd1\x4d\xf0\x03\x38\x87\x43\x84\xe0\
-\xaa\xe8\xa0\xe0\x90\x5a\xf6\xbf\x1e\xec\x55\xd3\xc9\x0b\x7e\xbc\
-\xdc\x0f\xcf\xf1\x7e\x5d\x66\x17\x1f\xae\x71\x83\x30\xc6\xe8\xe1\
-\x1d\xdf\x38\x48\x02\x55\xcc\xb1\xd9\x33\xc5\x2b\x62\xb0\xf1\x20\
-\x88\x37\xdc\x61\x00\x3f\x66\x58\xe2\x13\x57\x48\xa3\x83\x15\x4c\
-\x09\xda\x4d\x8b\x42\xc8\xe1\x62\xfb\x55\xfd\x02\x5d\xa9\x08\x9b\
-\x1a\xb4\xe0\xd9\x56\xc7\x79\xc4\x0f\x2a\x2a\xdc\x88\x43\x47\x7d\
-\x68\xe0\x44\xfa\x58\x40\xef\xf4\x6a\xc1\x04\xea\x50\x01\xfb\x5d\
-\xfb\x8b\xc6\x03\x50\x03\x6c\xb7\x9e\x30\x44\x13\x75\xe8\x91\x4a\
-\x16\x0d\x68\x43\x5d\xb9\x0c\x7b\xa5\x16\x74\xec\x1a\x23\x7c\x41\
-\x89\x40\xf7\x8f\xa2\x0b\xcd\x73\x72\x89\x36\xb4\x30\xaf\x01\x72\
-\x0b\xb5\x57\x93\x33\x1a\xf8\x1f\xed\xf4\x80\x94\xad\x8c\x49\xe2\
-\x1e\xce\x4f\x3b\x23\xc6\xfc\x02\xc9\x33\x31\x9a\xc9\x8d\x73\x38\
-\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x01\x67\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x17\x00\x00\x00\x17\x08\x06\x00\x00\x00\xe0\x2a\xd4\xa0\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x01\x19\x49\x44\x41\x54\x48\x89\xed\
-\x96\xcd\x11\x82\x40\x0c\x85\x9f\x8e\x77\xe8\x00\x3b\xd0\x0e\xdc\
-\x12\xe8\x40\x4b\xa0\x04\x4a\xb0\x04\x3a\xb0\x04\x29\x01\x3b\xa0\
-\x04\x3a\x78\x1e\xc8\xb2\x88\xd9\x1f\x87\xd1\x93\x6f\x26\x03\x93\
-\x64\xbf\x09\x24\xec\xb2\x21\x89\x04\xe5\x00\x5a\xb9\x37\x00\x06\
-\xb9\x3f\x8a\xf5\xb3\xb8\x13\xc9\x98\x1d\x49\xf6\x74\xea\xc5\x87\
-\x99\xaf\xd6\xd6\x6e\x23\x15\x97\x52\x51\x31\xf3\x15\xe2\x2b\x63\
-\x8f\x1b\x82\x57\x00\x6e\x00\x32\x25\x96\x49\x2c\xa8\x9d\xc7\xdf\
-\x00\x38\x2f\x7c\x0f\xb9\x1e\x62\xd0\x49\x8b\xf7\x94\x93\xec\xf8\
-\xae\x4e\x62\xb1\xf8\x0b\x2f\xd4\x38\xab\x46\x69\x56\xa3\xe4\xcd\
-\x1b\xfd\x02\x2f\x49\x0e\xca\x82\xab\x36\x05\x62\xb5\x92\x3f\x08\
-\x6b\x82\x57\x4a\x12\x49\x5e\x02\x60\x6b\x17\xcf\xda\xca\xc2\x97\
-\x15\x0f\x24\x4d\x02\xd8\x9a\xf1\x30\x72\xad\xf2\xf6\x03\xb0\xb5\
-\x76\xc1\xa8\x6d\xe5\xe0\xd8\x0c\x3b\x05\x6b\xe0\x9d\xb0\x40\x72\
-\x9a\x73\x03\x60\x0f\xe0\x9e\x3c\xc3\xba\x2a\x8c\xfb\x0c\x00\xf7\
-\x11\xf5\x02\xd7\xd4\x7a\xfc\xc6\xe3\x7f\x83\x87\x74\x4a\xc8\x51\
-\x15\xdb\xb8\x56\xe9\x0f\xff\x3d\x5c\x9b\x96\x13\x80\x94\x83\x35\
-\x9a\xf3\xd5\xca\x37\x74\xa7\x7f\x8e\xf1\x24\x5f\xa3\x0e\xee\xcf\
-\x00\x4f\xd8\x12\x8e\x47\x65\xaf\xb5\x35\x00\x00\x00\x00\x49\x45\
-\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x00\x74\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x14\x00\x00\x00\x05\x08\x06\x00\x00\x00\x45\x03\xcc\x33\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\x26\x49\x44\x41\x54\x18\x95\x63\
-\xfc\xff\xff\x7f\x03\x03\x15\x01\xe3\xff\xff\xff\xff\x53\xd3\x40\
-\x26\x6a\x1a\x46\x13\x03\x59\x18\x18\x18\x1a\xa9\x69\x20\x00\xae\
-\x00\x08\x05\x85\x9a\x3e\x65\x00\x00\x00\x00\x49\x45\x4e\x44\xae\
-\x42\x60\x82\
-\x00\x00\x01\xf1\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x16\x00\x00\x00\x0f\x08\x06\x00\x00\x00\xe0\x6d\x3f\x68\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x01\xa3\x49\x44\x41\x54\x38\x8d\x8d\
-\x94\x21\x6f\x54\x41\x14\x85\xcf\xb9\x73\x1d\x08\x5c\x8b\x6a\x42\
-\x1a\x04\x86\x75\x98\xfa\x26\x64\x25\x3f\x00\xd1\x1f\xc0\x2a\x4c\
-\x13\x12\x0c\x25\x68\x82\x41\xf0\x03\x2a\x10\x0d\x01\x85\x01\x83\
-\xdb\x04\x41\x42\x4d\x1d\x75\x24\x74\xcd\xce\xbb\x73\x30\xef\x6d\
-\xa6\x93\x7d\xbb\xbd\xc9\x88\x77\xef\xb9\xdf\x9c\x3b\x33\x79\x94\
-\x84\x3a\x22\xe2\x44\xd2\x2e\x00\x90\xfc\x03\xe0\x5d\x4a\xe9\x02\
-\x4d\x44\xc4\xb1\xa4\xfd\x5e\x77\x05\xe0\x4d\xad\x63\x0d\xee\xba\
-\xee\x73\x29\xe5\xb0\x06\x90\x04\xc9\x2f\x24\x4f\x01\xfc\x92\x74\
-\x04\xe0\x49\x29\xe5\x56\xad\x33\xb3\x4b\x92\x8f\x06\xf8\x0a\x1c\
-\x11\x27\x11\xf1\xbc\x75\x56\x6f\x00\x00\xed\x84\x0d\x7c\xee\xee\
-\x13\x00\xb0\x21\x29\xe9\x69\x0d\x31\xb3\x6b\x4d\x92\xd6\x42\xcd\
-\x6c\x51\x69\x1e\x46\xc4\xc1\x0a\x1c\x11\xc7\xa5\x94\x9d\x0a\x3c\
-\x77\x77\xb6\xf0\x76\x82\x7e\x7d\xad\xa7\x91\xf4\x6c\x05\x96\x34\
-\x19\x1a\xdc\xfd\x23\xc9\x57\x7d\xf3\x2c\xa5\xf4\x7d\x64\xec\x33\
-\x92\x8b\x88\x98\x92\xfc\x61\x66\xf3\xbe\x74\x00\x00\xde\x7f\xec\
-\x8f\x5a\x1b\x09\x49\xd3\x52\x0a\xcc\x6c\x21\xe9\x01\x80\xdb\x7d\
-\x7e\x27\x22\xf6\x28\x09\x5d\xd7\xa9\x94\x52\xbb\x99\xbb\xfb\xa4\
-\xcd\xaf\x3b\x0e\x33\x3b\x8b\x88\x69\x9d\x4f\x29\xcd\xd6\x82\x87\
-\xf3\xdb\x04\xdd\x14\x29\xa5\xd7\x1e\x11\x7b\xed\x6d\x8f\xbd\x80\
-\x9b\x86\xa4\x5d\xdf\x24\x30\xb3\x39\xc9\x6f\x00\xce\x9b\xd2\x3d\
-\x49\xf7\x25\x1d\x8e\x19\xf0\x94\xd2\xc5\x3a\x87\x66\xf6\xc2\xdd\
-\x5f\x6e\xda\x38\x22\x1e\x97\x52\xde\x4b\xba\x5b\xe7\x49\x9e\x0f\
-\x0f\xf5\xb2\x2e\xa4\x94\xde\x6e\x83\xf6\xba\x4f\x66\x76\x44\xf2\
-\x5f\x53\xfa\x0d\x49\xc8\x39\x7f\x58\x2e\x97\xca\x39\x2b\xe7\x7c\
-\x3a\x4c\x70\xd3\xd5\x75\xdd\x2c\xe7\x7c\xd5\x33\x7e\x4a\xba\xf6\
-\x13\xba\x03\xe0\xef\x36\x97\x5b\x62\xc5\xf8\x0f\xeb\x70\x18\x76\
-\xad\x0d\x47\x22\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\
-\x00\x00\x01\x3b\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x17\x00\x00\x00\x17\x08\x06\x00\x00\x00\xe0\x2a\xd4\xa0\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\xed\x49\x44\x41\x54\x48\x89\xc5\
-\x95\xdb\x0d\x83\x30\x0c\x45\x0f\x59\xa0\x2b\x30\x02\x23\x74\x04\
-\x46\xa0\x1b\x76\x04\x46\x60\x04\x46\x80\x01\x1c\xf7\xa3\x21\x2a\
-\xe1\x15\x23\x50\x2d\xf9\x27\x89\x1f\xb9\xf6\xb5\x0b\x55\x25\x8a\
-\xf7\x35\xd0\xe3\x5c\x87\x55\xbc\xaf\x80\x12\xe7\xde\xf1\x4c\x55\
-\xbf\x2a\xd2\xa8\x88\xaa\xc8\xa0\x22\x55\x3c\xcf\x51\x91\x2a\xd8\
-\xa9\x8a\x34\xd3\x79\xea\x58\xcd\x01\xe6\x8e\xf5\x37\x00\x2a\x52\
-\x27\x17\xf9\x01\xd6\x1d\x4f\x5a\x3b\xa0\x07\xc6\x15\x14\x1f\x40\
-\x1b\xb0\xdc\xc2\xb8\x0d\xef\x52\x19\x81\x3e\x27\x83\xe5\x0f\x32\
-\xdf\x9b\x0d\x2c\x89\x58\x30\x1c\x42\xe1\xb3\x7f\x58\xcc\xfa\xfc\
-\x18\xcb\x2d\x19\x81\xe7\x82\x1f\x27\xba\x20\xbb\xab\xce\xb6\x59\
-\x56\xbb\x1e\x11\x24\x25\x57\xaa\xcd\x9e\xfd\x1f\x32\xbf\x08\x73\
-\x67\x64\xde\x9a\x6c\x32\x79\xee\xfc\x98\xd2\x2f\x2c\xa3\xe2\x7e\
-\x86\xde\x36\x5b\xac\x8e\x0d\x01\x1c\x50\xee\x60\xbc\xa4\x74\xac\
-\x96\xeb\x80\xe7\x4e\x0d\xca\x9b\x37\xd1\x92\x8d\x97\xed\xd0\xf9\
-\x54\xbc\x78\xfb\x7f\x00\x73\x80\x30\xe0\x4c\xcb\x9c\x8f\x00\x00\
-\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x01\x74\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4\x6c\x3b\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x01\x26\x49\x44\x41\x54\x38\x8d\xb5\
-\x55\xdb\x6d\xc3\x30\x0c\xbc\x16\xfd\x8f\x36\xa8\x46\xc9\x08\x1d\
-\x41\x23\x78\x94\x8c\x90\x11\x34\x82\x47\x70\x36\xd0\x08\xc9\x04\
-\xd7\x0f\x8b\x31\x41\x93\x76\x60\x24\x07\x10\x96\x44\x89\x3c\x99\
-\x0f\x81\x24\x02\x29\x24\xc7\xfe\xd5\xeb\x89\x33\xaa\xa3\x7b\x8a\
-\xb7\x98\x49\x36\x2e\x68\x8e\x43\x8d\xea\x19\xfe\xc1\x1a\xcd\xcc\
-\x7f\x01\x4c\x00\xb2\xb3\x17\x00\xae\xee\x6a\x70\x95\x81\xaf\x23\
-\x79\x36\xbe\x1d\x5f\x09\x40\x09\xd8\x79\x18\xfb\x19\x41\xd6\x8c\
-\x2b\xc9\xbf\xee\x7d\x0a\x98\xdd\xbb\x78\x98\xfa\x2d\x9b\xc4\xc4\
-\x0b\x86\xc5\x85\x73\x40\x75\x70\x2f\x3b\x67\x8a\xb0\x0d\x37\x30\
-\x48\xa7\x1d\x42\x23\x76\x98\x46\x46\x45\x3c\xe6\x4d\x18\xa7\xee\
-\xdd\xfe\x3f\x7d\xfd\x48\xb2\x39\x33\x89\xee\x8b\xa4\x44\xf3\x0e\
-\xe0\xd4\xc7\x0f\x13\xe9\x2d\xb8\xe7\xbc\x74\x7b\x0b\xb4\xe1\xa6\
-\xc6\x27\xc4\x95\xa6\x91\xb1\xb0\x15\x14\x00\x49\xa2\xdb\xb8\xc6\
-\xd1\xe0\x91\x5d\x39\x46\x4a\x1e\x4f\xb7\xfa\xd1\x02\x01\x97\x52\
-\x1c\x78\xbc\xa4\x13\xe7\xb6\x50\xa9\xfa\xb1\x66\xb4\xd5\x2f\xb6\
-\x8c\xee\x36\x7a\xfd\x4a\xbc\x82\xc1\xb3\x11\xe5\xf1\xd9\xcc\x1f\
-\x4a\x6e\x46\x37\xb8\x16\x02\xc6\xb6\x31\xd9\xec\xb0\x4f\xd7\xaa\
-\xfc\xb7\x72\xb4\x28\x07\xf6\x1f\x16\xfa\x0f\xed\x53\xfe\x01\xbb\
-\x9a\xe3\xdc\x27\xf4\x16\x65\x00\x00\x00\x00\x49\x45\x4e\x44\xae\
-\x42\x60\x82\
-\x00\x00\x00\xd7\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x16\x00\x00\x00\x16\x08\x06\x00\x00\x00\xc4\xb4\x6c\x3b\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\x89\x49\x44\x41\x54\x38\x8d\xed\
-\x95\xcb\x0d\x80\x20\x10\x44\xdf\x1a\xee\x5a\x02\x1d\x48\x09\xda\
-\x81\x2d\x59\x99\xad\x58\x82\x1d\xe0\x41\x34\xc6\x60\x5c\x42\x38\
-\x90\x38\x09\x59\x0e\xb3\xc3\xf0\xdb\x15\xef\x3d\x99\x70\x40\x77\
-\x8b\x03\x80\x51\x24\x5a\x60\x03\xa6\x30\x3f\x87\x03\xda\xb7\x24\
-\x09\x8e\x87\xc7\xaa\x67\xec\x03\x6f\x04\x16\xfd\x26\x0e\xc7\xd9\
-\x67\x11\x43\x53\x42\xf4\x17\xae\x5c\xd8\x00\xb3\x82\xb7\x2a\x79\
-\x17\x8a\x39\x16\xaf\x2b\x16\xc9\x3f\xaf\xbe\xcb\xfb\x85\xcb\x0b\
-\x1b\x40\xf8\x2e\xf4\xc9\x10\xc5\x33\xb6\x64\xb4\xa6\x1c\x44\x9b\
-\xe9\x0e\x31\x4a\x1c\x7e\x07\x76\xe6\xd6\x00\x00\x00\x00\x49\x45\
-\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x01\x2c\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x11\x08\x06\x00\x00\x00\xd4\xaf\x2c\xc4\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\xde\x49\x44\x41\x54\x38\x8d\xa5\
-\x93\x51\x11\x84\x30\x0c\x44\x97\x1b\x04\x20\x01\x07\x87\x84\x93\
-\x80\x04\x24\x20\x01\x09\x48\xa8\x04\x24\x20\xa1\x38\x40\x02\x0e\
-\xde\x7d\x90\xce\xe4\x0a\xc7\x07\xec\x4c\x06\xda\xdd\xa4\x5b\x12\
-\x04\x08\x68\x81\xc8\x8e\x15\x18\x80\xca\x38\xd9\xfb\x60\x1c\xa6\
-\x6d\x01\xa5\xe4\x33\xcc\xae\xc0\xfc\x47\xd3\xca\x55\x9d\x80\x0f\
-\xd0\x7b\x41\x76\x40\x6f\x9a\x29\xb9\x95\x23\xbd\xe5\x24\x18\x2c\
-\x00\x42\x76\x25\xb0\x45\x00\x3a\x47\x0a\x68\xcc\x76\x65\x31\xdb\
-\x9e\xd7\x74\x40\x28\x00\x3d\xc1\xeb\x51\xb6\xa4\xd2\x9e\xbd\xa4\
-\xea\x46\xfe\x58\x00\x51\xd2\xfb\xa6\x81\xa5\xe0\xe1\x47\x28\x25\
-\x2d\xce\xc1\xa2\xfd\x3a\x57\x18\x7f\xf4\xd6\x0e\x8f\x90\xb5\xcb\
-\x47\xc8\xb4\x5d\x22\x62\x46\x4c\x59\xdf\x1b\x37\x5c\x09\x11\xfb\
-\x17\x04\xd4\xc0\xc6\x11\xdb\xc5\x7e\xed\x0b\xa4\x22\xb9\x93\x33\
-\xc4\x94\x9c\x17\xf0\x23\xba\x9e\x24\xae\x1c\x47\x5e\x57\xa3\x5c\
-\x5b\x48\xd2\x6a\x71\xc0\x17\x11\x38\x4c\x49\xd7\xf0\x47\xa6\x00\
-\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x01\x48\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x14\x00\x00\x00\x17\x08\x06\x00\x00\x00\x0b\x1d\x6f\xa3\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\xfa\x49\x44\x41\x54\x38\x8d\xe5\
-\x95\x5b\x11\x83\x30\x10\x45\xef\x30\x15\x80\x84\x4a\x40\x02\x12\
-\x2a\x01\x27\x45\x02\x55\x50\xea\x24\x75\x10\x1c\x20\x01\x07\xb7\
-\x1f\x6c\x12\x08\x79\x94\x4c\xff\x7a\x67\x32\x21\xd9\xec\x99\xdd\
-\x3c\x16\x90\x44\xa0\x0d\x24\xbb\x88\x0d\x62\x1b\x42\xb6\x0b\xc2\
-\xd2\x00\x9e\x00\xae\x32\x6e\xa5\x57\xd2\xdf\x01\x3c\x82\x9e\x91\
-\x08\x1a\x92\x0b\xe3\x5a\x64\xcd\xc1\xb7\x04\x96\x84\x86\x80\x7a\
-\xe3\xd4\x91\x9c\x37\xe3\x59\xe6\x8c\x74\x0e\xd8\x7c\x11\x99\xaf\
-\x96\x99\x43\x79\x47\x0e\x2a\xa6\x65\x3b\x30\xc0\x0e\xc0\x28\x46\
-\x85\x73\x32\xc0\x95\x41\x72\x94\xd0\x47\x09\xbf\x24\x65\xcb\x40\
-\xc0\x58\x02\xb4\xaa\x4e\xa6\x97\xd5\x9f\x02\x27\xf9\x9e\x52\x0b\
-\x33\xb2\x8c\x0a\x6b\x25\x79\xc1\x55\x94\x12\x39\x06\xf7\x4f\xaf\
-\xf4\xda\x58\x86\xbf\x87\x1a\xe7\x52\x9f\xc4\xc7\x89\xc7\x6a\x53\
-\x93\xec\xb9\xaf\x32\x23\xdd\x6b\xa0\xd8\x7a\x59\x9b\x2d\x5f\xa6\
-\x29\x2f\xad\xed\x76\xa8\x98\xdf\xcf\xaf\x4d\x2a\x42\x53\x48\xb5\
-\xa4\x56\xd3\x15\xdf\xe8\x0f\x2c\x05\x04\xc9\x9b\xb7\x4f\xb5\xcc\
-\x45\x7d\x3e\x00\x96\x4e\x2c\x38\xa6\x25\x5f\x00\x00\x00\x00\x49\
-\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x01\x43\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\xf5\x49\x44\x41\x54\x38\x8d\x9d\
-\x93\xc1\x95\xc2\x30\x0c\x44\xff\xe3\x71\x87\x12\xd2\x01\x94\x90\
-\x12\x28\xc1\x25\x50\x42\x3a\x58\x4a\x48\x09\x94\x90\x12\x5c\x02\
-\xdb\x81\x3b\x98\x3d\x44\x62\x15\x61\x38\x30\xef\xf9\x10\x6b\x34\
-\x1a\x29\x32\x92\x48\xa7\x48\x5a\xf4\x8a\xc5\x62\x1b\x7e\xfc\x18\
-\x24\xd5\x94\x34\x4a\xba\x48\x9a\xc3\x5d\x35\xee\x46\x60\x90\xd4\
-\x12\x29\x8a\x8f\x26\xe2\x05\x9a\x8b\x38\x21\x57\x9e\xdf\xb4\xe6\
-\xc9\xcd\x8b\xc4\x80\x07\x17\x49\xe7\x94\xec\x0e\x27\x3b\x57\xe3\
-\x97\x3d\x50\x58\xf1\x0b\x9c\x81\xc6\x2b\x1e\xc0\x0d\x18\x81\x0a\
-\x1c\xed\xbe\x10\x2c\xe7\xaa\xd9\x41\x17\x2e\xf0\x90\x74\xfc\x20\
-\x90\x67\xf4\xc4\xce\xac\xdc\x81\x19\xb8\x06\x7b\x11\x43\xe7\x6e\
-\x85\x09\x4d\x41\xb4\x76\xda\x29\x36\xc4\xbb\xb6\xbf\x5b\xd8\xd4\
-\x6b\x0a\x34\x9b\x74\xaf\x9d\x5b\xe0\x2d\x3b\xb3\x7e\x4a\xd3\x3f\
-\x00\x3f\xe1\x0f\x45\x44\xde\xfc\x69\x48\xed\x8d\x03\xdf\x81\xe7\
-\x22\xf5\x56\x59\x5a\xd7\x37\x27\x5f\xf4\xbf\x89\x9b\x55\xce\x8f\
-\xa9\x59\xaf\xc5\x84\xa6\x10\xeb\x3e\xa6\xaf\x9f\xf3\x1f\x31\xf3\
-\xe0\x1c\x64\xba\x73\xcb\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
-\x60\x82\
-\x00\x00\x01\x53\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x17\x00\x00\x00\x17\x08\x06\x00\x00\x00\xe0\x2a\xd4\xa0\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x01\x05\x49\x44\x41\x54\x48\x89\xd5\
-\x94\xcd\x11\x82\x30\x10\x46\x9f\x0e\x77\xed\xc0\x74\x20\x1d\x88\
-\x95\x88\x1d\x68\x07\x5a\x81\x76\xa0\x25\xd8\x81\xd0\x01\x25\x40\
-\x07\x58\x01\x1e\x12\x34\x66\xb2\x40\x06\x2e\x7e\x33\xcc\xc0\xfe\
-\x3c\x92\xcd\x66\x67\x4d\xd3\x00\x28\x20\x65\x5a\x95\x33\x03\x4f\
-\x80\xe7\xc4\xf0\x7c\x3e\x31\xf0\x47\xff\x0b\x8f\x3c\xb6\x23\x50\
-\x8c\x60\x5e\x81\xb5\x04\x2f\x80\x4c\x48\x8c\x81\xa5\xe0\xab\x4d\
-\x6e\xdd\x1a\x7c\x70\x49\x29\x70\xeb\xf0\xe7\xe8\xae\xfb\xa8\x85\
-\x17\xc0\xd6\x7a\x0f\x05\x7b\x15\xd1\xdf\xe3\x67\xe0\x61\xfd\x1c\
-\x74\x79\x2e\x43\xe0\x43\x64\xef\x26\x06\x4e\x43\x92\x42\x5b\x31\
-\x46\x1f\xf6\xc2\x7c\xbf\x80\x4a\x0a\xb6\x57\x5e\x01\xa5\x27\xa6\
-\xb5\xf9\xc0\x09\xba\xf5\x56\x7d\xf0\x3b\xf2\x76\x95\x00\xee\xbc\
-\x0f\x43\xcb\x52\xa2\x0f\xb5\x0b\x7c\x77\x93\x42\xfb\xbc\x36\x10\
-\x17\xbc\x1f\x0b\x07\x38\x08\xb6\x02\x68\x5c\xc7\x98\xc1\x95\xa2\
-\xcf\x21\x96\x02\x42\x57\x6e\x4b\x01\x1b\xbe\x73\xe8\xec\xf8\xcb\
-\x31\x70\x57\x27\xd7\x60\xc3\x15\xce\xe0\xe9\x91\xea\x0b\xb0\xe1\
-\x3b\xf3\x4c\xa6\x08\xdd\xc3\x6e\xbd\x42\x94\x49\x8e\x37\xb4\xef\
-\x38\x26\x14\x66\x94\xae\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
-\x60\x82\
-\x00\x00\x01\x00\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x18\x00\x00\x00\x0d\x08\x06\x00\x00\x00\xb3\x6c\xae\xd0\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\xb2\x49\x44\x41\x54\x38\x8d\xb5\
-\x91\x31\x0a\xc2\x40\x10\x45\x9f\xd6\x16\xde\x20\x85\x07\xd0\x03\
-\x78\x82\x74\x82\x07\xb1\xb4\x10\x6c\x3d\x86\xc7\xd0\x5e\xfb\xb4\
-\x42\x40\xcf\xa0\x58\x3f\x1b\x37\x89\x42\xe2\x2a\xeb\x83\x29\x96\
-\x61\xdf\x9f\x61\x50\xf9\x50\x1b\xb5\xb4\xa6\x54\xb7\x6a\x16\xf1\
-\x97\xae\x66\xa6\x16\xb6\x73\x8a\x09\xe9\x6a\xee\x3a\xe4\xcd\x6d\
-\xc2\x30\x0b\x75\x1a\x13\x90\xa9\xab\x08\x79\xe0\xfc\xf6\x2e\xd4\
-\xbc\x2d\x20\x57\x6f\x5f\xc8\xdb\xb8\x86\x90\xf7\xc9\x53\xc8\x03\
-\x85\x4a\x9f\x9a\x19\x30\x20\x1d\x63\xa0\x0a\xc8\x80\x79\x42\x79\
-\x45\x4f\x05\x28\x81\xd1\x3f\xfc\x61\x83\x7f\xc8\x8f\xc0\xcb\x0d\
-\x52\x72\x03\x96\xcd\x80\x35\x70\x4f\x24\xdf\x03\x39\x70\x80\xfa\
-\x06\x81\x09\x30\xfc\x51\x7c\x79\xd6\x0b\x0f\x8c\x7b\x0a\xf7\x65\
-\x9e\x9b\xb0\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x01\xbe\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x16\x00\x00\x00\x17\x08\x06\x00\x00\x00\x0f\xe8\xbf\x9e\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x01\x70\x49\x44\x41\x54\x38\x8d\xa5\
-\x95\xed\x71\xc2\x30\x0c\x86\x1f\x38\xfe\x37\x9d\x00\x6f\x50\x6f\
-\x40\x36\x68\x46\x60\x04\x36\x28\x6c\x10\x36\xe8\x06\xb4\x1b\xc0\
-\x06\x61\x83\xb0\x01\x4c\xa0\xfe\x88\x5c\x8b\xc4\x26\x7c\xbc\x77\
-\x3a\xe7\xf4\xf1\x46\x96\x25\x1b\x11\x21\x21\x2b\x11\xf1\x19\x9b\
-\x15\xaf\xbe\x03\x5b\xca\xb9\x96\x0e\xe7\x11\x72\xaf\x3e\xa2\x31\
-\x57\xf6\x29\x43\x34\xba\xbe\x01\x3e\x61\x0f\xa8\xd4\xc7\xc6\x44\
-\x64\xb2\x29\x45\xa4\xd5\x8c\x9c\xc9\xd0\xf7\xb2\x6d\xd4\xf7\xae\
-\x52\xf4\xb7\xda\xca\x10\x41\x5f\xe4\xe2\x53\xa5\x08\xf0\xba\xd5\
-\x79\xc2\x16\xf4\x55\x36\x3a\xf3\xc7\x2a\x91\x65\x0e\x55\xae\x14\
-\x4e\x8d\x76\x5b\xcd\x03\xc4\x8d\x89\x2b\x94\xcb\x4d\x44\xa4\x35\
-\xdb\xfd\xd5\x13\x0e\xe2\x8c\x58\xb4\x46\xbc\x91\x4f\xb5\x9f\x26\
-\x22\x52\x02\x6b\x60\x91\xa8\xd4\x85\xd8\x4a\xdf\xba\x2e\x7b\x67\
-\xd0\xc7\x01\x58\xdb\xba\x38\x89\xc3\x91\xc2\x5a\x25\x87\x5a\x62\
-\x6b\x5e\x75\x45\x0b\xec\x13\x19\xdc\x8b\xbd\x72\x00\x30\x03\x6a\
-\xe2\x84\xb9\x17\x88\x6b\x60\xa5\xdf\xcd\x0c\x28\x81\x8f\x17\x08\
-\x03\xe6\xc4\x26\x28\x02\x71\xc8\xb8\x04\xbe\x9e\x24\xde\x10\x4b\
-\xd9\xcc\x80\xb3\x51\x14\x4f\x92\x42\xd7\x3d\x81\xe7\xff\xf0\x2a\
-\x55\xee\x5e\x20\xde\x29\x47\x15\x88\x6b\x55\x86\x3e\x3e\x3d\x41\
-\x1a\x62\x16\xca\x55\x4f\xe9\x5a\xe4\x40\x57\xa3\x77\xe2\x00\x3c\
-\x82\xa5\xc6\x6e\x94\xab\xcd\x5d\x42\xa9\x41\xc9\x0d\xc8\xe0\xf5\
-\xe8\x0f\x88\xc5\x0a\x38\xde\x91\xe9\x91\xd8\xbb\x57\x18\xbb\x8f\
-\xb7\x37\xec\x5b\x6e\x3c\x5d\x13\x11\x19\xcb\xca\xd1\x9d\x74\xb8\
-\x8c\x3c\xf0\x83\x19\xdf\x14\xfe\x00\x23\xaf\x8c\xd8\x26\xf0\x9e\
-\xec\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x00\x8a\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\x3c\x49\x44\x41\x54\x38\x8d\x63\
-\xfc\xff\xff\x3f\x03\x89\x00\x45\x03\x13\xa9\xba\xd1\xc1\xc0\x1b\
-\xc0\x42\x86\x1e\x46\xba\xb9\x00\x3d\x7a\x18\xb1\x89\x0f\x7c\x20\
-\xd2\x34\x0c\x18\x89\x11\xa7\x8a\x0b\x88\x0a\x6d\x5c\xe2\x03\x1f\
-\x88\x14\x1b\x00\x00\xca\xe1\x09\x25\x2c\x11\x70\x5b\x00\x00\x00\
-\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x00\x82\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x16\x00\x00\x00\x0e\x08\x06\x00\x00\x00\x2b\x31\xec\xcd\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\x34\x49\x44\x41\x54\x38\x8d\xed\
-\xd2\xc1\x09\x00\x30\x0c\xc3\xc0\x4b\xc9\xfe\x2b\xa7\xbf\x6e\xe0\
-\x47\x21\x1a\x40\x18\xac\x9a\x99\x11\xe0\x24\xa4\xd0\xa8\x84\x38\
-\xb6\xf8\x3f\x71\x63\xab\xc0\x8f\xe7\x6d\x15\x8f\x0b\x2d\x2d\x06\
-\x20\x93\x05\xe7\x76\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\
-\x82\
-\x00\x00\x01\x59\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x16\x00\x00\x00\x17\x08\x06\x00\x00\x00\x0f\xe8\xbf\x9e\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x01\x0b\x49\x44\x41\x54\x38\x8d\xd5\
-\x94\xd1\x4d\xc3\x30\x10\x40\x1f\x28\xff\x64\x84\x6e\x40\x36\xc0\
-\x1b\x94\x11\xca\x06\xb0\x41\x3a\x01\x23\xd0\x0d\xe8\x06\x75\x37\
-\xc8\x08\x19\x21\x4c\x70\xfd\xe0\x1c\x8c\x7b\x71\x92\x36\xaa\xd4\
-\x27\x59\xb6\x4e\xf2\xb3\xe3\xbb\xdc\x83\x88\x6c\x80\x15\xcb\xd1\
-\x02\x3b\x44\xc4\xcb\xb2\x78\x11\xe1\x71\xc1\x9b\xfe\xe3\xfe\xc4\
-\x45\xb4\xfe\x00\x9a\x2b\x5c\x15\xf0\x69\x89\x1b\xc0\xeb\xba\xe4\
-\xb7\x52\xe2\x83\x6a\x42\xc6\x27\x50\x18\xb1\x52\x0f\x58\x01\x2e\
-\x91\x7f\xe9\x6c\xc9\x5b\x60\xab\x33\x71\xb9\x39\x11\x49\xcb\xaf\
-\x13\x91\x4a\xe3\x75\x14\x0f\xb1\xc1\x61\x25\xef\x1d\xf8\xd1\xf5\
-\x93\xde\xbe\x32\xbe\xca\x01\x32\x30\xbc\x25\x6e\x74\xd3\x98\x3c\
-\xcb\x50\xb9\x59\xf2\xf5\x1c\xb1\x95\xbc\x54\xee\x55\x9c\xd2\x01\
-\xc7\x24\x56\x02\xcf\x96\xf8\x15\xf8\x9e\x78\xa9\x70\x70\x8c\x03\
-\x0e\x70\xfe\x14\x7b\xe0\x6d\xa2\x38\x8b\xf5\x14\x3b\x9d\x37\x99\
-\x7d\xdd\xa8\xd9\x68\x9b\xf5\x58\x8d\x66\x86\x0b\xad\x33\xd7\x84\
-\x3c\x7f\xbf\xf8\x6c\x0a\xce\x13\x10\x78\xb9\x54\x0a\x37\x6a\x9b\
-\x43\xb8\x19\xbe\xfe\xef\x9c\x22\x3e\xcc\x10\xf7\xe4\xc4\xdb\x4b\
-\x84\x4a\x7b\x02\x14\x24\x16\xfc\xe9\xbe\xfb\x74\x00\x00\x00\x00\
-\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x01\x1f\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x10\x00\x00\x00\x11\x08\x06\x00\x00\x00\xd4\xaf\x2c\xc4\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\xd1\x49\x44\x41\x54\x38\x8d\x9d\
-\x92\x5b\x11\x84\x30\x0c\x45\xef\xa2\x00\x09\x95\x80\x14\x24\x20\
-\x61\x25\x20\x61\x25\xb0\x0e\x90\x80\x84\xe2\xa0\x12\x70\x70\xf6\
-\x83\x76\x26\xb4\xe5\x31\x7b\x66\xf2\x13\x72\x6f\x12\x52\x01\x02\
-\x5a\x60\x66\xc7\x03\x5d\xcc\xdb\xe8\x80\x10\x6b\xe6\xa8\x51\xfa\
-\x38\x72\xc4\x57\x0c\x7c\x56\xf3\xb1\x06\x0b\x25\xb9\x41\xce\x02\
-\xa8\xd1\xce\xa4\x23\x5f\x95\xe4\xb9\x5d\x63\x3a\x0c\x71\xb7\x31\
-\xed\x97\x45\x0b\xbc\x63\xe7\x21\xe5\x5f\x40\xa5\xd9\x73\x9a\xfb\
-\x92\x7b\x83\x56\xd2\xf8\x87\x76\x94\xd4\xda\xf3\x2c\x95\xbd\xcf\
-\x22\x5d\xcd\xe7\xe7\xe9\x1f\x88\x7b\x2b\x68\x24\xad\x66\xac\xe1\
-\xc1\xe8\xb6\x66\x4d\xe7\xb3\x0c\x17\xdd\x8b\xda\xb3\x67\x3a\x01\
-\xce\x08\x5d\xcc\x59\x3c\xe6\x29\x3b\x60\xa3\x64\xbb\xc8\x3b\x6b\
-\x90\x4c\xf2\x49\x6a\x78\x3b\xdd\xd9\x9e\xa1\x22\x0c\x54\xfe\xcf\
-\xd5\x53\x76\x31\x24\x29\xc4\x28\xf8\x01\x73\x68\x6f\x9f\x1b\x28\
-\x77\x21\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x01\xe2\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x1c\x00\x00\x00\x21\x08\x06\x00\x00\x00\xca\xe9\xcb\xe7\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x01\x94\x49\x44\x41\x54\x48\x89\xcd\
-\x96\xd1\x71\x83\x30\x10\x44\x97\x4c\xfe\x4d\x07\xa1\x03\x2b\x1d\
-\x50\x82\x4b\x70\x09\x2e\x81\x12\x9c\x0e\x52\x02\x25\xd0\x41\x48\
-\x07\xd0\x01\xae\xe0\xf2\x21\xc9\x3e\x1f\x02\xdd\x61\x3e\xb2\x33\
-\x9a\x61\x40\xec\x43\xba\x45\x52\x41\x44\x30\xca\x01\x28\xc3\xf5\
-\x04\xa0\x37\xbd\x4d\x44\xda\x76\x22\xa2\x81\xe6\x1a\xc2\x33\x95\
-\x8f\x16\x76\x4e\x80\xa4\xce\x7b\x01\x9d\x02\x16\xe5\xf6\x00\xb6\
-\x06\x60\x9b\xf3\x2b\x28\x1f\x9a\x09\xc0\x41\x19\x89\x1b\x0b\x54\
-\x52\x1a\xa0\x35\xc6\xc5\xda\xc3\x37\xa3\xd9\xcb\xd2\x00\x7f\x0d\
-\x7e\xd9\xbe\x1a\xe0\xd5\x00\xcc\xf7\xd5\xfc\x3b\x44\xd4\x29\x12\
-\xda\x69\xbc\xb4\xc0\x32\xf3\x7b\xb4\xa1\x4f\xd6\x4b\x93\x52\xae\
-\x1a\xc0\x09\x7e\x3d\x05\xfc\x3a\xda\x02\xe8\xb4\x06\x56\xe0\xcb\
-\xfa\x57\xbf\x85\x83\x9f\x2a\x32\xb6\x0e\x8f\x29\x9f\x6b\xa1\xb8\
-\x9a\xdd\x21\xa7\xe4\xee\x91\xaa\xa1\x03\xf0\x63\x9f\xac\xa4\x3e\
-\x21\x36\xe8\x14\x70\x00\xf0\xb1\x13\x70\x04\x50\xf1\x1b\xb2\x86\
-\xcd\x8e\x30\x04\xaf\x86\xdf\x90\x23\xb4\x6c\x45\x5a\x3d\x6d\x59\
-\x7c\x84\xe7\x04\x6c\xdc\x00\x90\xef\x1c\x82\xb7\x17\x4b\x50\xbf\
-\x90\xb4\x2d\xe9\x94\xea\x23\x87\x8f\xf0\x28\xbe\xec\x0b\x3e\x40\
-\x56\x0d\xe1\x5d\xae\xbb\x77\x04\xd6\xa2\xc3\x08\x51\x6c\xa3\x1a\
-\xcc\xa7\xb6\xe6\x40\xb9\x32\x5c\xe1\x03\xb4\x55\x13\xe6\x7b\xa3\
-\x5b\x03\xda\x4e\xd3\x69\x49\x8f\x55\x60\xb7\x03\x50\x7a\x3c\x01\
-\x79\x60\x46\xd9\xc9\xa8\x7a\xc1\xeb\x18\x81\x25\x7c\xaa\xe2\xc3\
-\x81\x75\x5a\x3d\x63\x2a\x14\xbd\xc6\xc0\x28\xdf\xe1\x0b\x7c\x09\
-\xcd\x61\xdb\xa8\x96\xf4\x1d\x7c\x1f\xf5\x4c\x6d\x21\xac\x39\xd2\
-\x1d\xa0\xb8\x2e\x6b\x9e\xda\x23\x46\x05\x5f\x9b\x3a\x5c\x57\xf0\
-\x0b\xf3\x2d\x7c\xfd\x04\x1f\x92\x0e\x99\x84\xff\x01\x0d\xfe\xb6\
-\xf5\x24\x16\xd3\x1d\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\
-\x82\
-\x00\x00\x01\x41\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x11\x00\x00\x00\x11\x08\x06\x00\x00\x00\x3b\x6d\x47\xfa\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\xf3\x49\x44\x41\x54\x38\x8d\xa5\
-\x93\x61\x71\xc3\x30\x0c\x85\xbf\x15\x81\x21\x8c\xc1\x5a\x06\x81\
-\x30\x08\x29\x83\x42\x18\x84\x96\x41\xc3\xc0\x10\xc2\x60\x81\x10\
-\x08\x19\x82\xd7\x1f\x79\xbe\xba\xa9\x13\xdf\x65\xba\xd3\x9d\xa3\
-\x24\x4f\xd2\x27\x19\x49\xec\xf4\x8b\xa4\x20\x89\xbd\x02\x77\xcd\
-\x36\x48\x0a\x1f\x92\xa8\x58\x6b\x1f\xed\xdf\xc0\x57\xf6\xbe\xab\
-\x65\x6c\xb5\x6d\x51\x52\xf8\x8f\xc0\x54\x63\xf2\x59\x11\x90\xb9\
-\x20\x89\x43\x81\xc1\x11\x88\x35\x50\x40\x48\x87\xa5\x48\x0b\xf4\
-\xc0\x00\x9c\x81\x0e\xf8\xab\x89\xa4\xf2\x83\xcb\x9b\x24\x35\x59\
-\x4b\x77\x8f\x71\x2a\xb4\x73\x4d\xed\x20\xe9\xe8\x0f\x07\xff\x98\
-\x73\x89\x9a\x97\xaa\x5f\xe3\x91\x98\x84\x6c\xee\x97\xac\xdc\x06\
-\xf8\xf1\xb9\xcf\xe2\x9d\xdb\x7e\x9a\xd5\xae\x8b\x2c\x8d\x5e\xa7\
-\x15\x25\x8d\xae\xfa\x6d\x9a\x69\x63\x83\xb3\xa5\x8a\x6e\x86\x3b\
-\x31\x6f\xe9\x2f\x70\x72\xec\xdd\x32\xc5\x60\x2e\x4b\x78\xa3\xb9\
-\xac\x2e\xe6\x32\x50\x12\x8a\x5b\x02\x25\x91\x24\x94\x18\x8d\x7e\
-\xde\x14\xd9\xba\xc5\x8d\x99\x94\x39\x64\xf6\x00\x46\x15\x8a\x4a\
-\xba\xc1\x6e\x07\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\
-\x00\x00\x00\x81\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x05\x00\x00\x00\x05\x08\x06\x00\x00\x00\x8d\x6f\x26\xe5\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\x33\x49\x44\x41\x54\x08\x99\x6d\
-\xcc\x31\x11\x00\x20\x0c\xc0\xc0\x14\x03\x58\x42\x02\xfe\x55\xb4\
-\x0a\xc2\xc0\xc0\x5d\x8f\x1f\x33\x04\x75\xab\xe9\x95\xea\x0a\x35\
-\x81\xc9\x53\xa1\x4a\x33\x80\x6a\xad\xf8\x3d\x0f\x3b\x32\x2f\x90\
-\x20\xa9\xf6\xb4\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\
-\x00\x00\x00\x9d\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x06\x00\x00\x00\x06\x08\x06\x00\x00\x00\xe0\xcc\xef\x48\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\x4f\x49\x44\x41\x54\x08\x99\x63\
-\xfc\xff\xff\x3f\x03\xe3\x84\xe9\x0e\x0c\x0c\x0c\x0e\x0c\x10\xb0\
-\xe1\x7f\x41\xe6\x05\x46\x86\xfe\x69\x06\x0c\x0c\x0c\xe7\x19\x50\
-\x81\x21\x13\x03\x03\x43\x00\x03\x26\x28\x60\xc2\x22\xc8\xc0\xc0\
-\xc0\xf0\x80\x89\x81\x81\xe1\x00\x16\x89\x0d\x8c\x50\xcb\x0d\x90\
-\x8c\xdc\xf0\xbf\x20\xf3\x02\x00\x77\x2e\x15\x69\x52\xa1\x49\x43\
-\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x00\xdc\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x0e\x00\x00\x00\x10\x08\x06\x00\x00\x00\x26\x94\x4e\x3a\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x00\x8e\x49\x44\x41\x54\x28\x91\xcd\
-\xd2\x41\x0d\xc2\x30\x14\x06\xe0\x2f\x84\xfb\x24\x80\x04\x1c\x30\
-\x09\x38\x00\x0b\x28\x60\x73\x30\x09\x48\x00\x07\xc3\x01\x38\x00\
-\x09\x28\x78\x1c\xd6\x25\x70\x60\x4b\x17\x0e\xfc\x49\xd3\x34\x79\
-\x5f\x5f\xdb\x54\x44\xb4\x11\x51\x45\x5e\xda\x99\x89\xf9\x39\x7c\
-\x4e\x85\x25\xf6\xb9\xf0\x82\x2b\x1a\x3c\x72\x3b\x4a\x70\x91\x03\
-\xd7\x58\xe2\x3e\xb0\xe9\xd7\x8e\x55\xea\x78\xce\x85\x5b\x6c\xb0\
-\xd3\xdd\xb9\xc6\xed\xbd\x60\x3e\x70\x9a\xa3\xee\x75\xcb\xb4\x3e\
-\xa1\x45\x31\x06\x8b\x54\xd8\xa4\x79\xd5\xa3\x31\xd8\xe3\x43\x1a\
-\x1f\xf9\x9f\xbf\x3a\x9a\x17\x31\xca\x48\x6f\x06\xea\xd0\xa2\x00\
-\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x0c\x7e\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\xc2\x00\x00\x00\x9e\x08\x06\x00\x00\x00\x60\xad\xd5\xbd\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x0c\x30\x49\x44\x41\x54\x78\x9c\xed\
-\x9d\xed\x71\xdb\x48\x12\x86\x1f\x6f\xed\x7f\xf1\x22\x30\x36\x02\
-\xf1\x22\x58\x38\x02\xeb\x22\x10\x36\x02\xf3\x22\x30\x37\x82\xb3\
-\x23\x30\x15\xc1\xd1\x11\x2c\x14\xc1\x8a\x11\x2c\x14\xc1\x8a\x11\
-\x68\x7f\x34\x60\xc2\x34\x08\x02\x24\x30\xd3\x0d\xf4\x53\x85\x52\
-\x49\xa4\x38\x4d\x60\xde\xe9\xf9\xec\x7e\xf3\xfa\xfa\xca\x44\x59\
-\x02\x49\xf9\xb3\xfa\x7d\x71\xf4\x9e\xa2\x76\x3d\x95\xd7\x9c\x58\
-\x20\xf7\x25\x2d\x7f\x6f\xbb\x47\x00\xf9\xd1\xef\x93\xe1\xcd\x84\
-\x84\x90\x00\x77\xe5\xf5\xeb\x15\x9f\xf3\x15\xd8\x96\xd7\xcb\xf5\
-\x66\xa9\x23\x41\xee\x51\x06\xdc\x5e\xf8\x19\x7b\xe4\xfe\xe4\x4c\
-\xe4\x3e\x4d\x41\x08\x29\xb0\xe6\xba\xca\xdf\xc4\x1e\xf8\x54\x5e\
-\xe6\x1f\x34\x72\x9f\x56\xc0\xfb\x81\x3f\xb7\x12\xc5\x1a\xc3\x9e\
-\xc2\xb2\x10\x96\x48\x25\x1d\x5a\x00\xc7\xec\x91\x87\xfc\x69\xe4\
-\x72\xc6\x62\x81\xd8\x7e\x1f\xa0\xac\x07\x44\x6c\xe6\x1a\x0e\xab\
-\x42\x58\x03\x1f\x03\x97\xf9\x88\x74\x29\x2c\x3d\xe4\x14\x69\xad\
-\x6f\x02\x96\xb9\x47\xee\x53\x1e\xb0\xcc\xab\xb1\x28\x84\x0d\x61\
-\x5a\xb7\x26\xf6\x48\xe5\xb2\x30\xa8\xce\x80\x2f\x11\xcb\xff\x0d\
-\x79\x56\x26\xf8\x29\xb6\x01\x3d\xd9\x10\x4f\x04\x20\x2d\x6b\xce\
-\x61\x26\x4a\x2b\x19\x71\x45\x40\x59\x7e\x16\xd9\x86\xce\x58\xf2\
-\x08\x9f\x80\x0f\xb1\x8d\x28\xd9\x23\xb3\x2f\x1a\xbb\x49\x19\xf1\
-\x45\x50\xe7\x1d\x06\xba\x49\x56\x84\x70\x07\xfc\x3f\xb6\x11\x47\
-\xec\xd0\xe7\x19\x96\x48\xa5\x0b\x39\x26\x38\xc7\x33\x62\x97\xc6\
-\x46\xe3\x1b\x16\xba\x46\xd5\xac\x87\x36\x6e\x91\x41\xbb\x26\x36\
-\xe8\x12\x01\xc0\x5b\xf4\xdd\xa7\x1f\xb0\x20\x84\x15\x72\x33\x35\
-\xf2\x11\xe9\x22\x69\x60\xc5\xe5\x0b\x64\x63\xf3\x01\x3d\xf7\xa9\
-\x11\x0b\x5d\xa3\x17\xf4\xb5\x72\x75\x1e\x88\x3f\x28\x5c\x20\x8b\
-\x59\x7e\x9f\x2e\x44\xbb\x47\xc8\xd0\xfd\x70\x41\x66\xb1\x92\xc8\
-\x36\xac\xd0\x7f\x9f\xee\xf8\x71\x1f\x93\x1a\xb4\x0b\xe1\x2e\xb6\
-\x01\x1d\x59\x47\x2e\x7f\x15\xb9\xfc\x2e\xdc\xa0\xf8\x79\x6a\x17\
-\xc2\xd0\xfb\x62\xc6\x22\x66\x6b\x97\xa1\xdf\x1b\x54\xa4\xb1\x0d\
-\x38\x85\x66\x21\xa4\xb1\x0d\xe8\x41\xcc\xd6\x4e\x6d\x2b\xdb\x80\
-\x5a\x5b\x5d\x08\xc3\x11\xe3\x21\x2f\xb0\xe3\x35\x41\x1a\x8c\x24\
-\xb6\x11\x4d\x68\x16\x82\xb6\xc5\xaa\x73\xc4\xa8\x90\x69\x84\x32\
-\xaf\x45\xe5\x73\xd5\x2c\x04\xb5\x33\x0c\x2d\xa4\x13\x2f\x6f\x08\
-\x5c\x08\x3d\x19\xfb\x9c\xc1\x18\x84\x7e\xc8\x2a\x2b\xd5\x19\x54\
-\x36\x70\x9a\x85\x60\x91\x34\x70\x79\xde\x58\x0c\x84\x0b\x61\x58\
-\x42\xb6\x76\x2a\x2b\x94\x55\xb4\x0a\xc1\xea\x43\x0e\xd9\x42\xab\
-\xec\x62\x58\x45\xab\x10\xfc\x21\x9f\xc7\x6a\x63\xa1\x12\xad\x42\
-\xb0\x4c\x1a\xa8\x1c\x6f\x2c\x06\xc4\x85\xe0\x38\xe8\x15\x42\x1e\
-\xdb\x00\x03\xb8\x47\x18\x10\xad\x42\x70\xce\xe3\x63\x84\x01\x71\
-\x21\x38\x0e\x2e\x04\x27\x3c\x79\x6c\x03\x9a\xd0\x2c\x84\xc7\xd8\
-\x06\x28\xa7\x88\x6d\xc0\x94\xd0\x2a\x84\x05\x4a\xb7\xeb\x2a\xa2\
-\x88\x6d\xc0\x85\x24\xb1\x0d\x68\x42\xa3\x10\x96\x48\x48\x45\xad\
-\x91\x2b\xda\x78\x24\x5c\x05\x7d\x42\x62\x06\x59\xe3\x1e\x85\xa1\
-\x20\xb5\x45\xb1\x58\x60\x53\x04\x0f\xc4\x0b\x8b\x9e\x95\x97\xb5\
-\x0d\x78\xaa\xa2\x5a\x68\x13\x82\xa6\xb0\x8e\x5d\x88\x29\x80\x63\
-\x52\xe4\xfe\x69\x8d\x6d\xd4\x84\x9a\x70\x90\x9a\x84\xb0\x00\xfe\
-\x8e\x6d\x44\x47\x76\x48\x6b\xa6\x31\x2a\xf6\x0a\x11\xa7\x85\x03\
-\xfd\x5f\x51\x72\x8e\x59\x93\x10\x34\xc6\x37\x6d\xe2\x77\xae\x0b\
-\xdf\x92\x96\x3f\x13\x9a\x07\x8e\x4f\x48\x50\xb3\x17\x2e\x17\xda\
-\x02\xc9\x8b\x60\xa1\xbb\xf4\x26\xb6\x01\x00\x3f\xc7\x36\xa0\x86\
-\xf6\x95\xd2\x3d\xe2\x05\xb6\x3d\xfe\x27\x41\x04\x9e\x22\xdf\xef\
-\x92\xb1\xcf\x0e\x11\x44\x95\xb3\xac\x4b\x30\xdd\x97\xb2\xcc\x0d\
-\x71\xc3\xe8\x77\x21\x41\x41\xd7\x52\x93\x10\x34\xd3\x37\x41\x48\
-\xc6\x70\xb1\x48\x6f\xcb\xab\xaa\xd0\x0f\x48\x05\xcf\x3b\xda\x91\
-\xa3\x2b\x4c\xfc\x31\x2a\xf6\x4c\x69\x9a\x3e\x2d\x62\x1b\x70\x82\
-\x3e\x22\xc8\x90\xef\xf1\x85\xf1\x06\xad\xf7\xc0\x1f\x48\x05\x4f\
-\x3b\xbc\x7f\x83\x74\xe7\xb4\xa2\x62\x9c\xa5\x69\x8c\x90\x00\x7f\
-\xc5\x36\xa2\x81\x2e\x29\x90\x92\xf2\x3d\x31\xfa\xe4\x9f\xe9\x16\
-\xf2\x71\x8b\xbe\x18\x48\x6a\x72\x4c\x68\xf3\x08\xda\xb6\x55\x54\
-\xdd\x90\x36\xaa\x05\xc0\x58\x03\xd3\x0f\x65\xf9\xe7\xba\x18\x19\
-\xfa\x16\xe0\xd4\xe4\xbd\xd0\xe4\x11\x40\x2a\xd5\x9f\xb1\x8d\x28\
-\xe9\x92\x1e\x4a\x53\x86\x9a\x1d\xd2\x55\x6a\xb3\x57\xd3\xcc\x9c\
-\x1a\x6f\x00\xba\x3c\x02\x48\xcb\xf6\x5b\x6c\x23\x4a\xce\x25\x1a\
-\xd7\x24\x02\x90\x31\x49\x7e\xe6\x3d\x5b\x74\x78\xdd\x6a\x06\x4e\
-\x0d\xda\x84\x00\xd2\x15\xf9\x0f\x72\xb3\x62\xb1\xa7\xdd\x6d\x2f\
-\xd0\x99\xa6\xa9\x4b\x3a\xab\xd8\xdd\x91\x47\x0e\xdd\x49\x35\x68\
-\x14\x02\x48\xcb\x95\x10\xcf\x3b\x6c\x68\xf7\x06\x9a\xd3\x34\x7d\
-\xa4\xbd\xcb\xb1\x25\xce\x58\x61\x87\x6c\xa9\x48\x51\x38\x43\xa8\
-\x55\x08\x20\x15\x71\x83\xdc\xc0\xd0\xb4\xb5\x9a\x09\x52\xd9\x34\
-\x73\xae\xd5\xdf\x84\x30\xa2\xa1\xcc\x3c\x42\xb9\x9d\xd0\x2c\x84\
-\x8a\x4d\xe0\xf2\x9e\x69\x6f\xb1\xd6\x61\xcc\xb8\x8a\x5f\x69\x5f\
-\x63\xe8\xb3\x3a\x3e\x14\x31\xca\xec\x8c\x05\x21\x84\xbe\x81\x6d\
-\xe5\x2d\x50\xb2\x49\xac\x03\x59\xcb\x6b\xa1\xcf\x32\xec\x50\xd8\
-\x1d\xaa\x63\x41\x08\x05\xb2\x4b\x31\x14\x79\xcb\x6b\x77\xe8\x1b\
-\x20\x9f\xe2\x9e\xf6\xb5\x85\x3c\x90\x1d\x10\x7f\x80\x7e\x16\x0b\
-\x42\x80\xb0\xdd\xa3\xb6\xd9\x0c\x2b\xde\xa0\x22\x6d\x79\x2d\xd4\
-\xac\xcd\x1e\xe5\xdd\x22\xb0\x23\x84\x50\x33\x1d\x7b\xda\x5d\x78\
-\x1a\xc0\x86\x21\x69\x13\x6e\x28\x21\x9c\x5b\x8f\x51\x81\x15\x21\
-\x40\x98\x41\x6a\x5b\xe5\x58\x62\xa7\x5b\x54\xd1\x36\x8d\x1a\x42\
-\x08\xe7\xd6\x63\xd4\x60\x49\x08\x1b\xc6\xf7\x0a\x45\xcb\x6b\x6a\
-\xb6\x03\xf4\xa0\x6d\xad\x23\x44\x2b\x6d\xc2\x1b\x80\x2d\x21\xc0\
-\xf8\xcb\xf2\x45\xcb\x6b\xc9\xc8\x65\x8f\x45\xda\xf2\xda\x98\x0d\
-\xcb\x33\x46\xbc\x01\xd8\x13\x42\x4e\xd8\x19\xa4\x3a\x16\x3d\xc2\
-\x39\x8a\x11\x3f\x7b\x85\x11\x6f\x00\xf6\x84\x00\xe2\x15\xc6\xda\
-\x87\x54\xb4\xbc\xa6\xe2\x24\xd5\x05\xa4\x11\xca\xfc\x8a\x81\x99\
-\xa2\x3a\x16\x85\xf0\xc2\x78\x5d\xa4\x62\xa4\xcf\x9d\x13\xcf\x28\
-\xdb\x59\xda\x05\x8b\x42\x80\x38\x2e\x37\x89\x50\xe6\xd8\x8c\x71\
-\x1f\x8b\x91\x3e\x77\x54\xac\x0a\x21\x06\xd6\xa2\xef\x75\x41\xd5\
-\x56\xe8\x98\xb8\x10\x0e\x9c\xdb\x6c\x37\x45\x5c\x08\x25\x2e\x04\
-\xa1\x3a\x36\x58\x44\xb6\x23\x34\x5b\xe0\xdf\xc4\x3d\x04\xa5\x02\
-\x17\x82\x78\x82\x94\xf3\xfd\xda\x18\xe7\x22\x42\xf0\x84\xc1\xc1\
-\xed\xd0\xb8\x10\x64\xeb\x46\xd7\xe8\x71\x53\x65\x4b\xbc\xf5\x19\
-\x15\xcc\x5d\x08\xcf\x28\x8c\xd5\x1f\x09\x33\xab\xc0\x63\x30\x77\
-\x21\xe4\xb1\x0d\x08\x40\xd7\x01\x71\x3e\xa6\x11\xda\x99\xbb\x10\
-\x8a\x1e\xef\xb5\x3a\xc3\xd2\xa7\x4b\xa7\x21\xd4\x4b\x14\xe6\x2e\
-\x04\xc7\x01\x5c\x08\x5d\x59\x63\x2b\x93\x4f\x9d\x2d\xdd\x37\x0c\
-\x26\x23\xda\xa1\x9a\xb9\x0b\xa1\x4b\x05\x59\xa3\x3f\x7c\x4b\x1b\
-\x37\x48\xff\xbf\xcb\x77\x9d\xe2\xea\x79\x27\xe6\x2e\x84\xe4\xcc\
-\xeb\x4b\x6c\x8b\xa0\xe2\x86\xf3\xbb\x41\xa7\xb8\xcd\xbc\x33\x73\
-\x17\xc2\x2d\xed\xdb\xab\xd7\x81\xec\x08\xc1\x5b\xda\x17\xce\x5c\
-\x08\x33\xa7\xed\x80\xbb\xb6\x7c\x02\xd7\xd2\xf6\x5d\xb3\x50\x46\
-\x68\xc4\x5a\xea\xa8\x14\x69\xb9\xd2\x01\x3f\x73\x8d\x74\x1b\x8e\
-\xa7\x19\x87\x2c\x43\x0b\xc9\x89\xbf\xa7\x0c\x97\xdf\x61\x89\x2c\
-\xce\x3d\xd5\x2e\xf5\x68\xcb\x8f\x50\xb1\xe0\x50\xe1\x97\x5c\x9e\
-\x88\xaf\x2b\x0f\xfc\x78\xb4\x30\x45\x52\x34\x4d\x8d\xe3\x2c\x96\
-\x21\xc2\xdb\x3f\xf2\xbd\x30\xd4\x89\x43\x8b\x10\xaa\x50\x8a\x55\
-\xe5\x8f\x11\x69\xba\x3a\x59\x95\x97\xbf\x6b\x4a\x5a\x32\x14\x8f\
-\x7c\xef\xe9\x56\xc4\xcb\xc9\xfc\x88\xdc\xeb\xea\x8a\x4a\x4c\x21\
-\x2c\x91\xca\x7f\x87\x9e\x10\xeb\xc7\x09\xb0\x5f\xb0\x17\xcb\xa8\
-\x8d\x07\x0e\x63\x81\x05\xba\x12\xbc\x57\xe7\x9c\x73\x22\x6c\x87\
-\x0f\x2d\x84\x04\x69\x85\xee\xd0\x3b\x67\xfd\x2f\x0e\x5d\xa4\x0d\
-\xfa\xf3\x14\xf7\xe1\x1d\x87\xd6\x37\x43\x6f\xda\xd9\x47\xe4\xde\
-\x37\x8d\xdd\x46\x21\x94\x10\xb2\xf2\xb2\x90\x09\xbe\x9e\x45\x33\
-\x41\xfa\xb3\x53\xf0\x0a\xc7\xdd\xa2\x2d\x36\x66\xc5\xfa\xe4\x95\
-\xbe\x98\x31\x85\xb0\x40\x5a\xff\x15\xb6\x2a\xd2\x71\x85\xc9\xd0\
-\xdb\x72\x76\x65\xcf\xf7\x27\xf0\xb4\x75\x8b\xba\xb0\x43\x66\xa3\
-\x36\x63\x7c\xf8\x18\xeb\x08\x09\x32\x00\x2b\x90\x55\x59\x4b\x22\
-\x00\xf1\x5a\x49\xed\xf7\x0d\xe2\x25\xac\x1e\x67\xac\xb2\x6d\x16\
-\xb5\xbf\xad\xa2\x58\x72\x1d\xb7\x48\x83\x54\x30\xc2\x9a\xc7\x90\
-\x1e\xc1\xaa\x07\x68\xa2\x3e\xa8\xac\x48\x90\xef\x96\x61\xe3\xfb\
-\x3d\x23\x0d\xd2\xa6\xe1\xb5\x02\xbd\x63\xb4\xae\xb4\x7d\xbf\xde\
-\x0c\x25\x84\x35\xd3\x10\x40\x9d\x5f\x68\x9e\xbd\xd8\x60\x63\x00\
-\x5d\x1f\x18\xd7\xc9\xb0\xdf\xd5\xab\xb3\x43\xea\x5e\x7e\xcd\x87\
-\x5c\x2b\x84\x14\xa9\x18\xd6\x5b\x97\x26\x9a\xbc\x02\xe8\x4a\xda\
-\x7d\x8a\x3d\xcd\x7b\xa8\x16\x88\xb8\xa7\xd4\x60\x55\x7c\x45\x9e\
-\xd7\x45\xb3\x4c\x97\x8e\x11\x16\xc8\xc0\xe5\x0f\xa6\x29\x02\x90\
-\x56\xbf\x69\x23\xda\x16\xfd\xe3\x85\x53\x3b\x4d\xa7\xe6\xb5\xeb\
-\xbc\xe7\x8a\xf1\xc3\x25\x42\x58\x22\x53\x8a\x56\x0f\xaa\xf4\x61\
-\xd3\xf3\xef\x5a\xd8\x34\xfc\x6d\x2a\x5b\xca\xdb\xb8\x41\xba\x7d\
-\x5b\x7a\x06\x6d\xee\x2b\x84\x0c\xd9\x76\x30\x55\x2f\x70\xcc\xa9\
-\x4c\xf6\x9a\x23\x3e\x3c\xd3\xdc\x5f\xde\x84\x35\x23\x2a\xef\x91\
-\xc6\xba\xf3\xd6\xf2\x3e\x42\xd8\x30\xad\x41\x56\x57\x3e\xf2\xe3\
-\xae\xcd\x02\xbd\x07\xdd\xd7\x0d\x7f\x5b\xa1\x67\x1b\x4b\x28\xde\
-\x22\x0d\x42\xd6\xe5\xcd\x5d\x84\xb0\x40\x5c\x8d\x85\x99\x92\xb1\
-\x48\x1a\xfe\xb6\x0e\x6c\x43\x17\x4e\xc5\x69\xb2\x9a\xdb\xe1\x5a\
-\xaa\xae\x52\x76\xee\x8d\xe7\x84\xb0\x40\x54\x65\x61\x29\x3e\x34\
-\x39\xfa\xbc\xc2\x3a\xb6\x01\x4a\xf9\xc2\x99\xee\x6c\x9b\x10\x2a\
-\x11\xcc\xcd\xa5\xf6\x41\xd3\x0a\xed\x8e\x79\x8d\x03\xfa\xf2\x81\
-\x96\xfb\x73\x4a\x08\x2e\x82\x6e\x3c\x01\x9f\x63\x1b\x51\xa2\x49\
-\x94\x5a\xb9\xe7\x84\x18\x9a\x84\xe0\x22\xe8\xc7\x9a\x30\xc9\xd0\
-\xdb\xf8\x8c\x82\xc3\x2d\x46\x68\x14\xc3\xb1\x10\x5c\x04\xfd\x79\
-\xa1\xfd\x50\xfc\xd8\xec\xf0\xb1\x41\x5f\xee\x39\xba\x67\x75\x21\
-\xb8\x08\x2e\x27\xe6\x19\xdc\x60\x87\x57\x26\xc6\x47\x6a\xb3\x49\
-\x95\x10\x5c\x04\xce\x1c\xf9\x36\xb5\x5a\x85\x73\xc9\x71\x11\x38\
-\xf3\xe4\x0b\x88\x47\x98\xe3\xaa\xa3\xe3\xd4\xf9\xf2\x13\xf3\x5d\
-\x75\x74\x9c\x6f\x78\xc8\x47\xc7\xc1\x85\xe0\x38\x80\x0b\xc1\x71\
-\x00\x17\x82\xe3\x00\x2e\x04\xc7\x01\x5c\x08\x8e\x03\xd8\xcb\x8f\
-\x10\x92\x1d\x8a\xc3\x98\xf7\x64\x53\xfe\x0c\x11\x62\xdf\x24\x2e\
-\x84\x03\xaa\xc2\x94\x0f\x4c\xc1\xf7\x9b\xcc\x12\x0e\x21\xf8\x53\
-\x7c\x41\x75\xd6\x42\x78\xe6\x10\x86\xfc\x5c\xa2\xbd\xa9\x51\x94\
-\x57\xf5\xbd\xab\xfc\x14\x77\xcc\xf4\x34\xe2\xdc\x84\xb0\x47\x1e\
-\x7e\x95\xda\xc8\x11\x5e\x90\xee\xd3\x86\x83\x28\x32\x6c\x44\x2f\
-\x1f\x84\xb9\x0c\x96\x77\x48\x20\xdf\x04\x79\xc0\x43\x8a\x20\x21\
-\xee\x79\x84\xb4\xbc\x86\xda\x2a\x53\x89\x22\x45\xc2\x5e\x7e\x46\
-\x7f\x40\xb3\xab\x79\xf3\xfa\xfa\xba\x66\xba\x81\x9f\x1e\x91\xbe\
-\x71\x3e\xd0\xe7\x2d\x1b\x2e\x4d\x91\xe3\x9e\x39\x0c\xee\xf3\xf2\
-\xe7\x10\x67\x15\x2a\x2f\xb1\x66\xa2\x03\xed\xa9\x0a\xe1\x81\x43\
-\x68\xfa\x4b\xa9\x27\x34\x4c\xb1\xdb\x4d\xa8\xc4\x91\x73\x10\xc7\
-\x35\x64\x4c\x50\x10\x53\x13\xc2\xb5\x02\xa8\x2a\xfe\x1d\x76\x2b\
-\xfe\x39\xf6\x1c\x26\x08\xae\x39\xdd\x96\x22\xf7\x7a\x12\xf7\x69\
-\x2a\x42\xb8\x46\x00\x4b\xa4\x95\xd3\x9c\xd7\x6d\x4c\xaa\x4c\x34\
-\x97\x8a\x22\x65\x02\x82\xb0\x3e\x58\x7e\x40\x06\x74\x19\xfd\x44\
-\xb0\xe0\x30\x68\xfe\x13\x89\x79\x33\x47\x11\xc0\x21\x13\xcd\xdf\
-\x88\x18\xfa\x0e\xfc\x73\x44\x0c\xef\xd0\x17\xf0\xac\x33\x56\x85\
-\x70\xa9\x00\x12\x64\x46\xa4\x40\x1e\xfe\xec\x17\x92\x8e\x78\x8f\
-\xe4\x7e\x28\x90\x93\x8b\x7d\x66\xa2\x72\x0e\x82\x88\x1d\xde\xa6\
-\x37\xd6\x84\xb0\x43\x6e\x74\xc6\x65\x02\xf8\x0b\x09\xe5\xa1\x69\
-\xa6\x47\x23\x6f\x81\xff\x71\x58\x91\xee\x2b\x88\x04\xf8\x2f\x86\
-\xa6\x5d\x2d\x09\xe1\x01\x69\x71\xf2\x1e\xff\x93\x20\xee\xbe\x12\
-\x80\xd3\x8f\x1b\x64\xfc\x58\xd0\x5f\x10\x9f\x90\xe7\xb5\x1b\xda\
-\xa8\x31\xb0\x22\x84\x2a\x8d\x53\xd7\xc1\x5c\xc2\xc1\x03\xcc\x72\
-\xcb\xc0\xc0\xd4\x05\xd1\x27\xb4\xe4\x13\x46\xc4\x60\x41\x08\xa7\
-\x72\x99\x9d\x62\x8d\x3c\x00\xf7\x00\xc3\x73\xc3\xa1\xcb\x94\x76\
-\xfc\x9f\x17\x0c\x88\x41\xbb\x10\xfa\x88\xa0\x4a\x69\x65\x31\xb7\
-\xb3\x35\xde\x22\xf9\xf3\x36\x74\xeb\x2e\xa9\x17\xc3\x9b\xd7\xd7\
-\xd7\x84\xe6\x44\x18\x1a\xc8\x3b\xbe\x6f\x8d\xfd\xb5\x10\xab\x3c\
-\x23\x8d\x55\xde\xe1\xbd\xd5\x6a\xbd\x3a\x86\x4c\x38\x1e\x83\x2a\
-\x9b\x8f\xe9\xc5\x9c\x89\xf0\x3b\x86\x83\x11\x5b\x16\xc2\x12\x11\
-\xc1\x5c\x17\xc2\x34\x72\x55\xae\xe3\x98\x58\x15\x42\x8a\x88\xc0\
-\xc7\x02\xfa\xd8\x21\xcf\xc7\x94\x18\xb4\x0f\x96\x9b\xc8\x90\x81\
-\x9a\x8b\x40\x27\xb7\xc8\x78\x41\xe5\x58\xe0\x14\xd6\x3c\x42\xc6\
-\x3c\x53\xdc\x5a\x64\x8f\x78\x06\x13\x27\x01\x2d\x79\x84\x0c\x17\
-\x81\x25\x6e\x30\xe4\x19\xac\x08\x21\xc3\x45\x60\x11\x33\x62\xb0\
-\xd0\x35\xca\x70\x11\x58\x67\x8f\x88\xa1\x88\x6c\xc7\x49\xb4\x7b\
-\x84\x0c\x17\xc1\x14\xb8\x41\x66\xf9\xd4\xe6\xe2\xd0\x2c\x84\x0c\
-\x17\xc1\x94\xa8\x66\x93\x54\x8a\x41\xab\x10\x32\x5c\x04\x53\x44\
-\xad\x18\x34\x8e\x11\x12\x64\xfb\xb4\x33\x5d\xbe\x12\x37\x16\xd4\
-\x0f\x68\xf4\x08\x49\x6c\x03\x9c\xd1\x51\xe7\x11\x34\x0a\xc1\x71\
-\x82\xe3\x42\x70\x1c\x5c\x08\x8e\x03\xb8\x10\x1c\x07\x70\x21\x38\
-\x0e\xe0\x42\x70\x1c\xc0\x85\xe0\x38\x80\x0b\xc1\x71\x00\x17\x82\
-\xe3\x00\x2e\x04\xc7\x01\x5c\x08\x8e\x03\xb8\x10\x1c\x07\x70\x21\
-\x38\x0e\xe0\x42\x70\x1c\xc0\x85\xe0\x38\x80\x0b\xc1\x71\x00\x17\
-\x82\xe3\x00\x2e\x04\xc7\x01\x5c\x08\x8e\x03\xb8\x10\x1c\x07\x70\
-\x21\x38\x0e\xe0\x42\x70\x1c\x00\x7e\x8e\x6d\x40\x03\x05\x92\x86\
-\xc8\x99\x2e\x45\x6c\x03\x8e\xf9\x07\x8d\xd2\xa5\xe0\xa7\x84\x0f\
-\xd3\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x02\x33\
-\x89\
-\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
-\x00\x00\x24\x00\x00\x00\x22\x08\x06\x00\x00\x00\x37\x59\x7b\x85\
-\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\x0b\x12\
-\x01\xd2\xdd\x7e\xfc\x00\x00\x01\xe5\x49\x44\x41\x54\x58\x85\xc5\
-\x98\xe1\x71\x82\x40\x10\x85\x3f\x6d\x40\x3a\xf0\x52\x81\xa4\x02\
-\xb1\x13\xd2\x81\x25\x58\x42\x3a\x88\x2d\x58\x41\x48\x05\x31\x15\
-\x04\x3b\xd0\x0a\x36\x3f\x38\x46\xc4\x3b\xd8\x3d\xe2\xf8\x66\x98\
-\x39\x60\x79\xfb\xd8\xdb\xdb\x5b\x98\x89\x08\x13\x91\x03\x7b\x3f\
-\x2e\x81\xe3\x14\xb2\xd9\x44\x41\x19\x50\x03\x0b\x7f\x7e\x01\x1c\
-\x70\x4e\x25\x9c\x4f\x51\x03\x54\x1d\x31\xf8\x71\x35\x85\x70\x8a\
-\xa0\x1d\xb0\x0a\x5c\x5f\xf9\x7b\x69\x10\x91\x94\xa3\x90\x71\x14\
-\x29\xdc\x29\x39\x94\xd1\x24\xee\x72\xc4\xee\x44\x93\xf0\xa6\x7c\
-\x4a\x99\xb2\xad\x42\x0c\xde\x66\x6b\x25\xb7\x46\x28\x07\xbe\x8d\
-\x3e\x5e\x31\x94\x02\x6b\x84\xde\x8d\xf6\xe6\x67\x2c\x11\x2a\x81\
-\x8f\xde\xb5\x0b\xf7\x6f\x9f\x73\x5b\x0a\x00\xde\xb8\x16\xcf\x61\
-\x28\xb3\x3f\x13\x91\x73\x60\x25\x55\x01\xdb\x2a\x60\x57\x7b\x8e\
-\x51\x5f\xda\x29\xdb\x06\xde\x1a\x9a\xaa\xac\xb9\xa6\x4e\x70\xcd\
-\x94\x39\xe0\x77\x88\xa3\x77\x1e\x23\xbc\xd0\x4c\x67\x3d\xe4\x4c\
-\x13\xa1\x9d\xc2\x46\x83\x85\x86\x6b\x2c\x42\x9a\x65\xae\x8d\x50\
-\x8b\xc1\x32\x30\x16\x21\xcd\x92\x75\x91\x71\x12\xe7\x90\xa0\x02\
-\x58\x2b\x1c\xb8\xc8\x38\x86\xb5\xe7\x36\x0b\xda\x29\xc8\x53\x11\
-\xe5\x8e\x09\x2a\xd0\x45\x27\x15\xd1\x28\xc5\x04\xed\x0d\xe4\x2e\
-\x32\x1e\x43\xd0\x47\x48\x50\x89\x6e\x37\x0f\x89\x70\x11\x9b\x10\
-\x96\xde\xd7\xa8\x20\x73\xcb\x30\x01\x77\xbe\xfa\x75\xa8\x00\x3e\
-\x8d\xa4\x27\xae\xd5\xd7\x61\x8b\x2e\xc0\x86\x4e\x1f\xde\x17\x54\
-\xf1\xd8\x64\x0e\xe1\x8b\x4e\x82\x77\xa7\xac\x48\x14\x73\x00\x5e\
-\xfc\x71\x48\x78\xfe\x76\xc5\x75\xb6\xfe\xbd\xa2\x71\xef\xe3\xdc\
-\x6b\x2b\x62\x6d\xca\x18\xf6\x2d\x47\x4b\xe4\x12\x48\x44\xf4\xfd\
-\x90\x06\x4e\x3a\xfd\x50\x99\x10\xea\x36\xdc\x79\xe7\x3c\x27\x3d\
-\x07\x4b\xb8\x26\x75\x8d\x7d\x75\xb4\xb8\x70\xfb\x6d\x1f\x6a\xe4\
-\x34\x38\x01\x6e\x26\x22\x05\xf6\xa5\xfe\x28\x6c\xe6\x0c\xec\xbc\
-\x4f\x40\x31\xe7\x36\x07\x9e\x8d\x7c\x26\x22\x19\x4d\x94\x72\x9a\
-\x4a\xeb\xfc\xcd\x8c\xf0\xcf\x84\xff\xc0\x0f\xd7\x4f\xec\xda\x1f\
-\x47\xa0\x9a\xf2\x7f\xc8\x11\xdf\x4c\x5b\x27\x66\xfc\x01\x80\x90\
-\x5d\x66\xe4\xbb\xdc\x43\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
-\x60\x82\
-"
-
-qt_resource_name = b"\
-\x00\x05\
-\x00\x6f\xa6\x53\
-\x00\x69\
-\x00\x63\x00\x6f\x00\x6e\x00\x73\
-\x00\x08\
-\x05\xf9\xfb\x73\
-\x00\x73\
-\x00\x6f\x00\x69\x00\x63\x00\x69\x00\x61\x00\x6c\x00\x73\
-\x00\x06\
-\x07\xa5\x9f\x7c\
-\x00\x73\
-\x00\x6f\x00\x63\x00\x69\x00\x61\x00\x6c\
-\x00\x0c\
-\x07\x28\x00\x87\
-\x00\x74\
-\x00\x65\x00\x6c\x00\x65\x00\x67\x00\x72\x00\x61\x00\x6d\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x14\
-\x0c\xcf\x6f\x67\
-\x00\x47\
-\x00\x69\x00\x74\x00\x48\x00\x75\x00\x62\x00\x2d\x00\x4c\x00\x6f\x00\x67\x00\x6f\x00\x2e\x00\x77\x00\x69\x00\x6e\x00\x65\x00\x2e\
-\x00\x70\x00\x6e\x00\x67\
-\x00\x02\
-\x00\x00\x03\x88\
-\x00\x31\
-\x00\x78\
-\x00\x10\
-\x00\x77\xb7\x67\
-\x00\x68\
-\x00\x6f\x00\x6d\x00\x65\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x34\x00\x36\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x10\
-\x00\x8c\xd1\x27\
-\x00\x68\
-\x00\x69\x00\x64\x00\x65\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x35\x00\x33\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x10\
-\x00\x9e\x0f\x67\
-\x00\x67\
-\x00\x61\x00\x6d\x00\x65\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x36\x00\x31\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x11\
-\x01\xcb\xb5\xe7\
-\x00\x63\
-\x00\x6c\x00\x6f\x00\x73\x00\x65\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x34\x00\x33\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\
-\x00\x10\
-\x02\x88\x1d\x67\
-\x00\x73\
-\x00\x65\x00\x74\x00\x74\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x35\x00\x30\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x10\
-\x02\x8a\xee\xa7\
-\x00\x77\
-\x00\x69\x00\x6e\x00\x64\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x35\x00\x31\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x10\
-\x03\x1f\x94\xc7\
-\x00\x73\
-\x00\x6d\x00\x69\x00\x6c\x00\x65\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x31\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x13\
-\x03\x43\x3b\x27\
-\x00\x61\
-\x00\x6e\x00\x64\x00\x72\x00\x6f\x00\x69\x00\x64\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x34\x00\x39\x00\x2e\x00\x70\
-\x00\x6e\x00\x67\
-\x00\x11\
-\x03\x7f\xcb\x27\
-\x00\x77\
-\x00\x6f\x00\x72\x00\x6c\x00\x64\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x36\x00\x30\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\
-\x00\x07\
-\x03\x8b\x57\xa7\
-\x00\x6d\
-\x00\x61\x00\x78\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x11\
-\x03\xc6\xb5\x67\
-\x00\x63\
-\x00\x6c\x00\x6f\x00\x75\x00\x64\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x34\x00\x38\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\
-\x00\x0f\
-\x04\x6e\xc9\x67\
-\x00\x62\
-\x00\x75\x00\x67\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x34\x00\x37\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x10\
-\x04\x8a\x8e\x67\
-\x00\x64\
-\x00\x72\x00\x61\x00\x67\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x35\x00\x32\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x08\
-\x05\xe2\x59\x27\
-\x00\x6c\
-\x00\x6f\x00\x67\x00\x6f\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x0b\
-\x06\x79\xc2\x27\
-\x00\x72\
-\x00\x65\x00\x73\x00\x74\x00\x6f\x00\x72\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x11\
-\x07\x0c\x04\x67\
-\x00\x73\
-\x00\x6d\x00\x69\x00\x6c\x00\x65\x00\x32\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x31\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\
-\x00\x09\
-\x07\x28\xba\xc7\
-\x00\x70\
-\x00\x65\x00\x70\x00\x6c\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x11\
-\x07\x39\xc1\x87\
-\x00\x63\
-\x00\x6c\x00\x65\x00\x61\x00\x6e\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x35\x00\x39\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\
-\x00\x12\
-\x08\xe2\xa4\x87\
-\x00\x62\
-\x00\x75\x00\x6c\x00\x6c\x00\x65\x00\x74\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x35\x00\x34\x00\x2e\x00\x70\x00\x6e\
-\x00\x67\
-\x00\x09\
-\x09\x6a\x86\x67\
-\x00\x61\
-\x00\x72\x00\x72\x00\x6f\x00\x77\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x10\
-\x0c\x89\x36\xe7\
-\x00\x62\
-\x00\x6f\x00\x6f\x00\x6b\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x35\x00\x37\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\x00\x12\
-\x0d\x31\xf3\x07\
-\x00\x70\
-\x00\x65\x00\x6f\x00\x70\x00\x6c\x00\x65\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x36\x00\x32\x00\x2e\x00\x70\x00\x6e\
-\x00\x67\
-\x00\x11\
-\x0f\x23\x0a\x07\
-\x00\x65\
-\x00\x72\x00\x72\x00\x6f\x00\x72\x00\x41\x00\x73\x00\x73\x00\x65\x00\x74\x00\x20\x00\x35\x00\x35\x00\x2e\x00\x70\x00\x6e\x00\x67\
-\
-"
-
-qt_resource_struct_v1 = b"\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x07\
-\x00\x00\x00\x10\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x04\
-\x00\x00\x00\x26\x00\x02\x00\x00\x00\x02\x00\x00\x00\x05\
-\x00\x00\x00\x38\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x00\x56\x00\x00\x00\x00\x00\x01\x00\x00\x02\x15\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x08\
-\x00\x00\x00\x84\x00\x02\x00\x00\x00\x17\x00\x00\x00\x09\
-\x00\x00\x00\x8e\x00\x00\x00\x00\x00\x01\x00\x00\x04\x36\
-\x00\x00\x00\xb4\x00\x00\x00\x00\x00\x01\x00\x00\x05\xa1\
-\x00\x00\x00\xda\x00\x00\x00\x00\x00\x01\x00\x00\x06\x19\
-\x00\x00\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x08\x0e\
-\x00\x00\x01\x28\x00\x00\x00\x00\x00\x01\x00\x00\x09\x4d\
-\x00\x00\x01\x4e\x00\x00\x00\x00\x00\x01\x00\x00\x0a\xc5\
-\x00\x00\x01\x74\x00\x00\x00\x00\x00\x01\x00\x00\x0b\xa0\
-\x00\x00\x01\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x0c\xd0\
-\x00\x00\x01\xc6\x00\x00\x00\x00\x00\x01\x00\x00\x0e\x1c\
-\x00\x00\x01\xee\x00\x00\x00\x00\x00\x01\x00\x00\x0f\x63\
-\x00\x00\x02\x02\x00\x00\x00\x00\x00\x01\x00\x00\x10\xba\
-\x00\x00\x02\x2a\x00\x00\x00\x00\x00\x01\x00\x00\x11\xbe\
-\x00\x00\x02\x4e\x00\x00\x00\x00\x00\x01\x00\x00\x13\x80\
-\x00\x00\x02\x74\x00\x00\x00\x00\x00\x01\x00\x00\x14\x0e\
-\x00\x00\x02\x8a\x00\x00\x00\x00\x00\x01\x00\x00\x14\x94\
-\x00\x00\x02\xa6\x00\x00\x00\x00\x00\x01\x00\x00\x15\xf1\
-\x00\x00\x02\xce\x00\x00\x00\x00\x00\x01\x00\x00\x17\x14\
-\x00\x00\x02\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x18\xfa\
-\x00\x00\x03\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x1a\x3f\
-\x00\x00\x03\x38\x00\x00\x00\x00\x00\x01\x00\x00\x1a\xc4\
-\x00\x00\x03\x50\x00\x00\x00\x00\x00\x01\x00\x00\x1b\x65\
-\x00\x00\x03\x76\x00\x00\x00\x00\x00\x01\x00\x00\x1c\x45\
-\x00\x00\x03\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x28\xc7\
-"
-
-qt_resource_struct_v2 = b"\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\
-\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x07\
-\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x10\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\
-\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x04\
-\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x26\x00\x02\x00\x00\x00\x02\x00\x00\x00\x05\
-\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x38\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x01\x8d\xe5\x16\x45\xc4\
-\x00\x00\x00\x56\x00\x00\x00\x00\x00\x01\x00\x00\x02\x15\
-\x00\x00\x01\x8d\xe5\x23\x99\x4e\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x08\
-\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x84\x00\x02\x00\x00\x00\x17\x00\x00\x00\x09\
-\x00\x00\x00\x00\x00\x00\x00\x00\
-\x00\x00\x00\x8e\x00\x00\x00\x00\x00\x01\x00\x00\x04\x36\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x00\xb4\x00\x00\x00\x00\x00\x01\x00\x00\x05\xa1\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x00\xda\x00\x00\x00\x00\x00\x01\x00\x00\x06\x19\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x08\x0e\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x01\x28\x00\x00\x00\x00\x00\x01\x00\x00\x09\x4d\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x01\x4e\x00\x00\x00\x00\x00\x01\x00\x00\x0a\xc5\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x01\x74\x00\x00\x00\x00\x00\x01\x00\x00\x0b\xa0\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x01\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x0c\xd0\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x01\xc6\x00\x00\x00\x00\x00\x01\x00\x00\x0e\x1c\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x01\xee\x00\x00\x00\x00\x00\x01\x00\x00\x0f\x63\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x02\x02\x00\x00\x00\x00\x00\x01\x00\x00\x10\xba\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x02\x2a\x00\x00\x00\x00\x00\x01\x00\x00\x11\xbe\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x02\x4e\x00\x00\x00\x00\x00\x01\x00\x00\x13\x80\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x02\x74\x00\x00\x00\x00\x00\x01\x00\x00\x14\x0e\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x02\x8a\x00\x00\x00\x00\x00\x01\x00\x00\x14\x94\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x02\xa6\x00\x00\x00\x00\x00\x01\x00\x00\x15\xf1\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x02\xce\x00\x00\x00\x00\x00\x01\x00\x00\x17\x14\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x02\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x18\xfa\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x03\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x1a\x3f\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x03\x38\x00\x00\x00\x00\x00\x01\x00\x00\x1a\xc4\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x03\x50\x00\x00\x00\x00\x00\x01\x00\x00\x1b\x65\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x03\x76\x00\x00\x00\x00\x00\x01\x00\x00\x1c\x45\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-\x00\x00\x03\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x28\xc7\
-\x00\x00\x01\x74\xf2\xe0\xfc\x28\
-"
-
-qt_version = [int(v) for v in QtCore.qVersion().split('.')]
-if qt_version < [5, 8, 0]:
- rcc_version = 1
- qt_resource_struct = qt_resource_struct_v1
-else:
- rcc_version = 2
- qt_resource_struct = qt_resource_struct_v2
-
-def qInitResources():
- QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
-
-def qCleanupResources():
- QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
-
-qInitResources()
diff --git a/UI/translations/ru_RU.qm b/UI/translations/ru_RU.qm
deleted file mode 100644
index 4b0df1f..0000000
Binary files a/UI/translations/ru_RU.qm and /dev/null differ
diff --git a/UI/translations/ru_RU.ts b/UI/translations/ru_RU.ts
deleted file mode 100644
index e96074c..0000000
--- a/UI/translations/ru_RU.ts
+++ /dev/null
@@ -1,336 +0,0 @@
-
-
-
-
- MainWindow
-
-
- Server connection
- Server connection radio
- Подключение к серверу
-
-
-
- Github conncection
- GitHub connection radio
- Подключение к GitHub
-
-
-
- Welcome
- main page title
- Приветствуем
-
-
-
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'Segoe UI'; font-size:10pt; font-weight:400; font-style:normal;">
-<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline; color:#008f96;">Stellaris DLC Unlocker</span></p>
-<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;">Requirements</span><span style=" font-family:'MS Shell Dlg 2';">:</span></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';"> </span><span style=" font-family:'MS Shell Dlg 2'; font-weight:600;">License</span><span style=" font-family:'MS Shell Dlg 2';">: Steam.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;">Installation</span><span style=" font-family:'MS Shell Dlg 2';">:</span></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';"> Follow the installer instructions. Installation is almost entirely automatic. <br /></span></p>
-<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline; color:#008f96;">Terms Of Use</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; color:#0000ff;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">1. This unlocker is distributed absolutely free of charge. Any commercial use of this unlocker is prohibited.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">2. THIS UNLOCKER IS PROVIDED "AS IS". NO WARRANTIES ARE PROVIDED OR IMPLIED. YOU USE THIS MODIFICATION OF THE ORIGINAL GAME AT YOUR OWN RISK. THE AUTHORS OF THE MODIFICATION WILL NOT BE LIABLE FOR ANY LOSSES OR DATA CORRUPTION, ANY LOST PROFITS IN THE PROCESS OF USE OR MISUSE OF THIS MODIFICATION.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">3. All rights not expressly granted here are reserved by the copyright holders.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">4. Installation and use of this modification implies that you have read and understand the terms of this license agreement and agree to them.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html>
- Welcome page text
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'Segoe UI'; font-size:10pt; font-weight:400; font-style:normal;">
-<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline; color:#008f96;">Stellaris DLC Unlocker</span></p>
-<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;">Требования</span><span style=" font-family:'MS Shell Dlg 2';">:</span></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';"> </span><span style=" font-family:'MS Shell Dlg 2'; font-weight:600;">Лицензия</span><span style=" font-family:'MS Shell Dlg 2';">: Steam.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;">Установка</span><span style=" font-family:'MS Shell Dlg 2';">:</span></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';"> Следуйте инструкциям инсталлятора. Установка почти полностью автоматическая. <br /></span></p>
-<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline; color:#008f96;">Правила использования</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; color:#0000ff;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">1. Данный анлокер распространяется абсолютно бесплатно. Любое коммерческое использование запрещается.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">2. ДАННЫЙ АНЛОКЕР ПОСТАВЛЯЕТСЯ ПО ПРИНЦИПУ «AS IS». НИКАКИХ ГАРАНТИЙ НЕ ПРИЛАГАЕТСЯ И НЕ ПРЕДУСМАТРИВАЕТСЯ. ВЫ ИСПОЛЬЗУЕТЕ ЭТУ МОДИФИКАЦИЮ ОРИГИНАЛЬНОЙ ИГРЫ НА СВОЙ СТРАХ И РИСК. АВТОРЫ МОДИФИКАЦИИ НЕ БУДУТ ОТВЕЧАТЬ НИ ЗА КАКИЕ ПОТЕРИ ИЛИ ИСКАЖЕНИЯ ДАННЫХ, ЛЮБУЮ УПУЩЕННУЮ ВЫГОДУ В ПРОЦЕССЕ ИСПОЛЬЗОВАНИЯ ИЛИ НЕПРАВИЛЬНОГО ИСПОЛЬЗОВАНИЯ ДАННОЙ МОДИФИКАЦИИ.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">3. Все права, не предоставленные здесь явно, сохраняются за правообладателями.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">4. Установка и использование данной модификации означает, что вы ознакомились и понимаете положения настоящего лицензионного соглашения и согласны с ними.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html>
-
-
-
- Next
- next button
- Далее
-
-
-
- Unlock settings
- work page label
- Настройка разблокировки
-
-
-
- Stellaris path
- sadsadsa
- stellaris path text
- Путь к игре
-
-
-
- Open
- open path button
- Открыть
-
-
-
- Unlock
- Unlock start button
- Начать
-
-
-
- Full launcher reinstallation
- full reinstal checkbox
- Полная переустановка
-
-
-
- <html><head/><body><p>This function will delete all saves and presets of mods.</p><p>It is only needed if something did not work during the normal installation</p></body></html>
- full reinstall tooltip
- <html><head/><body><p>Эта функция удалит все сохранения и пресеты модов.</p><p>Необходима только при проблемах с нормальной разблокировкой</p></body></html>
-
-
-
- Skip launcher reinstall
- Пропустить переустановку лаунчера
-
-
-
- <html><head/><body><p>It is used if it is impossible to automatically reinstall the launcher.</p><p>The program will assume that the launcher has already been reinstalled before</p></body></html>
- It is used if it is impossible to automatically reinstall the launcher.
-The program will assume that the launcher has already been reinstalled before
- Skip launcher reinstall tooltip
- <html><head/><body><p>Использовать при проблемах с автоматической переустановкой лаунчера.</p><p>Программа будет считать, что переустановка уже была произведена</p></body></html>
-
-
-
- Alternative unlock
- Alternative unlock checkbox
- Альернативная разблокировка
-
-
-
- <html><head/><body><p>Uses a different unlock method</p></body></html>
- Alternative unlock tooltip
- <html><head/><body><p>Использует иной метод разблокировки</p></body></html>
-
-
-
- Progress
- Progress label
- Прогресс
-
-
-
- Download files
- Download files progress radio
- Загрузка файлов
-
-
-
- Launcher reinstall
- Launcher reinstall progress radio
- Переустановка лаунчера
-
-
-
- Copy files
- Copy files progress radio
- Копирование файлов
-
-
-
- DLC Download progress
- DLC Download progress label
- Прогресс загрузки DLC
-
-
-
- Current DLC progress
- Current DLC Download progress label
- Текущее DLC
-
-
-
- Launch game
- Launch game checkbox
- Запустить игру
-
-
-
- Done
- Done buttone
- Готово
-
-
-
- Log
- bug page title
- Лог
-
-
-
- Close
- Закрыть
-
-
-
- Update old DLCs
- Update old DLCs button
- Обновить DLC
-
-
-
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'Segoe UI'; font-size:8.25pt; font-weight:400; font-style:normal;">
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt; color:#ff0000;">Old DLCs detected! </span><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt; color:#ffffff;">You can just update it while unlocking</span></p></body></html>
- Update old DLCs text
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'Segoe UI'; font-size:8.25pt; font-weight:400; font-style:normal;">
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt; color:#ff0000;">Обнаружены старые DLC! </span><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt; color:#ffffff;">Можно обновить их вместе с разблокировкой</span></p></body></html>
-
-
-
- Exit Unlocker?
- Закрыть программу?
-
-
-
- No
- Нет
-
-
-
- Yes
- Да
-
-
-
- Choose Stellaris path
- Выберите путь к игре
-
-
-
- This is not Stellaris path
- Это не путь к игре
-
-
-
- Ok
- Ок
-
-
-
- Please choose game path
- Пожайлуйста выберите путь к игре
-
-
-
- New version
- Новая версия
-
-
-
- New version found
-Please update the program to correctly work
- Найдена новая версия
-Пожалуйста обновите программу для корректной работы
-
-
-
- Cancel
- Отмена
-
-
-
- Update
- Обновить
-
-
-
- Can't establish connection with GitHub. Check internet
- Невозможно подключится к GitHub. Проверьте подключение
-
-
-
- Connection error
- Ошибка подключения
-
-
-
- Cant establish connection with server
-Check your connection or you can try download DLC directly
-Unzip downloaded "dlc" folder to game folder
-Then you can continue
- Невозможно подключится к серверу
-Проверьте подключение или вы можете попробовать скачать DLC напрямую
-Распакуйте скачанные DLC в папку "DLC" в папке с игрой
-Затем вы сможете продолжить
-
-
-
- Exit
- Выйти
-
-
-
- Alt launcher downloading
- Загрузка альт лаунчера
-
-
-
- Downloading
- Загрузка
-
-
-
- Cant download alt launcher
- Невозможно загрузить альт лаунчер
-
-
-
- File download error
- Ошибка загрузки файлов
-
-
-
- Launcher reinstall error
- Ошибка переустановки лаунчера
-
-
-
- Error while unzipping
- Ошибка во время распаковки
-
-
-
- Error unknown launcher
- Ошибка: неизвестный лаунчер
-
-
-
diff --git a/UI/translations/zh_CN.qm b/UI/translations/zh_CN.qm
deleted file mode 100644
index 9478e55..0000000
Binary files a/UI/translations/zh_CN.qm and /dev/null differ
diff --git a/UI/translations/zh_CN.ts b/UI/translations/zh_CN.ts
deleted file mode 100644
index 0ad9869..0000000
--- a/UI/translations/zh_CN.ts
+++ /dev/null
@@ -1,334 +0,0 @@
-
-
-
-
- MainWindow
-
-
- Server connection
- Server connection radio
- 服务器连接状态
-
-
-
- Github conncection
- GitHub connection radio
- Github 连接状态
-
-
-
- Welcome
- main page title
- 欢迎
-
-
-
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'Segoe UI'; font-size:10pt; font-weight:400; font-style:normal;">
-<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline; color:#008f96;">Stellaris DLC Unlocker</span></p>
-<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;">Requirements</span><span style=" font-family:'MS Shell Dlg 2';">:</span></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';"> </span><span style=" font-family:'MS Shell Dlg 2'; font-weight:600;">License</span><span style=" font-family:'MS Shell Dlg 2';">: Steam.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;">Installation</span><span style=" font-family:'MS Shell Dlg 2';">:</span></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';"> Follow the installer instructions. Installation is almost entirely automatic. <br /></span></p>
-<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline; color:#008f96;">Terms Of Use</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; color:#0000ff;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">1. This unlocker is distributed absolutely free of charge. Any commercial use of this unlocker is prohibited.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">2. THIS UNLOCKER IS PROVIDED "AS IS". NO WARRANTIES ARE PROVIDED OR IMPLIED. YOU USE THIS MODIFICATION OF THE ORIGINAL GAME AT YOUR OWN RISK. THE AUTHORS OF THE MODIFICATION WILL NOT BE LIABLE FOR ANY LOSSES OR DATA CORRUPTION, ANY LOST PROFITS IN THE PROCESS OF USE OR MISUSE OF THIS MODIFICATION.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">3. All rights not expressly granted here are reserved by the copyright holders.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">4. Installation and use of this modification implies that you have read and understand the terms of this license agreement and agree to them.</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html>
- Welcome page text
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'Segoe UI'; font-size:10pt; font-weight:400; font-style:normal;">
-<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline; color:#008f96;">Stellaris DLC 解锁器</span></p>
-<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;">要求</span><span style=" font-family:'MS Shell Dlg 2';">:</span></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';"> </span><span style=" font-family:'MS Shell Dlg 2'; font-weight:600;">许可</span><span style=" font-family:'MS Shell Dlg 2';">: 已购买。</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;">安装</span><span style=" font-family:'MS Shell Dlg 2';">:</span></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';"> 安装过程几乎全自动化,您只需依照安装程序的提示进行操作。 <br /></span></p>
-<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline; color:#008f96;">使用条款</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; color:#0000ff;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">1. 此解锁器完全免费分发。禁止用于任何商业用途。如果您是从任何渠道购买,请退款并差评。</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">2. 此解锁器按“原样”提供,不附带任何明示或暗示的保证,包括但不限于适销性、特定用途适用性或无侵权性的保证。在适用法律允许的最大范围内,作者在任何情况下均不对因使用或无法使用本修改而引起的任何直接、间接、附带、特殊或后续损害承担责任。这些损害包括但不限于数据丢失、经济损失、账号被封禁(包括 VAC 封禁或其他发行商采取的惩罚措施)。</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">3. 版权所有者保留所有未明确授予的权利。</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2';">4. 继续安装和使用此修改版即表示您已阅读并理解本许可协议的条款,并同意这些条款。</span></p>
-<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html>
-
-
-
- Next
- next button
- 下一步
-
-
-
- Unlock settings
- work page label
- 解锁设置
-
-
-
- Alternative unlock
- Alternative unlock checkbox
- 备用解锁
-
-
-
- <html><head/><body><p>Uses a different unlock method</p></body></html>
- Alternative unlock tooltip
- <html><head/><body><p>使用不同的解锁方式</p></body></html>
-
-
-
- Stellaris path
- sadsadsa
- stellaris path text
- Stellaris 路径
-
-
-
- Open
- open path button
- 打开
-
-
-
- Unlock
- Unlock start button
- 解锁
-
-
-
- Full launcher reinstallation
- full reinstal checkbox
- 完全重装启动器
-
-
-
- <html><head/><body><p>This function will delete all saves and presets of mods.</p><p>It is only needed if something did not work during the normal installation</p></body></html>
- full reinstall tooltip
- <html><head/><body><p>警告!此功能将删除所有存档和模组播放集。</p><p>请仅在在正常安装过程中出现问题时使用</p></body></html>
-
-
-
- Skip launcher reinstall
- 跳过启动器重装
-
-
-
- <html><head/><body><p>It is used if it is impossible to automatically reinstall the launcher.</p><p>The program will assume that the launcher has already been reinstalled before</p></body></html>
- Skip launcher reinstall tooltip
- <html><head/><body><p>请仅在无法自动重新安装启动器时使用。</p><p>解锁器将假定启动器已在之前重新安装</p></body></html>
-
-
-
- Progress
- Progress label
- 进度
-
-
-
- Download files
- Download files progress radio
- 下载文件
-
-
-
- Launcher reinstall
- Launcher reinstall progress radio
- 启动器重装
-
-
-
- Copy files
- Copy files progress radio
- 复制文件
-
-
-
- DLC Download progress
- DLC Download progress label
- DLC 下载进度
-
-
-
- Current DLC progress
- Current DLC Download progress label
- 当前 DLC 下载进度
-
-
-
- Launch game
- Launch game checkbox
- 启动游戏复选框
-
-
-
- Done
- Done buttone
- 完成
-
-
-
- Log
- bug page title
- 日志
-
-
-
- Close
- 关闭
-
-
-
- Update old DLCs
- Update old DLCs button
- 更新旧的DLCs
-
-
-
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'Segoe UI'; font-size:8.25pt; font-weight:400; font-style:normal;">
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt; color:#ff0000;">Old DLCs detected! </span><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt; color:#ffffff;">You can just update it while unlocking</span></p></body></html>
- Update old DLCs text
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'Segoe UI'; font-size:8.25pt; font-weight:400; font-style:normal;">
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt; color:#ff0000;">检测到旧的DLCs! </span><span style=" font-family:'MS Shell Dlg 2'; font-size:12pt; color:#ffffff;">解锁的时将自动更新为最新版本</span></p></body></html>
-
-
-
- Exit Unlocker?
- 确认退出解锁器?
-
-
-
- No
- 否
-
-
-
- Yes
- 是
-
-
-
- Choose Stellaris path
- 选择 Stellaris 路径
-
-
-
- This is not Stellaris path
- 这不是 Stellaris 路径
-
-
-
- Ok
- 好的
-
-
-
- Please choose game path
- 请选择游戏路径
-
-
-
- New version
- 新版本
-
-
-
- New version found
-Please update the program to correctly work
- 发现新版本
-请更新程序以正常工作
-
-
-
- Cancel
- 取消
-
-
-
- Update
- 更新
-
-
-
- Can't establish connection with GitHub. Check internet
- 无法与 GitHub 建立连接。请检查网络,并且尝试使用加速器。
-
-
-
- Connection error
- 连接错误
-
-
-
- Cant establish connection with server
-Check your connection or you can try download DLC directly
-Unzip downloaded "dlc" folder to game folder
-Then you can continue
- 无法与服务器建立连接
-请检查您的连接,或者您可以尝试直接下载 DLC
-将下载的 "dlc" 文件夹解压至游戏文件夹
-然后继续操作
-
-
-
- Exit
- 退出
-
-
-
- Alt launcher downloading
- 备用启动器下载
-
-
-
- Downloading
- 下载中
-
-
-
- Cant download alt launcher
- 无法下载备用启动器
-
-
-
- File download error
- 文件下载错误
-
-
-
- Launcher reinstall error
- 启动器重装发生错误
-
-
-
- Error while unzipping
- 解压发生错误
-
-
-
- Error unknown launcher
- 未知启动器错误
-
-
-
diff --git a/UI/ui_dialog.py b/UI/ui_dialog.py
deleted file mode 100644
index 268ef50..0000000
--- a/UI/ui_dialog.py
+++ /dev/null
@@ -1,167 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Form implementation generated from reading ui file 'UI/ui_dialog.ui'
-#
-# Created by: PyQt5 UI code generator 5.15.10
-#
-# WARNING: Any manual changes made to this file will be lost when pyuic5 is
-# run again. Do not edit this file unless you know what you are doing.
-
-
-from PyQt5 import QtCore, QtGui, QtWidgets
-
-
-class Ui_Dialog(object):
- def setupUi(self, Dialog):
- Dialog.setObjectName("Dialog")
- Dialog.resize(450, 235)
- Dialog.setMinimumSize(QtCore.QSize(450, 235))
- Dialog.setMaximumSize(QtCore.QSize(450, 235))
- Dialog.setStyleSheet("QDialog {\n"
-" background:rgb(51,51,51);\n"
-"}")
- self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
- self.verticalLayout.setContentsMargins(0, 0, 0, 0)
- self.verticalLayout.setSpacing(0)
- self.verticalLayout.setObjectName("verticalLayout")
- self.frame_2 = QtWidgets.QFrame(Dialog)
- self.frame_2.setStyleSheet("background:rgb(51,51,51);")
- self.frame_2.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_2.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_2.setObjectName("frame_2")
- self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame_2)
- self.verticalLayout_2.setContentsMargins(2, 2, 2, 2)
- self.verticalLayout_2.setSpacing(0)
- self.verticalLayout_2.setObjectName("verticalLayout_2")
- self.frame_top = QtWidgets.QFrame(self.frame_2)
- self.frame_top.setMinimumSize(QtCore.QSize(0, 55))
- self.frame_top.setMaximumSize(QtCore.QSize(16777215, 55))
- self.frame_top.setStyleSheet("background:rgb(91,90,90);")
- self.frame_top.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_top.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_top.setObjectName("frame_top")
- self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame_top)
- self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout.setSpacing(0)
- self.horizontalLayout.setObjectName("horizontalLayout")
- self.lab_heading = QtWidgets.QLabel(self.frame_top)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(14)
- self.lab_heading.setFont(font)
- self.lab_heading.setStyleSheet("color:rgb(255,255,255);")
- self.lab_heading.setText("")
- self.lab_heading.setAlignment(QtCore.Qt.AlignCenter)
- self.lab_heading.setObjectName("lab_heading")
- self.horizontalLayout.addWidget(self.lab_heading)
- self.bn_close = QtWidgets.QPushButton(self.frame_top)
- self.bn_close.setMinimumSize(QtCore.QSize(55, 55))
- self.bn_close.setMaximumSize(QtCore.QSize(55, 55))
- self.bn_close.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.bn_close.setStyleSheet("QPushButton {\n"
-" border: none;\n"
-" background-color: rgba(0,0,0,0);\n"
-"}\n"
-"QPushButton:hover {\n"
-" background-color: rgb(255,107,107);\n"
-"}\n"
-"QPushButton:pressed { \n"
-" background-color: rgba(0,0,0,0);\n"
-"}")
- self.bn_close.setText("")
- icon = QtGui.QIcon()
- icon.addPixmap(QtGui.QPixmap("UI\\icons/1x/closeAsset 43.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
- self.bn_close.setIcon(icon)
- self.bn_close.setIconSize(QtCore.QSize(22, 22))
- self.bn_close.setAutoDefault(False)
- self.bn_close.setFlat(True)
- self.bn_close.setObjectName("bn_close")
- self.horizontalLayout.addWidget(self.bn_close)
- self.verticalLayout_2.addWidget(self.frame_top)
- self.frame_bottom = QtWidgets.QFrame(self.frame_2)
- self.frame_bottom.setStyleSheet("background:rgb(91,90,90);")
- self.frame_bottom.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_bottom.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_bottom.setObjectName("frame_bottom")
- self.gridLayout = QtWidgets.QGridLayout(self.frame_bottom)
- self.gridLayout.setContentsMargins(15, -1, 35, 0)
- self.gridLayout.setHorizontalSpacing(5)
- self.gridLayout.setVerticalSpacing(0)
- self.gridLayout.setObjectName("gridLayout")
- self.bn_east = QtWidgets.QPushButton(self.frame_bottom)
- self.bn_east.setMinimumSize(QtCore.QSize(80, 25))
- self.bn_east.setMaximumSize(QtCore.QSize(80, 25))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(12)
- self.bn_east.setFont(font)
- self.bn_east.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.bn_east.setStyleSheet("QPushButton {\n"
-" border: 2px solid rgb(51,51,51);\n"
-" border-radius: 5px; \n"
-" color:rgb(255,255,255);\n"
-" background-color: rgb(51,51,51);\n"
-"}\n"
-"QPushButton:hover {\n"
-" border: 2px solid rgb(0,143,150);\n"
-" background-color: rgb(0,143,150);\n"
-"}\n"
-"QPushButton:pressed { \n"
-" border: 2px solid rgb(0,143,150);\n"
-" background-color: rgb(51,51,51);\n"
-"}")
- self.bn_east.setText("")
- self.bn_east.setAutoDefault(False)
- self.bn_east.setObjectName("bn_east")
- self.gridLayout.addWidget(self.bn_east, 1, 3, 1, 1)
- self.lab_icon = QtWidgets.QLabel(self.frame_bottom)
- self.lab_icon.setMinimumSize(QtCore.QSize(40, 40))
- self.lab_icon.setMaximumSize(QtCore.QSize(40, 40))
- self.lab_icon.setText("")
- self.lab_icon.setObjectName("lab_icon")
- self.gridLayout.addWidget(self.lab_icon, 0, 0, 1, 1)
- self.bn_west = QtWidgets.QPushButton(self.frame_bottom)
- self.bn_west.setMinimumSize(QtCore.QSize(69, 25))
- self.bn_west.setMaximumSize(QtCore.QSize(69, 25))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(12)
- self.bn_west.setFont(font)
- self.bn_west.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.bn_west.setStyleSheet("QPushButton {\n"
-" border: 2px solid rgb(51,51,51);\n"
-" border-radius: 5px; \n"
-" color:rgb(255,255,255);\n"
-" background-color: rgb(51,51,51);\n"
-"}\n"
-"QPushButton:hover {\n"
-" border: 2px solid rgb(255,107,107);\n"
-" background-color: rgb(255,107,107);\n"
-"}\n"
-"QPushButton:pressed { \n"
-" border: 2px solid rgb(255,107,107);\n"
-" background-color: rgb(51,51,51);\n"
-"}")
- self.bn_west.setText("")
- self.bn_west.setAutoDefault(False)
- self.bn_west.setObjectName("bn_west")
- self.gridLayout.addWidget(self.bn_west, 1, 2, 1, 1)
- self.lab_message = QtWidgets.QLabel(self.frame_bottom)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(12)
- self.lab_message.setFont(font)
- self.lab_message.setStyleSheet("color:rgb(255,255,255);")
- self.lab_message.setText("")
- self.lab_message.setWordWrap(True)
- self.lab_message.setObjectName("lab_message")
- self.gridLayout.addWidget(self.lab_message, 0, 1, 1, 3)
- self.verticalLayout_2.addWidget(self.frame_bottom)
- self.verticalLayout.addWidget(self.frame_2)
-
- self.retranslateUi(Dialog)
- QtCore.QMetaObject.connectSlotsByName(Dialog)
-
- def retranslateUi(self, Dialog):
- _translate = QtCore.QCoreApplication.translate
- Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
diff --git a/UI/ui_error.py b/UI/ui_error.py
deleted file mode 100644
index cfdbfe2..0000000
--- a/UI/ui_error.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Form implementation generated from reading ui file 'UI/ui_error.ui'
-#
-# Created by: PyQt5 UI code generator 5.15.10
-#
-# WARNING: Any manual changes made to this file will be lost when pyuic5 is
-# run again. Do not edit this file unless you know what you are doing.
-
-
-from PyQt5 import QtCore, QtGui, QtWidgets
-
-
-class Ui_Error(object):
- def setupUi(self, Error):
- Error.setObjectName("Error")
- Error.resize(250, 150)
- Error.setMinimumSize(QtCore.QSize(250, 150))
- Error.setMaximumSize(QtCore.QSize(250, 150))
- self.horizontalLayout = QtWidgets.QHBoxLayout(Error)
- self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout.setSpacing(0)
- self.horizontalLayout.setObjectName("horizontalLayout")
- self.frame = QtWidgets.QFrame(Error)
- self.frame.setStyleSheet("background:rgb(51,51,51);")
- self.frame.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame.setObjectName("frame")
- self.verticalLayout = QtWidgets.QVBoxLayout(self.frame)
- self.verticalLayout.setContentsMargins(2, 2, 2, 2)
- self.verticalLayout.setSpacing(0)
- self.verticalLayout.setObjectName("verticalLayout")
- self.frame_top = QtWidgets.QFrame(self.frame)
- self.frame_top.setMinimumSize(QtCore.QSize(0, 55))
- self.frame_top.setMaximumSize(QtCore.QSize(16777215, 55))
- self.frame_top.setStyleSheet("background:rgb(91,90,90);")
- self.frame_top.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_top.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_top.setObjectName("frame_top")
- self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_top)
- self.horizontalLayout_2.setContentsMargins(15, 5, 0, 0)
- self.horizontalLayout_2.setSpacing(5)
- self.horizontalLayout_2.setObjectName("horizontalLayout_2")
- self.lab_icon = QtWidgets.QLabel(self.frame_top)
- self.lab_icon.setMinimumSize(QtCore.QSize(35, 35))
- self.lab_icon.setMaximumSize(QtCore.QSize(35, 35))
- self.lab_icon.setText("")
- self.lab_icon.setObjectName("lab_icon")
- self.horizontalLayout_2.addWidget(self.lab_icon)
- self.lab_heading = QtWidgets.QLabel(self.frame_top)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(12)
- self.lab_heading.setFont(font)
- self.lab_heading.setStyleSheet("color:rgb(255,255,255);")
- self.lab_heading.setText("")
- self.lab_heading.setWordWrap(True)
- self.lab_heading.setObjectName("lab_heading")
- self.horizontalLayout_2.addWidget(self.lab_heading)
- self.verticalLayout.addWidget(self.frame_top)
- self.frame_bottom = QtWidgets.QFrame(self.frame)
- self.frame_bottom.setStyleSheet("background:rgb(91,90,90);")
- self.frame_bottom.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_bottom.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_bottom.setObjectName("frame_bottom")
- self.gridLayout = QtWidgets.QGridLayout(self.frame_bottom)
- self.gridLayout.setContentsMargins(-1, -1, -1, 0)
- self.gridLayout.setObjectName("gridLayout")
- self.bn_ok = QtWidgets.QPushButton(self.frame_bottom)
- self.bn_ok.setMinimumSize(QtCore.QSize(69, 25))
- self.bn_ok.setMaximumSize(QtCore.QSize(69, 25))
- self.bn_ok.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.bn_ok.setStyleSheet("QPushButton {\n"
-" border: 2px solid rgb(51,51,51);\n"
-" border-radius: 5px; \n"
-" color:rgb(255,255,255);\n"
-" background-color: rgb(51,51,51);\n"
-"}\n"
-"QPushButton:hover {\n"
-" border: 2px solid rgb(0,143,150);\n"
-" background-color: rgb(0,143,150);\n"
-"}\n"
-"QPushButton:pressed { \n"
-" border: 2px solid rgb(0,143,150);\n"
-" background-color: rgb(51,51,51);\n"
-"}\n"
-"")
- self.bn_ok.setText("")
- self.bn_ok.setObjectName("bn_ok")
- self.gridLayout.addWidget(self.bn_ok, 0, 0, 1, 1)
- self.verticalLayout.addWidget(self.frame_bottom)
- self.horizontalLayout.addWidget(self.frame)
-
- self.retranslateUi(Error)
- QtCore.QMetaObject.connectSlotsByName(Error)
-
- def retranslateUi(self, Error):
- _translate = QtCore.QCoreApplication.translate
- Error.setWindowTitle(_translate("Error", "Dialog"))
diff --git a/UI/ui_main.py b/UI/ui_main.py
deleted file mode 100644
index 96ad1ef..0000000
--- a/UI/ui_main.py
+++ /dev/null
@@ -1,1433 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Form implementation generated from reading ui file 'UI/ui_main.ui'
-#
-# Created by: PyQt5 UI code generator 5.15.10
-#
-# WARNING: Any manual changes made to this file will be lost when pyuic5 is
-# run again. Do not edit this file unless you know what you are doing.
-
-
-from PyQt5 import QtCore, QtGui, QtWidgets
-import UI.recources_rc
-
-
-class Ui_MainWindow(object):
- def setupUi(self, MainWindow):
- MainWindow.setObjectName("MainWindow")
- MainWindow.resize(800, 550)
- MainWindow.setMinimumSize(QtCore.QSize(800, 550))
- MainWindow.setWindowTitle("Stellaris DLC Unlocker")
- MainWindow.setToolTip("")
- MainWindow.setStatusTip("")
- MainWindow.setWhatsThis("")
- MainWindow.setAccessibleName("")
- self.centralwidget = QtWidgets.QWidget(MainWindow)
- self.centralwidget.setToolTip("")
- self.centralwidget.setStatusTip("")
- self.centralwidget.setWhatsThis("")
- self.centralwidget.setAccessibleName("")
- self.centralwidget.setStyleSheet("background:rgb(91,90,90);")
- self.centralwidget.setObjectName("centralwidget")
- self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
- self.verticalLayout.setContentsMargins(0, 0, 0, 0)
- self.verticalLayout.setSpacing(0)
- self.verticalLayout.setObjectName("verticalLayout")
- self.frame_top = QtWidgets.QFrame(self.centralwidget)
- self.frame_top.setMaximumSize(QtCore.QSize(16777215, 55))
- self.frame_top.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_top.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_top.setObjectName("frame_top")
- self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame_top)
- self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout.setSpacing(0)
- self.horizontalLayout.setObjectName("horizontalLayout")
- self.frame_top_east = QtWidgets.QFrame(self.frame_top)
- self.frame_top_east.setMaximumSize(QtCore.QSize(16777215, 55))
- self.frame_top_east.setStyleSheet("background:rgb(51,51,51);")
- self.frame_top_east.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_top_east.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_top_east.setObjectName("frame_top_east")
- self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.frame_top_east)
- self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_4.setSpacing(0)
- self.horizontalLayout_4.setObjectName("horizontalLayout_4")
- self.frame_appname = QtWidgets.QFrame(self.frame_top_east)
- self.frame_appname.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_appname.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_appname.setObjectName("frame_appname")
- self.horizontalLayout_10 = QtWidgets.QHBoxLayout(self.frame_appname)
- self.horizontalLayout_10.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_10.setSpacing(7)
- self.horizontalLayout_10.setObjectName("horizontalLayout_10")
- self.bn_home = QtWidgets.QPushButton(self.frame_appname)
- self.bn_home.setMinimumSize(QtCore.QSize(80, 55))
- self.bn_home.setMaximumSize(QtCore.QSize(160, 55))
- self.bn_home.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.bn_home.setToolTip("")
- self.bn_home.setStyleSheet("QPushButton {\n"
-" border: none;\n"
-" background-color: rgba(0,0,0,0);\n"
-"}\n"
-"QPushButton:hover {\n"
-" background-color: rgb(91,90,90);\n"
-"}\n"
-"QPushButton:pressed { \n"
-" background-color: rgba(0,0,0,0);\n"
-"}")
- self.bn_home.setText("")
- icon = QtGui.QIcon()
- icon.addPixmap(QtGui.QPixmap(":/icons/icons/1x/homeAsset 46.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
- self.bn_home.setIcon(icon)
- self.bn_home.setIconSize(QtCore.QSize(22, 22))
- self.bn_home.setShortcut("")
- self.bn_home.setFlat(True)
- self.bn_home.setObjectName("bn_home")
- self.horizontalLayout_10.addWidget(self.bn_home)
- self.lappname_title = QtWidgets.QLabel(self.frame_appname)
- font = QtGui.QFont()
- font.setFamily("Segoe UI Light")
- font.setPointSize(24)
- self.lappname_title.setFont(font)
- self.lappname_title.setToolTip("")
- self.lappname_title.setStyleSheet("color:rgb(255,255,255);")
- self.lappname_title.setText(" Stellaris DLC Unlocker
")
- self.lappname_title.setObjectName("lappname_title")
- self.horizontalLayout_10.addWidget(self.lappname_title)
- self.horizontalLayout_4.addWidget(self.frame_appname)
- self.frame_user = QtWidgets.QFrame(self.frame_top_east)
- self.frame_user.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_user.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_user.setObjectName("frame_user")
- self.horizontalLayout_9 = QtWidgets.QHBoxLayout(self.frame_user)
- self.horizontalLayout_9.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_9.setSpacing(0)
- self.horizontalLayout_9.setObjectName("horizontalLayout_9")
- self.formLayout = QtWidgets.QFormLayout()
- self.formLayout.setObjectName("formLayout")
- self.server_status = QtWidgets.QRadioButton(self.frame_user)
- self.server_status.setEnabled(True)
- self.server_status.setLayoutDirection(QtCore.Qt.RightToLeft)
- self.server_status.setStyleSheet("QRadioButton::indicator {\n"
-" width: 10px;\n"
-" height: 10px;\n"
-"}\n"
-"\n"
-"QRadioButton::indicator::unchecked {\n"
-" background-color: rgb(255,107,107);\n"
-" border-radius: 5px;\n"
-"}\n"
-"\n"
-"QRadioButton::indicator::checked {\n"
-" background-color: rgb(0,143,150);\n"
-" border-radius: 5px;\n"
-"}\n"
-"\n"
-"QRadioButton {\n"
-" color: white;\n"
-"}")
- self.server_status.setAutoExclusive(False)
- self.server_status.setObjectName("server_status")
- self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.server_status)
- self.gh_status = QtWidgets.QRadioButton(self.frame_user)
- self.gh_status.setEnabled(True)
- self.gh_status.setLayoutDirection(QtCore.Qt.RightToLeft)
- self.gh_status.setStyleSheet("QRadioButton::indicator {\n"
-" width: 10px;\n"
-" height: 10px;\n"
-"}\n"
-"\n"
-"QRadioButton::indicator::unchecked {\n"
-" background-color: rgb(255,107,107);\n"
-" border-radius: 5px;\n"
-"}\n"
-"\n"
-"QRadioButton::indicator::checked {\n"
-" background-color: rgb(0,143,150);\n"
-" border-radius: 5px;\n"
-"}\n"
-"\n"
-"QRadioButton {\n"
-" color: white;\n"
-"}")
- self.gh_status.setCheckable(True)
- self.gh_status.setChecked(False)
- self.gh_status.setAutoExclusive(False)
- self.gh_status.setObjectName("gh_status")
- self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.gh_status)
- self.horizontalLayout_9.addLayout(self.formLayout)
- self.horizontalLayout_4.addWidget(self.frame_user)
- self.frame_max = QtWidgets.QFrame(self.frame_top_east)
- self.frame_max.setMinimumSize(QtCore.QSize(55, 55))
- self.frame_max.setMaximumSize(QtCore.QSize(55, 55))
- self.frame_max.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_max.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_max.setObjectName("frame_max")
- self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.frame_max)
- self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_6.setSpacing(0)
- self.horizontalLayout_6.setObjectName("horizontalLayout_6")
- self.frame_min = QtWidgets.QFrame(self.frame_max)
- self.frame_min.setMinimumSize(QtCore.QSize(55, 55))
- self.frame_min.setMaximumSize(QtCore.QSize(55, 55))
- self.frame_min.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_min.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_min.setObjectName("frame_min")
- self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.frame_min)
- self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_7.setSpacing(0)
- self.horizontalLayout_7.setObjectName("horizontalLayout_7")
- self.horizontalLayout_6.addWidget(self.frame_min)
- self.horizontalLayout_4.addWidget(self.frame_max)
- self.frame_close = QtWidgets.QFrame(self.frame_top_east)
- self.frame_close.setMinimumSize(QtCore.QSize(55, 55))
- self.frame_close.setMaximumSize(QtCore.QSize(55, 55))
- self.frame_close.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_close.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_close.setObjectName("frame_close")
- self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.frame_close)
- self.horizontalLayout_5.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_5.setSpacing(0)
- self.horizontalLayout_5.setObjectName("horizontalLayout_5")
- self.bn_close = QtWidgets.QPushButton(self.frame_close)
- self.bn_close.setMaximumSize(QtCore.QSize(55, 55))
- self.bn_close.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.bn_close.setToolTip("")
- self.bn_close.setStyleSheet("QPushButton {\n"
-" border: none;\n"
-" background-color: rgba(0,0,0,0);\n"
-"}\n"
-"QPushButton:hover {\n"
-" background-color: rgb(255,107,107);\n"
-"}\n"
-"QPushButton:pressed { \n"
-" background-color: rgba(0,0,0,0);\n"
-"}")
- self.bn_close.setText("")
- icon1 = QtGui.QIcon()
- icon1.addPixmap(QtGui.QPixmap(":/icons/icons/1x/closeAsset 43.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
- self.bn_close.setIcon(icon1)
- self.bn_close.setIconSize(QtCore.QSize(22, 22))
- self.bn_close.setShortcut("")
- self.bn_close.setFlat(True)
- self.bn_close.setObjectName("bn_close")
- self.horizontalLayout_5.addWidget(self.bn_close)
- self.horizontalLayout_4.addWidget(self.frame_close)
- self.horizontalLayout.addWidget(self.frame_top_east)
- self.verticalLayout.addWidget(self.frame_top)
- self.frame_bottom = QtWidgets.QFrame(self.centralwidget)
- self.frame_bottom.setToolTip("")
- self.frame_bottom.setStatusTip("")
- self.frame_bottom.setWhatsThis("")
- self.frame_bottom.setAccessibleName("")
- self.frame_bottom.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_bottom.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_bottom.setObjectName("frame_bottom")
- self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_bottom)
- self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_2.setSpacing(0)
- self.horizontalLayout_2.setObjectName("horizontalLayout_2")
- self.frame_bottom_west = QtWidgets.QFrame(self.frame_bottom)
- self.frame_bottom_west.setMinimumSize(QtCore.QSize(80, 0))
- self.frame_bottom_west.setMaximumSize(QtCore.QSize(80, 16777215))
- self.frame_bottom_west.setAccessibleName("")
- self.frame_bottom_west.setStyleSheet("background:rgb(51,51,51);")
- self.frame_bottom_west.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_bottom_west.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_bottom_west.setObjectName("frame_bottom_west")
- self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame_bottom_west)
- self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
- self.verticalLayout_3.setSpacing(0)
- self.verticalLayout_3.setObjectName("verticalLayout_3")
- self.frame_home = QtWidgets.QFrame(self.frame_bottom_west)
- self.frame_home.setMinimumSize(QtCore.QSize(80, 55))
- self.frame_home.setMaximumSize(QtCore.QSize(160, 55))
- self.frame_home.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_home.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_home.setObjectName("frame_home")
- self.horizontalLayout_15 = QtWidgets.QHBoxLayout(self.frame_home)
- self.horizontalLayout_15.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_15.setSpacing(0)
- self.horizontalLayout_15.setObjectName("horizontalLayout_15")
- self.frame_bug = QtWidgets.QFrame(self.frame_home)
- self.frame_bug.setMinimumSize(QtCore.QSize(80, 55))
- self.frame_bug.setMaximumSize(QtCore.QSize(160, 55))
- self.frame_bug.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_bug.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_bug.setObjectName("frame_bug")
- self.horizontalLayout_16 = QtWidgets.QHBoxLayout(self.frame_bug)
- self.horizontalLayout_16.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_16.setSpacing(0)
- self.horizontalLayout_16.setObjectName("horizontalLayout_16")
- self.bn_bug = QtWidgets.QPushButton(self.frame_bug)
- self.bn_bug.setMinimumSize(QtCore.QSize(80, 55))
- self.bn_bug.setMaximumSize(QtCore.QSize(160, 55))
- self.bn_bug.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.bn_bug.setToolTip("")
- self.bn_bug.setStyleSheet("QPushButton {\n"
-" border: none;\n"
-" background-color: rgba(0,0,0,0);\n"
-"}\n"
-"QPushButton:hover {\n"
-" background-color: rgb(91,90,90);\n"
-"}\n"
-"QPushButton:pressed { \n"
-" background-color: rgba(0,0,0,0);\n"
-"}")
- self.bn_bug.setText("")
- icon2 = QtGui.QIcon()
- icon2.addPixmap(QtGui.QPixmap(":/icons/icons/1x/bugAsset 47.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
- self.bn_bug.setIcon(icon2)
- self.bn_bug.setIconSize(QtCore.QSize(22, 22))
- self.bn_bug.setFlat(True)
- self.bn_bug.setObjectName("bn_bug")
- self.horizontalLayout_16.addWidget(self.bn_bug)
- self.horizontalLayout_15.addWidget(self.frame_bug)
- self.verticalLayout_3.addWidget(self.frame_home)
- self.frame_8 = QtWidgets.QFrame(self.frame_bottom_west)
- self.frame_8.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_8.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_8.setObjectName("frame_8")
- self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.frame_8)
- self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)
- self.verticalLayout_4.setSpacing(0)
- self.verticalLayout_4.setObjectName("verticalLayout_4")
- spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.verticalLayout_4.addItem(spacerItem)
- self.version_label = QtWidgets.QLabel(self.frame_8)
- self.version_label.setMinimumSize(QtCore.QSize(0, 50))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setKerning(True)
- self.version_label.setFont(font)
- self.version_label.setAccessibleName("")
- self.version_label.setLayoutDirection(QtCore.Qt.LeftToRight)
- self.version_label.setStyleSheet("color:rgb(255,255,255);")
- self.version_label.setText("%version%")
- self.version_label.setAlignment(QtCore.Qt.AlignCenter)
- self.version_label.setObjectName("version_label")
- self.verticalLayout_4.addWidget(self.version_label)
- self.verticalLayout_3.addWidget(self.frame_8)
- self.horizontalLayout_2.addWidget(self.frame_bottom_west)
- self.frame_bottom_east = QtWidgets.QFrame(self.frame_bottom)
- self.frame_bottom_east.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_bottom_east.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_bottom_east.setObjectName("frame_bottom_east")
- self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame_bottom_east)
- self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
- self.verticalLayout_2.setSpacing(0)
- self.verticalLayout_2.setObjectName("verticalLayout_2")
- self.frame = QtWidgets.QFrame(self.frame_bottom_east)
- self.frame.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame.setObjectName("frame")
- self.horizontalLayout_14 = QtWidgets.QHBoxLayout(self.frame)
- self.horizontalLayout_14.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_14.setSpacing(0)
- self.horizontalLayout_14.setObjectName("horizontalLayout_14")
- self.stackedWidget = QtWidgets.QStackedWidget(self.frame)
- self.stackedWidget.setMinimumSize(QtCore.QSize(0, 55))
- self.stackedWidget.setStyleSheet("")
- self.stackedWidget.setObjectName("stackedWidget")
- self.main_page = QtWidgets.QWidget()
- self.main_page.setToolTip("")
- self.main_page.setStatusTip("")
- self.main_page.setWhatsThis("")
- self.main_page.setAccessibleName("")
- self.main_page.setStyleSheet("background:rgb(91,90,90);")
- self.main_page.setObjectName("main_page")
- self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.main_page)
- self.verticalLayout_8.setContentsMargins(5, 5, 5, 5)
- self.verticalLayout_8.setSpacing(5)
- self.verticalLayout_8.setObjectName("verticalLayout_8")
- self.horizontalLayout_13 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_13.setContentsMargins(-1, 0, -1, -1)
- self.horizontalLayout_13.setObjectName("horizontalLayout_13")
- self.first_main_page_label = QtWidgets.QLabel(self.main_page)
- self.first_main_page_label.setMinimumSize(QtCore.QSize(0, 55))
- self.first_main_page_label.setMaximumSize(QtCore.QSize(16777215, 55))
- font = QtGui.QFont()
- font.setFamily("Segoe UI Semilight")
- font.setPointSize(24)
- self.first_main_page_label.setFont(font)
- self.first_main_page_label.setStyleSheet("QLabel {\n"
-" color:rgb(255,255,255);\n"
-"}")
- self.first_main_page_label.setObjectName("first_main_page_label")
- self.horizontalLayout_13.addWidget(self.first_main_page_label)
- self.gridLayout_3 = QtWidgets.QGridLayout()
- self.gridLayout_3.setHorizontalSpacing(10)
- self.gridLayout_3.setVerticalSpacing(0)
- self.gridLayout_3.setObjectName("gridLayout_3")
- self.en_lang = QtWidgets.QRadioButton(self.main_page)
- self.en_lang.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.en_lang.setStyleSheet("padding-left: 5px")
- self.en_lang.setText("")
- self.en_lang.setChecked(True)
- self.en_lang.setObjectName("en_lang")
- self.gridLayout_3.addWidget(self.en_lang, 1, 1, 1, 1)
- self.ru_lang = QtWidgets.QRadioButton(self.main_page)
- self.ru_lang.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.ru_lang.setStyleSheet("padding-left: 5px")
- self.ru_lang.setText("")
- self.ru_lang.setObjectName("ru_lang")
- self.gridLayout_3.addWidget(self.ru_lang, 1, 2, 1, 1)
- self.cn_lang = QtWidgets.QRadioButton(self.main_page)
- self.cn_lang.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.cn_lang.setStyleSheet("padding-left: 5px")
- self.cn_lang.setText("")
- self.cn_lang.setObjectName("cn_lang")
- self.gridLayout_3.addWidget(self.cn_lang, 1, 3, 1, 1)
- self.label = QtWidgets.QLabel(self.main_page)
- self.label.setMaximumSize(QtCore.QSize(50, 16777215))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(11)
- self.label.setFont(font)
- self.label.setLayoutDirection(QtCore.Qt.LeftToRight)
- self.label.setStyleSheet("QLabel {\n"
-" color:rgb(255,255,255);\n"
-"}")
- self.label.setText("EN")
- self.label.setAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignHCenter)
- self.label.setObjectName("label")
- self.gridLayout_3.addWidget(self.label, 0, 1, 1, 1)
- self.label_3 = QtWidgets.QLabel(self.main_page)
- self.label_3.setMaximumSize(QtCore.QSize(50, 16777215))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(11)
- self.label_3.setFont(font)
- self.label_3.setStyleSheet("QLabel {\n"
-" color:rgb(255,255,255);\n"
-"}")
- self.label_3.setText("РУ")
- self.label_3.setAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignHCenter)
- self.label_3.setObjectName("label_3")
- self.gridLayout_3.addWidget(self.label_3, 0, 2, 1, 1)
- self.label_4 = QtWidgets.QLabel(self.main_page)
- self.label_4.setMaximumSize(QtCore.QSize(50, 16777215))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(11)
- self.label_4.setFont(font)
- self.label_4.setStyleSheet("QLabel {\n"
-" color:rgb(255,255,255);\n"
-"}")
- self.label_4.setText("简体")
- self.label_4.setAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignHCenter)
- self.label_4.setObjectName("label_4")
- self.gridLayout_3.addWidget(self.label_4, 0, 3, 1, 1)
- spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
- self.gridLayout_3.addItem(spacerItem1, 1, 4, 1, 1)
- spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.gridLayout_3.addItem(spacerItem2, 1, 0, 1, 1)
- spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.gridLayout_3.addItem(spacerItem3, 0, 0, 1, 1)
- self.horizontalLayout_13.addLayout(self.gridLayout_3)
- self.verticalLayout_8.addLayout(self.horizontalLayout_13)
- self.frame_2 = QtWidgets.QFrame(self.main_page)
- self.frame_2.setEnabled(True)
- self.frame_2.setMinimumSize(QtCore.QSize(0, 370))
- self.frame_2.setMaximumSize(QtCore.QSize(16777215, 16777215))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(12)
- self.frame_2.setFont(font)
- self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_2.setObjectName("frame_2")
- self.gridLayout_2 = QtWidgets.QGridLayout(self.frame_2)
- self.gridLayout_2.setContentsMargins(5, 5, 5, 5)
- self.gridLayout_2.setHorizontalSpacing(5)
- self.gridLayout_2.setVerticalSpacing(0)
- self.gridLayout_2.setObjectName("gridLayout_2")
- self.main_page_browser = QtWidgets.QTextBrowser(self.frame_2)
- self.main_page_browser.setEnabled(True)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(10)
- self.main_page_browser.setFont(font)
- self.main_page_browser.setAcceptDrops(False)
- self.main_page_browser.setToolTip("")
- self.main_page_browser.setStatusTip("")
- self.main_page_browser.setWhatsThis("")
- self.main_page_browser.setAccessibleName("")
- self.main_page_browser.setStyleSheet("\n"
-"QScrollBar::groove:vertical {\n"
-" background: red;\n"
-" width:5px\n"
-"}\n"
-"\n"
-"QScrollBar::handle:vertical {\n"
-" height: 10px;\n"
-" background:rgb(0,143,170);\n"
-" margin:0 -8px\n"
-"}\n"
-"\n"
-"QScrollBar::add-page:vertical {\n"
-" background:rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QScrollBar::sub-page:vertical {\n"
-" background:rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QListWidget {\n"
-" color: white;\n"
-" font-size: 15px;\n"
-"};\n"
-"color: white;\n"
-"border: none;\n"
-"background-color: rgb(51,51,51);\n"
-"")
- self.main_page_browser.setInputMethodHints(QtCore.Qt.ImhNone)
- self.main_page_browser.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
- self.main_page_browser.setPlaceholderText("")
- self.main_page_browser.setObjectName("main_page_browser")
- self.gridLayout_2.addWidget(self.main_page_browser, 0, 0, 1, 1)
- self.verticalLayout_8.addWidget(self.frame_2)
- spacerItem4 = QtWidgets.QSpacerItem(20, 162, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.verticalLayout_8.addItem(spacerItem4)
- self.frame_3 = QtWidgets.QFrame(self.main_page)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.frame_3.sizePolicy().hasHeightForWidth())
- self.frame_3.setSizePolicy(sizePolicy)
- self.frame_3.setMinimumSize(QtCore.QSize(0, 50))
- self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
- self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
- self.frame_3.setObjectName("frame_3")
- self.horizontalLayout_18 = QtWidgets.QHBoxLayout(self.frame_3)
- self.horizontalLayout_18.setObjectName("horizontalLayout_18")
- spacerItem5 = QtWidgets.QSpacerItem(602, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.horizontalLayout_18.addItem(spacerItem5)
- self.next_button = QtWidgets.QPushButton(self.frame_3)
- self.next_button.setMinimumSize(QtCore.QSize(79, 25))
- self.next_button.setMaximumSize(QtCore.QSize(69, 25))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(12)
- self.next_button.setFont(font)
- self.next_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.next_button.setStyleSheet("QPushButton {\n"
-" border: 2px solid rgb(51,51,51);\n"
-" border-radius: 5px; \n"
-" color:rgb(255,255,255);\n"
-" background-color: rgb(51,51,51);\n"
-"}\n"
-"QPushButton:hover {\n"
-" border: 2px solid rgb(0,143,150);\n"
-" background-color: rgb(0,143,150);\n"
-"}\n"
-"QPushButton:pressed { \n"
-" border: 2px solid rgb(0,143,150);\n"
-" background-color: rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QPushButton:disabled { \n"
-" border-radius: 5px; \n"
-" border: 2px solid rgb(112,112,112);\n"
-" background-color: rgb(112,112,112);\n"
-"}")
- self.next_button.setObjectName("next_button")
- self.horizontalLayout_18.addWidget(self.next_button)
- self.verticalLayout_8.addWidget(self.frame_3)
- self.stackedWidget.addWidget(self.main_page)
- self.work_page = QtWidgets.QWidget()
- self.work_page.setStyleSheet("background:rgb(91,90,90);")
- self.work_page.setObjectName("work_page")
- self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.work_page)
- self.verticalLayout_7.setContentsMargins(5, 5, 5, 5)
- self.verticalLayout_7.setSpacing(5)
- self.verticalLayout_7.setObjectName("verticalLayout_7")
- self.work_page_label = QtWidgets.QLabel(self.work_page)
- self.work_page_label.setMinimumSize(QtCore.QSize(0, 55))
- self.work_page_label.setMaximumSize(QtCore.QSize(16777215, 55))
- font = QtGui.QFont()
- font.setFamily("Segoe UI Semilight")
- font.setPointSize(24)
- self.work_page_label.setFont(font)
- self.work_page_label.setToolTip("")
- self.work_page_label.setStyleSheet("color:rgb(255,255,255);")
- self.work_page_label.setObjectName("work_page_label")
- self.verticalLayout_7.addWidget(self.work_page_label)
- self.frame_bug_main = QtWidgets.QFrame(self.work_page)
- self.frame_bug_main.setMinimumSize(QtCore.QSize(0, 200))
- self.frame_bug_main.setMaximumSize(QtCore.QSize(16777215, 300))
- self.frame_bug_main.setToolTip("")
- self.frame_bug_main.setAutoFillBackground(False)
- self.frame_bug_main.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_bug_main.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_bug_main.setObjectName("frame_bug_main")
- self.gridLayout = QtWidgets.QGridLayout(self.frame_bug_main)
- self.gridLayout.setObjectName("gridLayout")
- self.horizontalLayout_19 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_19.setSpacing(0)
- self.horizontalLayout_19.setObjectName("horizontalLayout_19")
- self.alternative_unloc_checkbox = QtWidgets.QCheckBox(self.frame_bug_main)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(14)
- self.alternative_unloc_checkbox.setFont(font)
- self.alternative_unloc_checkbox.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.alternative_unloc_checkbox.setToolTip("")
- self.alternative_unloc_checkbox.setLayoutDirection(QtCore.Qt.RightToLeft)
- self.alternative_unloc_checkbox.setStyleSheet("QCheckBox {\n"
-" color:rgb(255,255,255);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator {\n"
-" width: 12px;\n"
-" height: 12px;\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:unchecked {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(91,90,90);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:unchecked:pressed {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(0,143,170);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:checked {\n"
-" background-color:rgb(0,143,150);\n"
-" border: 2px solid rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:checked:pressed {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(91,90,90);\n"
-"}\n"
-"")
- self.alternative_unloc_checkbox.setObjectName("alternative_unloc_checkbox")
- self.horizontalLayout_19.addWidget(self.alternative_unloc_checkbox)
- self.label_2 = QtWidgets.QLabel(self.frame_bug_main)
- font = QtGui.QFont()
- font.setPointSize(10)
- self.label_2.setFont(font)
- self.label_2.setCursor(QtGui.QCursor(QtCore.Qt.WhatsThisCursor))
- self.label_2.setStyleSheet("padding-bottom: 10px;")
- self.label_2.setText("?")
- self.label_2.setObjectName("label_2")
- self.horizontalLayout_19.addWidget(self.label_2)
- spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.horizontalLayout_19.addItem(spacerItem6)
- self.gridLayout.addLayout(self.horizontalLayout_19, 2, 1, 1, 1)
- self.lab_bullet3 = QtWidgets.QLabel(self.frame_bug_main)
- self.lab_bullet3.setMaximumSize(QtCore.QSize(5, 16777215))
- self.lab_bullet3.setText("")
- self.lab_bullet3.setPixmap(QtGui.QPixmap("UI\\../../../Desktop/unlocker-v2_design/Minimalistic-Flat-Modern-GUI-Template-master/icons/1x/bulletAsset 54.png"))
- self.lab_bullet3.setObjectName("lab_bullet3")
- self.gridLayout.addWidget(self.lab_bullet3, 3, 0, 1, 1)
- self.lab_bullet = QtWidgets.QLabel(self.frame_bug_main)
- self.lab_bullet.setMaximumSize(QtCore.QSize(5, 16777215))
- self.lab_bullet.setText("")
- self.lab_bullet.setPixmap(QtGui.QPixmap("UI\\../../../Desktop/unlocker-v2_design/Minimalistic-Flat-Modern-GUI-Template-master/icons/1x/bulletAsset 54.png"))
- self.lab_bullet.setAlignment(QtCore.Qt.AlignCenter)
- self.lab_bullet.setObjectName("lab_bullet")
- self.gridLayout.addWidget(self.lab_bullet, 0, 0, 1, 1)
- spacerItem7 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
- self.gridLayout.addItem(spacerItem7, 0, 7, 1, 1)
- spacerItem8 = QtWidgets.QSpacerItem(421, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.gridLayout.addItem(spacerItem8, 5, 6, 1, 1)
- self.dlc_status_widget = QtWidgets.QListWidget(self.frame_bug_main)
- self.dlc_status_widget.setEnabled(True)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(self.dlc_status_widget.sizePolicy().hasHeightForWidth())
- self.dlc_status_widget.setSizePolicy(sizePolicy)
- self.dlc_status_widget.setMinimumSize(QtCore.QSize(230, 150))
- self.dlc_status_widget.setMaximumSize(QtCore.QSize(460, 16777215))
- font = QtGui.QFont()
- font.setPointSize(-1)
- self.dlc_status_widget.setFont(font)
- self.dlc_status_widget.setToolTip("")
- self.dlc_status_widget.setStatusTip("")
- self.dlc_status_widget.setWhatsThis("")
- self.dlc_status_widget.setAccessibleName("")
- self.dlc_status_widget.setStyleSheet("\n"
-"QScrollBar::groove:vertical {\n"
-" background: red;\n"
-" width:5px\n"
-"}\n"
-"\n"
-"QScrollBar::handle:vertical {\n"
-" height: 10px;\n"
-" background:rgb(0,143,170);\n"
-" margin:0 -8px\n"
-"}\n"
-"\n"
-"QScrollBar::add-page:vertical {\n"
-" background:rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QScrollBar::sub-page:vertical {\n"
-" background:rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QListWidget {\n"
-" color: white;\n"
-" font-size: 15px;\n"
-"};\n"
-"border: none;\n"
-"background-color: rgb(51,51,51);\n"
-"\n"
-"")
- self.dlc_status_widget.setAutoScroll(False)
- self.dlc_status_widget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
- self.dlc_status_widget.setProperty("showDropIndicator", False)
- self.dlc_status_widget.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
- self.dlc_status_widget.setObjectName("dlc_status_widget")
- item = QtWidgets.QListWidgetItem()
- item.setText("DLC Status")
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(12)
- item.setFont(font)
- item.setFlags(QtCore.Qt.ItemIsEnabled)
- self.dlc_status_widget.addItem(item)
- self.gridLayout.addWidget(self.dlc_status_widget, 0, 6, 1, 1)
- self.lab_bullet2 = QtWidgets.QLabel(self.frame_bug_main)
- self.lab_bullet2.setMaximumSize(QtCore.QSize(5, 16777215))
- self.lab_bullet2.setText("")
- self.lab_bullet2.setPixmap(QtGui.QPixmap("UI\\../../../Desktop/unlocker-v2_design/Minimalistic-Flat-Modern-GUI-Template-master/icons/1x/bulletAsset 54.png"))
- self.lab_bullet2.setObjectName("lab_bullet2")
- self.gridLayout.addWidget(self.lab_bullet2, 1, 0, 1, 1)
- self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_8.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
- self.horizontalLayout_8.setObjectName("horizontalLayout_8")
- self.game_path_label = QtWidgets.QLabel(self.frame_bug_main)
- self.game_path_label.setMinimumSize(QtCore.QSize(0, 0))
- self.game_path_label.setMaximumSize(QtCore.QSize(16777215, 25))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(14)
- self.game_path_label.setFont(font)
- self.game_path_label.setToolTip("")
- self.game_path_label.setStatusTip("")
- self.game_path_label.setWhatsThis("")
- self.game_path_label.setStyleSheet("color:rgb(255,255,255);")
- self.game_path_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
- self.game_path_label.setObjectName("game_path_label")
- self.horizontalLayout_8.addWidget(self.game_path_label)
- self.game_path_line = QtWidgets.QLineEdit(self.frame_bug_main)
- self.game_path_line.setMinimumSize(QtCore.QSize(200, 25))
- self.game_path_line.setAccessibleName("")
- self.game_path_line.setStyleSheet("QLineEdit {\n"
-" color:rgb(255,255,255);\n"
-" border:2px solid rgb(51,51,51);\n"
-" border-radius:4px;\n"
-" background:rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QLineEdit:disabled {\n"
-" color:rgb(255,255,255);\n"
-" border:2px solid rgb(112,112,112);\n"
-" border-radius:4px;\n"
-" background:rgb(112,112,112);\n"
-"}")
- self.game_path_line.setText("")
- self.game_path_line.setPlaceholderText("")
- self.game_path_line.setObjectName("game_path_line")
- self.horizontalLayout_8.addWidget(self.game_path_line)
- self.path_choose_button = QtWidgets.QPushButton(self.frame_bug_main)
- self.path_choose_button.setMinimumSize(QtCore.QSize(60, 25))
- self.path_choose_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.path_choose_button.setToolTip("")
- self.path_choose_button.setStatusTip("")
- self.path_choose_button.setWhatsThis("")
- self.path_choose_button.setAccessibleName("")
- self.path_choose_button.setStyleSheet("QPushButton {\n"
-" border: 2px solid rgb(51,51,51);\n"
-" border-radius: 5px; \n"
-" color:rgb(255,255,255);\n"
-" background-color: rgb(51,51,51);\n"
-"}\n"
-"QPushButton:hover {\n"
-" border: 2px solid rgb(0,143,150);\n"
-" background-color: rgb(0,143,150);\n"
-"}\n"
-"QPushButton:pressed { \n"
-" border: 2px solid rgb(0,143,150);\n"
-" background-color: rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QPushButton:disabled { \n"
-" border-radius: 5px; \n"
-" border: 2px solid rgb(112,112,112);\n"
-" background-color: rgb(112,112,112);\n"
-"}")
- self.path_choose_button.setObjectName("path_choose_button")
- self.horizontalLayout_8.addWidget(self.path_choose_button)
- self.gridLayout.addLayout(self.horizontalLayout_8, 0, 1, 1, 1)
- self.horizontalLayout_23 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_23.setObjectName("horizontalLayout_23")
- spacerItem9 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.horizontalLayout_23.addItem(spacerItem9)
- self.unlock_button = QtWidgets.QPushButton(self.frame_bug_main)
- self.unlock_button.setMinimumSize(QtCore.QSize(100, 25))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(12)
- self.unlock_button.setFont(font)
- self.unlock_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.unlock_button.setStyleSheet("QPushButton {\n"
-" border: 2px solid rgb(51,51,51);\n"
-" border-radius: 5px; \n"
-" color:rgb(255,255,255);\n"
-" background-color: rgb(51,51,51);\n"
-"}\n"
-"QPushButton:hover {\n"
-" border: 2px solid rgb(0,143,150);\n"
-" background-color: rgb(0,143,150);\n"
-"}\n"
-"QPushButton:pressed { \n"
-" border: 2px solid rgb(0,143,150);\n"
-" background-color: rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QPushButton:disabled { \n"
-" border-radius: 5px; \n"
-" border: 2px solid rgb(112,112,112);\n"
-" background-color: rgb(112,112,112);\n"
-"}")
- self.unlock_button.setObjectName("unlock_button")
- self.horizontalLayout_23.addWidget(self.unlock_button)
- spacerItem10 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.horizontalLayout_23.addItem(spacerItem10)
- self.gridLayout.addLayout(self.horizontalLayout_23, 5, 1, 1, 1)
- self.horizontalLayout_17 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_17.setContentsMargins(0, -1, 100, -1)
- self.horizontalLayout_17.setSpacing(0)
- self.horizontalLayout_17.setObjectName("horizontalLayout_17")
- self.full_reinstall_checkbox = QtWidgets.QCheckBox(self.frame_bug_main)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(14)
- self.full_reinstall_checkbox.setFont(font)
- self.full_reinstall_checkbox.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.full_reinstall_checkbox.setToolTip("")
- self.full_reinstall_checkbox.setLayoutDirection(QtCore.Qt.RightToLeft)
- self.full_reinstall_checkbox.setAutoFillBackground(False)
- self.full_reinstall_checkbox.setStyleSheet("QCheckBox {\n"
-" color:rgb(255,255,255);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator {\n"
-" width: 12px;\n"
-" height: 12px;\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:unchecked {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(91,90,90);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:unchecked:pressed {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(0,143,170);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:checked {\n"
-" background-color:rgb(0,143,150);\n"
-" border: 2px solid rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:checked:pressed {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(91,90,90);\n"
-"}\n"
-"")
- self.full_reinstall_checkbox.setTristate(False)
- self.full_reinstall_checkbox.setObjectName("full_reinstall_checkbox")
- self.horizontalLayout_17.addWidget(self.full_reinstall_checkbox)
- self.full_reinstall_tooltip = QtWidgets.QLabel(self.frame_bug_main)
- font = QtGui.QFont()
- font.setPointSize(10)
- font.setBold(False)
- font.setItalic(False)
- font.setUnderline(False)
- font.setWeight(50)
- font.setStrikeOut(False)
- font.setKerning(True)
- font.setStyleStrategy(QtGui.QFont.PreferDefault)
- self.full_reinstall_tooltip.setFont(font)
- self.full_reinstall_tooltip.setCursor(QtGui.QCursor(QtCore.Qt.WhatsThisCursor))
- self.full_reinstall_tooltip.setMouseTracking(False)
- self.full_reinstall_tooltip.setAcceptDrops(False)
- self.full_reinstall_tooltip.setToolTipDuration(-1)
- self.full_reinstall_tooltip.setStatusTip("")
- self.full_reinstall_tooltip.setWhatsThis("")
- self.full_reinstall_tooltip.setAccessibleName("")
- self.full_reinstall_tooltip.setStyleSheet("padding-bottom: 10px;")
- self.full_reinstall_tooltip.setText("?")
- self.full_reinstall_tooltip.setObjectName("full_reinstall_tooltip")
- self.horizontalLayout_17.addWidget(self.full_reinstall_tooltip)
- spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.horizontalLayout_17.addItem(spacerItem11)
- self.gridLayout.addLayout(self.horizontalLayout_17, 1, 1, 1, 1)
- self.horizontalLayout_22 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_22.setSpacing(0)
- self.horizontalLayout_22.setObjectName("horizontalLayout_22")
- self.skip_launcher_reinstall_checbox = QtWidgets.QCheckBox(self.frame_bug_main)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(14)
- self.skip_launcher_reinstall_checbox.setFont(font)
- self.skip_launcher_reinstall_checbox.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.skip_launcher_reinstall_checbox.setToolTip("")
- self.skip_launcher_reinstall_checbox.setLayoutDirection(QtCore.Qt.RightToLeft)
- self.skip_launcher_reinstall_checbox.setStyleSheet("QCheckBox {\n"
-" color:rgb(255,255,255);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator {\n"
-" width: 12px;\n"
-" height: 12px;\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:unchecked {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(91,90,90);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:unchecked:pressed {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(0,143,170);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:checked {\n"
-" background-color:rgb(0,143,150);\n"
-" border: 2px solid rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:checked:pressed {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(91,90,90);\n"
-"}\n"
-"")
- self.skip_launcher_reinstall_checbox.setObjectName("skip_launcher_reinstall_checbox")
- self.horizontalLayout_22.addWidget(self.skip_launcher_reinstall_checbox)
- self.skip_launcher_reinstall_tooltip = QtWidgets.QLabel(self.frame_bug_main)
- font = QtGui.QFont()
- font.setPointSize(10)
- self.skip_launcher_reinstall_tooltip.setFont(font)
- self.skip_launcher_reinstall_tooltip.setCursor(QtGui.QCursor(QtCore.Qt.WhatsThisCursor))
- self.skip_launcher_reinstall_tooltip.setStyleSheet("padding-bottom: 10px;")
- self.skip_launcher_reinstall_tooltip.setText("?")
- self.skip_launcher_reinstall_tooltip.setObjectName("skip_launcher_reinstall_tooltip")
- self.horizontalLayout_22.addWidget(self.skip_launcher_reinstall_tooltip)
- spacerItem12 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.horizontalLayout_22.addItem(spacerItem12)
- self.gridLayout.addLayout(self.horizontalLayout_22, 3, 1, 1, 1)
- self.verticalLayout_7.addWidget(self.frame_bug_main)
- self.horizontalLayout_20 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_20.setContentsMargins(-1, 0, -1, -1)
- self.horizontalLayout_20.setObjectName("horizontalLayout_20")
- spacerItem13 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.horizontalLayout_20.addItem(spacerItem13)
- self.verticalLayout_11 = QtWidgets.QVBoxLayout()
- self.verticalLayout_11.setContentsMargins(50, -1, 50, -1)
- self.verticalLayout_11.setSpacing(2)
- self.verticalLayout_11.setObjectName("verticalLayout_11")
- self.progress_label = QtWidgets.QLabel(self.work_page)
- self.progress_label.setMaximumSize(QtCore.QSize(16777215, 25))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(14)
- font.setBold(True)
- font.setWeight(75)
- self.progress_label.setFont(font)
- self.progress_label.setStyleSheet("color:rgb(255,255,255);")
- self.progress_label.setObjectName("progress_label")
- self.verticalLayout_11.addWidget(self.progress_label)
- self.download_files_radio = QtWidgets.QRadioButton(self.work_page)
- self.download_files_radio.setEnabled(False)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(10)
- self.download_files_radio.setFont(font)
- self.download_files_radio.setStyleSheet("QRadioButton::indicator {\n"
-" width: 10px;\n"
-" height: 10px;\n"
-"}\n"
-"\n"
-"QRadioButton::indicator::unchecked {\n"
-" background-color: rgb(255,107,107);\n"
-" border-radius: 5px;\n"
-"}\n"
-"\n"
-"QRadioButton::indicator::checked {\n"
-" background-color: rgb(0,143,150);\n"
-" border-radius: 5px;\n"
-"}\n"
-"\n"
-"QRadioButton {\n"
-" color: white;\n"
-"}")
- self.download_files_radio.setCheckable(True)
- self.download_files_radio.setAutoRepeat(False)
- self.download_files_radio.setAutoExclusive(False)
- self.download_files_radio.setObjectName("download_files_radio")
- self.verticalLayout_11.addWidget(self.download_files_radio)
- self.launcher_reinstall_radio = QtWidgets.QRadioButton(self.work_page)
- self.launcher_reinstall_radio.setEnabled(False)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(10)
- self.launcher_reinstall_radio.setFont(font)
- self.launcher_reinstall_radio.setStyleSheet("QRadioButton::indicator {\n"
-" width: 10px;\n"
-" height: 10px;\n"
-"}\n"
-"\n"
-"QRadioButton::indicator::unchecked {\n"
-" background-color: rgb(255,107,107);\n"
-" border-radius: 5px;\n"
-"}\n"
-"\n"
-"QRadioButton::indicator::checked {\n"
-" background-color: rgb(0,143,150);\n"
-" border-radius: 5px;\n"
-"}\n"
-"\n"
-"QRadioButton {\n"
-" color: white;\n"
-"}")
- self.launcher_reinstall_radio.setAutoExclusive(False)
- self.launcher_reinstall_radio.setObjectName("launcher_reinstall_radio")
- self.verticalLayout_11.addWidget(self.launcher_reinstall_radio)
- self.copy_files_radio = QtWidgets.QRadioButton(self.work_page)
- self.copy_files_radio.setEnabled(False)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(10)
- self.copy_files_radio.setFont(font)
- self.copy_files_radio.setStyleSheet("QRadioButton::indicator {\n"
-" width: 10px;\n"
-" height: 10px;\n"
-"}\n"
-"\n"
-"QRadioButton::indicator::unchecked {\n"
-" background-color: rgb(255,107,107);\n"
-" border-radius: 5px;\n"
-"}\n"
-"\n"
-"QRadioButton::indicator::checked {\n"
-" background-color: rgb(0,143,150);\n"
-" border-radius: 5px;\n"
-"}\n"
-"\n"
-"QRadioButton {\n"
-" color: white;\n"
-"}")
- self.copy_files_radio.setAutoExclusive(False)
- self.copy_files_radio.setObjectName("copy_files_radio")
- self.verticalLayout_11.addWidget(self.copy_files_radio)
- self.horizontalLayout_20.addLayout(self.verticalLayout_11)
- spacerItem14 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.horizontalLayout_20.addItem(spacerItem14)
- self.verticalLayout_6 = QtWidgets.QVBoxLayout()
- self.verticalLayout_6.setContentsMargins(-1, 0, -1, -1)
- self.verticalLayout_6.setObjectName("verticalLayout_6")
- self.dlc_download_label = QtWidgets.QLabel(self.work_page)
- self.dlc_download_label.setEnabled(True)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(12)
- self.dlc_download_label.setFont(font)
- self.dlc_download_label.setMouseTracking(False)
- self.dlc_download_label.setStyleSheet("color: white")
- self.dlc_download_label.setAlignment(QtCore.Qt.AlignCenter)
- self.dlc_download_label.setObjectName("dlc_download_label")
- self.verticalLayout_6.addWidget(self.dlc_download_label)
- self.dlc_download_progress_bar = QtWidgets.QProgressBar(self.work_page)
- self.dlc_download_progress_bar.setEnabled(True)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- self.dlc_download_progress_bar.setFont(font)
- self.dlc_download_progress_bar.setAccessibleName("")
- self.dlc_download_progress_bar.setStyleSheet("QProgressBar\n"
-"{\n"
-" color:rgb(255,255,255);\n"
-" background-color :rgb(51,51,51);\n"
-" border : 2px;\n"
-" border-radius:4px;\n"
-"}\n"
-"\n"
-"QProgressBar::chunk{\n"
-" border : 2px;\n"
-" border-radius:4px;\n"
-" background-color:rgb(0,143,170);\n"
-"}")
- self.dlc_download_progress_bar.setProperty("value", 0)
- self.dlc_download_progress_bar.setAlignment(QtCore.Qt.AlignCenter)
- self.dlc_download_progress_bar.setTextVisible(True)
- self.dlc_download_progress_bar.setOrientation(QtCore.Qt.Horizontal)
- self.dlc_download_progress_bar.setInvertedAppearance(False)
- self.dlc_download_progress_bar.setTextDirection(QtWidgets.QProgressBar.TopToBottom)
- self.dlc_download_progress_bar.setFormat("%p%")
- self.dlc_download_progress_bar.setObjectName("dlc_download_progress_bar")
- self.verticalLayout_6.addWidget(self.dlc_download_progress_bar)
- self.current_dlc_label = QtWidgets.QLabel(self.work_page)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(12)
- self.current_dlc_label.setFont(font)
- self.current_dlc_label.setStyleSheet("color: white")
- self.current_dlc_label.setAlignment(QtCore.Qt.AlignCenter)
- self.current_dlc_label.setObjectName("current_dlc_label")
- self.verticalLayout_6.addWidget(self.current_dlc_label)
- self.current_dlc_progress_bar = QtWidgets.QProgressBar(self.work_page)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- self.current_dlc_progress_bar.setFont(font)
- self.current_dlc_progress_bar.setStyleSheet("QProgressBar\n"
-"{\n"
-" color:rgb(255,255,255);\n"
-" background-color :rgb(51,51,51);\n"
-" border : 2px;\n"
-" border-radius:4px;\n"
-"}\n"
-"\n"
-"QProgressBar::chunk{\n"
-" border : 2px;\n"
-" border-radius:4px;\n"
-" background-color:rgb(0,143,170);\n"
-"}")
- self.current_dlc_progress_bar.setProperty("value", 0)
- self.current_dlc_progress_bar.setAlignment(QtCore.Qt.AlignCenter)
- self.current_dlc_progress_bar.setFormat("%p%")
- self.current_dlc_progress_bar.setObjectName("current_dlc_progress_bar")
- self.verticalLayout_6.addWidget(self.current_dlc_progress_bar)
- self.speed_label = QtWidgets.QLabel(self.work_page)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(9)
- self.speed_label.setFont(font)
- self.speed_label.setStyleSheet("color: white")
- self.speed_label.setText("")
- self.speed_label.setAlignment(QtCore.Qt.AlignCenter)
- self.speed_label.setObjectName("speed_label")
- self.verticalLayout_6.addWidget(self.speed_label)
- self.horizontalLayout_20.addLayout(self.verticalLayout_6)
- self.verticalLayout_7.addLayout(self.horizontalLayout_20)
- spacerItem15 = QtWidgets.QSpacerItem(20, 197, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.verticalLayout_7.addItem(spacerItem15)
- self.horizontalLayout_21 = QtWidgets.QHBoxLayout()
- self.horizontalLayout_21.setContentsMargins(-1, 10, -1, -1)
- self.horizontalLayout_21.setObjectName("horizontalLayout_21")
- self.formLayout_2 = QtWidgets.QFormLayout()
- self.formLayout_2.setContentsMargins(-1, -1, 10, -1)
- self.formLayout_2.setObjectName("formLayout_2")
- self.old_dlc_text = QtWidgets.QTextEdit(self.work_page)
- self.old_dlc_text.setEnabled(False)
- self.old_dlc_text.setMinimumSize(QtCore.QSize(590, 0))
- self.old_dlc_text.setMaximumSize(QtCore.QSize(16777215, 40))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- self.old_dlc_text.setFont(font)
- self.old_dlc_text.setInputMethodHints(QtCore.Qt.ImhNone)
- self.old_dlc_text.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.old_dlc_text.setUndoRedoEnabled(False)
- self.old_dlc_text.setTextInteractionFlags(QtCore.Qt.NoTextInteraction)
- self.old_dlc_text.setObjectName("old_dlc_text")
- self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.old_dlc_text)
- self.update_dlc_button = QtWidgets.QCheckBox(self.work_page)
- self.update_dlc_button.setMinimumSize(QtCore.QSize(300, 25))
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(13)
- self.update_dlc_button.setFont(font)
- self.update_dlc_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.update_dlc_button.setStyleSheet("QCheckBox {\n"
-" color:rgb(255,255,255);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator {\n"
-" width: 12px;\n"
-" height: 12px;\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:unchecked {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(91,90,90);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:unchecked:pressed {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(0,143,170);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:checked {\n"
-" background-color:rgb(0,143,150);\n"
-" border: 2px solid rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:checked:pressed {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(91,90,90);\n"
-"}\n"
-"")
- self.update_dlc_button.setChecked(True)
- self.update_dlc_button.setObjectName("update_dlc_button")
- self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.update_dlc_button)
- self.horizontalLayout_21.addLayout(self.formLayout_2)
- spacerItem16 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
- self.horizontalLayout_21.addItem(spacerItem16)
- self.verticalLayout_10 = QtWidgets.QVBoxLayout()
- self.verticalLayout_10.setContentsMargins(-1, 10, -1, -1)
- self.verticalLayout_10.setObjectName("verticalLayout_10")
- self.lauch_game_checkbox = QtWidgets.QCheckBox(self.work_page)
- font = QtGui.QFont()
- font.setPointSize(10)
- self.lauch_game_checkbox.setFont(font)
- self.lauch_game_checkbox.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.lauch_game_checkbox.setLayoutDirection(QtCore.Qt.LeftToRight)
- self.lauch_game_checkbox.setStyleSheet("QCheckBox {\n"
-" color:rgb(255,255,255);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator {\n"
-" width: 12px;\n"
-" height: 12px;\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:unchecked {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(91,90,90);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:unchecked:pressed {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(0,143,170);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:checked {\n"
-" background-color:rgb(0,143,150);\n"
-" border: 2px solid rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QCheckBox::indicator:checked:pressed {\n"
-" border:2px solid rgb(51,51,51);\n"
-" background:rgb(91,90,90);\n"
-"}\n"
-"")
- self.lauch_game_checkbox.setChecked(True)
- self.lauch_game_checkbox.setObjectName("lauch_game_checkbox")
- self.verticalLayout_10.addWidget(self.lauch_game_checkbox)
- spacerItem17 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
- self.verticalLayout_10.addItem(spacerItem17)
- self.done_button = QtWidgets.QPushButton(self.work_page)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(12)
- self.done_button.setFont(font)
- self.done_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
- self.done_button.setStyleSheet("QPushButton {\n"
-" border: 2px solid rgb(51,51,51);\n"
-" border-radius: 5px; \n"
-" color:rgb(255,255,255);\n"
-" background-color: rgb(51,51,51);\n"
-"}\n"
-"QPushButton:hover {\n"
-" border: 2px solid rgb(0,143,150);\n"
-" background-color: rgb(0,143,150);\n"
-"}\n"
-"QPushButton:pressed { \n"
-" border: 2px solid rgb(0,143,150);\n"
-" background-color: rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QPushButton:disabled { \n"
-" border-radius: 5px; \n"
-" border: 2px solid rgb(112,112,112);\n"
-" background-color: rgb(112,112,112);\n"
-"}")
- self.done_button.setShortcut("")
- self.done_button.setObjectName("done_button")
- self.verticalLayout_10.addWidget(self.done_button)
- self.horizontalLayout_21.addLayout(self.verticalLayout_10)
- self.verticalLayout_7.addLayout(self.horizontalLayout_21)
- self.stackedWidget.addWidget(self.work_page)
- self.bug_page = QtWidgets.QWidget()
- self.bug_page.setObjectName("bug_page")
- self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.bug_page)
- self.verticalLayout_5.setContentsMargins(5, 5, 5, 5)
- self.verticalLayout_5.setSpacing(5)
- self.verticalLayout_5.setObjectName("verticalLayout_5")
- self.bug_page_title = QtWidgets.QLabel(self.bug_page)
- self.bug_page_title.setMinimumSize(QtCore.QSize(0, 55))
- self.bug_page_title.setMaximumSize(QtCore.QSize(16777215, 55))
- font = QtGui.QFont()
- font.setFamily("Segoe UI Semilight")
- font.setPointSize(24)
- self.bug_page_title.setFont(font)
- self.bug_page_title.setStyleSheet("QLabel {\n"
-" color:rgb(255,255,255);\n"
-"}")
- self.bug_page_title.setObjectName("bug_page_title")
- self.verticalLayout_5.addWidget(self.bug_page_title)
- self.log_widget = QtWidgets.QListWidget(self.bug_page)
- self.log_widget.setEnabled(True)
- font = QtGui.QFont()
- font.setPointSize(-1)
- self.log_widget.setFont(font)
- self.log_widget.setToolTip("")
- self.log_widget.setStatusTip("")
- self.log_widget.setWhatsThis("")
- self.log_widget.setAccessibleName("")
- self.log_widget.setStyleSheet("\n"
-"QScrollBar::groove:vertical {\n"
-" background: red;\n"
-" width:5px\n"
-"}\n"
-"\n"
-"QScrollBar::handle:vertical {\n"
-" height: 10px;\n"
-" background:rgb(0,143,170);\n"
-" margin:0 -8px\n"
-"}\n"
-"\n"
-"QScrollBar::add-page:vertical {\n"
-" background:rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QScrollBar::sub-page:vertical {\n"
-" background:rgb(51,51,51);\n"
-"}\n"
-"\n"
-"QListWidget {\n"
-" color: white;\n"
-" font-size: 15px;\n"
-"};\n"
-"border: none;\n"
-"background-color: rgb(51,51,51);\n"
-"\n"
-"")
- self.log_widget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
- self.log_widget.setProperty("showDropIndicator", False)
- self.log_widget.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
- self.log_widget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectItems)
- self.log_widget.setSelectionRectVisible(False)
- self.log_widget.setObjectName("log_widget")
- item = QtWidgets.QListWidgetItem()
- item.setText("Nothing to display")
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(13)
- item.setFont(font)
- item.setFlags(QtCore.Qt.ItemIsEnabled)
- self.log_widget.addItem(item)
- self.verticalLayout_5.addWidget(self.log_widget)
- self.stackedWidget.addWidget(self.bug_page)
- self.horizontalLayout_14.addWidget(self.stackedWidget)
- self.verticalLayout_2.addWidget(self.frame)
- self.frame_low = QtWidgets.QFrame(self.frame_bottom_east)
- self.frame_low.setMinimumSize(QtCore.QSize(0, 20))
- self.frame_low.setMaximumSize(QtCore.QSize(16777215, 20))
- self.frame_low.setAccessibleName("")
- self.frame_low.setStyleSheet("")
- self.frame_low.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_low.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_low.setObjectName("frame_low")
- self.horizontalLayout_11 = QtWidgets.QHBoxLayout(self.frame_low)
- self.horizontalLayout_11.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_11.setSpacing(0)
- self.horizontalLayout_11.setObjectName("horizontalLayout_11")
- self.frame_tab = QtWidgets.QFrame(self.frame_low)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- self.frame_tab.setFont(font)
- self.frame_tab.setStyleSheet("background:rgb(51,51,51);")
- self.frame_tab.setFrameShape(QtWidgets.QFrame.NoFrame)
- self.frame_tab.setFrameShadow(QtWidgets.QFrame.Plain)
- self.frame_tab.setObjectName("frame_tab")
- self.horizontalLayout_12 = QtWidgets.QHBoxLayout(self.frame_tab)
- self.horizontalLayout_12.setContentsMargins(0, 0, 0, 0)
- self.horizontalLayout_12.setSpacing(0)
- self.horizontalLayout_12.setObjectName("horizontalLayout_12")
- self.bottom_label_github = QtWidgets.QLabel(self.frame_tab)
- font = QtGui.QFont()
- font.setFamily("Segoe UI")
- font.setPointSize(10)
- self.bottom_label_github.setFont(font)
- self.bottom_label_github.setAccessibleName("")
- self.bottom_label_github.setStyleSheet("color:rgb(255,255,255);")
- self.bottom_label_github.setText("
GitHub: github.com/seuyh/stellaris-dlc-unlocker
")
- self.bottom_label_github.setAlignment(QtCore.Qt.AlignCenter)
- self.bottom_label_github.setObjectName("bottom_label_github")
- self.horizontalLayout_12.addWidget(self.bottom_label_github)
- self.horizontalLayout_11.addWidget(self.frame_tab)
- self.verticalLayout_2.addWidget(self.frame_low)
- self.horizontalLayout_2.addWidget(self.frame_bottom_east)
- self.verticalLayout.addWidget(self.frame_bottom)
- MainWindow.setCentralWidget(self.centralwidget)
-
- self.retranslateUi(MainWindow)
- self.stackedWidget.setCurrentIndex(0)
- QtCore.QMetaObject.connectSlotsByName(MainWindow)
-
- def retranslateUi(self, MainWindow):
- _translate = QtCore.QCoreApplication.translate
- self.server_status.setText(_translate("MainWindow", "Server connection"))
- self.gh_status.setText(_translate("MainWindow", "Github conncection"))
- self.first_main_page_label.setText(_translate("MainWindow", "Welcome"))
- self.main_page_browser.setHtml(_translate("MainWindow", "\n"
-" \n"
-"Stellaris DLC Unlocker
\n"
-"
\n"
-"Requirements :
\n"
-" License : Steam.
\n"
-"
\n"
-"Installation :
\n"
-" Follow the installer instructions. Installation is almost entirely automatic.
\n"
-"Terms Of Use
\n"
-"
\n"
-"1. This unlocker is distributed absolutely free of charge. Any commercial use of this unlocker is prohibited.
\n"
-"
\n"
-"2. THIS UNLOCKER IS PROVIDED "AS IS". NO WARRANTIES ARE PROVIDED OR IMPLIED. YOU USE THIS MODIFICATION OF THE ORIGINAL GAME AT YOUR OWN RISK. THE AUTHORS OF THE MODIFICATION WILL NOT BE LIABLE FOR ANY LOSSES OR DATA CORRUPTION, ANY LOST PROFITS IN THE PROCESS OF USE OR MISUSE OF THIS MODIFICATION.
\n"
-"
\n"
-"3. All rights not expressly granted here are reserved by the copyright holders.
\n"
-"
\n"
-"4. Installation and use of this modification implies that you have read and understand the terms of this license agreement and agree to them.
\n"
-"
"))
- self.next_button.setText(_translate("MainWindow", "Next"))
- self.work_page_label.setText(_translate("MainWindow", "Unlock settings"))
- self.alternative_unloc_checkbox.setText(_translate("MainWindow", "Alternative unlock"))
- self.label_2.setToolTip(_translate("MainWindow", "Uses a different unlock method
"))
- __sortingEnabled = self.dlc_status_widget.isSortingEnabled()
- self.dlc_status_widget.setSortingEnabled(False)
- self.dlc_status_widget.setSortingEnabled(__sortingEnabled)
- self.game_path_label.setText(_translate("MainWindow", "Stellaris path", "sadsadsa"))
- self.path_choose_button.setText(_translate("MainWindow", "Open"))
- self.unlock_button.setText(_translate("MainWindow", "Unlock"))
- self.full_reinstall_checkbox.setText(_translate("MainWindow", "Full launcher reinstallation"))
- self.full_reinstall_tooltip.setToolTip(_translate("MainWindow", "This function will delete all saves and presets of mods.
It is only needed if something did not work during the normal installation
"))
- self.skip_launcher_reinstall_checbox.setText(_translate("MainWindow", "Skip launcher reinstall"))
- self.skip_launcher_reinstall_tooltip.setToolTip(_translate("MainWindow", "It is used if it is impossible to automatically reinstall the launcher.
The program will assume that the launcher has already been reinstalled before
"))
- self.progress_label.setText(_translate("MainWindow", "Progress"))
- self.download_files_radio.setText(_translate("MainWindow", "Download files"))
- self.launcher_reinstall_radio.setText(_translate("MainWindow", "Launcher reinstall"))
- self.copy_files_radio.setText(_translate("MainWindow", "Copy files"))
- self.dlc_download_label.setText(_translate("MainWindow", "DLC Download progress"))
- self.current_dlc_label.setText(_translate("MainWindow", "Current DLC progress"))
- self.old_dlc_text.setHtml(_translate("MainWindow", "\n"
-" \n"
-"Old DLCs detected! You can just update it while unlocking
"))
- self.update_dlc_button.setText(_translate("MainWindow", "Update old DLCs"))
- self.lauch_game_checkbox.setText(_translate("MainWindow", "Launch game"))
- self.done_button.setText(_translate("MainWindow", "Done"))
- self.bug_page_title.setText(_translate("MainWindow", "Log"))
- __sortingEnabled = self.log_widget.isSortingEnabled()
- self.log_widget.setSortingEnabled(False)
- self.log_widget.setSortingEnabled(__sortingEnabled)
diff --git a/UI_logic/DialogWindow.py b/UI_logic/DialogWindow.py
deleted file mode 100644
index 91adbcf..0000000
--- a/UI_logic/DialogWindow.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from PyQt5.QtCore import Qt
-from PyQt5.QtWidgets import QDialog
-from PyQt5 import QtGui
-
-from UI.ui_dialog import Ui_Dialog
-import UI.recources_rc
-
-
-class dialogUi(QDialog):
- def __init__(self, parent=None):
-
- super(dialogUi, self).__init__(parent)
- self.d = Ui_Dialog()
- self.d.setupUi(self)
- self.setWindowFlags(Qt.FramelessWindowHint)
-
-
-
- self.d.bn_close.clicked.connect(lambda: self.close())
-
- self.d.bn_east.clicked.connect(lambda: self.close())
- self.d.bn_west.clicked.connect(lambda: self.close())
-
- self.dragPos = self.pos()
- def movedialogWindow(event):
- if event.buttons() == Qt.LeftButton:
- self.move(self.pos() + event.globalPos() - self.dragPos)
- self.dragPos = event.globalPos()
- event.accept()
-
- self.d.frame_top.mouseMoveEvent = movedialogWindow
-
- def mousePressEvent(self, event):
- self.dragPos = event.globalPos()
-
- def dialogConstrict(self, heading, message, btn1, btn2, icon, parent=None):
- self.d.lab_heading.setText(str(heading))
- self.d.lab_message.setText(str(message))
- self.d.bn_east.setText(str(btn2))
- self.d.bn_west.setText(str(btn1))
- pixmap = QtGui.QPixmap(icon)
- self.d.lab_icon.setPixmap(pixmap)
- if parent:
- parent_rect = parent.frameGeometry()
- self.move(
- parent_rect.left() + (parent_rect.width() - self.width()) // 2,
- parent_rect.top() + (parent_rect.height() - self.height()) // 2
- )
-
- try:
- self.d.bn_east.clicked.disconnect()
- self.d.bn_west.clicked.disconnect()
- except TypeError:
- pass
-
- self.d.bn_west.clicked.connect(self.reject)
- self.d.bn_east.clicked.connect(self.accept)
\ No newline at end of file
diff --git a/UI_logic/ErrorWindow.py b/UI_logic/ErrorWindow.py
deleted file mode 100644
index 3d7bfe1..0000000
--- a/UI_logic/ErrorWindow.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from PyQt5.QtCore import Qt
-from PyQt5.QtWidgets import QDialog, QApplication, QDesktopWidget
-from PyQt5 import QtGui
-
-from UI.ui_error import Ui_Error
-import UI.recources_rc
-
-
-class errorUi(QDialog):
- def __init__(self, parent=None):
- super(errorUi, self).__init__(parent)
- self.e = Ui_Error()
- self.e.setupUi(self)
- self.setWindowFlags(Qt.FramelessWindowHint)
- self.setAttribute(Qt.WA_TranslucentBackground)
- self.screen = QDesktopWidget().screenGeometry()
-
- self.e.bn_ok.clicked.connect(self.close_app)
-
- self.dragPos = self.pos()
-
- def moveWindow(event):
- # MOVE WINDOW
- if event.buttons() == Qt.LeftButton:
- self.move(self.pos() + event.globalPos() - self.dragPos)
- self.dragPos = event.globalPos()
- event.accept()
-
- self.e.frame_top.mouseMoveEvent = moveWindow
- self.exitApp = False
-
- def mousePressEvent(self, event):
- self.dragPos = event.globalPos()
-
- def errorConstrict(self, heading, icon, btnOk, parent=None, exitApp=False):
- self.exitApp = exitApp
- self.e.lab_heading.setText(heading)
- self.e.bn_ok.setText(btnOk)
- pixmap2 = QtGui.QPixmap(icon)
- self.e.lab_icon.setPixmap(pixmap2)
-
- if parent:
- parent_rect = parent.frameGeometry()
- self.move(
- parent_rect.left() + (parent_rect.width() - self.width()) // 2,
- parent_rect.top() + (parent_rect.height() - self.height()) // 2
- )
- else:
- x = (self.screen.width() - self.width()) // 2
- y = (self.screen.height() - self.height()) // 2
- self.move(x, y)
-
- def close_app(self):
- if self.exitApp:
- QApplication.quit()
- else:
- self.close()
\ No newline at end of file
diff --git a/UI_logic/MainWindow.py b/UI_logic/MainWindow.py
deleted file mode 100644
index 3631042..0000000
--- a/UI_logic/MainWindow.py
+++ /dev/null
@@ -1,854 +0,0 @@
-import os
-from shutil import rmtree, copytree
-from sys import argv
-from zipfile import ZipFile, BadZipFile
-
-import requests
-import winreg
-from PyQt5.QtGui import QDesktopServices, QColor, QBrush, QIcon
-from PyQt5.QtWidgets import QMainWindow, QFileDialog, QListWidgetItem, QProgressDialog, QApplication
-from PyQt5.QtCore import Qt, QUrl, QTimer, QTranslator, QLocale, QObject, pyqtSignal, QThread
-from subprocess import run, CREATE_NO_WINDOW
-from pathlib import Path
-
-import UI.ui_main as ui_main
-from Libs.ConnectionCheck import ConnectionCheckThread
-from Libs.LauncherReinstall import ReinstallThread
-from Libs.logger import Logger
-from UI_logic.DialogWindow import dialogUi
-from UI_logic.ErrorWindow import errorUi
-from Libs.GamePath import stellaris_path, launcher_path, get_user_logon_name
-from Libs.ServerData import get_dlc_data, get_server_data
-from Libs.CreamApiMaker import CreamAPI
-from Libs.DownloadThread import DownloaderThread
-from Libs.MD5Check import MD5
-
-
-class SetupWorker(QObject):
- log_message = pyqtSignal(str)
- initial_data_ready = pyqtSignal(dict)
- update_info = pyqtSignal(dict)
- dlc_check_complete = pyqtSignal(list)
- connection_check_ready = pyqtSignal(object)
- finished = pyqtSignal()
-
- def __init__(self, parent=None):
- super().__init__(parent)
- self.GITHUB_API_URL = "https://api.github.com/repos/seuyh/stellaris-dlc-unlocker"
- self.server_url = None
- self.server_alturl = None
- self.alt_launcher_name = None
- self.latest_version = None
-
- def run(self):
- try:
- dlc_data = get_dlc_data()
- try:
- user_logon_name = get_user_logon_name()
- except:
- user_logon_name = os.getlogin()
-
- server_data = get_server_data()
- self.server_url = server_data.get('url')
- self.server_alturl = server_data.get('alturl')
- self.alt_launcher_name = server_data.get('altlauncher')
- self.latest_version = server_data.get('version')
- path = stellaris_path()
-
- initial_data = {
- 'dlc_data': dlc_data,
- 'user_logon_name': user_logon_name,
- 'server_url': self.server_url,
- 'server_alturl': self.server_alturl,
- 'alt_launcher_name': self.alt_launcher_name,
- 'latest_version': self.latest_version,
- 'path': path
- }
- self.initial_data_ready.emit(initial_data)
-
- self.kill_process('Paradox Launcher.exe')
- self.kill_process('stellaris.exe')
-
- if self.server_url:
- connection_thread = ConnectionCheckThread(self.server_url, self.GITHUB_API_URL)
- self.connection_check_ready.emit(connection_thread)
-
- if path and self.server_url:
- md5_checker = MD5(f"{path}\\dlc", self.server_url)
- not_updated_dlc = md5_checker.check_files()
- self.dlc_check_complete.emit(not_updated_dlc)
- else:
- self.dlc_check_complete.emit([])
-
- try:
- print(f"Checking updates via GitHub: {self.GITHUB_API_URL}")
- releases_url = f"{self.GITHUB_API_URL}/releases/latest"
- response = requests.get(releases_url, timeout=5)
-
- if response.status_code == 200:
- update_info = response.json()
- update_info['source'] = 'github'
- else:
- raise Exception(f"GitHub returned {response.status_code}")
-
- except Exception as e:
- print(f"Update check failed/skipped ({e}). Using server fallback.")
- update_info = {
- 'tag_name': self.latest_version,
- 'source': 'server'
- }
-
- self.update_info.emit(update_info)
-
- except Exception as e:
- print(f"CRITICAL ERROR IN WORKER: {e}")
- self.log_message.emit(f"Critical error: {e}")
-
- finally:
- self.finished.emit()
-
- def kill_process(self, process_name):
- self.log_message.emit(f'Killing {process_name}')
- try:
- run(["taskkill", "/F", "/IM", process_name], check=True, creationflags=CREATE_NO_WINDOW)
- except:
- self.log_message.emit(f'No process named {process_name}')
-
-
-class MainWindow(QMainWindow, ui_main.Ui_MainWindow):
- def __init__(self):
- super(MainWindow, self).__init__()
- self.translator = QTranslator()
- self.setWindowFlags(Qt.FramelessWindowHint)
- self.setupUi(self)
- self.setWindowState(Qt.WindowActive)
-
- self.error = errorUi()
- self.diag = dialogUi()
- self.game_path = None
- self.not_updated_dlc = []
- self.dlc_data = []
- self.user_logon_name = ''
- self.server_url, self.server_alturl, self.alt_launcher_name, self.latest_version = '', '', '', ''
- self.connection_thread = None
-
- self.draggable_elements = [self.frame_user, self.server_status, self.gh_status, self.lappname_title,
- self.frame_top]
- for element in self.draggable_elements:
- element.mousePressEvent = self.mousePressEvent
- element.mouseMoveEvent = self.mouseMoveEvent
- element.mouseReleaseEvent = self.mouseReleaseEvent
-
- self.is_dragging = False
- self.last_mouse_position = None
- self.launcher_downloaded = None
- self.continued = False
- self.downloaded_launcher_dir = None
- self.parent_directory = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
- self.is_downloading = False
- self.download_thread = None
- self.creamapidone = False
-
- self.current_version = '2.52'
- self.version_label.setText(f'Ver. {str(self.current_version)}')
-
- self.next_button.setEnabled(False)
- self.original_next_button_text = self.next_button.text()
- self.spinner_chars = ['/', '-', '\\', '|']
- self.spinner_index = 0
- self.spinner_timer = QTimer(self)
- self.spinner_timer.timeout.connect(self.update_spinner)
-
- self.copy_files_radio.setVisible(False)
- self.download_files_radio.setVisible(False)
- self.launcher_reinstall_radio.setVisible(False)
- self.progress_label.setVisible(False)
- self.dlc_download_label.setVisible(False)
- self.dlc_download_progress_bar.setVisible(False)
- self.current_dlc_label.setVisible(False)
- self.current_dlc_progress_bar.setVisible(False)
- self.lauch_game_checkbox.setVisible(False)
- self.done_button.setVisible(False)
- self.speed_label.setVisible(False)
- self.update_dlc_button.setVisible(False)
- self.old_dlc_text.setVisible(False)
-
- #self.gh_status.setVisible(False)
-
- self.en_lang.toggled.connect(self.switch_to_english)
- self.ru_lang.toggled.connect(self.switch_to_russian)
- self.cn_lang.toggled.connect(self.switch_to_chinese)
-
- self.setWindowTitle("Stellaris DLC Unlocker")
- self.setWindowIcon(QIcon(f'{self.parent_directory}/UI/icons/stellaris.png'))
-
- self.bn_bug.clicked.connect(lambda: self.stackedWidget.setCurrentIndex(2))
- self.path_choose_button.clicked.connect(self.browse_folder)
- self.next_button.clicked.connect(
- lambda: (
- setattr(self, 'continued', True),
- self.stackedWidget.setCurrentIndex(1),
- self.old_dlc_show()
- )
- )
- self.bn_home.clicked.connect(lambda: self.stackedWidget.setCurrentIndex(1 if self.continued else 0))
- self.unlock_button.clicked.connect(self.unlock)
- self.done_button.clicked.connect(self.finish)
- self.bn_close.clicked.connect(
- lambda: self.close() if self.dialogexec(self.tr("Close"), self.tr("Exit Unlocker?"), self.tr("No"),
- self.tr("Yes")) else None)
- self.bottom_label_github.setText(
- ''
- ''
- 'GitHub Repo '
- ' | '
- ''
- 'Site '
- '
'
- )
- self.bottom_label_github.linkActivated.connect(self.open_link_in_browser)
- #self.bottom_label_github.setVisible(False)
-
- self.logger = Logger('unlocker.log', self.log_widget)
- self.log_widget.clear()
-
- self.setup_thread = QThread()
- self.setup_worker = SetupWorker()
- self.setup_worker.moveToThread(self.setup_thread)
-
- self.setup_thread.started.connect(self.setup_worker.run)
- self.setup_worker.finished.connect(self.on_loading_complete)
- self.setup_worker.finished.connect(self.setup_thread.quit)
- self.setup_worker.finished.connect(self.setup_worker.deleteLater)
- self.setup_thread.finished.connect(self.setup_thread.deleteLater)
- self.setup_worker.initial_data_ready.connect(self.on_initial_data_ready)
- self.setup_worker.dlc_check_complete.connect(self.on_dlc_check_complete)
- self.setup_worker.update_info.connect(self.on_update_info_ready)
- self.setup_worker.connection_check_ready.connect(self.on_connection_check_ready)
- self.setup_worker.log_message.connect(self.add_log_message)
-
- def add_log_message(self, message):
- print(message)
-
- def update_spinner(self):
- self.spinner_index = (self.spinner_index + 1) % len(self.spinner_chars)
- self.next_button.setText(self.spinner_chars[self.spinner_index])
-
- def on_loading_complete(self):
- print("All background tasks are complete.")
- self.spinner_timer.stop()
- self.next_button.setText(self.original_next_button_text)
- self.retranslateUi(self)
- self.next_button.setEnabled(True)
-
- def on_initial_data_ready(self, data):
- self.dlc_data = data['dlc_data']
- self.user_logon_name = data['user_logon_name']
- self.server_url = data['server_url']
- self.server_alturl = data['server_alturl']
- self.alt_launcher_name = data['alt_launcher_name']
- self.latest_version = data['latest_version']
-
- if data['path']:
- path = data['path']
- print(f'Auto detected game path: {path}')
- self.game_path_line.setText(path)
- self.game_path = os.path.normpath(path)
- else:
- print('Cant detect game path')
-
- def on_dlc_check_complete(self, not_updated_dlc):
- self.not_updated_dlc = not_updated_dlc
- if self.game_path:
- self.loadDLCNames()
-
- def on_connection_check_ready(self, connection_thread):
- self.connection_thread = connection_thread
- self.connection_thread.github_status_checked.connect(self.handle_github_status)
- self.connection_thread.server_status_checked.connect(self.handle_server_status)
- self.connection_thread.start()
-
- def on_update_info_ready(self, latest_release):
- if not latest_release:
- return
-
- remote_version = latest_release.get('tag_name')
- source = latest_release.get('source', 'server')
- current_version = self.current_version
-
- if remote_version and remote_version > current_version:
- if self.dialogexec(self.tr('New version'),
- self.tr(f'New version {remote_version} found!'),
- self.tr('Cancel'), self.tr('Update')):
-
- url_to_open = None
-
- if source == 'github':
- for asset in latest_release.get('assets', []):
- if asset.get('name', '').endswith('.exe'):
- url_to_open = asset.get('browser_download_url')
- break
-
- if not url_to_open:
- url_to_open = f"https://{self.server_url}/unlocker/Stellaris-DLC-Unlocker.exe"
-
- self.open_link_in_browser(url_to_open)
- self.close()
-
- elif remote_version and remote_version < current_version:
- self.errorexec(self.tr("Beta"), self.tr("Ok"), exitApp=False)
- else:
- print(f"Unlocker is up to date. (Checked via {source})")
-
- def get_app_language(self):
- lang = QLocale.system().name().lower()
- print(f"Detected language: {lang}")
- if not lang:
- return "en"
- lang = lang.lower()
- if lang.startswith("ru"):
- return "ru"
- elif lang.startswith("zh"):
- return "zh"
- else:
- return "en"
-
- def apply_initial_language(self):
- self.set_language_radio(self.get_app_language())
-
- def set_language_radio(self, lang):
- if lang == "ru":
- self.ru_lang.setChecked(True)
- elif lang == "zh":
- self.cn_lang.setChecked(True)
- else:
- self.en_lang.setChecked(True)
- self.apply_language(lang)
-
- def apply_language(self, lang):
- app = QApplication.instance()
- app.removeTranslator(self.translator)
- print(f"Trying to apply language: {lang}")
- translation_path = ""
- if lang == "ru":
- translation_path = os.path.join(self.parent_directory, "UI", "translations", "ru_RU.qm")
- elif lang == "zh":
- translation_path = os.path.join(self.parent_directory, "UI", "translations", "zh_CN.qm")
-
- if translation_path and self.translator.load(translation_path):
- app.installTranslator(self.translator)
- print(f"{lang} translate Successfully loaded")
- else:
- if translation_path:
- print(f"Unable to load {lang}.qm")
-
- self.retranslateUi(self)
-
- def on_full_reinstall_checkbox_toggled(self, checked):
- if checked:
- if self.dialogexec("",
- self.tr("This function will delete all saves and presets of mods.
It is only needed if something did not work during the normal installation
"),
- self.tr("No"), self.tr("Yes")):
- self.full_reinstall_checkbox.setChecked(True)
- self.skip_launcher_reinstall_checbox.setChecked(False)
- else:
- self.full_reinstall_checkbox.setChecked(False)
-
- def on_alternative_unloc_checkbox_toggled(self, checked):
- if checked:
- self.skip_launcher_reinstall_checbox.setChecked(False)
-
- def on_skip_launcher_reinstall_checbox_toggled(self, checked):
- if checked:
- self.full_reinstall_checkbox.setChecked(False)
- self.alternative_unloc_checkbox.setChecked(False)
-
- def showEvent(self, event):
- super(MainWindow, self).showEvent(event)
- self.apply_initial_language()
- print('Start connection check')
- if not self.setup_thread.isRunning():
- self.spinner_timer.start(150)
- self.setup_thread.start()
- print('Start updates check')
-
- def switch_to_russian(self):
- if self.ru_lang.isChecked():
- self.apply_language("ru")
- print("ru_RU translate Successfully loaded")
-
- def switch_to_english(self):
- if self.en_lang.isChecked():
- self.apply_language("en")
- print("en-US translate Successfully loaded")
-
- def switch_to_chinese(self):
- if self.cn_lang.isChecked():
- self.apply_language("zh")
- print("zh_CN translate Successfully loaded")
-
- @staticmethod
- def open_link_in_browser(url):
- print(f"Attempting to open URL: {url}")
- QDesktopServices.openUrl(QUrl(url))
-
- def mousePressEvent(self, event):
- if event.button() == Qt.LeftButton:
- self.is_dragging = True
- self.last_mouse_position = event.globalPos() - self.frameGeometry().topLeft()
-
- def mouseMoveEvent(self, event):
- if self.is_dragging:
- self.move(event.globalPos() - self.last_mouse_position)
-
- def mouseReleaseEvent(self, event):
- if event.button() == Qt.LeftButton:
- self.is_dragging = False
-
- def dialogexec(self, heading, message, btn1, btn2, icon=":/icons/icons/1x/errorAsset 55.png"):
- print(f'Dialog exec {heading, message}')
- dialogUi.dialogConstrict(self.diag, heading, message, btn1, btn2, icon, self)
- return self.diag.exec_()
-
- def errorexec(self, heading, btnOk, icon=":/icons/icons/1x/closeAsset 43.png", exitApp=False):
- print(f'Error exec {heading, exitApp}')
- errorUi.errorConstrict(self.error, heading, icon, btnOk, self, exitApp)
- self.error.exec_()
-
- def remove_compatibility(self, exe_path):
- exe_path = os.path.abspath(exe_path)
- keys = [
- (winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"),
- (winreg.HKEY_LOCAL_MACHINE, r"Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"),
- ]
-
- for root, subkey in keys:
- try:
- with winreg.OpenKey(root, subkey, 0, winreg.KEY_ALL_ACCESS) as key:
- try:
- value, regtype = winreg.QueryValueEx(key, exe_path)
- print(f"Found compatibility parameter: {value} in {root}\\{subkey}")
- winreg.DeleteValue(key, exe_path)
- print(f"Compatibility parameter deleted: {exe_path}")
- except FileNotFoundError:
- print(f"Compatibility for ({subkey}) parameters are not set")
- pass
- except FileNotFoundError:
- continue
- def browse_folder(self):
- directory = QFileDialog.getExistingDirectory(self, self.tr("Choose Stellaris path"),
- self.game_path_line.text())
- directory = os.path.normpath(directory)
- if directory and os.path.isfile(os.path.join(directory, "stellaris.exe")):
- self.game_path_line.setText(directory)
- self.game_path = directory
- print(f'Path browsed: {self.game_path}')
- if self.server_url:
- md5_checker = MD5(f"{self.game_path}\\dlc", self.server_url)
- self.on_dlc_check_complete(md5_checker.check_files())
- else:
- print('Path browsed incorrectly')
- self.errorexec(self.tr("This is not Stellaris path"), self.tr("Ok"))
-
- def path_check(self):
- path = os.path.normpath(self.game_path_line.text())
- if path and os.path.isfile(os.path.join(path, "stellaris.exe")):
- print(f'Game path: {path}')
- return path
- self.errorexec(self.tr("Please choose game path"), self.tr("Ok"))
- return False
-
- def old_dlc_show(self):
- if self.not_updated_dlc:
- print(f"Not updated DLCs: {self.not_updated_dlc}")
- self.update_dlc_button.setVisible(True)
- self.old_dlc_text.setVisible(True)
- else:
- self.update_dlc_button.setChecked(False)
- print("All DlCs is up to date or server return error")
-
- def handle_github_status(self, status):
- self.gh_status.setChecked(status)
- print('GitHub connection established' if status else 'GitHub connection cant be established')
- if not status:
- print("Warning: GitHub is unavailable. Updates will be handled via fallback server.")
-
- def handle_server_status(self, status):
- self.server_status.setChecked(status)
- print('Server connection established' if status else 'Server connection cant be established')
- if not status:
- if self.dialogexec(self.tr('Connection error'), self.tr(
- 'Cant establish connection with server\nCheck your connection or you can try download DLC directly\nUnzip downloaded "dlc" folder to game folder\nThen you can continue'),
- self.tr("Exit"), self.tr("Open")):
- self.open_link_in_browser(self.server_alturl)
- self.alternative_unloc_checkbox.setEnabled(False)
- else:
- self.close()
-
- def loadDLCNames(self):
- self.dlc_status_widget.clear()
- for dlc in self.dlc_data:
- dlc_name = dlc.get('dlc_name', '').strip()
- if not dlc_name:
- continue
-
- item = QListWidgetItem(dlc_name)
- status_color = self.checkDLCStatus(dlc.get('dlc_folder', ''))
-
- if status_color != 'black':
- item.setForeground(QBrush(QColor(status_color)))
- if status_color == "orange":
- item.setText(item.text() + " (old)")
- self.dlc_status_widget.addItem(item)
-
- def checkDLCStatus(self, dlc_folder):
- if not dlc_folder or not self.game_path:
- return "black"
- dlc_path_folder = os.path.join(self.game_path, "dlc", dlc_folder)
- dlc_path_zip = os.path.join(self.game_path, "dlc", f'{dlc_folder}.zip')
- if os.path.exists(dlc_path_folder) or os.path.exists(dlc_path_zip):
- return "orange" if dlc_folder in self.not_updated_dlc else "teal"
- else:
- return "LightCoral"
-
- def full_reinstall(self):
- try:
- print(f'Deleting documents folder...')
- user_home = os.path.join("C:\\Users", self.user_logon_name)
- rmtree(os.path.join(user_home, "Documents", "Paradox Interactive", "Stellaris"))
- except Exception as e:
- print(f'Cant delete documents folder: {e}')
- try:
- print(f'Deleting dlc folder...')
- rmtree(os.path.join(self.game_path, "dlc"))
- except Exception as e:
- print(f'Cant delete dlc folder: {e}')
-
- def download_alt_method(self):
- print('Downloading alt launcher')
- file = argv[0]
- dir = os.path.dirname(file)
- print(f'Path to download: {dir}')
- self.downloaded_launcher_dir = f'{dir}\\{self.alt_launcher_name}'
- print(f'Download path {self.downloaded_launcher_dir}')
- print(f'Path exist: {os.path.isfile(self.downloaded_launcher_dir)}')
- if os.path.isfile(self.downloaded_launcher_dir):
- return
- progress_dialog = QProgressDialog(self.tr('Alt launcher downloading'), None, 0, 100)
- progress_dialog.setWindowTitle(self.tr('Downloading'))
- progress_dialog.setWindowModality(2)
- progress_dialog.show()
- download_breaked = 0
-
- try:
- response = requests.get(
- f"https://{self.server_url}/unlocker/{self.alt_launcher_name}",
- stream=True)
- total_size_in_bytes = int(response.headers.get('content-length', 0))
- block_size = 1024
- downloaded_bytes = 0
-
- with open(self.downloaded_launcher_dir, 'wb') as file:
- for data in response.iter_content(block_size):
- if progress_dialog.wasCanceled():
- download_breaked = 1
- break
- file.write(data)
- downloaded_bytes += len(data)
- progress = int(downloaded_bytes / total_size_in_bytes * 100)
- progress_dialog.setValue(progress)
-
- except Exception as e:
- print(f'Error while download alt launcher. Please try again or dont use this method Error: {e}')
- self.errorexec(self.tr("Cant download alt launcher"), self.tr("Ok"),
- exitApp=True)
-
- finally:
- progress_dialog.close()
- if not download_breaked:
- self.launcher_downloaded = True
- print(f'Launcher downloaded {self.downloaded_launcher_dir}')
-
- def unlock(self):
- print('Unlocking...')
- if not self.path_check():
- print('Error: incorrect path, return')
- return
- self.game_path = os.path.normpath(self.game_path_line.text())
- print('Unlock started')
- print(
- f'Settings:\nPath: {self.game_path}\nFull reinstall: {self.full_reinstall_checkbox.isChecked()}\nAlt unlock: {self.alternative_unloc_checkbox.isChecked()}\nSkip reinstall: {self.skip_launcher_reinstall_checbox.isChecked()}')
- self.unlock_button.setEnabled(False)
- self.game_path_line.setEnabled(False)
- self.path_choose_button.setEnabled(False)
- self.full_reinstall_checkbox.setEnabled(False)
- self.alternative_unloc_checkbox.setEnabled(False)
- self.skip_launcher_reinstall_checbox.setEnabled(False)
- self.update_dlc_button.setEnabled(False)
- self.copy_files_radio.setVisible(True)
- self.download_files_radio.setVisible(True)
- self.launcher_reinstall_radio.setVisible(True)
- self.progress_label.setVisible(True)
- self.dlc_download_label.setVisible(True)
- self.dlc_download_progress_bar.setVisible(True)
- self.current_dlc_label.setVisible(True)
- self.current_dlc_progress_bar.setVisible(True)
- self.speed_label.setVisible(True)
- if self.full_reinstall_checkbox.isChecked():
- self.full_reinstall()
- if self.alternative_unloc_checkbox.isChecked():
- self.download_alt_method()
- if not os.path.exists(os.path.join(self.game_path, "dlc")):
- os.makedirs(os.path.join(self.game_path, "dlc"))
- if self.game_path:
- try:
- self.remove_compatibility(f"{self.game_path}\\stellaris.exe")
- except Exception as e:
- print(f"Cant remove compatibility: {e}")
- pass
- self.is_downloading = True
- if self.update_dlc_button.isChecked():
- print("Updating DLCs...")
- self.delete_folders(f"{self.game_path}\\dlc", self.not_updated_dlc)
- self.not_updated_dlc = []
- self.loadDLCNames()
- self.creamapi_maker = CreamAPI()
- self.creamapi_maker.progress_signal.connect(self.update_creamapi_progress)
- self.creamapi_maker.start()
- self.dlc_count = 0
- self.dlc_downloaded = 0
- self.download_queue = []
-
- def start_next_download():
- if self.download_queue:
- file_url, save_path = self.download_queue.pop(0)
- print(f"Now downloading: {os.path.basename(file_url)}")
- self.download_thread = DownloaderThread(file_url, save_path, self.dlc_downloaded, self.dlc_count)
- self.download_thread.progress_signal.connect(self.update_progress)
- self.download_thread.progress_signal_2.connect(self.update_progress_2)
- self.download_thread.error_signal.connect(self.show_error)
- self.download_thread.speed_signal.connect(self.show_download_speed)
- self.download_thread.finished.connect(start_next_download)
- self.download_thread.start()
-
- for item in self.dlc_data:
- if 'dlc_folder' in item and item['dlc_folder']:
- self.dlc_count += 1
- for dlc in self.dlc_data:
- dlc_folder = dlc['dlc_folder']
- if dlc_folder == '':
- continue
- file_url = f"https://{self.server_url}/unlocker/{dlc_folder}.zip"
- save_path = os.path.join(self.game_path, 'dlc', f'{dlc_folder}.zip')
- dlc_path = os.path.join(self.game_path, 'dlc', dlc_folder)
-
- if not os.path.exists(dlc_path) and self.is_invalid_zip(save_path):
- if os.path.exists(save_path):
- os.remove(save_path)
- self.download_queue.append((file_url, save_path))
- else:
- self.dlc_downloaded += 1
- if self.dlc_count > 0:
- self.update_progress(int((self.dlc_downloaded / self.dlc_count) * 100))
-
- if self.download_queue:
- print('Starting downloads...')
- if self.server_status.isChecked():
- start_next_download()
- else:
- self.download_files_radio.setVisible(False)
- self.progress_label.setVisible(False)
- self.dlc_download_label.setVisible(False)
- self.dlc_download_progress_bar.setVisible(False)
- self.current_dlc_label.setVisible(False)
- self.current_dlc_progress_bar.setVisible(False)
- self.speed_label.setVisible(False)
- self.reinstall()
-
- def update_creamapi_progress(self, value):
- if value == 100:
- self.creamapidone = True
- self.download_complete()
-
- @staticmethod
- def is_invalid_zip(path):
- if not os.path.exists(path):
- return True
- if os.path.getsize(path) == 0:
- return True
- try:
- with ZipFile(path, 'r') as zf:
- if zf.testzip() is not None:
- return True
- except BadZipFile:
- return True
- return False
-
- @staticmethod
- def delete_folders(base_path, folders):
- base_path = Path(base_path)
- for name in folders:
- dir_path = base_path / name
- try:
- if dir_path.is_dir():
- rmtree(dir_path)
- print(f"Deleted: {dir_path}")
- else:
- pass
- except Exception as e:
- print(f"Can't delete {dir_path}: {e}")
-
- def update_progress(self, value, by_download=False):
- self.dlc_download_progress_bar.setValue(value)
- if by_download:
- self.dlc_downloaded += 1
- if self.dlc_count > 0:
- self.update_progress(int((self.dlc_downloaded / self.dlc_count) * 100))
- self.loadDLCNames()
- if value == 100:
- self.speed_label.setText(f"")
- self.update_progress_2(100)
- # self.download_text_dlc(' ')
- self.download_complete()
-
- def update_progress_2(self, value):
- self.current_dlc_progress_bar.setValue(value)
-
- def show_download_speed(self, speed):
- self.speed_label.setText(f'{speed}MB/s')
-
- def show_error(self, error_message):
- print(f'DownloadThread error signal: {error_message}')
- self.errorexec(self.tr("File download error"), self.tr("Exit"), exitApp=True)
-
- def show_reinstall_error(self, error_message):
- print(f'ReinstallThread error signal: {error_message}')
- self.errorexec(self.tr("Launcher reinstall error"), self.tr("Exit"), exitApp=True)
-
- def download_complete(self):
- if self.dlc_download_progress_bar.value() == 100 and self.creamapidone == True:
- print('DLC downloaded')
- self.reinstall()
-
- def reinstall(self):
- self.download_files_radio.setChecked(True)
- print('Reinstalling')
- paradox_folder1, paradox_folder2, paradox_folder3, paradox_folder4 = launcher_path()
- print(f"Launcher folders: [{paradox_folder1, paradox_folder2, paradox_folder3, paradox_folder4}]")
- if not self.skip_launcher_reinstall_checbox.isChecked():
- self.reinstall_thread = ReinstallThread(self.game_path, paradox_folder1, paradox_folder2, paradox_folder3,
- paradox_folder4, self.launcher_downloaded,
- self.downloaded_launcher_dir, self.user_logon_name)
- self.reinstall_thread.error_signal.connect(self.show_reinstall_error)
- self.reinstall_thread.continue_reinstall.connect(self.finalize_reinstallation)
- self.reinstall_thread.start()
- else:
- print('Reinstalling skipped')
- self.finalize_reinstallation(paradox_folder1)
-
- def finalize_reinstallation(self, paradox_folder1):
- self.launcher_reinstall_radio.setChecked(True)
- print('Starting post-install file processing...')
-
- try:
- print('Unzipping DLC files...')
- zip_files = [f for f in os.listdir(os.path.join(self.game_path, 'dlc')) if f.endswith('.zip')]
- if not zip_files:
- print("No .zip files found in DLC folder to unpack.")
- for zip_file in zip_files:
- self.unzip_and_replace(zip_file)
- except Exception as e:
- print(f"An error occurred during unzipping: {e}")
- self.errorexec(self.tr("Error while unzipping"), self.tr("Exit"), exitApp=True)
- return
-
- try:
- all_launcher_folders = [
- os.path.join(paradox_folder1, item)
- for item in os.listdir(paradox_folder1)
- if item.startswith("launcher") and os.path.isdir(os.path.join(paradox_folder1, item))
- ]
- except FileNotFoundError:
- self.errorexec(self.tr("Launcher directory not found!"), self.tr("Exit"), exitApp=True)
- return
-
- if not all_launcher_folders:
- print("CRITICAL: No launcher folders found after installation.")
- self.errorexec(self.tr("Error unknown launcher"), self.tr("Exit"), exitApp=True)
- return
-
- print(f"Found {len(all_launcher_folders)} launcher folder(s) to patch.")
-
- was_any_folder_patched = False
-
- for launcher_folder in all_launcher_folders:
- print(f"\n--- Processing: {launcher_folder} ---")
- copy_to_path = None
-
- path1 = os.path.join(launcher_folder, 'resources', 'app.asar.unpacked', 'node_modules', 'greenworks', 'lib')
- path2 = os.path.join(launcher_folder, 'resources', 'app', 'dist', 'main')
-
- if os.path.exists(path1):
- copy_to_path = path1
- elif os.path.exists(path2):
- copy_to_path = path2
-
- if copy_to_path:
- was_any_folder_patched = True
- print(f"Valid target path found: {copy_to_path}")
-
- try:
- copytree(f'{self.parent_directory}/creamapi_launcher_files', copy_to_path, dirs_exist_ok=True)
- print("Launcher-specific files copied successfully.")
- except Exception as e:
- print(f"ERROR copying launcher files: {e}")
- self.errorexec(self.tr("Error copying files"), self.tr("Exit"), exitApp=True)
- return
-
- try:
- xdelta_path = os.path.join(launcher_folder, 'xdelta3.exe')
- if os.path.exists(xdelta_path):
- os.remove(xdelta_path)
- print("xdelta3.exe removed.")
- except OSError as e:
- print(f"Could not remove xdelta3.exe: {e}")
- else:
- print("No valid target path found in this folder. Skipping.")
-
- if not was_any_folder_patched:
- print("CRITICAL: Found launcher folders, but none contained a valid target path.")
- self.errorexec(self.tr("Error unknown launcher"), self.tr("Exit"), exitApp=True)
- return
-
- print("\nCopying game-specific files...")
- copytree(f'{self.parent_directory}/creamapi_steam_files', self.game_path, dirs_exist_ok=True)
- print("Copy completed.")
-
- self.copy_files_radio.setChecked(True)
- self.lauch_game_checkbox.setVisible(True)
- self.update_dlc_button.setVisible(False)
- self.old_dlc_text.setVisible(False)
- self.done_button.setVisible(True)
- print('All done!')
-
- def unzip_and_replace(self, dlc_path):
- zip_path = os.path.join(self.game_path, 'dlc', dlc_path)
- extract_folder = os.path.join(self.game_path, 'dlc')
- os.makedirs(extract_folder, exist_ok=True)
-
- try:
- with ZipFile(zip_path, 'r') as zip_ref:
- zip_ref.extractall(extract_folder)
- os.remove(zip_path)
- except Exception as e:
- print(f'Error while unzipping {e}')
- self.errorexec(self.tr("Error while unzipping"), self.tr("Exit"), exitApp=True)
-
- def finish(self):
- if self.lauch_game_checkbox.isChecked():
- try:
- run('start steam://run/281990', shell=True, creationflags=CREATE_NO_WINDOW)
- except:
- pass
- self.close()
\ No newline at end of file
diff --git a/creamlinux/cream_api.ini b/creamlinux/cream_api.ini
new file mode 100644
index 0000000..41018bf
--- /dev/null
+++ b/creamlinux/cream_api.ini
@@ -0,0 +1,39 @@
+# add the dlc you want to fake here
+# APPID = DLC Name
+# copying a file from windows creamapi will not work, you need to fix line endings
+# the DLC id's below are for HOI4
+[config]
+# if we should also list the DLCs you own and not just the ones on this list
+issubscribedapp_on_false_use_real = true
+
+[methods]
+disable_steamapps_issubscribedapp = false
+
+[dlc]
+447680 = Stellaris: Symbols of Domination
+447683 = Stellaris: Arachnoid Portrait Pack
+447681 = Stellaris: Sign-up Campaign Bonus
+498870 = Stellaris: Plantoids Species Pack
+462720 = Stellaris: Creatures of the Void
+518910 = Stellaris: Leviathans Story Pack
+554350 = Stellaris: Horizon Signal
+553280 = Stellaris: Utopia
+633310 = Stellaris: Anniversary Portraits
+642750 = Stellaris: Synthetic Dawn
+716670 = Stellaris: Apocalypse
+756010 = Stellaris: Humanoids Species Pack
+844810 = Stellaris: Distant Stars Story Pack
+944290 = Stellaris: MegaCorp
+1045980 = Stellaris: Ancient Relics Story Pack
+1140000 = Stellaris: Lithoids Species Pack
+1140001 = Stellaris: Federations
+1341520 = Stellaris: Necroids Species Pack
+1522090 = Stellaris: Nemesis
+1749080 = Stellaris: Aquatics Species Pack
+1889490 = Stellaris: Overlord
+2115770 = Stellaris: Toxoids Species Pack
+2277860 = Stellaris: First Contact Story Pack
+2380030 = Stellaris: Galactic Paragons
+2534090 = Stellaris: Astral Planes
+2840100 = Stellaris: The Machine Age
+2863180 = Stellaris: Rick The Cube Species Portrait
\ No newline at end of file
diff --git a/creamlinux/lib32Creamlinux.so b/creamlinux/lib32Creamlinux.so
new file mode 100644
index 0000000..643e486
Binary files /dev/null and b/creamlinux/lib32Creamlinux.so differ
diff --git a/creamlinux/lib64Creamlinux.so b/creamlinux/lib64Creamlinux.so
new file mode 100644
index 0000000..f6b2e99
Binary files /dev/null and b/creamlinux/lib64Creamlinux.so differ
diff --git a/data.json b/data.json
deleted file mode 100644
index f2f5d44..0000000
--- a/data.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{"url": "femboysex.pro", "alturl": "https://mega.nz/folder/4zFRnD6a#aVGAK32ZHPxCp7bMtG87BA", "altlauncher": "launcher-installer-windows_2024.14.msi", "server_msg": ""}
-
-
-
-
diff --git a/main.py b/main.py
deleted file mode 100644
index 8f1b7ec..0000000
--- a/main.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from PyQt5.QtCore import Qt
-from PyQt5.QtWidgets import QApplication
-from UI_logic.MainWindow import MainWindow
-import sys
-if hasattr(Qt, 'AA_EnableHighDpiScaling'):
- QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
-if hasattr(Qt, 'AA_UseHighDpiPixmaps'):
- QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
-if __name__ == '__main__':
- app = QApplication(sys.argv)
- print(f"Using AA_EnableHighDpiScaling > {QApplication.testAttribute(Qt.AA_EnableHighDpiScaling)}")
- print(f"Using AA_UseHighDpiPixmaps > {QApplication.testAttribute(Qt.AA_UseHighDpiPixmaps)}")
- main_window = MainWindow()
- main_window.show()
- app.exec_()
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index e785136..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-PyQt5==5.15.10
-PyQt5_sip==12.13.0
-Requests==2.32.5
-vdf==3.4