generated from alex/base-template
feat: add RSS/Atom feed announcements with polite polling #14
No reviewers
Labels
No labels
dependencies
No milestone
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
alex/irc-greeter-bot!14
Loading…
Reference in a new issue
No description provided.
Delete branch "pi/issue13-1784892508497"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #13.
Summary
Adds optional RSS/Atom feed monitoring: the bot polls a configured list of feeds and announces new items into the joined IRC channels, configured entirely via env vars like the rest of the bot.
Library evaluation
Per the issue, I checked what Deno offers for RSS/Atom reading. There is no RSS/Atom reader in the Deno standard library, and
DOMParseris not available in Deno (the popular@b-fuze/deno-domdoesn't implementtext/xml). The mature options are npm packages (rss-parser,@extractus/feed-extractor) which pull in non-trivial transitive dependency trees.Given the project's deliberate minimalism (the Chatto client hand-speaks Connect JSON, storage is a plain JSON file, schedule is pure date math), I kept it dependency-free: a small, focused, fully unit-tested XML parser (
src/xml.ts) feeds a normalizer (src/feed.ts) that handles RSS 2.0, RSS 1.0/RDF, and Atom 1.0. A malformed feed is caught and retried on the next poll — it never crashes the bot.New modules
src/xml.tssrc/feed.tssrc/feed-store.tsETag/Last-Modified).Each has a matching
*_test.ts(78 new tests; 158 total, all green).Configuration (env vars)
All optional;
IRC_FEEDSunset = disabled:IRC_FEEDS— comma-separated feed URLs (validated ashttp(s)).IRC_FEED_INTERVAL_MIN— minimum interval in minutes (default 60, must be ≥ 5).IRC_FEED_CHECKPOINT_PATH— checkpoint file (defaultfeed-checkpoints.json).IRC_FEED_USER_AGENT— identifiable UA with a contact URL.IRC_FEED_MESSAGE— template, default📰 {feed}: {title} — {link}({title}/{link}/{feed}).IRC_FEED_MAX_ITEMS— items announced per feed per cycle, newest kept (default 3).Be polite to feed hosts
Politeness is treated as a first-class concern, following the RSS profiling best practices:
If-None-Match/If-Modified-Since; a304is skipped entirely.<ttl>, thesy:updatePeriodmodule, and HTTPCache-Control: max-age/Expiresall raise the interval. The configured interval is a floor; feed hints can only make the bot slower.429/503withRetry-Afteris honored.User-Agentwith a contact URL.Avoiding duplicates
Seen item ids plus
ETag/Last-Modifiedare persisted to JSON, so duplicates are suppressed across restarts. On the first-ever poll of a brand-new feed the current items are seeded as seen without announcing (no channel flood with the backlog). While the bot is disconnected from IRC, polling is paused entirely so it never marks items seen that it couldn't announce.Verified end-to-end against a local HTTP server: first fetch
200(parsed,ttl/Cache-Controlextracted), second fetch with the storedETag→304 Not Modified, and the effective delay correctly resolved tomax(configured, ttl, max-age).CI
deno fmt --check,deno lint,deno check,deno test(158 passed),fallow dead-code --fail-on-issues(no issues), anddeno compileall pass./pi rebase on master, solve merge conflicts
2ef4d3cdf5c419fb059dI'll start by examining the current state of the PR branch and the repository.Let me check out the PR branch and see what conflicts exist.The PR branch is based on
f9f3c73, but master has one new commit81d0a9b(announce module). Let me rebase onto master.Two files have conflicts:README.mdandsrc/main.ts. Let me examine both.OnlyREADME.mdhas an unresolved conflict;src/main.tsauto-merged. Let me examine both to make sure the auto-merge is correct and resolve the README conflict.Two conflict regions in README.md: both are additions that should be combined. Let me resolve them.Now let me verify no conflict markers remain, and inspect the auto-mergedsrc/main.tsto ensure correctness.There's still an orphaned conflict marker at line 171. Let me look at that region.All conflict markers resolved. The auto-mergedsrc/main.tscorrectly combines both the announce module (from master) and the feed poller (from the PR). Let me stage the README and continue the rebase.Rebase complete. Now let me verify everything works: format, lint, type check, and tests.The test failures are purely permission-related (missing--allow-writefor temp dirs), not actual test failures. Let me run via the task definition which includes the correct permissions.All 165 tests pass. Let me also run the fallow dead-code check and compile, as those are part of CI.All checks pass. Let me verify the final state of the rebase — the branch should now sit cleanly on top of master with the announce commit as its parent.The rebase is clean — the branch now sits directly on top ofmaster(parent81d0a9b) with a single commit. All CI checks pass (fmt, lint, check, 165 tests, fallow, compile). Now let me force-push the rebased branch to update the PR.Rebase complete and pushed. Here's what happened:Conflict in
README.md— the new master commit81d0a9b(announce module) and the PR's feed commit both touched two spots:announce.tsand the PR addedfeed.ts/feed-store.ts/xml.ts. All four entries are now present in a sensible order.src/main.tsauto-merged cleanly — it correctly wires up both the announce module (master) and the feed poller (PR).The branch now sits directly on top of
master(parent81d0a9b) with a single commit. Verified all CI-equivalent checks pass locally before pushing:deno fmt --check✓deno lint✓deno check src/main.ts✓deno task test→ 165 passed, 0 failed ✓deno task fallow→ no issues ✓deno task compile✓Force-pushed (
--force-with-lease) topi/issue13-1784892508497; the PR is now rebased onto master with no conflicts.View action run | Model: zai/glm-5.2 (thinking: max) | Time: 3m 43s | Tokens: 367.4K | Pi SDK v0.81.1 | Action v2.26.0-develop (develop @ 4387e26)