feedfetcher/.
Reads a list of feeds and writes an HTML page of the five most recent entries from each one.
Directory Listing
total 100K
drwxr-xr-x 3 4.0K Oct 13 11:48 ./
drwxr-xr-x 6 4.0K Oct 13 11:48 ../
-rw-r--r-- 1 1.7K Oct 13 11:34 AGENTS.md
-rwxr-xr-x 1 28K Oct 13 11:34 feedfetcher.py
-rw-r--r-- 1 9.3K Oct 12 11:50 feeds.txt
-rw-r--r-- 1 21 Oct 13 11:34 .gitignore
-rw-r--r-- 1 248 Mar 4 2026 LICENSE
-rw-r--r-- 1 15K Oct 13 11:14 page.css
-rw-r--r-- 1 1.6K Oct 13 11:14 page.html
-rw-r--r-- 1 5.7K Oct 13 11:44 page.js
-rw-r--r-- 1 3.5K Oct 13 11:34 README.md
-rw-r--r-- 1 93 Sep 30 10:53 summary.md
Download
- Git clone URL:
https://obsolete.computer/static/code/feedfetcher/.git - Download Tarball (Built 2026-10-13): feedfetcher.tar.bz2
Readme
feedfetcher
Reads a list of feeds and writes an HTML page of the five most recent entries from each one.
Usage
bash ./feedfetcher.py ./feedfetcher.py --feeds feeds.txt --output feeds.html ./feedfetcher.py --items 8 --new-interval 3d --copy user@host:~/feeds/ ./feedfetcher.py --from-cache --openWith no arguments it reads
feeds.txtand writesfeeds.htmlto$XDG_CACHE_HOME/feedfetcher/, or~/.cache/feedfetcher/whenXDG_CACHE_HOMEis unset. The fetched-feed cache isfeeds-cache.jsonin that same directory.--from-cacherebuilds the page from the cache without fetching.--copycopies the written HTML file, and--openopens it in the default browser.
Option Default --feeds FILEfeeds.txtFeed list to read --output FILE$XDG_CACHE_HOME/feedfetcher/feeds.htmlHTML file to write. Without XDG_CACHE_HOME, this is~/.cache/feedfetcher/feeds.html--copy DESTn/a Also copy the written HTML here. A destination containing :is sent withscp, the same way rsync tells a remote path from a local one. A missing local directory is skipped.--no-copyWrite the HTML and do not copy it --items N5Entries to keep from each feed --new-interval DURATION7dMark entries newer than this as NEW. 7d,12h, or30m--cache FILE$XDG_CACHE_HOME/feedfetcher/feeds-cache.jsonJSON file of the fetched feeds. Without XDG_CACHE_HOME, this is~/.cache/feedfetcher/feeds-cache.json--from-cacheBuild the page from the cache without fetching --openOpen the generated HTML file in the default browser A feed that fails to refresh is rendered from its cached copy when one exists, and that copy stays in the cache.
Needs Python 3. No extra packages. Copying to a remote path needs
scp. The page shell, styles, and script arepage.html,page.css, andpage.jsnext to the script; they are read when the HTML file is written.Feed list
feeds.txtis one feed URL per line.```text
===Retro Tech===The 8-bit Guy
https://www.youtube.com/feeds/videos.xml?channel_id=UC8uT9cgJorJPWu7ITLGo9Ww
```
- A line wrapped in
===starts a category. It covers every feed until the next category line, and becomes a heading and a filter chip on the page.- Lines starting with
#are comments and are skipped.###Namenotes above a URL are comments too; the channel name shown on the page comes from the feed.- Blank lines are skipped.
- YouTube Shorts are left out. If a channel feed is mostly Shorts, the long-form uploads playlist is used so the page can still show five videos.
- A semicolon after the URL adds a title filter:
https://example.com/feed;interviewkeeps entries whose titles contain that text. Quote the filter to keep spaces, as in;"live in". A filter starting with!excludes matching titles instead. Filtered entries are skipped the same way Shorts are, so the page still shows five entries when the feed lists enough matches. A YouTube feed only lists its 15 most recent videos.The page
Entries from the last seven days are marked NEW. Entries published in the last 24 hours are marked TODAY and are included in the new filter. The search box matches entry titles and feed names. The category chips and the new and today buttons can be used alone or together, and a feed or category with nothing left to show is hidden. The header stays put while scrolling.
Recent Changes
- [f48f3c9] 2026-10-13: Remove scrolling placeholder altogether on mobile, as header size doesn't change there
- [6ad7797] 2026-10-13: Make the cache dir the default destination for the generated file.
- [d29855b] 2026-10-13: Move static assets to their own files; remofe references to 'rss' from input & output file defaults.
- [19e6e74] 2026-10-13: Actually let's keep my feeds in the repo as a sample
- [e0cc2f1] 2026-10-13: Fix transparent scroll placeholder box covering clicks
License
This project is in the public domain.
Contributing changes back to this codebase and giving attribution when reusing this code are both wonderful things, but neither are necessary.