mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-07-28 17:27:01 +08:00
feat(mediaserver): add item count retrieval for various media servers
This commit is contained in:
@@ -243,6 +243,19 @@ class EmbyModule(_ModuleBase, _MediaServerBase[Emby]):
|
||||
return server_obj.get_items(library_id, start_index, limit)
|
||||
return None
|
||||
|
||||
def mediaserver_items_count(self, server: str, library_id: Union[str, int]) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库可同步的媒体条目总数
|
||||
|
||||
:param server: 媒体服务器名称
|
||||
:param library_id: 媒体库ID
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
server_obj: Emby = self.get_instance(server)
|
||||
if server_obj:
|
||||
return server_obj.get_items_count(library_id)
|
||||
return None
|
||||
|
||||
def mediaserver_iteminfo(self, server: str, item_id: str) -> Optional[schemas.MediaServerItem]:
|
||||
"""
|
||||
媒体库项目详情
|
||||
|
||||
@@ -693,6 +693,33 @@ class Emby:
|
||||
logger.error(f"连接/Users/{self.user}/Items/{itemid}出错:" + str(e))
|
||||
return None
|
||||
|
||||
def get_items_count(self, parent: Union[str, int]) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库可同步的电影和剧集总数
|
||||
|
||||
:param parent: 媒体库ID
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
if not parent or not self._host or not self._apikey:
|
||||
return None
|
||||
url = f"{self._host}emby/Users/{self.user}/Items"
|
||||
params = {
|
||||
"ParentId": parent,
|
||||
"Recursive": "true",
|
||||
"IncludeItemTypes": "Movie,Series",
|
||||
"Limit": 0,
|
||||
"api_key": self._apikey,
|
||||
}
|
||||
try:
|
||||
res = RequestUtils().get_res(url, params)
|
||||
if not res or res.status_code != 200:
|
||||
return None
|
||||
total_count = res.json().get("TotalRecordCount")
|
||||
return int(total_count) if total_count is not None else None
|
||||
except Exception as e:
|
||||
logger.error(f"查询媒体库 {parent} 的媒体总数出错:{str(e)}")
|
||||
return None
|
||||
|
||||
def get_items(self, parent: Union[str, int], start_index: Optional[int] = 0,
|
||||
limit: Optional[int] = -1) -> Generator[MediaServerItem | None | Any, Any, None]:
|
||||
"""
|
||||
|
||||
@@ -242,6 +242,19 @@ class JellyfinModule(_ModuleBase, _MediaServerBase[Jellyfin]):
|
||||
return server_obj.get_items(library_id, start_index, limit)
|
||||
return None
|
||||
|
||||
def mediaserver_items_count(self, server: str, library_id: Union[str, int]) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库可同步的媒体条目总数
|
||||
|
||||
:param server: 媒体服务器名称
|
||||
:param library_id: 媒体库ID
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
server_obj: Jellyfin = self.get_instance(server)
|
||||
if server_obj:
|
||||
return server_obj.get_items_count(library_id)
|
||||
return None
|
||||
|
||||
def mediaserver_iteminfo(self, server: str, item_id: str) -> Optional[schemas.MediaServerItem]:
|
||||
"""
|
||||
媒体库项目详情
|
||||
|
||||
@@ -808,6 +808,33 @@ class Jellyfin:
|
||||
logger.error(f"连接Users/{self.user}/Items/{itemid}:" + str(e))
|
||||
return None
|
||||
|
||||
def get_items_count(self, parent: Union[str, int]) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库可同步的电影和剧集总数
|
||||
|
||||
:param parent: 媒体库ID
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
if not parent or not self._host or not self._apikey or not self.user:
|
||||
return None
|
||||
url = f"{self._host}Users/{self.user}/Items"
|
||||
params = {
|
||||
"ParentId": parent,
|
||||
"Recursive": "true",
|
||||
"IncludeItemTypes": "Movie,Series",
|
||||
"Limit": 0,
|
||||
"api_key": self._apikey,
|
||||
}
|
||||
try:
|
||||
res = RequestUtils().get_res(url, params)
|
||||
if not res or res.status_code != 200:
|
||||
return None
|
||||
total_count = res.json().get("TotalRecordCount")
|
||||
return int(total_count) if total_count is not None else None
|
||||
except Exception as e:
|
||||
logger.error(f"查询媒体库 {parent} 的媒体总数出错:{str(e)}")
|
||||
return None
|
||||
|
||||
def get_items(self, parent: Union[str, int], start_index: Optional[int] = 0, limit: Optional[int] = -1) \
|
||||
-> Generator[MediaServerItem | None | Any, Any, None]:
|
||||
"""
|
||||
|
||||
@@ -253,6 +253,19 @@ class PlexModule(_ModuleBase, _MediaServerBase[Plex]):
|
||||
return server_obj.get_items(library_id, start_index, limit)
|
||||
return None
|
||||
|
||||
def mediaserver_items_count(self, server: str, library_id: Union[str, int]) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库可同步的媒体条目总数
|
||||
|
||||
:param server: 媒体服务器名称
|
||||
:param library_id: 媒体库ID
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
server_obj: Plex = self.get_instance(server)
|
||||
if server_obj:
|
||||
return server_obj.get_items_count(library_id)
|
||||
return None
|
||||
|
||||
def mediaserver_iteminfo(self, server: str, item_id: str) -> Optional[schemas.MediaServerItem]:
|
||||
"""
|
||||
媒体库项目详情
|
||||
|
||||
@@ -575,6 +575,22 @@ class Plex:
|
||||
user_state=user_state,
|
||||
)
|
||||
|
||||
def get_items_count(self, parent: Union[str, int]) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库可同步的媒体条目总数
|
||||
|
||||
:param parent: 媒体库ID
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
if not parent or not self._plex:
|
||||
return None
|
||||
try:
|
||||
section = self._plex.library.sectionByID(int(parent))
|
||||
return int(section.totalSize) if section else None
|
||||
except Exception as err:
|
||||
logger.error(f"查询媒体库 {parent} 的媒体总数出错:{str(err)}")
|
||||
return None
|
||||
|
||||
def get_items(self, parent: Union[str, int], start_index: Optional[int] = 0, limit: Optional[int] = -1) \
|
||||
-> Generator[MediaServerItem | None, Any, None]:
|
||||
"""
|
||||
|
||||
@@ -281,6 +281,21 @@ class TrimeMediaModule(_ModuleBase, _MediaServerBase[TrimeMedia]):
|
||||
return server_obj.get_items(library_id, start_index, limit)
|
||||
return None
|
||||
|
||||
def mediaserver_items_count(
|
||||
self, server: str, library_id: Union[str, int]
|
||||
) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库可同步的媒体条目总数
|
||||
|
||||
:param server: 媒体服务器名称
|
||||
:param library_id: 媒体库ID
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
server_obj: Optional[TrimeMedia] = self.get_instance(server)
|
||||
if server_obj:
|
||||
return server_obj.get_items_count(library_id)
|
||||
return None
|
||||
|
||||
def mediaserver_iteminfo(
|
||||
self, server: str, item_id: str
|
||||
) -> Optional[schemas.MediaServerItem]:
|
||||
|
||||
@@ -347,6 +347,32 @@ class Api:
|
||||
return [self.__build_item(info) for info in res.data.get("list", [])]
|
||||
return None
|
||||
|
||||
def item_count(self, guid: str, types=None) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库的媒体条目总数
|
||||
|
||||
:param guid: 媒体库GUID
|
||||
:param types: 需要统计的媒体类型
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
if types is None:
|
||||
types = [Type.MOVIE, Type.TV]
|
||||
post = {
|
||||
"ancestor_guid": guid,
|
||||
"tags": {"type": types},
|
||||
"exclude_grouped_video": 1,
|
||||
"page": 1,
|
||||
"page_size": 1,
|
||||
}
|
||||
if (res := self.request("/item/list", data=post)) and res.success:
|
||||
if not res.data:
|
||||
return 0
|
||||
total_count = res.data.get("total")
|
||||
if total_count is None:
|
||||
total_count = res.data.get("total_count")
|
||||
return int(total_count) if total_count is not None else None
|
||||
return None
|
||||
|
||||
def search_list(self, keywords: str) -> Optional[list[Item]]:
|
||||
"""
|
||||
搜索影片、演员
|
||||
|
||||
@@ -510,6 +510,20 @@ class TrimeMedia:
|
||||
use_cookies=True,
|
||||
)
|
||||
|
||||
def get_items_count(self, parent: Union[str, int]) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库可同步的媒体条目总数
|
||||
|
||||
:param parent: 媒体库ID
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
if not self.is_authenticated():
|
||||
return None
|
||||
return self._api.item_count(
|
||||
guid=str(parent),
|
||||
types=[fnapi.Type.MOVIE, fnapi.Type.TV],
|
||||
)
|
||||
|
||||
def get_items(
|
||||
self,
|
||||
parent: Union[str, int],
|
||||
|
||||
@@ -253,6 +253,21 @@ class UgreenModule(_ModuleBase, _MediaServerBase[Ugreen]):
|
||||
return server_obj.get_items(library_id, start_index, limit)
|
||||
return None
|
||||
|
||||
def mediaserver_items_count(
|
||||
self, server: str, library_id: Union[str, int]
|
||||
) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库可同步的媒体条目总数
|
||||
|
||||
:param server: 媒体服务器名称
|
||||
:param library_id: 媒体库ID
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
server_obj: Optional[Ugreen] = self.get_instance(server)
|
||||
if server_obj:
|
||||
return server_obj.get_items_count(library_id)
|
||||
return None
|
||||
|
||||
def mediaserver_iteminfo(
|
||||
self, server: str, item_id: str
|
||||
) -> Optional[schemas.MediaServerItem]:
|
||||
|
||||
@@ -66,15 +66,19 @@ class Ugreen:
|
||||
|
||||
@property
|
||||
def api(self) -> Optional[Api]:
|
||||
"""获取当前绿联影视 API 客户端"""
|
||||
return self._api
|
||||
|
||||
def close(self):
|
||||
"""关闭绿联影视连接"""
|
||||
self.disconnect()
|
||||
|
||||
def is_configured(self) -> bool:
|
||||
"""检查绿联影视连接配置是否完整"""
|
||||
return bool(self._host and self._username and self._password)
|
||||
|
||||
def is_authenticated(self) -> bool:
|
||||
"""检查绿联影视会话是否已认证"""
|
||||
return (
|
||||
self.is_configured()
|
||||
and self._api is not None
|
||||
@@ -83,6 +87,7 @@ class Ugreen:
|
||||
)
|
||||
|
||||
def is_inactive(self) -> bool:
|
||||
"""检查绿联影视会话是否已失效"""
|
||||
if not self.is_authenticated():
|
||||
return True
|
||||
self._userinfo = self._api.current_user() if self._api else None
|
||||
@@ -516,6 +521,12 @@ class Ugreen:
|
||||
return paths
|
||||
|
||||
def get_librarys(self, hidden: Optional[bool] = False) -> List[schemas.MediaServerLibrary]:
|
||||
"""
|
||||
获取绿联影视媒体库列表
|
||||
|
||||
:param hidden: 是否过滤未启用同步的媒体库
|
||||
:return: 媒体库列表
|
||||
"""
|
||||
if not self.is_authenticated() or not self._api:
|
||||
return []
|
||||
|
||||
@@ -567,12 +578,14 @@ class Ugreen:
|
||||
return libraries
|
||||
|
||||
def get_user_count(self) -> int:
|
||||
"""获取绿联影视媒体库用户数量"""
|
||||
if not self.is_authenticated() or not self._api:
|
||||
return 0
|
||||
users = self._api.media_lib_users()
|
||||
return len(users)
|
||||
|
||||
def get_medias_count(self) -> schemas.Statistic:
|
||||
"""获取绿联影视的电影和电视剧数量统计"""
|
||||
if not self.is_authenticated() or not self._api:
|
||||
return schemas.Statistic()
|
||||
|
||||
@@ -856,12 +869,36 @@ class Ugreen:
|
||||
break
|
||||
page += 1
|
||||
|
||||
def get_items_count(self, parent: Union[str, int]) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库可同步的媒体条目总数
|
||||
|
||||
:param parent: 媒体库ID
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
if not self.is_authenticated() or not self._api:
|
||||
return None
|
||||
if not self._libraries:
|
||||
self.get_librarys()
|
||||
library = self._libraries.get(str(parent))
|
||||
if not library:
|
||||
return None
|
||||
return int(library.get("video_count") or 0)
|
||||
|
||||
def get_items(
|
||||
self,
|
||||
parent: Union[str, int],
|
||||
start_index: Optional[int] = 0,
|
||||
limit: Optional[int] = -1,
|
||||
) -> Generator[schemas.MediaServerItem | None | Any, Any, None]:
|
||||
"""
|
||||
获取指定绿联影视媒体库的可同步条目
|
||||
|
||||
:param parent: 媒体库ID
|
||||
:param start_index: 起始条目索引
|
||||
:param limit: 最大返回条目数,-1表示不限制
|
||||
:return: 媒体条目生成器
|
||||
"""
|
||||
if not self.is_authenticated() or not self._api:
|
||||
return None
|
||||
|
||||
|
||||
@@ -237,6 +237,19 @@ class ZSpaceModule(_ModuleBase, _MediaServerBase[ZSpace]):
|
||||
return server_obj.get_items(library_id, start_index, limit)
|
||||
return None
|
||||
|
||||
def mediaserver_items_count(self, server: str, library_id: Union[str, int]) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库可同步的媒体条目总数
|
||||
|
||||
:param server: 媒体服务器名称
|
||||
:param library_id: 媒体库ID
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
server_obj: ZSpace = self.get_instance(server)
|
||||
if server_obj:
|
||||
return server_obj.get_items_count(library_id)
|
||||
return None
|
||||
|
||||
def mediaserver_iteminfo(self, server: str, item_id: str) -> Optional[schemas.MediaServerItem]:
|
||||
"""
|
||||
媒体库项目详情
|
||||
|
||||
@@ -815,6 +815,32 @@ class ZSpace:
|
||||
logger.error(f"连接/Users/{self.user}/Items/{itemid}出错:{e}")
|
||||
return None
|
||||
|
||||
def get_items_count(self, parent: Union[str, int]) -> Optional[int]:
|
||||
"""
|
||||
获取指定媒体库的媒体条目总数
|
||||
|
||||
极影视当前兼容层会忽略条目类型过滤,因此以递归查询返回的
|
||||
TotalRecordCount 作为同步进度的总数。
|
||||
|
||||
:param parent: 媒体库ID
|
||||
:return: 媒体条目总数,查询失败时返回None
|
||||
"""
|
||||
if not parent or not self._host or not self._apikey or not self.user:
|
||||
return None
|
||||
url = f"{self._host}emby/Users/{self.user}/Items"
|
||||
try:
|
||||
res = self.__request_utils().get_res(
|
||||
url,
|
||||
params={"ParentId": parent, "Recursive": "true", "Limit": 0},
|
||||
)
|
||||
if not res or res.status_code != 200:
|
||||
return None
|
||||
total_count = res.json().get("TotalRecordCount")
|
||||
return int(total_count) if total_count is not None else None
|
||||
except Exception as e:
|
||||
logger.error(f"查询媒体库 {parent} 的媒体总数出错:{e}")
|
||||
return None
|
||||
|
||||
def get_items(self, parent: Union[str, int], start_index: Optional[int] = 0,
|
||||
limit: Optional[int] = -1) -> Generator[MediaServerItem | None | Any, Any, None]:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user