[patch] 处理DY安装包打包后图片视频暂存路径部分权限问题
This commit is contained in:
@@ -686,6 +686,12 @@ class DouYinMessageHandler:
|
||||
self.sign_ctx = None
|
||||
self.js_engine = None
|
||||
|
||||
# 🧹 启动时清理超过24小时的旧临时文件
|
||||
self._cleanup_old_temp_files(max_age_hours=24)
|
||||
|
||||
# 🧹 设置定期清理任务(每6小时清理一次)
|
||||
self._setup_periodic_cleanup()
|
||||
|
||||
# 打印实例创建信息
|
||||
print(f"[DY Handler] 创建实例 {self.instance_id} for store {store_id}")
|
||||
|
||||
@@ -2079,8 +2085,9 @@ class DouYinMessageHandler:
|
||||
continue
|
||||
return None, None
|
||||
|
||||
# 保存到临时文件
|
||||
temp_dir = os.path.join(os.path.dirname(__file__), "temp_uploads")
|
||||
# 保存到临时文件(使用系统临时目录,兼容打包环境)
|
||||
import tempfile
|
||||
temp_dir = os.path.join(tempfile.gettempdir(), "shuidrop_temp_uploads")
|
||||
os.makedirs(temp_dir, exist_ok=True)
|
||||
|
||||
# 🔥 修复:智能提取文件扩展名
|
||||
@@ -2113,7 +2120,7 @@ class DouYinMessageHandler:
|
||||
return None, None
|
||||
|
||||
def _cleanup_temp_file(self, file_path):
|
||||
"""清理临时文件"""
|
||||
"""清理单个临时文件"""
|
||||
try:
|
||||
if file_path and os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
@@ -2121,6 +2128,76 @@ class DouYinMessageHandler:
|
||||
except Exception as e:
|
||||
self._log(f"⚠️ [DY上传] 删除临时文件失败: {e}", "WARNING")
|
||||
|
||||
def _cleanup_old_temp_files(self, max_age_hours=24):
|
||||
"""
|
||||
清理超过指定时间的旧临时文件
|
||||
|
||||
Args:
|
||||
max_age_hours: 文件最大保留时间(小时),默认24小时
|
||||
"""
|
||||
try:
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
temp_dir = os.path.join(tempfile.gettempdir(), "shuidrop_temp_uploads")
|
||||
if not os.path.exists(temp_dir):
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
max_age_seconds = max_age_hours * 3600
|
||||
cleaned_count = 0
|
||||
total_size = 0
|
||||
|
||||
# 遍历临时目录
|
||||
for filename in os.listdir(temp_dir):
|
||||
file_path = os.path.join(temp_dir, filename)
|
||||
|
||||
# 跳过目录
|
||||
if not os.path.isfile(file_path):
|
||||
continue
|
||||
|
||||
try:
|
||||
# 检查文件修改时间
|
||||
file_mtime = os.path.getmtime(file_path)
|
||||
file_age = current_time - file_mtime
|
||||
|
||||
# 如果文件超过保留时间,删除
|
||||
if file_age > max_age_seconds:
|
||||
file_size = os.path.getsize(file_path)
|
||||
os.remove(file_path)
|
||||
cleaned_count += 1
|
||||
total_size += file_size
|
||||
self._log(f"🗑️ [清理] 删除过期临时文件: {filename} (已存在{file_age/3600:.1f}小时)", "DEBUG")
|
||||
|
||||
except Exception as e:
|
||||
self._log(f"⚠️ [清理] 删除文件失败 {filename}: {e}", "WARNING")
|
||||
continue
|
||||
|
||||
if cleaned_count > 0:
|
||||
self._log(f"✅ [清理] 已清理 {cleaned_count} 个过期临时文件,释放空间: {total_size/(1024*1024):.2f}MB", "INFO")
|
||||
else:
|
||||
self._log(f"✅ [清理] 无需清理(所有临时文件都在保留期内)", "DEBUG")
|
||||
|
||||
except Exception as e:
|
||||
self._log(f"⚠️ [清理] 清理旧临时文件失败: {e}", "WARNING")
|
||||
|
||||
def _setup_periodic_cleanup(self):
|
||||
"""设置定期清理任务(每6小时清理一次超过24小时的文件)"""
|
||||
import threading
|
||||
|
||||
def periodic_cleanup_task():
|
||||
import time
|
||||
while self.is_running:
|
||||
# 每6小时清理一次
|
||||
time.sleep(6 * 3600) # 6小时
|
||||
if self.is_running:
|
||||
self._cleanup_old_temp_files(max_age_hours=24)
|
||||
|
||||
# 在后台线程中运行定期清理任务
|
||||
cleanup_thread = threading.Thread(target=periodic_cleanup_task, daemon=True, name="TempFileCleanup")
|
||||
cleanup_thread.start()
|
||||
self._log("🧹 [清理] 定期清理任务已启动(每6小时执行一次)", "DEBUG")
|
||||
|
||||
async def _get_upload_token(self, upload_type="image"):
|
||||
"""获取上传Token(图片或视频)"""
|
||||
try:
|
||||
@@ -2209,14 +2286,15 @@ class DouYinMessageHandler:
|
||||
if not upload_id:
|
||||
return None
|
||||
|
||||
success = await self._upload_file_part(store_uri, authorization, image_path, step=2, upload_id=upload_id)
|
||||
# 🔥 优化:只读取一次文件,计算CRC32并传递给step2和step3
|
||||
with open(image_path, 'rb') as f:
|
||||
file_content = f.read()
|
||||
crc32_hex = format(zlib.crc32(file_content), '08x')
|
||||
|
||||
success = await self._upload_file_part(store_uri, authorization, image_path, step=2, upload_id=upload_id, file_content=file_content, crc=crc32_hex)
|
||||
if not success:
|
||||
return None
|
||||
|
||||
with open(image_path, 'rb') as f:
|
||||
content = f.read()
|
||||
crc32_hex = format(zlib.crc32(content), '08x')
|
||||
|
||||
success = await self._upload_file_part(store_uri, authorization, image_path, step=3, upload_id=upload_id, crc=crc32_hex)
|
||||
if not success:
|
||||
return None
|
||||
@@ -2299,8 +2377,12 @@ class DouYinMessageHandler:
|
||||
self._log(f"❌ [DY图片] {action}失败: {e}", "ERROR")
|
||||
return None
|
||||
|
||||
async def _upload_file_part(self, uri, authorization, file_path, step, crc=None, upload_id=None):
|
||||
"""上传图片文件分片(带超时和重试)"""
|
||||
async def _upload_file_part(self, uri, authorization, file_path, step, crc=None, upload_id=None, file_content=None):
|
||||
"""上传图片文件分片(带超时和重试)
|
||||
|
||||
Args:
|
||||
file_content: 文件内容(step=2时直接使用,避免重复读取)
|
||||
"""
|
||||
try:
|
||||
headers = {
|
||||
"Authorization": authorization,
|
||||
@@ -2323,9 +2405,19 @@ class DouYinMessageHandler:
|
||||
return response.json().get("payload", {}).get("uploadID")
|
||||
|
||||
elif step == 2:
|
||||
with open(file_path, 'rb') as f:
|
||||
content = f.read()
|
||||
headers["Content-Crc32"] = format(zlib.crc32(content), '08x')
|
||||
# 🔥 优化:如果传入了file_content,直接使用;否则读取文件(兼容旧代码)
|
||||
if file_content is None:
|
||||
with open(file_path, 'rb') as f:
|
||||
content = f.read()
|
||||
else:
|
||||
content = file_content
|
||||
|
||||
# 使用传入的crc或重新计算(优先使用传入的)
|
||||
if crc:
|
||||
headers["Content-Crc32"] = crc
|
||||
else:
|
||||
headers["Content-Crc32"] = format(zlib.crc32(content), '08x')
|
||||
|
||||
headers["Content-Length"] = str(len(content))
|
||||
headers["Content-Type"] = 'application/octet-stream'
|
||||
params = {"partNumber": "1", "uploadID": upload_id}
|
||||
|
||||
Reference in New Issue
Block a user