From 68df332cadc7f4ba5c884306e485591063b75085 Mon Sep 17 00:00:00 2001
From: GRiker
Date: Sat, 18 Sep 2010 05:14:41 -0600
Subject: [PATCH 01/37] GwR apple driver patch
---
src/calibre/devices/apple/driver.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/calibre/devices/apple/driver.py b/src/calibre/devices/apple/driver.py
index 5fe36faf75..0946bd2f51 100644
--- a/src/calibre/devices/apple/driver.py
+++ b/src/calibre/devices/apple/driver.py
@@ -739,7 +739,7 @@ class ITUNES(DriverBase):
# Purge the booklist, self.cached_books, thumb cache
for i,bl_book in enumerate(booklists[0]):
- if DEBUG:
+ if False:
self.log.info(" evaluating '%s' by '%s' uuid:%s" %
(bl_book.title, bl_book.author,bl_book.uuid))
From 4416264c0289b80a7eda510c375591f88e1ab8d4 Mon Sep 17 00:00:00 2001
From: GRiker
Date: Sat, 18 Sep 2010 19:43:02 -0600
Subject: [PATCH 02/37] GwR wip tweak_epub
---
src/calibre/customize/builtins.py | 6 ++++-
src/calibre/gui2/actions/tweak_epub.py | 34 ++++++++++++++++++++++++++
2 files changed, 39 insertions(+), 1 deletion(-)
create mode 100755 src/calibre/gui2/actions/tweak_epub.py
diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py
index 68df832048..ec9f7e2bc2 100644
--- a/src/calibre/customize/builtins.py
+++ b/src/calibre/customize/builtins.py
@@ -666,13 +666,17 @@ class ActionCopyToLibrary(InterfaceActionBase):
name = 'Copy To Library'
actual_plugin = 'calibre.gui2.actions.copy_to_library:CopyToLibraryAction'
+class ActionTweakEpub(InterfaceActionBase):
+ name = 'Tweak ePub'
+ actual_plugin = 'calibre.gui2.actions.tweak_epub:TweakEpubAction'
+
plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog,
ActionConvert, ActionDelete, ActionEditMetadata, ActionView,
ActionFetchNews, ActionSaveToDisk, ActionShowBookDetails,
ActionRestart, ActionOpenFolder, ActionConnectShare,
ActionSendToDevice, ActionHelp, ActionPreferences, ActionSimilarBooks,
ActionAddToLibrary, ActionEditCollections, ActionChooseLibrary,
- ActionCopyToLibrary]
+ ActionCopyToLibrary, ActionTweakEpub]
# }}}
diff --git a/src/calibre/gui2/actions/tweak_epub.py b/src/calibre/gui2/actions/tweak_epub.py
new file mode 100755
index 0000000000..5f49c57379
--- /dev/null
+++ b/src/calibre/gui2/actions/tweak_epub.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
+
+__license__ = 'GPL v3'
+__copyright__ = '2010, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+from calibre.gui2.actions import InterfaceAction
+
+class TweakEpubAction(InterfaceAction):
+
+ name = 'Tweak ePub'
+ action_spec = (_('Edit ePub in situ'), 'document_open.png', None, None)
+ dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
+ action_type = 'current'
+
+ def genesis(self):
+ self.qaction.triggered.connect(self.edit_epub_in_situ)
+ print "gui2.actions.tweak_epub:TweakEpubAction.genesis()"
+
+ def initialization_complete(self):
+ print "gui2.actions.tweak_epub:TweakEpubAction.initialization_complete()"
+
+ def library_changed(self, db):
+ print "gui2.actions.tweak_epub:TweakEpubAction.library_changed()"
+
+ def location_selected(self, loc):
+ print "gui2.actions.tweak_epub:TweakEpubAction.location_selected()"
+
+ def shutting_down(self):
+ print "gui2.actions.tweak_epub:TweakEpubAction.shutting_down()"
+
+ def edit_epub_in_situ(self, *args):
+ print "gui2.actions.tweak_epub:TweakEpubAction.edit_epub_in_situ()"
From dec27fbaa1e9544675d6d10bda566d83fd7a85f2 Mon Sep 17 00:00:00 2001
From: ldolse
Date: Sun, 19 Sep 2010 13:02:02 +0800
Subject: [PATCH 03/37] new dehyphenation algorithm, using the document as a
dictionary
---
src/calibre/ebooks/conversion/preprocess.py | 58 +++++++++++++++++++--
src/calibre/ebooks/conversion/utils.py | 13 +++--
2 files changed, 62 insertions(+), 9 deletions(-)
diff --git a/src/calibre/ebooks/conversion/preprocess.py b/src/calibre/ebooks/conversion/preprocess.py
index 03a0047927..a1e28b2554 100644
--- a/src/calibre/ebooks/conversion/preprocess.py
+++ b/src/calibre/ebooks/conversion/preprocess.py
@@ -106,6 +106,50 @@ def line_length(format, raw, percent):
return lengths[index]
+class Dehyphenator(object):
+ '''
+ Analyzes words to determine whether hyphens should be retained/removed. Uses the document
+ itself is as a dictionary. This method handles all languages along with uncommon, made-up, and
+ scientific words. The primary disadvantage is that words appearing only once in the document
+ retain hyphens.
+ '''
+
+ def dehyphenate(self, match):
+ firsthalf = match.group('firstpart')
+ secondhalf = match.group('secondpart')
+ hyphenated = str(firsthalf) + "-" + str(secondhalf)
+ dehyphenated = str(firsthalf) + str(secondhalf)
+ # Add common suffixes to the regex below to increase the likelihood of a match -
+ # don't add suffixes which are also complete words, such as 'able' or 'sex'
+ removesuffixes = re.compile(r"((ed)?ly|(')?s|a?(t|s)ion(s|al(ly)?)?|ings?|(i)?ous|(i|a)ty|(it)?ies|ive|gence|istic|(e|a)nce|ment(s)?|ism|ated|(e|u)ct(ed)?|ed|(i|ed)?ness|(e|a)ncy|ble|ier|al|ex)$", re.IGNORECASE)
+ lookupword = removesuffixes.sub('', dehyphenated)
+ # remove prefixes if the prefix was not already the point of hyphenation
+ prefixes = re.compile(r'^(un|in|ex)$', re.IGNORECASE)
+ removeprefix = re.compile(r'^(un|in|ex)', re.IGNORECASE)
+ if prefixes.match(firsthalf) is None:
+ lookupword = removeprefix.sub('', lookupword)
+ booklookup = re.compile(u'%s' % lookupword, re.IGNORECASE)
+ #print "lookup word is: "+str(lookupword)+", orig is: " + str(hyphenated)
+ match = booklookup.search(self.html)
+ if match:
+ #print "returned dehyphenated word: " + str(dehyphenated)
+ return dehyphenated
+ else:
+ #print "returned hyphenated word: " + str(hyphenated)
+ return hyphenated
+
+ def __call__(self, html, format, length=1):
+ self.html = html
+ if format == 'html':
+ intextmatch = re.compile(u'(?<=.{%i})(?P[^“"\s>]+)-\s*(?=<)(\s*([iubp]>\s*<[iubp][^>]*>\s*)?]*>|[iubp]>\s*<[iubp][^>]*>)?\s*(?P[\w\d]+)' % length)
+ elif format == 'pdf':
+ intextmatch = re.compile(u'(?<=.{%i})(?P[^“"\s>]+)-\s*(|[iub]>\s*
\s*<[iub]>)\s*(?P[\w\d]+)'% length)
+ elif format == 'individual_words':
+ intextmatch = re.compile('>[^<]*\b(?P[^"\s>]+)-(?P\s*(?=[[a-z\d])'), lambda match: ''))
+ # unwrap em/en dashes
+ end_rules.append((re.compile(u'(?<=[–—])\s*\s*(?=[[a-z\d])'), lambda match: ''))
# unwrap/delete soft hyphens
end_rules.append((re.compile(u'[](\s*
)+\s*(?=[[a-z\d])'), lambda match: ''))
# unwrap/delete soft hyphens with formatting
@@ -350,7 +393,7 @@ class HTMLPreProcessor(object):
# print "The pdf line length returned is " + str(length)
end_rules.append(
# Un wrap using punctuation
- (re.compile(r'(?<=.{%i}([a-z,:)\-IA]|(?(i|b|u)>)?\s*(
\s*)+\s*(?=(<(i|b|u)>)?\s*[\w\d$(])' % length, re.UNICODE), wrap_lines),
+ (re.compile(r'(?<=.{%i}([a-z,:)\IA]|(?(i|b|u)>)?\s*(\s*)+\s*(?=(<(i|b|u)>)?\s*[\w\d$(])' % length, re.UNICODE), wrap_lines),
)
for rule in self.PREPROCESS + start_rules:
@@ -380,6 +423,11 @@ class HTMLPreProcessor(object):
for rule in rules + end_rules:
html = rule[0].sub(rule[1], html)
+ if is_pdftohtml:
+ # Dehyphenate
+ dehyphenator = Dehyphenator()
+ html = dehyphenator(html,'pdf', length)
+
#dump(html, 'post-preprocess')
# Handle broken XHTML w/ SVG (ugh)
diff --git a/src/calibre/ebooks/conversion/utils.py b/src/calibre/ebooks/conversion/utils.py
index 37fd169cb1..f9178ead0b 100644
--- a/src/calibre/ebooks/conversion/utils.py
+++ b/src/calibre/ebooks/conversion/utils.py
@@ -6,7 +6,7 @@ __copyright__ = '2010, Kovid Goyal '
__docformat__ = 'restructuredtext en'
import re
-from calibre.ebooks.conversion.preprocess import line_length
+from calibre.ebooks.conversion.preprocess import line_length, Dehyphenator
from calibre.utils.logging import default_log
class PreProcessor(object):
@@ -132,7 +132,6 @@ class PreProcessor(object):
# Arrange line feeds and
tags so the line_length and no_markup functions work correctly
html = re.sub(r"\s*
", "\n", html)
html = re.sub(r"\s*\s*", "\n
", html)
- #self.log("\n\n\n\n\n\n\n\n\n\n\n"+html+"\n\n\n\n\n\n\n\n\n\n\n\n\n")
# detect chapters/sections to match xpath or splitting logic
heading = re.compile(']*>', re.IGNORECASE)
self.html_preprocess_sections = len(heading.findall(html))
@@ -174,10 +173,16 @@ class PreProcessor(object):
length = line_length(format, html, getattr(self.extra_opts,
'html_unwrap_factor', 0.4))
self.log("*** Median line length is " + str(length) + ", calculated with " + format + " format ***")
+ max_length = length * 1.4
+ min_max = str("(?<=.{"+str(length)+"})(?\s*([iubp]>\s*<[iubp][^>]*>\s*)?]*>|[iubp]>\s*<[iubp][^>]*>)?\s*', '', html)
- html = re.sub(u'(?<=[-\u2013\u2014])\s*(?=<)( \s*([iubp]>\s*<[iubp][^>]*>\s*)?]*>|[iubp]>\s*<[iubp][^>]*>)?\s*(?=[[a-z\d])', '', html)
+ html = re.sub(u'%s(?<=[\u2013\u2014])\s*(?=<)( \s*([iubp]>\s*<[iubp][^>]*>\s*)?]*>|[iubp]>\s*<[iubp][^>]*>)?\s*(?=[[a-z\d])' % min_max, '', html)
+ # Dehyphenate
+ dehyphenator = Dehyphenator()
+ html = dehyphenator(html,'html', length)
# Unwrap lines using punctation and line length
unwrap = re.compile(r"(?<=.{%i}([a-z,;):\IA]|(?\s*((p|span|div)>)?\s*(?P<(p|span|div)[^>]*>\s*(<(p|span|div)[^>]*>\s*(span|p|div)>\s*)(span|p|div)>\s*){0,3}\s*<(span|div|p)[^>]*>\s*(<(span|div|p)[^>]*>)?\s*" % length, re.UNICODE)
From 90ff41dfb2ba554f64cb61dd5d1a6de599941b32 Mon Sep 17 00:00:00 2001
From: GRiker
Date: Sun, 19 Sep 2010 03:54:39 -0600
Subject: [PATCH 04/37] KG fix for TweakEpub
---
src/calibre/gui2/actions/tweak_epub.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/calibre/gui2/actions/tweak_epub.py b/src/calibre/gui2/actions/tweak_epub.py
index 5f49c57379..020e9c0382 100755
--- a/src/calibre/gui2/actions/tweak_epub.py
+++ b/src/calibre/gui2/actions/tweak_epub.py
@@ -11,7 +11,7 @@ class TweakEpubAction(InterfaceAction):
name = 'Tweak ePub'
action_spec = (_('Edit ePub in situ'), 'document_open.png', None, None)
- dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
+ #dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
action_type = 'current'
def genesis(self):
From 053d60331fcfb9f82e141ebc11a625b1acd3e1a4 Mon Sep 17 00:00:00 2001
From: ldolse
Date: Sun, 19 Sep 2010 23:07:07 +0800
Subject: [PATCH 05/37] regex optimizations
---
src/calibre/ebooks/conversion/preprocess.py | 2 +-
src/calibre/ebooks/conversion/utils.py | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/calibre/ebooks/conversion/preprocess.py b/src/calibre/ebooks/conversion/preprocess.py
index 16bfb42d1f..7f13cefcaa 100644
--- a/src/calibre/ebooks/conversion/preprocess.py
+++ b/src/calibre/ebooks/conversion/preprocess.py
@@ -121,7 +121,7 @@ class Dehyphenator(object):
dehyphenated = str(firsthalf) + str(secondhalf)
# Add common suffixes to the regex below to increase the likelihood of a match -
# don't add suffixes which are also complete words, such as 'able' or 'sex'
- removesuffixes = re.compile(r"((ed)?ly|(')?s|a?(t|s)ion(s|al(ly)?)?|ings?|(i)?ous|(i|a)ty|(it)?ies|ive|gence|istic|(e|a)nce|ment(s)?|ism|ated|(e|u)ct(ed)?|ed|(i|ed)?ness|(e|a)ncy|ble|ier|al|ex)$", re.IGNORECASE)
+ removesuffixes = re.compile(r"((ed)?ly|('e)?s|a?(t|s)ion(s|al(ly)?)?|ings?|(i)?ous|(i|a)ty|(it)?ies|ive|gence|istic|(e|a)nce|ment(s)?|ism|ated|(e|u)ct(ed)?|ed|(i|ed)?ness|(e|a)ncy|ble|ier|al|ex)$", re.IGNORECASE)
lookupword = removesuffixes.sub('', dehyphenated)
# remove prefixes if the prefix was not already the point of hyphenation
prefixes = re.compile(r'^(un|in|ex)$', re.IGNORECASE)
diff --git a/src/calibre/ebooks/conversion/utils.py b/src/calibre/ebooks/conversion/utils.py
index f9178ead0b..6a5eaa4a34 100644
--- a/src/calibre/ebooks/conversion/utils.py
+++ b/src/calibre/ebooks/conversion/utils.py
@@ -114,7 +114,7 @@ class PreProcessor(object):
html = re.sub(ur'\s*\s* ', ' ', html)
# Get rid of empty span, bold, & italics tags
html = re.sub(r"\s*]*>\s*(]>\s* ){0,2}\s* \s*", " ", html)
- html = re.sub(r"\s*<[ibu]>\s*(<[ibu]>\s*[ibu]>\s*){0,2}\s*[ibu]>", " ", html)
+ html = re.sub(r"\s*<[ibu][^>]*>\s*(<[ibu][^>]*>\s*[ibu]>\s*){0,2}\s*[ibu]>", " ", html)
html = re.sub(r"\s*]*>\s*(]>\s* ){0,2}\s* \s*", " ", html)
# If more than 40% of the lines are empty paragraphs then delete them to clean up spacing
@@ -139,16 +139,16 @@ class PreProcessor(object):
#
# Start with most typical chapter headings, get more aggressive until one works
if self.html_preprocess_sections < 10:
- chapdetect = re.compile(r'(?=?(br|p))(<(/?br|p)[^>]*>)\s*(<[ibu]>){0,2}\s*(]*>)?\s*(<[ibu]>){0,2}\s*(]*>)?\s*(?P(<[ibu]>){0,2}\s*.?(Introduction|Synopsis|Acknowledgements|Chapter|Epilogue|Volume|Prologue|Book\s|Part\s|Dedication)\s*([\d\w-]+\:?\s*){0,8}\s*([ibu]>){0,2})\s*( )?s*([ibu]>){0,2}\s*( )?\s*((p|/?br)>)\s*\s*(\s*]*>\s*
){0,2}\s*(<(/?br|p)[^>]*>\s*(<[ibu]>){0,2}\s*(]*>)?\s*(?P(<[ibu]>){0,2}(\s*[\w\'\"-]+){1,5}\s*([ibu]>){0,2})\s*( )?\s*([ibu]>){0,2}\s*((br|p)>))?', re.IGNORECASE|re.VERBOSE)
+ chapdetect = re.compile(r'(?=?(br|p))(<(/?br|p)[^>]*>)\s*(<[ibu][^>]*>){0,2}\s*(]*>)?\s*(<[ibu][^>]*>){0,2}\s*(]*>)?\s*(?P(<[ibu][^>]*>){0,2}\s*.?(Introduction|Synopsis|Acknowledgements|Chapter|Epilogue|Volume|Prologue|Book\s|Part\s|Dedication)\s*([\d\w-]+\:?\s*){0,8}\s*([ibu]>){0,2})\s*( )?s*([ibu]>){0,2}\s*( )?\s*((p|/?br)>)\s*\s*(\s*]*>\s*
){0,2}\s*(<(/?br|p)[^>]*>\s*(<[ibu][^>]*>){0,2}\s*(]*>)?\s*(?P(<[ibu][^>]*>){0,2}(\s*[\w\'\"-]+){1,5}\s*([ibu]>){0,2})\s*( )?\s*([ibu]>){0,2}\s*((br|p)>))?', re.IGNORECASE|re.VERBOSE)
html = chapdetect.sub(self.chapter_head, html)
if self.html_preprocess_sections < 10:
self.log("not enough chapters, only " + str(self.html_preprocess_sections) + ", trying numeric chapters")
- chapdetect2 = re.compile(r'(?=?(br|p))(<(/?br|p)[^>]*>)\s*(<[ibu]>){0,2}\s*(]*>)?\s*(?P(<[ibu]>){0,2}\s*.?(\d+\.?|(CHAPTER\s*([\dA-Z\-\'\"\?\.!#,]+\s*){1,10}))\s*([ibu]>){0,2})\s*( )?\s*([ibu]>){0,2}\s*((p|/?br)>)\s*(<(/?br|p)[^>]*>\s*(<[ibu]>){0,2}\s*(]*>)?\s*(?P(<[ibu]>){0,2}(\s*[\w\'\"-]+){1,5}\s*([ibu]>){0,2})\s*( )?\s*([ibu]>){0,2}\s*((br|p)>))?', re.UNICODE)
+ chapdetect2 = re.compile(r'(?=?(br|p))(<(/?br|p)[^>]*>)\s*(<[ibu][^>]*>){0,2}\s*(]*>)?\s*(?P(<[ibu][^>]*>){0,2}\s*.?(\d+\.?|(CHAPTER\s*([\dA-Z\-\'\"\?\.!#,]+\s*){1,10}))\s*([ibu]>){0,2})\s*( )?\s*([ibu]>){0,2}\s*((p|/?br)>)\s*(<(/?br|p)[^>]*>\s*(<[ibu][^>]*>){0,2}\s*(]*>)?\s*(?P(<[ibu][^>]*>){0,2}(\s*[\w\'\"-]+){1,5}\s*([ibu]>){0,2})\s*( )?\s*([ibu]>){0,2}\s*((br|p)>))?', re.UNICODE)
html = chapdetect2.sub(self.chapter_head, html)
if self.html_preprocess_sections < 10:
self.log("not enough chapters, only " + str(self.html_preprocess_sections) + ", trying with uppercase words")
- chapdetect2 = re.compile(r'(?=?(br|p))(<(/?br|p)[^>]*>)\s*(<[ibu]>){0,2}\s*(]*>)?\s*(?P(<[ibu]>){0,2}\s*.?([A-Z#\-\s]+)\s*([ibu]>){0,2})\s*( )?\s*([ibu]>){0,2}\s*((p|/?br)>)\s*(<(/?br|p)[^>]*>\s*(<[ibu]>){0,2}\s*(]*>)?\s*(?P(<[ibu]>){0,2}(\s*[\w\'\"-]+){1,5}\s*([ibu]>){0,2})\s*( )?\s*([ibu]>){0,2}\s*((br|p)>))?', re.UNICODE)
+ chapdetect2 = re.compile(r'(?=?(br|p))(<(/?br|p)[^>]*>)\s*(<[ibu][^>]*>){0,2}\s*(]*>)?\s*(?P(<[ibu][^>]*>){0,2}\s*.?([A-Z#\-\s]+)\s*([ibu]>){0,2})\s*( )?\s*([ibu]>){0,2}\s*((p|/?br)>)\s*(<(/?br|p)[^>]*>\s*(<[ibu][^>]*>){0,2}\s*(]*>)?\s*(?P(<[ibu][^>]*>){0,2}(\s*[\w\'\"-]+){1,5}\s*([ibu]>){0,2})\s*( )?\s*([ibu]>){0,2}\s*((br|p)>))?', re.UNICODE)
html = chapdetect2.sub(self.chapter_head, html)
###### Unwrap lines ######
@@ -191,7 +191,7 @@ class PreProcessor(object):
# If still no sections after unwrapping mark split points on lines with no punctuation
if self.html_preprocess_sections < 10:
self.log("Looking for more split points based on punctuation, currently have " + str(self.html_preprocess_sections))
- chapdetect3 = re.compile(r'<(?P(p|div)[^>]*)>\s*(?P(]*>)?\s*(<[ibu]>){0,2}\s*(]*>)?\s*(<[ibu]>){0,2}\s*(]*>)?\s*.?([a-z#-*]+\s*){1,5}\s*\s*( )?([ibu]>){0,2}\s*( )?\s*([ibu]>){0,2}\s*( )?\s*(p|div)>)', re.IGNORECASE)
+ chapdetect3 = re.compile(r'<(?P(p|div)[^>]*)>\s*(?P(]*>)?\s*(<[ibu][^>]*>){0,2}\s*(]*>)?\s*(<[ibu][^>]*>){0,2}\s*(]*>)?\s*.?(?=[a-z#\-*\s]+<)([a-z#-*]+\s*){1,5}\s*\s*( )?([ibu]>){0,2}\s*( )?\s*([ibu]>){0,2}\s*( )?\s*(p|div)>)', re.IGNORECASE)
html = chapdetect3.sub(self.chapter_break, html)
# search for places where a first or second level heading is immediately followed by another
# top level heading. demote the second heading to h3 to prevent splitting between chapter
From 980388f2bde3d4cb4b07673cb9e79c951aabd867 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Sun, 19 Sep 2010 09:48:39 -0600
Subject: [PATCH 06/37] Le Journal de Montreal by Luciano Furtado. Fixes #405
(New news feed)
---
resources/recipes/le_journal.recipe | 43 +++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 resources/recipes/le_journal.recipe
diff --git a/resources/recipes/le_journal.recipe b/resources/recipes/le_journal.recipe
new file mode 100644
index 0000000000..24a7d52164
--- /dev/null
+++ b/resources/recipes/le_journal.recipe
@@ -0,0 +1,43 @@
+__author__ = ' (lrfurtado@yahoo.com.br)'
+
+from calibre.web.feeds.news import BasicNewsRecipe
+
+class LeJournalDeMontrealRecipe(BasicNewsRecipe):
+
+ title = u'Le Journal de Montreal'
+ description = u'Le Journal de Montreal'
+ __author__ = 'Luciano Furtado'
+ language = 'fr'
+
+ oldest_article = 7
+ use_embedded_content=0
+ max_articles_per_feed = 15
+
+ remove_tags = [
+ dict(name='ul',attrs={'id':'mainNav'}),
+ dict(name='div',attrs={'id':'boxPolitique'}),
+ dict(name='div',attrs={'id':'boxScoop'}),
+ dict(name='div',attrs={'id':'DossierSpec'}),
+ dict(name='div',attrs={'id':'channelBoxes'}),
+ dict(name='div',attrs={'id':'sectionBoxes'}),
+ dict(name='div',attrs={'id':'header'}),
+ dict(name='div',attrs={'id':'footer'}),
+ dict(name='div',attrs={'id':'navbarCanoe_container'}),
+ dict(name='div',attrs={'id':'popularCanoe'}),
+ dict(name='div',attrs={'id':'textAds'}),
+ dict(name='div',attrs={'id':'24heures'}),
+ dict(name='div',attrs={'class':'bottomBox clear'}),
+ dict(name='div',attrs={'class':'articleControls thin'}),
+ ]
+
+
+ feeds = [
+ (u'Actualites',
+ u'http://www.canoe.com/rss/feed/nouvelles/ljm_actualites.xml'),
+ (u'Arts et spectacle',
+ u'http://www.canoe.com/rss/feed/nouvelles/ljm_arts.xml'),
+ (u'Sports',
+ u'http://www.canoe.com/rss/feed/nouvelles/ljm_sports.xml'),
+ (u'Chroniques',
+ u'http://www.canoe.com/rss/feed/nouvelles/ljm_chroniques.xml'),
+ ]
From 23cd4fd7833180d7036aa77c0c1efcbd09ca6a00 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Sun, 19 Sep 2010 10:16:41 -0600
Subject: [PATCH 07/37] Content server: Making serving of large files more
efficient.
---
src/calibre/library/server/content.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/calibre/library/server/content.py b/src/calibre/library/server/content.py
index 95794a8c1d..aeba8a3218 100644
--- a/src/calibre/library/server/content.py
+++ b/src/calibre/library/server/content.py
@@ -184,7 +184,7 @@ class ContentServer(object):
if path and os.path.exists(path):
updated = fromtimestamp(os.stat(path).st_mtime)
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
- return fmt.read()
+ return fmt
# }}}
From f4b885568343944d66950935df887f276eaa3b4f Mon Sep 17 00:00:00 2001
From: Timothy Legge
Date: Sun, 19 Sep 2010 21:46:13 -0300
Subject: [PATCH 08/37] KOBO: Fix issue where books that are read were getting
their status reset to Unread
---
src/calibre/devices/kobo/driver.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/calibre/devices/kobo/driver.py b/src/calibre/devices/kobo/driver.py
index 762a05d193..1171b74f5c 100644
--- a/src/calibre/devices/kobo/driver.py
+++ b/src/calibre/devices/kobo/driver.py
@@ -443,9 +443,9 @@ class KOBO(USBMS):
# 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/%\''
+ query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null and ReadStatus = 1 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/%\''
+ query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null and ReadStatus = 1 and ContentID not like \'file:///mnt/sd/%\''
try:
cursor.execute (query)
From 0fa7eef131080297085c0f4224907e351fc8e7fb Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Sun, 19 Sep 2010 19:01:53 -0600
Subject: [PATCH 09/37] Tagesanzeiger by noxxx
---
resources/recipes/tagesan.recipe | 45 ++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
create mode 100644 resources/recipes/tagesan.recipe
diff --git a/resources/recipes/tagesan.recipe b/resources/recipes/tagesan.recipe
new file mode 100644
index 0000000000..8514162598
--- /dev/null
+++ b/resources/recipes/tagesan.recipe
@@ -0,0 +1,45 @@
+from calibre.web.feeds.news import BasicNewsRecipe
+
+class AdvancedUserRecipe1284927619(BasicNewsRecipe):
+ title = u'Tagesanzeiger'
+ publisher = u'Tamedia AG'
+ oldest_article = 2
+ __author__ = 'noxxx'
+ max_articles_per_feed = 100
+ description = 'tagesanzeiger.ch: Nichts verpassen'
+ category = 'News, Politik, Nachrichten, Schweiz, Zürich'
+ language = 'de'
+
+ conversion_options = {
+ 'comments' : description
+ ,'tags' : category
+ ,'language' : language
+ ,'publisher' : publisher
+ }
+
+ remove_tags = [
+ dict(name='img')
+ ,dict(name='div',attrs={'class':['swissquote ad','boxNews','centerAD','contentTabs2','sbsLabel']})
+ ,dict(name='div',attrs={'id':['colRightAd','singleRight','singleSmallRight','MailInfo','metaLine','sidebarSky','contentFooter','commentInfo','commentInfo2','commentInfo3','footerBottom','clear','boxExclusiv','singleLogo','navSearch','headerLogin','headerBottomRight','horizontalNavigation','subnavigation','googleAdSense','footerAd','contentbox','articleGalleryNav']})
+ ,dict(name='form',attrs={'id':['articleMailForm','commentform']})
+ ,dict(name='div',attrs={'style':['position:absolute']})
+ ,dict(name='script',attrs={'type':['text/javascript']})
+ ,dict(name='p',attrs={'class':['schreiben','smallPrint','charCounter','caption']})
+ ]
+ feeds = [
+ (u'Front', u'http://www.tagesanzeiger.ch/rss.html')
+ ,(u'Zürich', u'http://www.tagesanzeiger.ch/zuerich/rss.html')
+ ,(u'Schweiz', u'http://www.tagesanzeiger.ch/schweiz/rss.html')
+ ,(u'Ausland', u'http://www.tagesanzeiger.ch/ausland/rss.html')
+ ,(u'Digital', u'http://www.tagesanzeiger.ch/digital/rss.html')
+ ,(u'Wissen', u'http://www.tagesanzeiger.ch/wissen/rss.html')
+ ,(u'Panorama', u'http://www.tagesanzeiger.ch/panorama/rss.html')
+ ,(u'Wirtschaft', u'http://www.tagesanzeiger.ch/wirtschaft/rss.html')
+ ,(u'Sport', u'http://www.tagesanzeiger.ch/sport/rss.html')
+ ,(u'Kultur', u'http://www.tagesanzeiger.ch/kultur/rss.html')
+ ,(u'Leben', u'http://www.tagesanzeiger.ch/leben/rss.html')
+ ,(u'Auto', u'http://www.tagesanzeiger.ch/auto/rss.html')]
+
+ def print_version(self, url):
+ return url + '/print.html'
+
From 77da36f05c3e09654650133671c1d7f904d8a7d0 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Sun, 19 Sep 2010 23:51:14 -0600
Subject: [PATCH 10/37] Add prologue and epilogue to default chapter detection
regex
---
src/calibre/ebooks/conversion/plumber.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/calibre/ebooks/conversion/plumber.py b/src/calibre/ebooks/conversion/plumber.py
index 3ea2926461..395447edba 100644
--- a/src/calibre/ebooks/conversion/plumber.py
+++ b/src/calibre/ebooks/conversion/plumber.py
@@ -241,7 +241,7 @@ OptionRecommendation(name='toc_filter',
OptionRecommendation(name='chapter',
recommended_value="//*[((name()='h1' or name()='h2') and "
- r"re:test(., 'chapter|book|section|part\s+', 'i')) or @class "
+ r"re:test(., 'chapter|book|section|part|prologue|epilogue\s+', 'i')) or @class "
"= 'chapter']", level=OptionRecommendation.LOW,
help=_('An XPath expression to detect chapter titles. The default '
'is to consider or tags that contain the words '
From 656c88792ddeb760cf7ed562ad54bce81d17f77e Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Mon, 20 Sep 2010 08:29:25 -0600
Subject: [PATCH 11/37] The Marker by Marbs
---
resources/recipes/the_marker.recipe | 52 +++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
create mode 100644 resources/recipes/the_marker.recipe
diff --git a/resources/recipes/the_marker.recipe b/resources/recipes/the_marker.recipe
new file mode 100644
index 0000000000..e5f1ffc761
--- /dev/null
+++ b/resources/recipes/the_marker.recipe
@@ -0,0 +1,52 @@
+import re
+from calibre.web.feeds.news import BasicNewsRecipe
+
+class AdvancedUserRecipe1283848012(BasicNewsRecipe):
+ description = 'TheMarker Financial News in Hebrew'
+ __author__ = 'TonyTheBookworm, Marbs'
+ cover_url = 'http://static.ispot.co.il/wp-content/upload/2009/09/themarker.jpg'
+ title = u'TheMarker'
+ language = 'he'
+ simultaneous_downloads = 5
+ remove_javascript = True
+ timefmt = '[%a, %d %b, %Y]'
+ oldest_article = 1
+ remove_tags = [dict(name='tr', attrs={'bgcolor':['#738A94']}) ]
+ max_articles_per_feed = 10
+ extra_css='body{direction: rtl;} .article_description{direction: rtl; } a.article{direction: rtl; } .calibre_feed_description{direction: rtl; }'
+ feeds = [(u'Head Lines', u'http://www.themarker.com/tmc/content/xml/rss/hpfeed.xml'),
+ (u'TA Market', u'http://www.themarker.com/tmc/content/xml/rss/sections/marketfeed.xml'),
+ (u'Real Estate', u'http://www.themarker.com/tmc/content/xml/rss/sections/realEstaterfeed.xml'),
+ (u'Wall Street & Global', u'http://www.themarker.com/tmc/content/xml/rss/sections/wallsfeed.xml'),
+ (u'Law', u'http://www.themarker.com/tmc/content/xml/rss/sections/lawfeed.xml'),
+ (u'Media', u'http://www.themarker.com/tmc/content/xml/rss/sections/mediafeed.xml'),
+ (u'Consumer', u'http://www.themarker.com/tmc/content/xml/rss/sections/consumerfeed.xml'),
+ (u'Career', u'http://www.themarker.com/tmc/content/xml/rss/sections/careerfeed.xml'),
+ (u'Car', u'http://www.themarker.com/tmc/content/xml/rss/sections/carfeed.xml'),
+ (u'High Tech', u'http://www.themarker.com/tmc/content/xml/rss/sections/hightechfeed.xml'),
+ (u'Investor Guide', u'http://www.themarker.com/tmc/content/xml/rss/sections/investorGuidefeed.xml')]
+
+ def print_version(self, url):
+ split1 = url.split("=")
+ weblinks = url
+
+ if weblinks is not None:
+ for link in weblinks:
+ #---------------------------------------------------------
+ #here we need some help with some regexpressions
+ #we are trying to find it.themarker.com in a url
+ #-----------------------------------------------------------
+ re1='.*?' # Non-greedy match on filler
+ re2='(it\\.themarker\\.com)' # Fully Qualified Domain Name 1
+ rg = re.compile(re1+re2,re.IGNORECASE|re.DOTALL)
+ m = rg.search(url)
+
+
+ if m:
+ split2 = url.split("article/")
+ print_url = 'http://it.themarker.com/tmit/PrintArticle/' + split2[1]
+
+ else:
+ print_url = 'http://www.themarker.com/ibo/misc/printFriendly.jhtml?ElementId=%2Fibo%2Frepositories%2Fstories%2Fm1_2000%2F' + split1[1]+'.xml'
+
+ return print_url
From cec2f873cb29b8868695da152467c8f9d3eb9ea5 Mon Sep 17 00:00:00 2001
From: GRiker
Date: Mon, 20 Sep 2010 07:44:33 -0700
Subject: [PATCH 12/37] GwR wip tweak_epub
---
src/calibre/gui2/dialogs/tweak_epub.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/calibre/gui2/dialogs/tweak_epub.py b/src/calibre/gui2/dialogs/tweak_epub.py
index cc5b526291..a78d26a9dc 100755
--- a/src/calibre/gui2/dialogs/tweak_epub.py
+++ b/src/calibre/gui2/dialogs/tweak_epub.py
@@ -117,7 +117,7 @@ class TweakEpub(QDialog, Ui_Dialog):
# Write mimetype
zf.write(os.path.join(self._exploded,'mimetype'), 'mimetype', compress_type=ZIP_STORED)
# Write everything else
- exclude_files = ['.DS_Store','mimetype','iTunesMetadata.plist']
+ exclude_files = ['.DS_Store','mimetype','iTunesMetadata.plist','rebuilt.epub']
for root, dirs, files in os.walk(self._exploded):
for fn in files:
if fn in exclude_files:
From 62d9449e88f6aa5a6a2e1234137f31ed3d9e25d9 Mon Sep 17 00:00:00 2001
From: GRiker
Date: Mon, 20 Sep 2010 07:57:05 -0700
Subject: [PATCH 13/37] GwR wip tweak_epub
---
src/calibre/gui2/dialogs/tweak_epub.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/calibre/gui2/dialogs/tweak_epub.py b/src/calibre/gui2/dialogs/tweak_epub.py
index a78d26a9dc..c0ad79385b 100755
--- a/src/calibre/gui2/dialogs/tweak_epub.py
+++ b/src/calibre/gui2/dialogs/tweak_epub.py
@@ -71,8 +71,8 @@ class TweakEpub(QDialog, Ui_Dialog):
prints(" killing file browser proc")
#self._file_browser_proc.terminate()
#self._file_browser_proc.kill()
- #self._file_browser_send_signal()
- #self._file_browser_proc = None
+ #self._file_browser_send_signal(?)
+ self._file_browser_proc = None
# Delete directory containing exploded ePub
if self._exploded is not None:
@@ -93,6 +93,7 @@ class TweakEpub(QDialog, Ui_Dialog):
elif iswindows:
cmd = 'start explorer.exe /e,/root,%s' % self._exploded
else:
+ # *** Kovid - need proper linux invocation here ***
cmd = ''
# *** Kovid - need a way of launching this process than can be killed in cleanup() ***
From bc82ea61032bf7f1d2564674f0a7174df4b3dab4 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Mon, 20 Sep 2010 09:28:39 -0600
Subject: [PATCH 14/37] Add button to Edit metadata dialog to trim borders from
the cover
---
imgsrc/trim.svg | 688 ++++++++++++++++++++
resources/images/trim.png | Bin 0 -> 2553 bytes
src/calibre/gui2/dialogs/metadata_single.py | 19 +
src/calibre/gui2/dialogs/metadata_single.ui | 11 +
4 files changed, 718 insertions(+)
create mode 100644 imgsrc/trim.svg
create mode 100644 resources/images/trim.png
diff --git a/imgsrc/trim.svg b/imgsrc/trim.svg
new file mode 100644
index 0000000000..8c8810fc66
--- /dev/null
+++ b/imgsrc/trim.svg
@@ -0,0 +1,688 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+ Oxygen team
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/images/trim.png b/resources/images/trim.png
new file mode 100644
index 0000000000000000000000000000000000000000..3cb93adfa670c8353a95b6d2b5d49180db4340e6
GIT binary patch
literal 2553
zcmb_eXH=8f7X1>CCSYt7Nr+;oj(|K=q=q(B0Y#*@V1SWcLQeq!L8$@;a44f9#W4hd
zpoBUgp$#Y?5HeCknk0Y(5CoDJ-;ek2{d?=2bN5;Mu6x&B=iVPX-Ok2LOyrCR003eZ
z<|a3JNcdSo0=%_L-+O=u0w^mp6M*|O%3CY*06>^zVPbeI=66=fa5mKJG_Bp?Bdbob
z*2gUC??=YJaeuyFH=GB@e2PJ_URZ&tnNHhM|}EKJukhn?Dch^V{$IP&d3-
zWIQ|%hwdCkm9Ii$Wx3Tr%;9O|gSonMvlHtV+w9%tbU3wo(QuR|$D~82EUpvubo|9_zz0xPq_uz>tenN)M`fv>1`N2@!%}qO
z;Rl`i`1p0MPF*UPfHd@+xkjBRE!nd56#bs2DSEsYGJU8R)sQF$Bq9#GE-1$L_)CF%
zrCPWvbXZX8b_Jpp`>j*T-441|En8{QFNQ;pf+@_bU2vP`y{H#{y4*dw9s`bFV5i}P92?@7waB&GC
z|4bRZK6;XXyT#0o74~&UrI}AIDIVYUkA%vINO&vCA-H0wOO$|ngq%r`oYC`(R0>P;
z^?+=TMJ<#80>EjROnGN#l-&1^%
z3aS|D?x&9u-J))w%4)GQ*@-6zBsZr!xMM(t!ZvIE3UkDp_^4s^O^th6-{t+7@W1mX
zAFdJ`*JaGiE8k+5*5E95i2nXyy=3WRi&An9uo2T>AwRIVVy}YXyn$zCrwjST8Gb$3
zMc5Rqr-Ucim@FULnp|wgulAF4pxy6h5j_;J|;#Di$Lw=WSqmc#W6Vu3H+JlY4
z=R#jdei;{3Kdml|YS3heM;FwsQv1<-{cX`#%9%Jt?yx{cknLIsqauHDauO+(dZL3K
z(W)eXLZqLYK2>Imp_rbDe|!GVRt;%>NmEJ<`t?wMgoj6w!dLo2J&hD#sk{}Zm+YwljRPmB5!{1;Txp!oam%}V)%fBOK0~X$B>2?tW(T=&JDvrqg=lCc1RphooE0@TFH-yR
z%jk3&nXHyjqmb^<-;j$Ke^r@p1mU-#EiDKRoZ_zlg<}2YqZUV^mwqFsn~*IJDNQM7
zh062$SpgonoI~sk{s)_3tQTCx*K%XkaiUTah)c|P60E6K6mVXvI01Ug(oosq%^-E{
zVzSiCRR-7Yrl?c~hHzwl`}}atP~c6Ss=PTX<)eP_H}H?q)x$o@ZJR+>I=!mYdTn=0
zXGY=xWn$^W197|i3XS)gEl~D0O~V6D0kCp$^uH=s5SRMCJSnW+X??j9!NL%<$1uMZ
z7!E7kL0foF>uplxcS1qOXlPsMT7JuQ>SO6?qrllC~xqZ$jtdw0k4`VU>v)Smga27*!t<7
z%WPJ-sam2N*7e~oq)?e*D@gpeAfH%VY~l;k}K>h
zNz^2{(~GPr_ra1Uwh&{gRJ=#}fk`5yK}=VIN-+e9B1NIsXm(^u4Z~Q2UBB%l=mf;3
zdzIdGe17cCz$y8MeV2ViKWhcc6AOtp{D3;c(cIJun>+8mS$D}-g&x4}L*2gZB3NZy
zT9{XHSJsQzS4s;L^%=YsOBG!ON|hL^?v$1Q5?d>)#5KuXc6J@qauZ$K6hzl1d09Nh
zIyzH770|)W$PXSN_RpmeSBN|fY^J`GE6nS5jV_yUWrC?{slvX^Hx7E7p;DX4dTlzS
zX1|}7h9RIU?#ekyAY%W_IQ0*@-$TaHee>m1!uxBy7dEB0T!+!>#mPnumtHyxI$f&4
z>EEsx)bIyEfy+g-Zv*_RK!kb#cv+=OyW@-<<^?tB9)@rkhsF;5IU4$`)Kg!nNIlGvAgP^GD
z@e48Af5d<1#LrSsqP{D@fL`o@olyw5tI@*pDcoTD1B}689I7?>h#dhElQ{I9i5*6L
z9&S6utIWI$k|;ViPD8oMD1jm7BL;6qX0Ez)L6AMOw%@NbHA;^YA8kde;wZMM<(VMq
zd&k-)r^bI3W&O1rQnL45zvu%zHK(IJt2R*Pga{<(uVu+A2C!{gq{wX7v&yE%ToE82
zaX6B~Wm)AOtin&=u^VGmocC=JE1kI4{~Q%QIDgRRV4U}E=B$>=hGRqgbvIS=ur=g2
zHx(6#7)_O!mloF-4v{JDSDvCALuIh0td}%%B~DVK=;)ABGwO&+W?gRUoroy<`Bw_t
zFc$4s2?`#1pWYXJ&h^Fhq^|kB;GDhDv;3;n9(u&p*(tVI2-zj?`YnsXxs#3wY?(f4oA4
zN=xL%%dygpcW>8A46rH?;61#1t9z~tUf0@uxV9iuU9Kd
+ -
+
+
+ Remove border (if any) from cover
+
+
+
+ :/images/trim.png :/images/trim.png
+
+
+
-
From 231aab95614acf5ab738ee4a949b52d312a28383 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Mon, 20 Sep 2010 09:37:15 -0600
Subject: [PATCH 15/37] WSJ: Don't error out if a single section fails
---
resources/recipes/wsj_free.recipe | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/resources/recipes/wsj_free.recipe b/resources/recipes/wsj_free.recipe
index 7f3664f1c4..df8234e8e2 100644
--- a/resources/recipes/wsj_free.recipe
+++ b/resources/recipes/wsj_free.recipe
@@ -54,10 +54,13 @@ class WallStreetJournal(BasicNewsRecipe):
def wsj_add_feed(self,feeds,title,url):
self.log('Found section:', title)
- if url.endswith('whatsnews'):
- articles = self.wsj_find_wn_articles(url)
- else:
- articles = self.wsj_find_articles(url)
+ try:
+ if url.endswith('whatsnews'):
+ articles = self.wsj_find_wn_articles(url)
+ else:
+ articles = self.wsj_find_articles(url)
+ except:
+ articles = []
if articles:
feeds.append((title, articles))
return feeds
From 8bd686628966bb3f8948377d8be7b4cadd78b433 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Mon, 20 Sep 2010 09:40:47 -0600
Subject: [PATCH 16/37] ...
---
resources/recipes/wsj.recipe | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/resources/recipes/wsj.recipe b/resources/recipes/wsj.recipe
index fd5e977d10..88e07bcea3 100644
--- a/resources/recipes/wsj.recipe
+++ b/resources/recipes/wsj.recipe
@@ -70,13 +70,16 @@ class WallStreetJournal(BasicNewsRecipe):
def wsj_add_feed(self,feeds,title,url):
self.log('Found section:', title)
- if url.endswith('whatsnews'):
- articles = self.wsj_find_wn_articles(url)
- else:
- articles = self.wsj_find_articles(url)
+ try:
+ if url.endswith('whatsnews'):
+ articles = self.wsj_find_wn_articles(url)
+ else:
+ articles = self.wsj_find_articles(url)
+ except:
+ articles = []
if articles:
feeds.append((title, articles))
- return feeds
+ return feeds
def parse_index(self):
soup = self.wsj_get_index()
@@ -99,7 +102,7 @@ class WallStreetJournal(BasicNewsRecipe):
url = 'http://online.wsj.com' + a['href']
feeds = self.wsj_add_feed(feeds,title,url)
title = 'What''s News'
- url = url.replace('pageone','whatsnews')
+ url = url.replace('pageone','whatsnews')
feeds = self.wsj_add_feed(feeds,title,url)
else:
title = self.tag_to_string(a)
@@ -141,7 +144,7 @@ class WallStreetJournal(BasicNewsRecipe):
articles = []
flavorarea = soup.find('div', attrs={'class':lambda x: x and 'ahed' in x})
- if flavorarea is not None:
+ if flavorarea is not None:
flavorstory = flavorarea.find('a', href=lambda x: x and x.startswith('/article'))
if flavorstory is not None:
flavorstory['class'] = 'mjLinkItem'
From ec8164470b8b4ac54b2f16bba57f22a6e856be8b Mon Sep 17 00:00:00 2001
From: GRiker
Date: Mon, 20 Sep 2010 19:39:33 -0700
Subject: [PATCH 17/37] GwR revisions tweak_epub
---
src/calibre/gui2/dialogs/tweak_epub.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/calibre/gui2/dialogs/tweak_epub.py b/src/calibre/gui2/dialogs/tweak_epub.py
index c0ad79385b..379352f390 100755
--- a/src/calibre/gui2/dialogs/tweak_epub.py
+++ b/src/calibre/gui2/dialogs/tweak_epub.py
@@ -25,7 +25,6 @@ class TweakEpub(QDialog, Ui_Dialog):
To do:
- need way to kill file browser proc in cleanup()
- - Windows file browser launch
- linux file browser launch
'''
@@ -109,6 +108,7 @@ class TweakEpub(QDialog, Ui_Dialog):
zipextract(self._epub, self._exploded)
self.display_exploded()
self.rebuild_button.setEnabled(True)
+ self.explode_button.setEnabled(False)
def rebuild(self):
if DEBUG:
From 3dfaa2cdaaeda5f56d5d39b02df61b1371942a58 Mon Sep 17 00:00:00 2001
From: GRiker
Date: Mon, 20 Sep 2010 20:10:17 -0700
Subject: [PATCH 18/37] change to use open_local_file
---
src/calibre/gui2/dialogs/tweak_epub.py | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/src/calibre/gui2/dialogs/tweak_epub.py b/src/calibre/gui2/dialogs/tweak_epub.py
index 379352f390..a967ca310a 100755
--- a/src/calibre/gui2/dialogs/tweak_epub.py
+++ b/src/calibre/gui2/dialogs/tweak_epub.py
@@ -15,6 +15,7 @@ from PyQt4.Qt import QDialog, SIGNAL
from calibre import prints
from calibre.constants import iswindows, isosx, DEBUG
+from calibre.gui2 import open_local_file
from calibre.gui2.dialogs.tweak_epub_ui import Ui_Dialog
from calibre.libunzip import extract as zipextract
from calibre.ptempfile import PersistentTemporaryDirectory
@@ -33,7 +34,7 @@ class TweakEpub(QDialog, Ui_Dialog):
self._epub = epub
self._exploded = None
- self._file_browser_proc = None
+ #self._file_browser_proc = None
self._output = None
# Run the dialog setup generated from tweak_epub.ui
@@ -64,14 +65,6 @@ class TweakEpub(QDialog, Ui_Dialog):
'''
if DEBUG:
prints("gui2.dialogs.tweak_epub:TweakEpub.cleanup()")
- # Kill file browser proc
- if self._file_browser_proc:
- if DEBUG:
- prints(" killing file browser proc")
- #self._file_browser_proc.terminate()
- #self._file_browser_proc.kill()
- #self._file_browser_send_signal(?)
- self._file_browser_proc = None
# Delete directory containing exploded ePub
if self._exploded is not None:
@@ -87,6 +80,7 @@ class TweakEpub(QDialog, Ui_Dialog):
'''
if DEBUG:
prints("gui2.dialogs.tweak_epub:TweakEpub.display_exploded()")
+ '''
if isosx:
cmd = 'open %s' % self._exploded
elif iswindows:
@@ -97,6 +91,8 @@ class TweakEpub(QDialog, Ui_Dialog):
# *** Kovid - need a way of launching this process than can be killed in cleanup() ***
self._file_browser_proc = subprocess.Popen(cmd, shell=True)
+ '''
+ open_local_file(self._exploded)
def explode(self):
if DEBUG:
From 88f980ad186859708aceb3907ae59d4052648ff3 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Mon, 20 Sep 2010 21:33:43 -0600
Subject: [PATCH 19/37] News download: Don't add inline table of contents when
downloading news for the Kindle
---
src/calibre/gui2/tools.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/calibre/gui2/tools.py b/src/calibre/gui2/tools.py
index 7a516bb4ff..2f0452a773 100644
--- a/src/calibre/gui2/tools.py
+++ b/src/calibre/gui2/tools.py
@@ -217,6 +217,10 @@ def fetch_scheduled_recipe(arg):
if 'output_profile' in ps:
recs.append(('output_profile', ps['output_profile'],
OptionRecommendation.HIGH))
+ if ps['output_profile'] == 'kindle':
+ recs.append(('no_inline_toc', True,
+ OptionRecommendation.HIGH))
+
lf = load_defaults('look_and_feel')
if lf.get('base_font_size', 0.0) != 0.0:
recs.append(('base_font_size', lf['base_font_size'],
From f50085d0388b08c15ef10295b74855bab8fb416b Mon Sep 17 00:00:00 2001
From: GRiker
Date: Tue, 21 Sep 2010 05:40:33 -0700
Subject: [PATCH 20/37] GR tweaks to tweak-epub
---
src/calibre/gui2/actions/tweak_epub.py | 3 +--
src/calibre/gui2/dialogs/tweak_epub.py | 3 ---
src/calibre/gui2/dialogs/tweak_epub.ui | 8 ++++----
3 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/src/calibre/gui2/actions/tweak_epub.py b/src/calibre/gui2/actions/tweak_epub.py
index 67ec34c12b..212aff8019 100755
--- a/src/calibre/gui2/actions/tweak_epub.py
+++ b/src/calibre/gui2/actions/tweak_epub.py
@@ -40,8 +40,7 @@ class TweakEpubAction(InterfaceAction):
_('No ePub available. First convert the book to ePub.'),
show=True)
-
- # Launch a modal dialog waiting for user to complete or cancel
+ # Launch modal dialog waiting for user to tweak or cancel
dlg = TweakEpub(self.gui, path_to_epub)
if dlg.exec_() == dlg.Accepted:
self.update_db(book_id, dlg._output)
diff --git a/src/calibre/gui2/dialogs/tweak_epub.py b/src/calibre/gui2/dialogs/tweak_epub.py
index fb3643884b..db6e93fd7a 100755
--- a/src/calibre/gui2/dialogs/tweak_epub.py
+++ b/src/calibre/gui2/dialogs/tweak_epub.py
@@ -21,8 +21,6 @@ class TweakEpub(QDialog, Ui_Dialog):
'''
Display controls for tweaking ePubs
- To do:
- - need way to kill file browser proc in cleanup()
'''
def __init__(self, parent, epub):
@@ -30,7 +28,6 @@ class TweakEpub(QDialog, Ui_Dialog):
self._epub = epub
self._exploded = None
- #self._file_browser_proc = None
self._output = None
# Run the dialog setup generated from tweak_epub.ui
diff --git a/src/calibre/gui2/dialogs/tweak_epub.ui b/src/calibre/gui2/dialogs/tweak_epub.ui
index 9daa5a8f67..f841bd5eea 100644
--- a/src/calibre/gui2/dialogs/tweak_epub.ui
+++ b/src/calibre/gui2/dialogs/tweak_epub.ui
@@ -32,7 +32,7 @@
&Explode ePub
-
+
:/images/wizard.png :/images/wizard.png
@@ -49,7 +49,7 @@
&Rebuild ePub
-
+
:/images/exec.png :/images/exec.png
@@ -63,7 +63,7 @@
&Cancel
-
+
:/images/window-close.png :/images/window-close.png
@@ -71,7 +71,7 @@
-
- First, explode the epub. Then edit is contents by right clicking on the individual files and selecting the editor of your choice. When you are done, click rebuild epub and the epub in your calibre library will be updated with the changes you have made.
+ Explode the ePub to display contents in a file browser window. To tweak individual files, right-click, selecting 'Open with...' your editor of choice. When tweaks are complete, close the file browser window. Rebuild the ePub, updating your calibre library.
true
From 98f0851ebb3eb4a2711440935e10531e6bdea996 Mon Sep 17 00:00:00 2001
From: GRiker
Date: Tue, 21 Sep 2010 05:47:22 -0700
Subject: [PATCH 21/37] GR tweaks to tweak-epub
---
src/calibre/gui2/dialogs/tweak_epub.ui | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/calibre/gui2/dialogs/tweak_epub.ui b/src/calibre/gui2/dialogs/tweak_epub.ui
index f841bd5eea..ccd33f44ab 100644
--- a/src/calibre/gui2/dialogs/tweak_epub.ui
+++ b/src/calibre/gui2/dialogs/tweak_epub.ui
@@ -71,7 +71,7 @@
-
- Explode the ePub to display contents in a file browser window. To tweak individual files, right-click, selecting 'Open with...' your editor of choice. When tweaks are complete, close the file browser window. Rebuild the ePub, updating your calibre library.
+ Explode the ePub to display contents in a file browser window. To tweak individual files, right-click, then 'Open with...' your editor of choice. When tweaks are complete, close the file browser window. Rebuild the ePub, updating your calibre library.
true
From 52f85d3ef422c882cde953c57e72e8e3e5fe50ad Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 21 Sep 2010 11:56:09 -0600
Subject: [PATCH 22/37] Cover cache: load images only in the GUI thread to
prevent stale files being leftover by set_path due to Windows file locking
---
src/calibre/gui2/__init__.py | 30 +++++++++++++++++++++++++++++-
src/calibre/gui2/library/models.py | 4 ++--
src/calibre/library/caches.py | 8 +++++---
3 files changed, 36 insertions(+), 6 deletions(-)
diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py
index c284900734..66e199b8a0 100644
--- a/src/calibre/gui2/__init__.py
+++ b/src/calibre/gui2/__init__.py
@@ -1,7 +1,7 @@
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal '
""" The GUI """
-import os, sys
+import os, sys, Queue
from threading import RLock
from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, \
@@ -296,6 +296,34 @@ class Dispatcher(QObject):
def dispatch(self, args, kwargs):
self.func(*args, **kwargs)
+class FunctionDispatcher(QObject):
+ '''
+ Convenience class to use Qt signals with arbitrary python functions.
+ By default, ensures that a function call always happens in the
+ thread this Dispatcher was created in.
+ '''
+ dispatch_signal = pyqtSignal(object, object, object)
+
+ def __init__(self, func, queued=True, parent=None):
+ QObject.__init__(self, parent)
+ self.func = func
+ typ = Qt.QueuedConnection
+ if not queued:
+ typ = Qt.AutoConnection if queued is None else Qt.DirectConnection
+ self.dispatch_signal.connect(self.dispatch, type=typ)
+
+ def __call__(self, *args, **kwargs):
+ q = Queue.Queue()
+ self.dispatch_signal.emit(q, args, kwargs)
+ return q.get()
+
+ def dispatch(self, q, args, kwargs):
+ try:
+ res = self.func(*args, **kwargs)
+ except:
+ res = None
+ q.put(res)
+
class GetMetadata(QObject):
'''
Convenience class to ensure that metadata readers are used only in the
diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py
index 3370fd4b75..53f701386b 100644
--- a/src/calibre/gui2/library/models.py
+++ b/src/calibre/gui2/library/models.py
@@ -12,7 +12,7 @@ from operator import attrgetter
from PyQt4.Qt import QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage, \
QModelIndex, QVariant, QDate
-from calibre.gui2 import NONE, config, UNDEFINED_QDATE
+from calibre.gui2 import NONE, config, UNDEFINED_QDATE, FunctionDispatcher
from calibre.utils.pyparsing import ParseException
from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors
from calibre.ptempfile import PersistentTemporaryFile
@@ -151,7 +151,7 @@ class BooksModel(QAbstractTableModel): # {{{
self.database_changed.emit(db)
if self.cover_cache is not None:
self.cover_cache.stop()
- self.cover_cache = CoverCache(db)
+ self.cover_cache = CoverCache(db, FunctionDispatcher(self.db.cover))
self.cover_cache.start()
def refresh_cover(event, ids):
if event == 'cover' and self.cover_cache is not None:
diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py
index 211baeb634..58edd89cb2 100644
--- a/src/calibre/library/caches.py
+++ b/src/calibre/library/caches.py
@@ -6,7 +6,7 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal '
__docformat__ = 'restructuredtext en'
-import re, itertools
+import re, itertools, time
from itertools import repeat
from datetime import timedelta
from threading import Thread, RLock
@@ -23,10 +23,11 @@ from calibre import fit_image
class CoverCache(Thread):
- def __init__(self, db):
+ def __init__(self, db, cover_func):
Thread.__init__(self)
self.daemon = True
self.db = db
+ self.cover_func = cover_func
self.load_queue = Queue()
self.keep_running = True
self.cache = {}
@@ -37,7 +38,8 @@ class CoverCache(Thread):
self.keep_running = False
def _image_for_id(self, id_):
- img = self.db.cover(id_, index_is_id=True, as_image=True)
+ time.sleep(0.050) # Limit 20/second to not overwhelm the GUI
+ img = self.cover_func(id_, index_is_id=True, as_image=True)
if img is None:
img = QImage()
if not img.isNull():
From 3f5e0c7e92bf074fdc1cbeed380e68606dcc0dc4 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 21 Sep 2010 12:22:50 -0600
Subject: [PATCH 23/37] set_path now *always* commits
---
src/calibre/library/database2.py | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py
index eb6e8336f9..93320166b7 100644
--- a/src/calibre/library/database2.py
+++ b/src/calibre/library/database2.py
@@ -402,7 +402,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
path = path.lower()
return path
- def set_path(self, index, index_is_id=False, commit=True):
+ def set_path(self, index, index_is_id=False):
'''
Set the path to the directory containing this books files based on its
current title and author. If there was a previous directory, its contents
@@ -432,7 +432,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if current_path and os.path.exists(spath): # Migrate existing files
cdata = self.cover(id, index_is_id=True)
if cdata is not None:
- open(os.path.join(tpath, 'cover.jpg'), 'wb').write(cdata)
+ with open(os.path.join(tpath, 'cover.jpg'), 'wb') as f:
+ f.write(cdata)
for format in formats:
# Get data as string (can't use file as source and target files may be the same)
f = self.format(id, format, index_is_id=True, as_file=False)
@@ -442,8 +443,6 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.add_format(id, format, stream, index_is_id=True,
path=tpath, notify=False)
self.conn.execute('UPDATE books SET path=? WHERE id=?', (path, id))
- if commit:
- self.conn.commit()
self.data.set(id, self.FIELD_MAP['path'], path, row_is_id=True)
# Delete not needed directories
if current_path and os.path.exists(spath):
@@ -1163,7 +1162,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
','.join([a.replace(',', '|') for a in authors]),
row_is_id=True)
self.data.set(id, self.FIELD_MAP['author_sort'], ss, row_is_id=True)
- self.set_path(id, index_is_id=True, commit=commit)
+ self.set_path(id, index_is_id=True)
if notify:
self.notify('metadata', [id])
@@ -1178,7 +1177,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.data.set(id, self.FIELD_MAP['sort'], title_sort(title), row_is_id=True)
else:
self.data.set(id, self.FIELD_MAP['sort'], title, row_is_id=True)
- self.set_path(id, index_is_id=True, commit=commit)
+ self.set_path(id, index_is_id=True)
if commit:
self.conn.commit()
if notify:
From b8edfe539437fdc9b29b0fc281917daa63c3c13e Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 21 Sep 2010 13:44:06 -0600
Subject: [PATCH 24/37] ...
---
src/calibre/library/database2.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py
index 93320166b7..1a2eef2c81 100644
--- a/src/calibre/library/database2.py
+++ b/src/calibre/library/database2.py
@@ -1130,7 +1130,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')]
@@ -1167,6 +1170,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):
From 8c74a347d773281b92bafba41662b66af366f789 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 21 Sep 2010 14:56:52 -0600
Subject: [PATCH 25/37] Fix #6899 (Updated recipe for Danas)
---
resources/recipes/danas.recipe | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/resources/recipes/danas.recipe b/resources/recipes/danas.recipe
index 3543acd684..1e0e319334 100644
--- a/resources/recipes/danas.recipe
+++ b/resources/recipes/danas.recipe
@@ -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 = [
From 0e8017ade69c0ad0f3d374db381f6170b175e21f Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 21 Sep 2010 16:45:42 -0600
Subject: [PATCH 26/37] News download: Rationalize cover processing. Fixes
#6852 (ebook-convert ieeespectrum.recipe .mobi crashes)
---
src/calibre/utils/magick/draw.py | 8 ++---
src/calibre/web/feeds/news.py | 50 +++++++++++++++-----------------
2 files changed, 28 insertions(+), 30 deletions(-)
diff --git a/src/calibre/utils/magick/draw.py b/src/calibre/utils/magick/draw.py
index ed9e3d3d83..dcf9d7b671 100644
--- a/src/calibre/utils/magick/draw.py
+++ b/src/calibre/utils/magick/draw.py
@@ -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:
diff --git a/src/calibre/web/feeds/news.py b/src/calibre/web/feeds/news.py
index a140dfbf05..d1e7866198 100644
--- a/src/calibre/web/feeds/news.py
+++ b/src/calibre/web/feeds/news.py
@@ -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())
- 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,
- 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':
+ 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 = open(cpath, 'rb')
+ stream = cStringIO.StringIO(cdata)
+ cdata = None
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])
+ cdata = mi.cover_data[1]
+ if not cdata:
+ return
+ if self.cover_margins[0] or self.cover_margins[1]:
+ 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])
+
+ 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(
From b958545a8af34885c7053e14f752fed2ba548627 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 21 Sep 2010 16:47:28 -0600
Subject: [PATCH 27/37] ...
---
src/calibre/ebooks/mobi/writer.py | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/src/calibre/ebooks/mobi/writer.py b/src/calibre/ebooks/mobi/writer.py
index 5d5de7b153..23f92d1fd2 100644
--- a/src/calibre/ebooks/mobi/writer.py
+++ b/src/calibre/ebooks/mobi/writer.py
@@ -1574,14 +1574,15 @@ class MobiWriter(object):
id = unicode(oeb.metadata.cover[0])
item = oeb.manifest.ids[id]
href = item.href
- index = self._images[href] - 1
- exth.write(pack('>III', 0xc9, 0x0c, index))
- exth.write(pack('>III', 0xcb, 0x0c, 0))
- nrecs += 2
- index = self._add_thumbnail(item)
- if index is not None:
- exth.write(pack('>III', 0xca, 0x0c, index - 1))
- nrecs += 1
+ if href in self._images:
+ index = self._images[href] - 1
+ exth.write(pack('>III', 0xc9, 0x0c, index))
+ exth.write(pack('>III', 0xcb, 0x0c, 0))
+ nrecs += 2
+ index = self._add_thumbnail(item)
+ if index is not None:
+ exth.write(pack('>III', 0xca, 0x0c, index - 1))
+ nrecs += 1
exth = exth.getvalue()
trail = len(exth) % 4
From 62c652869a30d136278356557db397b7417c06bc Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 21 Sep 2010 17:13:22 -0600
Subject: [PATCH 28/37] Fix #5900 (Alex reader from spring design is reconized
as N516 and send books to wrong location)
---
src/calibre/devices/hanvon/driver.py | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/src/calibre/devices/hanvon/driver.py b/src/calibre/devices/hanvon/driver.py
index 75728a94ea..6291864b86 100644
--- a/src/calibre/devices/hanvon/driver.py
+++ b/src/calibre/devices/hanvon/driver.py
@@ -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'
From 9656798e3881757f06bacb8bacee860a42f3be00 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 21 Sep 2010 19:00:50 -0600
Subject: [PATCH 29/37] Fix #6522 (Cannot recognize my Nexus One with 2.2
Cyanogen Root)
---
src/calibre/devices/android/driver.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py
index 7a451112c0..c9c0827759 100644
--- a/src/calibre/devices/android/driver.py
+++ b/src/calibre/devices/android/driver.py
@@ -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],
From 78490d39bd5f98eb7f6f19f62a9ff451862b08aa Mon Sep 17 00:00:00 2001
From: Timothy Legge
Date: Tue, 21 Sep 2010 22:17:50 -0300
Subject: [PATCH 30/37] Add support for setting the ReadStatus to Read and
correctly deal with empty collections
---
src/calibre/devices/kobo/driver.py | 120 +++++++++++++++++++++--------
1 file changed, 89 insertions(+), 31 deletions(-)
diff --git a/src/calibre/devices/kobo/driver.py b/src/calibre/devices/kobo/driver.py
index 1171b74f5c..104553b675 100644
--- a/src/calibre/devices/kobo/driver.py
+++ b/src/calibre/devices/kobo/driver.py
@@ -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,43 +443,99 @@ class KOBO(USBMS):
connection = sqlite.connect(self._main_prefix + '.kobo/KoboReader.sqlite')
cursor = connection.cursor()
- # 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/%\''
- elif oncard != 'carda' and oncard != 'cardb':
- query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null and ReadStatus = 1 and ContentID not like \'file:///mnt/sd/%\''
+
+ 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/%\''
+ elif oncard != 'carda' and oncard != 'cardb':
+ query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null and ReadStatus = 1 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 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']
-
- 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 = (datelastread,ContentID,)
-
try:
- cursor.execute('update content set ReadStatus=1,FirstTimeReading=\'false\',DateLastRead=? where BookID is Null and ContentID = ?', t)
+ cursor.execute (query)
except:
- debug_print('Database Exception: Unable create Im_Reading list')
+ debug_print('Database Exception: Unable to reset Im_Reading list')
raise
else:
+# debug_print('Commit: Reset Im_Reading list')
connection.commit()
- # debug_print('Database: Commit create Im_Reading list')
+
+ for book in books:
+# debug_print('Title:', book.title, 'lpath:', book.path)
+ book.device_collections = ['Im_Reading']
+
+ 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 = (datelastread,ContentID,)
+
+ try:
+ cursor.execute('update content set ReadStatus=1,FirstTimeReading=\'false\',DateLastRead=? where BookID is Null and ContentID = ?', t)
+ except:
+ debug_print('Database Exception: Unable create Im_Reading list')
+ raise
+ 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()
From f12f69ef5edc3c9395abc1862f62f2405245fe2d Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 21 Sep 2010 21:18:32 -0600
Subject: [PATCH 31/37] superesportes by Luciano Furtado. Fixes #405 (New news
feed)
---
resources/recipes/superesportes.recipe | 79 ++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
create mode 100644 resources/recipes/superesportes.recipe
diff --git a/resources/recipes/superesportes.recipe b/resources/recipes/superesportes.recipe
new file mode 100644
index 0000000000..49289f188d
--- /dev/null
+++ b/resources/recipes/superesportes.recipe
@@ -0,0 +1,79 @@
+__license__ = 'GPL v3'
+__copyright__ = '2010, Luciano Furtado '
+'''
+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
+
From 5cab12e26f3decf1b3114d10aa463cfc64da0549 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 21 Sep 2010 22:04:01 -0600
Subject: [PATCH 32/37] Don't use special tooltip style on linux. Draw yellow
color on splitter handle in background
---
src/calibre/gui2/__init__.py | 12 ------------
src/calibre/gui2/widgets.py | 2 +-
2 files changed, 1 insertion(+), 13 deletions(-)
diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py
index 66e199b8a0..c0c7b0a9ed 100644
--- a/src/calibre/gui2/__init__.py
+++ b/src/calibre/gui2/__init__.py
@@ -603,18 +603,6 @@ class Application(QApplication):
self._file_open_paths = []
self._file_open_lock = RLock()
- if islinux:
- self.setStyleSheet('''
- QToolTip {
- border: 2px solid black;
- padding: 5px;
- border-radius: 10px;
- opacity: 200;
- background-color: #e1e1ff;
- color: black;
- }
- ''')
-
def _send_file_open_events(self):
with self._file_open_lock:
if self._file_open_paths:
diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py
index 60224aefc7..5efce74c08 100644
--- a/src/calibre/gui2/widgets.py
+++ b/src/calibre/gui2/widgets.py
@@ -863,11 +863,11 @@ class SplitterHandle(QSplitterHandle):
self.update()
def paintEvent(self, ev):
- QSplitterHandle.paintEvent(self, ev)
if self.highlight:
painter = QPainter(self)
painter.setClipRect(ev.rect())
painter.fillRect(self.rect(), Qt.yellow)
+ QSplitterHandle.paintEvent(self, ev)
def mouseDoubleClickEvent(self, ev):
self.double_clicked.emit(self)
From edb26bcfa81eee64476cbcffec92e312fccc8329 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Wed, 22 Sep 2010 09:09:55 -0600
Subject: [PATCH 33/37] ...
---
src/calibre/gui2/widgets.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py
index 5efce74c08..60224aefc7 100644
--- a/src/calibre/gui2/widgets.py
+++ b/src/calibre/gui2/widgets.py
@@ -863,11 +863,11 @@ class SplitterHandle(QSplitterHandle):
self.update()
def paintEvent(self, ev):
+ QSplitterHandle.paintEvent(self, ev)
if self.highlight:
painter = QPainter(self)
painter.setClipRect(ev.rect())
painter.fillRect(self.rect(), Qt.yellow)
- QSplitterHandle.paintEvent(self, ev)
def mouseDoubleClickEvent(self, ev):
self.double_clicked.emit(self)
From ced6322e3f4ae0d9b620fcd989364252e7f57255 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Wed, 22 Sep 2010 09:21:54 -0600
Subject: [PATCH 34/37] Rmf24.pl by Tomasz Dlugosz and Gazeta Pomorska by
Richard z
---
resources/images/news/fronda.png | Bin 0 -> 646 bytes
resources/images/news/gazeta_pomorska.png | Bin 0 -> 323 bytes
resources/images/news/legeartis.png | Bin 0 -> 634 bytes
resources/images/news/michalkiewicz.png | Bin 1406 -> 1017 bytes
resources/images/news/rmf24_ESKN.png | Bin 0 -> 722 bytes
resources/images/news/rmf24_fakty.png | Bin 0 -> 722 bytes
resources/recipes/gazeta_pomorska.recipe | 104 ++++++++++++++++++++++
resources/recipes/nczas.recipe | 35 --------
resources/recipes/rmf24_ESKN.recipe | 46 ++++++++++
resources/recipes/rmf24_fakty.recipe | 44 +++++++++
10 files changed, 194 insertions(+), 35 deletions(-)
create mode 100644 resources/images/news/fronda.png
create mode 100644 resources/images/news/gazeta_pomorska.png
create mode 100644 resources/images/news/legeartis.png
create mode 100644 resources/images/news/rmf24_ESKN.png
create mode 100644 resources/images/news/rmf24_fakty.png
create mode 100644 resources/recipes/gazeta_pomorska.recipe
delete mode 100644 resources/recipes/nczas.recipe
create mode 100644 resources/recipes/rmf24_ESKN.recipe
create mode 100644 resources/recipes/rmf24_fakty.recipe
diff --git a/resources/images/news/fronda.png b/resources/images/news/fronda.png
new file mode 100644
index 0000000000000000000000000000000000000000..c332bbda497ebea167e6db230b2000e094538d63
GIT binary patch
literal 646
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b
zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87#P=kx;TbdoSr(#HbcZwqHX^B^z?Ma34YSv
z2i*>O1^haooH8=FOQs=WFg;E1RsEcV|t6Ls7m8!=+j4b&}ZkT@jdR{$6gHbLi1C2F7>(
z9=U$j(z-T4twZg>yF^P7L6;>f4XA%s<=mco`x4nNr}{S@ox$8R^V6GKm-p@7{4MXV
z=z(i<&Hqk#%3^*;)Y$f>lMWY)W5~y6r*8R1Dx8)nK7J<9mQA2VNvzbtw}bU0pGV&!)%d%k(q?5&ZI)f7i3tFY90ZV><00t5;^lpA3vg)e_f;l9a@fRIB8oR3OD*WMF8ZYhbBsWE5gx
uX=P|(Wo)5qU}j}t@Ww)1A4NlMeoAIqC2kFKQ`du%5re0zpUXO@geCwyI|fbw
literal 0
HcmV?d00001
diff --git a/resources/images/news/gazeta_pomorska.png b/resources/images/news/gazeta_pomorska.png
new file mode 100644
index 0000000000000000000000000000000000000000..1d7099d7f3e33461bf0e4153f5c8e7fcb7114afe
GIT binary patch
literal 323
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b
zK-vS0-A-oPfdtD69Mgd`SU*F|v9*VRoE%RV#}JFt$u)m|JgaBpVh~oH#oo@SW571O
z)x7J-cHwAA2_SgF#h;W>btS+571NAo`Rdya8SZNA|Mm8v)I{E+FIi`BzYu4;afs=r
z=!tV~e9Sz|8-B{i3b%?)FK#IZ0z|cU~z*5)9D8#_h%Fx`(*jU%V%*wz(-b5k-MMG|WN@iLmP=kS)uA!l>
jfpLg|iIu6Dm7$TYfjLma)decvKn)C@u6{1-oD!M}DHq-}n6p4nsx^HTzM
zlsu-XrX(_Jiz#trCGWibga6W!O*2itDNPH`OrCnoDd#Wq#e28Zn6q6jq%_SxEigBR
z`>x`}6w!E#f(m_`=dH#4M#lnHhB(tiTb@7f@QCMS>EJN3>WbAXj$QpRy=>aAGd#yHU%vD1
z%^qQerfajR6>O}Ni;5?2OcKmbZC$;0?{~&`(!4?rW!2KVLzLm4%+DD}-?k*LS`xn>l0FqtmanVwVQkYAQEelS<}c
zc)V1|zT0(!j@4T;7RLG0rzuQzisN~`yYXgqzVBD#exJHzuB$lLFB^RXvDF!10Ljzp{OI;(Q5CcmqLm)EOH88U>FxWnw
gyA?%4ZhlH;S|x4`$4+gw1ZrULboFyt=akR{0F^8KUjP6A
literal 0
HcmV?d00001
diff --git a/resources/images/news/michalkiewicz.png b/resources/images/news/michalkiewicz.png
index a87f30f5a37a930674e36cb0d4930a751e76f8fc..cfa61c7fd6982d98c9270d93e2f5cd192d52ff31 100644
GIT binary patch
literal 1017
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b
zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87?_njT^vI!PRCA+_K{%~Y1=>ZZsf8v=Qd2&
zyM53hQ}9Ma)UB?Jy($t{mYD2Wko!nAZqXG9;m55RzaDr`KGy!L!DdFrmQKaSSIuEd
z6HGFDo31)c^@{b{eOq+N-Pya}#@&d#q4)Ukm8)ND=02J8x&HYd_XlY+UPf-7G+V8%
zo_%|@?4FCeyZ8Nm=eS~1R(H2xoYb$TU2pB|{+VfVZ0BQsv$x#5w`}Uazp*B}V((~3
zU%9t!X3!mnPnk=E!z(`hO}uAo*IJ=%Dc7x(a_!~)`>kr05!zE%mc0&$ZNB@m;j7X-
z+qrk{?rC+_|EBzJz77WyxA^oM*MA#iFVzZ(JUm4->{6vhiomT|YmUW8#ZIg|GSk7}
z^5$ikvpBAqrfjmbt9`HW?hx1SvK-fSxehwgF2R~=_56YFKNnrya&fya`)=Of`=9uj
zu{T7iZj|Xxo>i&lyuj6%VTtSH;?u0_yuaGiFJR7bU1aYU&BSojY2N1J{TGYfjr(fm
zY5S=&aV6hpeYs8iMg5}LvHYeAyG^nWFt|?m_cjs
zG_2!#yv{D>>+QArF+M6C?n*zdr~EKJcrxBubmGF3-aY?nX1X)`=^b64c=^zYxqJ6~
z_?1}qLo;LMj_S|8tD@7A9*JM`c74;;rE#)jlFui%nVF^R=fc~58f-eXtS^s2EbY94
z-&~31drP_h&9$C+`gz5h4;)wJyf3`{8fJFU*3NJKpO&56pZENIwwa~bu!+04qjPD&
z(w83>$8X-2wc()R#*^Cx86vN4(AHuQPpe~oaKMHJ(Uc*lcu%8R3_pM3cuji&{zXT4nhew?lS0-d9aGd~ErFA9oX=ZSOnVorAw
zmfS+)iRTcRP4TWP)ExXBTb@$i^_bn4ynJ?BFmPWGGyeb;Jx^)=NT4zXi&!Ef%y7`qY3iE(Qt)A*AtpLpYoN*OQzjM
z>oq~=DZ!K(cB))AG3cXkRJ1el^CR3ljw^l6Vb5_ThAAFf92qX3Bt3=aW;>z>r+8x
z-y=%)++_Ws2bi3#)P4AvlW&L~ZwShFUckNgB=rX_arK$t**y=V
zL)RI;^&Lk)zD|4J2!jIyWR#r8So8@SYL3yT%%@=geG-ipGSW=w6H}O*WW!?1B-Xiu
z&LKf=`(2v$kFm1hD5ZNnba%9I>!Cmh@!|&l_W!tw|HJ>-1UC9dH>8^9o0C%$n`BqT
zmgWA@Zzm_Gnk{nTD!Fm#YH23Z%jHyyMSgW<{X1@lw19b`7Fm{4{0yb9xhtix+WbvA
zSx#6R_0o#XZ@H~AHxz{GWP41IVOe0{!c5ca>c}Y5lxenv(zGm9+F~jAm9UIxYk18J
z=hVe7&x??xLcKmO!FQb@Z%ge*nRV6N>-<
diff --git a/resources/images/news/rmf24_ESKN.png b/resources/images/news/rmf24_ESKN.png
new file mode 100644
index 0000000000000000000000000000000000000000..53ad00078a964edca84fbfb957006de84ec6ab90
GIT binary patch
literal 722
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b
zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87#M$hx;TbdoW45AJ6kwWqIG_LTG3U3jX|m=
zjz_t61r(~fx@s?4z|9?7(U`!huOMn3Dv%k>GJR2=mxK8t1*IFkADeVTSsYg?X>3u7
zEm$(S}zdbp1~lsA~}Hl
z6${J7_p_Kd>@F=j;KsO8<6_67=M4-VOxNyftZ4SgaIV>PVd28Zrwl`$`>uIZ`s@8W
zR^by3v1cz;Z98&mUfmr@VHOwTM8=M^c8vf%5%ayvYOk^+2YYKy<-fT7x8b(AOAGe#
zKNAx^?>E^*dV!;fz7B&)u7GLAe}__=!xNvkpL~8y;_sBjZ;Q;g_uYGTaQD~5rzQc+
zoDyb#1jD-3R{9iViQV>-Q;*k~=we)w*6>!`f5V|Qg4gBxdy0i%lYRMlxe27{?l#Gf~o}jci%G845s7H%yIa+E@GKc6~v|xyGERH00)|WTsW(*04Hc
Rayd`~gQu&X%Q~loCIBf=9ykC1
literal 0
HcmV?d00001
diff --git a/resources/images/news/rmf24_fakty.png b/resources/images/news/rmf24_fakty.png
new file mode 100644
index 0000000000000000000000000000000000000000..53ad00078a964edca84fbfb957006de84ec6ab90
GIT binary patch
literal 722
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b
zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87#M$hx;TbdoW45AJ6kwWqIG_LTG3U3jX|m=
zjz_t61r(~fx@s?4z|9?7(U`!huOMn3Dv%k>GJR2=mxK8t1*IFkADeVTSsYg?X>3u7
zEm$(S}zdbp1~lsA~}Hl
z6${J7_p_Kd>@F=j;KsO8<6_67=M4-VOxNyftZ4SgaIV>PVd28Zrwl`$`>uIZ`s@8W
zR^by3v1cz;Z98&mUfmr@VHOwTM8=M^c8vf%5%ayvYOk^+2YYKy<-fT7x8b(AOAGe#
zKNAx^?>E^*dV!;fz7B&)u7GLAe}__=!xNvkpL~8y;_sBjZ;Q;g_uYGTaQD~5rzQc+
zoDyb#1jD-3R{9iViQV>-Q;*k~=we)w*6>!`f5V|Qg4gBxdy0i%lYRMlxe27{?l#Gf~o}jci%G845s7H%yIa+E@GKc6~v|xyGERH00)|WTsW(*04Hc
Rayd`~gQu&X%Q~loCIBf=9ykC1
literal 0
HcmV?d00001
diff --git a/resources/recipes/gazeta_pomorska.recipe b/resources/recipes/gazeta_pomorska.recipe
new file mode 100644
index 0000000000..083f5cbeed
--- /dev/null
+++ b/resources/recipes/gazeta_pomorska.recipe
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+
+# # Przed uzyciem przeczytaj komentarz w sekcji "feeds"
+
+__license__ = 'GPL v3'
+__copyright__ = u'2010, Richard z forum.eksiazki.org'
+'''pomorska.pl'''
+
+import re
+from calibre.web.feeds.news import BasicNewsRecipe
+
+class GazetaPomorska(BasicNewsRecipe):
+ title = u'Gazeta Pomorska'
+ publisher = u'Gazeta Pomorska'
+ description = u'Kujawy i Pomorze - wiadomo\u015bci'
+ language = 'pl'
+ __author__ = u'Richard z forum.eksiazki.org'
+ # # (dziekuje t3d z forum.eksiazki.org za testy)
+ oldest_article = 2
+ max_articles_per_feed = 20
+ no_stylesheets = True
+ remove_javascript = True
+ preprocess_regexps = [
+ (re.compile(r''
-'''
-nczas.com
-'''
-
-from calibre.web.feeds.news import BasicNewsRecipe
-
-#
-
-class NCzas(BasicNewsRecipe):
- title = u'Najwy\u017cszy Czas!'
- description = u'Najwy\u017cszy Czas!\nwydanie internetowe'
- __author__ = u'Tomasz D\u0142ugosz'
- language = 'pl'
- oldest_article = 7
- max_articles_per_feed = 100
- no_stylesheets = True
- cover_url = 'http://nczas.com/wp-content/themes/default/grafika/logo.png'
-
- keep_only_tags = [dict(name='div', attrs={'class':'trescartykulu'})]
-
- feeds = [(u'Najwy\u017cszy Czas!', u'http://nczas.com/feed/')]
-
- def postprocess_html(self, soup, first):
-
- for tag in soup.findAll(name= 'img', alt=""):
- tag.extract()
-
- for item in soup.findAll(align = "right"):
- del item['align']
-
- return soup
diff --git a/resources/recipes/rmf24_ESKN.recipe b/resources/recipes/rmf24_ESKN.recipe
new file mode 100644
index 0000000000..992b84529c
--- /dev/null
+++ b/resources/recipes/rmf24_ESKN.recipe
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+__license__ = 'GPL v3'
+__copyright__ = u'2010, Tomasz Dlugosz '
+'''
+rmf24.pl
+'''
+
+import re
+from calibre.web.feeds.news import BasicNewsRecipe
+
+class RMF24_ESKN(BasicNewsRecipe):
+ title = u'Rmf24.pl - Ekonomia Sport Kultura Nauka'
+ description = u'Ekonomia, sport, kultura i nauka ze strony rmf24.pl'
+ language = 'pl'
+ oldest_article = 7
+ max_articles_per_feed = 100
+ __author__ = u'Tomasz D\u0142ugosz'
+ no_stylesheets = True
+ remove_javascript = True
+
+ feeds = [(u'Ekonomia', u'http://www.rmf24.pl/ekonomia/feed'),
+ (u'Sport', u'http://www.rmf24.pl/sport/feed'),
+ (u'Kultura', u'http://www.rmf24.pl/kultura/feed'),
+ (u'Nauka', u'http://www.rmf24.pl/nauka/feed')]
+
+ keep_only_tags = [dict(name='div', attrs={'class':'box articleSingle print'})]
+
+ remove_tags = [
+ dict(name='div', attrs={'class':'toTop'}),
+ dict(name='div', attrs={'class':'category'}),
+ dict(name='div', attrs={'class':'REMOVE'}),
+ dict(name='div', attrs={'class':'embed embedAd'})]
+
+ extra_css = '''
+ h1 { font-size: 1.2em; }
+ '''
+
+ preprocess_regexps = [
+ (re.compile(i[0], re.IGNORECASE | re.DOTALL), i[1]) for i in
+ [
+ (r'Zdj.cie ', lambda match: ''),
+ (r'embed embed(Left|Right|Center) articleEmbed(Audio|Wideo articleEmbedVideo|ArticleFull|ArticleTitle|ArticleListTitle|AlbumHorizontal)">', lambda match: 'REMOVE">'),
+ (r'', lambda match: 'REMOVE">'),
+ (r'