From fe540ef88713d889bc6275a3136b3af481a65f46 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 24 Oct 2011 22:04:21 +0530 Subject: [PATCH 01/13] Fix #880946 (Update for RTE News Recipe) --- recipes/rte.recipe | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/recipes/rte.recipe b/recipes/rte.recipe index cbf540069f..00034b6b01 100644 --- a/recipes/rte.recipe +++ b/recipes/rte.recipe @@ -1,15 +1,18 @@ -from calibre.web.feeds.news import BasicNewsRecipe - -class RTE(BasicNewsRecipe): - title = u'RTE News' - oldest_article = 7 - max_articles_per_feed = 100 - __author__ = u'Robin Phillips' - language = 'en_IE' - - remove_tags = [dict(attrs={'class':['topAd','botad','previousNextItem','headline','footerLinks','footernav']})] - - feeds = [(u'News', u'http://www.rte.ie/rss/news.xml'), (u'Sport', u'http://www.rte.ie/rss/sport.xml'), (u'Soccer', u'http://www.rte.ie/rss/soccer.xml'), (u'GAA', u'http://www.rte.ie/rss/gaa.xml'), (u'Rugby', u'http://www.rte.ie/rss/rugby.xml'), (u'Racing', u'http://www.rte.ie/rss/racing.xml'), (u'Business', u'http://www.rte.ie/rss/business.xml'), (u'Entertainment', u'http://www.rte.ie/rss/entertainment.xml')] - - def print_version(self, url): - return url.replace('http://www', 'http://m') +from calibre.web.feeds.news import BasicNewsRecipe + +class RTE(BasicNewsRecipe): + title = u'RTE News' + oldest_article = 7 + max_articles_per_feed = 100 + __author__ = u'Robin Phillips, Neil Grogan' + language = 'en_IE' + + remove_tags = [dict(attrs={'class':['share','global-return-to-top clearfix','sprite subnav-top-link','related-articles']}), + dict(id=['warning-lofi','masthead', 'nav-sections-menu', 'ad-leaderboard','article-nav']), + dict(name=['header','script', 'footer', 'style'])] + + + feeds = [(u'News', u'http://www.rte.ie/rss/news.xml'), (u'Sport', u'http://www.rte.ie/rss/sport.xml'), (u'Soccer', u'http://www.rte.ie/rss/soccer.xml'), (u'GAA', u'http://www.rte.ie/rss/gaa.xml'), (u'Rugby', u'http://www.rte.ie/rss/rugby.xml'), (u'Racing', u'http://www.rte.ie/rss/racing.xml'), (u'Business', u'http://www.rte.ie/rss/business.xml'), (u'Entertainment', u'http://www.rte.ie/rss/entertainment.xml')] + + def print_version(self, url): + return url.replace('http://www', 'http://m') \ No newline at end of file From 3ac697f8e02b13030de44009f6f4c0f9de91fe0c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 24 Oct 2011 22:05:45 +0530 Subject: [PATCH 02/13] ODT Input: CSS rationalization should not fail with non ascii class names --- src/calibre/ebooks/odt/input.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/calibre/ebooks/odt/input.py b/src/calibre/ebooks/odt/input.py index 927c43f66d..4e6bf5a4e2 100644 --- a/src/calibre/ebooks/odt/input.py +++ b/src/calibre/ebooks/odt/input.py @@ -74,7 +74,10 @@ class Extract(ODF2XHTML): style = style[0] css = style.text if css: - style.text, sel_map = self.do_filter_css(css) + css, sel_map = self.do_filter_css(css) + if not isinstance(css, unicode): + css = css.decode('utf-8', 'ignore') + style.text = css for x in root.xpath('//*[@class]'): extra = [] orig = x.get('class') From 5b600f708aed65acc36c16433f9d90d1b8a912ac Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 24 Oct 2011 22:07:26 +0530 Subject: [PATCH 03/13] Fix #880936 (Incorrect classification of news source) --- recipes/new_london_day.recipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/new_london_day.recipe b/recipes/new_london_day.recipe index bc8c44e40e..de79ce5673 100644 --- a/recipes/new_london_day.recipe +++ b/recipes/new_london_day.recipe @@ -8,7 +8,7 @@ class AdvancedUserRecipe1294342201(BasicNewsRecipe): title = u'New London Day' __author__ = 'Being' description = 'State, local and business news from New London, CT' - language = 'en_GB' + language = 'en' oldest_article = 1 max_articles_per_feed = 200 From 25b5a61e68997d7575423703247abec19ca8f7da Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 24 Oct 2011 22:11:40 +0530 Subject: [PATCH 04/13] FB2 Input: Dont choke on FB2 files that have empty embedded content tags. Fixes #880904 (can't view fb2 file - 'NoneType' object has no attribute 'strip') --- src/calibre/ebooks/fb2/input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/ebooks/fb2/input.py b/src/calibre/ebooks/fb2/input.py index 3c62b9671d..147e940eb4 100644 --- a/src/calibre/ebooks/fb2/input.py +++ b/src/calibre/ebooks/fb2/input.py @@ -127,7 +127,7 @@ class FB2Input(InputFormatPlugin): def extract_embedded_content(self, doc): self.binary_map = {} for elem in doc.xpath('./*'): - if 'binary' in elem.tag and elem.attrib.has_key('id'): + if elem.text and 'binary' in elem.tag and elem.attrib.has_key('id'): ct = elem.get('content-type', '') fname = elem.attrib['id'] ext = ct.rpartition('/')[-1].lower() From 628e7fef1fd24bad10c3a7323e9b7827ac537300 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 24 Oct 2011 22:15:53 +0530 Subject: [PATCH 05/13] Fix #880351 (Private bug) --- src/calibre/ebooks/mobi/writer2/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/ebooks/mobi/writer2/main.py b/src/calibre/ebooks/mobi/writer2/main.py index 4339532ee3..655aa12c9e 100644 --- a/src/calibre/ebooks/mobi/writer2/main.py +++ b/src/calibre/ebooks/mobi/writer2/main.py @@ -601,7 +601,7 @@ class MobiWriter(object): Write the PalmDB header ''' title = ascii_filename(unicode(self.oeb.metadata.title[0])).replace( - ' ', '_')[:32] + ' ', '_')[:31] title = title + (b'\0' * (32 - len(title))) now = int(time.time()) nrecords = len(self.records) From c6918632823b241c86e4287018c112393b0ba905 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Mon, 24 Oct 2011 21:27:05 -0300 Subject: [PATCH 06/13] Kobo add support for annotations --- src/calibre/devices/kobo/bookmark.py | 115 +++++++++++++++ src/calibre/devices/kobo/driver.py | 206 +++++++++++++++++++++++++-- 2 files changed, 313 insertions(+), 8 deletions(-) create mode 100644 src/calibre/devices/kobo/bookmark.py diff --git a/src/calibre/devices/kobo/bookmark.py b/src/calibre/devices/kobo/bookmark.py new file mode 100644 index 0000000000..d0856d5758 --- /dev/null +++ b/src/calibre/devices/kobo/bookmark.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai + +__license__ = 'GPL v3' +__copyright__ = '2011, Timothy Legge and Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +import os +from cStringIO import StringIO +from struct import unpack +from calibre.devices.usbms.driver import debug_print +from contextlib import closing + +import sqlite3 as sqlite + +class Bookmark(): # {{{ + ''' + A simple class fetching bookmark data + kobo-specific + ''' + def __init__(self, db_path, contentid, path, id, book_format, bookmark_extension): + self.book_format = book_format + self.bookmark_extension = bookmark_extension + self.book_length = 0 # Not Used + self.id = id + self.last_read = 0 + self.last_read_location = 0 # Not Used + self.path = path + self.timestamp = 0 + self.user_notes = None + self.db_path = db_path + self.contentid = contentid + self.percent_read = 0 + self.get_bookmark_data() + self.get_book_length() # Not Used + + def get_bookmark_data(self): + ''' Return the timestamp and last_read_location ''' + + user_notes = {} + self.timestamp = os.path.getmtime(self.path) + with closing(sqlite.connect(self.db_path)) as connection: + # return bytestrings if the content cannot the decoded as unicode + connection.text_factory = lambda x: unicode(x, "utf-8", "ignore") + + cursor = connection.cursor() + t = (self.contentid,) + + cursor.execute('select bm.bookmarkid, bm.contentid, bm.volumeid, ' + 'bm.text, bm.annotation, bm.ChapterProgress, ' + 'bm.StartContainerChildIndex, bm.StartOffset, c.BookTitle, ' + 'c.TITLE, c.volumeIndex, c.___NumPages ' + 'from Bookmark bm inner join Content c on ' + 'bm.contentid = c.contentid and ' + 'bm.volumeid = ? order by bm.volumeid, bm.chapterprogress', t) + + previous_chapter = 0 + for row in cursor: + current_chapter = row[10] + if previous_chapter == current_chapter: + bm_count = bm_count + 1 + else: + bm_count = 0 + + text = row[3] + annotation = row[4] + + # A dog ear (bent upper right corner) is a bookmark + if row[6] == row[7] == 0: # StartContainerChildIndex = StartOffset = 0 + e_type = 'Bookmark' + text = row[9] + # highlight is text with no annotation + elif text is not None and annotation is None: + e_type = 'Highlight' + elif text and annotation: + e_type = 'Annotation' + else: + e_type = 'Unknown annotation type' + + note_id = row[10] + bm_count + chapter_title = row[9] + # book_title = row[8] + chapter_progress = min(round(float(100*row[5]),2),100) + user_notes[note_id] = dict(id=self.id, + displayed_location=note_id, + type=e_type, + text=text, + annotation=annotation, + chapter=row[10], + chapter_title=chapter_title, + chapter_progress=chapter_progress) + previous_chapter = row[10] + # debug_print("e_type:" , e_type, '\t', 'loc: ', note_id, 'text: ', text, + # 'annotation: ', annotation, 'chapter_title: ', chapter_title, + # 'chapter_progress: ', chapter_progress, 'date: ') + + cursor.execute('select datelastread, ___PercentRead from content ' + 'where bookid is Null and ' + 'contentid = ?', t) + for row in cursor: + self.last_read = row[0] + self.percent_read = row[1] + # print row[1] + cursor.close() + +# self.last_read_location = self.last_read - self.pdf_page_offset + self.user_notes = user_notes + + + def get_book_length(self): +#TL self.book_length = 0 +#TL self.book_length = int(unpack('>I', record0[0x04:0x08])[0]) + pass + +# }}} diff --git a/src/calibre/devices/kobo/driver.py b/src/calibre/devices/kobo/driver.py index 9739046db0..50130f5ba0 100644 --- a/src/calibre/devices/kobo/driver.py +++ b/src/calibre/devices/kobo/driver.py @@ -2,21 +2,23 @@ # vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai __license__ = 'GPL v3' -__copyright__ = '2010, Timothy Legge and Kovid Goyal ' +__copyright__ = '2010, Timothy Legge and Kovid Goyal ' __docformat__ = 'restructuredtext en' -import os +import os, time, calendar import sqlite3 as sqlite from contextlib import closing from calibre.devices.usbms.books import BookList from calibre.devices.kobo.books import Book from calibre.devices.kobo.books import ImageWrapper +from calibre.devices.kobo.bookmark import Bookmark from calibre.devices.mime import mime_type_ext from calibre.devices.usbms.driver import USBMS, debug_print from calibre import prints from calibre.devices.usbms.books import CollectionsBookList from calibre.utils.magick.draw import save_cover_data_to from calibre.ptempfile import PersistentTemporaryFile +from calibre.ebooks.metadata import MetaInformation class KOBO(USBMS): @@ -24,7 +26,7 @@ class KOBO(USBMS): gui_name = 'Kobo Reader' description = _('Communicate with the Kobo Reader') author = 'Timothy Legge' - version = (1, 0, 10) + version = (1, 0, 11) dbversion = 0 fwversion = 0 @@ -47,6 +49,7 @@ class KOBO(USBMS): EBOOK_DIR_MAIN = '' SUPPORTS_SUB_DIRS = True + SUPPORTS_ANNOTATIONS = True VIRTUAL_BOOK_EXTENSIONS = frozenset(['kobo']) @@ -77,11 +80,6 @@ class KOBO(USBMS): self.book_class = Book self.dbversion = 7 - def create_annotations_path(self, mdata, device_path=None): - if device_path: - return device_path - return USBMS.create_annotations_path(self, mdata) - def books(self, oncard=None, end_session=True): from calibre.ebooks.metadata.meta import path_to_ext @@ -111,6 +109,7 @@ class KOBO(USBMS): if self.fwversion != '1.0' and self.fwversion != '1.4': self.has_kepubs = True + debug_print('Version of driver: ', self.version, 'Has kepubs:', self.has_kepubs) debug_print('Version of firmware: ', self.fwversion, 'Has kepubs:', self.has_kepubs) self.booklist_class.rebuild_collections = self.rebuild_collections @@ -893,3 +892,194 @@ class KOBO(USBMS): tf.write(r.read()) paths[idx] = tf.name return paths + + def create_annotations_path(self, mdata, device_path=None): + if device_path: + return device_path + return USBMS.create_annotations_path(self, mdata) + + def get_annotations(self, path_map): + EPUB_FORMATS = [u'epub'] + epub_formats = set(EPUB_FORMATS) + + def get_storage(): + storage = [] + if self._main_prefix: + storage.append(os.path.join(self._main_prefix, self.EBOOK_DIR_MAIN)) + if self._card_a_prefix: + storage.append(os.path.join(self._card_a_prefix, self.EBOOK_DIR_CARD_A)) + if self._card_b_prefix: + storage.append(os.path.join(self._card_b_prefix, self.EBOOK_DIR_CARD_B)) + return storage + + def resolve_bookmark_paths(storage, path_map): + pop_list = [] + book_ext = {} + for id in path_map: + file_fmts = set() + for fmt in path_map[id]['fmts']: + file_fmts.add(fmt) + bookmark_extension = None + if file_fmts.intersection(epub_formats): + book_extension = list(file_fmts.intersection(epub_formats))[0] + bookmark_extension = 'epub' + + if bookmark_extension: + for vol in storage: + bkmk_path = path_map[id]['path'] + bkmk_path = bkmk_path + if os.path.exists(bkmk_path): + path_map[id] = bkmk_path + book_ext[id] = book_extension + break + else: + pop_list.append(id) + else: + pop_list.append(id) + + # Remove non-existent bookmark templates + for id in pop_list: + path_map.pop(id) + return path_map, book_ext + + storage = get_storage() + path_map, book_ext = resolve_bookmark_paths(storage, path_map) + + bookmarked_books = {} + for id in path_map: + extension = os.path.splitext(path_map[id])[1] + ContentType = self.get_content_type_from_extension(extension) if extension != '' else self.get_content_type_from_path(path_map[id]) + ContentID = self.contentid_from_path(path_map[id], ContentType) + + bookmark_ext = extension + + db_path = self.normalize_path(self._main_prefix + '.kobo/KoboReader.sqlite') + myBookmark = Bookmark(db_path, ContentID, path_map[id], id, book_ext[id], bookmark_ext) + bookmarked_books[id] = self.UserAnnotation(type='kobo_bookmark', value=myBookmark) + + # This returns as job.result in gui2.ui.annotations_fetched(self,job) + return bookmarked_books + + def generate_annotation_html(self, bookmark): + from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag, NavigableString + # Returns
...
+ last_read_location = bookmark.last_read_location + timestamp = bookmark.timestamp + percent_read = bookmark.percent_read + debug_print("Date: ", bookmark.last_read) + try: + last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(calendar.timegm(time.strptime(bookmark.last_read, "%Y-%m-%dT%H:%M:%S")))) + except: + last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(calendar.timegm(time.strptime(bookmark.last_read, "%Y-%m-%dT%H:%M:%S.%f")))) + + # debug_print("Percent read: ", percent_read) + ka_soup = BeautifulSoup() + dtc = 0 + divTag = Tag(ka_soup,'div') + divTag['class'] = 'user_annotations' + + # Add the last-read location + spanTag = Tag(ka_soup, 'span') + spanTag['style'] = 'font-weight:normal' + if bookmark.book_format == 'epub': + spanTag.insert(0,NavigableString( + _("
Book Last Read: %(time)s
Percentage Read: %(pr)d%%
") % \ + dict(time=last_read, + #loc=last_read_location, + pr=percent_read))) + else: + spanTag.insert(0,NavigableString( + _("
Book Last Read: %(time)s
Percentage Read: %(pr)d%%
") % \ + dict(time=last_read, + #loc=last_read_location, + pr=percent_read))) + + divTag.insert(dtc, spanTag) + dtc += 1 + divTag.insert(dtc, Tag(ka_soup,'br')) + dtc += 1 + + if bookmark.user_notes: + user_notes = bookmark.user_notes + annotations = [] + + # Add the annotations sorted by location + for location in sorted(user_notes): + if user_notes[location]['type'] == 'Bookmark': + annotations.append( + _('Chapter %(chapter)d: %(chapter_title)s
%(typ)s
Chapter Progress: %(chapter_progress)s%%
%(annotation)s

') % \ + dict(chapter=user_notes[location]['chapter'], + dl=user_notes[location]['displayed_location'], + typ=user_notes[location]['type'], + chapter_title=user_notes[location]['chapter_title'], + chapter_progress=user_notes[location]['chapter_progress'], + annotation=user_notes[location]['annotation'] if user_notes[location]['annotation'] is not None else "")) + elif user_notes[location]['type'] == 'Highlight': + annotations.append( + _('Chapter %(chapter)d: %(chapter_title)s
%(typ)s
Chapter Progress: %(chapter_progress)s%%
Highlight: %(text)s

') % \ + dict(chapter=user_notes[location]['chapter'], + dl=user_notes[location]['displayed_location'], + typ=user_notes[location]['type'], + chapter_title=user_notes[location]['chapter_title'], + chapter_progress=user_notes[location]['chapter_progress'], + text=user_notes[location]['text'])) + elif user_notes[location]['type'] == 'Annotation': + annotations.append( + _('Chapter %(chapter)d: %(chapter_title)s
%(typ)s
Chapter Progress: %(chapter_progress)s%%
Highlight: %(text)s
Notes: %(annotation)s

') % \ + dict(chapter=user_notes[location]['chapter'], + dl=user_notes[location]['displayed_location'], + typ=user_notes[location]['type'], + chapter_title=user_notes[location]['chapter_title'], + chapter_progress=user_notes[location]['chapter_progress'], + text=user_notes[location]['text'], + annotation=user_notes[location]['annotation'])) + else: + annotations.append( + _('Chapter %(chapter)d: %(chapter_title)s
%(typ)s
Chapter Progress: %(chapter_progress)s%%
Highlight: %(text)s
Notes: %(annotation)s

') % \ + dict(chapter=user_notes[location]['chapter'], + dl=user_notes[location]['displayed_location'], + typ=user_notes[location]['type'], + chapter_title=user_notes[location]['chapter_title'], + chapter_progress=user_notes[location]['chapter_progress'], + text=user_notes[location]['text'], \ + annotation=user_notes[location]['annotation'])) + + for annotation in annotations: + divTag.insert(dtc, annotation) + dtc += 1 + + ka_soup.insert(0,divTag) + return ka_soup + + def add_annotation_to_library(self, db, db_id, annotation): + from calibre.ebooks.BeautifulSoup import Tag + bm = annotation + ignore_tags = set(['Catalog', 'Clippings']) + + if bm.type == 'kobo_bookmark': + mi = db.get_metadata(db_id, index_is_id=True) + user_notes_soup = self.generate_annotation_html(bm.value) + if mi.comments: + a_offset = mi.comments.find('
') + ad_offset = mi.comments.find('
') + + if a_offset >= 0: + mi.comments = mi.comments[:a_offset] + if ad_offset >= 0: + mi.comments = mi.comments[:ad_offset] + if set(mi.tags).intersection(ignore_tags): + return + if mi.comments: + hrTag = Tag(user_notes_soup,'hr') + hrTag['class'] = 'annotations_divider' + user_notes_soup.insert(0, hrTag) + + mi.comments += unicode(user_notes_soup.prettify()) + else: + mi.comments = unicode(user_notes_soup.prettify()) + # Update library comments + db.set_comment(db_id, mi.comments) + + # Add bookmark file to db_id + db.add_format_with_hooks(db_id, bm.value.bookmark_extension, + bm.value.path, index_is_id=True) From 2baaf359249b07944a7c475ef99da1afd923b613 Mon Sep 17 00:00:00 2001 From: John Schember Date: Mon, 24 Oct 2011 20:37:05 -0400 Subject: [PATCH 07/13] Fix bug #880930: Fix rb format compression. --- src/calibre/ebooks/rb/writer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/calibre/ebooks/rb/writer.py b/src/calibre/ebooks/rb/writer.py index f71b103fbd..fc73d25b2d 100644 --- a/src/calibre/ebooks/rb/writer.py +++ b/src/calibre/ebooks/rb/writer.py @@ -104,8 +104,9 @@ class RBWriter(object): size = len(text) pages = [] - for i in range(0, (len(text) / TEXT_RECORD_SIZE) + 1): - pages.append(zlib.compress(text[i * TEXT_RECORD_SIZE : (i * TEXT_RECORD_SIZE) + TEXT_RECORD_SIZE], 9)) + for i in range(0, (len(text) + TEXT_RECORD_SIZE-1) / TEXT_RECORD_SIZE): + zobj = zlib.compressobj(9, zlib.DEFLATED, 13, 8, 0) + pages.append(zobj.compress(text[i * TEXT_RECORD_SIZE : (i * TEXT_RECORD_SIZE) + TEXT_RECORD_SIZE]) + zobj.flush()) return (size, pages) From 3f7a72120b75a03912d2b2a939e98bdb25314f24 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 25 Oct 2011 07:07:51 +0530 Subject: [PATCH 08/13] Calibre Blog by Krittika Goyal --- recipes/calibre_blog.recipe | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 recipes/calibre_blog.recipe diff --git a/recipes/calibre_blog.recipe b/recipes/calibre_blog.recipe new file mode 100644 index 0000000000..468876ef3d --- /dev/null +++ b/recipes/calibre_blog.recipe @@ -0,0 +1,18 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class CalibreBlog(BasicNewsRecipe): + title = u'Calibre Blog' + language = 'en' + __author__ = 'Krittika Goyal' + oldest_article = 1000 #days + max_articles_per_feed = 5 + use_embedded_content = False + + no_stylesheets = True + auto_cleanup = True + + + feeds = [ +('Article', + 'http://blog.calibre-ebook.com/feeds/posts/default'), +] From ebbda632bf0ee55d15fdc424e7c11b652920f317 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 25 Oct 2011 07:12:06 +0530 Subject: [PATCH 09/13] revert changes to RTE News --- recipes/rte.recipe | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/recipes/rte.recipe b/recipes/rte.recipe index 00034b6b01..cbf540069f 100644 --- a/recipes/rte.recipe +++ b/recipes/rte.recipe @@ -1,18 +1,15 @@ -from calibre.web.feeds.news import BasicNewsRecipe - -class RTE(BasicNewsRecipe): - title = u'RTE News' - oldest_article = 7 - max_articles_per_feed = 100 - __author__ = u'Robin Phillips, Neil Grogan' - language = 'en_IE' - - remove_tags = [dict(attrs={'class':['share','global-return-to-top clearfix','sprite subnav-top-link','related-articles']}), - dict(id=['warning-lofi','masthead', 'nav-sections-menu', 'ad-leaderboard','article-nav']), - dict(name=['header','script', 'footer', 'style'])] - - - feeds = [(u'News', u'http://www.rte.ie/rss/news.xml'), (u'Sport', u'http://www.rte.ie/rss/sport.xml'), (u'Soccer', u'http://www.rte.ie/rss/soccer.xml'), (u'GAA', u'http://www.rte.ie/rss/gaa.xml'), (u'Rugby', u'http://www.rte.ie/rss/rugby.xml'), (u'Racing', u'http://www.rte.ie/rss/racing.xml'), (u'Business', u'http://www.rte.ie/rss/business.xml'), (u'Entertainment', u'http://www.rte.ie/rss/entertainment.xml')] - - def print_version(self, url): - return url.replace('http://www', 'http://m') \ No newline at end of file +from calibre.web.feeds.news import BasicNewsRecipe + +class RTE(BasicNewsRecipe): + title = u'RTE News' + oldest_article = 7 + max_articles_per_feed = 100 + __author__ = u'Robin Phillips' + language = 'en_IE' + + remove_tags = [dict(attrs={'class':['topAd','botad','previousNextItem','headline','footerLinks','footernav']})] + + feeds = [(u'News', u'http://www.rte.ie/rss/news.xml'), (u'Sport', u'http://www.rte.ie/rss/sport.xml'), (u'Soccer', u'http://www.rte.ie/rss/soccer.xml'), (u'GAA', u'http://www.rte.ie/rss/gaa.xml'), (u'Rugby', u'http://www.rte.ie/rss/rugby.xml'), (u'Racing', u'http://www.rte.ie/rss/racing.xml'), (u'Business', u'http://www.rte.ie/rss/business.xml'), (u'Entertainment', u'http://www.rte.ie/rss/entertainment.xml')] + + def print_version(self, url): + return url.replace('http://www', 'http://m') From 26c407795cd8c4d5d26ea7751073144ea83024c0 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 25 Oct 2011 07:17:11 +0530 Subject: [PATCH 10/13] Silicon Republic by Neil Grogan. Fixes #881066 (Enhancement: Add Silicon Republic News Recipe) --- recipes/silicon_republic.recipe | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 recipes/silicon_republic.recipe diff --git a/recipes/silicon_republic.recipe b/recipes/silicon_republic.recipe new file mode 100644 index 0000000000..0b5f17786e --- /dev/null +++ b/recipes/silicon_republic.recipe @@ -0,0 +1,22 @@ +__license__ = 'GPL v3' +__copyright__ = '2011 Neil Grogan' +# +# Silicon Republic Recipe +# + +from calibre.web.feeds.news import BasicNewsRecipe + +class SiliconRepublic(BasicNewsRecipe): + title = u'Silicon Republic' + oldest_article = 7 + max_articles_per_feed = 100 + __author__ = u'Neil Grogan' + language = 'en_IE' + + remove_tags = [dict(attrs={'class':['thumb','txt','compactbox','icons','catlist','catlistinner','taglist','taglistinner','social','also-in','also-in-inner','also-in-footer','zonek-dfp','paneladvert','rcadvert','panel','h2b']}), + dict(id=['header','logo','header-right','sitesearch','rsslinks','topnav','topvideos','topvideos-list','topnews','topnews-list','slideshow','slides','compactheader','compactnews','compactfeatures','article-type','contactlinks-header','banner-zone-k-dfp','footer-related','directory-services','also-in-section','featuredrelated1','featuredrelated2','featuredrelated3','featuredrelated4','advert2-dfp']), + dict(name=['script', 'style'])] + + + feeds = [(u'News', u'http://www.siliconrepublic.com/feeds/')] + From f4ef6bcecdc7935351e9fc1e98984ee16a886252 Mon Sep 17 00:00:00 2001 From: Timothy Legge Date: Mon, 24 Oct 2011 22:52:39 -0300 Subject: [PATCH 11/13] Kobo annotations fixes --- src/calibre/devices/kobo/bookmark.py | 3 ++- src/calibre/devices/kobo/driver.py | 14 +++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/calibre/devices/kobo/bookmark.py b/src/calibre/devices/kobo/bookmark.py index d0856d5758..56e76b39e9 100644 --- a/src/calibre/devices/kobo/bookmark.py +++ b/src/calibre/devices/kobo/bookmark.py @@ -55,6 +55,7 @@ class Bookmark(): # {{{ 'bm.volumeid = ? order by bm.volumeid, bm.chapterprogress', t) previous_chapter = 0 + bm_count = 0 for row in cursor: current_chapter = row[10] if previous_chapter == current_chapter: @@ -70,7 +71,7 @@ class Bookmark(): # {{{ e_type = 'Bookmark' text = row[9] # highlight is text with no annotation - elif text is not None and annotation is None: + elif text is not None and (annotation is None or annotation == ""): e_type = 'Highlight' elif text and annotation: e_type = 'Annotation' diff --git a/src/calibre/devices/kobo/driver.py b/src/calibre/devices/kobo/driver.py index 50130f5ba0..e45710bb5c 100644 --- a/src/calibre/devices/kobo/driver.py +++ b/src/calibre/devices/kobo/driver.py @@ -967,11 +967,15 @@ class KOBO(USBMS): timestamp = bookmark.timestamp percent_read = bookmark.percent_read debug_print("Date: ", bookmark.last_read) - try: - last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(calendar.timegm(time.strptime(bookmark.last_read, "%Y-%m-%dT%H:%M:%S")))) - except: - last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(calendar.timegm(time.strptime(bookmark.last_read, "%Y-%m-%dT%H:%M:%S.%f")))) - + if bookmark.last_read is not None: + try: + last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(calendar.timegm(time.strptime(bookmark.last_read, "%Y-%m-%dT%H:%M:%S")))) + except: + last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(calendar.timegm(time.strptime(bookmark.last_read, "%Y-%m-%dT%H:%M:%S.%f")))) + else: + #self.datetime = time.gmtime() + last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()) + # debug_print("Percent read: ", percent_read) ka_soup = BeautifulSoup() dtc = 0 From 7706ffe6aad6eec6f89d32b56687441b4f5e3c21 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 25 Oct 2011 11:26:04 +0530 Subject: [PATCH 12/13] MOBI Output: Fix use of list elements as link anchors caused links to always point to start of list. Fixes #879391 (Private bug) --- src/calibre/ebooks/mobi/mobiml.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/calibre/ebooks/mobi/mobiml.py b/src/calibre/ebooks/mobi/mobiml.py index 4dfcf5d7b6..12ea561469 100644 --- a/src/calibre/ebooks/mobi/mobiml.py +++ b/src/calibre/ebooks/mobi/mobiml.py @@ -138,6 +138,7 @@ class MobiMLizer(object): self.mobimlize_elem(body, stylizer, BlockState(nbody), [FormatState()]) item.data = nroot + #print etree.tostring(nroot) def mobimlize_font(self, ptsize): return self.fnums[self.fmap[ptsize]] @@ -233,9 +234,19 @@ class MobiMLizer(object): elif tag in TABLE_TAGS: para.attrib['valign'] = 'top' if istate.ids: - last = bstate.body[-1] - for id in istate.ids: - last.addprevious(etree.Element(XHTML('a'), attrib={'id': id})) + for id_ in istate.ids: + anchor = etree.Element(XHTML('a'), attrib={'id': id_}) + if tag == 'li': + try: + last = bstate.body[-1][-1] + except: + break + last.insert(0, anchor) + anchor.tail = last.text + last.text = None + else: + last = bstate.body[-1] + last.addprevious(anchor) istate.ids.clear() if not text: return From 5da7897c45f62f3fb65a31a8b243b8223d0f46a2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 25 Oct 2011 11:56:05 +0530 Subject: [PATCH 13/13] Book details panel: Show tooltip only when hovering over cover, not the rest of the book information. Fixes #876454 ([Enhancement] Turn off Balloon Help) --- src/calibre/gui2/book_details.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index fc05c86531..b710b62177 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -326,6 +326,18 @@ class CoverView(QWidget): # {{{ if id_ is not None: self.cover_removed.emit(id_) + def update_tooltip(self, current_path): + try: + sz = self.pixmap.size() + except: + sz = QSize(0, 0) + self.setToolTip( + '

'+_('Double-click to open Book Details window') + + '

' + _('Path') + ': ' + current_path + + '

' + _('Cover size: %(width)d x %(height)d')%dict( + width=sz.width(), height=sz.height()) + ) + # }}} # Book Info {{{ @@ -561,16 +573,7 @@ class BookDetails(QWidget): # {{{ def update_layout(self): self._layout.do_layout(self.rect()) - try: - sz = self.cover_view.pixmap.size() - except: - sz = QSize(0, 0) - self.setToolTip( - '

'+_('Double-click to open Book Details window') + - '

' + _('Path') + ': ' + self.current_path + - '

' + _('Cover size: %(width)d x %(height)d')%dict( - width=sz.width(), height=sz.height()) - ) + self.cover_view.update_tooltip(self.current_path) def reset_info(self): self.show_data(Metadata(_('Unknown')))