返回 douyin-downloader
video_downloader.py
根目录 / core / video_downloader.py
1 from typing import Any, Dict
2
3 from core.downloader_base import BaseDownloader, DownloadResult
4 from utils.logger import setup_logger
5
6 logger = setup_logger("VideoDownloader")
7
8
9 class VideoDownloader(BaseDownloader):
10 async def download(self, parsed_url: Dict[str, Any]) -> DownloadResult:
11 result = DownloadResult()
12
13 aweme_id = parsed_url.get("aweme_id")
14 if not aweme_id:
15 logger.error("No aweme_id found in parsed URL")
16 return result
17
18 result.total = 1
19 self._progress_set_item_total(1, "单作品下载")
20 self._progress_update_step("下载作品", "单作品资源下载中")
21
22 if not await self._should_download(aweme_id):
23 logger.info("Video %s already downloaded, skipping", aweme_id)
24 result.skipped += 1
25 self._progress_advance_item("skipped", str(aweme_id))
26 return result
27
28 await self.rate_limiter.acquire()
29
30 aweme_data = await self.api_client.get_video_detail(aweme_id)
31 if not aweme_data:
32 logger.error("Failed to get video detail: %s", aweme_id)
33 result.failed += 1
34 self._progress_advance_item("failed", str(aweme_id))
35 return result
36
37 success = await self._download_aweme(aweme_data)
38 if success:
39 result.success += 1
40 self._progress_advance_item("success", str(aweme_id))
41 else:
42 result.failed += 1
43 self._progress_advance_item("failed", str(aweme_id))
44
45 return result
46
47 async def _download_aweme(self, aweme_data: Dict[str, Any]) -> bool:
48 author = aweme_data.get("author", {}) or {}
49 author_name = author.get("nickname", "unknown")
50 # Cache author on the hosting job so JobRow can display the nickname
51 # and `retry_failed_awemes` doesn't need to re-fetch user info.
52 self._progress_report_author(
53 nickname=author_name if author_name != "unknown" else None,
54 sec_uid=author.get("sec_uid"),
55 )
56 return await self._download_aweme_assets(aweme_data, author_name)
57
57 lines PYTHON