Merge from trunk

This commit is contained in:
Charles Haley 2010-09-22 11:44:43 +01:00
commit 2c1debbe79
16 changed files with 395 additions and 124 deletions

View File

@ -49,7 +49,11 @@ class Danas(BasicNewsRecipe):
, 'language' : language
}
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
preprocess_regexps = [
(re.compile(u'\u0110'), lambda match: u'\u00D0')
,(re.compile(u'\u201c'), lambda match: '"')
,(re.compile(u'\u201e'), lambda match: '"')
]
keep_only_tags = [dict(name='div', attrs={'id':'left'})]
remove_tags = [

View File

@ -50,3 +50,5 @@ class Novosti(BasicNewsRecipe):
item['alt'] = 'image'
return soup

View File

@ -0,0 +1,79 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Luciano Furtado <lrfurtado at yahoo.com.br>'
'''
www.superesportes.com.br
'''
from calibre.web.feeds.news import BasicNewsRecipe
class SuperEsportesRecipe(BasicNewsRecipe):
title = u'www.superesportes.com.br'
description = u'Superesportes - Notícias do esporte no Brasil e no mundo'
__author__ = 'Luciano Furtado'
language = 'pt'
category = 'esportes, Brasil'
no_stylesheets = True
oldest_article = 7
use_embedded_content=0
max_articles_per_feed = 10
cover_url = 'http://imgs.mg.superesportes.com.br/superesportes_logo.png'
extra_css = 'div.info_noticias h1 { font-size: 100% }'
remove_tags = [
dict(name='div',attrs={'class':'topo'}),
dict(name='div',attrs={'class':'rodape'}),
dict(name='div',attrs={'class':'navegacao'}),
dict(name='div',attrs={'class':'lateral2'}),
dict(name='div',attrs={'class':'leia_mais'}),
dict(name='div',attrs={'id':'comentar'}),
dict(name='div',attrs={'id':'vrumelc_noticia'}),
dict(name='div',attrs={'class':'compartilhe'}),
dict(name='div',attrs={'class':'linha_noticias'}),
dict(name='div',attrs={'class':'botoes_noticias'}),
dict(name='div',attrs={'class':'barra_time bg_time'}),
]
def parse_index(self):
feeds = []
sections = [
(u'Atletico', 'http://www.df.superesportes.com.br/futebol/atletico-mg/capa_atletico_mg/index.shtml'),
(u'Botafogo', 'http://www.df.superesportes.com.br/futebol/botafogo/capa_botafogo/index.shtml'),
(u'Corinthinas', 'http://www.df.superesportes.com.br/futebol/corinthians/capa_corinthians/index.shtml'),
(u'Cruzeiro', 'http://www.df.superesportes.com.br/futebol/cruzeiro/capa_cruzeiro/index.shtml'),
(u'Flamengo', 'http://www.df.superesportes.com.br/futebol/flamengo/capa_flamengo/index.shtml'),
(u'Fluminense', 'http://www.df.superesportes.com.br/futebol/fluminense/capa_fluminense/index.shtml'),
(u'Palmeiras', 'http://www.df.superesportes.com.br/futebol/palmeiras/capa_palmeiras/index.shtml'),
(u'Santos', 'http://www.df.superesportes.com.br/futebol/santos/capa_santos/index.shtml'),
(u'S√£o Paulo', 'http://www.df.superesportes.com.br/futebol/sao-paulo/capa_sao_paulo/index.shtml'),
(u'Vasco', 'http://www.df.superesportes.com.br/futebol/vasco/capa_vasco/index.shtml'),
]
for section, url in sections:
current_articles = []
soup = self.index_to_soup(url)
latestNews = soup.find(name='ul',attrs={'class': 'lista_ultimas_noticias'})
for li_tag in latestNews.findAll(name='li'):
a_tag = li_tag.find('a', href= True)
if a_tag is None:
continue
title = self.tag_to_string(a_tag)
url = a_tag.get('href', False)
self.log("\n\nFound title: " + title + "\nUrl: " + url + "\nSection: " + section)
current_articles.append({'title': title, 'url': url, 'description': title, 'date':''})
if current_articles:
feeds.append((section, current_articles))
return feeds

View File

@ -2,7 +2,7 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
__appname__ = 'calibre'
__version__ = '0.7.900'
__version__ = '0.7.901'
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
import re

View File

@ -36,13 +36,17 @@ Run an embedded python interpreter.
'plugin code.')
parser.add_option('--reinitialize-db', default=None,
help='Re-initialize the sqlite calibre database at the '
'specified path. Useful to recover from db corruption.')
'specified path. Useful to recover from db corruption.'
' You can also specify the path to an SQL dump which '
'will be used instead of trying to dump the database.'
' This can be useful when dumping fails, but dumping '
'with sqlite3 works.')
parser.add_option('-p', '--py-console', help='Run python console',
default=False, action='store_true')
return parser
def reinit_db(dbpath, callback=None):
def reinit_db(dbpath, callback=None, sql_dump=None):
if not os.path.exists(dbpath):
raise ValueError(dbpath + ' does not exist')
from calibre.library.sqlite import connect
@ -52,13 +56,17 @@ def reinit_db(dbpath, callback=None):
uv = conn.get('PRAGMA user_version;', all=False)
conn.execute('PRAGMA writable_schema=ON')
conn.commit()
if sql_dump is None:
sql_lines = conn.dump()
else:
sql_lines = open(sql_dump, 'rb').read()
conn.close()
dest = dbpath + '.tmp'
try:
with closing(connect(dest, False)) as nconn:
nconn.execute('create temporary table temp_sequence(id INTEGER PRIMARY KEY AUTOINCREMENT)')
nconn.commit()
if sql_dump is None:
if callable(callback):
callback(len(sql_lines), True)
for i, line in enumerate(sql_lines):
@ -72,6 +80,8 @@ def reinit_db(dbpath, callback=None):
finally:
if callable(callback):
callback(i, False)
else:
nconn.executescript(sql_lines)
nconn.execute('pragma user_version=%d'%int(uv))
nconn.commit()
os.remove(dbpath)
@ -170,7 +180,10 @@ def main(args=sys.argv):
prints('CALIBRE_EXTENSIONS_PATH='+sys.extensions_location)
prints('CALIBRE_PYTHON_PATH='+os.pathsep.join(sys.path))
elif opts.reinitialize_db is not None:
reinit_db(opts.reinitialize_db)
sql_dump = None
if len(args) > 1 and os.access(args[-1], os.R_OK):
sql_dump = args[-1]
reinit_db(opts.reinitialize_db, sql_dump=sql_dump)
else:
from calibre import ipython
ipython()

View File

@ -29,7 +29,9 @@ class ANDROID(USBMS):
# Sony Ericsson
0xfce : { 0xd12e : [0x0100]},
0x18d1 : { 0x4e11 : [0x0100, 0x226], 0x4e12: [0x0100, 0x226]},
# Google
0x18d1 : { 0x4e11 : [0x0100, 0x226, 0x227], 0x4e12: [0x0100, 0x226,
0x227]},
# Samsung
0x04e8 : { 0x681d : [0x0222, 0x0400],

View File

@ -11,6 +11,10 @@ import re
from calibre.devices.usbms.driver import USBMS
def is_alex(device_info):
return device_info[3] == u'Linux 2.6.28 with pxa3xx_u2d' and \
device_info[4] == u'Seleucia Disk'
class N516(USBMS):
name = 'N516 driver'
@ -34,6 +38,9 @@ class N516(USBMS):
EBOOK_DIR_MAIN = 'e_book'
SUPPORTS_SUB_DIRS = True
def can_handle(self, device_info, debug=False):
return not is_alex(device_info)
class THEBOOK(N516):
name = 'The Book driver'
gui_name = 'The Book'
@ -61,6 +68,9 @@ class ALEX(N516):
EBOOK_DIR_MAIN = 'eBooks'
SUPPORTS_SUB_DIRS = True
def can_handle(self, device_info, debug=False):
return is_alex(device_info)
class AZBOOKA(ALEX):
name = 'Azbooka driver'
@ -74,6 +84,9 @@ class AZBOOKA(ALEX):
EBOOK_DIR_MAIN = ''
def can_handle(self, device_info, debug=False):
return not is_alex(device_info)
class EB511(USBMS):
name = 'Elonex EB 511 driver'

View File

@ -98,6 +98,8 @@ class KOBO(USBMS):
if readstatus == 1:
playlist_map[lpath]= "Im_Reading"
elif readstatus == 2:
playlist_map[lpath]= "Read"
path = self.normalize_path(path)
# print "Normalized FileName: " + path
@ -441,6 +443,11 @@ class KOBO(USBMS):
connection = sqlite.connect(self._main_prefix + '.kobo/KoboReader.sqlite')
cursor = connection.cursor()
if collections:
# Process any collections that exist
for category, books in collections.items():
if category == 'Im_Reading':
# Reset Im_Reading list in the database
if oncard == 'carda':
query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null and ReadStatus = 1 and ContentID like \'file:///mnt/sd/%\''
@ -456,8 +463,6 @@ class KOBO(USBMS):
# debug_print('Commit: Reset Im_Reading list')
connection.commit()
for category, books in collections.items():
if category == 'Im_Reading':
for book in books:
# debug_print('Title:', book.title, 'lpath:', book.path)
book.device_collections = ['Im_Reading']
@ -478,6 +483,59 @@ class KOBO(USBMS):
else:
connection.commit()
# debug_print('Database: Commit create Im_Reading list')
if category == 'Read':
# Reset Im_Reading list in the database
if oncard == 'carda':
query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null and ReadStatus = 2 and ContentID like \'file:///mnt/sd/%\''
elif oncard != 'carda' and oncard != 'cardb':
query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null and ReadStatus = 2 and ContentID not like \'file:///mnt/sd/%\''
try:
cursor.execute (query)
except:
debug_print('Database Exception: Unable to reset Im_Reading list')
raise
else:
# debug_print('Commit: Reset Im_Reading list')
connection.commit()
for book in books:
# debug_print('Title:', book.title, 'lpath:', book.path)
book.device_collections = ['Read']
extension = os.path.splitext(book.path)[1]
ContentType = self.get_content_type_from_extension(extension)
ContentID = self.contentid_from_path(book.path, ContentType)
# datelastread = time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime())
t = (ContentID,)
try:
cursor.execute('update content set ReadStatus=2,FirstTimeReading=\'true\' where BookID is Null and ContentID = ?', t)
except:
debug_print('Database Exception: Unable set book as Rinished')
raise
else:
connection.commit()
# debug_print('Database: Commit set ReadStatus as Finished')
else: # No collections
# Since no collections exist the ReadStatus needs to be reset to 0 (Unread)
print "Reseting ReadStatus to 0"
# Reset Im_Reading list in the database
if oncard == 'carda':
query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null and ContentID like \'file:///mnt/sd/%\''
elif oncard != 'carda' and oncard != 'cardb':
query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null and ContentID not like \'file:///mnt/sd/%\''
try:
cursor.execute (query)
except:
debug_print('Database Exception: Unable to reset Im_Reading list')
raise
else:
# debug_print('Commit: Reset Im_Reading list')
connection.commit()
cursor.close()
connection.close()

View File

@ -1574,6 +1574,7 @@ class MobiWriter(object):
id = unicode(oeb.metadata.cover[0])
item = oeb.manifest.ids[id]
href = item.href
if href in self._images:
index = self._images[href] - 1
exth.write(pack('>III', 0xc9, 0x0c, index))
exth.write(pack('>III', 0xcb, 0x0c, 0))

View File

@ -590,7 +590,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
mi.pubdate = self.pubdate(idx, index_is_id=index_is_id)
mi.uuid = self.uuid(idx, index_is_id=index_is_id)
mi.title_sort = self.title_sort(idx, index_is_id=index_is_id)
mi.formats = self.formats(idx, index_is_id=index_is_id).split(',')
mi.formats = self.formats(idx, index_is_id=index_is_id)
if hasattr(mi.formats, 'split'):
mi.formats = mi.formats.split(',')
else:
mi.formats = None
tags = self.tags(idx, index_is_id=index_is_id)
if tags:
mi.tags = [i.strip() for i in tags.split(',')]
@ -1213,7 +1217,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
def set_authors(self, id, authors, notify=True, commit=True):
'''
`authors`: A list of authors.
Note that even if commit is False, the db will still be committed to
because this causes the location of files to change
:param authors: A list of authors.
'''
if not authors:
authors = [_('Unknown')]
@ -1250,6 +1257,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.notify('metadata', [id])
def set_title(self, id, title, notify=True, commit=True):
'''
Note that even if commit is False, the db will still be committed to
because this causes the location of files to change
'''
if not title:
return
if not isinstance(title, unicode):

View File

@ -60,15 +60,15 @@ def identify(path):
data = open(path, 'rb').read()
return identify_data(data)
def add_borders_to_image(path_to_image, left=0, top=0, right=0, bottom=0,
border_color='#ffffff'):
def add_borders_to_image(img_data, left=0, top=0, right=0, bottom=0,
border_color='#ffffff', fmt='jpg'):
img = Image()
img.open(path_to_image)
img.load(img_data)
lwidth, lheight = img.size
canvas = create_canvas(lwidth+left+right, lheight+top+bottom,
border_color)
canvas.compose(img, left, top)
canvas.save(path_to_image)
return canvas.export(fmt)
def create_text_wand(font_size, font_path=None):
if font_path is None:

View File

@ -8,14 +8,18 @@ __docformat__ = 'restructuredtext en'
import sys
from calibre import prints as prints_
from calibre.utils.config import Config, StringConfig
from calibre.utils.config import Config, ConfigProxy
def console_config(defaults=None):
desc=_('Settings to control the calibre content server')
c = Config('console', desc) if defaults is None else StringConfig(defaults, desc)
def console_config():
desc='Settings to control the calibre console'
c = Config('console', desc)
c.add_opt('--theme', default='default', help='The color theme')
c.add_opt('theme', default='native', help='The color theme')
return c
prefs = ConfigProxy(console_config())
def prints(*args, **kwargs):

View File

@ -6,16 +6,18 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import sys, textwrap, traceback, StringIO
from functools import partial
from PyQt4.Qt import QTextEdit, Qt, QTextFrameFormat, pyqtSignal, \
QCoreApplication
QApplication, QColor, QPalette, QMenu, QActionGroup
from pygments.lexers import PythonLexer, PythonTracebackLexer
from pygments.styles import get_all_styles
from calibre.constants import __appname__, __version__
from calibre.utils.pyconsole.formatter import Formatter
from calibre.utils.pyconsole.repl import Interpreter, DummyFile
from calibre.utils.pyconsole import prints
from calibre.utils.pyconsole import prints, prefs
from calibre.gui2 import error_dialog
class EditBlock(object): # {{{
@ -47,6 +49,30 @@ class Prepender(object): # {{{
self.console.cursor_pos = self.opos
# }}}
class ThemeMenu(QMenu): # {{{
def __init__(self, parent):
QMenu.__init__(self, _('Choose theme (needs restart)'))
parent.addMenu(self)
self.group = QActionGroup(self)
current = prefs['theme']
alls = list(sorted(get_all_styles()))
if current not in alls:
current = prefs['theme'] = 'default'
self.actions = []
for style in alls:
ac = self.group.addAction(style)
ac.setCheckable(True)
if current == style:
ac.setChecked(True)
self.actions.append(ac)
ac.triggered.connect(partial(self.set_theme, style))
self.addAction(ac)
def set_theme(self, style, *args):
prefs['theme'] = style
# }}}
class Console(QTextEdit):
@ -99,8 +125,16 @@ class Console(QTextEdit):
self.doc.setMaximumBlockCount(10000)
self.lexer = PythonLexer(ensurenl=False)
self.tb_lexer = PythonTracebackLexer()
self.formatter = Formatter(prompt, continuation, style='default')
self.setStyleSheet(self.formatter.stylesheet)
self.context_menu = cm = QMenu(self) # {{{
cm.theme = ThemeMenu(cm)
# }}}
self.formatter = Formatter(prompt, continuation, style=prefs['theme'])
p = QPalette()
p.setColor(p.Base, QColor(self.formatter.background_color))
p.setColor(p.Text, QColor(self.formatter.color))
self.setPalette(p)
self.key_dispatcher = { # {{{
Qt.Key_Enter : self.enter_pressed,
@ -109,6 +143,8 @@ class Console(QTextEdit):
Qt.Key_End : self.end_pressed,
Qt.Key_Left : self.left_pressed,
Qt.Key_Right : self.right_pressed,
Qt.Key_Backspace : self.backspace_pressed,
Qt.Key_Delete : self.delete_pressed,
} # }}}
motd = textwrap.dedent('''\
@ -127,6 +163,9 @@ class Console(QTextEdit):
sys.excepthook = self.unhandled_exception
def contextMenuEvent(self, event):
self.context_menu.popup(event.globalPos())
event.accept()
# Prompt management {{{
@ -239,7 +278,7 @@ class Console(QTextEdit):
except:
prints(tb, end='')
self.ensureCursorVisible()
QCoreApplication.processEvents()
QApplication.processEvents()
def show_output(self, raw):
def do_show():
@ -257,7 +296,7 @@ class Console(QTextEdit):
else:
do_show()
self.ensureCursorVisible()
QCoreApplication.processEvents()
QApplication.processEvents()
# }}}
@ -290,6 +329,22 @@ class Console(QTextEdit):
self.setTextCursor(c)
self.ensureCursorVisible()
def backspace_pressed(self):
lineno, pos = self.cursor_pos
if lineno < 0: return
if pos > self.prompt_len:
self.cursor.deletePreviousChar()
elif lineno > 0:
c = self.cursor
c.movePosition(c.Up)
c.movePosition(c.EndOfLine)
self.setTextCursor(c)
self.ensureCursorVisible()
def delete_pressed(self):
self.cursor.deleteChar()
self.ensureCursorVisible()
def right_pressed(self):
lineno, pos = self.cursor_pos
if lineno < 0: return
@ -305,6 +360,11 @@ class Console(QTextEdit):
def home_pressed(self):
if self.prompt_frame is not None:
mods = QApplication.keyboardModifiers()
ctrl = bool(int(mods & Qt.CTRL))
if ctrl:
self.cursor_pos = (0, self.prompt_len)
else:
c = self.cursor
c.movePosition(c.StartOfLine)
c.movePosition(c.NextCharacter, n=self.prompt_len)
@ -313,6 +373,10 @@ class Console(QTextEdit):
def end_pressed(self):
if self.prompt_frame is not None:
mods = QApplication.keyboardModifiers()
ctrl = bool(int(mods & Qt.CTRL))
if ctrl:
self.cursor_pos = (len(list(self.prompt()))-1, self.prompt_len)
c = self.cursor
c.movePosition(c.EndOfLine)
self.setTextCursor(c)

View File

@ -8,18 +8,20 @@ __docformat__ = 'restructuredtext en'
from PyQt4.Qt import QTextCharFormat, QFont, QBrush, QColor
from pygments.formatter import Formatter as PF
from pygments.token import Token, Generic
from pygments.token import Token, Generic, string_to_tokentype
class Formatter(object):
def __init__(self, prompt, continuation, **options):
def __init__(self, prompt, continuation, style='default'):
if len(prompt) != len(continuation):
raise ValueError('%r does not have the same length as %r' %
(prompt, continuation))
self.prompt, self.continuation = prompt, continuation
self.set_style(style)
pf = PF(**options)
def set_style(self, style):
pf = PF(style=style)
self.styles = {}
self.normal = self.base_fmt()
self.background_color = pf.style.background_color
@ -27,6 +29,7 @@ class Formatter(object):
for ttype, ndef in pf.style:
fmt = self.base_fmt()
fmt.setProperty(fmt.UserProperty, str(ttype))
if ndef['color']:
fmt.setForeground(QBrush(QColor('#%s'%ndef['color'])))
fmt.setUnderlineColor(QColor('#%s'%ndef['color']))
@ -45,10 +48,14 @@ class Formatter(object):
self.styles[ttype] = fmt
self.stylesheet = '''
QTextEdit { color: %s; background-color: %s }
'''%(self.color, self.background_color)
def get_fmt(self, token):
if type(token) != type(Token.Generic):
token = string_to_tokentype(token)
fmt = self.styles.get(token, None)
if fmt is None:
fmt = self.base_fmt()
fmt.setProperty(fmt.UserProperty, str(token))
return fmt
def base_fmt(self):
fmt = QTextCharFormat()
@ -59,7 +66,7 @@ class Formatter(object):
cursor.insertText(raw, self.normal)
def render_syntax_error(self, tb, cursor):
fmt = self.styles[Token.Error]
fmt = self.get_fmt(Token.Error)
cursor.insertText(tb, fmt)
def render(self, tokens, cursor):
@ -84,7 +91,9 @@ class Formatter(object):
def render_prompt(self, is_continuation, cursor):
pr = self.continuation if is_continuation else self.prompt
fmt = self.styles[Generic.Prompt]
fmt = self.get_fmt(Generic.Prompt)
if fmt is None:
fmt = self.base_fmt()
cursor.insertText(pr, fmt)

View File

@ -9,7 +9,7 @@ __version__ = '0.1.0'
from functools import partial
from PyQt4.Qt import QDialog, QToolBar, QStatusBar, QLabel, QFont, Qt, \
QApplication, QIcon, QVBoxLayout
QApplication, QIcon, QVBoxLayout, QAction
from calibre.constants import __appname__, __version__
from calibre.utils.pyconsole.console import Console
@ -19,8 +19,9 @@ class MainWindow(QDialog):
def __init__(self,
default_status_msg=_('Welcome to') + ' ' + __appname__+' console',
parent=None):
QDialog.__init__(self, parent)
self.restart_requested = False
self.l = QVBoxLayout()
self.setLayout(self.l)
@ -51,14 +52,26 @@ class MainWindow(QDialog):
self.setWindowTitle(__appname__ + ' console')
self.setWindowIcon(QIcon(I('console.png')))
self.restart_action = QAction(_('Restart console'), self)
self.restart_action.setShortcut(_('Ctrl+R'))
self.addAction(self.restart_action)
self.restart_action.triggered.connect(self.restart)
self.console.context_menu.addAction(self.restart_action)
def restart(self):
self.restart_requested = True
self.reject()
def main():
QApplication.setApplicationName(__appname__+' console')
QApplication.setOrganizationName('Kovid Goyal')
app = QApplication([])
app
while True:
m = MainWindow()
m.show()
app.exec_()
m.exec_()
if not m.restart_requested:
break
if __name__ == '__main__':

View File

@ -7,7 +7,7 @@ Defines various abstract base classes that can be subclassed to create powerful
__docformat__ = "restructuredtext en"
import os, time, traceback, re, urlparse, sys
import os, time, traceback, re, urlparse, sys, cStringIO
from collections import defaultdict
from functools import partial
from contextlib import nested, closing
@ -27,6 +27,7 @@ from calibre.web.fetch.simple import RecursiveFetcher
from calibre.utils.threadpool import WorkRequest, ThreadPool, NoResultsPending
from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.date import now as nowf
from calibre.utils.magick.draw import save_cover_data_to, add_borders_to_image
class LoginFailed(ValueError):
pass
@ -948,38 +949,36 @@ class BasicNewsRecipe(Recipe):
try:
cu = self.get_cover_url()
except Exception, err:
cu = None
self.log.error(_('Could not download cover: %s')%str(err))
self.log.debug(traceback.format_exc())
if cu is not None:
ext = cu.split('/')[-1].rpartition('.')[-1]
if '?' in ext:
ext = ''
ext = ext.lower() if ext and '/' not in ext else 'jpg'
cpath = os.path.join(self.output_dir, 'cover.'+ext)
else:
cdata = None
if os.access(cu, os.R_OK):
with open(cpath, 'wb') as cfile:
cfile.write(open(cu, 'rb').read())
cdata = open(cu, 'rb').read()
else:
self.report_progress(1, _('Downloading cover from %s')%cu)
with nested(open(cpath, 'wb'), closing(self.browser.open(cu))) as (cfile, r):
cfile.write(r.read())
with closing(self.browser.open(cu)) as r:
cdata = r.read()
if not cdata:
return
ext = cu.split('/')[-1].rpartition('.')[-1].lower().strip()
if ext == 'pdf':
from calibre.ebooks.metadata.pdf import get_metadata
stream = cStringIO.StringIO(cdata)
cdata = None
mi = get_metadata(stream)
if mi.cover_data and mi.cover_data[1]:
cdata = mi.cover_data[1]
if not cdata:
return
if self.cover_margins[0] or self.cover_margins[1]:
from calibre.utils.magick.draw import add_borders_to_image
add_borders_to_image(cpath,
cdata = add_borders_to_image(cdata,
left=self.cover_margins[0],right=self.cover_margins[0],
top=self.cover_margins[1],bottom=self.cover_margins[1],
border_color=self.cover_margins[2])
if ext.lower() == 'pdf':
from calibre.ebooks.metadata.pdf import get_metadata
stream = open(cpath, 'rb')
mi = get_metadata(stream)
cpath = None
if mi.cover_data and mi.cover_data[1]:
cpath = os.path.join(self.output_dir,
'cover.'+mi.cover_data[0])
with open(cpath, 'wb') as f:
f.write(mi.cover_data[1])
cpath = os.path.join(self.output_dir, 'cover.jpg')
save_cover_data_to(cdata, cpath)
self.cover_path = cpath
def download_cover(self):
@ -1422,7 +1421,6 @@ class CalibrePeriodical(BasicNewsRecipe):
return br
def download(self):
import cStringIO
self.log('Fetching downloaded recipe')
try:
raw = self.browser.open_novisit(