init
This commit is contained in:
1
app/core/utils/__init__.py
Normal file
1
app/core/utils/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .exceptions import getCode
|
||||
202
app/core/utils/config.py
Normal file
202
app/core/utils/config.py
Normal file
@@ -0,0 +1,202 @@
|
||||
# coding:utf-8
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
from PyQt6.QtGui import QPixmap
|
||||
from qfluentwidgets import (
|
||||
BoolValidator,
|
||||
ConfigItem,
|
||||
ConfigSerializer,
|
||||
OptionsConfigItem,
|
||||
OptionsValidator,
|
||||
qconfig,
|
||||
QConfig,
|
||||
FolderValidator,
|
||||
Theme,
|
||||
setThemeColor,
|
||||
)
|
||||
|
||||
from .encryption import encrypt
|
||||
from .setting import CONFIG_FILE, DOWNLOAD_FOLDER
|
||||
|
||||
|
||||
def isWin11():
|
||||
return sys.platform == "win32" and sys.getwindowsversion().build >= 22000
|
||||
|
||||
|
||||
class EncrpytionSerializer(ConfigSerializer):
|
||||
"""QColor serializer"""
|
||||
|
||||
def serialize(self, value):
|
||||
return encrypt.encrypt(value)
|
||||
|
||||
def deserialize(self, value):
|
||||
|
||||
return encrypt.decrypt(value)
|
||||
|
||||
|
||||
class Config(QConfig):
|
||||
"""Config of application"""
|
||||
|
||||
# TODO: ADD YOUR CONFIG GROUP HERE
|
||||
|
||||
# register
|
||||
rememberMe = ConfigItem(
|
||||
"UmVnaXN0ZXI=", "UmVtZW1iZXJNZQ==", True, serializer=EncrpytionSerializer()
|
||||
)
|
||||
email = ConfigItem(
|
||||
"UmVnaXN0ZXI=", "RW1haWw=", "", serializer=EncrpytionSerializer()
|
||||
)
|
||||
activationCode = ConfigItem(
|
||||
"UmVnaXN0ZXI=", "QWN0aXZhdGlvbkNvZGU=", "", serializer=EncrpytionSerializer()
|
||||
)
|
||||
|
||||
# main window
|
||||
micaEnabled = ConfigItem("MainWindow", "MicaEnabled", isWin11(), BoolValidator())
|
||||
dpiScale = OptionsConfigItem(
|
||||
"MainWindow",
|
||||
"DpiScale",
|
||||
"Auto",
|
||||
OptionsValidator([1, 1.25, 1.5, 1.75, 2, "Auto"]),
|
||||
restart=True,
|
||||
)
|
||||
|
||||
# software update
|
||||
checkUpdateAtStartUp = ConfigItem(
|
||||
"Update", "CheckUpdateAtStartUp", True, BoolValidator()
|
||||
)
|
||||
|
||||
# bg
|
||||
customBackground = ConfigItem(
|
||||
"Background",
|
||||
"CustomBackground",
|
||||
"app\\resource\\images\\bg0.png",
|
||||
)
|
||||
customOpactity = ConfigItem("Background", "Opactity", 0.2)
|
||||
|
||||
downloadSavePath = ConfigItem(
|
||||
"Download", "SavePath", DOWNLOAD_FOLDER, validator=FolderValidator()
|
||||
)
|
||||
|
||||
# language
|
||||
language = OptionsConfigItem(
|
||||
"General", "Language", "zh", OptionsValidator(["zh", "en"]), restart=False
|
||||
)
|
||||
|
||||
|
||||
class UserConfig:
|
||||
def __init__(self, userData):
|
||||
self.userData = userData
|
||||
self.token = None
|
||||
self.avaterPixmap = None
|
||||
|
||||
@property
|
||||
def userId(self):
|
||||
if self.userData:
|
||||
return self.userData["data"].get("id", "")
|
||||
else:
|
||||
return None
|
||||
|
||||
@property
|
||||
def userAvatarURL(self):
|
||||
if self.userData and "avatar" in self.userData["data"]:
|
||||
return self.userData["data"].get("avatar", "")
|
||||
else:
|
||||
return ""
|
||||
|
||||
@property
|
||||
def userName(self):
|
||||
if self.userData:
|
||||
return self.userData["data"].get("nickname", "")
|
||||
else:
|
||||
return ""
|
||||
|
||||
@property
|
||||
def userEmail(self):
|
||||
if self.userData:
|
||||
return self.userData["data"].get("user_name", "")
|
||||
else:
|
||||
return ""
|
||||
|
||||
@property
|
||||
def userGroup(self):
|
||||
if self.userData:
|
||||
return self.userData.get("data", {}).get("group", {}).get("name", "")
|
||||
else:
|
||||
return ""
|
||||
|
||||
@property
|
||||
def userScore(self):
|
||||
if self.userData:
|
||||
return str(self.userData["data"].get("score", 0))
|
||||
|
||||
@property
|
||||
def userCreatedTime(self):
|
||||
if self.userData:
|
||||
return self.format_date(self.userData["data"].get("created_at", ""))
|
||||
|
||||
def setUserAvatarPixmap(self, avaterPixmap):
|
||||
self.avaterPixmap: QPixmap = avaterPixmap
|
||||
|
||||
def returnAvatarPixmap(self):
|
||||
return self.avaterPixmap
|
||||
|
||||
def setToken(self, token):
|
||||
"""设置JWT token"""
|
||||
self.token = token
|
||||
|
||||
def getToken(self):
|
||||
"""获取JWT token"""
|
||||
return self.token
|
||||
|
||||
def format_date(self, date_str):
|
||||
"""格式化日期时间"""
|
||||
try:
|
||||
# 处理带小数秒的情况
|
||||
if "." in date_str:
|
||||
# 分割日期和小数秒部分
|
||||
date_part, fractional_part = date_str.split(".", 1)
|
||||
# 去除末尾的"Z"并截取前6位小数
|
||||
fractional_sec = fractional_part.rstrip("Z")[:6]
|
||||
# 重新组合日期字符串
|
||||
normalized_date_str = f"{date_part}.{fractional_sec}Z"
|
||||
date_time = datetime.strptime(
|
||||
normalized_date_str, "%Y-%m-%dT%H:%M:%S.%fZ"
|
||||
)
|
||||
else:
|
||||
# 处理没有小数秒的情况
|
||||
date_time = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ")
|
||||
except ValueError:
|
||||
# 如果所有格式都失败,返回原始字符串
|
||||
return date_str
|
||||
|
||||
return date_time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
class PolicyConfig:
|
||||
def __init__(self):
|
||||
self.currentPolicy = {}
|
||||
self.currentPath = "/"
|
||||
|
||||
def returnPolicy(self):
|
||||
return self.currentPolicy
|
||||
|
||||
def setPolicy(self, policy):
|
||||
self.currentPolicy = policy
|
||||
|
||||
def setCurrentPath(self, path):
|
||||
self.currentPath = path
|
||||
|
||||
def returnCurrentPath(self):
|
||||
return self.currentPath
|
||||
|
||||
|
||||
cfg = Config()
|
||||
cfg.themeMode.value = Theme.AUTO
|
||||
# 设置默认主题色为蓝色 (使用RGB值)
|
||||
setThemeColor('#2F80ED') # 这是一个标准的蓝色RGB值
|
||||
qconfig.load(str(CONFIG_FILE.absolute()), cfg)
|
||||
|
||||
userConfig = UserConfig(None)
|
||||
|
||||
policyConfig = PolicyConfig()
|
||||
77
app/core/utils/encryption.py
Normal file
77
app/core/utils/encryption.py
Normal file
@@ -0,0 +1,77 @@
|
||||
import json
|
||||
import base64
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util.Padding import pad, unpad
|
||||
from Crypto.Random import get_random_bytes
|
||||
|
||||
|
||||
# from .setting import ENCRYPTKEY
|
||||
ENCRYPTKEY = b"lunminalinguaai_"
|
||||
|
||||
|
||||
class AESCipher:
|
||||
def __init__(self, key):
|
||||
"""
|
||||
初始化AES加密器
|
||||
:param key: 加密密钥(16/24/32字节),可以是字符串或字节
|
||||
"""
|
||||
if isinstance(key, str):
|
||||
key = key.encode("utf-8")
|
||||
if len(key) not in [16, 24, 32]:
|
||||
raise ValueError("密钥长度必须为16、24或32字节")
|
||||
self.key = key
|
||||
|
||||
def encrypt(self, data):
|
||||
"""
|
||||
加密数据(支持字符串/列表/字典等JSON可序列化类型)
|
||||
:param data: 要加密的数据
|
||||
:return: 返回Base64编码的加密字符串
|
||||
"""
|
||||
# 生成随机初始化向量
|
||||
iv = get_random_bytes(AES.block_size)
|
||||
|
||||
# 创建AES加密器
|
||||
cipher = AES.new(self.key, AES.MODE_CBC, iv)
|
||||
|
||||
# 序列化数据为JSON字符串并编码为字节
|
||||
json_data = json.dumps(data)
|
||||
plain_bytes = json_data.encode("utf-8")
|
||||
|
||||
# 填充并加密数据
|
||||
padded_bytes = pad(plain_bytes, AES.block_size)
|
||||
cipher_bytes = cipher.encrypt(padded_bytes)
|
||||
|
||||
# 组合IV和密文并进行Base64编码
|
||||
encrypted_data = iv + cipher_bytes
|
||||
return base64.b64encode(encrypted_data).decode("utf-8")
|
||||
|
||||
def decrypt(self, enc_data):
|
||||
"""
|
||||
解密数据并恢复原始格式
|
||||
:param enc_data: Base64编码的加密字符串
|
||||
:return: 原始数据(保持原始格式)
|
||||
"""
|
||||
# Base64解码
|
||||
encrypted_data = base64.b64decode(enc_data)
|
||||
|
||||
# 提取初始化向量
|
||||
iv = encrypted_data[: AES.block_size]
|
||||
cipher_bytes = encrypted_data[AES.block_size :]
|
||||
|
||||
# 创建AES解密器
|
||||
cipher = AES.new(self.key, AES.MODE_CBC, iv)
|
||||
|
||||
# 解密并去除填充
|
||||
decrypted_bytes = cipher.decrypt(cipher_bytes)
|
||||
unpadded_bytes = unpad(decrypted_bytes, AES.block_size)
|
||||
|
||||
# 解码JSON并恢复原始数据结构
|
||||
json_data = unpadded_bytes.decode("utf-8")
|
||||
return json.loads(json_data)
|
||||
|
||||
encrypt = AESCipher(ENCRYPTKEY)
|
||||
|
||||
if __name__ == '__main__':
|
||||
data = "sk-3e47a49bf60e49e8ab08bb1f1550aa86"
|
||||
enc_data = encrypt.encrypt(data)
|
||||
print(enc_data)
|
||||
14
app/core/utils/exceptions.py
Normal file
14
app/core/utils/exceptions.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# API请求code
|
||||
|
||||
stateCodeList = {
|
||||
"0": "成功",
|
||||
"40026": "验证码错误",
|
||||
"40001": "读取用户头像数据失败",
|
||||
"40020": "邮箱或密码不正确",
|
||||
"40018": "该账号未激活",
|
||||
"40033": "用户未激活,已重新发送激活邮件",
|
||||
}
|
||||
|
||||
|
||||
def getCode(code):
|
||||
return stateCodeList.get(str(code), "未知错误,请联系技术支持")
|
||||
67
app/core/utils/format.py
Normal file
67
app/core/utils/format.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def formatSize(size):
|
||||
"""格式化文件大小"""
|
||||
for unit in ["B", "KB", "MB", "GB", "TB"]:
|
||||
if size < 1024:
|
||||
return f"{size:.2f} {unit}"
|
||||
size /= 1024
|
||||
return f"{size:.2f} PB"
|
||||
|
||||
|
||||
def formatDate(date_str):
|
||||
"""格式化日期时间"""
|
||||
try:
|
||||
# 处理带小数秒的情况
|
||||
if "." in date_str:
|
||||
# 分割日期和小数秒部分
|
||||
date_part, fractional_part = date_str.split(".", 1)
|
||||
# 去除末尾的'Z'并截取前6位小数
|
||||
fractional_sec = fractional_part.rstrip("Z")[:6]
|
||||
# 重新组合日期字符串
|
||||
normalized_date_str = f"{date_part}.{fractional_sec}Z"
|
||||
date_time = datetime.strptime(normalized_date_str, "%Y-%m-%dT%H:%M:%S.%fZ")
|
||||
else:
|
||||
# 处理没有小数秒的情况
|
||||
date_time = datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ")
|
||||
except ValueError:
|
||||
# 如果所有格式都失败,返回原始字符串
|
||||
return date_str
|
||||
|
||||
return date_time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
def getFileIcon(fileType, fileName):
|
||||
if fileType == "file":
|
||||
suffix = fileName.split(".")[-1].lower()
|
||||
icon_map = {
|
||||
"txt": "Txt.svg",
|
||||
"png": "Image.svg",
|
||||
"jpg": "Image.svg",
|
||||
"svg": "Image.svg",
|
||||
"jpeg": "Image.svg",
|
||||
"bmp": "Image.svg",
|
||||
"gif": "Gif.svg",
|
||||
"xls": "Excel.svg",
|
||||
"xlsx": "Excel.svg",
|
||||
"doc": "Word.svg",
|
||||
"docx": "Word.svg",
|
||||
"pdf": "Pdf.svg",
|
||||
"ppt": "PPT.svg",
|
||||
"mp4": "Video.svg",
|
||||
"mkv": "Video.svg",
|
||||
"mp3": "music.svg",
|
||||
"wav": "music.svg",
|
||||
"zip": "Zip.svg",
|
||||
"rar": "Zip.svg",
|
||||
"csv": "Excel.svg",
|
||||
"db": "Database.svg",
|
||||
"py": "Programme.svg",
|
||||
"c": "Programme.svg",
|
||||
"cpp": "Programme.svg",
|
||||
"go": "Programme.svg",
|
||||
}
|
||||
return icon_map.get(suffix, "None.svg") # 默认图标
|
||||
else:
|
||||
return "Folder.svg"
|
||||
90
app/core/utils/morelang.py
Normal file
90
app/core/utils/morelang.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# coding: utf-8
|
||||
import json
|
||||
import os
|
||||
from loguru import logger
|
||||
from pathlib import Path
|
||||
|
||||
# 导入配置
|
||||
from .config import cfg, qconfig
|
||||
|
||||
# 当前语言设置,默认为中文
|
||||
_current_language = "zh"
|
||||
# 翻译词典
|
||||
_translations = {}
|
||||
# 语言文件目录
|
||||
_LANG_DIR = Path("app/resource/lang").absolute()
|
||||
# print(Path("app/resource/lang").absolute())
|
||||
|
||||
|
||||
def load_language(lang_code="zh"):
|
||||
"""
|
||||
加载指定语言的翻译文件
|
||||
|
||||
Args:
|
||||
lang_code: 语言代码,如 "zh"、"en"
|
||||
"""
|
||||
global _current_language, _translations
|
||||
|
||||
try:
|
||||
# 构建语言文件路径
|
||||
lang_file = os.path.join(_LANG_DIR, f"{lang_code}.json")
|
||||
|
||||
# 检查文件是否存在
|
||||
if not os.path.exists(lang_file):
|
||||
logger.warning(f"语言文件不存在: {lang_file},使用默认语言")
|
||||
lang_code = "zh"
|
||||
lang_file = os.path.join(_LANG_DIR, "zh.json")
|
||||
|
||||
# 读取语言文件
|
||||
with open(lang_file, "r", encoding="utf-8") as f:
|
||||
_translations = json.load(f)
|
||||
|
||||
_current_language = lang_code
|
||||
logger.info(f"已加载语言: {lang_code}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"加载语言文件失败: {e}")
|
||||
# 如果加载失败,使用空字典
|
||||
_translations = {}
|
||||
|
||||
|
||||
def lang(text):
|
||||
"""
|
||||
翻译文本
|
||||
|
||||
Args:
|
||||
text: 要翻译的原文
|
||||
|
||||
Returns:
|
||||
翻译后的文本,如果没有找到翻译,则返回原文
|
||||
"""
|
||||
# 如果翻译词典为空,尝试加载默认语言
|
||||
if not _translations:
|
||||
load_language(_current_language)
|
||||
|
||||
# 返回翻译后的文本,找不到则返回原文
|
||||
return _translations.get(text, text)
|
||||
|
||||
|
||||
def get_current_language():
|
||||
"""
|
||||
获取当前语言代码
|
||||
|
||||
Returns:
|
||||
当前语言代码
|
||||
"""
|
||||
return _current_language
|
||||
|
||||
|
||||
# 初始化时从配置加载语言
|
||||
try:
|
||||
if hasattr(cfg, "language"):
|
||||
initial_lang = qconfig.get(cfg.language)
|
||||
load_language(initial_lang)
|
||||
else:
|
||||
# 如果配置中没有语言设置,使用默认值
|
||||
load_language()
|
||||
except Exception as e:
|
||||
logger.error(f"加载语言配置时出错: {e}")
|
||||
# 出错时使用默认语言
|
||||
load_language("zh")
|
||||
16
app/core/utils/setting.py
Normal file
16
app/core/utils/setting.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# coding: utf-8
|
||||
from pathlib import Path
|
||||
|
||||
# change DEBUG to False if you want to compile the code to exe
|
||||
DEBUG = "__compiled__" not in globals()
|
||||
|
||||
|
||||
YEAR = 2025
|
||||
AUTHOR = "Miao"
|
||||
VERSION = "v0.0.1"
|
||||
APP_NAME = "miaostarspan"
|
||||
|
||||
CONFIG_FOLDER = Path("config").absolute()
|
||||
CONFIG_FILE = CONFIG_FOLDER / "config.json"
|
||||
DOWNLOAD_FOLDER = Path("download").absolute()
|
||||
# 23
|
||||
34
app/core/utils/signal_bus.py
Normal file
34
app/core/utils/signal_bus.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# coding: utf-8
|
||||
from PyQt6.QtCore import QObject, pyqtSignal
|
||||
from PyQt6.QtGui import QPixmap
|
||||
|
||||
|
||||
class SignalBus(QObject):
|
||||
"""Signal bus"""
|
||||
|
||||
checkUpdateSig = pyqtSignal()
|
||||
micaEnableChanged = pyqtSignal(bool)
|
||||
|
||||
dirOpenSignal = pyqtSignal(str)
|
||||
shareDirOpenSignal = pyqtSignal(str)
|
||||
avatarUpdated = pyqtSignal(QPixmap) # 头像更新信号
|
||||
|
||||
imagePreviewSignal = pyqtSignal(str)
|
||||
txtPreviewSignal = pyqtSignal(str)
|
||||
|
||||
opacityChanged = pyqtSignal() # 透明度变化信号
|
||||
backgroundChanged = pyqtSignal() # 背景颜色变化信号
|
||||
|
||||
refreshFolderListSignal = pyqtSignal()
|
||||
|
||||
addUploadFileTask = pyqtSignal(str) # 添加upload任务信号
|
||||
addDownloadFileTask = pyqtSignal(str, str, str) # 添加download任务信号
|
||||
|
||||
shareFolderViewSignal = pyqtSignal(str) # 分享文件夹
|
||||
shareFileDownloadSignal = pyqtSignal() # 分享文件下载
|
||||
|
||||
languageChanged = pyqtSignal() # 语言变更信号
|
||||
loginSuccessSignal = pyqtSignal() # 登录成功信号
|
||||
|
||||
|
||||
signalBus = SignalBus()
|
||||
6
app/core/utils/version.py
Normal file
6
app/core/utils/version.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# coding: utf-8
|
||||
"""
|
||||
Version information for the application
|
||||
"""
|
||||
|
||||
version = "0.0.2"
|
||||
Reference in New Issue
Block a user