Compare commits
2
Commits
98f1c6631a
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b750d719c
|
||
|
|
69a8af761f
|
No files matched your search
@@ -0,0 +1,2 @@
|
|||||||
|
.DS_Store
|
||||||
|
build/
|
||||||
+12
@@ -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
|
||||||
|
|
||||||
+68
-24
@@ -1,17 +1,13 @@
|
|||||||
import sys
|
import sys
|
||||||
from PyQt6.QtCore import Qt
|
from PySide6.QtCore import Qt
|
||||||
from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QLabel, QPushButton, QFileDialog, QInputDialog, QMessageBox, QCheckBox
|
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QLabel, QPushButton, QFileDialog, QInputDialog, QMessageBox, QCheckBox
|
||||||
from PyQt6.QtGui import QFont
|
from PySide6.QtGui import QFont
|
||||||
from Crypto.Cipher import AES
|
from Crypto.Cipher import AES
|
||||||
import base64
|
import base64
|
||||||
import gzip
|
import gzip
|
||||||
import zlib
|
import zlib
|
||||||
import pyperclip
|
import pyperclip
|
||||||
import hashlib
|
import hashlib
|
||||||
import platform
|
|
||||||
|
|
||||||
if platform.system() == "Windows":
|
|
||||||
from winmica import EnableMica, BackdropType, is_mica_supported
|
|
||||||
|
|
||||||
MAC_SAVE_KEY = (
|
MAC_SAVE_KEY = (
|
||||||
b"\x69\x70\x75\x39\x54\x55\x76\x35\x34\x79\x76\x5d\x69\x73\x46\x4d"
|
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):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.setWindowTitle("GDUtils")
|
self.setWindowTitle("GDUtils")
|
||||||
self.apply_mica(self)
|
|
||||||
|
|
||||||
titleLabel = QLabel("GDUtils")
|
titleLabel = QLabel("GDUtils")
|
||||||
font = QFont()
|
font = QFont()
|
||||||
@@ -136,6 +131,19 @@ class MainWindow(QMainWindow):
|
|||||||
levelDataButtons.addWidget(self.levelDataIsOfficial, alignment=Qt.AlignmentFlag.AlignHCenter)
|
levelDataButtons.addWidget(self.levelDataIsOfficial, alignment=Qt.AlignmentFlag.AlignHCenter)
|
||||||
levelDataButtons.addStretch()
|
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")
|
gjpLabel = QLabel("GJP")
|
||||||
|
|
||||||
self.gjpDecode = QPushButton("Decode")
|
self.gjpDecode = QPushButton("Decode")
|
||||||
@@ -160,6 +168,8 @@ class MainWindow(QMainWindow):
|
|||||||
layout.addLayout(saveFileButtons)
|
layout.addLayout(saveFileButtons)
|
||||||
layout.addWidget(levelDataLabel, alignment=Qt.AlignmentFlag.AlignHCenter)
|
layout.addWidget(levelDataLabel, alignment=Qt.AlignmentFlag.AlignHCenter)
|
||||||
layout.addLayout(levelDataButtons)
|
layout.addLayout(levelDataButtons)
|
||||||
|
layout.addWidget(gdLvlGDShareLabel, alignment=Qt.AlignmentFlag.AlignHCenter)
|
||||||
|
layout.addLayout(gdLvlGDShareButtons)
|
||||||
layout.addWidget(gjpLabel, alignment=Qt.AlignmentFlag.AlignHCenter)
|
layout.addWidget(gjpLabel, alignment=Qt.AlignmentFlag.AlignHCenter)
|
||||||
layout.addLayout(gjpButtons)
|
layout.addLayout(gjpButtons)
|
||||||
layout.addWidget(gjp2Label, alignment=Qt.AlignmentFlag.AlignHCenter)
|
layout.addWidget(gjp2Label, alignment=Qt.AlignmentFlag.AlignHCenter)
|
||||||
@@ -170,12 +180,6 @@ class MainWindow(QMainWindow):
|
|||||||
container.setLayout(layout)
|
container.setLayout(layout)
|
||||||
self.setCentralWidget(container)
|
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):
|
def on_save_decode_click(self):
|
||||||
file_path, _ = QFileDialog.getOpenFileName(
|
file_path, _ = QFileDialog.getOpenFileName(
|
||||||
self,
|
self,
|
||||||
@@ -237,7 +241,6 @@ class MainWindow(QMainWindow):
|
|||||||
dialog = QInputDialog(self)
|
dialog = QInputDialog(self)
|
||||||
dialog.setWindowTitle("Level decoder")
|
dialog.setWindowTitle("Level decoder")
|
||||||
dialog.setLabelText("Enter the level data to decode:")
|
dialog.setLabelText("Enter the level data to decode:")
|
||||||
self.apply_mica(dialog)
|
|
||||||
ok = dialog.exec()
|
ok = dialog.exec()
|
||||||
data = dialog.textValue()
|
data = dialog.textValue()
|
||||||
if ok and data:
|
if ok and data:
|
||||||
@@ -245,14 +248,12 @@ class MainWindow(QMainWindow):
|
|||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setWindowTitle("Level decoder")
|
msg.setWindowTitle("Level decoder")
|
||||||
msg.setText("The decoded level data has been copied to your clipboard")
|
msg.setText("The decoded level data has been copied to your clipboard")
|
||||||
self.apply_mica(msg)
|
|
||||||
msg.exec()
|
msg.exec()
|
||||||
|
|
||||||
def on_level_encode_click(self):
|
def on_level_encode_click(self):
|
||||||
dialog = QInputDialog(self)
|
dialog = QInputDialog(self)
|
||||||
dialog.setWindowTitle("Level encoder")
|
dialog.setWindowTitle("Level encoder")
|
||||||
dialog.setLabelText("Enter the level data to encode:")
|
dialog.setLabelText("Enter the level data to encode:")
|
||||||
self.apply_mica(dialog)
|
|
||||||
ok = dialog.exec()
|
ok = dialog.exec()
|
||||||
data = dialog.textValue()
|
data = dialog.textValue()
|
||||||
if ok and data:
|
if ok and data:
|
||||||
@@ -260,14 +261,62 @@ class MainWindow(QMainWindow):
|
|||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setWindowTitle("Level encoder")
|
msg.setWindowTitle("Level encoder")
|
||||||
msg.setText("The encoded level data has been copied to your clipboard")
|
msg.setText("The encoded level data has been copied to your clipboard")
|
||||||
self.apply_mica(msg)
|
|
||||||
msg.exec()
|
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):
|
def on_gjp_decode_click(self):
|
||||||
dialog = QInputDialog(self)
|
dialog = QInputDialog(self)
|
||||||
dialog.setWindowTitle("GJP decoder")
|
dialog.setWindowTitle("GJP decoder")
|
||||||
dialog.setLabelText("Enter the GJP to decode:")
|
dialog.setLabelText("Enter the GJP to decode:")
|
||||||
self.apply_mica(dialog)
|
|
||||||
ok = dialog.exec()
|
ok = dialog.exec()
|
||||||
data = dialog.textValue()
|
data = dialog.textValue()
|
||||||
if ok and data:
|
if ok and data:
|
||||||
@@ -275,14 +324,12 @@ class MainWindow(QMainWindow):
|
|||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setWindowTitle("GJP decoder")
|
msg.setWindowTitle("GJP decoder")
|
||||||
msg.setText("The decoded GJP has been copied to your clipboard")
|
msg.setText("The decoded GJP has been copied to your clipboard")
|
||||||
self.apply_mica(msg)
|
|
||||||
msg.exec()
|
msg.exec()
|
||||||
|
|
||||||
def on_gjp_encode_click(self):
|
def on_gjp_encode_click(self):
|
||||||
dialog = QInputDialog(self)
|
dialog = QInputDialog(self)
|
||||||
dialog.setWindowTitle("GJP encoder")
|
dialog.setWindowTitle("GJP encoder")
|
||||||
dialog.setLabelText("Enter the password to encode:")
|
dialog.setLabelText("Enter the password to encode:")
|
||||||
self.apply_mica(dialog)
|
|
||||||
ok = dialog.exec()
|
ok = dialog.exec()
|
||||||
data = dialog.textValue()
|
data = dialog.textValue()
|
||||||
if ok and data:
|
if ok and data:
|
||||||
@@ -290,14 +337,12 @@ class MainWindow(QMainWindow):
|
|||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setWindowTitle("GJP encoder")
|
msg.setWindowTitle("GJP encoder")
|
||||||
msg.setText("The encoded GJP has been copied to your clipboard")
|
msg.setText("The encoded GJP has been copied to your clipboard")
|
||||||
self.apply_mica(msg)
|
|
||||||
msg.exec()
|
msg.exec()
|
||||||
|
|
||||||
def on_gjp2_encode_click(self):
|
def on_gjp2_encode_click(self):
|
||||||
dialog = QInputDialog(self)
|
dialog = QInputDialog(self)
|
||||||
dialog.setWindowTitle("GJP2 encoder")
|
dialog.setWindowTitle("GJP2 encoder")
|
||||||
dialog.setLabelText("Enter the password to encode:")
|
dialog.setLabelText("Enter the password to encode:")
|
||||||
self.apply_mica(dialog)
|
|
||||||
ok = dialog.exec()
|
ok = dialog.exec()
|
||||||
data = dialog.textValue()
|
data = dialog.textValue()
|
||||||
if ok and data:
|
if ok and data:
|
||||||
@@ -305,7 +350,6 @@ class MainWindow(QMainWindow):
|
|||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setWindowTitle("GJP2 encoder")
|
msg.setWindowTitle("GJP2 encoder")
|
||||||
msg.setText("The encoded GJP2 has been copied to your clipboard")
|
msg.setText("The encoded GJP2 has been copied to your clipboard")
|
||||||
self.apply_mica(msg)
|
|
||||||
msg.exec()
|
msg.exec()
|
||||||
|
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
@@ -9,10 +9,14 @@ A simple python utility app for things related to Geometry Dash
|
|||||||
- GJP encode/decode
|
- GJP encode/decode
|
||||||
- GJP2 encode
|
- 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:
|
[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)
|
`pip install -r requirements.txt` then run `python GDUtils.py`
|
||||||
then run
|
|
||||||
`python app.py` (you may need to replace python with python3)
|
(you may need to replace pip and python with pip3 and python3)
|
||||||
+1
-2
@@ -1,4 +1,3 @@
|
|||||||
PyQt6
|
pyside6
|
||||||
pycryptodome
|
pycryptodome
|
||||||
pyperclip
|
pyperclip
|
||||||
winmica
|
|
||||||
Reference in new issue
Block a user