mirror of
https://github.com/EstrellaXD/Auto_Bangumi.git
synced 2026-07-26 16:41:51 +08:00
fix: improve rename reliability and add torrent tagging API
- Fix qBittorrent rename verification (verify file actually renamed) - Add pending rename cooldown to prevent spam when rename delayed - Add torrent tagging API for accurate offset lookup - Add auto calendar refresh every 24 hours - Fix frontend error handling (don't logout on server errors) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from pydantic import BaseModel
|
||||
|
||||
from module.database import Database
|
||||
from module.downloader import DownloadClient
|
||||
from module.security.api import get_current_user
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/downloader", tags=["downloader"])
|
||||
|
||||
|
||||
@@ -16,6 +21,12 @@ class TorrentDeleteRequest(BaseModel):
|
||||
delete_files: bool = False
|
||||
|
||||
|
||||
class TorrentTagRequest(BaseModel):
|
||||
"""Request to tag a torrent with a bangumi ID."""
|
||||
hash: str
|
||||
bangumi_id: int
|
||||
|
||||
|
||||
@router.get("/torrents", dependencies=[Depends(get_current_user)])
|
||||
async def get_torrents():
|
||||
async with DownloadClient() as client:
|
||||
@@ -44,3 +55,91 @@ async def delete_torrents(req: TorrentDeleteRequest):
|
||||
async with DownloadClient() as client:
|
||||
await client.delete_torrent(hashes, delete_files=req.delete_files)
|
||||
return {"msg_en": "Torrents deleted", "msg_zh": "种子已删除"}
|
||||
|
||||
|
||||
@router.post("/torrents/tag", dependencies=[Depends(get_current_user)])
|
||||
async def tag_torrent(req: TorrentTagRequest):
|
||||
"""Tag a torrent with a bangumi ID for accurate offset lookup.
|
||||
|
||||
This adds the 'ab:ID' tag to the torrent in qBittorrent, which allows
|
||||
the renamer to look up the correct episode/season offset.
|
||||
"""
|
||||
# Verify bangumi exists
|
||||
with Database() as db:
|
||||
bangumi = db.bangumi.search_id(req.bangumi_id)
|
||||
if not bangumi:
|
||||
return {
|
||||
"status": False,
|
||||
"msg_en": f"Bangumi {req.bangumi_id} not found",
|
||||
"msg_zh": f"未找到番剧 {req.bangumi_id}",
|
||||
}
|
||||
|
||||
tag = f"ab:{req.bangumi_id}"
|
||||
async with DownloadClient() as client:
|
||||
await client.add_tag(req.hash, tag)
|
||||
|
||||
return {
|
||||
"status": True,
|
||||
"msg_en": f"Tagged torrent with {tag}",
|
||||
"msg_zh": f"已为种子添加标签 {tag}",
|
||||
}
|
||||
|
||||
|
||||
@router.post("/torrents/tag/auto", dependencies=[Depends(get_current_user)])
|
||||
async def auto_tag_torrents():
|
||||
"""Auto-tag all untagged Bangumi torrents based on name/path matching.
|
||||
|
||||
This helps fix torrents that were added before tagging was implemented.
|
||||
Returns the number of torrents tagged and any that couldn't be matched.
|
||||
"""
|
||||
tagged_count = 0
|
||||
unmatched = []
|
||||
|
||||
async with DownloadClient() as client:
|
||||
# Get all Bangumi torrents
|
||||
torrents = await client.get_torrent_info(category="Bangumi", status_filter=None)
|
||||
|
||||
with Database() as db:
|
||||
for torrent in torrents:
|
||||
torrent_hash = torrent["hash"]
|
||||
torrent_name = torrent["name"]
|
||||
save_path = torrent["save_path"]
|
||||
tags = torrent.get("tags", "")
|
||||
|
||||
# Skip if already has ab: tag
|
||||
if "ab:" in tags:
|
||||
continue
|
||||
|
||||
# Try to match bangumi
|
||||
bangumi = None
|
||||
|
||||
# First try by torrent name
|
||||
bangumi = db.bangumi.match_torrent(torrent_name)
|
||||
|
||||
# Then try by save_path
|
||||
if not bangumi:
|
||||
bangumi = db.bangumi.match_by_save_path(save_path)
|
||||
|
||||
if bangumi and not bangumi.deleted:
|
||||
tag = f"ab:{bangumi.id}"
|
||||
await client.add_tag(torrent_hash, tag)
|
||||
tagged_count += 1
|
||||
logger.info(
|
||||
f"[AutoTag] Tagged '{torrent_name[:50]}...' with {tag} "
|
||||
f"(matched: {bangumi.official_title})"
|
||||
)
|
||||
else:
|
||||
unmatched.append({
|
||||
"hash": torrent_hash,
|
||||
"name": torrent_name,
|
||||
"save_path": save_path,
|
||||
})
|
||||
|
||||
return {
|
||||
"status": True,
|
||||
"tagged_count": tagged_count,
|
||||
"unmatched_count": len(unmatched),
|
||||
"unmatched": unmatched[:10], # Return first 10 unmatched for debugging
|
||||
"msg_en": f"Tagged {tagged_count} torrents, {len(unmatched)} could not be matched",
|
||||
"msg_zh": f"已标记 {tagged_count} 个种子,{len(unmatched)} 个无法匹配",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user