feat(feed): periodic background refresh with failed-fetch guard

Self-rescheduling refresh timer (default 30 min, configurable via a
Preferences item, re-read on every tick, skips in-flight refreshes).
fetchEpisodes returns null on network failure/timeout so a failed
refresh can never wipe a feed's episodes (addFeed/refreshFeed/
refreshAllFeeds all treat null as unchanged); feeds still refresh on
launch.
This commit is contained in:
2026-08-11 13:11:20 -04:00
parent df9c519439
commit 2d7d49b91c
6 changed files with 107 additions and 6 deletions

View File

@@ -219,6 +219,32 @@ export function usePreferencesItems(): SettingItem[] {
app.updatePreferences({ fetchMoreMode: next });
},
},
{
id: "refreshInterval",
label: "Feed Refresh Interval",
kind: "number",
display: () => `${prefs().refreshIntervalMinutes} min`,
help: () =>
`How often subscribed feeds are re-fetched in the background, so new episodes appear without a restart or manual refresh (r).\nType: number (1120 minutes)\nDefault: 30\nCurrent: ${prefs().refreshIntervalMinutes} min\nj/k to /+5 · Enter to type a value.`,
cycle: (dir) => {
const next = Math.min(
120,
Math.max(1, prefs().refreshIntervalMinutes + dir * 5),
);
app.updatePreferences({ refreshIntervalMinutes: next });
},
renderEditor: () => (
<NumberInputEditor
label="Feed Refresh Interval (minutes)"
value={() => prefs().refreshIntervalMinutes}
commit={(n) => {
app.updatePreferences({
refreshIntervalMinutes: Math.min(120, n),
});
}}
/>
),
},
];
// Whitelist management only appears while scope is set to "whitelist".