;;; feedly-to-elfeed.el --- convert feedly OPML to elfeed -*- lexical-binding: t; -*- ;; Copyright (C) 2019 Michael Herstine ;; Author: Michael Herstine ;; Maintainer: Michael Herstine ;; Created: 8 November 2019 ;; Keywords: tools, hypermedia ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; This package provides a single function: `feedly-to-elfeed'. It ;; takes as input the path to a Feedly OPML export file & returns a ;; string containing Emacs Lisp configuring elfeed with your Feedly ;; tags. Yes, there's `elfeed-load-opml' but it didn't work for my ;; Feedly export. ;;; Code: (require 'xml) (defun feedly--outline-to-alist (tags) "Convert a list of top-level outline XML nodes to a more convenient alist." (let ((feed-alist '())) ;; will be an assoc list: "feed-title" => (xmlUrl (tag-title)) (while tags (let* ((tag (car tags)) (tag-title (xml-get-attribute tag 'title)) (feeds (xml-get-children tag 'outline))) (while feeds (let* ((feed (car feeds)) (feed-title (xml-get-attribute feed 'title)) (xml-url (xml-get-attribute feed 'xmlUrl)) (entry (assoc feed-title feed-alist))) (if entry ;; `feed-title' is already in `feed-alist', we just ;; need to add `tag-title' to the list of tags (let ((title (car entry)) (url (nth 1 entry)) (tags (nth 2 entry))) (unless (member tag-title tags) (setq tags (append tags (list tag-title))) (assoc-delete-all feed-title feed-alist) (setq feed-alist (append feed-alist (list (list feed-title xml-url tags)))))) ;; This is a new feed-- make a new entry in `feed-alist'. (setq feed-alist (append feed-alist (list (list feed-title xml-url (list tag-title))))))) (setq feeds (cdr feeds)))) (setq tags (cdr tags))) feed-alist)) (defun feedly-to-elfeed--alist-to-org-table (feeds) "Convert an association list to an org-mode table. Produces tab-delimited output-- you'll need to insert it into an org file, select the text, and do C-|." (let ((lines '())) (while feeds (let* ((feed (car feeds)) (feed-url (nth 1 feed)) (tags (nth 2 feed)) (feed-title (nth 0 feed))) (setq lines (append lines (list (format "%s\t%s\t%s" feed-title (mapconcat 'identity tags " ") feed-url))))) (setq feeds (cdr feeds))) (format "Title\tTags\tURL\n%s" (mapconcat 'identity lines "\n")))) (defun feedly-to-elfeed (opml-file) "Convert Feedly OPML to elfeed configuration." (let* ((body (assq 'body (assq 'opml (xml-parse-file opml-file)))) (tags (xml-get-children body 'outline))) ;; `tags' will be the list of "outer" `outline' tags (feedly-to-elfeed--alist-to-org-table (feedly--outline-to-alist tags)))) (provide 'feedly-to-elfeed) ;;; feedly-to-elfeed.el ends here