rss tool

bd88407 better readme

2 years ago

22ec97a better formatting

2 years ago


feef isn't a feed reader, it's a feed tool. It can be used in scripts, or as a basis for a feed reader

feef uses Go templates for output formatting and expr for filtering. This makes feef quite easy to use but very flexible. It errs on the "do it all in 1 command" side, for better or for worse

feef is not yet stable. Your mileage may vary as RSS can be very different across the web. If you find a bug or think a feature would go well with feef, create a GitHub issue or a Sourcehut ticket


# Open a random item
feef -f '{{.Link}}' | shuf -n1 | xargs $BROWSER
# Print the links of the 10 newest items (newest to oldest)
feef -f '{{.Link}}' -s -m 10
# Show me the links of items with titles containing Genode on Lobsters
feef -f '{{.Link}}' -u '~lobsters' -i 'Title contains "Genode"'
# Notify me of new items with notify-send
feef -n new -c "notify-send '{{.Feed.Title}}' '{{.Title}}'" -f ''
# Download the 10 newest items of the Lingthusiasm podcast
feef -s -m 10 -c "wget -nc -O '{{slug .Title}}.mp3' '{{(index .Enclosures 0).URL}}' || echo {{.Title}} already downloaded" -u 'https://feeds.soundcloud.com/users/soundcloud:users:237055046/sounds.rss'

Additionaly, the feef-read script in this repository is a fzf-based feed reader.


  • I needed a tool for downloading podcast episodes, and I'm not happy grepping raw XML or manually copy-pasting links
  • I want to be notified of new items automatically rather than polling newsboat
  • I found read/unread to be clutter, since I don't want to read every new item. feef doesn't track whether you read an item or not.


go get -u -v git.sr.ht/~skuzzymiglet/feef

Or download a binary from releases to somewhere in your $PATH

Put file with the URLs you want to read, one per line, in .config/feef/urls or wherever you put your configs. Alternatively, specify a URLs file with the -U flag.

Note you don't need a URLs file if you provide an exact URL to query


Running feef with no options will print the GUID of every item of every feed in your URLs file.


Usage of feef:
      --cpu-profile                 record CPU profile
  -p, --download-threads int        maximum number of concurrent downloads (default 4)
  -c, --exec string                 execute command template for each item
  -e, --exit-on-failed-command      exit if a command (-c) fails
  -h, --help                        print help and exit
  -i, --item-matcher string         expression to match feed items (default "true")
  -l, --loglevel string             log level (default "info")
  -m, --max int                     maximum items to output, 0 for no limit
      --memory-profile              record memory profile
  -n, --notify-mode string          notification mode (none, new or all) (default "none")
  -r, --notify-poll-time duration   time between feed refreshes in notification mode (default 2m0s)
  -s, --sort                        sort feed items chronologically, newest to oldest
  -f, --template string             output template for each feed item (default "{{.GUID}}")
  -t, --timeout duration            feed-fetching timeout (default 5s)
  -U, --url-file string             file with newline delimited URLs (default "/home/skuzzymiglet/.config/feef/urls")
  -u, --url-spec strings            List of URLs or URL patterns to match against the URLs file (prefixes: / for regexp, ~ for fuzzy match, ? for glob) (default [~])

#URL matching

Use -u to specify an URL. You can use exact URL, or prefix with these symbols:

  • ~: fuzzy match
  • /: regex (Go regexp) match
  • ?: glob match

~ and / alone can be used to match every URL

Default: ~


feef uses Go templates to format the output

Templates specified with -f are printed to the standard output, with newlines between them. Templates specified with -c are evaluated then passed as commands to the shell

To find out what fields you can use, see gofeed.Item. Additionaly, you can use .Feed to access the parent gofeed.Feed. You can see all the values in an item with the template {{.}}

Some useful template functions are provided:

  • datef: format dates
  • slug: transform a string into a path/URL friendly format
  • trunc: truncate a string to a length
  • truncPad: truncate or pad a string to a length
  • sanitizeHTML: sanitize HTML (strictest policy)

Refer to defaultFuncMap for definitions

Default: {{.GUID}} (the GUID of the item)


Filtering is done with expr expressions. The same data is provided to expressions as to templates. Expressions must return a boolean.

Default: true


feef can notify you of new items. Specify a notification mode with -n. There are 3 modes:

  • new: print new items
  • all: print all items, then new items as they come
  • none: print all items and exit

You can use -r to control the interval for polling feeds for changes. By default this is 2 minutes

Default: none

#other options

  • -s sorts items chronologically. All items need to be accumulated, which makes this seem slow
  • -e exit when commands (-c) fail
  • -E exit when there's an error fetching a feed (TODO)
  • -m n stops feef after n numbers have passed through the filter
  • -p n allows up to n threads to be fetching at the same time
  • -l controls the log level. This can be one of panic, fatal, error, warn, info, debug or trace, case-insensitive. See the loglevel-parsing code
  • --cpu-profile and --memory-profile run CPU and memory profiles respectively. The location of the profiles is printed to stderr at the end



The feef-read script is a simple but flexible RSS reader, with notifications of new items. The items are formatted and piped into fzf. You can fuzzy-search the items.

feef-read binds these keys:

  • enter: open the selected item's Link with xdg-open or the $OPENER environment variable
  • tab: toggles the sort order between best match and chronological
  • ctrl-d: downloads the item's Link using wget or the $DOWNLOADER environment variable

feef-read also notifies you of new items using notify-send


Bugs and TODOs are noted in comments near the relevant code. A quick rg TODO should work. Major ones are listed here:

  • Logging and loglevel separation need work
  • A way to work feed-wise is needed. Currently you can't retrieve info about a feed
  • Libify the logic
  • Provide more information to filters