Skip to content

Fix podcast episode sync: per-show UUID uniqueness and episode creati… - #180

Merged
dannyvfilms merged 1 commit into
dannyvfilms:latestfrom
nakenyon:fix/podcast-episode-sync
May 3, 2026
Merged

Fix podcast episode sync: per-show UUID uniqueness and episode creati…#180
dannyvfilms merged 1 commit into
dannyvfilms:latestfrom
nakenyon:fix/podcast-episode-sync

Conversation

@nakenyon

Copy link
Copy Markdown

Summary

  • Root cause: PodcastEpisode.episode_uuid had a global unique=True constraint, but RSS GUIDs are only unique within a single feed. When any two shows shared a GUID, IntegrityError silently aborted all remaining episode creation for the second show. Combined with max_length=36, this also broke entirely on PostgreSQL (URL-format GUIDs are typically 50–200 chars).
  • Cross-show lookup bug: RSS sync paths used PodcastEpisode.objects.get(episode_uuid=...) globally — if the GUID existed in any show, the episode was skipped for the current show.
  • No per-episode error isolation: One failed episode create aborted all remaining episodes for the entire show.

Changes

  • PodcastEpisode.episode_uuid: global unique=True (max_length=36) → unique_together = [("show", "episode_uuid")] (max_length=500)
  • Migration 0116_podcastepisode_uuid_fix implementing the above
  • Removed cross-show objects.get() lookups in views.py RSS sync paths
  • Added per-episode try/except in all episode creation loops (views.py, events/tasks.py, integrations/imports/pocketcasts.py)
  • Improved exception log level: debugwarning for RSS sync failures on show detail page
  • Bundled decorator_include module (replaces django-decorator-include package dependency)
  • Synced Item model with upstream fields: manual_metadata, provider_metadata_status
  • PodcastEpisode.audio_url max_length synced with upstream (200 → 500)

Test plan

  • Add a new podcast show via iTunes search — verify full episode list appears immediately
  • Add two podcast shows that might share GUIDs (same hosting platform) — verify both get their full episode list
  • Wait for or manually trigger the daily reload_calendar task — verify new episodes are added for existing shows
  • Visit a show detail page — verify new episodes are fetched inline without 500 errors
  • Run python manage.py migrate — verify 0116 applies cleanly

🤖 Generated with Claude Code

##Fixes
Issue #179

…on reliability

RSS GUIDs are only unique within a single feed, not globally. The previous
global unique constraint on PodcastEpisode.episode_uuid caused IntegrityError
when two shows shared any GUID, silently aborting all remaining episode creation
for the second show. max_length=36 also blocked URL-format GUIDs on PostgreSQL.

- Change episode_uuid from globally unique (max_length=36) to unique per show
  via unique_together, and increase max_length to 500 to accommodate URL GUIDs
- Remove cross-show PodcastEpisode.objects.get() lookups in RSS sync paths that
  prevented episode creation when a GUID existed in any other show
- Add per-episode try/except in all episode creation loops so one collision does
  not abort the entire sync for a show
- Improve exception logging from debug to warning for RSS sync failures on the
  show detail page
- Bundle decorator_include module to replace django-decorator-include dependency
- Sync Item model with upstream fields: manual_metadata, provider_metadata_status
- Sync PodcastEpisode.audio_url max_length with upstream (200 -> 500)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dannyvfilms
dannyvfilms merged commit 6039ef8 into dannyvfilms:latest May 3, 2026
1 of 2 checks passed
@nakenyon
nakenyon deleted the fix/podcast-episode-sync branch May 4, 2026 22:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants