From 49a51cca25d348d2399027d2cc55a5b78688387b Mon Sep 17 00:00:00 2001 From: jxxghp Date: Thu, 7 May 2026 12:54:38 +0800 Subject: [PATCH] fix(media): use Jellyfin-compatible season artwork names Save season artwork in season folders with standard names like poster.jpg so Jellyfin can recognize them. Fixes #5725. --- app/chain/media.py | 10 ++++++++++ tests/test_mediascrape.py | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/app/chain/media.py b/app/chain/media.py index 5833b56e..d4685089 100644 --- a/app/chain/media.py +++ b/app/chain/media.py @@ -352,6 +352,16 @@ class MediaChain(ChainBase, ConfigReloadMixin, metaclass=Singleton): return current_fileitem, None # 返回一个表示失败的FileItem和None target_dir_path = Path(target_dir_item.path) # 图片通常是放在当前目录 (current_fileitem) 下 + # Jellyfin/Kodi 等在季目录内使用通用图片名,而不是 season01-poster.jpg + elif item_type == ScrapingTarget.SEASON: + season_image_name_map = { + ScrapingMetadata.POSTER: "poster", + ScrapingMetadata.BANNER: "banner", + ScrapingMetadata.THUMB: "thumb", + } + if season_image_name := season_image_name_map.get(metadata_type): + hint_ext = Path(filename_hint).suffix if filename_hint else ".jpg" + final_filename = f"{season_image_name}{hint_ext}" # 如果是 EPISODE 类型的图片(如thumb),通常也是放在文件同级目录,文件名与视频文件一致 elif ( metadata_type in [ScrapingMetadata.THUMB] diff --git a/tests/test_mediascrape.py b/tests/test_mediascrape.py index 415b837f..f37ca1db 100644 --- a/tests/test_mediascrape.py +++ b/tests/test_mediascrape.py @@ -64,6 +64,28 @@ class TestMediaScrapingPaths(unittest.TestCase): self.assertEqual(target_item, fileitem) self.assertEqual(target_path, Path("/tv/Show/Season 1/season.nfo")) + def test_season_dir_poster_path(self): + fileitem = schemas.FileItem(path="/tv/Show/Season 1", name="Season 1", type="dir", storage="local") + target_item, target_path = self.media_chain._get_target_fileitem_and_path( + current_fileitem=fileitem, + item_type=ScrapingTarget.SEASON, + metadata_type=ScrapingMetadata.POSTER, + filename_hint="season01-poster.jpg" + ) + self.assertEqual(target_item, fileitem) + self.assertEqual(target_path, Path("/tv/Show/Season 1/poster.jpg")) + + def test_season_dir_specials_poster_path(self): + fileitem = schemas.FileItem(path="/tv/Show/Specials", name="Specials", type="dir", storage="local") + target_item, target_path = self.media_chain._get_target_fileitem_and_path( + current_fileitem=fileitem, + item_type=ScrapingTarget.SEASON, + metadata_type=ScrapingMetadata.POSTER, + filename_hint="season-specials-poster.jpg" + ) + self.assertEqual(target_item, fileitem) + self.assertEqual(target_path, Path("/tv/Show/Specials/poster.jpg")) + def test_episode_file_nfo_path(self): fileitem = schemas.FileItem(path="/tv/Show/Season 1/S01E01.mp4", name="S01E01.mp4", type="file", storage="local") parent_item = schemas.FileItem(path="/tv/Show/Season 1", name="Season 1", type="dir", storage="local") @@ -171,6 +193,7 @@ class TestMediaScrapingImages(unittest.TestCase): calls = self.media_chain._download_and_save_image.call_args_list self.assertEqual(len(calls), 1) self.assertEqual(calls[0].kwargs["url"], "http://season01") + self.assertEqual(calls[0].kwargs["path"], Path("/tv/Show/Season 1/poster.jpg")) def test_scrape_episode_thumb_image_path(self): fileitem = schemas.FileItem(path="/tv/Show/Season 1/S01E01.mp4", name="S01E01.mp4", type="file", storage="local")