Add per-episode podcast cover art and fix nested album grouping
- podcast_feeds.py: fetch per-episode cover art from a feed's itunes:image (when it's genuinely distinct from the channel image) or, failing that, from the og:image on the episode's own linked page; extract audio from video-only enclosures via ffmpeg; match podcast-dl's filename convention (illegal characters become "_" instead of being dropped) so enabling feed.txt on an already-downloaded show doesn't re-download its back catalog - scanner.py: _cover_for_episode now checks for a same-stem sidecar cover image before falling back to embedded ID3 art and the shared folder cover - scanner.py/__init__.py: fixed a bug where an album folder nested one level deeper than usual (an age-range grouping folder, say) was mistaken for an empty album and skipped; added periodic progress logging for long scans and analysis passes Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -237,6 +237,22 @@ async def test_a_cover_file_is_found_and_used(config_dir: Path) -> None:
|
||||
assert album.colors[0] != colors_from_id(album.id)[0]
|
||||
|
||||
|
||||
async def test_an_episodes_sidecar_cover_wins_over_the_shows_shared_one(config_dir: Path) -> None:
|
||||
from PIL import Image
|
||||
|
||||
# Downloaded by `podcast_feeds.py` when a feed has real per-episode art (see its
|
||||
# `episode_cover_filename`) - same stem as the episode's audio file.
|
||||
podcast = config_dir / "music" / "Kinderpodcasts" / "Wissen macht Ah"
|
||||
Image.new("RGB", (32, 32), (10, 20, 30)).save(podcast / "cover.jpg")
|
||||
Image.new("RGB", (32, 32), (200, 40, 30)).save(podcast / "20260101 - Neu.jpg")
|
||||
|
||||
library = await build(config_dir)
|
||||
|
||||
assert album_named(library, "Neu").cover == podcast / "20260101 - Neu.jpg"
|
||||
# No sidecar for this one, so it still falls back to the show's shared cover.
|
||||
assert album_named(library, "Alt").cover == podcast / "cover.jpg"
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- cache
|
||||
|
||||
|
||||
@@ -359,6 +375,28 @@ def test_album_ids_are_stable_and_path_derived(tmp_path: Path) -> None:
|
||||
assert first != other
|
||||
|
||||
|
||||
async def test_an_album_nested_under_an_extra_grouping_folder_is_still_found(
|
||||
config_dir: Path,
|
||||
) -> None:
|
||||
"""The bug this fixed: an artist folder that groups its books one level deeper than
|
||||
usual (an age-range folder, say) has no audio directly in it, so the scanner used to
|
||||
treat it as an empty album and skip the whole artist rather than looking further
|
||||
down for the actual album folders."""
|
||||
for index in range(2):
|
||||
write_track(
|
||||
config_dir / "music" / "Hörbücher" / "Petzi" / "ab 5" / "Petzi und der Wal"
|
||||
/ f"{index:02d} - teil.mp3",
|
||||
title=f"Teil {index}",
|
||||
album="Petzi und der Wal",
|
||||
albumartist="Petzi",
|
||||
)
|
||||
library = await build(config_dir)
|
||||
|
||||
album = album_named(library, "Petzi und der Wal")
|
||||
assert album.kind == "book"
|
||||
assert len(album.tracks) == 2
|
||||
|
||||
|
||||
# -------------------------------------------------------------------- figure kinds
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user