From 977f701eef48abbfd5d7884105a74f2ec05d3501 Mon Sep 17 00:00:00 2001
From: RedDeadDepresso <94017243+RedDeadDepresso@users.noreply.github.com>
Date: Wed, 24 Jul 2024 03:46:19 +0100
Subject: [PATCH] fix: checkboxes changes saved
---
app/common/config.py | 44 +-------
app/common/file_manager.py | 154 +++++++++++++-------------
app/common/logger.py | 69 ++++++++----
app/components/navigation_checkbox.py | 17 ++-
app/modules/base.py | 17 ---
app/modules/create_backup.py | 33 +++---
app/modules/fc_kks.py | 119 ++++++++++----------
app/modules/handler.py | 15 +++
app/modules/install_chara.py | 71 ++++++------
app/modules/remove_chara.py | 55 ++++-----
app/modules/request.py | 73 ++++++++++++
app/view/logger_interface.py | 6 +-
app/view/main_window.py | 8 +-
script.py | 16 +--
14 files changed, 388 insertions(+), 309 deletions(-)
delete mode 100644 app/modules/base.py
create mode 100644 app/modules/handler.py
create mode 100644 app/modules/request.py
diff --git a/app/common/config.py b/app/common/config.py
index ba5b562..b85370f 100644
--- a/app/common/config.py
+++ b/app/common/config.py
@@ -60,13 +60,13 @@ class Config(QConfig):
# fckks
fckksEnable = ConfigItem(
- "FCKKS", "Enable", False, BoolValidator()
+ "FilterConvertKKS", "Enable", False, BoolValidator()
)
fccksPath = ConfigItem(
- "FCKKS", "InputPath", "", FolderValidator()
+ "FilterConvertKKS", "InputPath", "", FolderValidator()
)
convert = ConfigItem(
- "FCKKS", "Convert", False, BoolValidator()
+ "FilterConvertKKS", "Convert", False, BoolValidator()
)
# installChara
@@ -102,44 +102,6 @@ class Config(QConfig):
# software update
checkUpdateAtStartUp = ConfigItem("Update", "CheckUpdateAtStartUp", True, BoolValidator())
- # def validate(self):
- # Logger.log_info("SCRIPT", "Validating config")
- # self.ok = True
- # self.tasks = self.config_data["Core"]["Tasks"]
- # self.create_gamepath()
-
- # for task in self.tasks:
- # if self.config_data[task]["Enable"]:
- # if "InputPath" in self.config_data[task]:
- # path = self.config_data[task]["InputPath"]
- # elif "OutputPath" in self.config_data[task]:
- # path = self.config_data[task]["OutputPath"]
- # if not os.path.exists(path):
- # Logger.log_error("SCRIPT", f"Path invalid for task {task}")
- # raise Exception()
-
- # self.install_chara = self.config_data.get("InstallChara", {})
- # self.create_backup = self.config_data.get("CreateBackup", {})
- # self.remove_chara = self.config_data.get("RemoveChara", {})
- # self.fc_kks = self.config_data.get("FCKKS", {})
-
- # def create_gamepath(self):
- # base = self.config_data["Core"]["GamePath"]
- # self.game_path = {
- # "base": base,
- # "UserData": os.path.join(base, "UserData"),
- # "BepInEx": os.path.join(base, "BepInEx"),
- # "mods": os.path.join(base, "mods"),
- # "chara": os.path.join(base, "UserData\\chara\\female"),
- # "coordinate": os.path.join(base, "UserData\coordinate"),
- # "Overlays": os.path.join(base, "UserData\Overlays")
- # }
-
- # for path in self.game_path.values():
- # if not os.path.exists(path):
- # Logger.log_error("SCRIPT", "Game path not valid")
- # raise Exception()
-
YEAR = 2023
AUTHOR = "zhiyiYo"
diff --git a/app/common/file_manager.py b/app/common/file_manager.py
index 84d8de2..2286cb3 100644
--- a/app/common/file_manager.py
+++ b/app/common/file_manager.py
@@ -14,98 +14,98 @@ class FileManager:
def __init__(self, config):
self.config = config
- def find_all_files(self, directory):
- file_list = []
- compressed_file_list = []
- compressed_extensions = [".rar", ".zip", ".7z"]
+ def findAllFiles(self, directory):
+ fileList = []
+ archiveList = []
+ archiveExtensions = [".rar", ".zip", ".7z"]
for root, dirs, files in os.walk(directory):
for file in files:
- file_path = os.path.join(root, file)
- file_size = os.path.getsize(file_path)
- _, file_extension = os.path.splitext(file_path)
+ filePath = os.path.join(root, file)
+ fileSize = os.path.getsize(filePath)
+ _, fileExtension = os.path.splitext(filePath)
- if file_extension in compressed_extensions:
- compressed_file_list.append((file_path, file_size, file_extension))
+ if fileExtension in archiveExtensions:
+ archiveList.append((filePath, fileSize, fileExtension))
else:
- file_list.append((file_path, file_size, file_extension))
+ fileList.append((filePath, fileSize, fileExtension))
- file_list.sort(key=lambda x: x[1])
- compressed_file_list.sort(key=lambda x: x[1])
- return file_list, compressed_file_list
+ fileList.sort(key=lambda x: x[1])
+ archiveList.sort(key=lambda x: x[1])
+ return fileList, archiveList
- def copy_and_paste(self, type, source_path, destination_folder):
- source_path = source_path[0]
- base_name = os.path.basename(source_path)
- destination_path = os.path.join(destination_folder, base_name)
+ def copyAndPaste(self, type, sourcePath, destinationFolder):
+ sourcePath = sourcePath[0]
+ baseName = os.path.basename(sourcePath)
+ destinationPath = os.path.join(destinationFolder, baseName)
conflicts = self.config.install_chara["FileConflicts"]
- already_exists = os.path.exists(destination_path)
+ alreadyExists = os.path.exists(destinationPath)
- if already_exists and conflicts == "Skip":
- logger.log_skipped(type, base_name)
+ if alreadyExists and conflicts == "Skip":
+ logger.skipped(type, baseName)
return
- elif already_exists and conflicts == "Replace":
- logger.log_replaced(type, base_name)
+ elif alreadyExists and conflicts == "Replace":
+ logger.replaced(type, baseName)
- elif already_exists and conflicts == "Rename":
- max_retries = 3
- for attempt in range(max_retries):
+ elif alreadyExists and conflicts == "Rename":
+ maxRetries = 3
+ for attempt in range(maxRetries):
try:
- filename, file_extension = os.path.splitext(source_path)
- new_name = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')
- new_source_path = f"{filename}_{new_name}{file_extension}"
- os.rename(source_path, new_source_path)
- source_path = new_source_path
- logger.log_renamed(type, base_name)
+ filename, fileExtension = os.path.splitext(sourcePath)
+ newName = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')
+ newSourcePath = f"{filename}_{newName}{fileExtension}"
+ os.rename(sourcePath, newSourcePath)
+ sourcePath = newSourcePath
+ logger.renamed(type, baseName)
- filename, file_extension = os.path.splitext(destination_path)
- destination_path = f"{filename}_{new_name}{file_extension}"
+ filename, fileExtension = os.path.splitext(destinationPath)
+ destinationPath = f"{filename}_{newName}{fileExtension}"
break # Exit the loop if renaming is successful
except PermissionError:
- if attempt < max_retries - 1:
+ if attempt < maxRetries - 1:
time.sleep(1) # Wait for 1 second before retrying
else:
- logger.log_error(type, f"Failed to rename {base_name} after {max_retries} attempts.")
+ logger.error(type, f"Failed to rename {baseName} after {maxRetries} attempts.")
return
try:
- shutil.copy(source_path, destination_path)
- print(f"File copied successfully from {source_path} to {destination_path}")
- if not already_exists:
- logger.log_success(type, base_name)
+ shutil.copy(sourcePath, destinationPath)
+ print(f"File copied successfully from {sourcePath} to {destinationPath}")
+ if not alreadyExists:
+ logger.success(type, baseName)
except FileNotFoundError:
- logger.log_error(type, f"{base_name} does not exist.")
+ logger.error(type, f"{baseName} does not exist.")
except PermissionError:
- logger.log_error(type, f"Permission denied for {base_name}")
+ logger.error(type, f"Permission denied for {baseName}")
except Exception as e:
- logger.log_error(type, f"An error occurred: {e}")
+ logger.error(type, f"An error occurred: {e}")
- def find_and_remove(self, type, source_path, destination_folder):
- source_path = source_path[0]
- base_name = os.path.basename(source_path)
- destination_path = os.path.join(destination_folder, base_name)
- if os.path.exists(destination_path):
+ def findAndRemove(self, type, sourcePath, destinationFolder):
+ sourcePath = sourcePath[0]
+ baseName = os.path.basename(sourcePath)
+ destinationPath = os.path.join(destinationFolder, baseName)
+ if os.path.exists(destinationPath):
try:
- os.remove(destination_path)
- logger.log_removed(type, base_name)
+ os.remove(destinationPath)
+ logger.removed(type, baseName)
except OSError as e:
- logger.log_error(type, base_name)
+ logger.error(type, baseName)
- def create_archive(self, folders, archive_path):
+ def createArchive(self, folders, archivePath):
# Specify the full path to the 7zip executable
- path_to_7zip = patoolib.util.find_program("7z")
- if not path_to_7zip:
- logger.log_error("SCRIPT", "7zip not found. Unable to create backup")
+ pathTo7zip = patoolib.util.find_program("7z")
+ if not pathTo7zip:
+ logger.error("SCRIPT", "7zip not found. Unable to create backup")
raise Exception()
- if os.path.exists(archive_path+".7z"):
- os.remove(archive_path+".7z")
+ if os.path.exists(archivePath+".7z"):
+ os.remove(archivePath+".7z")
- path_to_7zip = f'"{path_to_7zip}"'
- archive_path = f'"{archive_path}"'
- exclude_folders = [
+ pathTo7zip = f'"{pathTo7zip}"'
+ archivePath = f'"{archivePath}"'
+ excludeFolders = [
'"Sideloader Modpack"',
'"Sideloader Modpack - Studio"',
'"Sideloader Modpack - KK_UncensorSelector"',
@@ -118,52 +118,52 @@ class FileManager:
]
# Create a string of folder names to exclude
- exclude_string = ''
- for folder in exclude_folders:
- exclude_string += f'-xr!{folder} '
+ excludeString = ''
+ for folder in excludeFolders:
+ excludeString += f'-xr!{folder} '
# Create a string of folder names to include
- include_string = ''
+ includeString = ''
for folder in folders:
- include_string += f'"{folder}" '
+ includeString += f'"{folder}" '
# Construct the 7zip command
- command = f'{path_to_7zip} a -t7z {archive_path} {include_string} {exclude_string}'
+ command = f'{pathTo7zip} a -t7z {archivePath} {includeString} {excludeString}'
# Call the command
process = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# Print the output
for line in process.stdout.decode().split('\n'):
if line.strip() != "":
- logger.log_info("7-Zip", line)
+ logger.info("7-Zip", line)
# Check the return code
if process.returncode not in [0, 1]:
raise Exception()
- def extract_archive(self, archive_path):
+ def extractArchive(self, archivePath):
try:
- archive_name = os.path.basename(archive_path)
- logger.log_info("ARCHIVE", f"Extracting {archive_name}")
- extract_path = os.path.join(f"{os.path.splitext(archive_path)[0]}_{datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')}")
- patoolib.extract_archive(archive_path, outdir=extract_path)
- return extract_path
+ archiveName = os.path.basename(archivePath)
+ logger.info("ARCHIVE", f"Extracting {archiveName}")
+ extractPath = os.path.join(f"{os.path.splitext(archivePath)[0]}_{datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')}")
+ patoolib.extract_archive(archivePath, outdir=extractPath)
+ return extractPath
except patoolib.util.PatoolError as e:
- text = f"There is an error with the archive {archive_name} but it is impossible to detect the cause. Maybe it requires a password?"
+ text = f"There is an error with the archive {archiveName} but it is impossible to detect the cause. Maybe it requires a password?"
while self.config.install_chara["Password"] == "Request Password":
try:
dialog = customtkinter.CTkInputDialog(text=text, title="Enter Password")
password = dialog.get_input()
if password is not None or "":
- patoolib.extract_archive(archive_path, outdir=extract_path, password=password)
- return extract_path
+ patoolib.extract_archive(archivePath, outdir=extractPath, password=password)
+ return extractPath
else:
break
except:
- text = f"Wrong password or {archive_name} is corrupted. Please enter password again or click Cancel"
+ text = f"Wrong password or {archiveName} is corrupted. Please enter password again or click Cancel"
- logger.log_skipped("ARCHIVE", archive_name)
+ logger.skipped("ARCHIVE", archiveName)
fileManager = FileManager()
\ No newline at end of file
diff --git a/app/common/logger.py b/app/common/logger.py
index bdfd389..b66f226 100644
--- a/app/common/logger.py
+++ b/app/common/logger.py
@@ -26,7 +26,7 @@ class Logger:
self.logger.setLevel(logging.INFO)
self.logger.addHandler(handler1)
- def __out__(self, message: str, level: int = 1, raw_print=False) -> None:
+ def __out__(self, category: str, message: str, level: int = 1, raw_print=False) -> None:
"""
Output log
:param message: log message
@@ -41,10 +41,13 @@ class Logger:
while len(logging.root.handlers) > 0:
logging.root.handlers.pop()
- # Status Text: INFO, WARNING, ERROR, CRITICAL
- status = [' INFO', ' WARNING', ' ERROR', 'CRITICAL']
- # Status Color: Blue, Orange, Red, Purple
- statusColor = ['#2d8cf0', '#f90', '#ed3f14', '#3e0480']
+ # Status Text: INFO, SUCCESS, ERROR, SKIPPED, REPLACED, RENAMED, REMOVED
+ status = [' INFO', ' SUCCESS', ' ERROR',
+ ' SKIPPED', ' REPLACED', ' RENAMED', ' REMOVED']
+
+ # Status Color: Blue, Red, Green, Orange,
+ statusColor = ['#2d8cf0', '#ed3f14', '#f90', '#f90', '#f90', '#f90', '#00c12b']
+
# Status HTML: status
statusHtml = [
f'{status}'
@@ -55,7 +58,7 @@ class Logger:
message = message.replace('\n', '
').replace(' ', ' ')
adding = (f'''
- {statusHtml[level - 1]} | {datetime.now().strftime("%Y-%m-%d %H:%M:%S")} | {message}
+ {statusHtml[level - 1]} | {category} | {message}
''')
self.logs += adding
@@ -63,37 +66,61 @@ class Logger:
else:
print(f'{statusHtml[level - 1]} | {datetime.now().strftime("%Y-%m-%d %H:%M:%S")} | {message}')
- def info(self, message: str) -> None:
+ def info(self, category: str, message: str) -> None:
"""
:param message: log message
Output info log
"""
- self.__out__(message, 1)
+ self.__out__(category, message, 1)
- def warning(self, message: str) -> None:
- """
- :param message: log message
-
- Output warn log
- """
- self.__out__(message, 2)
-
- def error(self, message: Union[str, Exception]) -> None:
+ def success(self, category: str, message: Union[str, Exception]) -> None:
"""
:param message: log message
Output error log
"""
- self.__out__(message, 3)
+ self.__out__(category, message, 2)
- def critical(self, message: str) -> None:
+ def error(self, category: str, message: Union[str, Exception]) -> None:
"""
:param message: log message
- Output critical log
+ Output error log
"""
- self.__out__(message, 4)
+ self.__out__(category, message, 3)
+
+ def skipped(self, category: str, message: str) -> None:
+ """
+ :param message: log message
+
+ Output warn log
+ """
+ self.__out__(category, message, 4)
+
+ def replaced(self, category: str, message: str) -> None:
+ """
+ :param message: log message
+
+ Output warn log
+ """
+ self.__out__(category, message, 5)
+
+ def renamed(self, category: str, message: str) -> None:
+ """
+ :param message: log message
+
+ Output warn log
+ """
+ self.__out__(category, message, 6)
+
+ def removed(self, category: str, message: str) -> None:
+ """
+ :param message: log message
+
+ Output warn log
+ """
+ self.__out__(category, message, 6)
def line(self) -> None:
"""
diff --git a/app/components/navigation_checkbox.py b/app/components/navigation_checkbox.py
index 1c5255b..2fcdd3b 100644
--- a/app/components/navigation_checkbox.py
+++ b/app/components/navigation_checkbox.py
@@ -6,13 +6,16 @@ from qfluentwidgets import ToolButton, CheckBox
from qfluentwidgets.common.icon import FluentIcon as FIF
from app.common.signal_bus import signalBus
+from app.common.config import cfg
class NavigationCheckBox(QWidget):
- def __init__(self, text, settingGroup) -> None:
+ def __init__(self, text, configItem, settingGroup) -> None:
super().__init__()
self.layout = QHBoxLayout()
self.checkBox = CheckBox(text)
+ self.configItem = configItem
+ self.loadCheckState()
self.toolButton = ToolButton(FIF.SETTING)
self.settingGroup = settingGroup
@@ -25,10 +28,22 @@ class NavigationCheckBox(QWidget):
self.setLayout(self.layout)
def __connectSignalToSlot(self):
+ self.checkBox.stateChanged.connect(self.saveCheckState)
self.toolButton.clicked.connect(lambda: signalBus.switchToSettingGroup.emit(self.settingGroup))
signalBus.selectAllClicked.connect(lambda: self.checkBox.setChecked(True))
signalBus.clearAllClicked.connect(lambda: self.checkBox.setChecked(False))
+ def loadCheckState(self):
+ value = cfg.get(self.configItem)
+ if value:
+ self.checkBox.setCheckState(Qt.CheckState.Checked)
+ else:
+ self.checkBox.setCheckState(Qt.CheckState.Unchecked)
+
+ def saveCheckState(self, state):
+ isChecked = state > 0
+ cfg.set(self.configItem, isChecked)
+
diff --git a/app/modules/base.py b/app/modules/base.py
deleted file mode 100644
index 04f4444..0000000
--- a/app/modules/base.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from app.common.config import cfg
-
-
-class Request:
- def __init__(self) -> None:
- pass
-
-
-class Handler:
- def __init__(self) -> None:
- pass
-
- def set_next(self):
- pass
-
- def handle(self):
- pass
\ No newline at end of file
diff --git a/app/modules/create_backup.py b/app/modules/create_backup.py
index 1cc36a3..afe0632 100644
--- a/app/modules/create_backup.py
+++ b/app/modules/create_backup.py
@@ -1,24 +1,25 @@
import os
-class CreateBackup:
- def __init__(self, config, file_manager):
- """Initializes the Bounty module.
+from app.common.file_manager import fileManager
+from app.modules.handler import Handler
- Args:
- config (Config): BAAuto Config instance
- """
- self.config = config
- self.file_manager = file_manager
- self.backup_folders = self.config.create_backup["GameFolders"]
- self.filename = self.config.create_backup["Filename"]
- self.output_path = self.config.create_backup["OutputPath"]
- self.game_path = self.config.game_path
+
+class CreateBackup(Handler):
+ def __str__(self) -> str:
+ return "Create Backup"
- def logic_wrapper(self):
- selected_folders = [self.game_path[folder] for folder in self.backup_folders if self.backup_folders[folder]]
- output_path = os.path.join(self.output_path, self.filename)
- self.file_manager.create_archive(selected_folders, output_path)
+ def loadConfig(self, config):
+ super().loadConfig(config)
+ folders = ["mods", "UserData", "BepInEx"]
+ self.folders = [self.gamePath[f] for f in folders if self.config[f]]
+ self.outputPath = self.config["OutputPath"]
+ self.filename = self.config["Filename"]
+
+ def handle(self, request):
+ outputPath = os.path.join(self.outputPath, self.filename)
+ fileManager.createArchive(self.folders, outputPath)
+ self.setNext(request)
diff --git a/app/modules/fc_kks.py b/app/modules/fc_kks.py
index 992d041..b363c92 100644
--- a/app/modules/fc_kks.py
+++ b/app/modules/fc_kks.py
@@ -2,106 +2,107 @@ import os
import re as regex
import codecs
import shutil
-from util.logger import Logger
-class FilterConvertKKS:
- def __init__(self, config, file_manager):
- """Initializes the Bounty module.
+from app.common.logger import logger
+from app.modules.handler import Handler
- Args:
- config (Config): BAAuto Config instance
- """
- self.config = config
- self.file_manager = file_manager
- self.convert = self.config.fc_kks["Convert"]
- def get_list(self, folder_path):
- new_list = []
- for root, dirs, files in os.walk(folder_path):
+class FilterConvertKKS(Handler):
+ def __str__(self) -> str:
+ return "Filter Convert KKS"
+
+ def loadConfig(self, config):
+ super().loadConfig(config)
+ self.convert = self.config["Convert"]
+
+ def getList(self, folderPath):
+ newList = []
+ for root, dirs, files in os.walk(folderPath):
for filename in files:
if regex.match(r".*(\.png)$", filename):
- new_list.append(os.path.join(root, filename))
- return new_list
+ newList.append(os.path.join(root, filename))
+ return newList
- def check_png(self, card_path):
- with codecs.open(card_path, "rb") as card:
+ def checkPng(self, cardPath):
+ with codecs.open(cardPath, "rb") as card:
data = card.read()
- card_type = 0
+ cardType = 0
if data.find(b"KoiKatuChara") != -1:
- card_type = 1
+ cardType = 1
if data.find(b"KoiKatuCharaSP") != -1:
- card_type = 2
+ cardType = 2
elif data.find(b"KoiKatuCharaSun") != -1:
- card_type = 3
- Logger.log_info(f"[{card_type}]", f"{card_path}")
- return card_type
+ cardType = 3
+ logger.info(f"[{cardType}]", f"{cardPath}")
+ return cardType
- def convert_kk(self, card_name, card_path, destination_path):
- with codecs.open(card_path, mode="rb") as card:
+ def convertKk(self, cardName, cardPath, destinationPath):
+ with codecs.open(cardPath, mode="rb") as card:
data = card.read()
- replace_list = [
+ replaceList = [
[b"\x15\xe3\x80\x90KoiKatuCharaSun", b"\x12\xe3\x80\x90KoiKatuChara"],
[b"Parameter\xa7version\xa50.0.6", b"Parameter\xa7version\xa50.0.5"],
[b"version\xa50.0.6\xa3sex", b"version\xa50.0.5\xa3sex"],
]
- for text in replace_list:
+ for text in replaceList:
data = data.replace(text[0], text[1])
- new_file_path = os.path.normpath(os.path.join(destination_path, f"KKS2KK_{card_name}"))
- # print(f"new_file_path {new_file_path}")
+ newFilePath = os.path.normpath(os.path.join(destinationPath, f"KKS2KK_{cardName}"))
- with codecs.open(new_file_path, "wb") as new_card:
- new_card.write(data)
+ with codecs.open(newFilePath, "wb") as newCard:
+ newCard.write(data)
- def logic_wrapper(self):
+ def handle(self, request):
path = self.config.fc_kks["InputPath"]
- kks_card_list = []
- kks_folder = "_KKS_card_"
- kks_folder2 = "_KKS_to_KK_"
+ kksCardList = []
+ kksFolder = "_KKS_card_"
+ kksFolder2 = "_KKS_to_KK_"
- png_list = self.get_list(path)
+ pngList = self.getList(path)
- count = len(png_list)
+ count = len(pngList)
if count > 0:
- Logger.log_info("SCRIPT", "0: unknown / 1: kk / 2: kksp / 3: kks")
- for png in png_list:
- if self.check_png(png) == 3:
- kks_card_list.append(png)
+ logger.info("SCRIPT", "0: unknown / 1: kk / 2: kksp / 3: kks")
+ for png in pngList:
+ if self.checkPng(png) == 3:
+ kksCardList.append(png)
else:
- Logger.log_success("SCRIPT", f"no PNG found")
+ logger.success("SCRIPT", f"no PNG found")
return
- count = len(kks_card_list)
+ count = len(kksCardList)
if count > 0:
- print(kks_card_list)
+ print(kksCardList)
- target_folder = os.path.normpath(os.path.join(path, kks_folder))
- target_folder2 = os.path.normpath(os.path.join(path, kks_folder2))
- if not os.path.isdir(target_folder):
- os.mkdir(target_folder)
+ targetFolder = os.path.normpath(os.path.join(path, kksFolder))
+ targetFolder2 = os.path.normpath(os.path.join(path, kksFolder2))
+ if not os.path.isdir(targetFolder):
+ os.mkdir(targetFolder)
if self.convert:
- Logger.log_info("SCRIPT", f"Conversion to KK is [{self.convert}]")
- if not os.path.isdir(target_folder2):
- os.mkdir(target_folder2)
+ logger.info("SCRIPT", f"Conversion to KK is [{self.convert}]")
+ if not os.path.isdir(targetFolder2):
+ os.mkdir(targetFolder2)
- for card_path in kks_card_list:
- source = card_path
- card = os.path.basename(card_path)
- target = os.path.normpath(os.path.join(target_folder, card))
+ for cardPath in kksCardList:
+ source = cardPath
+ card = os.path.basename(cardPath)
+ target = os.path.normpath(os.path.join(targetFolder, card))
# copy & convert before move
if self.convert:
- self.convert_kk(card, source, target_folder2)
+ self.convertKk(card, source, targetFolder2)
# move file
shutil.move(source, target)
if self.convert:
- Logger.log_success("SCRIPT", f"[{count}] cards moved to [{kks_folder}] folder, converted and save to [{kks_folder2}] folder")
+ logger.success("SCRIPT", f"[{count}] cards moved to [{kksFolder}] folder, converted and save to [{kksFolder2}] folder")
else:
- Logger.log_success("SCRIPT", f"[{count}] cards moved to [{kks_folder}] folder")
+ logger.success("SCRIPT", f"[{count}] cards moved to [{kksFolder}] folder")
else:
- Logger.log_success("SCRIPT", f"no KKS card found")
+ logger.success("SCRIPT", f"no KKS card found")
+
+ self.setNext(request)
\ No newline at end of file
diff --git a/app/modules/handler.py b/app/modules/handler.py
new file mode 100644
index 0000000..1dbfa9c
--- /dev/null
+++ b/app/modules/handler.py
@@ -0,0 +1,15 @@
+class Handler:
+ def __str__(self) -> str:
+ return "Handler"
+
+ def loadConfig(self, config):
+ self.gamePath = config.get("Core", "GamePath")
+ self.config = config.get(str(self))
+
+ def handle(self, request):
+ pass
+
+ def setNext(self, request):
+ request.removeHandler()
+ request.process()
+
diff --git a/app/modules/install_chara.py b/app/modules/install_chara.py
index 05f12b1..3f9d1bb 100644
--- a/app/modules/install_chara.py
+++ b/app/modules/install_chara.py
@@ -1,56 +1,57 @@
import os
import codecs
-from util.logger import Logger
-class InstallChara:
- def __init__(self, config, file_manager):
- """Initializes the Bounty module.
+from app.common.file_manager import fileManager
+from app.common.logger import logger
+from app.modules.handler import Handler
- Args:
- config (Config): BAAuto Config instance
- """
- self.config = config
- self.file_manager = file_manager
- self.game_path = self.config.game_path
- self.input_path = self.config.install_chara["InputPath"]
- def resolve_png(self, image_path):
- with codecs.open(image_path[0], "rb") as card:
+class InstallChara(Handler):
+ def __str__(self) -> str:
+ return "Install Chara"
+
+ def loadConfig(self, config):
+ super().loadConfig(config)
+ self.inputPath = self.config["InputPath"]
+
+ def resolvePng(self, imagePath):
+ with codecs.open(imagePath[0], "rb") as card:
data = card.read()
if data.find(b"KoiKatuChara") != -1:
if data.find(b"KoiKatuCharaSP") != -1 or data.find(b"KoiKatuCharaSun") != -1:
- basename = os.path.basename(image_path[0])
- Logger.log_error("CHARA", f"{basename} is a KKS card")
+ basename = os.path.basename(imagePath[0])
+ logger.error("CHARA", f"{basename} is a KKS card")
return
- self.file_manager.copy_and_paste("CHARA", image_path, self.game_path["chara"])
+ fileManager.copyAndPaste("CHARA", imagePath, self.gamePath["chara"])
elif data.find(b"KoiKatuClothes") != -1:
- self.file_manager.copy_and_paste("COORD",image_path, self.game_path["coordinate"])
+ fileManager.copyAndPaste("COORD",imagePath, self.gamePath["coordinate"])
else:
- self.file_manager.copy_and_paste("OVERLAYS", image_path, self.game_path["Overlays"])
+ fileManager.copyAndPaste("OVERLAYS", imagePath, self.gamePath["Overlays"])
- def logic_wrapper(self, folder_path=None):
- if folder_path is None:
- folder_path = self.input_path
- foldername = os.path.basename(folder_path)
- Logger.log_msg("FOLDER", foldername)
- file_list, compressed_file_list = self.file_manager.find_all_files(folder_path)
+ def handle(self, request, folderPath=None):
+ if folderPath is None:
+ folderPath = self.inputPath
+ foldername = os.path.basename(folderPath)
+ logger.log_msg("FOLDER", foldername)
+ fileList, archiveList = fileManager.findAllFiles(folderPath)
- for file in file_list:
- file_extension = file[2]
- match file_extension:
+ for file in fileList:
+ extension = file[2]
+ match extension:
case ".zipmod":
- self.file_manager.copy_and_paste("MODS", file, self.game_path["mods"])
+ fileManager.copyAndPaste("MODS", file, self.gamePath["mods"])
case ".png":
- self.resolve_png(file)
+ self.resolvePng(file)
case _:
basename = os.path.basename(file[0])
- Logger.log_error("UKNOWN", f"Cannot classify {basename}")
- print("[MSG]")
+ logger.error("UKNOWN", f"Cannot classify {basename}")
- for compressed in compressed_file_list:
- extract_path = self.file_manager.extract_archive(compressed[0])
- if extract_path is not None:
- self.logic_wrapper(extract_path)
+ for archive in archiveList:
+ extractPath = fileManager.extractArchive(archive[0])
+ if extractPath is not None:
+ self.handle(extractPath)
+
+ self.setNext(request)
\ No newline at end of file
diff --git a/app/modules/remove_chara.py b/app/modules/remove_chara.py
index a80d5f2..792fa58 100644
--- a/app/modules/remove_chara.py
+++ b/app/modules/remove_chara.py
@@ -1,47 +1,48 @@
import os
import codecs
-from util.logger import Logger
-class RemoveChara:
- def __init__(self, config, file_manager):
- """Initializes the Bounty module.
+from app.common.file_manager import fileManager
+from app.common.logger import logger
+from app.modules.handler import Handler
- Args:
- config (Config): BAAuto Config instance
- """
- self.config = config
- self.file_manager = file_manager
- self.game_path = self.config.game_path
- self.input_path = self.config.remove_chara["InputPath"]
- def resolve_png(self, image_path):
- with codecs.open(image_path[0], "rb") as card:
+class RemoveChara(Handler):
+ def __str__(self) -> str:
+ return "Remove Chara"
+
+ def loadConfig(self, config):
+ super().configLoad(config)
+ self.inputPath = self.config["InputPath"]
+
+ def resolvePng(self, imagePath):
+ with codecs.open(imagePath[0], "rb") as card:
data = card.read()
if data.find(b"KoiKatuChara") != -1:
if data.find(b"KoiKatuCharaSP") != -1 or data.find(b"KoiKatuCharaSun") != -1:
return
- self.file_manager.find_and_remove("CHARA", image_path, self.game_path["chara"])
+ fileManager.findAndRemove("CHARA", imagePath, self.gamePath["chara"])
elif data.find(b"KoiKatuClothes") != -1:
- self.file_manager.find_and_remove("COORD",image_path, self.game_path["coordinate"])
+ fileManager.findAndRemove("COORD",imagePath, self.gamePath["coordinate"])
else:
- self.file_manager.find_and_remove("OVERLAYS", image_path, self.game_path["Overlays"])
+ fileManager.findAndRemove("OVERLAYS", imagePath, self.gamePath["Overlays"])
- def logic_wrapper(self):
- foldername = os.path.basename(self.input_path)
- Logger.log_msg("FOLDER", foldername)
- file_list, archive_list = self.file_manager.find_all_files(self.input_path)
+ def handle(self, request):
+ foldername = os.path.basename(self.inputPath)
+ logger.info("FOLDER", foldername)
+ fileList, archiveList = fileManager.findAllFiles(self.inputPath)
- for file in file_list:
- file_extension = file[2]
- match file_extension:
+ for file in fileList:
+ extension = file[2]
+ match extension:
case ".zipmod":
- self.file_manager.find_and_remove("MODS", file, self.game_path["mods"])
+ fileManager.findAndRemove("MODS", file, self.game_path["mods"])
case ".png":
- self.resolve_png(file)
+ self.resolvePng(file)
case _:
pass
- print("[MSG]")
-
+
+ logger.line()
+ self.setNext(request)
\ No newline at end of file
diff --git a/app/modules/request.py b/app/modules/request.py
new file mode 100644
index 0000000..438da0b
--- /dev/null
+++ b/app/modules/request.py
@@ -0,0 +1,73 @@
+import os
+
+from app.common.config import cfg
+from app.common.logger import logger
+
+from app.modules.handler import Handler
+from app.modules.create_backup import CreateBackup
+from app.modules.fc_kks import FilterConvertKKS
+from app.modules.install_chara import InstallChara
+from app.modules.remove_chara import RemoveChara
+
+
+class Request:
+ def __init__(self):
+ self._handlers = [CreateBackup(), FilterConvertKKS(), InstallChara(), RemoveChara()]
+ self._config = cfg.toDict()
+ self._isValid = True
+
+ logger.info("SCRIPT", "Validating config")
+ self.validateGamepath()
+ self._handlers = [x for x in self.handlers if self.isTaskEnabled(x)]
+ if not self._isValid:
+ raise Exception()
+
+ def validatePath(self, path, errorMsg):
+ if not os.path.exists(path):
+ logger.error("SCRIPT", errorMsg)
+ self._isValid = False
+ return False
+ return True
+
+ def validateGamepath(self):
+ base = self.config['Core']['GamePath']
+ self.config['Core']['GamePath'] = {
+ "base": base,
+ "UserData": os.path.join(base, "UserData"),
+ "BepInEx": os.path.join(base, "BepInEx"),
+ "mods": os.path.join(base, "mods"),
+ "chara": os.path.join(base, "UserData\\chara\\female"),
+ "coordinate": os.path.join(base, "UserData\\coordinate"),
+ "Overlays": os.path.join(base, "UserData\\Overlays")
+ }
+
+ for directory, path in self.config['Core']['GamePath'].items():
+ self.validatePath(path, f"Game path not valid. Missing {directory} directory.")
+
+ def isTaskEnabled(self, handler: Handler):
+ task = str(handler).replace(" ", "")
+ taskConfig = self.config[task]
+
+ if not taskConfig["Enable"]:
+ return False
+
+ if (path := taskConfig.get("InputPath")):
+ self.validatePath(path, f"Invalid path for {str(handler)}: {path}")
+
+ if (path := taskConfig.get("OutputPath")):
+ self.validatePath(path, f"Invalid path for {str(handler)}: {path}")
+
+ if self._isValid:
+ handler.loadConfig(self.config)
+
+ return True
+
+ def removeHandler(self) -> Handler:
+ if len(self._handlers) > 1:
+ return self._handlers.pop(0)
+
+ def process(self):
+ if self._handlers:
+ self._handlers[0].handle()
+
+
diff --git a/app/view/logger_interface.py b/app/view/logger_interface.py
index c6a67a0..2f721f0 100644
--- a/app/view/logger_interface.py
+++ b/app/view/logger_interface.py
@@ -15,7 +15,7 @@ class LoggerInterface(QFrame):
# setting label
self.mainLayout = QVBoxLayout()
self.topLayout = QHBoxLayout()
- self.settingLabel = QLabel(self.tr("Log"))
+ self.loggerLabel = QLabel(self.tr("Log"))
self.clearBUtton = PushButton('Clear')
self.autoscrollButton = PushButton('Autoscroll Off')
self.loggerBox = TextEdit()
@@ -28,7 +28,7 @@ class LoggerInterface(QFrame):
self.setObjectName('loggerInterface')
# initialize style sheet
- self.settingLabel.setObjectName('settingLabel')
+ self.loggerLabel.setObjectName('settingLabel')
StyleSheet.SETTING_INTERFACE.apply(self)
# initialize layout
@@ -36,7 +36,7 @@ class LoggerInterface(QFrame):
self.__connectSignalToSlot()
def __initLayout(self):
- self.topLayout.addWidget(self.settingLabel, alignment=Qt.AlignmentFlag.AlignLeft)
+ self.topLayout.addWidget(self.loggerLabel, alignment=Qt.AlignmentFlag.AlignLeft)
self.topLayout.addWidget(self.clearBUtton, alignment=Qt.AlignmentFlag.AlignRight)
self.topLayout.addWidget(self.autoscrollButton, alignment=Qt.AlignmentFlag.AlignRight)
diff --git a/app/view/main_window.py b/app/view/main_window.py
index 82c8ef8..0974ae0 100644
--- a/app/view/main_window.py
+++ b/app/view/main_window.py
@@ -53,10 +53,10 @@ class MainWindow(FluentWindow):
)
self.navigationInterface.panel.topLayout.setAlignment(Qt.AlignCenter)
scrollLayout = self.navigationInterface.panel.scrollLayout
- scrollLayout.addWidget(NavigationCheckBox('Create Backup', self.settingInterface.backupGroup))
- scrollLayout.addWidget(NavigationCheckBox('Filter and Convert KKS', self.settingInterface.fckksGroup))
- scrollLayout.addWidget(NavigationCheckBox('Install Chara', self.settingInterface.installGroup))
- scrollLayout.addWidget(NavigationCheckBox('Remove Chara', self.settingInterface.removeGroup))
+ scrollLayout.addWidget(NavigationCheckBox('Create Backup', cfg.backupEnable, self.settingInterface.backupGroup))
+ scrollLayout.addWidget(NavigationCheckBox('Filter and Convert KKS', cfg.fckksEnable, self.settingInterface.fckksGroup))
+ scrollLayout.addWidget(NavigationCheckBox('Install Chara', cfg.installEnable, self.settingInterface.installGroup))
+ scrollLayout.addWidget(NavigationCheckBox('Remove Chara', cfg.removeEnable, self.settingInterface.removeGroup))
scrollLayout.addWidget(NavigationActionButtons())
# add custom widget to bottom
diff --git a/script.py b/script.py
index b3412d6..3ac79a6 100644
--- a/script.py
+++ b/script.py
@@ -4,7 +4,7 @@ try:
with open('traceback.log', 'w') as f:
pass
- from app.common.logger import Logger
+ from app.common.logger import logger
from app.modules.install_chara import InstallChara
from app.modules.remove_chara import RemoveChara
from app.modules.fc_kks import FilterConvertKKS
@@ -20,7 +20,7 @@ try:
config (Config): BAAuto Config instance
"""
self.config = config
- self.file_manager = file_manager
+ fileManager = file_manager
self.modules = {
'InstallChara': None,
'RemoveChara': None,
@@ -28,22 +28,22 @@ try:
'FCKKS': None,
}
if self.config.install_chara['Enable']:
- self.modules['InstallChara'] = InstallChara(self.config, self.file_manager)
+ self.modules['InstallChara'] = InstallChara(self.config, fileManager)
if self.config.remove_chara['Enable']:
- self.modules['RemoveChara'] = RemoveChara(self.config, self.file_manager)
+ self.modules['RemoveChara'] = RemoveChara(self.config, fileManager)
if self.config.create_backup['Enable']:
- self.modules['CreateBackup'] = CreateBackup(self.config, self.file_manager)
+ self.modules['CreateBackup'] = CreateBackup(self.config, fileManager)
if self.config.fc_kks["Enable"]:
- self.modules['FCKKS'] = FilterConvertKKS(self.config, self.file_manager)
+ self.modules['FCKKS'] = FilterConvertKKS(self.config, fileManager)
def run(self):
for task in self.config.tasks:
if self.modules[task]:
- Logger.log_info("SCRIPT", f'Start Task: {task}')
+ logger.info("SCRIPT", f'Start Task: {task}')
try:
self.modules[task].logic_wrapper()
except:
- Logger.log_error("SCRIPT", f'Task error: {task}. For more info, check the traceback.log file.')
+ logger.error("SCRIPT", f'Task error: {task}. For more info, check the traceback.log file.')
with open('traceback.log', 'a') as f:
f.write(f'[{task}]\n')
traceback.print_exc(None, f, True)