186 lines
7.6 KiB
EmacsLisp
186 lines
7.6 KiB
EmacsLisp
;;; +elfeed.el -*- lexical-binding: t; -*-
|
|
|
|
;;; Code:
|
|
|
|
(require 'elfeed)
|
|
|
|
;; https://karthinks.com/software/lazy-elfeed/
|
|
(defun +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 +elfeed-scroll-down-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-down-command arg)
|
|
(error (elfeed-show-prev)))))
|
|
|
|
(defun +elfeed-search-browse-generic ()
|
|
"Browse a url with `browse-url-generic-browser'."
|
|
(interactive)
|
|
(elfeed-search-browse-url t))
|
|
|
|
(defun +elfeed-show-browse-generic ()
|
|
"Browse a url with `browse-url-generic-browser'."
|
|
(interactive)
|
|
(elfeed-show-visit t))
|
|
|
|
(defun +elfeed-show-mark-read-and-advance ()
|
|
"Mark an item as read and advance to the next item.
|
|
If multiple items are selected, don't advance."
|
|
(interactive)
|
|
(call-interactively #'elfeed-search-untag-all-unread)
|
|
(unless (region-active-p)
|
|
(call-interactively #'next-line)))
|
|
|
|
;;; Fetch feeds async
|
|
;; https://github.com/skeeto/elfeed/issues/367
|
|
|
|
(defun +elfeed--update-message ()
|
|
(message "[Elfeed] Update in progress")
|
|
'ignore)
|
|
|
|
(defvar +elfeed--update-running-p nil "Whether an update is currently running.")
|
|
(defvar +elfeed--update-count 0 "How many times `+elfeed-update-command' has run.")
|
|
(defcustom +elfeed-update-niceness 15
|
|
"How \"nice\" `+elfeed-update-command' should be."
|
|
:type 'integer
|
|
:group 'elfeed)
|
|
|
|
(defcustom +elfeed-update-lockfile
|
|
(expand-file-name "+elfeed-update-lock" (temporary-file-directory))
|
|
"The file to ")
|
|
|
|
(defun +elfeed-update-command ()
|
|
(interactive)
|
|
(unless (or +elfeed--update-running-p
|
|
(derived-mode-p 'elfeed-show-mode 'elfeed-search-mode))
|
|
(let ((script (expand-file-name "/tmp/elfeed-update.el"))
|
|
(update-message-format "[Elfeed] Background update: %s"))
|
|
(setq +elfeed--update-running-p t)
|
|
(elfeed-db-save)
|
|
(advice-add 'elfeed :override #'+elfeed--update-message)
|
|
(ignore-errors (kill-buffer "*elfeed-search*"))
|
|
(ignore-errors (kill-buffer "*elfeed-log*"))
|
|
(elfeed-db-unload)
|
|
(make-directory (file-name-directory script) :parents)
|
|
(with-temp-buffer
|
|
(insert
|
|
(let ((print-level nil)
|
|
(print-length nil))
|
|
(prin1-to-string ;; Print the following s-expression to a string
|
|
`(progn
|
|
;; Set up the environment
|
|
(setq lexical-binding t)
|
|
(load (locate-user-emacs-file "early-init"))
|
|
(dolist (pkg '(elfeed elfeed-org))
|
|
(straight-use-package pkg)
|
|
(require pkg))
|
|
;; Copy variables from current environment
|
|
(progn
|
|
,@(cl-loop for copy-var in '(rmh-elfeed-org-files
|
|
elfeed-db-directory
|
|
elfeed-curl-program-name
|
|
elfeed-use-curl
|
|
elfeed-curl-extra-arguments
|
|
elfeed-enclosure-default-dir)
|
|
collect `(progn (message "%S = %S" ',copy-var ',(symbol-value copy-var))
|
|
(setq ,copy-var ',(symbol-value copy-var)))))
|
|
;; Define new variables for this environment
|
|
(progn
|
|
,@(cl-loop for (new-var . new-val) in '((elfeed-curl-max-connections . 4))
|
|
collect `(progn (message "%S = %S" ',new-var ',new-val)
|
|
(setq ,new-var ',new-val))))
|
|
;; Redefine `elfeed-log' to log everything
|
|
(defun elfeed-log (level fmt &rest objects)
|
|
(princ (format "[%s] [%s]: %s\n"
|
|
(format-time-string "%F %T")
|
|
level
|
|
(apply #'format fmt objects))))
|
|
;; Run elfeed
|
|
(elfeed-org)
|
|
(elfeed)
|
|
(elfeed-db-load)
|
|
(elfeed-update)
|
|
;; Wait for `elfeed-update' to finish
|
|
(let ((q<5-count 0))
|
|
(while (and (> (elfeed-queue-count-total) 0)
|
|
(< q<5-count 5))
|
|
(sleep-for 5)
|
|
(message "Elfeed queue count total: %s" (elfeed-queue-count-total))
|
|
(when (< (elfeed-queue-count-total) 5)
|
|
(cl-incf q<5-count))
|
|
(accept-process-output)))
|
|
;; Garbage collect and save the database
|
|
(elfeed-db-gc)
|
|
(elfeed-db-save)
|
|
(princ (format ,update-message-format "done."))))))
|
|
(write-file script))
|
|
(chmod script #o777)
|
|
(message update-message-format "start")
|
|
(set-process-sentinel (start-process-shell-command
|
|
"Elfeed" "*+elfeed-update-background*"
|
|
(format "nice -n %d %s %s"
|
|
+elfeed-update-niceness
|
|
"emacs -Q --script"
|
|
script))
|
|
(lambda (proc stat)
|
|
(advice-remove 'elfeed #'+elfeed--update-message)
|
|
(setq +elfeed--update-running-p nil)
|
|
(unless (string= stat "killed")
|
|
(setq +elfeed--update-count (1+ +elfeed--update-count)))
|
|
(message update-message-format (string-trim stat)))))))
|
|
|
|
(defvar +elfeed--update-timer nil "Timer for `elfeed-update-command'.")
|
|
(defvar +elfeed--update-first-time 6 "How long to wait for the first time.")
|
|
(defvar +elfeed--update-repeat (* 60 15) "How long between updates.")
|
|
|
|
(defcustom +elfeed-update-proceed-hook nil
|
|
"Predicates to query before running `+elfeed-update-command'.
|
|
Each hook is passed no arguments."
|
|
:type 'hook)
|
|
|
|
(defun +elfeed-update-command-wrapper ()
|
|
"Run `+elfeed-update-command', but only sometimes.
|
|
If any of the predicates in `+elfeed-update-proceed-hook' return
|
|
nil, don't run `+elfeed-update-command'. If they all return
|
|
non-nil, proceed."
|
|
(when (run-hook-with-args-until-failure '+elfeed-update-proceed-hook)
|
|
(+elfeed-update-command)))
|
|
|
|
(defun +elfeed--cancel-update-timer ()
|
|
"Cancel `+elfeed--update-timer'."
|
|
(unless +elfeed--update-running-p
|
|
(ignore-errors (cancel-timer +elfeed--update-timer))
|
|
(setq +elfeed--update-timer nil)))
|
|
|
|
(defun +elfeed--reinstate-update-timer ()
|
|
"Reinstate `+elfeed--update-timer'."
|
|
;; First, unload the db
|
|
(setq +elfeed--update-timer
|
|
(run-at-time +elfeed--update-first-time
|
|
+elfeed--update-repeat
|
|
#'+elfeed-update-command-wrapper)))
|
|
|
|
(define-minor-mode +elfeed-update-async-mode
|
|
"Minor mode to update elfeed async-style."
|
|
:global t
|
|
(if +elfeed-update-async-mode
|
|
(progn ; enable
|
|
(+elfeed--reinstate-update-timer)
|
|
(advice-add 'elfeed :before '+elfeed--cancel-update-timer)
|
|
(advice-add 'elfeed-search-quit-window :after '+elfeed--reinstate-update-timer))
|
|
(progn ; disable
|
|
(advice-remove 'elfeed '+elfeed--cancel-update-timer)
|
|
(advice-remove 'elfeed-search-quit-window '+elfeed--reinstate-update-timer)
|
|
(+elfeed--cancel-update-timer))))
|
|
|
|
(provide '+elfeed)
|
|
;;; +elfeed.el ends here
|