mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-10-31 20:34:48 +08:00
* fix(scraper): return NFO text from built-in providers * test: cover type migration boundaries * fix: silence dynamic import lint diagnostics * test: keep coverage policy stable for nfo repair * fix: preserve merged scraper documentation during conflict repair --------- Co-authored-by: Derrors <derrors@local> Co-authored-by: jxxghp <jxxghp@gmail.com>
141 lines
5.7 KiB
Python
141 lines
5.7 KiB
Python
"""
|
|
依据豆瓣媒体信息生成 NFO XML 和主海报、背景图片地址清单。
|
|
"""
|
|
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
from xml.dom import minidom
|
|
|
|
from app.domain.context import MediaInfo
|
|
from app.foundation.dom import DomUtils
|
|
from app.schemas.types import MediaType
|
|
|
|
|
|
class DoubanScraper:
|
|
"""
|
|
根据豆瓣媒体信息生成 NFO 与图片清单。
|
|
"""
|
|
|
|
_force_nfo = False
|
|
_force_img = False
|
|
|
|
def get_metadata_nfo(self, mediainfo: MediaInfo, season: Optional[int] = None) -> Optional[str]:
|
|
"""
|
|
生成电影、整剧或季级别的 NFO XML。
|
|
|
|
:param mediainfo: 包含豆瓣简介、演职员和评分的媒体对象
|
|
:param season: 季号;非电影且提供季号时生成季文档
|
|
:return: 包含 UTF-8 编码声明的 XML 文本;无法生成时返回 None
|
|
"""
|
|
if mediainfo.type == MediaType.MOVIE:
|
|
doc = self.__gen_movie_nfo_file(mediainfo=mediainfo)
|
|
else:
|
|
if season is not None:
|
|
doc = self.__gen_tv_season_nfo_file(mediainfo=mediainfo, season=season)
|
|
else:
|
|
doc = self.__gen_tv_nfo_file(mediainfo=mediainfo)
|
|
if doc:
|
|
return doc.toprettyxml(indent=" ", encoding="utf-8").decode("utf-8")
|
|
|
|
return None
|
|
|
|
@staticmethod
|
|
def get_metadata_img(mediainfo: MediaInfo, season: Optional[int] = None, episode: Optional[int] = None) -> dict[str, str]:
|
|
"""
|
|
生成主媒体图片文件名到原始地址的映射。
|
|
|
|
:param mediainfo: 提供海报与背景图片路径的媒体对象
|
|
:param season: 豆瓣不提供季图片;非 None 时返回空字典
|
|
:param episode: 豆瓣不提供单集图片;非零时返回空字典
|
|
:return: 已有主海报及背景图的文件名与地址;没有图片时为空字典
|
|
"""
|
|
ret_dict = {}
|
|
if season is not None:
|
|
return {}
|
|
if episode:
|
|
return {}
|
|
if mediainfo.poster_path:
|
|
ret_dict[f"poster{Path(mediainfo.poster_path).suffix}"] = mediainfo.poster_path
|
|
if mediainfo.backdrop_path:
|
|
ret_dict[f"backdrop{Path(mediainfo.backdrop_path).suffix}"] = mediainfo.backdrop_path
|
|
return ret_dict
|
|
|
|
@staticmethod
|
|
def __gen_common_nfo(mediainfo: MediaInfo, doc: minidom.Document, root: minidom.Element) -> minidom.Document:
|
|
"""
|
|
向已有文档追加豆瓣简介、演职员和评分信息。
|
|
"""
|
|
xplot = DomUtils.add_node(doc, root, "plot")
|
|
xplot.appendChild(doc.createCDATASection(mediainfo.overview or ""))
|
|
xoutline = DomUtils.add_node(doc, root, "outline")
|
|
xoutline.appendChild(doc.createCDATASection(mediainfo.overview or ""))
|
|
for director in mediainfo.directors:
|
|
DomUtils.add_node(doc, root, "director", director.get("name") or "")
|
|
for actor in mediainfo.actors:
|
|
xactor = DomUtils.add_node(doc, root, "actor")
|
|
DomUtils.add_node(doc, xactor, "name", actor.get("name") or "")
|
|
DomUtils.add_node(doc, xactor, "type", "Actor")
|
|
DomUtils.add_node(doc, xactor, "role", actor.get("character") or actor.get("role") or "")
|
|
DomUtils.add_node(doc, xactor, "thumb", actor.get('avatar', {}).get('normal'))
|
|
DomUtils.add_node(doc, xactor, "profile", actor.get('url'))
|
|
DomUtils.add_node(doc, root, "rating", mediainfo.vote_average or "0")
|
|
|
|
return doc
|
|
|
|
def __gen_movie_nfo_file(self, mediainfo: MediaInfo) -> minidom.Document:
|
|
"""
|
|
生成电影的NFO描述文件。
|
|
|
|
:param mediainfo: 豆瓣信息
|
|
"""
|
|
doc = minidom.Document()
|
|
root = DomUtils.add_node(doc, doc, "movie")
|
|
doc = self.__gen_common_nfo(mediainfo=mediainfo,
|
|
doc=doc,
|
|
root=root)
|
|
DomUtils.add_node(doc, root, "title", mediainfo.title or "")
|
|
DomUtils.add_node(doc, root, "year", mediainfo.year or "")
|
|
|
|
return doc
|
|
|
|
def __gen_tv_nfo_file(self, mediainfo: MediaInfo) -> minidom.Document:
|
|
"""
|
|
生成电视剧的NFO描述文件。
|
|
|
|
:param mediainfo: 媒体信息
|
|
"""
|
|
doc = minidom.Document()
|
|
root = DomUtils.add_node(doc, doc, "tvshow")
|
|
doc = self.__gen_common_nfo(mediainfo=mediainfo,
|
|
doc=doc,
|
|
root=root)
|
|
DomUtils.add_node(doc, root, "title", mediainfo.title or "")
|
|
DomUtils.add_node(doc, root, "year", mediainfo.year or "")
|
|
DomUtils.add_node(doc, root, "season", "-1")
|
|
DomUtils.add_node(doc, root, "episode", "-1")
|
|
|
|
return doc
|
|
|
|
@staticmethod
|
|
def __gen_tv_season_nfo_file(mediainfo: MediaInfo,
|
|
season: int) -> minidom.Document:
|
|
"""
|
|
生成电视剧季的NFO描述文件。
|
|
|
|
:param mediainfo: 媒体信息
|
|
:param season: 季号
|
|
"""
|
|
doc = minidom.Document()
|
|
root = DomUtils.add_node(doc, doc, "season")
|
|
xplot = DomUtils.add_node(doc, root, "plot")
|
|
xplot.appendChild(doc.createCDATASection(mediainfo.overview or ""))
|
|
xoutline = DomUtils.add_node(doc, root, "outline")
|
|
xoutline.appendChild(doc.createCDATASection(mediainfo.overview or ""))
|
|
DomUtils.add_node(doc, root, "title", "季 %s" % season)
|
|
DomUtils.add_node(doc, root, "premiered", mediainfo.release_date or "")
|
|
DomUtils.add_node(doc, root, "releasedate", mediainfo.release_date or "")
|
|
DomUtils.add_node(doc, root, "year", mediainfo.release_date[:4] if mediainfo.release_date else "")
|
|
DomUtils.add_node(doc, root, "seasonnumber", str(season))
|
|
|
|
return doc
|