diff --git a/resources/recipes/eu_commission.recipe b/resources/recipes/eu_commission.recipe new file mode 100644 index 0000000000..01d2a31a40 --- /dev/null +++ b/resources/recipes/eu_commission.recipe @@ -0,0 +1,58 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +LANGUAGE = 'de' + +def feedlink(num): + return u'http://europa.eu/rapid/syndication/QuickRSSAction.do?id='+\ + str(num)+'&lang='+ LANGUAGE + +class EUCommissionPress(BasicNewsRecipe): + title = u'Pressemitteilungen der EU Kommission pro Politikbereich' + oldest_article = 7 + max_articles_per_feed = 100 + no_stylesheets = True + cover_url = 'http://ec.europa.eu/wel/template_2007/images/banners/banner-background.jpg' + __author__ = 'malfi' + language = LANGUAGE + keep_only_tags = [] + keep_only_tags.append(dict(name = 'div', attrs = {'class': 'pressReleaseContentMain'})) + remove_tags = [] + + + feeds = [ + (u'Pressemitteilung des Tages',feedlink(64)), + (u'Presidency',feedlink(137)), + (u'Foreign affairs and security policy',feedlink(138)), + (u'Agriculture and rural development',feedlink(139)), + (u'Budget and financial programming ',feedlink(140)), + (u'Climate action',feedlink(141)), + (u'Competition',feedlink(142)), + (u'Development',feedlink(143)), + (u'Digital agenda',feedlink(144)), + (u'Economic and monetary affairs',feedlink(145)), + (u'Education, culture, multilingualism and youth ',feedlink(146)), + (u'Employment, social Affairs and inclusion ',feedlink(147)), + (u'Energy',feedlink(148)), + (u'Enlargment and European neighbourhood policy ',feedlink(149)), + (u'Environment',feedlink(150)), + (u'Health and consumer policy',feedlink(151)), + (u'Home affairs',feedlink(152)), + (u'Industry and entrepreneurship',feedlink(153)), + (u'Inter-Institutional relations and administration',feedlink(154)), + (u'Internal market and services',feedlink(155)), + (u'International cooperation, humanitarian aid and crisis response',feedlink(156)), + (u'Justice, fundamental rights and citizenship',feedlink(157)), + (u'Maritime affairs and fisheries',feedlink(158)), + (u'Regional policy',feedlink(159)), + (u'Research and innovation',feedlink(160)), + (u'Taxation and customs union, audit and anti-fraud',feedlink(161)), + (u'Trade',feedlink(162)), + (u'Transport',feedlink(163)) + ] + extra_css = ''' + h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;} + h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;} + p{font-family:Arial,Helvetica,sans-serif;font-size:small;} + body{font-family:Helvetica,Arial,sans-serif;font-size:small;} + ''' + diff --git a/resources/recipes/german_gov.recipe b/resources/recipes/german_gov.recipe new file mode 100644 index 0000000000..afe55d89c9 --- /dev/null +++ b/resources/recipes/german_gov.recipe @@ -0,0 +1,28 @@ +import re + +from calibre.web.feeds.news import BasicNewsRecipe + +class GermanGovermentPress(BasicNewsRecipe): + title = u'Pressemitteilungen der Bundesregierung' + oldest_article = 14 + __author__ = 'malfi' + max_articles_per_feed = 100 + no_stylesheets = True + cover_url = 'http://www.bundesregierung.de/static/images/logoBR.gif' + language = 'de' + keep_only_tags = [] + keep_only_tags.append(dict(name = 'h2')) + keep_only_tags.append(dict(name = 'div', attrs = {'class': 'textblack'})) + keep_only_tags.append(dict(name = 'div', attrs = {'class': 'subtitle'})) + keep_only_tags.append(dict(name = 'div', attrs = {'class': 'text'})) + remove_tags = [] + feeds = [ (u'Pressemitteilungen',u'http://www.bundesregierung.de/Webs/Breg/DE/Service/RSS/Functions/bundesregierungPressemitteilungenRSS20,templateId=renderNewsfeed.rdf') ] + extra_css = ''' + h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;} + h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;} + p{font-family:Arial,Helvetica,sans-serif;font-size:small;} + body{font-family:Helvetica,Arial,sans-serif;font-size:small;} + ''' + def print_version(self, url): + m = re.search(r'^(.*).html$', url) + return str(m.group(1)) + ',layoutVariant=Druckansicht.html' diff --git a/resources/recipes/la_jornada.recipe b/resources/recipes/la_jornada.recipe index eb3aa094d2..3ee6dc4b3f 100644 --- a/resources/recipes/la_jornada.recipe +++ b/resources/recipes/la_jornada.recipe @@ -54,10 +54,7 @@ class LaJornada_mx(BasicNewsRecipe): preprocess_regexps = [ (re.compile( r'
(.*)

' ,re.DOTALL|re.IGNORECASE) - ,lambda match: '

' + match.group(1) + '

'), - (re.compile( r'(.*?)' - ,re.DOTALL|re.IGNORECASE) - ,lambda match: '"' + match.group(1) + '"') + ,lambda match: '

' + match.group(1) + '

') ] keep_only_tags = [ diff --git a/resources/recipes/wash_post.recipe b/resources/recipes/wash_post.recipe index ae56172674..fb6d5bc598 100644 --- a/resources/recipes/wash_post.recipe +++ b/resources/recipes/wash_post.recipe @@ -31,8 +31,9 @@ class WashingtonPost(BasicNewsRecipe): ('Education', 'http://www.washingtonpost.com/wp-dyn/rss/education/index.xml'), ('Style', 'http://www.washingtonpost.com/wp-dyn/rss/print/style/index.xml'), - ('Sports', - 'http://feeds.washingtonpost.com/wp-dyn/rss/linkset/2010/08/19/LI2010081904067_xml'), + ('NFL Sports', + 'http://www.washingtonpost.com/wp-dyn/rss/sports/index/nfl/index.xml'), + ('Redskins', 'http://www.washingtonpost.com/wp-dyn/rss/sports/redskins/index.xml'), ('Editorials', 'http://www.washingtonpost.com/wp-dyn/rss/linkset/2005/05/30/LI2005053000331.xml'), ] diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index bd766827a5..681d953c9b 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -454,7 +454,7 @@ from calibre.customize.profiles import input_profiles, output_profiles from calibre.devices.apple.driver import ITUNES from calibre.devices.hanlin.driver import HANLINV3, HANLINV5, BOOX, SPECTRA from calibre.devices.blackberry.driver import BLACKBERRY -from calibre.devices.cybook.driver import CYBOOK +from calibre.devices.cybook.driver import CYBOOK, ORIZON from calibre.devices.eb600.driver import EB600, COOL_ER, SHINEBOOK, \ POCKETBOOK360, GER2, ITALICA, ECLICTO, DBOOK, INVESBOOK, \ BOOQ, ELONEX, POCKETBOOK301, MENTOR @@ -535,6 +535,7 @@ plugins += [ HANLINV5, BLACKBERRY, CYBOOK, + ORIZON, ILIAD, IREXDR1000, IREXDR800, diff --git a/src/calibre/devices/cybook/driver.py b/src/calibre/devices/cybook/driver.py index 7c436a7d0e..becb7912a9 100644 --- a/src/calibre/devices/cybook/driver.py +++ b/src/calibre/devices/cybook/driver.py @@ -5,7 +5,7 @@ __copyright__ = '2009, John Schember ' __docformat__ = 'restructuredtext en' ''' -Device driver for Bookeen's Cybook Gen 3 and Opus +Device driver for Bookeen's Cybook Gen 3 and Opus and Orizon ''' import os @@ -56,3 +56,23 @@ class CYBOOK(USBMS): if isunix: return device_info[3] == 'Bookeen' and (device_info[4] == 'Cybook Gen3' or device_info[4] == 'Cybook Opus') return True + +class ORIZON(CYBOOK): + + name = 'Orizon Device Interface' + gui_name = 'Orizon' + description = _('Communicate with the Cybook Orizon eBook reader.') + + BCD = [0x319] + + WINDOWS_MAIN_MEM = re.compile(r'CYBOOK_ORIZON__-FD') + WINDOWS_CARD_A_MEM = re.compile('CYBOOK_ORIZON__-SD') + + EBOOK_DIR_MAIN = EBOOK_DIR_CARD_A = 'Digital Editions' + + @classmethod + def can_handle(cls, device_info, debug=False): + if isunix: + return device_info[3] == 'Bookeen' and device_info[4] == 'Cybook Orizon' + return True + diff --git a/src/calibre/devices/prs505/sony_cache.py b/src/calibre/devices/prs505/sony_cache.py index c2899f54ee..f271329fc8 100644 --- a/src/calibre/devices/prs505/sony_cache.py +++ b/src/calibre/devices/prs505/sony_cache.py @@ -610,7 +610,11 @@ class XMLCache(object): # is not new, compare its Sony DB date against localtime and gmtime. # Count the matches. When we must set a date, use the one with the most # matches. Use localtime if the case of a tie, and hope it is right. - timestamp = os.path.getmtime(path) + try: + timestamp = os.path.getmtime(path) + except: + debug_print('Failed to get timestamp for:', path) + timestamp = time.time() rec_date = record.get('date', None) def clean(x): @@ -627,12 +631,12 @@ class XMLCache(object): pass if not getattr(book, '_new_book', False): # book is not new - if record.get('tz', None) is not None: - use_tz_var = True - if strftime(timestamp, zone=time.gmtime) == rec_date: - gtz_count += 1 - elif strftime(timestamp, zone=time.localtime) == rec_date: - ltz_count += 1 + if record.get('tz', None) is not None: + use_tz_var = True + if strftime(timestamp, zone=time.gmtime) == rec_date: + gtz_count += 1 + elif strftime(timestamp, zone=time.localtime) == rec_date: + ltz_count += 1 else: # book is new. Set the time using the current votes if use_tz_var: tz = time.localtime @@ -646,7 +650,10 @@ class XMLCache(object): debug_print("Use GMT TZ for new book", book.lpath) date = strftime(timestamp, zone=tz) record.set('date', clean(date)) - record.set('size', clean(str(os.stat(path).st_size))) + try: + record.set('size', clean(str(os.stat(path).st_size))) + except: + record.set('size', '0') title = book.title if book.title else _('Unknown') record_set('title', title) ts = book.title_sort diff --git a/src/calibre/gui2/wizard/__init__.py b/src/calibre/gui2/wizard/__init__.py index 54d034a705..2ac0908ea9 100644 --- a/src/calibre/gui2/wizard/__init__.py +++ b/src/calibre/gui2/wizard/__init__.py @@ -153,6 +153,11 @@ class CybookOpus(CybookG3): output_profile = 'cybook_opus' id = 'cybook_opus' +class CybookOrizon(CybookOpus): + + name = 'Cybook Orizon' + id = 'cybook_orizon' + class PocketBook360(CybookOpus): manufacturer = 'PocketBook' diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py index ad9aebac1b..2008d20c8f 100644 --- a/src/calibre/library/catalog.py +++ b/src/calibre/library/catalog.py @@ -3,14 +3,13 @@ __license__ = 'GPL v3' __copyright__ = '2010, Greg Riker ' -import base64, codecs, cStringIO, datetime, htmlentitydefs, os, re, shutil, time, zlib - +import codecs, datetime, htmlentitydefs, os, re, shutil, time, zlib +from contextlib import closing from collections import namedtuple from copy import deepcopy -from PIL import Image as PILImage from xml.sax.saxutils import escape -from calibre import fit_image, prints, prepare_string_for_xml, strftime +from calibre import prints, prepare_string_for_xml, strftime from calibre.constants import preferred_encoding from calibre.customize import CatalogPlugin from calibre.customize.conversion import OptionRecommendation, DummyReporter @@ -20,6 +19,7 @@ from calibre.utils.config import config_dir from calibre.utils.date import isoformat, now as nowf from calibre.utils.logging import default_log as log from calibre.utils.zipfile import ZipFile, ZipInfo +from calibre.utils.magick.draw import thumbnail FIELDS = ['all', 'author_sort', 'authors', 'comments', 'cover', 'formats', 'id', 'isbn', 'ondevice', 'pubdate', 'publisher', 'rating', @@ -1658,7 +1658,7 @@ class EPUB_MOBI(CatalogPlugin): aTag.insert(0, title['author']) # Prefix author with read|reading|none symbol or missing symbol - if self.opts.wishlist_tag in title['tags']: + if self.opts.wishlist_tag in title.get('tags', []): authorTag.insert(0, NavigableString(self.MISSING_SYMBOL + " by ")) else: if title['read']: @@ -2044,7 +2044,7 @@ class EPUB_MOBI(CatalogPlugin): ptc = 0 # book with read|reading|unread symbol or wishlist item - if self.opts.wishlist_tag in book['tags']: + if self.opts.wishlist_tag in book.get('tags', []): pBookTag['class'] = "wishlist_item" pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL)) ptc += 1 @@ -4469,70 +4469,41 @@ class EPUB_MOBI(CatalogPlugin): Thumbs are cached with the full cover's crc. If the crc doesn't match, the cover has been changed since the thumb was cached and needs to be replaced. - 2010-11-13 switched to PIL library for faster thumb generation - ''' - if True: - # Generate crc for current cover - #self.opts.log.info(" generateThumbnail():") - data = open(title['cover'], 'rb') - stream = cStringIO.StringIO() - stream.write(data.read()) - cover_crc = hex(zlib.crc32(stream.getvalue())) - stream.close() + # Generate crc for current cover + #self.opts.log.info(" generateThumbnail():") + data = open(title['cover'], 'rb').read() + cover_crc = hex(zlib.crc32(data)) - # Test cache for uuid + # Test cache for uuid + with closing(ZipFile(self.__archive_path, mode='r')) as zfr: try: - zfr = ZipFile(self.__archive_path, mode='r') t_info = zfr.getinfo(title['uuid']) + except: + pass + else: if t_info.comment == cover_crc: # uuid found in cache with matching crc thumb_data = zfr.read(title['uuid']) zfr.extract(title['uuid'],image_dir) - zfr.close() os.rename(os.path.join(image_dir,title['uuid']), - os.path.join(image_dir,thumb_file)) + os.path.join(image_dir,thumb_file)) return - else: - # uuid found in cache, but crc mismatch - zfr.close() - except: - # uuid not found in cache - zfr.close() - # Create a new thumb - im = PILImage.open(title['cover']) - scaled, width, height = fit_image(im.size[0],im.size[1], - self.thumbWidth, self.thumbHeight) - im = im.resize((int(width),int(height)), PILImage.ANTIALIAS) + # Save thumb for catalog + thumb_data = thumbnail(data, + width=self.thumbWidth, height=self.thumbHeight)[-1] + with open(os.path.join(image_dir, thumb_file), 'wb') as f: + f.write(thumb_data) - # Save thumb for catalog - im.convert('RGB').save(os.path.join(image_dir, thumb_file),'JPEG') - - # Save thumb to archive - thumb_stream = cStringIO.StringIO() - im.convert('RGB').save(thumb_stream,'JPEG') - thumb_data = thumb_stream.getvalue() - thumb_stream.close() - t_info = ZipInfo(title['uuid'],time.localtime()[0:6]) - t_info.comment = cover_crc - zfw = ZipFile(self.__archive_path, mode='a') - zfw.writestr(t_info, thumb_data) - zfw.close() - - else: - # non-caching code using ImageMagick - from calibre.utils.magick import Image - try: - img = Image() - img.open(title['cover']) - # img, width, height - img.thumbnail(self.thumbWidth, self.thumbHeight) - img.save(os.path.join(image_dir, thumb_file)) - except: - self.opts.log.error("generateThumbnail(): Error with %s" % title['title']) + # Save thumb to archive + t_info = ZipInfo(title['uuid'],time.localtime()[0:6]) + t_info.comment = cover_crc + zfw = ZipFile(self.__archive_path, mode='a') + zfw.writestr(t_info, thumb_data) + zfw.close() def getFriendlyGenreTag(self, genre): # Find the first instance of friendly_tag matching genre diff --git a/src/calibre/library/database.py b/src/calibre/library/database.py index c4f6908002..6016dbd03e 100644 --- a/src/calibre/library/database.py +++ b/src/calibre/library/database.py @@ -9,6 +9,7 @@ from zlib import compress, decompress from calibre.ebooks.metadata import MetaInformation from calibre.ebooks.metadata import string_to_authors +from calibre import isbytestring class Concatenate(object): '''String concatenation aggregator for sqlite''' @@ -1379,6 +1380,10 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE; self.conn.commit() def add_feed(self, title, script): + if isbytestring(title): + title = title.decode('utf-8') + if isbytestring(script): + script = script.decode('utf-8') self.conn.execute('INSERT INTO feeds(title, script) VALUES (?, ?)', (title, script)) self.conn.commit()