mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
cf8e89aed5
@ -85,7 +85,11 @@ class ISBNMerge(object):
|
|||||||
isbns, min_year = xisbn.get_isbn_pool(isbn)
|
isbns, min_year = xisbn.get_isbn_pool(isbn)
|
||||||
if not isbns:
|
if not isbns:
|
||||||
isbns = frozenset([isbn])
|
isbns = frozenset([isbn])
|
||||||
self.pools[isbns] = pool = (min_year, [])
|
if isbns in self.pools:
|
||||||
|
# xISBN had a brain fart
|
||||||
|
pool = self.pools[isbns]
|
||||||
|
else:
|
||||||
|
self.pools[isbns] = pool = (min_year, [])
|
||||||
|
|
||||||
if not self.pool_has_result_from_same_source(pool, result):
|
if not self.pool_has_result_from_same_source(pool, result):
|
||||||
pool[1].append(result)
|
pool[1].append(result)
|
||||||
|
@ -45,6 +45,11 @@ class xISBN(object):
|
|||||||
ans.append(rec)
|
ans.append(rec)
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
def isbns_in_data(self, data):
|
||||||
|
for rec in data:
|
||||||
|
for i in rec.get('isbn', []):
|
||||||
|
yield i
|
||||||
|
|
||||||
def get_data(self, isbn):
|
def get_data(self, isbn):
|
||||||
isbn = self.purify(isbn)
|
isbn = self.purify(isbn)
|
||||||
with self.lock:
|
with self.lock:
|
||||||
@ -57,9 +62,8 @@ class xISBN(object):
|
|||||||
data = []
|
data = []
|
||||||
id_ = len(self._data)
|
id_ = len(self._data)
|
||||||
self._data.append(data)
|
self._data.append(data)
|
||||||
for rec in data:
|
for i in self.isbns_in_data(data):
|
||||||
for i in rec.get('isbn', []):
|
self._map[i] = id_
|
||||||
self._map[i] = id_
|
|
||||||
self._map[isbn] = id_
|
self._map[isbn] = id_
|
||||||
return self._data[self._map[isbn]]
|
return self._data[self._map[isbn]]
|
||||||
|
|
||||||
|
@ -443,11 +443,15 @@ class MobiMLizer(object):
|
|||||||
tag = 'span' if tag == 'td' else 'div'
|
tag = 'span' if tag == 'td' else 'div'
|
||||||
|
|
||||||
if tag == 'table':
|
if tag == 'table':
|
||||||
|
col = style.backgroundColor
|
||||||
|
if col:
|
||||||
|
elem.set('bgcolor', col)
|
||||||
css = style.cssdict()
|
css = style.cssdict()
|
||||||
if 'border' in css or 'border-width' in css:
|
if 'border' in css or 'border-width' in css:
|
||||||
elem.set('border', '1')
|
elem.set('border', '1')
|
||||||
if tag in TABLE_TAGS:
|
if tag in TABLE_TAGS:
|
||||||
for attr in ('rowspan', 'colspan', 'width', 'border', 'scope'):
|
for attr in ('rowspan', 'colspan', 'width', 'border', 'scope',
|
||||||
|
'bgcolor'):
|
||||||
if attr in elem.attrib:
|
if attr in elem.attrib:
|
||||||
istate.attrib[attr] = elem.attrib[attr]
|
istate.attrib[attr] = elem.attrib[attr]
|
||||||
if tag == 'q':
|
if tag == 'q':
|
||||||
|
@ -11,7 +11,6 @@ __copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.com>'
|
|||||||
import os, itertools, re, logging, copy, unicodedata
|
import os, itertools, re, logging, copy, unicodedata
|
||||||
from weakref import WeakKeyDictionary
|
from weakref import WeakKeyDictionary
|
||||||
from xml.dom import SyntaxErr as CSSSyntaxError
|
from xml.dom import SyntaxErr as CSSSyntaxError
|
||||||
import cssutils
|
|
||||||
from cssutils.css import (CSSStyleRule, CSSPageRule, CSSStyleDeclaration,
|
from cssutils.css import (CSSStyleRule, CSSPageRule, CSSStyleDeclaration,
|
||||||
CSSFontFaceRule, cssproperties)
|
CSSFontFaceRule, cssproperties)
|
||||||
try:
|
try:
|
||||||
@ -20,7 +19,8 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
# cssutils >= 0.9.8
|
# cssutils >= 0.9.8
|
||||||
from cssutils.css import PropertyValue as CSSValueList
|
from cssutils.css import PropertyValue as CSSValueList
|
||||||
from cssutils import profile as cssprofiles
|
from cssutils import (profile as cssprofiles, parseString, parseStyle, log as
|
||||||
|
cssutils_log, CSSParser, profiles)
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from lxml.cssselect import css_to_xpath, ExpressionError, SelectorSyntaxError
|
from lxml.cssselect import css_to_xpath, ExpressionError, SelectorSyntaxError
|
||||||
from calibre import force_unicode
|
from calibre import force_unicode
|
||||||
@ -28,7 +28,7 @@ from calibre.ebooks import unit_convert
|
|||||||
from calibre.ebooks.oeb.base import XHTML, XHTML_NS, CSS_MIME, OEB_STYLES
|
from calibre.ebooks.oeb.base import XHTML, XHTML_NS, CSS_MIME, OEB_STYLES
|
||||||
from calibre.ebooks.oeb.base import XPNSMAP, xpath, urlnormalize
|
from calibre.ebooks.oeb.base import XPNSMAP, xpath, urlnormalize
|
||||||
|
|
||||||
cssutils.log.setLevel(logging.WARN)
|
cssutils_log.setLevel(logging.WARN)
|
||||||
|
|
||||||
_html_css_stylesheet = None
|
_html_css_stylesheet = None
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ def html_css_stylesheet():
|
|||||||
global _html_css_stylesheet
|
global _html_css_stylesheet
|
||||||
if _html_css_stylesheet is None:
|
if _html_css_stylesheet is None:
|
||||||
html_css = open(P('templates/html.css'), 'rb').read()
|
html_css = open(P('templates/html.css'), 'rb').read()
|
||||||
_html_css_stylesheet = cssutils.parseString(html_css)
|
_html_css_stylesheet = parseString(html_css)
|
||||||
_html_css_stylesheet.namespaces['h'] = XHTML_NS
|
_html_css_stylesheet.namespaces['h'] = XHTML_NS
|
||||||
return _html_css_stylesheet
|
return _html_css_stylesheet
|
||||||
|
|
||||||
@ -157,11 +157,11 @@ class Stylizer(object):
|
|||||||
|
|
||||||
# Add cssutils parsing profiles from output_profile
|
# Add cssutils parsing profiles from output_profile
|
||||||
for profile in self.opts.output_profile.extra_css_modules:
|
for profile in self.opts.output_profile.extra_css_modules:
|
||||||
cssutils.profile.addProfile(profile['name'],
|
cssprofiles.addProfile(profile['name'],
|
||||||
profile['props'],
|
profile['props'],
|
||||||
profile['macros'])
|
profile['macros'])
|
||||||
|
|
||||||
parser = cssutils.CSSParser(fetcher=self._fetch_css_file,
|
parser = CSSParser(fetcher=self._fetch_css_file,
|
||||||
log=logging.getLogger('calibre.css'))
|
log=logging.getLogger('calibre.css'))
|
||||||
self.font_face_rules = []
|
self.font_face_rules = []
|
||||||
for elem in head:
|
for elem in head:
|
||||||
@ -473,6 +473,7 @@ class Style(object):
|
|||||||
self._width = None
|
self._width = None
|
||||||
self._height = None
|
self._height = None
|
||||||
self._lineHeight = None
|
self._lineHeight = None
|
||||||
|
self._bgcolor = None
|
||||||
stylizer._styles[element] = self
|
stylizer._styles[element] = self
|
||||||
|
|
||||||
def set(self, prop, val):
|
def set(self, prop, val):
|
||||||
@ -533,6 +534,48 @@ class Style(object):
|
|||||||
def pt_to_px(self, value):
|
def pt_to_px(self, value):
|
||||||
return (self._profile.dpi / 72.0) * value
|
return (self._profile.dpi / 72.0) * value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def backgroundColor(self):
|
||||||
|
'''
|
||||||
|
Return the background color by parsing both the background-color and
|
||||||
|
background shortcut properties. Note that inheritance/default values
|
||||||
|
are not used. None is returned if no background color is set.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def validate_color(col):
|
||||||
|
return cssprofiles.validateWithProfile('color',
|
||||||
|
col,
|
||||||
|
profiles=[profiles.Profiles.CSS_LEVEL_2])[1]
|
||||||
|
|
||||||
|
if self._bgcolor is None:
|
||||||
|
col = None
|
||||||
|
val = self._style.get('background-color', None)
|
||||||
|
if val and validate_color(val):
|
||||||
|
col = val
|
||||||
|
else:
|
||||||
|
val = self._style.get('background', None)
|
||||||
|
if val is not None:
|
||||||
|
try:
|
||||||
|
style = parseStyle('background: '+val)
|
||||||
|
val = style.getProperty('background').cssValue
|
||||||
|
try:
|
||||||
|
val = list(val)
|
||||||
|
except:
|
||||||
|
# val is CSSPrimitiveValue
|
||||||
|
val = [val]
|
||||||
|
for c in val:
|
||||||
|
c = c.cssText
|
||||||
|
if validate_color(c):
|
||||||
|
col = c
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if col is None:
|
||||||
|
self._bgcolor = False
|
||||||
|
else:
|
||||||
|
self._bgcolor = col
|
||||||
|
return self._bgcolor if self._bgcolor else None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fontSize(self):
|
def fontSize(self):
|
||||||
def normalize_fontsize(value, base):
|
def normalize_fontsize(value, base):
|
||||||
|
@ -287,6 +287,18 @@ class ChooseLibraryAction(InterfaceAction):
|
|||||||
'rate of approximately 1 book every three seconds.'), show=True)
|
'rate of approximately 1 book every three seconds.'), show=True)
|
||||||
|
|
||||||
def restore_database(self):
|
def restore_database(self):
|
||||||
|
m = self.gui.library_view.model()
|
||||||
|
db = m.db
|
||||||
|
if (iswindows and len(db.library_path) >
|
||||||
|
LibraryDatabase2.WINDOWS_LIBRARY_PATH_LIMIT):
|
||||||
|
return error_dialog(self.gui, _('Too long'),
|
||||||
|
_('Path to library too long. Must be less than'
|
||||||
|
' %d characters. Move your library to a location with'
|
||||||
|
' a shorter path using Windows Explorer, then point'
|
||||||
|
' calibre to the new location and try again.')%
|
||||||
|
LibraryDatabase2.WINDOWS_LIBRARY_PATH_LIMIT,
|
||||||
|
show=True)
|
||||||
|
|
||||||
from calibre.gui2.dialogs.restore_library import restore_database
|
from calibre.gui2.dialogs.restore_library import restore_database
|
||||||
m = self.gui.library_view.model()
|
m = self.gui.library_view.model()
|
||||||
m.stop_metadata_backup()
|
m.stop_metadata_backup()
|
||||||
|
@ -388,6 +388,10 @@ class MetadataSingleDialogBase(ResizableDialog):
|
|||||||
|
|
||||||
def apply_changes(self):
|
def apply_changes(self):
|
||||||
self.changed.add(self.book_id)
|
self.changed.add(self.book_id)
|
||||||
|
if self.db is None:
|
||||||
|
# break_cycles has already been called, don't know why this should
|
||||||
|
# happen but a user reported it
|
||||||
|
return True
|
||||||
for widget in self.basic_metadata_widgets:
|
for widget in self.basic_metadata_widgets:
|
||||||
try:
|
try:
|
||||||
if not widget.commit(self.db, self.book_id):
|
if not widget.commit(self.db, self.book_id):
|
||||||
|
@ -21,8 +21,8 @@ NS = 'http://calibre-ebook.com/recipe_collection'
|
|||||||
E = ElementMaker(namespace=NS, nsmap={None:NS})
|
E = ElementMaker(namespace=NS, nsmap={None:NS})
|
||||||
|
|
||||||
def iterate_over_builtin_recipe_files():
|
def iterate_over_builtin_recipe_files():
|
||||||
exclude = ['craigslist', 'iht', 'outlook_india', 'toronto_sun',
|
exclude = ['craigslist', 'iht', 'toronto_sun',
|
||||||
'indian_express', 'india_today', 'livemint']
|
'india_today', 'livemint']
|
||||||
d = os.path.dirname
|
d = os.path.dirname
|
||||||
base = os.path.join(d(d(d(d(d(d(os.path.abspath(__file__))))))), 'recipes')
|
base = os.path.join(d(d(d(d(d(d(os.path.abspath(__file__))))))), 'recipes')
|
||||||
for f in os.listdir(base):
|
for f in os.listdir(base):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user