From 0e18837cb6a1baa7f2219d2ca8ec409a66508105 Mon Sep 17 00:00:00 2001
From: Hiroshi Miura
Date: Wed, 5 Jan 2011 23:17:38 +0900
Subject: [PATCH 01/17] fix encoding, reflect change of the site
---
resources/recipes/cnetjapan.recipe | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/recipes/cnetjapan.recipe b/resources/recipes/cnetjapan.recipe
index 1058b90401..b57bce5b97 100644
--- a/resources/recipes/cnetjapan.recipe
+++ b/resources/recipes/cnetjapan.recipe
@@ -11,7 +11,7 @@ class CNetJapan(BasicNewsRecipe):
(u'CNet Blog', u'http://feed.japan.cnet.com/rss/blog/index.rdf')
]
language = 'ja'
- encoding = 'Shift_JIS'
+ encoding = 'utf-8'
remove_javascript = True
preprocess_regexps = [
From 6871651ff1719971c1f52b4fb8ed6c2ae2025c44 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 9 Jan 2011 16:41:54 +0000
Subject: [PATCH 02/17] Fix bug in formatter where parse errors at end of file
threw an exception instead of providing the message.
---
src/calibre/utils/formatter.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/calibre/utils/formatter.py b/src/calibre/utils/formatter.py
index 2e4f843c3d..40760bf91b 100644
--- a/src/calibre/utils/formatter.py
+++ b/src/calibre/utils/formatter.py
@@ -98,9 +98,10 @@ class _Parser(object):
m = 'Formatter: ' + message + _(' near ')
if self.lex_pos > 0:
m = '{0} {1}'.format(m, self.prog[self.lex_pos-1][1])
- m = '{0} {1}'.format(m, self.prog[self.lex_pos][1])
- if self.lex_pos < len(self.prog):
+ elif self.lex_pos < len(self.prog):
m = '{0} {1}'.format(m, self.prog[self.lex_pos+1][1])
+ else:
+ m = '{0} {1}'.format(m, _('end of program'))
raise ValueError(m)
def token(self):
From 0067f6af4edf0a5645acc6a9a48a1608f60fb5a6 Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 9 Jan 2011 16:42:11 +0000
Subject: [PATCH 03/17] Fix bug in formatter where parse errors at end of file
threw an exception instead of providing the message.
---
src/calibre/gui2/preferences/plugboard.py | 31 +++++++++++++++++++----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/src/calibre/gui2/preferences/plugboard.py b/src/calibre/gui2/preferences/plugboard.py
index 296387106c..e1dc6b03bd 100644
--- a/src/calibre/gui2/preferences/plugboard.py
+++ b/src/calibre/gui2/preferences/plugboard.py
@@ -5,11 +5,11 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal '
__docformat__ = 'restructuredtext en'
-from PyQt4 import QtGui
-from PyQt4.Qt import Qt
+from PyQt4.Qt import Qt, QLineEdit, QComboBox, SIGNAL, QListWidgetItem
from calibre.gui2 import error_dialog
from calibre.gui2.device import device_name_for_plugboards
+from calibre.gui2.dialogs.template_dialog import TemplateDialog
from calibre.gui2.preferences import ConfigWidgetBase, test_widget
from calibre.gui2.preferences.plugboard_ui import Ui_Form
from calibre.customize.ui import metadata_writers, device_plugins
@@ -17,6 +17,27 @@ from calibre.library.save_to_disk import plugboard_any_format_value, \
plugboard_any_device_value, plugboard_save_to_disk_value
from calibre.utils.formatter import validation_formatter
+
+class LineEditWithTextBox(QLineEdit):
+
+ '''
+ Extend the context menu of a QLineEdit to include more actions.
+ '''
+
+ def contextMenuEvent(self, event):
+ menu = self.createStandardContextMenu()
+ menu.addSeparator()
+
+ action_open_editor = menu.addAction(_('Open Editor'))
+
+ self.connect(action_open_editor, SIGNAL('triggered()'), self.open_editor)
+ menu.exec_(event.globalPos())
+
+ def open_editor(self):
+ t = TemplateDialog(self, self.text())
+ if t.exec_():
+ self.setText(t.textbox.toPlainText())
+
class ConfigWidget(ConfigWidgetBase, Ui_Form):
def genesis(self, gui):
@@ -72,10 +93,10 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
self.source_widgets = []
self.dest_widgets = []
for i in range(0, len(self.dest_fields)-1):
- w = QtGui.QLineEdit(self)
+ w = LineEditWithTextBox(self)
self.source_widgets.append(w)
self.fields_layout.addWidget(w, 5+i, 0, 1, 1)
- w = QtGui.QComboBox(self)
+ w = QComboBox(self)
self.dest_widgets.append(w)
self.fields_layout.addWidget(w, 5+i, 1, 1, 1)
@@ -297,7 +318,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
for op in self.current_plugboards[f][d]:
ops.append('([' + op[0] + '] -> ' + op[1] + ')')
txt = '%s:%s = %s\n'%(f, d, ', '.join(ops))
- item = QtGui.QListWidgetItem(txt)
+ item = QListWidgetItem(txt)
item.setData(Qt.UserRole, (f, d))
self.existing_plugboards.addItem(item)
self.refilling = False
From cdc017bc6349cfb29944e7da4657c2ba42f122fd Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 9 Jan 2011 16:42:28 +0000
Subject: [PATCH 04/17] Fix #8244 Merging two books fails (None custom numeric
values throws exception)
---
src/calibre/library/custom_columns.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/calibre/library/custom_columns.py b/src/calibre/library/custom_columns.py
index d925f7c91d..d905f6d01a 100644
--- a/src/calibre/library/custom_columns.py
+++ b/src/calibre/library/custom_columns.py
@@ -151,6 +151,8 @@ class CustomColumns(object):
return v
def adapt_number(x, d):
+ if x is None:
+ return None
if isinstance(x, (str, unicode, bytes)):
if x.lower() == 'none':
return None
From 1670cd29bae7b41186141f902e0057676d985967 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Sun, 9 Jan 2011 10:32:19 -0700
Subject: [PATCH 05/17] Cicero by mad
---
resources/recipes/cicero.recipe | 35 +++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
create mode 100644 resources/recipes/cicero.recipe
diff --git a/resources/recipes/cicero.recipe b/resources/recipes/cicero.recipe
new file mode 100644
index 0000000000..2df6b68000
--- /dev/null
+++ b/resources/recipes/cicero.recipe
@@ -0,0 +1,35 @@
+from calibre.web.feeds.news import BasicNewsRecipe
+
+class Cicero(BasicNewsRecipe):
+ timefmt = ' [%Y-%m-%d]'
+ title = u'Cicero'
+ __author__ = 'mad@sharktooth.de'
+ description = u'Magazin f\xfcr politische Kultur'
+ oldest_article = 7
+ language = 'de'
+ max_articles_per_feed = 100
+ no_stylesheets = True
+ use_embedded_content = False
+ publisher = 'Ringier Publishing'
+ category = 'news, politics, Germany'
+ encoding = 'iso-8859-1'
+ publication_type = 'magazine'
+ masthead_url = 'http://www.cicero.de/img2/cicero_logo_rss.gif'
+ feeds = [
+(u'Das gesamte Portfolio', u'http://www.cicero.de/rss/rss.php?ress_id='),
+#(u'Alle Heft-Inhalte', u'http://www.cicero.de/rss/rss.php?ress_id=heft'),
+#(u'Alle Online-Inhalte', u'http://www.cicero.de/rss/rss.php?ress_id=online'),
+#(u'Berliner Republik', u'http://www.cicero.de/rss/rss.php?ress_id=4'),
+#(u'Weltb\xfchne', u'http://www.cicero.de/rss/rss.php?ress_id=1'),
+#(u'Salon', u'http://www.cicero.de/rss/rss.php?ress_id=7'),
+#(u'Kapital', u'http://www.cicero.de/rss/rss.php?ress_id=6'),
+#(u'Netzst\xfccke', u'http://www.cicero.de/rss/rss.php?ress_id=9'),
+#(u'Leinwand', u'http://www.cicero.de/rss/rss.php?ress_id=12'),
+#(u'Bibliothek', u'http://www.cicero.de/rss/rss.php?ress_id=15'),
+(u'Kolumne - Alle Kolulmnen', u'http://www.cicero.de/rss/rss2.php?ress_id='),
+#(u'Kolumne - Schreiber, Berlin', u'http://www.cicero.de/rss/rss2.php?ress_id=35'),
+#(u'Kolumne - TV Kritik', u'http://www.cicero.de/rss/rss2.php?ress_id=34')
+]
+
+ def print_version(self, url):
+ return 'http://www.cicero.de/page_print.php?' + url.rpartition('?')[2]
From e58ccd8c5e4f4a251c8bf738a621d1a29c6e91da Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Sun, 9 Jan 2011 10:55:15 -0700
Subject: [PATCH 06/17] Fix XSS vulnerability in content server. Fixes #7980
(Security vulnerability in Calibre 0.7.34)
---
src/calibre/library/server/browse.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/calibre/library/server/browse.py b/src/calibre/library/server/browse.py
index 37799c4cbc..3e4687be95 100644
--- a/src/calibre/library/server/browse.py
+++ b/src/calibre/library/server/browse.py
@@ -756,7 +756,7 @@ class BrowseServer(object):
sort = self.browse_sort_book_list(items, list_sort)
ids = [x[0] for x in items]
html = render_book_list(ids, self.opts.url_prefix,
- suffix=_('in search')+': '+query)
+ suffix=_('in search')+': '+xml(query))
return self.browse_template(sort, category=False, initial_search=query).format(
title=_('Matching books'),
script='booklist();', main=html)
From 6349979ca5a06d4efaf573902508fd5ac437128f Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Sun, 9 Jan 2011 18:15:02 +0000
Subject: [PATCH 07/17] Fix regression on empty ismult custom columns
---
src/calibre/library/custom_columns.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/calibre/library/custom_columns.py b/src/calibre/library/custom_columns.py
index d905f6d01a..f94081f046 100644
--- a/src/calibre/library/custom_columns.py
+++ b/src/calibre/library/custom_columns.py
@@ -197,8 +197,8 @@ class CustomColumns(object):
data = self.custom_column_num_map[num]
row = self.data._data[idx] if index_is_id else self.data[idx]
ans = row[self.FIELD_MAP[data['num']]]
- if ans and data['is_multiple'] and data['datatype'] == 'text':
- ans = ans.split('|')
+ if data['is_multiple'] and data['datatype'] == 'text':
+ ans = ans.split('|') if ans else []
if data['display'].get('sort_alpha', False):
ans.sort(cmp=lambda x,y:cmp(x.lower(), y.lower()))
return ans
From 31c354a164a8816576ce5194a6b0e1b5d64b6728 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Sun, 9 Jan 2011 11:15:34 -0700
Subject: [PATCH 08/17] ...
---
setup/build_environment.py | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/setup/build_environment.py b/setup/build_environment.py
index 10ab1b0735..bdfddd2205 100644
--- a/setup/build_environment.py
+++ b/setup/build_environment.py
@@ -117,7 +117,6 @@ if iswindows:
poppler_inc_dirs = consolidate('POPPLER_INC_DIR',
r'%s\poppler;%s'%(sw_inc_dir, sw_inc_dir))
- popplerqt4_inc_dirs = poppler_inc_dirs + [poppler_inc_dirs[1]+r'\qt4']
poppler_lib_dirs = consolidate('POPPLER_LIB_DIR', sw_lib_dir)
popplerqt4_lib_dirs = poppler_lib_dirs
poppler_libs = ['poppler']
@@ -131,7 +130,6 @@ elif isosx:
fc_lib = '/sw/lib'
poppler_inc_dirs = consolidate('POPPLER_INC_DIR',
'/sw/build/poppler-0.14.5/poppler:/sw/build/poppler-0.14.5')
- popplerqt4_inc_dirs = poppler_inc_dirs + [poppler_inc_dirs[0]+'/qt4']
poppler_lib_dirs = consolidate('POPPLER_LIB_DIR',
'/sw/lib')
poppler_libs = ['poppler']
@@ -150,9 +148,6 @@ else:
# Include directories
poppler_inc_dirs = pkgconfig_include_dirs('poppler',
'POPPLER_INC_DIR', '/usr/include/poppler')
- popplerqt4_inc_dirs = pkgconfig_include_dirs('poppler-qt4', '', '')
- if not popplerqt4_inc_dirs:
- popplerqt4_inc_dirs = poppler_inc_dirs + [poppler_inc_dirs[0]+'/qt4']
png_inc_dirs = pkgconfig_include_dirs('libpng', 'PNG_INC_DIR',
'/usr/include')
magick_inc_dirs = pkgconfig_include_dirs('MagickWand', 'MAGICK_INC', '/usr/include/ImageMagick')
@@ -187,13 +182,10 @@ if not poppler_inc_dirs or not os.path.exists(
poppler_error = \
('Poppler not found on your system. Various PDF related',
' functionality will not work. Use the POPPLER_INC_DIR and',
- ' POPPLER_LIB_DIR environment variables.')
-
-popplerqt4_error = None
-if not popplerqt4_inc_dirs or not os.path.exists(
- os.path.join(popplerqt4_inc_dirs[-1], 'poppler-qt4.h')):
- popplerqt4_error = \
- ('Poppler Qt4 bindings not found on your system.')
+ ' POPPLER_LIB_DIR environment variables. calibre requires '
+ ' the poppler XPDF headers. If your distro does not '
+ ' include them you will have to re-compile poppler '
+ ' by hand with --enable-xpdf-headers')
magick_error = None
if not magick_inc_dirs or not os.path.exists(os.path.join(magick_inc_dirs[0],
From d63bfeff1158fc9f8ef9f7ba78cd7b39f18c9a98 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Sun, 9 Jan 2011 11:18:35 -0700
Subject: [PATCH 09/17] ...
---
setup/build_environment.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup/build_environment.py b/setup/build_environment.py
index bdfddd2205..f0adaf9584 100644
--- a/setup/build_environment.py
+++ b/setup/build_environment.py
@@ -192,7 +192,7 @@ if not magick_inc_dirs or not os.path.exists(os.path.join(magick_inc_dirs[0],
'wand')):
magick_error = ('ImageMagick not found on your system. '
'Try setting the environment variables MAGICK_INC '
- 'and MAGICK_LIB to help calibre locate the inclue and libbrary '
+ 'and MAGICK_LIB to help calibre locate the include and library '
'files.')
podofo_lib = os.environ.get('PODOFO_LIB_DIR', podofo_lib)
From be03e57f2cf8d25b87e888b781ab14cc4ff3b20f Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Sun, 9 Jan 2011 11:44:43 -0700
Subject: [PATCH 10/17] El Correo by desUBIKado
---
resources/recipes/el_correo.recipe | 122 +++++++++++++++++++++++++++++
1 file changed, 122 insertions(+)
create mode 100644 resources/recipes/el_correo.recipe
diff --git a/resources/recipes/el_correo.recipe b/resources/recipes/el_correo.recipe
new file mode 100644
index 0000000000..9190560b02
--- /dev/null
+++ b/resources/recipes/el_correo.recipe
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+__license__ = 'GPL v3'
+__copyright__ = '08 Januery 2011, desUBIKado'
+__author__ = 'desUBIKado'
+__description__ = 'Daily newspaper from Biscay'
+__version__ = 'v0.08'
+__date__ = '08, Januery 2011'
+'''
+[url]http://www.elcorreo.com/[/url]
+'''
+
+import time
+import re
+from calibre.web.feeds.news import BasicNewsRecipe
+
+class heraldo(BasicNewsRecipe):
+ __author__ = 'desUBIKado'
+ description = 'Daily newspaper from Biscay'
+ title = u'El Correo'
+ publisher = 'Vocento'
+ category = 'News, politics, culture, economy, general interest'
+ oldest_article = 2
+ delay = 1
+ max_articles_per_feed = 100
+ no_stylesheets = True
+ use_embedded_content = False
+ language = 'es'
+ timefmt = '[%a, %d %b, %Y]'
+ encoding = 'iso-8859-1'
+ remove_empty_feeds = True
+ remove_javascript = False
+
+ feeds = [
+ (u'Portada', u'http://www.elcorreo.com/vizcaya/portada.xml'),
+ (u'Local', u'http://www.elcorreo.com/vizcaya/rss/feeds/vizcaya.xml'),
+ (u'Internacional', u'hhttp://www.elcorreo.com/vizcaya/rss/feeds/internacional.xml'),
+ (u'Econom\xeda', u'http://www.elcorreo.com/vizcaya/rss/feeds/economia.xml'),
+ (u'Pol\xedtica', u'http://www.elcorreo.com/vizcaya/rss/feeds/politica.xml'),
+ (u'Opini\xf3n', u'http://www.elcorreo.com/vizcaya/rss/feeds/opinion.xml'),
+ (u'Deportes', u'http://www.elcorreo.com/vizcaya/rss/feeds/deportes.xml'),
+ (u'Sociedad', u'http://www.elcorreo.com/vizcaya/rss/feeds/sociedad.xml'),
+ (u'Cultura', u'http://www.elcorreo.com/vizcaya/rss/feeds/cultura.xml'),
+ (u'Televisi\xf3n', u'http://www.elcorreo.com/vizcaya/rss/feeds/television.xml'),
+ (u'Gente', u'http://www.elcorreo.com/vizcaya/rss/feeds/gente.xml')
+ ]
+
+ keep_only_tags = [
+ dict(name='div', attrs={'class':['grouphead','date','art_head','story-texto','text','colC_articulo','contenido_comentarios']}),
+ dict(name='div' , attrs={'id':['articulo','story-texto','story-entradilla']})
+ ]
+
+ remove_tags = [
+ dict(name='div', attrs={'class':['art_barra','detalles-opinion','formdenunciar','modulo calculadoras','nubetags','pie']}),
+ dict(name='div', attrs={'class':['mod_lomas','bloque_lomas','blm_header','link-app3','link-app4','botones_listado']}),
+ dict(name='div', attrs={'class':['navegacion_galeria','modulocanalpromocion','separa','separacion','compartir','tags_relacionados']}),
+ dict(name='div', attrs={'class':['moduloBuscadorDeportes','modulo-gente','moddestacadopeq','OpcArt','articulopiniones']}),
+ dict(name='div', attrs={'class':['modulo-especial','publiEspecial']}),
+ dict(name='div', attrs={'id':['articulopina']}),
+ dict(name='br', attrs={'class':'clear'}),
+ dict(name='form', attrs={'name':'frm_conversor2'})
+ ]
+
+ remove_tags_before = dict(name='div' , attrs={'class':'articulo '})
+ remove_tags_after = dict(name='div' , attrs={'class':'comentarios'})
+
+ def get_cover_url(self):
+ cover = None
+ st = time.localtime()
+ year = str(st.tm_year)
+ month = "%.2d" % st.tm_mon
+ day = "%.2d" % st.tm_mday
+ #[url]http://img.kiosko.net/2011/01/02/es/elcorreo.750.jpg[/url]
+ #[url]http://info.elcorreo.com/pdf/06012011-viz.pdf[/url]
+ cover='http://info.elcorreo.com/pdf/'+ day + month + year +'-viz.pdf'
+
+ br = BasicNewsRecipe.get_browser()
+ try:
+ br.open(cover)
+ except:
+ self.log("\nPortada no disponible")
+ cover ='http://www.elcorreo.com/vizcaya/noticias/201002/02/Media/logo-elcorreo-nuevo.png'
+ return cover
+
+ extra_css = '''
+ h1, .headline {font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:30px;}
+ h2, .subhead {font-family:Arial,Helvetica,sans-serif; font-style:italic; font-weight:normal;font-size:18px;}
+ h3, .overhead {font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:16px;}
+ h4 {font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:16px;}
+ h5 {font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:16px;}
+ h6 {font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:16px;}
+ .date,.byline, .photo {font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:14px;}
+ img{margin-bottom: 0.4em}
+ '''
+
+
+
+ preprocess_regexps = [
+
+ # To present the image of the embedded video
+ (re.compile(r'var RUTA_IMAGEN', re.DOTALL|re.IGNORECASE), lambda match: '
'),
+ (re.compile(r'var SITIO = "elcorreo";', re.DOTALL|re.IGNORECASE), lambda match: '
', re.DOTALL|re.IGNORECASE), lambda match: '
'),
+
+# To put a blank line between the intro of the embedded videos and the previous text
+ (re.compile(r'
\n
\n', re.DOTALL|re.IGNORECASE), lambda match: ''),
+
+ ]
+
From 9fff468d7415adc11f48c99fd6ffb3c6428a8577 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Sun, 9 Jan 2011 11:47:15 -0700
Subject: [PATCH 11/17] Update Heraldo de Aragon
---
resources/recipes/heraldo.recipe | 58 +++++++++++++++++++-------------
1 file changed, 35 insertions(+), 23 deletions(-)
diff --git a/resources/recipes/heraldo.recipe b/resources/recipes/heraldo.recipe
index c5669e116b..f3236ec4a9 100644
--- a/resources/recipes/heraldo.recipe
+++ b/resources/recipes/heraldo.recipe
@@ -3,29 +3,31 @@ __license__ = 'GPL v3'
__copyright__ = '04 December 2010, desUBIKado'
__author__ = 'desUBIKado'
__description__ = 'Daily newspaper from Aragon'
-__version__ = 'v0.03'
-__date__ = '11, December 2010'
+__version__ = 'v0.04'
+__date__ = '6, Januery 2011'
'''
[url]http://www.heraldo.es/[/url]
'''
import time
+import re
from calibre.web.feeds.news import BasicNewsRecipe
class heraldo(BasicNewsRecipe):
- __author__ = 'desUBIKado'
- description = 'Daily newspaper from Aragon'
+ __author__ = 'desUBIKado'
+ description = 'Daily newspaper from Aragon'
title = u'Heraldo de Aragon'
publisher = 'OJD Nielsen'
category = 'News, politics, culture, economy, general interest'
language = 'es'
timefmt = '[%a, %d %b, %Y]'
- oldest_article = 1
+ oldest_article = 2
+ delay = 1
max_articles_per_feed = 100
use_embedded_content = False
remove_javascript = True
no_stylesheets = True
- recursion = 10
+
feeds = [
(u'Portadas', u'http://www.heraldo.es/index.php/mod.portadas/mem.rss')
@@ -37,29 +39,39 @@ class heraldo(BasicNewsRecipe):
remove_tags = [dict(name='a', attrs={'class':['com flo-r','enl-if','enl-df']}),
dict(name='div', attrs={'class':['brb-b-s con marg-btt','cnt-rel con']}),
- dict(name='form', attrs={'class':'form'})]
+ dict(name='form', attrs={'class':'form'}),
+ dict(name='ul', attrs={'id':['cont-tags','pag-1']})]
remove_tags_before = dict(name='div' , attrs={'id':'dts'})
remove_tags_after = dict(name='div' , attrs={'id':'com'})
def get_cover_url(self):
- cover = None
- st = time.localtime()
- year = str(st.tm_year)
- month = "%.2d" % st.tm_mon
- day = "%.2d" % st.tm_mday
+ cover = None
+ st = time.localtime()
+ year = str(st.tm_year)
+ month = "%.2d" % st.tm_mon
+ day = "%.2d" % st.tm_mday
#[url]http://oldorigin-www.heraldo.es/20101211/primeras/portada_aragon.pdf[/url]
- cover='http://oldorigin-www.heraldo.es/'+ year + month + day +'/primeras/portada_aragon.pdf'
- br = BasicNewsRecipe.get_browser()
- try:
- br.open(cover)
- except:
- self.log("\nPortada no disponible")
- cover ='http://www.heraldo.es/MODULOS/global/publico/interfaces/img/logo-Heraldo.png'
- return cover
-
+ cover='http://oldorigin-www.heraldo.es/'+ year + month + day +'/primeras/portada_aragon.pdf'
+ br = BasicNewsRecipe.get_browser()
+ try:
+ br.open(cover)
+ except:
+ self.log("\nPortada no disponible")
+ cover ='http://www.heraldo.es/MODULOS/global/publico/interfaces/img/logo-Heraldo.png'
+ return cover
extra_css = '''
- h2{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:xx-large;}
- '''
+ .con strong{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:16px;}
+ .con h2{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:30px;}
+ .con span{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:12px;}
+ .ent {font-family:Arial,Helvetica,sans-serif; font-weight:normal; font-style:italic; font-size:18px;}
+ img{margin-bottom: 0.4em}
+ '''
+
+ preprocess_regexps = [
+
+# To separate the comments with a blank line
+ (re.compile(r'
Date: Mon, 10 Jan 2011 13:23:07 +0000
Subject: [PATCH 12/17] Fix for #8266: exception when book has no author.
---
src/calibre/library/sqlite.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/calibre/library/sqlite.py b/src/calibre/library/sqlite.py
index 75856dd0f6..bd5a1f8ab9 100644
--- a/src/calibre/library/sqlite.py
+++ b/src/calibre/library/sqlite.py
@@ -99,7 +99,7 @@ class AumSortedConcatenate(object):
def finalize(self):
keys = self.ans.keys()
if len(keys) == 0:
- return None
+ return 'Unknown:::Unknown'
if len(keys) == 1:
return self.ans[keys[0]]
return ':#:'.join([self.ans[v] for v in sorted(keys)])
From cc736d3326f2e5551bfa75dd6aa3854b993f467f Mon Sep 17 00:00:00 2001
From: Charles Haley <>
Date: Mon, 10 Jan 2011 16:31:28 +0000
Subject: [PATCH 13/17] Add capability and option to Sony driver to sync covers
during automatic management
---
src/calibre/devices/prs505/driver.py | 36 ++++++++++++++++++++++++----
1 file changed, 32 insertions(+), 4 deletions(-)
diff --git a/src/calibre/devices/prs505/driver.py b/src/calibre/devices/prs505/driver.py
index 98a7241a36..874fbe4b10 100644
--- a/src/calibre/devices/prs505/driver.py
+++ b/src/calibre/devices/prs505/driver.py
@@ -76,12 +76,23 @@ class PRS505(USBMS):
'sending DRMed books in which you cannot change the cover.'
' WARNING: This option should only be used with newer '
'SONY readers: 350, 650, 950 and newer.'),
+ _('Refresh separate covers when using automatic management (newer readers)') +
+ ':::' +
+ _('Set this option to have separate book covers uploaded '
+ 'every time you connect your device. Unset this option if '
+ 'you have so many books on the reader that performance is '
+ 'unacceptable.')
]
EXTRA_CUSTOMIZATION_DEFAULT = [
', '.join(['series', 'tags']),
+ False,
False
]
+ OPT_COLLECTIONS = 0
+ OPT_UPLOAD_COVERS = 1
+ OPT_REFRESH_COVERS = 2
+
plugboard = None
plugboard_func = None
@@ -171,7 +182,7 @@ class PRS505(USBMS):
opts = self.settings()
if opts.extra_customization:
collections = [x.strip() for x in
- opts.extra_customization[0].split(',')]
+ opts.extra_customization[self.OPT_COLLECTIONS].split(',')]
else:
collections = []
debug_print('PRS505: collection fields:', collections)
@@ -183,6 +194,20 @@ class PRS505(USBMS):
c.update(blists, collections, pb)
c.write()
+ if opts.extra_customization[self.OPT_REFRESH_COVERS]:
+ debug_print('PRS505: uploading covers in sync_booklists')
+ for idx,bl in blists.items():
+ prefix = self._card_a_prefix if idx == 1 else \
+ self._card_b_prefix if idx == 2 \
+ else self._main_prefix
+ for book in bl:
+ p = os.path.join(prefix, book.lpath)
+ self._upload_cover(os.path.dirname(p),
+ os.path.splitext(os.path.basename(p))[0],
+ book, p)
+ else:
+ debug_print('PRS505: NOT uploading covers in sync_booklists')
+
USBMS.sync_booklists(self, booklists, end_session=end_session)
debug_print('PRS505: finished sync_booklists')
@@ -199,11 +224,14 @@ class PRS505(USBMS):
def upload_cover(self, path, filename, metadata, filepath):
opts = self.settings()
- if not opts.extra_customization[1]:
+ if not opts.extra_customization[self.OPT_UPLOAD_COVERS]:
# Building thumbnails disabled
- debug_print('PRS505: not uploading covers')
+ debug_print('PRS505: not uploading cover')
return
- debug_print('PRS505: uploading covers')
+ debug_print('PRS505: uploading cover')
+ self._upload_cover(path, filename, metadata, filepath)
+
+ def _upload_cover(self, path, filename, metadata, filepath):
if metadata.thumbnail and metadata.thumbnail[-1]:
path = path.replace('/', os.sep)
is_main = path.startswith(self._main_prefix)
From 03f70c156c7d557d61db1e348f11bb2a997d90e1 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Mon, 10 Jan 2011 10:44:09 -0700
Subject: [PATCH 14/17] RTF Input: Fix regression that broke the Preprocess
HTML option
---
src/calibre/ebooks/conversion/utils.py | 6 +++---
src/calibre/ebooks/rtf/input.py | 2 +-
src/calibre/ebooks/txt/input.py | 6 +++---
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/calibre/ebooks/conversion/utils.py b/src/calibre/ebooks/conversion/utils.py
index 52d1bcc619..dac93fa2e2 100644
--- a/src/calibre/ebooks/conversion/utils.py
+++ b/src/calibre/ebooks/conversion/utils.py
@@ -191,15 +191,15 @@ class PreProcessor(object):
blanklines = "\s*(?P<(p|span|div)[^>]*>\s*(<(p|span|div)[^>]*>\s*(span|p|div)>\s*)(span|p|div)>\s*){0,3}\s*"
line_opening = "<(span|div|p)[^>]*>\s*(<(span|div|p)[^>]*>)?\s*"
txt_line_wrap = u"((\u0020|\u0009)*\n){1,4}"
-
+
unwrap_regex = lookahead+line_ending+blanklines+line_opening
if format == 'txt':
unwrap_regex = lookahead+txt_line_wrap
-
+
unwrap = re.compile(u"%s" % unwrap_regex, re.UNICODE)
content = unwrap.sub(' ', content)
return content
-
+
def __call__(self, html):
self.log("********* Preprocessing HTML *********")
diff --git a/src/calibre/ebooks/rtf/input.py b/src/calibre/ebooks/rtf/input.py
index 8c7561f68c..5154373eda 100644
--- a/src/calibre/ebooks/rtf/input.py
+++ b/src/calibre/ebooks/rtf/input.py
@@ -296,7 +296,7 @@ class RTFInput(InputFormatPlugin):
u'\u00a0
\n'.encode('utf-8'), res)
if self.opts.preprocess_html:
preprocessor = PreProcessor(self.opts, log=getattr(self, 'log', None))
- res = preprocessor(res)
+ res = preprocessor(res.decode('utf-8')).encode('utf-8')
f.write(res)
self.write_inline_css(inline_class, border_styles)
stream.seek(0)
diff --git a/src/calibre/ebooks/txt/input.py b/src/calibre/ebooks/txt/input.py
index 3957391494..aaff8b55c0 100644
--- a/src/calibre/ebooks/txt/input.py
+++ b/src/calibre/ebooks/txt/input.py
@@ -53,7 +53,7 @@ class TXTInput(InputFormatPlugin):
def convert(self, stream, options, file_ext, log,
accelerators):
log.debug('Reading text from file...')
-
+
txt = stream.read()
# Get the encoding of the document.
if options.input_encoding:
@@ -80,7 +80,7 @@ class TXTInput(InputFormatPlugin):
# Get length for hyphen removal and punctuation unwrap
docanalysis = DocAnalysis('txt', txt)
length = docanalysis.line_length(.5)
-
+
if options.formatting_type == 'auto':
options.formatting_type = detect_formatting_type(txt)
@@ -122,7 +122,7 @@ class TXTInput(InputFormatPlugin):
txt = preprocessor.punctuation_unwrap(length, txt, 'txt')
flow_size = getattr(options, 'flow_size', 0)
-
+
if options.formatting_type == 'heuristic':
html = convert_heuristic(txt, epub_split_size_kb=flow_size)
else:
From 27ab085fc6db7521c55792a5ebc7a16790ac6431 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Mon, 10 Jan 2011 11:26:09 -0700
Subject: [PATCH 15/17] Tyzden by zemiak. Fixes #405 (New news feed)
---
resources/recipes/tyzden.recipe | 80 +++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
create mode 100644 resources/recipes/tyzden.recipe
diff --git a/resources/recipes/tyzden.recipe b/resources/recipes/tyzden.recipe
new file mode 100644
index 0000000000..c206244ff6
--- /dev/null
+++ b/resources/recipes/tyzden.recipe
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+__license__ = 'GPL v3'
+__copyright__ = '2011, Miroslav Vasko zemiak@gmail.com'
+
+'''
+.tyzden, a weekly news magazine (a week old issue)
+'''
+from calibre import strftime
+from calibre.web.feeds.news import BasicNewsRecipe
+from datetime import date
+import re
+
+class TyzdenRecipe(BasicNewsRecipe):
+ __license__ = 'GPL v3'
+ __author__ = 'zemiak'
+ language = 'sk'
+ version = 1
+
+ publisher = u'www.tyzden.sk'
+ category = u'Magazine'
+ description = u'A conservative weekly magazine. The latest free issue'
+
+ today = date.today()
+ iso = today.isocalendar()
+ year = iso[0]
+ weeknum = iso[1]
+
+ if (weeknum > 1):
+ weeknum -= 1
+
+ title = u'.tyzden ' + str(weeknum) + '/' + str(year)
+
+ base_url_path = 'http://www.tyzden.sk/casopis/' + str(year) + '/' + str(weeknum)
+ base_url = base_url_path + '.html'
+
+ oldest_article = 20
+ max_articles_per_feed = 100
+ remove_javascript = True
+
+ use_embedded_content = False
+ no_stylesheets = True
+
+ keep_only_tags = []
+ keep_only_tags.append(dict(name = 'h1'))
+ keep_only_tags.append(dict(name = 'div', attrs = {'class': 'text_area top_nofoto'}))
+ keep_only_tags.append(dict(name = 'div', attrs = {'class': 'text_block'}))
+
+ remove_tags_after = [dict(name = 'div', attrs = {'class': 'text_block'})]
+
+ def find_sections(self):
+ soup = self.index_to_soup(self.base_url)
+ # find cover pic
+ imgdiv = soup.find('div', attrs = {'class': 'foto'})
+ if imgdiv is not None:
+ img = imgdiv.find('img')
+ if img is not None:
+ self.cover_url = 'http://www.tyzden.sk/' + img['src']
+ # end find cover pic
+
+ for s in soup.findAll('a', attrs={'href': re.compile(r'rubrika/.*')}):
+ yield (self.tag_to_string(s), s)
+
+ def find_articles(self, soup):
+ for art in soup.findAllNext('a'):
+ if (not art['href'].startswith('casopis/')):
+ break;
+
+ url = art['href']
+ title = self.tag_to_string(art)
+ yield {
+ 'title': title, 'url':self.base_url_path + '/' + url, 'description':title,
+ 'date' : strftime('%a, %d %b'),
+ }
+
+ def parse_index(self):
+ feeds = []
+ for title, soup in self.find_sections():
+ feeds.append((title, list(self.find_articles(soup))))
+
+ return feeds
From 6dc9142043089434c26c8887001b32c779f74a56 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Mon, 10 Jan 2011 11:40:14 -0700
Subject: [PATCH 16/17] Fix #8040 (Device Support for Archos 70)
---
src/calibre/devices/android/driver.py | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py
index 73c930778e..5a82882dfa 100644
--- a/src/calibre/devices/android/driver.py
+++ b/src/calibre/devices/android/driver.py
@@ -53,6 +53,9 @@ class ANDROID(USBMS):
# LG
0x1004 : { 0x61cc : [0x100] },
+ # Archos
+ 0x0e79 : { 0x1420 : [0x0216]},
+
}
EBOOK_DIR_MAIN = ['eBooks/import', 'wordplayer/calibretransfer', 'Books']
EXTRA_CUSTOMIZATION_MESSAGE = _('Comma separated list of directories to '
@@ -61,18 +64,19 @@ class ANDROID(USBMS):
EXTRA_CUSTOMIZATION_DEFAULT = ', '.join(EBOOK_DIR_MAIN)
VENDOR_NAME = ['HTC', 'MOTOROLA', 'GOOGLE_', 'ANDROID', 'ACER',
- 'GT-I5700', 'SAMSUNG', 'DELL', 'LINUX', 'GOOGLE']
+ 'GT-I5700', 'SAMSUNG', 'DELL', 'LINUX', 'GOOGLE', 'ARCHOS']
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE',
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897',
'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID',
'SCH-I500_CARD', 'SPH-D700_CARD', 'MB810', 'GT-P1000', 'DESIRE',
- 'SGH-T849', '_MB300']
+ 'SGH-T849', '_MB300', 'A70S']
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
- 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD']
+ 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD',
+ 'A70S']
- OSX_MAIN_MEM = 'HTC Android Phone Media'
+ OSX_MAIN_MEM = 'Android Device Main Memory'
- MAIN_MEMORY_VOLUME_LABEL = 'Android Phone Internal Memory'
+ MAIN_MEMORY_VOLUME_LABEL = 'Android Device Main Memory'
SUPPORTS_SUB_DIRS = True
From 8796a60db0f183b75f9d662d5cde481a9827db55 Mon Sep 17 00:00:00 2001
From: John Schember
Date: Mon, 10 Jan 2011 18:42:39 -0500
Subject: [PATCH 17/17] TXT Output: Write hr as scene break marker.
---
src/calibre/ebooks/txt/txtml.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/calibre/ebooks/txt/txtml.py b/src/calibre/ebooks/txt/txtml.py
index 786f50824d..00992a8612 100644
--- a/src/calibre/ebooks/txt/txtml.py
+++ b/src/calibre/ebooks/txt/txtml.py
@@ -218,6 +218,10 @@ class TXTMLizer(object):
if tag in SPACE_TAGS:
text.append(u' ')
+
+ # Scene breaks.
+ if tag == 'hr':
+ text.append('\n\n* * *\n\n')
# Process tags that contain text.
if hasattr(elem, 'text') and elem.text: