My elfeed configuration

This commit is contained in:
Bram Schoenmakers 2024-04-29 22:37:16 +02:00
parent 68b36fc922
commit a8f7732067
Signed by: bram
GPG key ID: 0CCD19DFDC63258F
2 changed files with 388 additions and 0 deletions

196
gists.org
View file

@ -943,6 +943,202 @@ Which covers my (potential) GPG/SSH usage within Emacs. Now, anytime a I perform
(display-buffer (current-buffer))))
#+end_src
* elfeed configuration :emacs:
#+begin_src elisp :tangle gists/elfeed.el
;; For constructing relative date strings from a timestamp.
;; Clone from https://github.com/rougier/relative-date
(use-package relative-date
:ensure nil
:load-path "lisp/relative-date"
:config
(defun bram85-fix-relative-date-in-future (f &rest args)
"Fix future relative dates, as they are returned with a +-
prefix given the `relative-dates-formats' below. Because the
internal data is negative, it shows up as such when replacing
placeholders."
(replace-regexp-in-string "\\`+-" "+" (apply f args)))
(advice-add 'relative-date :around #'bram85-fix-relative-date-in-future)
(setq relative-date-formats
(let* ((seconds 1)
(minutes (* 60 seconds))
(hours (* 60 minutes))
(days (* 24 hours))
(months (* 30 days))
(years (* 365 days)))
`((, (* 3 minutes) . "now") ;; Less than 3 minutes (past)
(,(- (* 3 minutes)) . "soon") ;; Less than 3 minutes (future)
(, (* 1 hours) . "%(M)m") ;; Less than 1 hour
(,(- (* 1 hours)) . "+%(M)m") ;; Less than 1 hour in the future
(, (* 24 hours) . "%(H)h") ;; Less than 24 hours
(,(- (* 24 hours)) . "+%(H)h") ;; Less than 24 hours in the future
(, (* 7 days) . "%(d)d") ;; Less than 7 days
(,(- (* 7 days)) . "+%(d)d") ;; Less than 7 days in the future
(, (* 1 months) . "%(w)w") ;; Less than 30 days
(,(- (* 1 months)) . "+%(w)w") ;; Less than 30 days in the future
(, (* 365 days) . "%(m)mo") ;; Less than a year
(,(- (* 365 days)) . "+%(m)mo") ;; Less than a year in the future
(, (* 1000 years) . "%(y)y") ;; Less than 1000 years
(,(- (* 100 years)) . "+%(y)y") ;; Less than 100 years in the future (to fit in 4 chars)
))))
(use-package elfeed
:after relative-date
:init
(defun bram85-elfeed-show-eww-open (&optional use-generic-p)
"open with eww"
(interactive "P")
(let ((browse-url-browser-function #'eww-browse-url))
(elfeed-show-visit use-generic-p)))
(defun bram85-elfeed-search-eww-open (&optional use-generic-p)
"open with eww"
(interactive "P")
(let ((browse-url-browser-function #'eww-browse-url))
(elfeed-search-browse-url use-generic-p)))
;; The following functions is for easy navigation, taken from
;; Karthinks blog: https://karthinks.com/software/lazy-elfeed/
(defun bram85-elfeed-scroll-up-command (&optional arg)
"Scroll up or go to next feed item in Elfeed"
(interactive "^P")
(let ((scroll-error-top-bottom nil))
(condition-case-unless-debug nil
(scroll-up-command arg)
(error (elfeed-show-next)))))
(defun bram85-elfeed-scroll-down-command (&optional arg)
"Scroll down or go to prev feed item in Elfeed"
(interactive "^P")
(let ((scroll-error-top-bottom nil))
(condition-case-unless-debug nil
(scroll-down-command arg)
(error (elfeed-show-prev)))))
:bind
(("C-x w" . elfeed)
:map elfeed-show-mode-map
("w" . elfeed-show-visit)
("W" . bram85-elfeed-show-eww-open)
("SPC" . bram85-elfeed-scroll-up-command)
("S-SPC" . bram85-elfeed-scroll-down-command)
:map elfeed-search-mode-map
("w" . elfeed-search-browse-url)
("W" . bram85-elfeed-search-eww-open))
:config
(setq-default elfeed-search-filter "@3-days-ago +unread")
(setq elfeed-feeds '(
;; ...
))
;; enable relative dates which are max 4 chars wide
(setq elfeed-search-date-format '("rel" 4 :right))
(defvar bram85-elfeed-hidden-tags
'(unread
highvol
lowvol
linkonly)
"List of tags which do not get printed.")
(defun bram85-elfeed-tags (entry)
"Return a list of tags as strings for the given ENTRY, where
hidden tags are filtered out."
(mapcar #'symbol-name
(seq-difference (elfeed-entry-tags entry) bram85-elfeed-hidden-tags)))
(defun bram85-elfeed-search-print-entry (entry)
"Print elfeed ENTRY to the buffer."
(let ((format-time-string-orig (symbol-function #'format-time-string)))
;; Make sure that elfeed-search-format-date calls relative-date
;; instead of format-time-string, if the format is "rel".
(cl-letf (((symbol-function #'format-time-string)
(lambda (fmt &optional time zone)
(if (string= fmt "rel")
(relative-date time)
;; For all other formats, call the builtin function.
(funcall format-time-string-orig fmt time zone)))))
(let* ((date (elfeed-search-format-date (elfeed-entry-date entry)))
(title (or (elfeed-meta entry :title) (elfeed-entry-title entry) ""))
(title-faces (elfeed-search--faces (elfeed-entry-tags entry)))
(feed (elfeed-entry-feed entry))
(feed-title
(when feed
(or (elfeed-meta feed :title) (elfeed-feed-title feed))))
(tags (bram85-elfeed-tags entry))
(tags-str (propertize (concat ":" (string-join tags ":") ":")
'face 'elfeed-search-tag-face))
(title-width (- (window-width) 10 elfeed-search-trailing-width))
(title-column (elfeed-format-column
title (elfeed-clamp
elfeed-search-title-min-width
title-width
elfeed-search-title-max-width)
:left)))
;; relative date
(insert (propertize date 'face 'elfeed-search-date-face) " ")
;; title
(insert (propertize title-column 'face title-faces 'kbd-help title) " ")
;; feed title
(when feed-title
(insert (propertize feed-title 'face 'elfeed-search-feed-face) " "))
;; tags
(when tags
(insert tags-str))))))
;; install the print function
(setq elfeed-search-print-entry-function #'bram85-elfeed-search-print-entry)
(setq elfeed-search-trailing-width 20)
;; record read date when an entry is opened
(eval-when-compile
(require 'elfeed))
(defun bram85-elfeed--mark-read (entry read-date)
"Set the READ-DATE for the given ENTRY."
(unless (elfeed-tagged-p 'unread entry)
(setf (elfeed-meta entry :read-date) read-date)))
(defun bram85-elfeed-mark-read (entries tags)
"Mark the ENTRIES as read and record the read date with some delay.
It is considered marked read if the 'unread' tag is part of
TAGS to be removed from ENTRIES."
(when (member 'unread tags)
(let* ((date (format-time-string "%FT%T%z"))
(entry-unread-p (lambda (e) (elfeed-tagged-p 'unread e)))
(filtered-entries (seq-filter entry-unread-p entries)))
(dolist (entry filtered-entries)
(run-with-timer 5 nil #'bram85-elfeed--mark-read entry date)))))
(defun bram85-elfeed-mark-as-unread (entries tags)
"Reset the read date when ENTRIES are marked as read again.
It is considered marked unread if the 'unread' tag is part of
TAGS to be added to ENTRIES."
(when (member 'unread tags)
(dolist (entry entries)
(setf (elfeed-meta entry :read-date) nil))))
(add-hook 'elfeed-untag-hooks 'bram85-elfeed-mark-read)
(add-hook 'elfeed-tag-hooks 'bram85-elfeed-mark-as-unread)
;; Fix bug in Elfeed where the history variable
;; elfeed-search-filter-history remains unused.
(defun bram85-elfeed-advice-elfeed-search-live-filter (f &rest args)
(let ((read-from-minibuffer-orig (symbol-function #'read-from-minibuffer)))
(cl-letf (((symbol-function #'read-from-minibuffer)
(lambda (prompt init-value)
(funcall read-from-minibuffer-orig prompt init-value nil nil 'elfeed-search-filter-history))))
(apply f args))))
(advice-add #'elfeed-search-live-filter :around #'bram85-elfeed-advice-elfeed-search-live-filter)
(add-hook 'elfeed-update-hooks (lambda (_) (when (zerop (elfeed-queue-count-total)) (elfeed-db-save))))
;; update elfeed every two hours, only when idle
(run-with-timer nil (* 2 60 60) (lambda () (run-with-idle-timer 120 nil 'elfeed-update))))
#+end_src
* Meta
** License

192
gists/elfeed.el Normal file
View file

@ -0,0 +1,192 @@
;; For constructing relative date strings from a timestamp.
;; Clone from https://github.com/rougier/relative-date
(use-package relative-date
:ensure nil
:load-path "lisp/relative-date"
:config
(defun bram85-fix-relative-date-in-future (f &rest args)
"Fix future relative dates, as they are returned with a +-
prefix given the `relative-dates-formats' below. Because the
internal data is negative, it shows up as such when replacing
placeholders."
(replace-regexp-in-string "\\`+-" "+" (apply f args)))
(advice-add 'relative-date :around #'bram85-fix-relative-date-in-future)
(setq relative-date-formats
(let* ((seconds 1)
(minutes (* 60 seconds))
(hours (* 60 minutes))
(days (* 24 hours))
(months (* 30 days))
(years (* 365 days)))
`((, (* 3 minutes) . "now") ;; Less than 3 minutes (past)
(,(- (* 3 minutes)) . "soon") ;; Less than 3 minutes (future)
(, (* 1 hours) . "%(M)m") ;; Less than 1 hour
(,(- (* 1 hours)) . "+%(M)m") ;; Less than 1 hour in the future
(, (* 24 hours) . "%(H)h") ;; Less than 24 hours
(,(- (* 24 hours)) . "+%(H)h") ;; Less than 24 hours in the future
(, (* 7 days) . "%(d)d") ;; Less than 7 days
(,(- (* 7 days)) . "+%(d)d") ;; Less than 7 days in the future
(, (* 1 months) . "%(w)w") ;; Less than 30 days
(,(- (* 1 months)) . "+%(w)w") ;; Less than 30 days in the future
(, (* 365 days) . "%(m)mo") ;; Less than a year
(,(- (* 365 days)) . "+%(m)mo") ;; Less than a year in the future
(, (* 1000 years) . "%(y)y") ;; Less than 1000 years
(,(- (* 100 years)) . "+%(y)y") ;; Less than 100 years in the future (to fit in 4 chars)
))))
(use-package elfeed
:after relative-date
:init
(defun bram85-elfeed-show-eww-open (&optional use-generic-p)
"open with eww"
(interactive "P")
(let ((browse-url-browser-function #'eww-browse-url))
(elfeed-show-visit use-generic-p)))
(defun bram85-elfeed-search-eww-open (&optional use-generic-p)
"open with eww"
(interactive "P")
(let ((browse-url-browser-function #'eww-browse-url))
(elfeed-search-browse-url use-generic-p)))
;; The following functions is for easy navigation, taken from
;; Karthinks blog: https://karthinks.com/software/lazy-elfeed/
(defun bram85-elfeed-scroll-up-command (&optional arg)
"Scroll up or go to next feed item in Elfeed"
(interactive "^P")
(let ((scroll-error-top-bottom nil))
(condition-case-unless-debug nil
(scroll-up-command arg)
(error (elfeed-show-next)))))
(defun bram85-elfeed-scroll-down-command (&optional arg)
"Scroll down or go to prev feed item in Elfeed"
(interactive "^P")
(let ((scroll-error-top-bottom nil))
(condition-case-unless-debug nil
(scroll-down-command arg)
(error (elfeed-show-prev)))))
:bind
(("C-x w" . elfeed)
:map elfeed-show-mode-map
("w" . elfeed-show-visit)
("W" . bram85-elfeed-show-eww-open)
("SPC" . bram85-elfeed-scroll-up-command)
("S-SPC" . bram85-elfeed-scroll-down-command)
:map elfeed-search-mode-map
("w" . elfeed-search-browse-url)
("W" . bram85-elfeed-search-eww-open))
:config
(setq-default elfeed-search-filter "@3-days-ago +unread")
(setq elfeed-feeds '(
;; ...
))
;; enable relative dates which are max 4 chars wide
(setq elfeed-search-date-format '("rel" 4 :right))
(defvar bram85-elfeed-hidden-tags
'(unread
highvol
lowvol
linkonly)
"List of tags which do not get printed.")
(defun bram85-elfeed-tags (entry)
"Return a list of tags as strings for the given ENTRY, where
hidden tags are filtered out."
(mapcar #'symbol-name
(seq-difference (elfeed-entry-tags entry) bram85-elfeed-hidden-tags)))
(defun bram85-elfeed-search-print-entry (entry)
"Print elfeed ENTRY to the buffer."
(let ((format-time-string-orig (symbol-function #'format-time-string)))
;; Make sure that elfeed-search-format-date calls relative-date
;; instead of format-time-string, if the format is "rel".
(cl-letf (((symbol-function #'format-time-string)
(lambda (fmt &optional time zone)
(if (string= fmt "rel")
(relative-date time)
;; For all other formats, call the builtin function.
(funcall format-time-string-orig fmt time zone)))))
(let* ((date (elfeed-search-format-date (elfeed-entry-date entry)))
(title (or (elfeed-meta entry :title) (elfeed-entry-title entry) ""))
(title-faces (elfeed-search--faces (elfeed-entry-tags entry)))
(feed (elfeed-entry-feed entry))
(feed-title
(when feed
(or (elfeed-meta feed :title) (elfeed-feed-title feed))))
(tags (bram85-elfeed-tags entry))
(tags-str (propertize (concat ":" (string-join tags ":") ":")
'face 'elfeed-search-tag-face))
(title-width (- (window-width) 10 elfeed-search-trailing-width))
(title-column (elfeed-format-column
title (elfeed-clamp
elfeed-search-title-min-width
title-width
elfeed-search-title-max-width)
:left)))
;; relative date
(insert (propertize date 'face 'elfeed-search-date-face) " ")
;; title
(insert (propertize title-column 'face title-faces 'kbd-help title) " ")
;; feed title
(when feed-title
(insert (propertize feed-title 'face 'elfeed-search-feed-face) " "))
;; tags
(when tags
(insert tags-str))))))
;; install the print function
(setq elfeed-search-print-entry-function #'bram85-elfeed-search-print-entry)
(setq elfeed-search-trailing-width 20)
;; record read date when an entry is opened
(eval-when-compile
(require 'elfeed))
(defun bram85-elfeed--mark-read (entry read-date)
"Set the READ-DATE for the given ENTRY."
(unless (elfeed-tagged-p 'unread entry)
(setf (elfeed-meta entry :read-date) read-date)))
(defun bram85-elfeed-mark-read (entries tags)
"Mark the ENTRIES as read and record the read date with some delay.
It is considered marked read if the 'unread' tag is part of
TAGS to be removed from ENTRIES."
(when (member 'unread tags)
(let* ((date (format-time-string "%FT%T%z"))
(entry-unread-p (lambda (e) (elfeed-tagged-p 'unread e)))
(filtered-entries (seq-filter entry-unread-p entries)))
(dolist (entry filtered-entries)
(run-with-timer 5 nil #'bram85-elfeed--mark-read entry date)))))
(defun bram85-elfeed-mark-as-unread (entries tags)
"Reset the read date when ENTRIES are marked as read again.
It is considered marked unread if the 'unread' tag is part of
TAGS to be added to ENTRIES."
(when (member 'unread tags)
(dolist (entry entries)
(setf (elfeed-meta entry :read-date) nil))))
(add-hook 'elfeed-untag-hooks 'bram85-elfeed-mark-read)
(add-hook 'elfeed-tag-hooks 'bram85-elfeed-mark-as-unread)
;; Fix bug in Elfeed where the history variable
;; elfeed-search-filter-history remains unused.
(defun bram85-elfeed-advice-elfeed-search-live-filter (f &rest args)
(let ((read-from-minibuffer-orig (symbol-function #'read-from-minibuffer)))
(cl-letf (((symbol-function #'read-from-minibuffer)
(lambda (prompt init-value)
(funcall read-from-minibuffer-orig prompt init-value nil nil 'elfeed-search-filter-history))))
(apply f args))))
(advice-add #'elfeed-search-live-filter :around #'bram85-elfeed-advice-elfeed-search-live-filter)
(add-hook 'elfeed-update-hooks (lambda (_) (when (zerop (elfeed-queue-count-total)) (elfeed-db-save))))
;; update elfeed every two hours, only when idle
(run-with-timer nil (* 2 60 60) (lambda () (run-with-idle-timer 120 nil 'elfeed-update))))