From dc340dd4e9209f55f1141d2c276c5ae15f1580a9 Mon Sep 17 00:00:00 2001 From: rays Date: Fri, 9 Oct 2026 01:49:54 +0000 Subject: [PATCH] Look a group's title up once, not once per feed in it (#159) subscriptions() names each feed derived from an OPML or a Patreon creator after its group when the group has no folder, and asked feed_summary, three queries, for the group's title once for every feed in it: the same title each time. Production's 32 Glass Cannon Network shows made that about 96 queries each time it ran, which is every feed list, every live update the page receives, every scan and every wait between scans. It now asks once a group per call. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + src/main.rs | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50a5392..59751c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- The feed list, and each live update of it, no longer asks the database for a group's title once for every feed in the group. - An episode that came as a torrent of several files plays its largest file, and can be deleted, by hand or to free space, instead of staying on disk for good. - Removing an account takes the feeds only that person read off the server, as unsubscribing does, instead of leaving them downloading every new episode for no one. - Freeing disk space counts only the people who subscribe to a feed: an episode is no longer taken as heard by everyone because someone who has since unsubscribed heard it, and their pins no longer keep files for good. diff --git a/src/main.rs b/src/main.rs index e8bc682..6647ccf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1294,6 +1294,9 @@ pub async fn subscriptions(ctx: &Ctx) -> Result> { .map(|(id, f)| Sub { id: id.clone(), cfg: f.clone(), managed: false }) .collect(); + // A group's title, once a group: asked for each feed in it, three queries a feed, it was about + // 96 for The Glass Cannon Network's 32 shows on every feed list, live update and scan (#159). + let mut group_titles = std::collections::HashMap::::new(); for m in ctx.db.managed_feeds().await? { if cfg.feeds.contains_key(&m.id) { continue; // promoted to config at some point; that entry wins @@ -1307,7 +1310,13 @@ pub async fn subscriptions(ctx: &Ctx) -> Result> { } let base = match parent.and_then(|p| p.folder.clone()) { Some(folder) => folder, - None => ctx.db.feed_summary(&m.group_id).await.ok().and_then(|s| s.title).unwrap_or_else(|| m.group_id.clone()), + None => { + if !group_titles.contains_key(&m.group_id) { + let title = ctx.db.feed_summary(&m.group_id).await.ok().and_then(|s| s.title); + group_titles.insert(m.group_id.clone(), title.unwrap_or_else(|| m.group_id.clone())); + } + group_titles[&m.group_id].clone() + } }; let title = m.title.clone().unwrap_or_else(|| m.id.clone()); out.push(Sub {