From 5f050f35b648fb46723fe299f4ba68d666d2a926 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sun, 13 Sep 2026 11:11:40 +0800 Subject: [PATCH] fix(jellyfin): fallback when collection type is missing --- app/modules/jellyfin/jellyfin.py | 10 ++++++--- tests/test_jellyfin_medias_count.py | 32 +++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/app/modules/jellyfin/jellyfin.py b/app/modules/jellyfin/jellyfin.py index eb795fcb8..169b34dff 100644 --- a/app/modules/jellyfin/jellyfin.py +++ b/app/modules/jellyfin/jellyfin.py @@ -356,7 +356,7 @@ class Jellyfin: 优先遍历用户媒体库视图逐库统计:全局 `Items/Counts` 按数据库原始条目 计数,同一影片在库内有多个版本/多个文件夹拷贝时会重复累计(#5915), 而用户级 `Users/{user}/Items` 查询会折叠版本,与 Jellyfin 页面显示一致。 - 仅在用户视图不可用时回退到 `Items/Counts`。 + 仅在用户视图不可用或没有可识别媒体库时回退到 `Items/Counts`。 :return: MovieCount SeriesCount EpisodeCount """ if not self._host or not self._apikey: @@ -392,7 +392,7 @@ class Jellyfin: `Users/{user}/Views` 每个媒体库仅返回一条记录(库包含多个文件夹时 也不会重复),按 `CollectionType` 分桶后用用户级条目查询累计。 - :return: 统计结果,用户或媒体库视图不可用时返回None(由调用方回退) + :return: 统计结果;用户、媒体库视图不可用或没有可识别媒体库时返回None(由调用方回退) """ if not self.user: return None @@ -400,19 +400,23 @@ class Jellyfin: if not librarys: return None stat = _SchemaStatistic() + has_known_library = False for library in librarys: library_id = library.get("Id") if not library_id: continue collection_type = library.get("CollectionType") if collection_type == "movies": + has_known_library = True stat.movie_count += self.get_items_count(library_id, include_item_types="Movie") or 0 elif collection_type == "tvshows": + has_known_library = True stat.tv_count += self.get_items_count(library_id, include_item_types="Series") or 0 stat.episode_count += self.get_items_count(library_id, include_item_types="Episode") or 0 elif collection_type in ("music", "musicvideos"): + has_known_library = True stat.music_count += self.get_items_count(library_id, include_item_types="MusicAlbum") or 0 - return stat + return stat if has_known_library else None def __get_jellyfin_series_id_by_name(self, name: str, year: str) -> Optional[str]: """ diff --git a/tests/test_jellyfin_medias_count.py b/tests/test_jellyfin_medias_count.py index 399a03e09..094a91c6a 100644 --- a/tests/test_jellyfin_medias_count.py +++ b/tests/test_jellyfin_medias_count.py @@ -106,6 +106,38 @@ def test_medias_count_falls_back_without_user(): assert args[0] == "http://media.local/Items/Counts" +def test_medias_count_falls_back_when_collection_type_missing(): + """媒体库缺少 CollectionType 时应回退到全局 Items/Counts 统计。""" + client = _make_client() + views = { + "Items": [{ + "Id": "lib-mixed", + "TypeOptions": ["Series", "Season", "Episode", "Movie"], + }] + } + global_counts = { + "MovieCount": 8, + "SeriesCount": 3, + "EpisodeCount": 24, + "MusicAlbumCount": 11, + } + + with patch("app.modules.jellyfin.jellyfin.RequestUtils") as request_utils_cls: + request_utils_cls.return_value.get_res.side_effect = _routed_get_res( + views, {}, global_counts=global_counts + ) + stat = client.get_medias_count() + + assert stat.movie_count == 8 + assert stat.tv_count == 3 + assert stat.episode_count == 24 + assert stat.music_count == 11 + assert [call.args[0] for call in request_utils_cls.return_value.get_res.call_args_list] == [ + "http://media.local/Users/user-id/Views", + "http://media.local/Items/Counts", + ] + + def test_medias_count_falls_back_when_views_unavailable(): """媒体库视图查询失败时应回退到全局 Items/Counts 统计。""" client = _make_client()