about summary refs log tree commit diff stats
path: root/lisp/+elfeed.el
blob: f669afd7d6c40cee93c17b7032bdcb86d358069a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
;;; +elfeed.el -*- lexical-binding: t; -*-

;;; Code:

;; 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))

;;; Fetch feeds async
;; https://github.com/skeeto/elfeed/issues/367

(defun +elfeed--update-message ()
  (message "[Elfeed] Update in progress")
  'ignore)

(defvar +elfeed--update-running nil "Whether an update is currently running.")

(defun +elfeed-update-command ()
  (interactive)
  (let ((script (expand-file-name "~/.local/bin/elfeed-update.el"))
        (update-message-format "[Elfeed] Background update: %s"))
    (message update-message-format "start")
    (setq +elfeed--update-running 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)
    (unless (file-exists-p script)
      (make-directory (file-name-directory script) :parents)
      (with-temp-buffer
        (insert
         (nconcat nil
           "#!/usr/bin/env -S emacs --script"
           "(setq lexical-binding t)"
           ;; I have to load the necessary files
           "(load (locate-user-emacs-file \"early-init\"))"
           "(straight-use-package 'elfeed)"
           "(straight-use-package 'elfeed-org)"
           "(require 'elfeed)"
           "(require 'elfeed-org)"
           ;; And set needed variables
           (let ((copy-environment))
             (dolist (var '(rmh-elfeed-org-files
                            elfeed-db-directory
                            elfeed-curl-program-name
                            elfeed-use-curl
                            elfeed-curl-extra-arguments
                            elfeed-enclosure-default-dir))
               (push (concat "(setq " (symbol-name var)
                             " '" (prin1-to-string (symbol-value var)) ")\n")
                     copy-environment))
             (nreverse copy-environment))
           ;; Overwrite log function to go to stdout
           "(defun elfeed-log (level fmt &rest objects)"
           "  (princ (format \"[%s] [%s]: %s\\n\""
           "                 (format-time-string \"%F %T\")"
           "                 level"
           "                 (apply #'format fmt objects))))"
           ;; Load elfeed
           "(elfeed-org)"
           "(elfeed-db-load)"
           "(elfeed)"
           ;; Update elfeed
           "(elfeed-update)"
           ;; Wait to finish ... I think.
           "(while (> (elfeed-queue-count-total) 0)"
           "  (sleep-for 5)"
           "  (message \"%s\" (elfeed-queue-count-total))"
           "  (accept-process-output))"
           ;; Save and garbage-collect
           "(elfeed-db-save)"
           "(elfeed-db-gc)"))
        (write-file script))
      (chmod script #o777))
    (set-process-sentinel (start-process-shell-command
                           "Elfeed" nil script)
                          (lambda (a b)
                            (advice-remove 'elfeed #'+elfeed--update-message)
                            (setq +elfeed--update-running nil)
                            (message update-message-format
                                     (string-trim b))))))

(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.")

(defun +elfeed--cancel-update-timer ()
  "Cancel `+elfeed--update-timer'."
  (unless +elfeed--update-running
    (ignore-errors (cancel-timer +elfeed--update-timer))
    (setq +elfeed--update-timer nil)))

(defun +elfeed--reinstate-update-timer ()
  "Reinstate `+elfeed--update-timer'."
  (setq +elfeed--update-timer
        (run-at-time +elfeed--update-first-time
                     +elfeed--update-repeat
                     #'+elfeed-update-command)))

(define-minor-mode +elfeed-update-async-mode
  "Minor mode to update elfeed async-style every 15 minutes."
  :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