Skip to content

Re-key episodes whose GUID the host changed instead of duplicating them - #118

Merged
Niall-Faughnan merged 1 commit into
developfrom
claude/big-tech-show-recency-bug-vugfmb
Oct 28, 2026
Merged

Niall-Faughnan merged 1 commit into
developfrom
claude/big-tech-show-recency-bug-vugfmb

Conversation

@Niall-Faughnan

Copy link
Copy Markdown
Collaborator

Problem

Home's New section filled with 190 Blocked and Reported episodes, some from as far back as December 2021.

Substack rewrote the GUIDs of 178 of the 522 episodes in that show's feed: substack:post:N → substack:post:N:unlocked. Refreshes match stored episodes by (podcastId, guid), so every rewritten episode was inserted a second time with addedAt = now. They showed up as New and as duplicates on the podcast page. The same thing had happened with another podcast before.

Change

This is adapted from AntennaPod's FeedDatabaseWriter + FeedItemDuplicateGuesser.

New EpisodeDao.repairChangedGuids(podcastId, feedItems) (@Transaction) runs before each refresh matches by GUID:

  • Fast path: when every stored GUID is still in the feed, it returns after one SELECT guid query.
  • Matching: otherwise it pairs stored episodes whose GUID is gone from the feed with feed items that seemsSameEpisodeAs them. AntennaPod's rules: the same audio URL, or the same normalized title on the same day with lengths within 10 minutes of each other.
  • Re-key: the stored row takes the new GUID and keeps its play state, download and addedAt. The refresh then updates that row instead of inserting a copy.
  • Repair: if an earlier refresh already inserted a copy under the new GUID, the copy's play state, download and listening sessions move to the original and the copy is deleted. This cleans up the existing Blocked and Reported duplicates on the next refresh. It's skipped when both copies are downloaded, so no file is orphaned.
  • Safeguard: episodes still in the feed under their own GUID are never matched, so two real episodes that share a title are left alone.
  • Matching cost: it loads a lightweight projection (EpisodeMatchRow), not full rows with descriptions.

It's called from FeedRefreshWorker, refresh-all in AppViewModel, PodcastDetailViewModel.refreshFeed, and re-subscribing to a known show (AppViewModel, DiscoverViewModel).

Tests: five Robolectric EpisodeDaoTest cases on a real database:

  • re-keying by audio URL;
  • re-keying by title, day and length when the URL also changed;
  • folding an already-inserted copy into the original (including its listening session);
  • no match while both GUIDs are in the feed;
  • no match for an unrelated dropped episode.

Version 1.6.74 (122) → 1.6.75 (123), with a What's New entry.

Testing

Local compilation could not be run: Gradle can't resolve dependencies in the agent environment. The CI build check (all unit tests plus assembleDebug) is the compile check for this PR.


Generated by Claude Code

Blocked and Reported's Substack feed rewrote the GUIDs of 178 back-catalogue
episodes (substack:post:N -> substack:post:N:unlocked). Refreshes match by
GUID, so every one was inserted a second time with addedAt = now and Home's
New section filled with episodes from as far back as 2021.

Adapted from AntennaPod's FeedDatabaseWriter + FeedItemDuplicateGuesser:
before each refresh matches by GUID, EpisodeDao.repairChangedGuids pairs
stored episodes whose GUID is gone from the feed with feed items that look
like the same episode (same audio URL, or same title on the same day within
10 minutes' length). The stored row takes the new GUID, keeping its play
state, download and addedAt, so the refresh updates it instead of inserting
a copy. Copies an earlier refresh already inserted are folded into the
original (play state, download and listening sessions move over) and
deleted. Episodes still in the feed under their own GUID are never matched.

Wired into the background worker, refresh-all, the podcast page refresh and
re-subscribing to a known show.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01RK5hqcE13d42xpsT576dRw
@Niall-Faughnan
Niall-Faughnan merged commit 7db5c51 into develop Oct 28, 2026
4 checks passed
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