commit 04e09341c0cfbc66a9618a58f6af8b3026b410eb
parent 80245f41431d8859a388f07a130081782b573bb9
Author: Yuval Langer <yuval.langer@gmail.com>
Date: Sat, 29 Jun 2024 05:52:27 +0300
Fix the o2e-elfeed-feeds updating function and add a ton of docstrings.
Diffstat:
1 file changed, 118 insertions(+), 43 deletions(-)
diff --git a/opml-to-elfeed-feeds.el b/opml-to-elfeed-feeds.el
@@ -37,23 +37,33 @@ Each member is either a string or the URL, or a list with the URL
as the first member and optional tags.
The tags would be attached to each feed in the OPML file."
+
:type
'(repeat (choice string
(cons string (repeat symbol)))))
(defcustom o2e-elfeed-feeds
'()
- "The GCO `elfeed-feeds'."
+ "`o2e-elfeeds' is the `o2e'-specific `elfeed-feeds' of all OPMLs after running the function `o2e--update-o2e-efleed-feeds'."
+
:type
'(repeat (choice string
(cons string (repeat symbol)))))
-(defun o2e--blogger-name-to-symbol (blogger-name)
+(defun o2e--text-element-value-to-tag (text-element-value)
+ "Convert TEXT-ELEMENT-VALUE of an OPML's \"outline\" into a symbol.
+
+It is used as an elfeed-feeds tag.
+
+In the Craftering OPML it represents the author of the blog's name."
+
(intern (downcase (replace-regexp-in-string "[ .()]+"
"-"
- blogger-name))))
+ text-element-value))))
(defun o2e--response-body-position (response-buffer)
+ "Return the starting position of the body within the HTTP RESPONSE-BUFFER."
+
(with-current-buffer response-buffer
(named-let loop ((position 1))
(cond
@@ -68,25 +78,44 @@ The tags would be attached to each feed in the OPML file."
(loop (1+ position)))))))
(defun o2e--parse-response-buffer-to-xml (response-buffer)
+ "Return the parsed XML contents of the HTTP RESPONSE-BUFFER."
+
(with-current-buffer response-buffer
(let ((start (o2e--response-body-position response-buffer))
(end (buffer-end 1)))
+ ;; XXX: Last time I've tried using it, the builtin
+ ;; `xml-parse-regin' function returned some weird crap:
+ ;;
;; (xml-parse-region beg
;; end
;; response-buffer)
+ ;;
+ ;; So I'm using the libxml library instead:
(libxml-parse-xml-region start
end))))
-(defun o2e--xml-to-opml-outlines (xml)
- (pcase (assq 'body xml)
- ;; TODO: What the hell is this?
+(defun o2e--xml-to-opml-outlines (opml)
+ "Return the outlines of the parsed OPML."
+
+ (pcase (assq 'body opml)
+ ;; TODO: What the hell is this? Does anybody know?
(`(body ,TODO-WHAT-THE-HELL-IS-THIS? . ,outlines)
outlines)))
(cl-defun o2e--response-buffer-to-elfeed-feed (response-buffer
&key
(tags '())
- (tag-blogger-name? '()))
+ (text-element-value-to-tag '()))
+ "Convert the raw OPML data within RESPONSE-BUFFER to an `elfeed-feeds' and return it.
+
+The optional named arguments:
+
+- TAGS - A list of symbols that would be added to every
+ resulting feed.
+
+- TEXT-ELEMENT-VALUE-TO-TAG - When non-nil, would append the
+ munged \"text\" entry of each \"outline\" within the OPML."
+
(let* ((xml (o2e--parse-response-buffer-to-xml response-buffer))
(outlines (o2e--xml-to-opml-outlines xml)))
(named-let loop ((outlines outlines)
@@ -99,15 +128,18 @@ The tags would be attached to each feed in the OPML file."
'outline))
(let* ((outline-values (cadar outlines))
(rest-of-outlines (cdr outlines))
+ ;; XXX: In Craftering OPML uses to represent the name
+ ;; of the author.
(text (cdr (assq 'text
outline-values)))
(xml-url (cdr (assq 'xmlUrl
outline-values)))
- (blogger-name-tag (o2e--blogger-name-to-symbol text))
(all-tags (elfeed-normalize-tags
- (if tag-blogger-name?
- (list blogger-name-tag)
- '())
+ ;; If user provided a "text" munging
+ ;; function, use it to create a tag.
+ (when text-element-value-to-tag
+ (list (funcall text-element-value-to-tag
+ text)))
tags))
(elfeed-feed-entry (append (list xml-url)
all-tags)))
@@ -124,7 +156,10 @@ The tags would be attached to each feed in the OPML file."
accumulator))))))
(defun o2e--elfeed-feeds-entry-url (elfeed-feeds-entry)
- "Takes an `elfeed-feeds' kind of entry as ELFEED-FEEDS-ENTRY and return its URL."
+ "Return the URL of ELFEED-FEEDS-ENTRY.
+
+ELFEED-FEEDS-ENTRY is of the `elfeed-feeds' type."
+
(pcase elfeed-feeds-entry
(`(,url . ,tags)
url)
@@ -132,26 +167,54 @@ The tags would be attached to each feed in the OPML file."
url)))
(defun o2e--elfeed-feeds-entry-tags (elfeed-feeds-entry)
- "Takes an `elfeed-feeds' kind of entry as ELFEED-FEEDS-ENTRY and return its list of tags."
+ "Return the tags of ELFEED-FEEDS-ENTRY.
+
+ELFEED-FEEDS-ENTRY is of the `elfeed-feeds' type."
+
(pcase elfeed-feeds-entry
(`(,url . ,tags)
tags)
(url
'())))
-(defun o2e--hash-table-to-alist (hash-table)
- "Convert an hash-table HASH-TABLE to a list.
+(cl-defun o2e--hash-table-to-alist (hash-table &key (ordp 'string<))
+ "Return HASH-TABLE represented as a list.
+
+The optional named argument ORDP decides how to order the
+returned list. Its default value is the symbol `string<'.
TODO: There MUST be a standard function for that, right? Send a
patch if you know."
+
+ '(unless ordp
+ (setq ordp 'string<))
+
(mapcar (lambda (key)
(cons key
(gethash key
hash-table)))
(sort (hash-table-keys hash-table)
- 'string<)))
+ ordp)))
+
+(cl-defun o2e--normalise-elfeed-feeds (elfeed-feeds &key (ordp 'string<))
+ "Return ELFEED-FEEDS with duplicate entries merged.
+
+\"Merged\", in this case, means that calling the function with an
+ELFEED-FEEDS with the value of:
+
+'((\"https://example.com/blog.xml\" a b c)
+ (\"https://example.com/blog.xml\" b c d))
+
+would result with:
+
+'((\"https://example.com/blog.xml\" a b c d))
+
+The order of the original elfeed-feeds is destroyed but it is
+ordered according to the optional named argument ORDP."
+
+ '(unless ordp
+ (setq ordp 'string<))
-(defun o2e--normalise-elfeed-feeds (elfeed-feeds)
(let (;; XXX: Pass ":test 'equal" into make-hash-table so that
;; string comparisons work, otherwise it'll put many of the
;; same string as keys, each with its own values, like:
@@ -177,34 +240,46 @@ patch if you know."
(o2e--hash-table-to-alist hash)))
(defun o2e--update-o2e-efleed-feeds ()
- "TODO: This here supposed to take the opmls and add and dedup the GCO elfeed-feeds"
- (let ((our-elfeed-feeds o2e-elfeed-feeds))
- (dolist (opml-list-entry
- o2e-opml-list
- (setq o2e-elfeed-feeds (o2e--normalise-elfeed-feeds
- (apply 'append
- our-elfeed-feeds))))
- (let* ((url+tags (cond
- ;; If we have a simple string entry,
- ((stringp opml-list-entry)
- ;; convert to a tagged entry with empty tag
- ;; list.
- (list opml-list-entry))
- ;; If we have a tagged entry,
- ((and (consp opml-list-entry)
- (stringp (car opml-list-entry)))
- ;; just evaluate to the entry.
- (message "%S" opml-list-entry)
- opml-list-entry)))
- (url (car url+tags))
- (tags (cdr url+tags))
- (response-buffer (url-retrieve-synchronously url)))
- (setq our-elfeed-feeds
- (cons (o2e--response-buffer-to-elfeed-feed response-buffer
- :tags tags)
- our-elfeed-feeds))))))
+ "Retrieve the feed list for each of the OPML lists in `o2e-opml-list' and merge them into `o2e-elfeed-feeds'."
+
+ (let ((new-elfeed-feeds
+ (apply 'append
+ (mapcar (lambda (opml-list-entry)
+ (let* ((url+tags (cond
+ ;; If we have a simple string entry,
+ ((stringp opml-list-entry)
+ ;; convert to a tagged entry with empty tag
+ ;; list.
+ (list opml-list-entry))
+ ;; If we have a tagged entry,
+ ((and (consp opml-list-entry)
+ (stringp (car opml-list-entry)))
+ ;; just evaluate to the entry.
+ opml-list-entry)))
+ (url (car url+tags))
+ (tags (cdr url+tags))
+ (response-buffer (url-retrieve-synchronously url)))
+ (o2e--response-buffer-to-elfeed-feed response-buffer
+ :tags tags)))
+ o2e-opml-list))))
+ (message "%S" new-elfeed-feeds)
+ (customize-save-variable 'o2e-elfeed-feeds
+ (o2e--normalise-elfeed-feeds
+ (append new-elfeed-feeds
+ o2e-elfeed-feeds)))))
+
+(defun o2e--merge-o2e-elfeed-feeds-with-elfeed-elfeed-feeds ()
+ "Merge the two variables `elfeed-feeds' and `o2e-elfeed-feeds' and
+save the result in `elfeed-feeds' as the default value.
+
+TODO: Do you really call the saved customization \"default value\"?"
+
+ (customize-save-variable 'elfeed-feeds
+ (o2e--normalise-elfeed-feeds (append elfeed-feeds
+ o2e-elfeed-feeds))))
;;; XXX: Manual testing AHOY!
+;; (customize-save-variable 'o2e-elfeed-feeds '())
;; o2e-elfeed-feeds
;; (o2e--update-o2e-efleed-feeds)
;; (setq craftering (url-retrieve-synchronously (caar o2e-opml-list)))