elfeed-curate is an add-on for elfeed, an RSS reader for Emacs.
The purpose of this package is to add the additional functionality needed to
curate RSS feeds. It provides the capability to annotate feed entries and to
publish entries grouped by their subject categories. elfeed-curate
uses the
available elfeed
search functionality for marking, tagging, and filtering of
feed entries. The new functions available to support the curation workflow are:
elfeed-curate-edit-entry-annoation
(a
key) adds the ability to create and edit annotation text to an entry. Annotations can have org mode formatting and are saved in theelfeed
database. This function works in both search and show mode.When an annotation is added a custom tag (
elfeed-curate-annotation-tag
, default isann
) is also added to the entry. This shows which entries have annotations in the search window and can also be used as a filter (s +ann
).
elfeed-curate-toggle-star
(m
key) is a convenience function that allows starring entries from the show buffer. See Star and unstar articles in elfeed.elfeed-curate-star-tag
(default isstar
) can be used to change the tag name.
elfeed-curate-export-entries
(x
key) exports entries in the*elfeed-search*
buffer to the desired publication format (seeelfeed-curate-org-export-backend
). The newly generated file is also opened with the associated application (e.g. a browser for HTML). Exporting directly to Hugo (Markdown plus Front matter) is also supported.The subject categories are based on the entry tag names (see details below).
- Use
M-x elfeed-curate-reconcile-annotations
to ensure all database entries have the correct annotation tags.
My preferred workflow is as follows:
- If an entry has content of interest,
star
(m
key) it and add annotation (a
key) if desired. - Select all starred entries (
s +star
) and export them (x
key). This can be repeated as often as is needed to ensure that the exported content is to your liking. - Publish exported content.
- (optional) Previously published entries can be tracked by tagging all starred
entries with a new date-based publication tag (e.g.
+ pub_DDMMYY
). - Remove all of the star tags (
m
key or- star
).
That’s it. The Elfeed filtering capabilities can provide many other entry selection criteria (e.g. time-based), but so far I’ve found that specifically tagging selected entries independent of their subject matter to be simple and efficient.
This is the elfeed search window showing the starred entries to be exported. The entries with annotations (ann
) are highlighted.
The exported content (as HTML here) shows how entries are grouped (based on tag name) and some annotation examples. The same content exported to Hugo is here: 21-Sep-2023 Content of Interest.
This package only depends on org
and elfeed
being installed.
If you use MELPA, an easy way to install this package is via
package-install
. Alternatively, download elfeed-curate.el
, put it in
your load-path
and require
it.
If you use both MELPA and use-package
, you can use this, too:
(use-package elfeed-curate
:ensure
:after elfeed)
The annotate function works in both search and show modes while
the export function works only in search mode. The keys in
the elfeed-search-mode-map
and elfeed-show-mode-map
maps can
be bound as shown here:
(use-package elfeed-curate
:ensure
:bind (:map elfeed-search-mode-map
("a" . elfeed-curate-edit-entry-annoation)
("x" . elfeed-curate-export-entries))
(:map elfeed-show-mode-map
("a" . elfeed-curate-edit-entry-annoation)
("m" . elfeed-curate-toggle-star)
("q" . kill-buffer-and-window)))
Doom configuration
;;...
(package! elfeed-curate)
;;...
(after! elfeed
;; Your custom Elfeed configuration.
;; elfeed-curate key bindings:
(define-key elfeed-search-mode-map "a" #'elfeed-curate-edit-entry-annoation)
(define-key elfeed-search-mode-map "x" #'elfeed-curate-export-entries)
(define-key elfeed-search-mode-map "m" #'elfeed-curate-toggle-star)
(define-key elfeed-show-mode-map "a" #'elfeed-curate-edit-entry-annoation)
(define-key elfeed-show-mode-map "m" #'elfeed-curate-toggle-star)
(define-key elfeed-show-mode-map "q" #'kill-buffer-and-window))
I had issues closing the show window after the annotation buffer was displayed
there. Not sure what the root cause was (is), but overriding the q
key with
kill-buffer-and-window
seems to have solved the problem. This needs more
investigation.
- I have only tested this with Emacs 29.1, both bare-bones and with Doom. The code is compatible back to Emacs 25.1 and Org/Elfeed are the only dependencies, so there’s a good chance this will work out of the box on most modern systems.
- Testing of the export backends has been limited to mostly HTML and Markdown.
Exported annotation:
The a
key (elfeed-curate-edit-entry-annoation
) will display an org-mode
buffer for managing annotation content. Annotation can be added, edited, and
deleted for an entry from both the elfeed search and show windows. The
annotation tag (ann
) will be added or removed automatically.
Most org-mode formatting will be exported properly, but may differ depending on the export format.
Surrounding annotation text with angle brackets < text >
allows you to
override the original entry link and author(s). Everything outside of the angle
brackets will be ignored. This is handy for adding an arbitrary link that is not
currently in your feed list. The entry tags remain unchanged so you can decide
which group(s) the entry should be in. A link override example would typically
look like this:
<Link Name (Author Name) =Interesting stuff.=>
The following key combinations are used to exit the annotation buffer:
Keys | Action | Notes |
---|---|---|
C-c C-c | Save | Saves the annotation content. If the annotation buffer is empty, the annotation is removed. |
C-c C-d | Delete | Delete the annotation content. |
C-c C-k | Abort | Exit the annotation buffer without saving changes. |
The x
key (elfeed-curate-export-entries
) takes the following actions:
- All displayed or selected search entries are grouped based on their subject matter tagging.
- Tags are converted to group headings by replacing
_
characters with a space and capitalizing all words. E.g. themed_dev
tag becomes “Med Dev”. - Tags to be excluded from the subject categories are specified in
elfeed-curate-group-exclude-tag-list
. Non-subject group tags should be added to this list. - If one or more authors are available from the feed, they will be listed next to the link in parentheses: (Author 1, Author 2, …).
- An entry will only be displayed in one group. If the entry is in multiple groups, the other groups will be shown in bold brackets ([Group 2, Group 3,…]) next to the exported link.
- Use
elfeed-curate-no-group-tag
to determine how entries that do not belong to any group are treated. I.e. there are no tags left after removing the excluded list tags (above). By default, they are added to the “No Category” group. Set to nil to not display these entries. - By default, the count of each group is included in the group heading. If a
prefix argument is used before the export (
C-u x
), the count will not be shown. The count can be permanently removed by settingelfeed-curate-show-group-count
tonil
.
- Tags are converted to group headings by replacing
- The grouped content is exported to an
org
file (export.org in theelfeed-curate-export-dir
directory).- Use
elfeed-curate-org-options
to specify custom org file options. - The
elfeed-curate-org-content-header-function
can be used to customize all org file header content.
- Use
- The
export.org
file is then converted to the desired export format specified byelfeed-curate-org-export-backend
. A date-stamped export file with the selected backend extension (.md
,.html
, etc.) is created. - The exported content is then displayed.
- If the format is Markdown (
md
) andelfeed-curate-hugo-base-dir
is specified the exported date-stamped Markdown file is written to the specified content section (elfeed-curate-hugo-section
). The Hugo development server will automatically detect the change and display the new content. - In all other cases, the exported content will attempt to be displayed via
elfeed-curate--open-in-external-app
(xdg-open
in most cases).
- If the format is Markdown (
Here are the variables that can be customized:
Variable | Default | Desc. |
---|---|---|
elfeed-curate-title-length | 60 | Maximum length of the entry title to show in the annotation edit buffer. |
elfeed-curate-annotation-key | :my/annotation | Elfeed database meta data key to store annotations. |
elfeed-curate-annotation-tag | ‘ann | Tag used to indicate that annotation has been added to an entry. |
elfeed-curate-star-tag | ‘star | Tag used to indicate that annotation has been `starred`. |
elfeed-curate-no-group-tag | ‘no_category | Tag used to indicate that an entry has no group tag. The entry will be added to this group in the export. Set to nil to not display these entries. |
elfeed-curate-org-content-header-function | #’elfeed-curate-org-content-header–default | Function used to create the header (options and title) content. The default is for HTML output. |
elfeed-curate-org-title | Content of Note | The TITLE part of the ‘<Date> <Title>’ format. See the elfeed-curate-org-content-header--default function. |
elfeed-curate-date-format | “%d-%b-%Y” | The date format used in the title. |
elfeed-curate-org-options | #html-style:nil toc:nil num:nil f:nil html-postamble:nil html-preamble:nil | Set org document format options. Default is for an HTML export: no styles, TOC, section numbering, footer. |
elfeed-curate-export-dir | ~/org | Write the .org file and exported content to this directory. |
elfeed-curate-org-export-backend | ‘html | Select export format. Can be one of: |
ascii - Export to plain ASCII text. | ||
html - Export to HTML. | ||
md - Export to Markdown. | ||
odt - Export to OpenDocument Text. | ||
pdf - Export to PDF (requires additional setup). | ||
elfeed-curate-group-exclude-tag-list | (list ‘unread elfeed-curate-star-tag elfeed-curate-annotation-tag) | List of tags to exclude from the group list. These are typically non-subject categories. |
elfeed-curate-show-group-count | t | Flag to enable showing the count of each group in the exported output. If a prefix argument is used before the export (C-u x ), the count will not be shown. |
elfeed-curate-hugo-base-dir | nil | Base directory of the Hugo project. Used for ‘md exports. |
elfeed-curate-hugo-section | “posts” | Hugo section name. Posts will be written to elfeed-curate-hugo-base-dir/content/<section>. |