#!/usr/bin/env python from subprocess import Popen, PIPE import plistlib from calibre.web.feeds.news import BasicNewsRecipe class SafariReadingListRecipe(BasicNewsRecipe): # General info about this recipe. title = 'Safari Reading List' description = 'Generate an ebook from the unread items in your Safari Reading List. (For Mac OS X only.)' __author__ = 'Jim DeVona' __version__ = '1.2' # Configure Calibre's processing of each article. Unlike most recipes, this # recipe is not fetching articles from a single known source, so we can't # really predict how the articles will be formatted. Use Readability. auto_cleanup = True no_stylesheets = True remove_javascript = True def parse_index(self): articles = [] # First, get the xml_data containing Safari's bookmarks. xml_pipe = Popen('/usr/bin/plutil -convert xml1 -o - ~/Library/Safari/Bookmarks.plist', shell=True, stdout=PIPE).stdout bm_plist = plistlib.readPlist(xml_pipe) xml_pipe.close() # Locate the part of the property list containing the Reading List bookmarks rl_section = filter(lambda rec: 'com.apple.ReadingList' == rec.get('Title'), bm_plist['Children']) reading_list = rl_section[0].get('Children') if None == reading_list: # Raise an exception to prevent the recipe from generating an empty book. # Results in an annoying error displayed to the user, but does not block other scheduled recipes. # Reference: http://www.mobileread.com/forums/showthread.php?p=1370010#post1370010 raise Exception, "There are no Reading List articles." # Loop through the Reading List items, starting with the oldest reading_list.reverse() for rl_item in reading_list: # We're only interested in Unread items, not items that have already been viewed. if None != rl_item['ReadingList'].get('DateLastViewed'): continue # Extract metadata about the article. item_title = rl_item['URIDictionary']['title'] item_preview = rl_item['ReadingList'].get('PreviewText', '') item_url = rl_item['URLString'] item_fetchdate = rl_item['ReadingList'].get('DateLastFetched') if None == item_fetchdate: item_fetchdate = rl_item['ReadingListNonSync'].get('DateLastFetched') item_author = '' articles.append({ 'title': item_title, 'url': item_url, 'description': item_preview, 'date': item_fetchdate, 'author': item_author}) return [('Reading List Items', articles)]