fix personmeta

This commit is contained in:
jxxghp
2023-10-01 11:52:25 +08:00
parent 2f069afc77
commit fcbfb63645
7 changed files with 251 additions and 69 deletions

View File

@ -1,5 +1,5 @@
from pathlib import Path
from typing import Optional, Tuple, Union, Any, List
from typing import Optional, Tuple, Union, Any, List, Generator
from app import schemas
from app.core.context import MediaInfo
@ -122,7 +122,7 @@ class EmbyModule(_ModuleBase):
media_statistic.user_count = self.emby.get_user_count()
return [media_statistic]
def mediaserver_librarys(self, server: str) -> List[schemas.MediaServerLibrary]:
def mediaserver_librarys(self, server: str) -> Optional[List[schemas.MediaServerLibrary]]:
"""
媒体库列表
"""
@ -130,7 +130,7 @@ class EmbyModule(_ModuleBase):
return None
return self.emby.get_librarys()
def mediaserver_items(self, server: str, library_id: str) -> Optional[List[schemas.MediaServerItem]]:
def mediaserver_items(self, server: str, library_id: str) -> Optional[Generator]:
"""
媒体库项目列表
"""

View File

@ -880,7 +880,7 @@ class Emby(metaclass=Singleton):
logger.error(f"连接Emby出错" + str(e))
return None
def post_data(self, url: str, data: str = None):
def post_data(self, url: str, data: str = None) -> Optional[Response]:
"""
自定义URL从媒体服务器获取数据其中[HOST]、[APIKEY]、[USER]会被替换成实际的值
:param url: 请求地址
@ -892,7 +892,11 @@ class Emby(metaclass=Singleton):
.replace("[APIKEY]", self._apikey) \
.replace("[USER]", self.user)
try:
return RequestUtils(content_type="application/json").post_res(url=url, data=data)
return RequestUtils(
headers={
"Content-Type": "application/json"
}
).post_res(url=url, data=data)
except Exception as e:
logger.error(f"连接Emby出错" + str(e))
return None

View File

@ -1,5 +1,5 @@
from pathlib import Path
from typing import Optional, Tuple, Union, Any, List
from typing import Optional, Tuple, Union, Any, List, Generator
from app import schemas
from app.core.context import MediaInfo
@ -109,7 +109,7 @@ class JellyfinModule(_ModuleBase):
"""
media_statistic = self.jellyfin.get_medias_count()
media_statistic.user_count = self.jellyfin.get_user_count()
return media_statistic
return [media_statistic]
def mediaserver_librarys(self, server: str) -> Optional[List[schemas.MediaServerLibrary]]:
"""
@ -128,7 +128,7 @@ class JellyfinModule(_ModuleBase):
path=library.get("path")
) for library in librarys]
def mediaserver_items(self, server: str, library_id: str) -> Optional[List[schemas.MediaServerItem]]:
def mediaserver_items(self, server: str, library_id: str) -> Optional[Generator]:
"""
媒体库项目列表
"""

View File

@ -561,7 +561,7 @@ class Jellyfin(metaclass=Singleton):
.replace("[APIKEY]", self._apikey) \
.replace("[USER]", self.user)
try:
return RequestUtils().get_res(url=url)
return RequestUtils(accept_type="application/json").get_res(url=url)
except Exception as e:
logger.error(f"连接Jellyfin出错" + str(e))
return None
@ -578,7 +578,11 @@ class Jellyfin(metaclass=Singleton):
.replace("[APIKEY]", self._apikey) \
.replace("[USER]", self.user)
try:
return RequestUtils().post_res(url=url, data=data)
return RequestUtils(
headers={
"Content-Type": "application/json"
}
).post_res(url=url, data=data)
except Exception as e:
logger.error(f"连接Jellyfin出错" + str(e))
return None

View File

@ -1,5 +1,5 @@
from pathlib import Path
from typing import Optional, Tuple, Union, Any, List
from typing import Optional, Tuple, Union, Any, List, Generator
from app import schemas
from app.core.context import MediaInfo
@ -122,7 +122,7 @@ class PlexModule(_ModuleBase):
return None
return self.plex.get_librarys()
def mediaserver_items(self, server: str, library_id: str) -> Optional[List[schemas.MediaServerItem]]:
def mediaserver_items(self, server: str, library_id: str) -> Optional[Generator]:
"""
媒体库项目列表
"""

View File

@ -4,6 +4,7 @@ import xml.dom.minidom
from threading import Event
from typing import Tuple, List, Dict, Any, Optional
import pytz
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
@ -100,11 +101,19 @@ class DoubanRank(_PluginBase):
logger.error(f"豆瓣榜单订阅服务启动失败,错误信息:{str(e)}")
self.systemmessage.put(f"豆瓣榜单订阅服务启动失败,错误信息:{str(e)}")
else:
self._scheduler.add_job(func=self.__refresh_rss,
trigger=CronTrigger.from_crontab("0 8 * * *"),
name="豆瓣榜单订阅")
self._scheduler.add_job(func=self.__refresh_rss, trigger='date',
run_date=datetime.datetime.now(
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3)
)
logger.info("豆瓣榜单订阅服务启动,周期:每天 08:00")
if self._onlyonce:
logger.info("豆瓣榜单订阅服务启动,立即运行一次")
self._scheduler.add_job(func=self.__refresh_rss, trigger='date',
run_date=datetime.datetime.now(
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3)
)
if self._onlyonce or self._clear:
# 关闭一次性开关
self._onlyonce = False

View File

@ -1,9 +1,12 @@
import copy
import datetime
import json
import threading
import time
from pathlib import Path
from typing import Any, List, Dict, Tuple
from typing import Any, List, Dict, Tuple, Optional
import pytz
import zhconv
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
@ -71,17 +74,22 @@ class PersonMeta(_PluginBase):
# 启动服务
if self._enabled or self._onlyonce:
self._scheduler = BackgroundScheduler(timezone=settings.TZ)
if self._cron or self._onlyonce:
if self._cron:
logger.info(f"演职人员刮削服务启动,周期:{self._cron}")
try:
self._scheduler.add_job(func=self.scrap_library,
trigger=CronTrigger.from_crontab(self._cron),
name="演职人员刮削")
logger.info(f"演职人员刮削服务启动,周期:{self._cron}")
except Exception as e:
logger.error(f"演职人员刮削服务启动失败,错误信息:{str(e)}")
self.systemmessage.put(f"演职人员刮削服务启动失败,错误信息:{str(e)}")
if self._onlyonce:
self._scheduler.add_job(func=self.scrap_library, trigger='date',
run_date=datetime.datetime.now(
tz=pytz.timezone(settings.TZ)) + datetime.timedelta(seconds=3)
)
logger.info(f"演职人员刮削服务启动,立即运行一次")
# 关闭一次性开关
self._onlyonce = False
# 保存配置
@ -253,6 +261,9 @@ class PersonMeta(_PluginBase):
continue
if not item.item_id:
continue
if "Series" not in item.item_type \
and "Movie" not in item.item_type:
continue
if self._event.is_set():
logger.info(f"演职人员刮削服务停止")
return
@ -284,25 +295,166 @@ class PersonMeta(_PluginBase):
logger.warn(f"{item.title} 未找到媒体项")
return
# 处理媒体项中的人物信息
if not iteminfo.get("People"):
logger.warn(f"{item.title} 未找到人物信息")
return
if iteminfo.get("People"):
"""
"People": [
{
"Name": "丹尼尔·克雷格",
"Id": "33625",
"Role": "James Bond",
"Type": "Actor",
"PrimaryImageTag": "bef4f764540f10577f804201d8d27918"
}
]
"""
peoples = []
# 更新当前媒体项人物
for people in iteminfo["People"]:
if not people.get("Name"):
continue
if StringUtils.is_chinese(people.get("Name")):
continue
info = self.__update_people(server=server, people=people)
if info:
peoples.append(info)
else:
peoples.append(people)
# 保存媒体项信息
if peoples:
iteminfo["People"] = peoples
self.set_iteminfo(server=server, itemid=item.item_id, iteminfo=iteminfo)
# 处理季和集人物
if iteminfo.get("Type") and "Series" in iteminfo["Type"]:
# 获取季媒体项
seasons = self.get_items(server=server, parentid=item.item_id, mtype="Season")
if not seasons:
logger.warn(f"{item.title} 未找到季媒体项")
return
for season in seasons["Items"]:
# 如果是Jellyfin更新季的人物Emby/Plex季没有人物
if server == "jellyfin":
seasoninfo = self.get_iteminfo(server=server, itemid=season.get("Id"))
if not seasoninfo:
logger.warn(f"{item.title} 未找到季媒体项:{season.get('Id')}")
continue
# 更新季媒体项人物
peoples = []
if seasoninfo.get("People"):
for people in seasoninfo["People"]:
if not people.get("Name"):
continue
if StringUtils.is_chinese(people.get("Name")):
continue
# 更新人物信息
info = self.__update_people(server=server, people=people)
if info:
peoples.append(info)
else:
peoples.append(people)
# 保存季媒体项信息
if peoples:
seasoninfo["People"] = peoples
self.set_iteminfo(server=server, itemid=season.get("Id"), iteminfo=seasoninfo)
# 获取集媒体项
episodes = self.get_items(server=server, parentid=season.get("Id"), mtype="Episode")
if not episodes:
logger.warn(f"{item.title} 未找到集媒体项")
continue
# 更新集媒体项人物
for episode in episodes["Items"]:
# 获取集媒体项详情
episodeinfo = self.get_iteminfo(server=server, itemid=episode.get("Id"))
if not episodeinfo:
logger.warn(f"{item.title} 未找到集媒体项:{episode.get('Id')}")
continue
# 更新集媒体项人物
if episodeinfo.get("People"):
peoples = []
for people in episodeinfo["People"]:
if not people.get("Name"):
continue
if StringUtils.is_chinese(people.get("Name")):
continue
# 更新人物信息
info = self.__update_people(server=server, people=people)
if info:
peoples.append(info)
else:
peoples.append(people)
# 保存集媒体项信息
if peoples:
episodeinfo["People"] = peoples
self.set_iteminfo(server=server, itemid=episode.get("Id"), iteminfo=episodeinfo)
def __update_people(self, server: str, people: dict) -> Optional[dict]:
"""
更新人物信息,返回替换后的人物信息
"""
def __get_peopleid(p: dict) -> Tuple[Optional[str], Optional[str]]:
"""
获取人物的TMDBID、IMDBID
"""
if not p.get("ProviderIds"):
return None, None
peopletmdbid, peopleimdbid = None, None
if "Tmdb" in p["ProviderIds"]:
peopletmdbid = p["ProviderIds"]["Tmdb"]
if "tmdb" in p["ProviderIds"]:
peopletmdbid = p["ProviderIds"]["tmdb"]
if "Imdb" in p["ProviderIds"]:
peopleimdbid = p["ProviderIds"]["Imdb"]
if "imdb" in p["ProviderIds"]:
peopleimdbid = p["ProviderIds"]["imdb"]
return peopletmdbid, peopleimdbid
# 返回的人物信息
ret_people = copy.deepcopy(people)
try:
# 查询人物详情
# 查询媒体库人物详情
personinfo = self.get_iteminfo(server=server, itemid=people.get("Id"))
if not personinfo:
logger.debug(f"{item.title} 未找到人物 {people.get('Id')} 的信息")
continue
# TODO 使用TMDB中的信息转换中文名称和描述
# TODO 检查豆瓣影片信息并匹配转换人物中文名称和描述
# TODO 更新人物图片
# TODO 刷新一次人物信息
logger.debug(f"未找到人物 {people.get('Id')} 的信息")
return None
# 获取人物的TMDBID
person_tmdbid, person_imdbid = __get_peopleid(personinfo)
if not person_tmdbid:
logger.warn(f"未找到人物 {people.get('Id')} 的tmdbid")
return None
# 是否更新标志
updated = False
# 查询人物TMDB详情
person_tmdbinfo = self.tmdbchain.person_detail(int(person_tmdbid))
if person_tmdbinfo:
cn_name = self.__get_chinese_name(person_tmdbinfo)
if cn_name:
updated = True
# 更新中文名
personinfo["Name"] = cn_name
ret_people["Name"] = cn_name
if "Name" not in personinfo["LockedFields"]:
personinfo["LockedFields"].append("Name")
# 更新中文描述
biography = person_tmdbinfo.get("biography")
if StringUtils.is_chinese(biography):
personinfo["Overview"] = biography
if "Overview" not in personinfo["LockedFields"]:
personinfo["LockedFields"].append("Overview")
# 更新人物图片
profile_path = f"https://image.tmdb.org/t/p/original{person_tmdbinfo.get('profile_path')}"
if profile_path:
logger.info(f"更新人物 {people.get('Id')} 的图片:{profile_path}")
self.set_item_image(server=server, itemid=people.get("Id"), imageurl=profile_path)
# 更新人物信息
if updated:
logger.info(f"更新人物 {people.get('Id')} 的信息:{personinfo}")
ret = self.set_iteminfo(server=server, itemid=people.get("Id"), iteminfo=personinfo)
if ret:
return ret_people
except Exception as err:
logger.error(f"更新人物信息失败:{err}")
return None
@staticmethod
def get_iteminfo(server: str, itemid: str) -> dict:
@ -382,7 +534,7 @@ class PersonMeta(_PluginBase):
return __get_plex_iteminfo()
@staticmethod
def get_items(server: str, parentid: str) -> dict:
def get_items(server: str, parentid: str, mtype: str = None) -> dict:
"""
获得媒体的所有子媒体项
"""
@ -420,7 +572,7 @@ class PersonMeta(_PluginBase):
logger.error(f"获取Jellyfin媒体的所有子媒体项失败{err}")
return {}
def __get_plex_items() -> dict:
def __get_plex_items(t: str) -> dict:
"""
获得Plex媒体的所有子媒体项
"""
@ -429,7 +581,7 @@ class PersonMeta(_PluginBase):
plex = Plex().get_plex()
items['Items'] = []
if parentid:
if type and 'Season' in type:
if mtype and 'Season' in t:
plexitem = plex.library.fetchItem(ekey=parentid)
items['Items'] = []
for season in plexitem.seasons():
@ -440,7 +592,7 @@ class PersonMeta(_PluginBase):
'Overview': season.summary
}
items['Items'].append(item)
elif type and 'Episode' in type:
elif mtype and 'Episode' in t:
plexitem = plex.library.fetchItem(ekey=parentid)
items['Items'] = []
for episode in plexitem.episodes():
@ -491,7 +643,7 @@ class PersonMeta(_PluginBase):
elif server == "jellyfin":
return __get_jellyfin_items()
else:
return __get_plex_items()
return __get_plex_items(mtype)
@staticmethod
def set_iteminfo(server: str, itemid: str, iteminfo: dict):
@ -505,10 +657,14 @@ class PersonMeta(_PluginBase):
"""
try:
res = Emby().post_data(
url=f'[HOST]emby/Items/{itemid}?api_key=[APIKEY]',
url=f'[HOST]emby/Items/{itemid}?api_key=[APIKEY]&reqformat=json',
data=json.dumps(iteminfo)
)
return True if res else False
if res and res.status_code in [200, 204]:
return True
else:
logger.error(f"更新Emby媒体项详情失败错误码{res.status_code}")
return False
except Exception as err:
logger.error(f"更新Emby媒体项详情失败{err}")
return False
@ -522,7 +678,11 @@ class PersonMeta(_PluginBase):
url=f'[HOST]Items/{itemid}?api_key=[APIKEY]',
data=json.dumps(iteminfo)
)
return True if res else False
if res and res.status_code in [200, 204]:
return True
else:
logger.error(f"更新Jellyfin媒体项详情失败错误码{res.status_code}")
return False
except Exception as err:
logger.error(f"更新Jellyfin媒体项详情失败{err}")
return False
@ -553,7 +713,7 @@ class PersonMeta(_PluginBase):
return __set_plex_iteminfo()
@staticmethod
def __set_item_image(server: str, itemid: str, imageurl: str):
def set_item_image(server: str, itemid: str, imageurl: str):
"""
更新媒体项图片
"""
@ -566,7 +726,11 @@ class PersonMeta(_PluginBase):
url = f'[HOST]emby/Items/{itemid}/Images/Primary/0/Url?api_key=[APIKEY]'
data = json.dumps({'Url': imageurl})
res = Emby().post_data(url=url, data=data)
return True if res else False
if res and res.status_code in [200, 204]:
return True
else:
logger.error(f"更新Emby媒体项图片失败错误码{res.status_code}")
return False
except Exception as result:
logger.error(f"更新Emby媒体项图片失败{result}")
return False
@ -579,7 +743,11 @@ class PersonMeta(_PluginBase):
url = f'[HOST]Items/{itemid}/RemoteImages/Download?' \
f'Type=Primary&ImageUrl={imageurl}&ProviderName=TheMovieDb&api_key=[APIKEY]'
res = Jellyfin().post_data(url=url)
return True if res else None
if res and res.status_code in [200, 204]:
return True
else:
logger.error(f"更新Jellyfin媒体项图片失败错误码{res.status_code}")
return False
except Exception as err:
logger.error(f"更新Jellyfin媒体项图片失败{err}")
return False
@ -603,15 +771,12 @@ class PersonMeta(_PluginBase):
else:
return __set_plex_item_image()
def __get_chinese_name(self, person: dict) -> str:
@staticmethod
def __get_chinese_name(personinfo: dict) -> str:
"""
获取TMDB别名中的中文名
"""
if not person.get("id"):
return ""
try:
personinfo = self.tmdbchain.person_detail(person.get("id"))
if personinfo:
also_known_as = personinfo.get("also_known_as") or []
if also_known_as:
for name in also_known_as:
@ -620,7 +785,7 @@ class PersonMeta(_PluginBase):
return zhconv.convert(name, "zh-hans")
except Exception as err:
logger.error(f"获取人物中文名失败:{err}")
return person.get("name") or ""
return ""
def stop_service(self):
"""