Podcasts: neues Abo bringt nur die neueste Folge in die Inbox
Beim ersten Abruf eines Feeds (Abonnieren, OPML-Import, gpodder) kam der ganze Rückkatalog als „neu“ in die Inbox (bei Lage der Nation 200 Folgen). Jetzt zählt nur die neueste; die älteren sind ausgeblendet, nicht gehört, und stehen weiter in der Folgenliste des Podcasts. Auch automatisches Einreihen nimmt beim ersten Abruf nur diese eine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
176771a407
commit
a1e17081c5
2 changed files with 48 additions and 0 deletions
|
|
@ -111,6 +111,7 @@ class AutoQueueTests(TestCase):
|
|||
self.user = User.objects.create_user(username='alice', password='pw12345678')
|
||||
self.feed = PodcastFeed.objects.create(
|
||||
user=self.user, rss_url='https://example.org/feed', title='Feed', auto_queue=True,
|
||||
last_refreshed_at=datetime(2026, 1, 1, tzinfo=timezone.utc), # not the first fetch
|
||||
)
|
||||
other = PodcastFeed.objects.create(user=self.user, rss_url='https://example.org/o', title='O')
|
||||
self.old = [
|
||||
|
|
@ -148,6 +149,39 @@ class AutoQueueTests(TestCase):
|
|||
self.assertEqual(self.refresh(), ['o0', 'o1', 'o2'])
|
||||
|
||||
|
||||
class FirstFetchTests(TestCase):
|
||||
"""A new subscription doesn't flood the inbox with its back catalogue."""
|
||||
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(username='alice', password='pw12345678')
|
||||
self.client.force_login(self.user)
|
||||
self.rss = _rss([(f'e{i}', f'Mon, {i + 1:02d} Jan 2026 10:00:00 GMT') for i in range(5)])
|
||||
|
||||
def subscribe(self):
|
||||
with patch('podcasts.views._fetch_feed', lambda url: _parse(self.rss)):
|
||||
return self.client.post('/podcasts/feeds/add/', json.dumps({'rss_url': 'https://example.org/f'}),
|
||||
content_type='application/json')
|
||||
|
||||
def test_only_the_newest_is_new(self):
|
||||
self.assertEqual(self.subscribe().json()['new_episodes'], 5)
|
||||
inbox = self.client.get('/podcasts/inbox/').json()['episodes']
|
||||
self.assertEqual([e['title'] for e in inbox], ['e4'])
|
||||
# The others are still listed for the podcast, not marked played.
|
||||
feed = PodcastFeed.objects.get(user=self.user)
|
||||
eps = self.client.get(f'/podcasts/feeds/{feed.id}/episodes/').json()['episodes']
|
||||
self.assertEqual(len(eps), 5)
|
||||
self.assertFalse(any(e['played'] for e in eps))
|
||||
|
||||
def test_later_fetches_keep_every_new_episode(self):
|
||||
self.subscribe()
|
||||
feed = PodcastFeed.objects.get(user=self.user)
|
||||
self.rss = _rss([(f'e{i}', f'Mon, {i + 1:02d} Jan 2026 10:00:00 GMT') for i in range(8)])
|
||||
with patch('podcasts.views._fetch_feed', lambda url: _parse(self.rss)):
|
||||
_refresh_feed(feed)
|
||||
inbox = self.client.get('/podcasts/inbox/').json()['episodes']
|
||||
self.assertEqual([e['title'] for e in inbox], ['e7', 'e6', 'e5', 'e4'])
|
||||
|
||||
|
||||
class RefreshAllTests(TestCase):
|
||||
"""One request refreshes all feeds on the server; one request returns the state."""
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ from .models import EpisodeProgress, PodcastEpisode, PodcastFeed, PodcastQueue,
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
FEED_TIMEOUT = 20 # seconds per feed download
|
||||
NEW_ON_SUBSCRIBE = 1 # episodes of a new subscription that count as new
|
||||
FEED_WORKERS = 8 # feeds downloaded at the same time
|
||||
|
||||
|
||||
|
|
@ -167,6 +168,8 @@ def _refresh_feed(feed_obj, parsed=None):
|
|||
if parsed is None:
|
||||
parsed = _fetch_feed(feed_obj.rss_url)
|
||||
channel = parsed.feed
|
||||
# The first fetch of a new subscription brings the whole back catalogue.
|
||||
first_fetch = feed_obj.last_refreshed_at is None
|
||||
|
||||
feed_obj.title = channel.get('title', feed_obj.title or feed_obj.rss_url)[:300]
|
||||
feed_obj.description = channel.get('subtitle', channel.get('description', ''))[:2000]
|
||||
|
|
@ -245,6 +248,17 @@ def _refresh_feed(feed_obj, parsed=None):
|
|||
new_count += 1
|
||||
new_episodes_list.append(episode_obj)
|
||||
|
||||
if first_fetch and len(new_episodes_list) > NEW_ON_SUBSCRIBE:
|
||||
# Only the newest episodes count as new; the rest stay in the
|
||||
# podcast's episode list, out of the inbox (dismissed, not played).
|
||||
newest_first = sorted(new_episodes_list, key=lambda e: e.pub_date or e.discovered_at, reverse=True)
|
||||
older = newest_first[NEW_ON_SUBSCRIBE:]
|
||||
EpisodeProgress.objects.bulk_create(
|
||||
[EpisodeProgress(user=feed_obj.user, episode=e, dismissed=True) for e in older],
|
||||
ignore_conflicts=True,
|
||||
)
|
||||
new_episodes_list = newest_first[:NEW_ON_SUBSCRIBE]
|
||||
|
||||
if feed_obj.auto_queue and new_episodes_list:
|
||||
where = PodcastSettings.for_user(feed_obj.user).auto_queue_position
|
||||
# Newest first in front of what's there; oldest first when appended,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue