diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aaab5ad --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +build/ \ No newline at end of file diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 0000000..c732c0f --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,12 @@ +# macOS + +nuitka --standalone --enable-plugin=pyside6 --macos-create-app-bundle --output-dir=build GDUtils.py + +# Windows + +nuitka --standalone --enable-plugin=pyside6 --windows-console-mode=disable --output-dir=build GDUtils.py + +# Linux + +nuitka --standalone --enable-plugin=pyside6 --output-dir=build GDUtils.py + diff --git a/app.py b/GDUtils.py similarity index 81% rename from app.py rename to GDUtils.py index 1615086..c768121 100644 --- a/app.py +++ b/GDUtils.py @@ -1,17 +1,13 @@ import sys -from PyQt6.QtCore import Qt -from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QLabel, QPushButton, QFileDialog, QInputDialog, QMessageBox, QCheckBox -from PyQt6.QtGui import QFont +from PySide6.QtCore import Qt +from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QLabel, QPushButton, QFileDialog, QInputDialog, QMessageBox, QCheckBox +from PySide6.QtGui import QFont from Crypto.Cipher import AES import base64 import gzip import zlib import pyperclip import hashlib -import platform - -if platform.system() == "Windows": - from winmica import EnableMica, BackdropType, is_mica_supported MAC_SAVE_KEY = ( b"\x69\x70\x75\x39\x54\x55\x76\x35\x34\x79\x76\x5d\x69\x73\x46\x4d" @@ -98,7 +94,6 @@ class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("GDUtils") - self.apply_mica(self) titleLabel = QLabel("GDUtils") font = QFont() @@ -136,6 +131,19 @@ class MainWindow(QMainWindow): levelDataButtons.addWidget(self.levelDataIsOfficial, alignment=Qt.AlignmentFlag.AlignHCenter) levelDataButtons.addStretch() + gdLvlGDShareLabel = QLabel("GDLVL/GDShare") + + self.convertToGdLvl = QPushButton("Convert to GDLVL") + self.convertToGdLvl.clicked.connect(self.on_convert_from_gmd_click) + self.convertToGmd = QPushButton("Convert to GMD") + self.convertToGmd.clicked.connect(self.on_convert_from_gdlvl_click) + + gdLvlGDShareButtons = QHBoxLayout() + gdLvlGDShareButtons.addStretch() + gdLvlGDShareButtons.addWidget(self.convertToGdLvl, alignment=Qt.AlignmentFlag.AlignHCenter) + gdLvlGDShareButtons.addWidget(self.convertToGmd, alignment=Qt.AlignmentFlag.AlignHCenter) + gdLvlGDShareButtons.addStretch() + gjpLabel = QLabel("GJP") self.gjpDecode = QPushButton("Decode") @@ -160,6 +168,8 @@ class MainWindow(QMainWindow): layout.addLayout(saveFileButtons) layout.addWidget(levelDataLabel, alignment=Qt.AlignmentFlag.AlignHCenter) layout.addLayout(levelDataButtons) + layout.addWidget(gdLvlGDShareLabel, alignment=Qt.AlignmentFlag.AlignHCenter) + layout.addLayout(gdLvlGDShareButtons) layout.addWidget(gjpLabel, alignment=Qt.AlignmentFlag.AlignHCenter) layout.addLayout(gjpButtons) layout.addWidget(gjp2Label, alignment=Qt.AlignmentFlag.AlignHCenter) @@ -170,12 +180,6 @@ class MainWindow(QMainWindow): container.setLayout(layout) self.setCentralWidget(container) - def apply_mica(self, widget): - if platform.system() == "Windows" and is_mica_supported(): - widget.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True) - hwnd = int(widget.winId()) - EnableMica(hwnd, BackdropType.MICA) - def on_save_decode_click(self): file_path, _ = QFileDialog.getOpenFileName( self, @@ -237,7 +241,6 @@ class MainWindow(QMainWindow): dialog = QInputDialog(self) dialog.setWindowTitle("Level decoder") dialog.setLabelText("Enter the level data to decode:") - self.apply_mica(dialog) ok = dialog.exec() data = dialog.textValue() if ok and data: @@ -245,14 +248,12 @@ class MainWindow(QMainWindow): msg = QMessageBox() msg.setWindowTitle("Level decoder") msg.setText("The decoded level data has been copied to your clipboard") - self.apply_mica(msg) msg.exec() def on_level_encode_click(self): dialog = QInputDialog(self) dialog.setWindowTitle("Level encoder") dialog.setLabelText("Enter the level data to encode:") - self.apply_mica(dialog) ok = dialog.exec() data = dialog.textValue() if ok and data: @@ -260,14 +261,62 @@ class MainWindow(QMainWindow): msg = QMessageBox() msg.setWindowTitle("Level encoder") msg.setText("The encoded level data has been copied to your clipboard") - self.apply_mica(msg) msg.exec() + def on_convert_from_gdlvl_click(self): + file_path, _ = QFileDialog.getOpenFileName( + self, + "Select a GDLVL file", + "", + "GDLVL Files (*.gdlvl)" + ) + if not file_path: + return + + output_file_path, _ = QFileDialog.getSaveFileName( + self, + "Select a location for the output GMD file", + file_path.removesuffix(".gdlvl") + ".gmd", + "GMD Files (*.gmd)" + ) + if not output_file_path: + return + + with open(file_path, "r") as f: + data = f.read() + + with open(output_file_path, "w") as f: + f.write(decode_level(data, False)) + + def on_convert_from_gmd_click(self): + file_path, _ = QFileDialog.getOpenFileName( + self, + "Select a GMD file", + "", + "GMD Files (*.gmd)" + ) + if not file_path: + return + + output_file_path, _ = QFileDialog.getSaveFileName( + self, + "Select a location for the output GDLVL file", + file_path.removesuffix(".gmd") + ".gdlvl", + "GDLVL Files (*.gdlvl)" + ) + if not output_file_path: + return + + with open(file_path, "r") as f: + data = f.read() + + with open(output_file_path, "w") as f: + f.write(encode_level(data, False)) + def on_gjp_decode_click(self): dialog = QInputDialog(self) dialog.setWindowTitle("GJP decoder") dialog.setLabelText("Enter the GJP to decode:") - self.apply_mica(dialog) ok = dialog.exec() data = dialog.textValue() if ok and data: @@ -275,14 +324,12 @@ class MainWindow(QMainWindow): msg = QMessageBox() msg.setWindowTitle("GJP decoder") msg.setText("The decoded GJP has been copied to your clipboard") - self.apply_mica(msg) msg.exec() def on_gjp_encode_click(self): dialog = QInputDialog(self) dialog.setWindowTitle("GJP encoder") dialog.setLabelText("Enter the password to encode:") - self.apply_mica(dialog) ok = dialog.exec() data = dialog.textValue() if ok and data: @@ -290,14 +337,12 @@ class MainWindow(QMainWindow): msg = QMessageBox() msg.setWindowTitle("GJP encoder") msg.setText("The encoded GJP has been copied to your clipboard") - self.apply_mica(msg) msg.exec() def on_gjp2_encode_click(self): dialog = QInputDialog(self) dialog.setWindowTitle("GJP2 encoder") dialog.setLabelText("Enter the password to encode:") - self.apply_mica(dialog) ok = dialog.exec() data = dialog.textValue() if ok and data: @@ -305,7 +350,6 @@ class MainWindow(QMainWindow): msg = QMessageBox() msg.setWindowTitle("GJP2 encoder") msg.setText("The encoded GJP2 has been copied to your clipboard") - self.apply_mica(msg) msg.exec() app = QApplication(sys.argv) diff --git a/README.md b/README.md index 119ca7c..3441c6a 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,14 @@ A simple python utility app for things related to Geometry Dash - GJP encode/decode - GJP2 encode -## Setup +## Download + +Download the latest release for your platform [here](https://git.lncvrt.xyz/Lncvrt/gdutils/releases) + +## Run manually with Python [Download the repository as a ZIP](https://git.lncvrt.xyz/Lncvrt/gdutils/archive/main.zip) and unzip it then run: -`pip install -r requirements.txt` (you may need to replace pip with pip3) -then run -`python app.py` (you may need to replace python with python3) +`pip install -r requirements.txt` then run `python GDUtils.py` + +(you may need to replace pip and python with pip3 and python3) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e44d756..a3879c2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -PyQt6 +pyside6 pycryptodome pyperclip -winmica ; sys_platform == 'win32'