fix(anime): 파이프라인 5건 수정 — 에피소드 정규식(v2/S01E), 릴리스 그룹 필터, 자막 보호, 배치 다운로드, 타임아웃

This commit is contained in:
2026-03-15 08:27:08 +09:00
parent 63818999d9
commit 9f74812710
40 changed files with 2759 additions and 815 deletions

View File

@@ -196,3 +196,66 @@ class QBitClient:
}
except Exception as e:
return {"connected": False, "error": str(e), "url": self.url}
async def delete_torrent(self, info_hash: str, delete_files: bool = False) -> bool:
"""토렌트 삭제 (완료 후 정리용)."""
await self._ensure_login()
async with httpx.AsyncClient(timeout=10) as client:
resp = await client.post(
f"{self.url}/api/v2/torrents/delete",
data={
"hashes": info_hash,
"deleteFiles": str(delete_files).lower(),
},
cookies=self._cookies(),
)
return resp.status_code == 200
# ── CLI 진입점 ──
if __name__ == "__main__":
import sys
import asyncio
args = sys.argv[1:]
client = QBitClient()
async def main():
if not args or args[0] == "status":
# python tools/qbit_client.py status
torrents = await client.list_torrents(category="anime")
if not torrents:
print("🎬 다운로드 중인 애니 없음")
return
print(f"🎬 다운로드 현황 ({len(torrents)}건):")
for t in torrents:
speed = f"{t.download_speed / (1024**2):.1f}MB/s" if t.download_speed > 0 else "-"
eta = f"{t.eta // 60}" if t.eta > 0 else ""
print(f" {t.progress*100:.0f}% | {t.name[:50]} | {speed} | ETA: {eta}")
elif args[0] == "add" and len(args) > 1:
# python tools/qbit_client.py add "magnet:..." --path "\\NAS\path"
magnet = args[1]
path = ""
for i, a in enumerate(args):
if a == "--path" and i + 1 < len(args):
path = args[i + 1]
ok = await client.add_torrent(magnet, save_path=path)
print(f"{'✅ 추가 성공' if ok else '❌ 추가 실패'}")
elif args[0] == "delete" and len(args) > 1:
# python tools/qbit_client.py delete <hash> [--files]
hash_ = args[1]
delete_files = "--files" in args
ok = await client.delete_torrent(hash_, delete_files=delete_files)
print(f"{'✅ 삭제 성공' if ok else '❌ 삭제 실패'}")
elif args[0] == "test":
info = await client.test_connection()
print(f"연결: {'' if info['connected'] else ''} {info}")
else:
print("사용법: python tools/qbit_client.py [status|add|delete|test] [옵션]")
asyncio.run(main())