""" 阿里云盘回收站清理模块 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, }