new project for personal toolbox

This commit is contained in:
2025-09-09 16:22:57 +08:00
parent 4bacbb7bb8
commit 648dedb611
33 changed files with 1555 additions and 20 deletions

0
gui/codes/__init__.py Normal file
View File

View File

View File

View File

@@ -0,0 +1,6 @@
from pathlib import Path
base_path = Path(__file__).resolve().parent.parent.parent
code_dict = [4, 11, 4, 31, 22, 12, 19, 23, 7, 16, 7, 23, 1, 8, 7, 18, 27, 32, 28, 25, 7, 32, 9, 15, 2, 32, 0, 12, 26, 15, 14, 17]
salt = ""
max_db_number = 10

View File

@@ -0,0 +1,64 @@
import sqlite3
from threading import Lock
import time
from codes.common import clibs
def db_init(db_file):
conn = sqlite3.connect(db_file, isolation_level=None, check_same_thread=False, cached_statements=2048, timeout=10.0)
cursor = conn.cursor()
cursor.execute("PRAGMA journal_mode=wal")
cursor.execute("PRAGMA wal_checkpoint=TRUNCATE")
cursor.execute("PRAGMA synchronous=normal")
cursor.execute("PRAGMA temp_store=memory")
cursor.execute("PRAGMA mmap_size=30000000000")
cursor.execute("PRAGMA cache_size=200000")
cursor.execute(
"""
create table if not exists logs(
id integer primary key autoincrement,
timestamp DATETIME DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW', 'localtime')),
level text,
module text,
content text
)
"""
)
cursor.close()
conn.close()
def db_lock(func):
def wrapper(*args, **kwargs):
try:
Lock().acquire(True)
ret = func(*args, **kwargs)
finally:
Lock().release()
return ret
return wrapper
def db_backup():
t = time.strftime("%Y%m%d%H%M%S", time.localtime())
db_file = clibs.base_path / "assets/database/toolbox.db"
db_file_backup = clibs.base_path / f"assets/database/toolbox.{t}.db"
if not (db_file.exists() and db_file.is_file()):
db_init(db_file)
else:
db_file_backup.write_bytes(db_file.read_bytes())
db_dir = clibs.base_path / "assets/database"
db_list = [db for db in db_dir.glob("*.db")]
print(f"db_list: {sorted(db_list)}")
for db in sorted(db_list)[:-clibs.max_db_number]:
db.unlink()
def db_conn():
db_file = clibs.base_path / "assets/database/toolbox.db"
conn = sqlite3.connect(db_file, isolation_level=None, check_same_thread=False, cached_statements=2048, timeout=10.0)
cursor = conn.cursor()
cursor.execute("PRAGMA journal_mode=wal")
cursor.execute("PRAGMA wal_checkpoint=TRUNCATE")
cursor.execute("PRAGMA synchronous=normal")
cursor.execute("PRAGMA temp_store=memory")
cursor.execute("PRAGMA mmap_size=30000000000")
cursor.execute("PRAGMA cache_size=200000")
return conn, cursor

View File

@@ -0,0 +1,37 @@
import base64
import hashlib
from Crypto.Cipher import AES
from Crypto import Random
from Crypto.Util.Padding import pad, unpad
class PassCipher:
def __init__(self, salt):
salt = salt.encode("utf-8")
self.key = hashlib.sha256(salt).digest()
def encrypt(self, plaintext):
plaintext = plaintext.encode("utf-8")
iv = Random.new().read(AES.block_size)
cipher = AES.new(self.key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(plaintext, AES.block_size))
return base64.b64encode(iv + ciphertext).decode("utf-8")
def decrypt(self, ciphertext):
ciphertext = base64.b64decode(ciphertext)
iv = ciphertext[:AES.block_size]
ciphertext = ciphertext[AES.block_size:]
cipher = AES.new(self.key, AES.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size)
return plaintext.decode("utf-8")
# if __name__ == "__main__":
# salt = "my_secret_salt_string"
# cipher = PassCipher(salt)
# original_text = "这是一段需要加密的敏感信息"
# encrypted_text = cipher.encrypt(original_text)
# print(f"加密后的文本: {encrypted_text}")
# decrypted_text = cipher.decrypt(encrypted_text)
# print(f"解密后的文本: {decrypted_text}")
# print(f"加解密是否成功: {original_text == decrypted_text}")

26
gui/codes/common/ui2py.py Normal file
View File

@@ -0,0 +1,26 @@
import subprocess
import sys
from codes.common import clibs
from pathlib import Path
UIC_CMD = "pyside6-uic"
def single_uic(ui_path: str, py_path: str):
for file in Path(ui_path).rglob("*.ui"):
file_name = file.stem
ui_file = file
py_file = Path(py_path) / f"{file_name}.py"
cmd = [UIC_CMD, "-o", py_file, ui_file]
print(f"Processing {ui_file} -> {py_file}")
try:
subprocess.run(cmd, check=True, capture_output=True, text=True)
except subprocess.CalledProcessError as e:
print(f"转换失败: {ui_file}\n{e.stderr}", file=sys.stderr)
if __name__ == "__main__":
ui_path = clibs.base_path / "assets" / "ui"
py_path = clibs.base_path / "codes" / "ui"
single_uic(str(ui_path), str(py_path))

View File

@@ -0,0 +1,40 @@
from PySide6.QtCore import QThread, Signal, QRunnable, QThreadPool, QMetaObject, Q_ARG, QMetaType, Qt
from typing import Callable, Any
class Worker(QThread):
result = Signal(dict)
error = Signal(dict)
def __init__(self, func, *args, **kwargs):
super().__init__()
self.func = func
self.args = args
self.kwargs = kwargs
def run(self):
try:
result = self.func(*self.args, **self.kwargs)
self.result.emit({"result": result})
except Exception as error:
self.error.emit({"error": str(error)})
# launch函数必须在主进程中定义调用
# def launch(self, func, on_anything: Callable[..., Any] = print, *args, **kwargs):
# self.thread = Worker(func, *args, **kwargs)
# self.thread.started.connect(lambda: on_anything({"started": True}))
# self.thread.result.connect(on_anything)
# self.thread.error.connect(on_anything)
# self.thread.finished.connect(lambda: on_anything({"finished": True}))
# self.thread.start()
#
#
# def on_anything(results):
# if "started" in results:
# print("运行开始:", results["started"])
# if "result" in results:
# print("正常结束:", results["result"])
# if "error" in results:
# print(f"有异常发生:", results["error"])
# if "finished" in results:
# print("运行结束:", results["finished"])

0
gui/codes/ui/__init__.py Normal file
View File

85
gui/codes/ui/app.py Normal file
View File

@@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'app.ui'
##
## Created by: Qt User Interface Compiler version 6.9.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient,
QCursor, QFont, QFontDatabase, QGradient,
QIcon, QImage, QKeySequence, QLinearGradient,
QPainter, QPalette, QPixmap, QRadialGradient,
QTransform)
from PySide6.QtWidgets import (QApplication, QMainWindow, QMenu, QMenuBar,
QSizePolicy, QStatusBar, QWidget)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(1100, 550)
MainWindow.setMinimumSize(QSize(1100, 550))
font = QFont()
font.setFamilies([u"Consolas"])
font.setPointSize(12)
MainWindow.setFont(font)
self.actionExit = QAction(MainWindow)
self.actionExit.setObjectName(u"actionExit")
self.action = QAction(MainWindow)
self.action.setObjectName(u"action")
self.actionExit_2 = QAction(MainWindow)
self.actionExit_2.setObjectName(u"actionExit_2")
self.action_2 = QAction(MainWindow)
self.action_2.setObjectName(u"action_2")
self.action_3 = QAction(MainWindow)
self.action_3.setObjectName(u"action_3")
self.action_4 = QAction(MainWindow)
self.action_4.setObjectName(u"action_4")
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(MainWindow)
self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 1100, 33))
self.menu = QMenu(self.menubar)
self.menu.setObjectName(u"menu")
self.menu_2 = QMenu(self.menubar)
self.menu_2.setObjectName(u"menu_2")
self.menu_3 = QMenu(self.menubar)
self.menu_3.setObjectName(u"menu_3")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QStatusBar(MainWindow)
self.statusbar.setObjectName(u"statusbar")
MainWindow.setStatusBar(self.statusbar)
self.menubar.addAction(self.menu.menuAction())
self.menubar.addAction(self.menu_3.menuAction())
self.menubar.addAction(self.menu_2.menuAction())
self.menu.addAction(self.action_4)
self.menu.addAction(self.action_3)
self.menu_2.addAction(self.action_2)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
# setupUi
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"Toolbox", None))
self.actionExit.setText(QCoreApplication.translate("MainWindow", u"Exit", None))
self.action.setText(QCoreApplication.translate("MainWindow", u"\u5173\u4e8e", None))
self.actionExit_2.setText(QCoreApplication.translate("MainWindow", u"Exit", None))
self.action_2.setText(QCoreApplication.translate("MainWindow", u"\u5173\u4e8e", None))
self.action_3.setText(QCoreApplication.translate("MainWindow", u"\u9000\u51fa", None))
self.action_4.setText(QCoreApplication.translate("MainWindow", u"\u8bbe\u7f6e", None))
self.menu.setTitle(QCoreApplication.translate("MainWindow", u"\u6587\u4ef6", None))
self.menu_2.setTitle(QCoreApplication.translate("MainWindow", u"\u5e2e\u52a9", None))
self.menu_3.setTitle(QCoreApplication.translate("MainWindow", u"\u65e5\u5fd7", None))
# retranslateUi

145
gui/codes/ui/login.py Normal file
View File

@@ -0,0 +1,145 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'login.ui'
##
## Created by: Qt User Interface Compiler version 6.9.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QFormLayout, QHBoxLayout, QLabel,
QLineEdit, QPushButton, QSizePolicy, QVBoxLayout,
QWidget)
class Ui_login(object):
def setupUi(self, login):
if not login.objectName():
login.setObjectName(u"login")
login.resize(450, 150)
sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(login.sizePolicy().hasHeightForWidth())
login.setSizePolicy(sizePolicy)
login.setMinimumSize(QSize(450, 150))
login.setMaximumSize(QSize(450, 150))
self.verticalLayout_3 = QVBoxLayout(login)
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
self.horizontalLayout_2 = QHBoxLayout()
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
self.verticalLayout_2 = QVBoxLayout()
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.lb_logo = QLabel(login)
self.lb_logo.setObjectName(u"lb_logo")
self.lb_logo.setMinimumSize(QSize(100, 100))
self.lb_logo.setMaximumSize(QSize(105, 105))
self.lb_logo.setScaledContents(True)
self.lb_logo.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.lb_logo.setMargin(0)
self.lb_logo.setIndent(-1)
self.verticalLayout_2.addWidget(self.lb_logo)
self.lb_none = QLabel(login)
self.lb_none.setObjectName(u"lb_none")
self.lb_none.setMinimumSize(QSize(0, 40))
self.verticalLayout_2.addWidget(self.lb_none)
self.horizontalLayout_2.addLayout(self.verticalLayout_2)
self.verticalLayout = QVBoxLayout()
self.verticalLayout.setObjectName(u"verticalLayout")
self.formLayout = QFormLayout()
self.formLayout.setObjectName(u"formLayout")
self.formLayout.setLabelAlignment(Qt.AlignmentFlag.AlignCenter)
self.formLayout.setFormAlignment(Qt.AlignmentFlag.AlignCenter)
self.formLayout.setContentsMargins(30, 15, 30, 15)
self.lb_username = QLabel(login)
self.lb_username.setObjectName(u"lb_username")
font = QFont()
font.setFamilies([u"Consolas"])
font.setPointSize(12)
font.setItalic(True)
self.lb_username.setFont(font)
self.formLayout.setWidget(0, QFormLayout.ItemRole.LabelRole, self.lb_username)
self.le_username = QLineEdit(login)
self.le_username.setObjectName(u"le_username")
font1 = QFont()
font1.setFamilies([u"Consolas"])
font1.setPointSize(12)
self.le_username.setFont(font1)
self.formLayout.setWidget(0, QFormLayout.ItemRole.FieldRole, self.le_username)
self.lb_password = QLabel(login)
self.lb_password.setObjectName(u"lb_password")
self.lb_password.setFont(font)
self.formLayout.setWidget(1, QFormLayout.ItemRole.LabelRole, self.lb_password)
self.le_password = QLineEdit(login)
self.le_password.setObjectName(u"le_password")
self.le_password.setFont(font1)
self.le_password.setEchoMode(QLineEdit.EchoMode.Password)
self.formLayout.setWidget(1, QFormLayout.ItemRole.FieldRole, self.le_password)
self.verticalLayout.addLayout(self.formLayout)
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.horizontalLayout.setContentsMargins(40, 0, 40, 20)
self.pb_login = QPushButton(login)
self.pb_login.setObjectName(u"pb_login")
font2 = QFont()
font2.setFamilies([u"Consolas"])
font2.setPointSize(12)
font2.setBold(True)
self.pb_login.setFont(font2)
self.horizontalLayout.addWidget(self.pb_login)
self.pb_cancel = QPushButton(login)
self.pb_cancel.setObjectName(u"pb_cancel")
self.pb_cancel.setFont(font2)
self.horizontalLayout.addWidget(self.pb_cancel)
self.verticalLayout.addLayout(self.horizontalLayout)
self.horizontalLayout_2.addLayout(self.verticalLayout)
self.verticalLayout_3.addLayout(self.horizontalLayout_2)
self.retranslateUi(login)
QMetaObject.connectSlotsByName(login)
# setupUi
def retranslateUi(self, login):
login.setWindowTitle(QCoreApplication.translate("login", u"\u767b\u5f55", None))
self.lb_logo.setText("")
self.lb_none.setText("")
self.lb_username.setText(QCoreApplication.translate("login", u"Username", None))
self.lb_password.setText(QCoreApplication.translate("login", u"Password", None))
self.pb_login.setText(QCoreApplication.translate("login", u"\u767b\u5f55", None))
self.pb_cancel.setText(QCoreApplication.translate("login", u"\u53d6\u6d88", None))
# retranslateUi