feat 支持多媒体服务器同时使用

This commit is contained in:
jxxghp
2023-09-23 09:20:51 +08:00
parent 78dab04c96
commit fd9eef2089
12 changed files with 159 additions and 96 deletions

View File

@ -1,4 +1,3 @@
import json
from pathlib import Path
from typing import Optional, Tuple, Union, Any, List, Generator
@ -41,7 +40,7 @@ class EmbyModule(_ModuleBase):
# Emby认证
return self.emby.authenticate(name, password)
def webhook_parser(self, body: Any, form: Any, args: Any) -> WebhookEventInfo:
def webhook_parser(self, body: Any, form: Any, args: Any) -> Optional[WebhookEventInfo]:
"""
解析Webhook报文体
:param body: 请求体
@ -49,11 +48,7 @@ class EmbyModule(_ModuleBase):
:param args: 请求参数
:return: 字典解析为消息时需要包含title、text、image
"""
if form and form.get("data"):
result = form.get("data")
else:
result = json.dumps(dict(args))
return self.emby.get_webhook_message(result)
return self.emby.get_webhook_message(form, args)
def media_exists(self, mediainfo: MediaInfo, itemid: str = None) -> Optional[ExistMediaInfo]:
"""
@ -87,7 +82,7 @@ class EmbyModule(_ModuleBase):
logger.info(f"{mediainfo.title_year} 媒体库中已存在:{tvs}")
return ExistMediaInfo(type=MediaType.TV, seasons=tvs)
def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: Path) -> Optional[bool]:
def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: Path) -> None:
"""
刷新媒体库
:param mediainfo: 识别的媒体信息
@ -103,25 +98,27 @@ class EmbyModule(_ModuleBase):
target_path=file_path
)
]
return self.emby.refresh_library_by_items(items)
self.emby.refresh_library_by_items(items)
def media_statistic(self) -> schemas.Statistic:
def media_statistic(self) -> List[schemas.Statistic]:
"""
媒体数量统计
"""
media_statistic = self.emby.get_medias_count()
user_count = self.emby.get_user_count()
return schemas.Statistic(
return [schemas.Statistic(
movie_count=media_statistic.get("MovieCount") or 0,
tv_count=media_statistic.get("SeriesCount") or 0,
episode_count=media_statistic.get("EpisodeCount") or 0,
user_count=user_count or 0
)
)]
def mediaserver_librarys(self) -> List[schemas.MediaServerLibrary]:
def mediaserver_librarys(self, server: str) -> Optional[List[schemas.MediaServerLibrary]]:
"""
媒体库列表
"""
if server != "emby":
return None
librarys = self.emby.get_librarys()
if not librarys:
return []
@ -133,10 +130,12 @@ class EmbyModule(_ModuleBase):
path=library.get("path")
) for library in librarys]
def mediaserver_items(self, library_id: str) -> Generator:
def mediaserver_items(self, server: str, library_id: str) -> Optional[Generator]:
"""
媒体库项目列表
"""
if server != "emby":
return None
items = self.emby.get_items(library_id)
for item in items:
yield schemas.MediaServerItem(
@ -153,10 +152,13 @@ class EmbyModule(_ModuleBase):
path=item.get("path"),
)
def mediaserver_tv_episodes(self, item_id: Union[str, int]) -> List[schemas.MediaServerSeasonInfo]:
def mediaserver_tv_episodes(self, server: str,
item_id: Union[str, int]) -> Optional[List[schemas.MediaServerSeasonInfo]]:
"""
获取剧集信息
"""
if server != "emby":
return None
seasoninfo = self.emby.get_tv_episodes(item_id=item_id)
if not seasoninfo:
return []

View File

@ -545,7 +545,7 @@ class Emby(metaclass=Singleton):
logger.error(f"连接Users/Items出错" + str(e))
yield {}
def get_webhook_message(self, message_str: str) -> WebhookEventInfo:
def get_webhook_message(self, form: any, args: dict) -> Optional[WebhookEventInfo]:
"""
解析Emby Webhook报文
电影:
@ -783,9 +783,22 @@ class Emby(metaclass=Singleton):
}
}
"""
message = json.loads(message_str)
if not form and not args:
return None
try:
if form and form.get("data"):
result = form.get("data")
else:
result = json.dumps(dict(args))
message = json.loads(result)
except Exception as e:
logger.debug(f"解析emby webhook报文出错" + str(e))
return None
eventType = message.get('Event')
if not eventType:
return None
logger.info(f"接收到emby webhook{message}")
eventItem = WebhookEventInfo(event=message.get('Event', ''), channel="emby")
eventItem = WebhookEventInfo(event=eventType, channel="emby")
if message.get('Item'):
if message.get('Item', {}).get('Type') == 'Episode':
eventItem.item_type = "TV"

View File

@ -41,7 +41,7 @@ class JellyfinModule(_ModuleBase):
# Jellyfin认证
return self.jellyfin.authenticate(name, password)
def webhook_parser(self, body: Any, form: Any, args: Any) -> WebhookEventInfo:
def webhook_parser(self, body: Any, form: Any, args: Any) -> Optional[WebhookEventInfo]:
"""
解析Webhook报文体
:param body: 请求体
@ -49,7 +49,7 @@ class JellyfinModule(_ModuleBase):
:param args: 请求参数
:return: 字典解析为消息时需要包含title、text、image
"""
return self.jellyfin.get_webhook_message(json.loads(body))
return self.jellyfin.get_webhook_message(body)
def media_exists(self, mediainfo: MediaInfo, itemid: str = None) -> Optional[ExistMediaInfo]:
"""
@ -83,32 +83,34 @@ class JellyfinModule(_ModuleBase):
logger.info(f"{mediainfo.title_year} 媒体库中已存在:{tvs}")
return ExistMediaInfo(type=MediaType.TV, seasons=tvs)
def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: Path) -> Optional[bool]:
def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: Path) -> None:
"""
刷新媒体库
:param mediainfo: 识别的媒体信息
:param file_path: 文件路径
:return: 成功或失败
"""
return self.jellyfin.refresh_root_library()
self.jellyfin.refresh_root_library()
def media_statistic(self) -> schemas.Statistic:
def media_statistic(self) -> List[schemas.Statistic]:
"""
媒体数量统计
"""
media_statistic = self.jellyfin.get_medias_count()
user_count = self.jellyfin.get_user_count()
return schemas.Statistic(
return [schemas.Statistic(
movie_count=media_statistic.get("MovieCount") or 0,
tv_count=media_statistic.get("SeriesCount") or 0,
episode_count=media_statistic.get("EpisodeCount") or 0,
user_count=user_count or 0
)
)]
def mediaserver_librarys(self) -> List[schemas.MediaServerLibrary]:
def mediaserver_librarys(self, server: str) -> Optional[List[schemas.MediaServerLibrary]]:
"""
媒体库列表
"""
if server != "jellyfin":
return None
librarys = self.jellyfin.get_librarys()
if not librarys:
return []
@ -120,10 +122,12 @@ class JellyfinModule(_ModuleBase):
path=library.get("path")
) for library in librarys]
def mediaserver_items(self, library_id: str) -> Generator:
def mediaserver_items(self, server: str, library_id: str) -> Optional[Generator]:
"""
媒体库项目列表
"""
if server != "jellyfin":
return None
items = self.jellyfin.get_items(library_id)
for item in items:
yield schemas.MediaServerItem(
@ -140,10 +144,13 @@ class JellyfinModule(_ModuleBase):
path=item.get("path"),
)
def mediaserver_tv_episodes(self, item_id: Union[str, int]) -> List[schemas.MediaServerSeasonInfo]:
def mediaserver_tv_episodes(self, server: str,
item_id: Union[str, int]) -> Optional[List[schemas.MediaServerSeasonInfo]]:
"""
获取剧集信息
"""
if server != "jellyfin":
return None
seasoninfo = self.jellyfin.get_tv_episodes(item_id=item_id)
if not seasoninfo:
return []

View File

@ -387,7 +387,7 @@ class Jellyfin(metaclass=Singleton):
logger.error(f"连接Library/Refresh出错" + str(e))
return False
def get_webhook_message(self, message: dict) -> WebhookEventInfo:
def get_webhook_message(self, body: any) -> Optional[WebhookEventInfo]:
"""
解析Jellyfin报文
{
@ -450,9 +450,21 @@ class Jellyfin(metaclass=Singleton):
"UserId": "9783d2432b0d40a8a716b6aa46xxxxx"
}
"""
if not body:
return None
try:
message = json.loads(body)
except Exception as e:
logger.debug(f"解析Jellyfin Webhook报文出错" + str(e))
return None
if not message:
return None
logger.info(f"接收到jellyfin webhook{message}")
eventType = message.get('NotificationType')
if not eventType:
return None
eventItem = WebhookEventInfo(
event=message.get('NotificationType', ''),
event=eventType,
channel="jellyfin"
)
eventItem.item_id = message.get('ItemId')

View File

@ -31,7 +31,7 @@ class PlexModule(_ModuleBase):
if not self.plex.is_inactive():
self.plex = Plex()
def webhook_parser(self, body: Any, form: Any, args: Any) -> WebhookEventInfo:
def webhook_parser(self, body: Any, form: Any, args: Any) -> Optional[WebhookEventInfo]:
"""
解析Webhook报文体
:param body: 请求体
@ -39,7 +39,7 @@ class PlexModule(_ModuleBase):
:param args: 请求参数
:return: 字典解析为消息时需要包含title、text、image
"""
return self.plex.get_webhook_message(form.get("payload"))
return self.plex.get_webhook_message(form)
def media_exists(self, mediainfo: MediaInfo, itemid: str = None) -> Optional[ExistMediaInfo]:
"""
@ -77,7 +77,7 @@ class PlexModule(_ModuleBase):
logger.info(f"{mediainfo.title_year} 媒体库中已存在:{tvs}")
return ExistMediaInfo(type=MediaType.TV, seasons=tvs)
def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: Path) -> Optional[bool]:
def refresh_mediaserver(self, mediainfo: MediaInfo, file_path: Path) -> None:
"""
刷新媒体库
:param mediainfo: 识别的媒体信息
@ -93,24 +93,26 @@ class PlexModule(_ModuleBase):
target_path=file_path
)
]
return self.plex.refresh_library_by_items(items)
self.plex.refresh_library_by_items(items)
def media_statistic(self) -> schemas.Statistic:
def media_statistic(self) -> List[schemas.Statistic]:
"""
媒体数量统计
"""
media_statistic = self.plex.get_medias_count()
return schemas.Statistic(
return [schemas.Statistic(
movie_count=media_statistic.get("MovieCount") or 0,
tv_count=media_statistic.get("SeriesCount") or 0,
episode_count=media_statistic.get("EpisodeCount") or 0,
user_count=1
)
)]
def mediaserver_librarys(self) -> List[schemas.MediaServerLibrary]:
def mediaserver_librarys(self, server: str) -> Optional[List[schemas.MediaServerLibrary]]:
"""
媒体库列表
"""
if server != "plex":
return None
librarys = self.plex.get_librarys()
if not librarys:
return []
@ -122,10 +124,12 @@ class PlexModule(_ModuleBase):
path=library.get("path")
) for library in librarys]
def mediaserver_items(self, library_id: str) -> Generator:
def mediaserver_items(self, server: str, library_id: str) -> Optional[Generator]:
"""
媒体库项目列表
"""
if server != "plex":
return None
items = self.plex.get_items(library_id)
for item in items:
yield schemas.MediaServerItem(
@ -142,10 +146,13 @@ class PlexModule(_ModuleBase):
path=item.get("path"),
)
def mediaserver_tv_episodes(self, item_id: Union[str, int]) -> List[schemas.MediaServerSeasonInfo]:
def mediaserver_tv_episodes(self, server: str,
item_id: Union[str, int]) -> Optional[List[schemas.MediaServerSeasonInfo]]:
"""
获取剧集信息
"""
if server != "plex":
return None
seasoninfo = self.plex.get_tv_episodes(item_id=item_id)
if not seasoninfo:
return []

View File

@ -353,7 +353,7 @@ class Plex(metaclass=Singleton):
logger.error(f"获取媒体库列表出错:{err}")
yield {}
def get_webhook_message(self, message_str: str) -> WebhookEventInfo:
def get_webhook_message(self, form: any) -> Optional[WebhookEventInfo]:
"""
解析Plex报文
eventItem 字段的含义
@ -457,9 +457,21 @@ class Plex(metaclass=Singleton):
}
}
"""
message = json.loads(message_str)
if not form:
return None
payload = form.get("payload")
if not payload:
return None
try:
message = json.loads(payload)
except Exception as e:
logger.debug(f"解析plex webhook出错{str(e)}")
return None
eventType = message.get('event')
if not eventType:
return None
logger.info(f"接收到plex webhook{message}")
eventItem = WebhookEventInfo(event=message.get('event', ''), channel="plex")
eventItem = WebhookEventInfo(event=eventType, channel="plex")
if message.get('Metadata'):
if message.get('Metadata', {}).get('type') == 'episode':
eventItem.item_type = "TV"