v0.2.7: 修复Redis连接 + 启动管理后台

- 修复Redis认证 (配置密码)
- 启动Python管理后台 (端口9531, 15个功能开关)
- 统一版本号 0.2.7
- 更新docker-compose.yml (镜像版本/Redis URL/Admin服务)
This commit is contained in:
2026-05-17 02:22:18 +08:00
commit 83cbfaf03f
164 changed files with 25195 additions and 0 deletions

View 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,
}