navidrome/persistence
Jiho Andrew Lee 152a032ae1 feat(podcast): implement Podcasting 2.0 namespace support (Tier 1–3)
Adds full support for the Podcasting 2.0 namespace
(https://podcastindex.org/namespace/1.0) across RSS parsing, persistence,
Subsonic API responses, and OpenSubsonic extensions.

- podcast:guid: channel-level UUIDv5 for stable identity across feed URL changes
- podcast:chapters: per-episode chapters URL + MIME type (chaptersUrl in API)
- podcast:transcript: multiple transcripts per episode stored in a dedicated
  podcast_transcript table; attributes: url, type, language, rel
- podcast:season: season number + optional name per episode
- podcast:episode: episode number (decimal string) + optional display label

- podcast:person: host/guest entries at both channel and episode level stored in
  a dedicated podcast_person table; attributes: name, role, group, img, href;
  role defaults to "host" and group defaults to "cast" per spec
- podcast:locked: feed lock flag + optional owner email on channel
- podcast:funding: first funding entry URL + display text on channel
- podcast:medium: content type classification on channel
- podcast:soundbite: startTime (float), duration (float), title per episode
- podcast:updateFrequency: display text + rrule + complete flag on channel

- podcast:podroll: creator-recommended feed list stored in podcast_podroll table
  (feedGuid, feedUrl, title, sort_order); returned as podroll[] in GetPodcasts
- podcast:liveItem: live stream detection stored in podcast_live_item table
  (one row per channel, unique index); stores status, start/end times,
  enclosure URL/type, and contentLink for fallback playback; returned as
  liveItem object in GetPodcasts; Upsert preserves created_at on updates
- podcast:podping: usesPodping boolean on channel; RefreshChannels skips
  channels with usesPodping=true (they receive updates via Podping WebSocket)

- 20260428000000_add_podcast20.go: ALTER TABLE adds 9 columns to
  podcast_channel, 9 columns to podcast_episode; CREATE TABLE
  podcast_transcript (episode_id FK, url, mime_type, language, rel) and
  podcast_person (no FK constraints — put() serialises "" not NULL)
- 20260428120000_add_podcast_tier3.go: ALTER TABLE adds uses_podping to
  podcast_channel; CREATE TABLE podcast_podroll and podcast_live_item
  (UNIQUE INDEX on channel_id)

GetPodcasts response (PodcastChannel) gains:
  podcastGuid, locked, medium, fundingUrl, fundingText, updateFrequency,
  complete, usesPodping, person[], podroll[], liveItem{}

GetPodcastEpisode response (PodcastEpisode) gains:
  season, seasonName, episode, episodeDisplay, chaptersUrl, soundbiteStart,
  soundbiteDur, transcript[], person[]

GetPodcastEpisode now loads transcripts and persons from their repositories
(previously only read the base episode row).

New OpenSubsonic extensions declared:
  podcastChapters, podcastTranscripts, podcastSeason, podcastPerson,
  podcastFunding, podcastMedium, podcastPodroll, podcastLiveItem, podcastPodping

- core/podcasts/rss_test.go: 41 new specs covering all namespace tags,
  default value handling (role→"host", group→"cast"), backward compatibility
- core/podcasts/podcasts_test.go: 26 new service specs covering AddChannel
  field persistence, transcript/person saving, podroll/liveItem saving,
  RefreshChannels podping skip behaviour
- persistence/podcast_transcript_repository_test.go: 10 specs
- persistence/podcast_person_repository_test.go: 12 specs
- persistence/podcast_podroll_repository_test.go: 10 specs
- persistence/podcast_live_item_repository_test.go: 8 specs
- server/subsonic/podcasts_test.go: 15 new handler specs for Tier 2 and
  Tier 3 fields in GetPodcasts and GetPodcastEpisode responses
2026-09-19 21:07:17 +09:00
..
e2e feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
album_repository.go fix(artwork): never retry absent artwork on its own (#6054) 2026-09-01 20:48:41 -04:00
album_repository_test.go fix(artwork): never retry absent artwork on its own (#6054) 2026-09-01 20:48:41 -04:00
artist_repository.go Merge commit from fork 2026-09-12 13:37:33 -04:00
artist_repository_test.go Merge commit from fork 2026-09-12 13:37:33 -04:00
artwork_hydration.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
artwork_hydration_test.go fix(artwork): never retry absent artwork on its own (#6054) 2026-09-01 20:48:41 -04:00
artwork_queue_repository.go fix(artwork): never retry absent artwork on its own (#6054) 2026-09-01 20:48:41 -04:00
artwork_queue_repository_test.go fix(artwork): never retry absent artwork on its own (#6054) 2026-09-01 20:48:41 -04:00
artwork_repository.go feat(artwork): store the resolution trace so artwork explain works offline (#5980) 2026-08-21 10:24:01 -04:00
artwork_repository_test.go feat(artwork): store the resolution trace so artwork explain works offline (#5980) 2026-08-21 10:24:01 -04:00
collation_test.go perf(db): index media_file album/artist sort orders (#5706) 2026-07-03 08:58:55 -04:00
criteria_sql.go feat(scrobbler): add per-user scrobble filter (#5964) 2026-08-15 16:10:53 -04:00
criteria_sql_benchmark_test.go feat(scrobbler): add per-user scrobble filter (#5964) 2026-08-15 16:10:53 -04:00
criteria_sql_test.go feat(scrobbler): add per-user scrobble filter (#5964) 2026-08-15 16:10:53 -04:00
export_test.go feat(bfr): Big Refactor: new scanner, lots of new fields and tags, improvements and DB schema changes (#2709) 2025-02-19 20:35:17 -05:00
folder_repository.go fix(artwork): re-resolve artwork when image files change on disk (#5965) 2026-08-16 13:24:07 -04:00
folder_repository_test.go test: unskip path-separator tests on Windows (#5381) (#5916) 2026-08-19 11:50:32 -04:00
genre_repository.go fix(jellyfin): resolve genre id as a MusicGenre item 2026-08-10 21:37:57 -04:00
genre_repository_test.go refactor: run Go modernize (#5002) 2026-02-08 09:57:30 -05:00
helpers.go feat: add optional natural sort order for names and titles (#6015) 2026-08-23 14:31:37 -04:00
helpers_test.go feat: add optional natural sort order for names and titles (#6015) 2026-08-23 14:31:37 -04:00
item_tags_test.go perf(genre): index genre filtering via join tables across all APIs (#5940) 2026-08-11 08:00:50 -04:00
library_repository.go fix(server): update StoreMusicFolder to skip updates when path is unchanged 2026-09-06 12:40:07 -04:00
library_repository_test.go fix(server): update StoreMusicFolder to skip updates when path is unchanged 2026-09-06 12:40:07 -04:00
mediafile_repository.go feat(cli): add missing file list and remap subcommands (#5928) 2026-09-12 12:08:25 -04:00
mediafile_repository_test.go feat(cli): add missing file list and remap subcommands (#5928) 2026-09-12 12:08:25 -04:00
persistence.go feat(podcast): implement Podcasting 2.0 namespace support (Tier 1–3) 2026-09-19 21:07:17 +09:00
persistence_suite_test.go feat(podcast): add podcast feature with UX improvements - #5420 2026-09-19 21:07:04 +09:00
persistence_test.go fix(server): play queue should not return empty entries for deleted tracks 2024-09-20 11:22:37 -04:00
player_repository.go fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00
player_repository_test.go fix(share): enforce per-user ownership on share reads 2026-06-05 15:50:59 -04:00
playlist_repository.go fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00
playlist_repository_test.go fix(artwork): never retry absent artwork on its own (#6054) 2026-09-01 20:48:41 -04:00
playlist_track_repository.go feat: add optional natural sort order for names and titles (#6015) 2026-08-23 14:31:37 -04:00
playlist_track_repository_test.go fix(playlists): chunk track deletes to stay under the SQLite variable limit (#5977) 2026-08-17 15:47:41 -04:00
playqueue_repository.go refactor: multiple syntax updates for Go 1.26 2026-05-19 18:02:36 -03:00
playqueue_repository_test.go fix(server): ensure single record per user by reusing existing playqueue ID 2025-06-11 17:26:13 -04:00
plugin_cleanup.go feat(plugins): New Plugin System with multi-language PDK support (#4833) 2026-01-14 19:22:48 -05:00
plugin_cleanup_test.go feat(plugins): New Plugin System with multi-language PDK support (#4833) 2026-01-14 19:22:48 -05:00
plugin_repository.go fix(nativeapi): stop partial PUTs from clearing untouched columns (#6058) 2026-08-31 11:21:32 -04:00
plugin_repository_test.go fix(plugins): clear plugin errors on startup to allow retrying 2026-03-02 08:56:56 -05:00
podcast_channel_repository.go fix(podcast): address code review feedback 2026-09-19 21:07:17 +09:00
podcast_channel_repository_test.go feat(podcast): add podcast feature with UX improvements - #5420 2026-09-19 21:07:04 +09:00
podcast_episode_repository.go fix(podcast): address code review feedback 2026-09-19 21:07:17 +09:00
podcast_episode_repository_test.go feat(podcast): add podcast feature with UX improvements - #5420 2026-09-19 21:07:04 +09:00
podcast_live_item_repository.go feat(podcast): implement Podcasting 2.0 namespace support (Tier 1–3) 2026-09-19 21:07:17 +09:00
podcast_live_item_repository_test.go feat(podcast): implement Podcasting 2.0 namespace support (Tier 1–3) 2026-09-19 21:07:17 +09:00
podcast_person_repository.go feat(podcast): implement Podcasting 2.0 namespace support (Tier 1–3) 2026-09-19 21:07:17 +09:00
podcast_person_repository_test.go feat(podcast): implement Podcasting 2.0 namespace support (Tier 1–3) 2026-09-19 21:07:17 +09:00
podcast_podroll_repository.go feat(podcast): implement Podcasting 2.0 namespace support (Tier 1–3) 2026-09-19 21:07:17 +09:00
podcast_podroll_repository_test.go feat(podcast): implement Podcasting 2.0 namespace support (Tier 1–3) 2026-09-19 21:07:17 +09:00
podcast_transcript_repository.go feat(podcast): implement Podcasting 2.0 namespace support (Tier 1–3) 2026-09-19 21:07:17 +09:00
podcast_transcript_repository_test.go feat(podcast): implement Podcasting 2.0 namespace support (Tier 1–3) 2026-09-19 21:07:17 +09:00
property_repository.go Replace beego/orm with dbx (#2693) 2023-12-09 13:52:17 -05:00
property_repository_test.go revert: separation of write and read DBs 2024-11-19 18:41:50 -05:00
radio_repository.go fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00
radio_repository_test.go fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00
scrobble_buffer_repository.go fix(plugins): discard buffered scrobbles when a plugin is removed (#5737) 2026-07-08 12:37:17 -04:00
scrobble_buffer_repository_test.go fix(plugins): discard buffered scrobbles when a plugin is removed (#5737) 2026-07-08 12:37:17 -04:00
scrobble_repository.go feat(server): add scrobble history Native API (#5761) 2026-07-13 11:32:03 -04:00
scrobble_repository_test.go feat(server): add scrobble history Native API (#5761) 2026-07-13 11:32:03 -04:00
share_repository.go fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00
share_repository_test.go Merge commit from fork 2026-09-12 13:38:08 -04:00
smart_playlist_repository.go fix(subsonic): update the playlist changed timestamp when renaming a smart playlist (#6082) 2026-09-03 16:07:53 -04:00
smart_playlist_repository_test.go fix(subsonic): update the playlist changed timestamp when renaming a smart playlist (#6082) 2026-09-03 16:07:53 -04:00
sort_index_coverage_test.go perf(db): index media_file album/artist sort orders (#5706) 2026-07-03 08:58:55 -04:00
sql_annotations.go feat(cli): add missing file list and remap subcommands (#5928) 2026-09-12 12:08:25 -04:00
sql_annotations_test.go feat(cli): add missing file list and remap subcommands (#5928) 2026-09-12 12:08:25 -04:00
sql_base_repository.go fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00
sql_base_repository_test.go fix(jellyfin): honor the Filters, SortBy and MaxHeight params clients actually send (#5981) 2026-08-19 08:36:44 -04:00
sql_bookmarks.go feat(cli): add missing file list and remap subcommands (#5928) 2026-09-12 12:08:25 -04:00
sql_bookmarks_test.go revert: separation of write and read DBs 2024-11-19 18:41:50 -05:00
sql_participations.go perf(persistence): use *_artists join tables for artist participant filters (#5930) 2026-08-10 11:42:27 -04:00
sql_restful.go fix(jellyfin): honor the Filters, SortBy and MaxHeight params clients actually send (#5981) 2026-08-19 08:36:44 -04:00
sql_restful_test.go feat(subsonic): sort search3 results by relevance (#5086) 2026-02-23 08:51:54 -05:00
sql_search.go perf(subsonic): speed up artist search3 deep-offset pagination (#5620) 2026-06-16 21:47:15 -04:00
sql_search_fts.go feat(search): rank exact matches above prefix matches (#5704) 2026-07-02 15:51:03 -04:00
sql_search_fts_test.go feat(search): rank exact matches above prefix matches (#5704) 2026-07-02 15:51:03 -04:00
sql_search_like.go chore: go fix 2026-05-28 22:13:05 -03:00
sql_search_like_test.go feat(subsonic): sort search3 results by relevance (#5086) 2026-02-23 08:51:54 -05:00
sql_search_test.go feat(subsonic): sort search3 results by relevance (#5086) 2026-02-23 08:51:54 -05:00
sql_tags.go perf(genre): index genre filtering via join tables across all APIs (#5940) 2026-08-11 08:00:50 -04:00
tag_library_filtering_test.go refactor: run Go modernize (#5002) 2026-02-08 09:57:30 -05:00
tag_repository.go feat(jellyfin): filter items by year and record label (#5817) 2026-07-19 12:39:31 -04:00
tag_repository_test.go refactor: run Go modernize (#5002) 2026-02-08 09:57:30 -05:00
transcoding_repository.go fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00
transcoding_repository_test.go fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00
user_props_repository.go Replace beego/orm with dbx (#2693) 2023-12-09 13:52:17 -05:00
user_repository.go fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00
user_repository_test.go fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00