Authentication (01), one input policy for skip/mute/volume steps (04), the firmware's interleaved serial frames (05), podcast as an album kind (06), and eight smaller cleanups (07). Each says why, what was decided, the design, the tests and when it is done. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4.3 KiB
Task: make "podcast" a kind of album
Why
AlbumKind is Literal["music", "book"] (python-backend/musicmouse/library/sections.py),
and the Kinderpodcasts shelf is declared kind="book". So "is this a podcast?" is
answered differently in each layer:
- web:
album.section === "Kinderpodcasts"(web/src/lib/search.ts,groupOf), and everything else goes throughgroupOf(album) === "podcasts"(App, PlayView, BrowseView, MobileBrowse, keyboard.ts, remote.ts, ambience.ts, useTrackDetail); - backend:
SECTIONS[album.section].album_unit == "episode"(MusicLibrary.latest_episode,tippen/rewards.py); - typing game: reward kinds
"episode"and"podcast_episode"(services/web/tippen_api.py).
The shelf's folder name is therefore a de-facto API string the front-end depends on.
todo.md already asks for a cleaner podcast data model.
What the owner decided
Add "podcast" to the album kind. Podcast-ness is then a property of the album, carried
in the index and the API, and nobody compares section names.
Design
Backend
AlbumKind = Literal["music", "book", "podcast"].SECTIONS["Kinderpodcasts"]getskind="podcast".Section.album_unitstays. It is the scanner's structural fact (one album per file), not a classification. Keep using it in the scanner (scan_library) and inpodcast_feeds.find_feed_shows. Every place that asks "is this album a podcast?" switches toalbum.kind == "podcast":MusicLibrary.latest_episode;tippen/rewards.py(_chronological_episodes, and thealbum_unit == "folder"branches that really mean "not a podcast");tippen_api._animation_kind;- the
is_podcasthelper, if task 04 added one: change its body, keep its callers.
scanner.scan_albumderivesseriesonly forkind == "book". Check that episode albums still getseries = folder.name(they do, inscan_episodes) and that nothing else branches on"book"meaning "book or podcast".grep -rn '"book"' python-backend/musicmouseand decide per hit.FigureConfig.kindstaysLiteral["music", "book"]. A figurine holding a podcast is not a thing. TypeConfig.figure_kindsaccordingly.cache._album_from_jsonvalidates the kind: accept"podcast". Bump_INDEX_VERSION(with a comment line, like the existing ones), so every cached podcast album is re-scanned with the new kind instead of being read back as"book"._ANALYZED_KINDSstays("music",).services/web/schemas.py:AlbumOut.kindandPlayerStateOut.kindbecome theAlbumKindliteral instead ofstr, so the OpenAPI schema says what the values are.
Web
src/api/types.ts:AlbumKind = "music" | "book" | "podcast".src/lib/search.ts,groupOf: map fromkindalone (podcast→"podcasts",book→"audiobooks", else"music"). Nosectioncomparison may remain anywhere inweb/src.src/lib/covers.ts:isBookandaspectOfKindtreat"book"specially. Podcasts are drawn like books today because they werekind: "book". Keep them looking exactly as they do now: decide explicitly whetherisBook/aspectOfKindinclude"podcast", and check BrowseView'smostlyBooks/allPodcaststiles and the play view. The result must be visually unchanged; compare screenshots of the podcast shelf, a podcast category and the podcast play view before and after.- Anything else that reads
state.kindoralbum.kind: grep and decide per hit.
Leave alone
The section field stays in the API; it is still useful for display and debugging.
Don't rename the shelves, the folders or the Group names.
Tests
tests/test_library.py: aKinderpodcastsepisode scans askind == "podcast"; a cache written at the previous_INDEX_VERSIONis discarded;latest_episodestill works.tests/test_tippen_rewards.py/test_tippen_api.py: episode rewards still resolve and still animate aspodcast_episode.tests/test_web.py:/api/libraryreports"podcast".web/src/lib/__tests__/search.test.ts:groupOfuseskind; an album whose section saysKinderpodcastsbut whose kind ismusicis music. That proves nothing compares the section any more.
Done when
scripts/check.sh passes, grep -rn "Kinderpodcasts" web/src finds nothing, the
backend's "is it a podcast" checks all read album.kind, and the podcast UI looks the
same as before.