import datetime from abc import abstractmethod from dataclasses import dataclass from pathlib import Path from models import FavoriteItem, FavoriteItemPage, Upper from utils import aopen @dataclass class Base: """基类,有个工具方法""" @abstractmethod def to_xml(self) -> str: ... @staticmethod def escape(s: str) -> str: """转义 xml 特殊字符""" return s.translate(str.maketrans({"<": "<", ">": ">", "&": "&", "'": "'", '"': """})) async def to_file(self, path: Path) -> None: """把 xml 写入文件""" async with aopen(path, "w", encoding="utf-8") as f: await f.write(self.to_xml()) @dataclass class EpisodeInfo(Base): """分p的单集信息""" title: str season: int episode: int @staticmethod def from_favorite_item_page(page: FavoriteItemPage) -> "EpisodeInfo": return EpisodeInfo(title=page.name, season=1, episode=page.page) def to_xml(self) -> str: return f""" {self.escape(self.title)} {self.season} {self.episode} """.strip() @dataclass class Actor(Base): name: str role: str @staticmethod def from_upper(upper: Upper) -> "Actor": return Actor(name=upper.mid, role=upper.name) def to_xml(self) -> str: return f""" {self.name} {self.escape(self.role)} """.strip() @dataclass class MovieInfo(Base): """单p的视频信息""" title: str plot: str tags: list[str] actor: list[Actor] bvid: str aired: datetime.datetime @staticmethod def from_favorite_item(fav_item: FavoriteItem) -> "MovieInfo": return MovieInfo( title=fav_item.name, plot=fav_item.desc, actor=[Actor.from_upper(fav_item.upper)], tags=fav_item.tags, bvid=fav_item.bvid, aired=fav_item.ctime, ) def to_xml(self) -> str: actor = "\n".join(_.to_xml() for _ in self.actor) tags = ( "\n".join(f" {self.escape(_)}" for _ in self.tags) if isinstance(self.tags, list) else "" ) return f""" {self.escape(self.title)} {actor} {self.aired.year} {tags} {self.bvid} {self.aired.strftime("%Y-%m-%d")} """.strip() @dataclass class TVShowInfo(Base): title: str plot: str tags: list[str] actor: list[Actor] bvid: str aired: datetime.datetime @staticmethod def from_favorite_item(fav_item: FavoriteItem) -> "TVShowInfo": return TVShowInfo( title=fav_item.name, plot=fav_item.desc, actor=[Actor.from_upper(fav_item.upper)], tags=fav_item.tags, bvid=fav_item.bvid, aired=fav_item.ctime, ) def to_xml(self) -> str: actor = "\n".join(_.to_xml() for _ in self.actor) tags = ( "\n".join(f" {self.escape(_)}" for _ in self.tags) if isinstance(self.tags, list) else "" ) return f""" {self.escape(self.title)} {actor} {self.aired.year} {tags} {self.bvid} {self.aired.strftime("%Y-%m-%d")} """.strip() @dataclass class UpperInfo(Base): mid: int created_at: datetime.datetime def from_upper(upper: Upper) -> "UpperInfo": return UpperInfo(mid=upper.mid, created_at=upper.created_at) def to_xml(self) -> str: return f""" false {self.created_at.strftime("%Y-%m-%d %H:%M:%S")} {self.mid} {self.mid} """.strip()