feat(ingest): parse video refs and fetch detail by bvid

This commit is contained in:
kairee committed 2026-11-01 13:46:46 +08:00
1 parent e903c49921
commit d2adb65e08
6 files changed
+410

No files matched your search

+83
View File
@@ -146,6 +146,89 @@ class ViewStat:
)
@dataclass(frozen=True)
class VideoDetail:
"""``x/web-interface/view`` 的完整元数据 + 七项统计。
比 :class:`ViewStat` 多出 UP、时长、分 P 数、封面等字段,供手动入库建库使用。
"""
aid: int
bvid: str | None
title: str
up_mid: int | None
up_name: str | None
pubdate: int
duration: int
pages: int | None
cover: str | None
stat: ViewStat
def metrics(self) -> dict[str, int]:
return self.stat.metrics()
@classmethod
def from_api(cls, item: Mapping[str, Any]) -> "VideoDetail":
stat = ViewStat.from_api(item)
owner = item.get("owner") or {}
if not isinstance(owner, Mapping):
owner = {}
raw_mid = owner.get("mid")
up_mid = (
raw_mid
if isinstance(raw_mid, int) and not isinstance(raw_mid, bool)
else None
)
up_name = owner.get("name")
if not isinstance(up_name, str) or not up_name:
up_name = None
raw_duration = item.get("duration")
duration = (
raw_duration
if isinstance(raw_duration, int)
and not isinstance(raw_duration, bool)
and raw_duration >= 0
else 0
)
pages: int | None = None
raw_pages = item.get("pages")
if isinstance(raw_pages, list) and raw_pages:
pages = len(raw_pages)
else:
raw_videos = item.get("videos")
if (
isinstance(raw_videos, int)
and not isinstance(raw_videos, bool)
and raw_videos > 0
):
pages = raw_videos
raw_pubdate = item.get("pubdate") or item.get("ctime")
pubdate = (
raw_pubdate
if isinstance(raw_pubdate, int) and not isinstance(raw_pubdate, bool)
else 0
)
cover = item.get("pic")
if not isinstance(cover, str) or not cover:
cover = None
return cls(
aid=stat.aid,
bvid=stat.bvid,
title=stat.title,
up_mid=up_mid,
up_name=up_name,
pubdate=pubdate,
duration=duration,
pages=pages,
cover=cover,
stat=stat,
)
@dataclass(frozen=True)
class FanStat:
mid: int