🎨 新增Player类 更改项目文件结构
This commit is contained in:
+134
@@ -0,0 +1,134 @@
|
||||
from pathlib import Path
|
||||
|
||||
from zhenxun.configs.path_config import DATA_PATH
|
||||
|
||||
# 签到状态
|
||||
g_bSignStatus = True
|
||||
|
||||
# 是否处于Debug模式
|
||||
g_bIsDebug = False
|
||||
|
||||
# 数据库文件目录
|
||||
g_sDBPath = DATA_PATH / "farm_db"
|
||||
|
||||
# 数据库文件路径
|
||||
g_sDBFilePath = DATA_PATH / "farm_db/farm.db"
|
||||
|
||||
# 农场资源文件目录
|
||||
g_sResourcePath = Path(__file__).resolve().parent / "../resource"
|
||||
|
||||
# 农场作物数据库
|
||||
g_sPlantPath = g_sResourcePath / "db/plant.db"
|
||||
|
||||
# 农场配置文件目录
|
||||
g_sConfigPath = Path(__file__).resolve().parent / "../config"
|
||||
|
||||
# 农场签到文件路径
|
||||
g_sSignInPath = g_sConfigPath / "sign_in.json"
|
||||
|
||||
# 土地等级上限
|
||||
g_iSoilLevelMax = 3
|
||||
|
||||
# 农场同一文本
|
||||
g_sTranslation = {
|
||||
"basic": {
|
||||
"notFarm": "尚未开通农场,快at我发送 开通农场 开通吧 🌱🚜",
|
||||
"point": "你的当前农场币为: {point} 🌾💰",
|
||||
"vipPoint": "你的当前点券为: {vipPoint} 🌾💰",
|
||||
"error": "❌ 农场功能异常,请稍后再试 💔",
|
||||
},
|
||||
"register": {
|
||||
"success": "✅ 农场开通成功!\n💼 初始资金:{point}农场币 🥳🎉",
|
||||
"repeat": "🎉 您已经开通农场啦~ 😄",
|
||||
"error": "⚠️ 开通失败,请稍后再试 💔",
|
||||
},
|
||||
"buySeed": {
|
||||
"notSeed": "🌱 请在指令后跟需要购买的种子名称",
|
||||
"notNum": "❗️ 请输入购买数量!",
|
||||
"noLevel": "🔒 你的等级不够哦,努努力吧 💪",
|
||||
"noPoint": "💰 你的农场币不够哦~ 快速速氪金吧!💸",
|
||||
"noVipPoint": "💰 你的点券不够哦~ 快速速氪金吧!💸",
|
||||
"success": "✅ 成功购买{name},花费{total}农场币,剩余{point}农场币 🌾",
|
||||
"vipSuccess": "✅ 成功购买{name},花费{total}点券,剩余{point}点券 🌾",
|
||||
"errorSql": "❌ 购买失败,执行数据库错误!🛑",
|
||||
"error": "❌ 购买出错!请检查需购买的种子名称!🔍",
|
||||
},
|
||||
"sowing": {
|
||||
"notSeed": "🌱 请在指令后跟需要播种的种子名称",
|
||||
"noSeed": "❌ 没有在你的仓库发现{name}种子,快去买点吧!🛒",
|
||||
"noNum": "⚠️ 播种失败!仓库中的{name}种子数量不足,当前剩余{num}个种子 🍂",
|
||||
"success": "✅ 播种{name}成功!仓库剩余{num}个种子 🌱",
|
||||
"success2": "✅ 播种数量超出开垦土地数量,已将可播种土地成功播种{name}!仓库剩余{num}个种子 🌾",
|
||||
"error": "❌ 播种失败,请稍后重试!⏳",
|
||||
},
|
||||
"harvest": {
|
||||
"append": "🌾 收获作物:{name},数量为:{num},经验为:{exp} ✨",
|
||||
"exp": "✨ 累计获得经验:{exp} 📈",
|
||||
"no": "🤷♂️ 没有可收获的作物哦~ 不要试图拔苗助长 🚫",
|
||||
"error": "❌ 收获失败,请稍后重试!⏳",
|
||||
},
|
||||
"eradicate": {
|
||||
"success": "🗑️ 成功铲除荒废作物,累计获得经验:{exp} ✨",
|
||||
"error": "❌ 没有可以铲除的作物 🚜",
|
||||
},
|
||||
"reclamation": {
|
||||
"confirm": "⚠️ 回复“是”将执行开垦 ⛏️",
|
||||
"timeOut": "⏰ 等待开垦回复超时,请重试",
|
||||
"perfect": "🌟 你已经开垦了全部土地 🎉",
|
||||
"next": "🔜 下次开垦所需条件:等级:{level},农场币:{num} 💰",
|
||||
"next2": "🔜 下次开垦所需条件:等级:{level},农场币:{num},物品:{item} 📦",
|
||||
"nextLevel": "📈 当前用户等级{level},升级所需等级为{next} ⏳",
|
||||
"noNum": "💰 当前用户农场币不足,升级所需农场币为{num} 💸",
|
||||
"success": "✅ 开垦土地成功!🌱",
|
||||
"error": "❌ 获取开垦土地条件失败!",
|
||||
"error1": "❌ 执行开垦失败!",
|
||||
"error2": "❌ 未知错误{e}💥",
|
||||
},
|
||||
"sellPlant": {
|
||||
"no": "🤷♀️ 你仓库没有可以出售的作物 🌾",
|
||||
"success": "💰 成功出售所有作物,获得农场币:{point},当前农场币:{num} 🎉",
|
||||
"success1": "💰 成功出售{name},获得农场币:{point},当前农场币:{num} 🥳",
|
||||
"error": "❌ 出售作物{name}出错:仓库中不存在该作物 🚫",
|
||||
"error1": "❌ 出售作物{name}出错:数量不足 ⚠️",
|
||||
},
|
||||
"stealing": {
|
||||
"noTarget": "🎯 请在指令后跟需要at的人 👤",
|
||||
"targetNotFarm": "🚜 目标尚未开通农场,快邀请ta开通吧 😉",
|
||||
"max": "❌ 你今天可偷次数到达上限啦,手下留情吧 🙏",
|
||||
"info": "🤫 成功偷到作物:{name},数量为:{num} 🍒",
|
||||
"noPlant": "🌱 目标没有作物可以被偷 🌾",
|
||||
"repeat": "🚫 你已经偷过目标啦,请手下留情 🙏",
|
||||
},
|
||||
"changeName": {
|
||||
"noName": "✏️ 请在指令后跟需要更改的农场名",
|
||||
"success": "✅ 更新农场名成功!🎉",
|
||||
"error": "❌ 农场名不支持特殊符号!🚫",
|
||||
"error1": "❌ 更新农场名失败!💔",
|
||||
},
|
||||
"signIn": {
|
||||
"success": "📝 签到成功!累计签到天数:{day}\n🎁 获得经验{exp},获得金币{num} 💰",
|
||||
"grandTotal": "\n🎉 成功领取累计签到奖励:\n✨ 额外获得经验{exp},额外获得金币{num} 🥳",
|
||||
"grandTotal1": ",额外获得点券{num} 🎫",
|
||||
"grandTotal2": "\n🌱 获得{name}种子 * {num} 🌟",
|
||||
"error": "❗️ 签到功能异常!",
|
||||
"error1": "❌ 签到失败!未知错误 💔",
|
||||
},
|
||||
"soilInfo": {
|
||||
"success": "土地成功升级至{name},效果为:{text}",
|
||||
"timeOut": "等待土地升级回复超时,请重试",
|
||||
"error": "土地信息尚未查询到",
|
||||
"error1": "该土地已经升至满级啦~",
|
||||
"red": "增产+10%",
|
||||
"black": "增产+20% 时间-20%",
|
||||
"gold": "增产+28% 经验+28% 时间-20%",
|
||||
"amethyst": "增产+30% 经验+30% 时间-25% 幸运+1%",
|
||||
"aquamarine": "增产+32% 经验+32% 时间-28% 幸运+1%",
|
||||
"blackcrystal": "增产+32% 经验+40% 时间-28% 幸运+2%",
|
||||
},
|
||||
"lockPlant": {
|
||||
"noPlant": "很抱歉,你的作物仓库中没有该作物",
|
||||
"lockPlant": "加锁成功,现在{name}不会被一键售卖了",
|
||||
"unlockPlant": "解锁成功,现在{name}会被一键售卖了",
|
||||
"error": "未知错误",
|
||||
},
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
import json
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
|
||||
from . import config
|
||||
from .request import g_pRequestManager
|
||||
|
||||
|
||||
class CJsonManager:
|
||||
def __init__(self):
|
||||
self.m_pItem = {}
|
||||
self.m_pLevel = {}
|
||||
self.m_pSoil = {}
|
||||
self.m_pSign = {}
|
||||
|
||||
async def init(self) -> bool:
|
||||
if not await self.initItem():
|
||||
return False
|
||||
|
||||
if not await self.initLevel():
|
||||
return False
|
||||
|
||||
if not await self.initSoil():
|
||||
return False
|
||||
|
||||
return await self.initSignInFile()
|
||||
|
||||
async def initItem(self) -> bool:
|
||||
try:
|
||||
with open(
|
||||
config.g_sConfigPath / "item.json",
|
||||
encoding="utf-8",
|
||||
) as file:
|
||||
self.m_pItem = json.load(file)
|
||||
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
logger.warning("item.json 打开失败")
|
||||
return False
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warning(f"item.json JSON格式错误: {e}")
|
||||
return False
|
||||
|
||||
async def initLevel(self) -> bool:
|
||||
try:
|
||||
with open(
|
||||
config.g_sConfigPath / "level.json",
|
||||
encoding="utf-8",
|
||||
) as file:
|
||||
self.m_pLevel = json.load(file)
|
||||
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
logger.warning("level.json 打开失败")
|
||||
return False
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warning(f"level.json JSON格式错误: {e}")
|
||||
return False
|
||||
|
||||
async def initSoil(self) -> bool:
|
||||
try:
|
||||
with open(
|
||||
config.g_sConfigPath / "soil.json",
|
||||
encoding="utf-8",
|
||||
) as file:
|
||||
self.m_pSoil = json.load(file)
|
||||
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
logger.warning("soil.json 打开失败")
|
||||
return False
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warning(f"soil.json JSON格式错误: {e}")
|
||||
return False
|
||||
|
||||
async def initSignInFile(self) -> bool:
|
||||
if not await g_pRequestManager.initSignInFile():
|
||||
config.g_bSignStatus = False
|
||||
|
||||
return False
|
||||
else:
|
||||
result = await self.initSign()
|
||||
|
||||
config.g_bSignStatus = result
|
||||
|
||||
return result
|
||||
|
||||
async def initSign(self) -> bool:
|
||||
try:
|
||||
with open(
|
||||
config.g_sSignInPath,
|
||||
encoding="utf-8",
|
||||
) as file:
|
||||
self.m_pSign = json.load(file)
|
||||
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
logger.warning("sign_in.json 打开失败")
|
||||
return False
|
||||
except json.JSONDecodeError as e:
|
||||
logger.warning(f"sign_in.json JSON格式错误: {e}")
|
||||
return False
|
||||
|
||||
|
||||
g_pJsonManager = CJsonManager()
|
||||
@@ -0,0 +1,293 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
import httpx
|
||||
from rich.progress import (
|
||||
BarColumn,
|
||||
DownloadColumn,
|
||||
Progress,
|
||||
TextColumn,
|
||||
TimeRemainingColumn,
|
||||
TransferSpeedColumn,
|
||||
)
|
||||
|
||||
from zhenxun.configs.config import Config
|
||||
from zhenxun.services.log import logger
|
||||
|
||||
from ..core.dbService import g_pDBService
|
||||
from .config import g_sPlantPath, g_sSignInPath
|
||||
from .tool import g_pToolManager
|
||||
|
||||
|
||||
class CRequestManager:
|
||||
m_sTokens = "xZ%?z5LtWV7H:0-Xnwp+bNRNQ-jbfrxG"
|
||||
|
||||
@classmethod
|
||||
async def download(
|
||||
cls,
|
||||
url: str,
|
||||
savePath: str,
|
||||
fileName: str,
|
||||
params: dict | None = None,
|
||||
jsonData: dict | None = None,
|
||||
) -> bool:
|
||||
"""下载文件到指定路径并覆盖已存在的文件
|
||||
|
||||
Args:
|
||||
url (str): 文件的下载链接
|
||||
savePath (str): 保存文件夹路径
|
||||
fileName (str): 保存后的文件名
|
||||
params (dict | None): 可选的 URL 查询参数
|
||||
jsonData (dict | None): 可选的 JSON 请求体
|
||||
|
||||
Returns:
|
||||
bool: 是否下载成功
|
||||
"""
|
||||
headers = {"token": cls.m_sTokens}
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||
requestArgs: dict = {"headers": headers}
|
||||
if params:
|
||||
requestArgs["params"] = params
|
||||
if jsonData:
|
||||
requestArgs["json"] = jsonData
|
||||
|
||||
response = await client.request(
|
||||
"GET", url, **requestArgs, follow_redirects=True
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
logger.warning(
|
||||
f"文件下载失败: HTTP {response.status_code} {response.text}"
|
||||
)
|
||||
return False
|
||||
|
||||
totalLength = int(response.headers.get("Content-Length", 0))
|
||||
fullPath = os.path.join(savePath, fileName)
|
||||
os.makedirs(os.path.dirname(fullPath), exist_ok=True)
|
||||
|
||||
with Progress(
|
||||
TextColumn("[progress.description]{task.description}"),
|
||||
BarColumn(),
|
||||
DownloadColumn(),
|
||||
TransferSpeedColumn(),
|
||||
TimeRemainingColumn(),
|
||||
transient=True,
|
||||
) as progress:
|
||||
task = progress.add_task(
|
||||
f"[green]【真寻农场】正在下载 {fileName}", total=totalLength
|
||||
)
|
||||
|
||||
with open(fullPath, "wb") as f:
|
||||
async for chunk in response.aiter_bytes(chunk_size=1024):
|
||||
f.write(chunk)
|
||||
progress.advance(task, len(chunk))
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"下载文件异常: {e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def post(cls, endpoint: str, name: str = "", jsonData: dict = {}) -> dict:
|
||||
"""发送POST请求到指定接口,统一调用,仅支持JSON格式数据
|
||||
|
||||
Args:
|
||||
endpoint (str): 请求的接口路径
|
||||
name (str, optional): 操作名称用于日志记录
|
||||
jsonData (dict): 以JSON格式发送的数据
|
||||
|
||||
Raises:
|
||||
ValueError: 当jsonData未提供时抛出
|
||||
|
||||
Returns:
|
||||
dict: 返回请求结果的JSON数据
|
||||
"""
|
||||
baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址")
|
||||
url = f"{baseUrl.rstrip('/')}:8998/{endpoint.lstrip('/')}"
|
||||
headers = {"token": cls.m_sTokens}
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=5.0) as client:
|
||||
response = await client.post(url, json=jsonData, headers=headers)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
logger.warning(
|
||||
f"{name}请求失败: HTTP {response.status_code} {response.text}"
|
||||
)
|
||||
return {}
|
||||
except httpx.RequestError as e:
|
||||
logger.warning(f"{name}请求异常", e=e)
|
||||
return {}
|
||||
except Exception as e:
|
||||
logger.warning(f"{name}处理异常", e=e)
|
||||
return {}
|
||||
|
||||
@classmethod
|
||||
async def get(cls, endpoint: str, name: str = "") -> dict:
|
||||
"""发送GET请求到指定接口,统一调用,仅支持无体的查询
|
||||
|
||||
Args:
|
||||
endpoint (str): 请求的接口路径
|
||||
name (str, optional): 操作名称用于日志记录
|
||||
|
||||
Returns:
|
||||
dict: 返回请求结果的JSON数据
|
||||
"""
|
||||
baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址")
|
||||
url = f"{baseUrl.rstrip('/')}:8998/{endpoint.lstrip('/')}"
|
||||
headers = {"token": cls.m_sTokens}
|
||||
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=5.0) as client:
|
||||
response = await client.get(url, headers=headers)
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
else:
|
||||
logger.warning(
|
||||
f"{name}请求失败: HTTP {response.status_code} {response.text}"
|
||||
)
|
||||
return {}
|
||||
except httpx.RequestError as e:
|
||||
logger.warning(f"{name}请求异常", e=e)
|
||||
return {}
|
||||
except Exception as e:
|
||||
logger.warning(f"{name}处理异常", e=e)
|
||||
return {}
|
||||
|
||||
@classmethod
|
||||
async def initSignInFile(cls) -> bool:
|
||||
if os.path.exists(g_sSignInPath):
|
||||
try:
|
||||
with open(g_sSignInPath, encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
sign = json.loads(content)
|
||||
|
||||
date = sign.get("date", "")
|
||||
yearMonth = g_pToolManager.dateTime().now().strftime("%Y%m")
|
||||
|
||||
if date == yearMonth:
|
||||
logger.debug("真寻农场签到文件检查完毕")
|
||||
return True
|
||||
else:
|
||||
logger.warning("真寻农场签到文件检查失败, 即将下载")
|
||||
return await cls.downloadSignInFile()
|
||||
except json.JSONDecodeError:
|
||||
logger.warning("真寻农场签到文件格式错误, 即将下载")
|
||||
return await cls.downloadSignInFile()
|
||||
else:
|
||||
return await cls.downloadSignInFile()
|
||||
|
||||
@classmethod
|
||||
async def downloadSignInFile(cls) -> bool:
|
||||
"""下载签到文件,并重命名为 sign_in.json
|
||||
|
||||
Returns:
|
||||
bool: 是否下载成功
|
||||
"""
|
||||
try:
|
||||
baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址")
|
||||
url = f"{baseUrl.rstrip('/')}:8998/sign_in"
|
||||
path = str(g_sSignInPath.parent.resolve(strict=False))
|
||||
yearMonth = g_pToolManager.dateTime().now().strftime("%Y%m")
|
||||
|
||||
# 下载为 signTemp.json
|
||||
success = await cls.download(
|
||||
url=url,
|
||||
savePath=path,
|
||||
fileName="signTemp.json",
|
||||
jsonData={"date": yearMonth},
|
||||
)
|
||||
|
||||
if not success:
|
||||
return False
|
||||
|
||||
# 重命名为 sign_in.json
|
||||
g_pToolManager.renameFile(f"{path}/signTemp.json", "sign_in.json")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error("下载签到文件失败", e=e)
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
async def initPlantDBFile(cls) -> bool:
|
||||
"""检查本地 plant.db 版本,如远程版本更新则重新下载
|
||||
|
||||
Returns:
|
||||
bool: 是否为最新版或成功更新
|
||||
"""
|
||||
versionPath = os.path.join(os.path.dirname(g_sPlantPath), "version.json")
|
||||
|
||||
try:
|
||||
with open(versionPath, encoding="utf-8") as f:
|
||||
localVersion = json.load(f).get("version", 0)
|
||||
except Exception as e:
|
||||
logger.warning(f"读取本地版本失败,默认版本为0: {e}")
|
||||
localVersion = 0
|
||||
|
||||
remoteInfo = await cls.get("plant_version", name="版本检查")
|
||||
remoteVersion = remoteInfo.get("version")
|
||||
|
||||
if remoteVersion is None:
|
||||
logger.warning("获取远程版本失败")
|
||||
return False
|
||||
|
||||
if float(remoteVersion) <= float(localVersion):
|
||||
logger.debug("plant.db 已为最新版本")
|
||||
return True
|
||||
|
||||
logger.warning(
|
||||
f"发现新版本 plant.db(远程: {remoteVersion} / 本地: {localVersion}),开始更新..."
|
||||
)
|
||||
|
||||
# 先断开数据库连接
|
||||
await g_pDBService.cleanup()
|
||||
|
||||
return await cls.downloadPlantDBFile(remoteVersion)
|
||||
|
||||
@classmethod
|
||||
async def downloadPlantDBFile(cls, remoteVersion: float) -> bool:
|
||||
"""下载最新版 plant.db 并更新本地 version.json
|
||||
|
||||
Args:
|
||||
remoteVersion (float): 远程版本号
|
||||
|
||||
Returns:
|
||||
bool: 是否下载并更新成功
|
||||
"""
|
||||
baseUrl = Config.get_config("zhenxun_plugin_farm", "服务地址")
|
||||
|
||||
savePath = os.path.dirname(g_sPlantPath)
|
||||
success = await cls.download(
|
||||
url=f"{baseUrl.rstrip('/')}:8998/file/plant.db",
|
||||
savePath=savePath,
|
||||
fileName="plantTemp.db",
|
||||
)
|
||||
|
||||
if not success:
|
||||
return False
|
||||
|
||||
# 重命名为 sign_in.json
|
||||
g_pToolManager.renameFile(f"{savePath}/plantTemp.db", "plant.db")
|
||||
|
||||
versionPath = os.path.join(savePath, "version.json")
|
||||
try:
|
||||
with open(versionPath, "w", encoding="utf-8") as f:
|
||||
json.dump({"version": remoteVersion}, f)
|
||||
logger.debug("版本文件已更新")
|
||||
except Exception as e:
|
||||
logger.warning(f"写入版本文件失败: {e}")
|
||||
return False
|
||||
|
||||
await g_pDBService.plant.init()
|
||||
await g_pDBService.plant.downloadPlant()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
g_pRequestManager = CRequestManager()
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
from datetime import datetime
|
||||
import os
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.message import MessageUtils
|
||||
|
||||
from ..core.player.player import CPlayer
|
||||
from ..core.player.playerPool import g_pUserPool
|
||||
|
||||
|
||||
class CToolManager:
|
||||
@classmethod
|
||||
async def repeat(cls):
|
||||
await MessageUtils.build_message(
|
||||
"尚未开通农场,快at我发送 开通农场 开通吧"
|
||||
).send()
|
||||
|
||||
@classmethod
|
||||
async def getPlayerByUid(cls, uid: str) -> CPlayer | None:
|
||||
player = g_pUserPool.getUser(uid)
|
||||
if player is None:
|
||||
player = CPlayer()
|
||||
if not await player.init(uid):
|
||||
return None
|
||||
g_pUserPool.createUser(uid, player)
|
||||
|
||||
return player
|
||||
|
||||
@classmethod
|
||||
def sanitize_username(cls, username: str, max_length: int = 15) -> str:
|
||||
"""
|
||||
安全处理用户名
|
||||
功能:
|
||||
1. 移除首尾空白
|
||||
2. 过滤危险字符
|
||||
3. 转义单引号
|
||||
4. 处理空值
|
||||
5. 限制长度
|
||||
"""
|
||||
# 处理空值
|
||||
if not username:
|
||||
return "神秘农夫"
|
||||
|
||||
# 基础清洗
|
||||
cleaned = username.strip()
|
||||
|
||||
# 允许的字符白名单(可自定义扩展)
|
||||
# fmt: off
|
||||
safe_chars = {
|
||||
"_", "-", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")",
|
||||
"+", "=", ".", ",", "~", "·", " ",
|
||||
"a","b","c","d","e","f","g","h","i","j","k","l","m",
|
||||
"n","o","p","q","r","s","t","u","v","w","x","y","z",
|
||||
"A","B","C","D","E","F","G","H","I","J","K","L","M",
|
||||
"N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
|
||||
"0","1","2","3","4","5","6","7","8","9",
|
||||
}
|
||||
# fmt: on
|
||||
# 添加常用中文字符(Unicode范围)
|
||||
safe_chars.update(chr(c) for c in range(0x4E00, 0x9FFF + 1))
|
||||
|
||||
# 过滤危险字符
|
||||
filtered = [
|
||||
c if c in safe_chars or 0x4E00 <= ord(c) <= 0x9FFF else "" for c in cleaned
|
||||
]
|
||||
|
||||
# 合并处理结果
|
||||
safe_str = "".join(filtered)
|
||||
|
||||
# 转义单引号(双重保障)
|
||||
escaped = safe_str.replace("'", "''")
|
||||
|
||||
# 处理空结果
|
||||
if not escaped:
|
||||
return "神秘农夫"
|
||||
|
||||
# 长度限制
|
||||
return escaped[:max_length]
|
||||
|
||||
@classmethod
|
||||
def renameFile(cls, currentFilePath: str, newFileName: str) -> bool:
|
||||
"""重命名文件,如果目标文件名已存在则先删除再重命名
|
||||
|
||||
Args:
|
||||
currentFilePath (str): 当前文件的完整路径
|
||||
newFileName (str): 重命名后的文件名
|
||||
|
||||
Returns:
|
||||
bool: 重命名成功返回 True,否则返回 False
|
||||
"""
|
||||
try:
|
||||
dirPath = os.path.dirname(currentFilePath)
|
||||
newFilePath = os.path.join(dirPath, newFileName)
|
||||
|
||||
if os.path.exists(newFilePath):
|
||||
os.remove(newFilePath)
|
||||
|
||||
os.rename(currentFilePath, newFilePath)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"文件重命名失败: {e}")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def dateTime(cls) -> datetime:
|
||||
tz = ZoneInfo("Asia/Shanghai")
|
||||
return datetime.now(tz)
|
||||
|
||||
|
||||
g_pToolManager = CToolManager()
|
||||
Reference in New Issue
Block a user