Browse Source

Org-feed.el: Improvements

Carsten Dominik 16 years ago
parent
commit
73c31c945b
2 changed files with 114 additions and 60 deletions
  1. 3 0
      lisp/ChangeLog
  2. 111 60
      lisp/org-feed.el

+ 3 - 0
lisp/ChangeLog

@@ -1,5 +1,8 @@
 2009-03-24  Carsten Dominik  <carsten.dominik@gmail.com>
 2009-03-24  Carsten Dominik  <carsten.dominik@gmail.com>
 
 
+	* org-feed.el (org-feed-assume-stable): New option.
+	(org-feed-before-adding-hook): New hook.
+
 	* org-exp.el (org-export-as-html): Close local lists depending on
 	* org-exp.el (org-export-as-html): Close local lists depending on
 	indentation, also when starting a table.
 	indentation, also when starting a table.
 
 

+ 111 - 60
lisp/org-feed.el

@@ -148,6 +148,25 @@ of the file pointed to by the URL."
 	  (const :tag "Externally with wget" wget)
 	  (const :tag "Externally with wget" wget)
 	  (function :tag "Function")))
 	  (function :tag "Function")))
 
 
+(defcustom org-feed-assume-stable t
+  "Non-nil means, assume feeds to be stable.
+A stable feed is one which only adds and removes items, but never removes
+an item with a given GUID and then later adds it back in.  So if the feed
+is stable, this means we can simple remember the GUIDs present as the ones
+we have seen, and we can forget GUIDs that used to be in the feed but no
+longer are.  So for stable feeds, we only need to remember a limited
+number of GUIDs.  For unstable ones, we need to remember all GUIDs we have
+ever seen, which can be a very long list indeed."
+  :group 'org-feed
+  :type 'boolean)
+
+(defcustom org-feed-before-adding-hook nil
+  "Hook that is run before adding new feed items to a file.
+You might want to commit the file in its current state to version control,
+for example."
+  :group 'org-feed
+  :type 'hook)
+
 (defcustom org-feed-after-adding-hook nil
 (defcustom org-feed-after-adding-hook nil
   "Hook that is run after new items have been added to a file.
   "Hook that is run after new items have been added to a file.
 Depending on `org-feed-save-after-adding', the buffer will already
 Depending on `org-feed-save-after-adding', the buffer will already
@@ -155,11 +174,91 @@ have been saved."
   :group 'org-feed
   :group 'org-feed
   :type 'hook)
   :type 'hook)
 
 
-
 (defvar org-feed-buffer "*Org feed*"
 (defvar org-feed-buffer "*Org feed*"
   "The buffer used to retrieve a feed.")
   "The buffer used to retrieve a feed.")
 
 
-(defun org-feed-goto-inbox (file heading)
+;;;###autoload
+(defun org-feed-update-all ()
+  "Get inbox items from all feeds in `org-feed-alist'."
+  (interactive)
+  (let ((nfeeds (length org-feed-alist))
+	(nnew (apply '+  (mapcar 'org-feed-update org-feed-alist))))
+    (message "%s from %d %s"
+	     (cond ((= nnew 0) "No new entries")
+		   ((= nnew 1) "1 new entry")
+		   (t (format "%d new entries" nnew)))
+	     nfeeds
+	     (if (= nfeeds 1) "feed" "feeds"))))
+
+;;;###autoload
+(defun org-feed-update (feed)
+  "Get inbox items from FEED.
+FEED can be a string with an association in `org-feed-alist', or
+it can be a list structured like an entry in `org-feed-alist'."
+  (interactive (list (org-completing-read "Feed name: " org-feed-alist)
+		     current-prefix-arg))
+  (if (stringp feed) (setq feed (assoc feed org-feed-alist)))
+  (unless feed
+    (error "No such feed in `org-feed-alist"))
+  (let ((feed-name (car feed))
+	(feed-url (nth 1 feed))
+	(feed-file (nth 2 feed))
+	(feed-headline (nth 3 feed))
+	(feed-formatter (nth 4 feed))
+	feed-buffer feed-pos
+	entries entries2 old-guids current-guids new new-selected e)
+    (setq feed-buffer (org-feed-get-feed feed-url))
+    (unless (and feed-buffer (bufferp feed-buffer))
+      (error "Cannot get feed %s" feed-name))
+    (setq entries (org-feed-parse-feed feed-buffer)
+	  entries2 entries)
+    (ignore-errors (kill-buffer feed-buffer))
+    (save-excursion
+      (save-window-excursion
+	(setq feed-pos (org-feed-goto-inbox-internal feed-file feed-headline))
+	(setq old-guids (org-feed-get-old-guids feed-pos))
+	(while (setq e (pop entries2))
+	  (unless (member (plist-get e :guid) old-guids)
+	    (push (org-feed-parse-entry e) new)))
+	(if (not new)
+	    (progn (message "No new items in feed %s" feed-name) 0)
+	  ;; Format the new entries
+	  (run-hooks 'org-feed-before-adding-hook)
+	  (setq new-selected new)
+	  (when feed-formatter
+	    (setq new-selected (mapcar feed-formatter new-selected)))
+	  (setq new-selected (mapcar 'org-feed-format new-selected))
+	  (setq new-selected (delq nil new-selected))
+	  ;; Insert the new items
+	  (apply 'org-feed-add-items feed-pos new-selected)
+	  ;; Update the list of seen GUIDs in a drawer
+	  (if org-feed-assume-stable
+	      (apply 'org-feed-add-guids feed-pos 'replace entries)
+	    (apply 'org-feed-add-guids feed-pos nil new))
+	  (goto-char feed-pos)
+	  (show-children)
+	  (when org-feed-save-after-adding
+	    (save-buffer))
+	  (message "Added %d new item%s from feed %s to file %s, heading %s"
+		   (length new) (if (> (length new) 1) "s" "")
+		   feed-name
+		   (file-name-nondirectory feed-file) feed-headline)
+	  (run-hooks 'org-feed-after-adding-hook)
+	  (length new))))))
+
+;;;###autoload
+(defun org-feed-goto-inbox (feed)
+  "Go to the inbox that captures feed FEED."
+  (interactive
+   (list (if (= (length org-feed-alist) 1)
+	     (car org-feed-alist)
+	   (org-completing-read "Feed name: " org-feed-alist))))
+  (if (stringp feed) (setq feed (assoc feed org-feed-alist)))
+  (unless feed
+    (error "No such feed in `org-feed-alist"))
+  (org-feed-goto-inbox (nth 2 feed) (nth 3 feed)))
+
+(defun org-feed-goto-inbox-internal (file heading)
   "Find or create HEADING in FILE.
   "Find or create HEADING in FILE.
 Switch to that buffer, and return the position of that headline."
 Switch to that buffer, and return the position of that headline."
   (find-file file)
   (find-file file)
@@ -187,14 +286,21 @@ This will find the FEEDGUIDS drawer and extract the IDs."
 			    "[ \t]*\n[ \t]*")
 			    "[ \t]*\n[ \t]*")
 	nil))))
 	nil))))
 
 
-(defun org-feed-add-guids (pos &rest entries)
-  "Add GUIDs to the headline at POS."
+(defun org-feed-add-guids (pos replace &rest entries)
+  "Add GUIDs for headline at POS.
+When REPLACE is non-nil, replace all GUIDs by the new ones."
   (save-excursion
   (save-excursion
     (goto-char pos)
     (goto-char pos)
     (let ((end (save-excursion (org-end-of-subtree t t)))
     (let ((end (save-excursion (org-end-of-subtree t t)))
 	  guid)
 	  guid)
       (if (re-search-forward "^[ \t]*:FEEDGUIDS:[ \t]*\n" end t)
       (if (re-search-forward "^[ \t]*:FEEDGUIDS:[ \t]*\n" end t)
-	  (goto-char (match-end 0))
+	  (progn
+	    (goto-char (match-end 0))
+	    (when replace
+	      (delete-region (point)
+			     (save-excursion
+			       (and (re-search-forward "^[ \t]*:END:" nil t)
+				    (match-beginning 0))))))
 	(outline-next-heading)
 	(outline-next-heading)
 	(insert "  :FEEDGUIDS:\n  :END:\n")
 	(insert "  :FEEDGUIDS:\n  :END:\n")
 	(beginning-of-line 0))
 	(beginning-of-line 0))
@@ -303,61 +409,6 @@ containing the properties `:guid' and `:item-full-text'."
       (setq entry (plist-put entry :guid-permalink t))))
       (setq entry (plist-put entry :guid-permalink t))))
   entry)
   entry)
 
 
-;;;###autoload
-(defun org-feed-update (feed)
-  "Get inbox items from FEED.
-FEED can be a string with an association in `org-feed-alist', or
-it can be a list structured like an entry in `org-feed-alist'."
-  (interactive (list (org-completing-read "Feed name: " org-feed-alist)))
-  (if (stringp feed) (setq feed (assoc feed org-feed-alist)))
-  (unless feed
-    (error "No such feed in `org-feed-alist"))
-  (let ((feed-name (car feed))
-	(feed-url (nth 1 feed))
-	(feed-file (nth 2 feed))
-	(feed-headline (nth 3 feed))
-	(feed-formatter (nth 4 feed))
-	feed-buffer feed-pos
-	entries old-guids new new-selected e)
-    (setq feed-buffer (org-feed-get-feed feed-url))
-    (unless (and feed-buffer (bufferp feed-buffer))
-      (error "Cannot get feed %s" feed-name))
-    (setq entries (org-feed-parse-feed feed-buffer))
-    (ignore-errors (kill-buffer feed-buffer))
-    (save-excursion
-      (save-window-excursion
-	(setq feed-pos (org-feed-goto-inbox feed-file feed-headline))
-	(setq old-guids (org-feed-get-old-guids feed-pos))
-	(while (setq e (pop entries))
-	  (unless (member (plist-get e :guid) old-guids)
-	    (push (org-feed-parse-entry e) new)))
-	(if (not new)
-	    (message "No new items in feed %s" feed-name)
-	  ;; Format the new entries
-	  (setq new-selected new)
-	  (when feed-formatter
-	    (setq new-selected (mapcar feed-formatter new-selected)))
-	  (setq new-selected (mapcar 'org-feed-format new-selected))
-	  (setq new-selected (delq nil new-selected))
-	  ;; Insert them
-	  (apply 'org-feed-add-items feed-pos new-selected)
-	  (apply 'org-feed-add-guids feed-pos new)
-	  (goto-char feed-pos)
-	  (show-children)
-	  (when org-feed-save-after-adding
-	    (save-buffer))
-	  (message "Added %d new item%s from feed %s to file %s, heading %s"
-		   (length new) (if (> (length new) 1) "s" "")
-		   feed-name
-		   (file-name-nondirectory feed-file) feed-headline)
-	  (run-hooks 'org-feed-after-adding-hook))))))
-
-;;;###autoload
-(defun org-feed-update-all ()
-  "Get inbox items from all feeds in `org-feed-alist'."
-  (interactive)
-  (mapc 'org-feed-update org-feed-alist))
-
 (provide 'org-feed)
 (provide 'org-feed)
 
 
 ;;; org-feed.el ends here
 ;;; org-feed.el ends here