Merge from trunk

This commit is contained in:
Charles Haley 2012-05-05 08:26:57 +02:00
commit 49d1385ea9
11 changed files with 714 additions and 502 deletions

34
recipes/rebelion.recipe Normal file
View File

@ -0,0 +1,34 @@
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import unicode_literals
from calibre.web.feeds.news import BasicNewsRecipe
import re
class RebelionRecipe (BasicNewsRecipe):
__author__ = u'Marc Busqué <marc@lamarciana.com>' #Thanks to atlantique http://www.mobileread.com/forums/member.php?u=67876
__url__ = 'http://www.lamarciana.com'
__version__ = '1.0'
__license__ = 'GPL v3'
__copyright__ = '2012, Marc Busqué <marc@lamarciana.com>'
title = u'Rebelion.org'
description = u'Rebelión pretende ser un medio de información alternativa que publique las noticias que no son consideradas importantes por los medios de comunicación tradicionales. También, dar a las noticias un tratamiento diferente en la línea de mostrar los intereses que los poderes económicos y políticos del mundo capitalista ocultan para mantener sus privilegios y el status actual. Queremos servir y ayudarnos de todos los grupos, colectivos y personas que trabajan por cambiar este mundo en una perspectiva radicalmente diferente, más justa, igualitaria y equilibrada social y ecológicamente. Es nuestro objetivo contar con la participación y colaboración de todos vosotros para que Rebelión sea un espacio serio, riguroso y actualizado en la difusión de noticias.'
url = 'http://www.rebelion.org'
language = 'es'
tags = 'contrainformación, información alternativa'
oldest_article = 1
remove_empty_feeds = True
encoding = 'latin1' #
keep_only_tags = [
{'name': 'div', 'attrs': {'id': 'CuerpoNoticia'}}
]
no_stylesheets = True
extra_css = '.autor {font-style: italic;} .titulo {font-size: 150%;} .titulo, .pretitulo {text-align: center;} #TextoNoticia {text-align:justify;} .autor, .fuente, .entradilla {font-size: 90%; text-align: left;}'
feeds = [
(u'Titulares del día', u'http://www.rebelion.org/rss_portada.php'),
]
#See http://www.mobileread.com/forums/showthread.php?t=174501
def print_version(self, url):
id = re.compile('\d*$').search(url).group()
return u'http://www.rebelion.org/noticia.php?id=%s' % id

View File

@ -177,7 +177,7 @@ class ANDROID(USBMS):
'TELECHIP', 'HUAWEI', 'T-MOBILE', 'SEMC', 'LGE', 'NVIDIA', 'TELECHIP', 'HUAWEI', 'T-MOBILE', 'SEMC', 'LGE', 'NVIDIA',
'GENERIC-', 'ZTE', 'MID', 'QUALCOMM', 'PANDIGIT', 'HYSTON', 'GENERIC-', 'ZTE', 'MID', 'QUALCOMM', 'PANDIGIT', 'HYSTON',
'VIZIO', 'GOOGLE', 'FREESCAL', 'KOBO_INC', 'LENOVO', 'ROCKCHIP', 'VIZIO', 'GOOGLE', 'FREESCAL', 'KOBO_INC', 'LENOVO', 'ROCKCHIP',
'POCKET', 'ONDA_MID', 'ZENITHIN', 'INGENIC', 'PMID701C'] 'POCKET', 'ONDA_MID', 'ZENITHIN', 'INGENIC', 'PMID701C', 'PD']
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE', WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE',
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897', '__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897',
'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID',
@ -193,7 +193,7 @@ class ANDROID(USBMS):
'GT-I9003_CARD', 'XT912', 'FILE-CD_GADGET', 'RK29_SDK', 'MB855', 'GT-I9003_CARD', 'XT912', 'FILE-CD_GADGET', 'RK29_SDK', 'MB855',
'XT910', 'BOOK_A10', 'USB_2.0_DRIVER', 'I9100T', 'P999DW', 'XT910', 'BOOK_A10', 'USB_2.0_DRIVER', 'I9100T', 'P999DW',
'KTABLET_PC', 'INGENIC', 'GT-I9001_CARD', 'USB_2.0_DRIVER', 'KTABLET_PC', 'INGENIC', 'GT-I9001_CARD', 'USB_2.0_DRIVER',
'GT-S5830L_CARD'] 'GT-S5830L_CARD', 'UNIVERSE']
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897', WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD', 'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD',
'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB', 'SGH-T849_CARD', 'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB', 'SGH-T849_CARD',

View File

@ -312,13 +312,9 @@ class EPUBOutput(OutputFormatPlugin):
Perform various markup transforms to get the output to render correctly Perform various markup transforms to get the output to render correctly
in the quirky ADE. in the quirky ADE.
''' '''
from calibre.ebooks.oeb.base import XPath, XHTML, OEB_STYLES, barename, urlunquote from calibre.ebooks.oeb.base import XPath, XHTML, barename, urlunquote
stylesheet = None stylesheet = self.oeb.manifest.main_stylesheet
for item in self.oeb.manifest:
if item.media_type.lower() in OEB_STYLES:
stylesheet = item
break
# ADE cries big wet tears when it encounters an invalid fragment # ADE cries big wet tears when it encounters an invalid fragment
# identifier in the NCX toc. # identifier in the NCX toc.

View File

@ -99,12 +99,8 @@ class PDFOutput(OutputFormatPlugin):
# Remove page-break-before on <body> element as it causes # Remove page-break-before on <body> element as it causes
# blank pages in PDF Output # blank pages in PDF Output
from calibre.ebooks.oeb.base import OEB_STYLES, XPath from calibre.ebooks.oeb.base import XPath
stylesheet = None stylesheet = self.oeb.manifest.main_stylesheet
for item in self.oeb.manifest:
if item.media_type.lower() in OEB_STYLES:
stylesheet = item
break
if stylesheet is not None: if stylesheet is not None:
from cssutils.css import CSSRule from cssutils.css import CSSRule
classes = set(['.calibre']) classes = set(['.calibre'])

View File

@ -5,7 +5,7 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import re import re, error as re_error
from math import ceil from math import ceil
from calibre.ebooks.conversion.preprocess import DocAnalysis, Dehyphenator from calibre.ebooks.conversion.preprocess import DocAnalysis, Dehyphenator
from calibre.utils.logging import default_log from calibre.utils.logging import default_log
@ -148,7 +148,7 @@ class HeuristicProcessor(object):
return wordcount.words return wordcount.words
def markup_italicis(self, html): def markup_italicis(self, html):
self.log.debug("\n\n\nitalicize debugging \n\n\n") #self.log.debug("\n\n\nitalicize debugging \n\n\n")
ITALICIZE_WORDS = [ ITALICIZE_WORDS = [
'Etc.', 'etc.', 'viz.', 'ie.', 'i.e.', 'Ie.', 'I.e.', 'eg.', 'Etc.', 'etc.', 'viz.', 'ie.', 'i.e.', 'Ie.', 'I.e.', 'eg.',
'e.g.', 'Eg.', 'E.g.', 'et al.', 'et cetera', 'n.b.', 'N.b.', 'e.g.', 'Eg.', 'E.g.', 'et al.', 'et cetera', 'n.b.', 'N.b.',
@ -184,6 +184,9 @@ class HeuristicProcessor(object):
except OverflowError: except OverflowError:
# match.group(0) was too large to be compiled into a regex # match.group(0) was too large to be compiled into a regex
continue continue
except re_error:
# the match was not a valid regular expression
continue
return html return html

View File

@ -81,6 +81,23 @@ _css_url_re = re.compile(r'url\s*\([\'"]{0,1}(.*?)[\'"]{0,1}\)', re.I)
_css_import_re = re.compile(r'@import "(.*?)"') _css_import_re = re.compile(r'@import "(.*?)"')
_archive_re = re.compile(r'[^ ]+') _archive_re = re.compile(r'[^ ]+')
# Tags that should not be self closed in epub output
self_closing_bad_tags = {'a', 'abbr', 'address', 'article', 'aside', 'audio', 'b',
'bdo', 'blockquote', 'body', 'button', 'cite', 'code', 'dd', 'del', 'details',
'dfn', 'div', 'dl', 'dt', 'em', 'fieldset', 'figcaption', 'figure', 'footer',
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'i', 'ins', 'kbd',
'label', 'legend', 'li', 'map', 'mark', 'meter', 'nav', 'ol', 'output', 'p',
'pre', 'progress', 'q', 'rp', 'rt', 'samp', 'section', 'select', 'small',
'span', 'strong', 'sub', 'summary', 'sup', 'textarea', 'time', 'ul', 'var',
'video'}
_self_closing_pat = re.compile(
r'<(?P<tag>%s)(?=[\s/])(?P<arg>[^>]*)/>'%('|'.join(self_closing_bad_tags)),
re.IGNORECASE)
def close_self_closing_tags(raw):
return _self_closing_pat.sub(r'<\g<tag>\g<arg>></\g<tag>>', raw)
def iterlinks(root, find_links_in_css=True): def iterlinks(root, find_links_in_css=True):
''' '''
Iterate over all links in a OEB Document. Iterate over all links in a OEB Document.
@ -938,13 +955,10 @@ class Manifest(object):
if isinstance(data, etree._Element): if isinstance(data, etree._Element):
ans = xml2str(data, pretty_print=self.oeb.pretty_print) ans = xml2str(data, pretty_print=self.oeb.pretty_print)
if self.media_type in OEB_DOCS: if self.media_type in OEB_DOCS:
# Convert self closing div|span|a|video|audio|iframe tags # Convert self closing div|span|a|video|audio|iframe|etc tags
# to normally closed ones, as they are interpreted # to normally closed ones, as they are interpreted
# incorrectly by some browser based renderers # incorrectly by some browser based renderers
ans = re.sub( ans = close_self_closing_tags(ans)
# tag name followed by either a space or a /
r'<(?P<tag>div|a|span|video|audio|iframe)(?=[\s/])(?P<arg>[^>]*)/>',
r'<\g<tag>\g<arg>></\g<tag>>', ans)
return ans return ans
if isinstance(data, unicode): if isinstance(data, unicode):
return data.encode('utf-8') return data.encode('utf-8')
@ -1142,6 +1156,19 @@ class Manifest(object):
element(elem, OPF('item'), attrib=attrib) element(elem, OPF('item'), attrib=attrib)
return elem return elem
@dynamic_property
def main_stylesheet(self):
def fget(self):
ans = getattr(self, '_main_stylesheet', None)
if ans is None:
for item in self:
if item.media_type.lower() in OEB_STYLES:
ans = item
break
return ans
def fset(self, item):
self._main_stylesheet = item
return property(fget=fget, fset=fset)
class Spine(object): class Spine(object):
"""Collection of manifest items composing an OEB data model book's main """Collection of manifest items composing an OEB data model book's main

View File

@ -378,7 +378,7 @@ class CSSFlattener(object):
for child in node: for child in node:
self.flatten_node(child, stylizer, names, styles, psize, item_id, left) self.flatten_node(child, stylizer, names, styles, psize, item_id, left)
def flatten_head(self, item, stylizer, href): def flatten_head(self, item, href, global_href):
html = item.data html = item.data
head = html.find(XHTML('head')) head = html.find(XHTML('head'))
for node in head: for node in head:
@ -390,34 +390,56 @@ class CSSFlattener(object):
and node.get('type', CSS_MIME) in OEB_STYLES: and node.get('type', CSS_MIME) in OEB_STYLES:
head.remove(node) head.remove(node)
href = item.relhref(href) href = item.relhref(href)
etree.SubElement(head, XHTML('link'), l = etree.SubElement(head, XHTML('link'),
rel='stylesheet', type=CSS_MIME, href=href) rel='stylesheet', type=CSS_MIME, href=href)
stylizer.page_rule['margin-top'] = '%gpt'%\ l.tail='\n'
float(self.context.margin_top) href = item.relhref(global_href)
stylizer.page_rule['margin-bottom'] = '%gpt'%\ l = etree.SubElement(head, XHTML('link'),
float(self.context.margin_bottom) rel='stylesheet', type=CSS_MIME, href=href)
l.tail = '\n'
items = stylizer.page_rule.items()
items.sort()
css = '; '.join("%s: %s" % (key, val) for key, val in items)
style = etree.SubElement(head, XHTML('style'), type=CSS_MIME)
style.text = "\n\t\t@page { %s; }" % css
rules = [r.cssText for r in stylizer.font_face_rules]
raw = '\n\n'.join(rules)
# Make URLs referring to fonts relative to this item
sheet = cssutils.parseString(raw, validate=False)
cssutils.replaceUrls(sheet, item.relhref, ignoreImportRules=True)
style.text += '\n' + sheet.cssText
def replace_css(self, css): def replace_css(self, css):
manifest = self.oeb.manifest manifest = self.oeb.manifest
id, href = manifest.generate('css', 'stylesheet.css')
for item in manifest.values(): for item in manifest.values():
if item.media_type in OEB_STYLES: if item.media_type in OEB_STYLES:
manifest.remove(item) manifest.remove(item)
item = manifest.add(id, href, CSS_MIME, data=css) id, href = manifest.generate('css', 'stylesheet.css')
item = manifest.add(id, href, CSS_MIME, data=cssutils.parseString(css,
validate=False))
self.oeb.manifest.main_stylesheet = item
return href return href
def collect_global_css(self):
global_css = defaultdict(list)
for item in self.oeb.spine:
stylizer = self.stylizers[item]
stylizer.page_rule['margin-top'] = '%gpt'%\
float(self.context.margin_top)
stylizer.page_rule['margin-bottom'] = '%gpt'%\
float(self.context.margin_bottom)
items = stylizer.page_rule.items()
items.sort()
css = ';\n'.join("%s: %s" % (key, val) for key, val in items)
css = '@page {\n%s\n}\n'%css
rules = [r.cssText for r in stylizer.font_face_rules]
raw = '\n\n'.join(rules)
css += '\n\n' + raw
global_css[css].append(item)
gc_map = {}
manifest = self.oeb.manifest
for css in global_css:
id_, href = manifest.generate('page_css', 'page_styles.css')
manifest.add(id_, href, CSS_MIME, data=cssutils.parseString(css,
validate=False))
gc_map[css] = href
ans = {}
for css, items in global_css.iteritems():
for item in items:
ans[item] = gc_map[css]
return ans
def flatten_spine(self): def flatten_spine(self):
names = defaultdict(int) names = defaultdict(int)
styles = {} styles = {}
@ -433,7 +455,8 @@ class CSSFlattener(object):
items.sort() items.sort()
css = ''.join(".%s {\n%s;\n}\n\n" % (key, val) for key, val in items) css = ''.join(".%s {\n%s;\n}\n\n" % (key, val) for key, val in items)
href = self.replace_css(css) href = self.replace_css(css)
global_css = self.collect_global_css()
for item in self.oeb.spine: for item in self.oeb.spine:
stylizer = self.stylizers[item] stylizer = self.stylizers[item]
self.flatten_head(item, stylizer, href) self.flatten_head(item, href, global_css[item])

View File

@ -9,7 +9,7 @@ __docformat__ = 'restructuredtext en'
from collections import Counter from collections import Counter
from calibre.ebooks.oeb.base import OEB_STYLES, barename, XPath from calibre.ebooks.oeb.base import barename, XPath
class RemoveAdobeMargins(object): class RemoveAdobeMargins(object):
''' '''
@ -51,10 +51,7 @@ class RemoveFakeMargins(object):
self.stats = {} self.stats = {}
self.selector_map = {} self.selector_map = {}
for item in self.oeb.manifest: stylesheet = self.oeb.manifest.main_stylesheet
if item.media_type.lower() in OEB_STYLES:
stylesheet = item
break
if stylesheet is None: if stylesheet is None:
return return

View File

@ -259,33 +259,36 @@ class RuleEditor(QDialog): # {{{
l.addWidget(l3, 2, 2) l.addWidget(l3, 2, 2)
self.color_box = QComboBox(self) self.color_box = QComboBox(self)
self.color_label = QLabel('Sample text Sample text')
self.color_label.setTextFormat(Qt.RichText)
l.addWidget(self.color_box, 2, 3) l.addWidget(self.color_box, 2, 3)
l.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding), 2, 4) l.addWidget(self.color_label, 2, 4)
l.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding), 2, 5)
self.l4 = l4 = QLabel( self.l4 = l4 = QLabel(
_('Only if the following conditions are all satisfied:')) _('Only if the following conditions are all satisfied:'))
l.addWidget(l4, 3, 0, 1, 5) l.addWidget(l4, 3, 0, 1, 6)
self.scroll_area = sa = QScrollArea(self) self.scroll_area = sa = QScrollArea(self)
sa.setMinimumHeight(300) sa.setMinimumHeight(300)
sa.setMinimumWidth(950) sa.setMinimumWidth(950)
sa.setWidgetResizable(True) sa.setWidgetResizable(True)
l.addWidget(sa, 4, 0, 1, 5) l.addWidget(sa, 4, 0, 1, 6)
self.add_button = b = QPushButton(QIcon(I('plus.png')), self.add_button = b = QPushButton(QIcon(I('plus.png')),
_('Add another condition')) _('Add another condition'))
l.addWidget(b, 5, 0, 1, 5) l.addWidget(b, 5, 0, 1, 6)
b.clicked.connect(self.add_blank_condition) b.clicked.connect(self.add_blank_condition)
self.l5 = l5 = QLabel(_('You can disable a condition by' self.l5 = l5 = QLabel(_('You can disable a condition by'
' blanking all of its boxes')) ' blanking all of its boxes'))
l.addWidget(l5, 6, 0, 1, 5) l.addWidget(l5, 6, 0, 1, 6)
self.bb = bb = QDialogButtonBox( self.bb = bb = QDialogButtonBox(
QDialogButtonBox.Ok|QDialogButtonBox.Cancel) QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
bb.accepted.connect(self.accept) bb.accepted.connect(self.accept)
bb.rejected.connect(self.reject) bb.rejected.connect(self.reject)
l.addWidget(bb, 7, 0, 1, 5) l.addWidget(bb, 7, 0, 1, 6)
self.conditions_widget = QWidget(self) self.conditions_widget = QWidget(self)
sa.setWidget(self.conditions_widget) sa.setWidget(self.conditions_widget)
@ -308,8 +311,21 @@ class RuleEditor(QDialog): # {{{
self.color_box.addItems(QColor.colorNames()) self.color_box.addItems(QColor.colorNames())
self.color_box.setCurrentIndex(0) self.color_box.setCurrentIndex(0)
self.update_color_label()
self.color_box.currentIndexChanged.connect(self.update_color_label)
self.resize(self.sizeHint()) self.resize(self.sizeHint())
def update_color_label(self):
pal = QApplication.palette()
bg1 = unicode(pal.color(pal.Base).name())
bg2 = unicode(pal.color(pal.AlternateBase).name())
c = unicode(self.color_box.currentText())
self.color_label.setText('''
<span style="color: {c}; background-color: {bg1}">&nbsp;{st}&nbsp;</span>
<span style="color: {c}; background-color: {bg2}">&nbsp;{st}&nbsp;</span>
'''.format(c=c, bg1=bg1, bg2=bg2, st=_('Sample Text')))
def add_blank_condition(self): def add_blank_condition(self):
c = ConditionEditor(self.fm, parent=self.conditions_widget) c = ConditionEditor(self.fm, parent=self.conditions_widget)
self.conditions.append(c) self.conditions.append(c)
@ -617,7 +633,7 @@ if __name__ == '__main__':
db = db() db = db()
if False: if True:
d = RuleEditor(db.field_metadata) d = RuleEditor(db.field_metadata)
d.add_blank_condition() d.add_blank_condition()
d.exec_() d.exec_()

View File

@ -9,7 +9,7 @@ import mechanize
from calibre.constants import (__appname__, __version__, iswindows, isosx, from calibre.constants import (__appname__, __version__, iswindows, isosx,
isportable) isportable)
from calibre import browser from calibre import browser, prints, as_unicode
from calibre.utils.config import prefs from calibre.utils.config import prefs
from calibre.gui2 import config, dynamic, open_url from calibre.gui2 import config, dynamic, open_url
from calibre.gui2.dialogs.plugin_updater import get_plugin_updates_available from calibre.gui2.dialogs.plugin_updater import get_plugin_updates_available
@ -45,14 +45,14 @@ class CheckForUpdates(QThread):
version = get_newest_version() version = get_newest_version()
if version and version != __version__ and len(version) < 10: if version and version != __version__ and len(version) < 10:
calibre_update_version = version calibre_update_version = version
except: except Exception as e:
traceback.print_exc() prints('Failed to check for calibre update:', as_unicode(e))
try: try:
update_plugins = get_plugin_updates_available() update_plugins = get_plugin_updates_available()
if update_plugins is not None: if update_plugins is not None:
plugins_update_found = len(update_plugins) plugins_update_found = len(update_plugins)
except: except Exception as e:
traceback.print_exc() prints('Failed to check for plugin update:', as_unicode(e))
if (calibre_update_version != NO_CALIBRE_UPDATE or if (calibre_update_version != NO_CALIBRE_UPDATE or
plugins_update_found > 0): plugins_update_found > 0):
self.update_found.emit('%s%s%d'%(calibre_update_version, self.update_found.emit('%s%s%d'%(calibre_update_version,

File diff suppressed because it is too large Load Diff