Podcasts: alle Folgen an einem Tag (Archiv, Kurs) zählen als selten, nicht als täglich
Some checks failed
Test / e2e (push) Waiting to run
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Has been cancelled

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mrwnslz 2026-10-19 17:29:39 +02:00
parent ba3c6ff905
commit 2cb5dc4c04
3 changed files with 15 additions and 5 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; kept an hour). Heard is a filter chip, not an order. age, at least 30 days, the same when all came on one day; 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

@ -810,6 +810,14 @@ class EpisodeListTests(TestCase):
self.assertAlmostEqual(feeds[self.fa.id]['interval_days'], (_at(1, 3) - _at(1, 1)).total_seconds() / 86400 / 2, places=1) self.assertAlmostEqual(feeds[self.fa.id]['interval_days'], (_at(1, 3) - _at(1, 1)).total_seconds() / 86400 / 2, places=1)
self.assertAlmostEqual(feeds[self.fb.id]['interval_days'], (_at(1, 5) - _at(1, 4)).total_seconds() / 86400, places=1) self.assertAlmostEqual(feeds[self.fb.id]['interval_days'], (_at(1, 5) - _at(1, 4)).total_seconds() / 86400, places=1)
def test_a_whole_archive_at_once_counts_as_seldom(self):
f = PodcastFeed.objects.create(user=self.user, rss_url='https://example.org/c', title='Archiv')
for k in range(5):
PodcastEpisode.objects.create(feed=f, guid=f'c{k}', title=f'C{k}', audio_url=f'https://example.org/c{k}.mp3',
pub_date=_at(1, 1) + timedelta(minutes=k))
feeds = {x['id']: x for x in self.client.get('/podcasts/state/').json()['feeds']}
self.assertGreater(feeds[f.id]['interval_days'], 30)
def test_all_newest_first_without_date_last(self): def test_all_newest_first_without_date_last(self):
data = self.get() data = self.get()
self.assertEqual([e['id'] for e in data['episodes']], self.assertEqual([e['id'] for e in data['episodes']],

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: its age, at least INTERVAL_SINGLE_DAYS. The lists INTERVAL_EPISODES. One episode only (or all on one day): 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}'
@ -835,10 +835,12 @@ def _intervals(user):
now = timezone.now() now = timezone.now()
out = {} out = {}
for feed_id, ds in dates.items(): for feed_id, ds in dates.items():
if len(ds) == 1: span = (max(ds) - min(ds)).total_seconds() / 86400
days = max((now - ds[0]).total_seconds() / 86400, INTERVAL_SINGLE_DAYS) if len(ds) == 1 or span < 1:
# One episode, or all of them at once (an archive, a course): no rhythm to go by.
days = max((now - max(ds)).total_seconds() / 86400, INTERVAL_SINGLE_DAYS)
else: else:
days = (max(ds) - min(ds)).total_seconds() / 86400 / (len(ds) - 1) days = span / (len(ds) - 1)
out[feed_id] = round(days, 2) out[feed_id] = round(days, 2)
cache.set(key, out, 3600) cache.set(key, out, 3600)
return out return out