index

Article posted on: 2021-11-01 19:13
Last edited on: 2021-11-01 19:13
Written by: Sylvain Gauthier

Minimal tips 3: sneed: feeds and sfeed (formerly newsboat)

Recently (like a few months ago), I had the unpleasant surprise to see that newsboat, my okay-ish terminal based feed reader, had been rewritten in Rust. Of course, because of the abomination that is cargo, this also meant that the build was broken on Gentoo, so I decided to switch to the excellent sfeed, a minimal, modular RSS/atom parser.

After a bit of experimenting, I settled with a pretty good, minimal system that I think is worth presenting here, since it uses our homemade menu selector choice.

sfeed is made of different little C programs that are meant to work together, to separate fetching, parsing and delivery.

Fetching feeds and parsing them into the TAB-separated format is done with sfeed_update, which will source ~/.sfeed/sfeedrc to get the feeds, man sfeed_update for more details. It will create one TAB-separated feed file per feed, located in ~/.sfeed/feeds.

You can then use the different delivery / parsing programs included in sfeed to parse those feed files and do what you want with the result.

In my system, I use sfeed_plain, which, as the name implies, output the feeds' timestamp, name, title and URL, in a nice fancy column format. It crops the articles' titles to 70 characters. Here is what a typical output looks like:

$ sfeed_plain ~/.sfeed/feeds/codemadness
  2021-10-23 11:00  codemadness      Setup an OpenBSD RISCV-64 VM in QEMU                                   https://www.codemadness.org/openbsd-riscv64-vm.html
  2021-10-23 11:00  codemadness      Setup an OpenBSD RISCV64 VM in QEMU                                    https://www.codemadness.org/openbsd-riscv64-vm.html
  2020-06-25 10:00  codemadness      Sfeed_curses: a curses UI front-end for sfeed                          https://www.codemadness.org/sfeed_curses-ui.html
  2019-11-10 11:00  codemadness      hurl: HTTP, HTTPS and Gopher file grabber                              https://www.codemadness.org/hurl.html
  2019-10-13 11:00  codemadness      json2tsv: a JSON to TSV converter                                      https://www.codemadness.org/json2tsv.html
  2019-04-24 10:00  codemadness      OpenBSD: setup a local auto-installation server                        https://www.codemadness.org/openbsd-autoinstall.html
  2019-02-10 11:00  codemadness      Idiotbox: Youtube interface                                            https://www.codemadness.org/idiotbox.html
  2018-08-17 10:00  codemadness      Gopher HTTP proxy                                                      https://www.codemadness.org/gopher-proxy.html
  2018-03-10 11:00  codemadness      Setup your own file paste service                                      https://www.codemadness.org/paste-service.html
  2018-02-25 11:00  codemadness      Setup your own git hosting service                                     https://www.codemadness.org/setup-git-hosting.html
  2017-12-11 11:00  codemadness      Setup an OpenBSD SPARC64 VM in QEMU                                    https://www.codemadness.org/openbsd-sparc64-vm.html
  2017-09-24 10:00  codemadness      jsdatatable: a small datatable Javascript                              https://www.codemadness.org/datatable.html
  2017-09-24 10:00  codemadness      Tscrape: a Twitter scraper                                             https://www.codemadness.org/tscrape.html
  2017-08-04 10:00  codemadness      Stagit-gopher: a static git page generator for gopher                  https://www.codemadness.org/stagit-gopher.html
  2017-06-10 10:00  codemadness      Saait: a boring HTML page generator                                    https://www.codemadness.org/saait.html
  2017-05-10 10:00  codemadness      Stagit: a static git page generator                                    https://www.codemadness.org/stagit.html
  2015-07-05 10:00  codemadness      OpenBSD httpd, slowcgi and cgit                                        https://www.codemadness.org/openbsd-httpd-and-cgit.html
  2014-11-23 11:00  codemadness      twitch: application to watch Twitch streams                            https://www.codemadness.org/twitch-interface.html
  2014-03-02 11:00  codemadness      Userscript: focus input field                                          https://www.codemadness.org/userscript-focus-input-field.html
  2013-02-21 11:00  codemadness      Userscript: Youtube circumvent age verification                        https://www.codemadness.org/userscript-youtube-circumvent-age-verification.html
  2012-10-21 11:00  codemadness      Userscript: block stupid fonts                                         https://www.codemadness.org/userscript-block-stupid-fonts.html
  2011-04-01 11:00  codemadness      Sfeed: simple RSS and Atom parser                                      https://www.codemadness.org/sfeed-simple-feed-parser.html
  2011-01-07 11:00  codemadness      Vim theme: relaxed                                                     https://www.codemadness.org/vim-theme-relaxed.html
  2010-10-31 11:00  codemadness      GTK2 theme: gtk-murrine-rape                                           https://www.codemadness.org/gtk2-theme-gtk-murrine-rape.html
  2010-10-31 11:00  codemadness      Seturgent: set urgency hints for X applications                        https://www.codemadness.org/seturgent-set-urgency-hints-for-x-applications.html
  2010-08-12 10:00  codemadness      DWM-hiltjo: my windowmanager configuration                             https://www.codemadness.org/dwm-hiltjo-my-windowmanager-configuration.html
  2010-04-21 10:00  codemadness      Query unused CSS rules on current document state                       https://www.codemadness.org/query-unused-css-rules-on-current-document-state.html
  2009-07-05 10:00  codemadness      Driconf: enabling S3 texture compression on Linux                      https://www.codemadness.org/driconf-enabling-s3-texture-compression-on-linux.html
  2009-04-13 10:00  codemadness      Getting the USB-powerline bridge to work on Linux                      https://www.codemadness.org/getting-the-usb-powerline-bridge-to-work-on-linux.html
  2009-04-12 10:00  codemadness      Gothic 1 game guide                                                    https://www.codemadness.org/gothic-1-guide.html

I think the “intended” use, at least from glancing over the examples, is to then feed that to a selector like dmenu. My system is not much different, except I use choice for this purpose. It has the advantage of being purely terminal-based, very (VERY) fast at filtering/searching entries and I am familiar enough with the code to add features myself.

First, I reformat things a little bit to make it work optimally on choice. choice hides the first space-delimited field of each line (the “key”) to show only values, but once a value is selected, it outputs the “key”. In that use case, the key is of course the article URL, and the value is the timestamp and description. To do the trick:

sfeed_plain $feed | sed 's/\(.*\) \([^ ]*\)$/\2 \1/g'

Which outputs:

https://www.codemadness.org/openbsd-riscv64-vm.html   2021-10-23 11:00  codemadness      Setup an OpenBSD RISCV-64 VM in QEMU
https://www.codemadness.org/openbsd-riscv64-vm.html   2021-10-23 11:00  codemadness      Setup an OpenBSD RISCV64 VM in QEMU
https://www.codemadness.org/sfeed_curses-ui.html   2020-06-25 10:00  codemadness      Sfeed_curses: a curses UI front-end for sfeed
https://www.codemadness.org/hurl.html   2019-11-10 11:00  codemadness      hurl: HTTP, HTTPS and Gopher file grabber
https://www.codemadness.org/json2tsv.html   2019-10-13 11:00  codemadness      json2tsv: a JSON to TSV converter
https://www.codemadness.org/openbsd-autoinstall.html   2019-04-24 10:00  codemadness      OpenBSD: setup a local auto-installation server
https://www.codemadness.org/idiotbox.html   2019-02-10 11:00  codemadness      Idiotbox: Youtube interface
https://www.codemadness.org/gopher-proxy.html   2018-08-17 10:00  codemadness      Gopher HTTP proxy
https://www.codemadness.org/paste-service.html   2018-03-10 11:00  codemadness      Setup your own file paste service
https://www.codemadness.org/setup-git-hosting.html   2018-02-25 11:00  codemadness      Setup your own git hosting service
https://www.codemadness.org/openbsd-sparc64-vm.html   2017-12-11 11:00  codemadness      Setup an OpenBSD SPARC64 VM in QEMU
https://www.codemadness.org/datatable.html   2017-09-24 10:00  codemadness      jsdatatable: a small datatable Javascript
https://www.codemadness.org/tscrape.html   2017-09-24 10:00  codemadness      Tscrape: a Twitter scraper
https://www.codemadness.org/stagit-gopher.html   2017-08-04 10:00  codemadness      Stagit-gopher: a static git page generator for gopher
https://www.codemadness.org/saait.html   2017-06-10 10:00  codemadness      Saait: a boring HTML page generator
https://www.codemadness.org/stagit.html   2017-05-10 10:00  codemadness      Stagit: a static git page generator
https://www.codemadness.org/openbsd-httpd-and-cgit.html   2015-07-05 10:00  codemadness      OpenBSD httpd, slowcgi and cgit
https://www.codemadness.org/twitch-interface.html   2014-11-23 11:00  codemadness      twitch: application to watch Twitch streams
https://www.codemadness.org/userscript-focus-input-field.html   2014-03-02 11:00  codemadness      Userscript: focus input field
https://www.codemadness.org/userscript-youtube-circumvent-age-verification.html   2013-02-21 11:00  codemadness      Userscript: Youtube circumvent age verification
https://www.codemadness.org/userscript-block-stupid-fonts.html   2012-10-21 11:00  codemadness      Userscript: block stupid fonts
https://www.codemadness.org/sfeed-simple-feed-parser.html   2011-04-01 11:00  codemadness      Sfeed: simple RSS and Atom parser
https://www.codemadness.org/vim-theme-relaxed.html   2011-01-07 11:00  codemadness      Vim theme: relaxed
https://www.codemadness.org/gtk2-theme-gtk-murrine-rape.html   2010-10-31 11:00  codemadness      GTK2 theme: gtk-murrine-rape
https://www.codemadness.org/seturgent-set-urgency-hints-for-x-applications.html   2010-10-31 11:00  codemadness      Seturgent: set urgency hints for X applications
https://www.codemadness.org/dwm-hiltjo-my-windowmanager-configuration.html   2010-08-12 10:00  codemadness      DWM-hiltjo: my windowmanager configuration
https://www.codemadness.org/query-unused-css-rules-on-current-document-state.html   2010-04-21 10:00  codemadness      Query unused CSS rules on current document state
https://www.codemadness.org/driconf-enabling-s3-texture-compression-on-linux.html   2009-07-05 10:00  codemadness      Driconf: enabling S3 texture compression on Linux
https://www.codemadness.org/getting-the-usb-powerline-bridge-to-work-on-linux.html   2009-04-13 10:00  codemadness      Getting the USB-powerline bridge to work on Linux
https://www.codemadness.org/gothic-1-guide.html   2009-04-12 10:00  codemadness      Gothic 1 game guide

Looks ugly, but then, when fed into choice, things become much more aesthetic.

choice

That’s the core idea. A bit of bash sweetener on top of it to make it more usable, and here is the final script, which I named sneed for the chuckle:

#!/bin/bash

BROWSER=elinks

feed="$(find "$HOME/.sfeed/feeds/$1" -type f)"
test -n "$feed" || exit 1

while true ; do
    url="$(sfeed_plain $feed | sed 's/\(.*\) \([^ ]*\)$/\2 \1/g' | choice)"
    test -n "$url" || exit 0
    $BROWSER "$url"
done

I also patched sfeed_plain to not crop articles' description at 70 character. This “feature” seems very arbitrary to me and doesn’t make much sense. It should be left to the reader to crop things if needed.

diff --git a/sfeed_plain.c b/sfeed_plain.c
index 1b11a71..773bf66 100644
--- a/sfeed_plain.c
+++ b/sfeed_plain.c
@@ -43,7 +43,7 @@ printfeed(FILE *fp, const char *feedname)
                        printutf8pad(stdout, feedname, 15, ' ');
                        fputs("  ", stdout);
                }
-               printutf8pad(stdout, fields[FieldTitle], 70, ' ');
+               printf("%s", fields[FieldTitle]);
                printf(" %s\n", fields[FieldLink]);
        }
 }

Here is the final result in action:

sneed

Typing sneed <feed_name> will restrict the display to only that particular feed. Typing sneed alone will open/concatenate all feeds, sorted first by name then by date. choice allows for lightning-fast search through all feeds. Since the date is part of the searchable value, you can easily filter by date, get only entries for the month, etc. The selected entry is opened using $BROWSER.

There is no notion of “opened” feed. sfeed_plain displays a N flag for entries less than one day old, that’s it. While it seems like a limitation, it’s actually not that big of a deal. I have been using this for the past two months without caring too much for it. It still suits my needs better than any other bloated solutions out there.