Podcasts: „auf einmal“ heißt innerhalb einer Stunde – stündliche Nachrichten bleiben häufig
Some checks failed
Build and push Docker image / build (push) Successful in 16s
Test / test (push) Successful in 9m23s
Test / e2e (push) Failing after 1m21s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mrwnslz 2026-10-19 17:30:38 +02:00
parent 2cb5dc4c04
commit f539158a19
3 changed files with 12 additions and 4 deletions

View file

@ -40,7 +40,7 @@ Diese Woche (the last 7 days), Diesen Monat (30 days), then the months — after
Kino feed. In „Folgen“ (sort „Nach Zeitraum, seltene zuerst“, the default) and „Neu“ Kino feed. In „Folgen“ (sort „Nach Zeitraum, seltene zuerst“, the default) and „Neu“
the podcasts that seldom come go first within a group: `interval_days` of each feed the podcasts that seldom come go first within a group: `interval_days` of each feed
in `/podcasts/state/`, the mean gap between its newest 10 episodes (one episode: its in `/podcasts/state/`, the mean gap between its newest 10 episodes (one episode: its
age, at least 30 days, the same when all came on one day; kept an hour). Heard is a filter chip, not an order. age, at least 30 days, the same when all came within an hour; kept an hour). Heard is a filter chip, not an order.
### Shared code: `static/js/folders.js` (diora-web, every platform) ### Shared code: `static/js/folders.js` (diora-web, every platform)

View file

@ -817,6 +817,13 @@ class EpisodeListTests(TestCase):
pub_date=_at(1, 1) + timedelta(minutes=k)) pub_date=_at(1, 1) + timedelta(minutes=k))
feeds = {x['id']: x for x in self.client.get('/podcasts/state/').json()['feeds']} feeds = {x['id']: x for x in self.client.get('/podcasts/state/').json()['feeds']}
self.assertGreater(feeds[f.id]['interval_days'], 30) self.assertGreater(feeds[f.id]['interval_days'], 30)
hourly = PodcastFeed.objects.create(user=self.user, rss_url='https://example.org/h', title='Stündlich')
for k in range(10):
PodcastEpisode.objects.create(feed=hourly, guid=f'h{k}', title=f'H{k}', audio_url=f'https://example.org/h{k}.mp3',
pub_date=_at(1, 1) + timedelta(hours=k))
cache.clear()
feeds = {x['id']: x for x in self.client.get('/podcasts/state/').json()['feeds']}
self.assertAlmostEqual(feeds[hourly.id]['interval_days'], 1 / 24, places=2)
def test_all_newest_first_without_date_last(self): def test_all_newest_first_without_date_last(self):
data = self.get() data = self.get()

View file

@ -816,7 +816,7 @@ INTERVAL_SINGLE_DAYS = 30
def _intervals(user): def _intervals(user):
"""How often each feed brings an episode, in days: the mean gap between its newest """How often each feed brings an episode, in days: the mean gap between its newest
INTERVAL_EPISODES. One episode only (or all on one day): its age, at least INTERVAL_SINGLE_DAYS. The lists INTERVAL_EPISODES. One episode only (or all within an hour): its age, at least INTERVAL_SINGLE_DAYS. The lists
put the seldom ones first within a day or week (after Kino's feed; feeds.js does the put the seldom ones first within a day or week (after Kino's feed; feeds.js does the
same for blogs). One query (the newest episodes per feed by a window), kept an hour.""" same for blogs). One query (the newest episodes per feed by a window), kept an hour."""
key = f'podcasts:intervals:{user.id}' key = f'podcasts:intervals:{user.id}'
@ -836,8 +836,9 @@ def _intervals(user):
out = {} out = {}
for feed_id, ds in dates.items(): for feed_id, ds in dates.items():
span = (max(ds) - min(ds)).total_seconds() / 86400 span = (max(ds) - min(ds)).total_seconds() / 86400
if len(ds) == 1 or span < 1: if len(ds) == 1 or span < 1 / 24:
# One episode, or all of them at once (an archive, a course): no rhythm to go by. # One episode, or all within an hour (an archive, a course put up at once): no rhythm
# to go by. Hourly news still has one.
days = max((now - max(ds)).total_seconds() / 86400, INTERVAL_SINGLE_DAYS) days = max((now - max(ds)).total_seconds() / 86400, INTERVAL_SINGLE_DAYS)
else: else:
days = span / (len(ds) - 1) days = span / (len(ds) - 1)