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()