v0.2.7: 修复Redis连接 + 启动管理后台
- 修复Redis认证 (配置密码) - 启动Python管理后台 (端口9531, 15个功能开关) - 统一版本号 0.2.7 - 更新docker-compose.yml (镜像版本/Redis URL/Admin服务)
This commit is contained in:
203
cloudsearch_transfer/adapter/aliyun/cleanup.py
Normal file
203
cloudsearch_transfer/adapter/aliyun/cleanup.py
Normal file
@@ -0,0 +1,203 @@
|
||||
"""
|
||||
阿里云盘回收站清理模块 v1.0.0
|
||||
将文件移入回收站(非直接删除),支持批量操作。
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Dict
|
||||
|
||||
import requests
|
||||
|
||||
from .credential import AliyunCredentialManager, API_HOST
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# ─── API 端点 ──────────────────────────────────────────────
|
||||
|
||||
# 批量操作(v4)
|
||||
BATCH_URL = f"{API_HOST}/adrive/v4/batch"
|
||||
|
||||
# 默认请求头
|
||||
DEFAULT_HEADERS = {
|
||||
"User-Agent": (
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
"Chrome/135.0.0.0 Safari/537.36"
|
||||
),
|
||||
"Accept": "application/json, text/plain, */*",
|
||||
"Content-Type": "application/json",
|
||||
"Referer": "https://aliyundrive.com",
|
||||
}
|
||||
|
||||
|
||||
class AliyunCleanup:
|
||||
"""
|
||||
阿里云盘回收站清理
|
||||
|
||||
将文件移入回收站(放入回收站,非永久删除)。
|
||||
使用 v4 批量接口,支持一次清理多个文件。
|
||||
|
||||
用法:
|
||||
credential = AliyunCredentialManager(refresh_token="xxx")
|
||||
cleanup = AliyunCleanup(credential, drive_id="12345")
|
||||
result = cleanup.delete_files(["file_id_1", "file_id_2"])
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
credential: AliyunCredentialManager,
|
||||
drive_id: str = "",
|
||||
request_timeout: int = 30,
|
||||
):
|
||||
self.credential = credential
|
||||
self.drive_id = drive_id or credential.get_drive_id()
|
||||
self.request_timeout = request_timeout
|
||||
self._session = requests.Session()
|
||||
self._session.headers.update(DEFAULT_HEADERS)
|
||||
|
||||
# ─── 公开 API ──────────────────────────────────────────
|
||||
|
||||
def delete_files(self, file_ids: List[str]) -> Dict:
|
||||
"""
|
||||
将指定文件移入回收站(批量)。
|
||||
|
||||
Args:
|
||||
file_ids: 要删除的文件 ID 列表
|
||||
|
||||
Returns:
|
||||
{
|
||||
"success": True/False,
|
||||
"deleted_count": 成功删除数量,
|
||||
"total_count": 总文件数,
|
||||
"failed_ids": 失败的文件 ID 列表,
|
||||
"error": None or "错误信息",
|
||||
}
|
||||
|
||||
实现:
|
||||
POST /adrive/v4/batch
|
||||
{
|
||||
"requests": [
|
||||
{
|
||||
"url": "/recyclebin/trash",
|
||||
"body": {"file_id": "...", "drive_id": "..."},
|
||||
"headers": {"Content-Type": "application/json"},
|
||||
"id": "...",
|
||||
"method": "POST"
|
||||
}
|
||||
],
|
||||
"resource": "file"
|
||||
}
|
||||
"""
|
||||
if not file_ids:
|
||||
return self._error("文件 ID 列表为空")
|
||||
|
||||
drive_id = self.drive_id
|
||||
if not drive_id:
|
||||
drive_id = self.credential.get_drive_id()
|
||||
if not drive_id:
|
||||
return self._error("缺少 drive_id,无法执行删除操作")
|
||||
|
||||
# 构建批量请求体
|
||||
requests_list = []
|
||||
for fid in file_ids:
|
||||
requests_list.append({
|
||||
"url": "/recyclebin/trash",
|
||||
"body": {
|
||||
"drive_id": drive_id,
|
||||
"file_id": fid,
|
||||
},
|
||||
"headers": {"Content-Type": "application/json"},
|
||||
"id": fid,
|
||||
"method": "POST",
|
||||
})
|
||||
|
||||
try:
|
||||
headers = self.credential.get_headers()
|
||||
|
||||
resp = self._session.post(
|
||||
BATCH_URL,
|
||||
json={"requests": requests_list, "resource": "file"},
|
||||
headers=headers,
|
||||
timeout=self.request_timeout,
|
||||
)
|
||||
data = resp.json()
|
||||
|
||||
if resp.status_code != 200:
|
||||
logger.error(
|
||||
f"[AliyunCleanup] 批量删除失败: "
|
||||
f"HTTP {resp.status_code}, {data}"
|
||||
)
|
||||
return self._error(f"HTTP {resp.status_code}")
|
||||
|
||||
code = data.get("code", "")
|
||||
if code:
|
||||
logger.error(
|
||||
f"[AliyunCleanup] 批量删除 API 错误: "
|
||||
f"code={code}, message={data.get('message', '')}"
|
||||
)
|
||||
return self._error(data.get("message", f"API code={code}"))
|
||||
|
||||
# 统计结果
|
||||
responses = data.get("responses", [])
|
||||
success_ids = []
|
||||
failed_ids = []
|
||||
|
||||
for item in responses:
|
||||
status = item.get("status", 0)
|
||||
fid = item.get("id", "")
|
||||
if status in (200, 201, 202):
|
||||
success_ids.append(fid)
|
||||
else:
|
||||
logger.warning(
|
||||
f"[AliyunCleanup] 删除文件失败: "
|
||||
f"id={fid}, status={status}, body={item.get('body', {})}"
|
||||
)
|
||||
failed_ids.append(fid)
|
||||
|
||||
logger.info(
|
||||
f"[AliyunCleanup] 删除完成: "
|
||||
f"成功={len(success_ids)}, 失败={len(failed_ids)}, 总计={len(file_ids)}"
|
||||
)
|
||||
|
||||
return {
|
||||
"success": len(failed_ids) == 0,
|
||||
"deleted_count": len(success_ids),
|
||||
"total_count": len(file_ids),
|
||||
"success_ids": success_ids,
|
||||
"failed_ids": failed_ids,
|
||||
"error": None,
|
||||
}
|
||||
|
||||
except requests.RequestException as e:
|
||||
logger.error(f"[AliyunCleanup] 批量删除网络异常: {e}")
|
||||
return self._error(str(e))
|
||||
except Exception as e:
|
||||
logger.exception(f"[AliyunCleanup] 批量删除异常: {e}")
|
||||
return self._error(str(e))
|
||||
|
||||
def empty_recycle_bin(self) -> Dict:
|
||||
"""
|
||||
清空回收站(永久删除回收站中的所有文件)。
|
||||
|
||||
NOTE: 阿里云盘 API 目前不直接支持清空回收站,
|
||||
此方法作为占位,需要逐个文件 ID 调用 delete_files。
|
||||
实际使用请先 list 回收站内容再调用 delete_files。
|
||||
|
||||
Returns:
|
||||
{"success": False, "error": "清空回收站需要通过 list + delete 两步完成"}
|
||||
"""
|
||||
logger.warning("[AliyunCleanup] 清空回收站 API 暂未实现,需要 list+delete 两步")
|
||||
return self._error("清空回收站需要通过列出回收站内容 + 逐个删除两步完成,尚未实现")
|
||||
|
||||
# ─── 工具方法 ──────────────────────────────────────────
|
||||
|
||||
def _error(self, message: str) -> Dict:
|
||||
"""构造错误返回"""
|
||||
return {
|
||||
"success": False,
|
||||
"deleted_count": 0,
|
||||
"total_count": 0,
|
||||
"success_ids": [],
|
||||
"failed_ids": [],
|
||||
"error": message,
|
||||
}
|
||||
Reference in New Issue
Block a user