diff --git a/src/calibre/ebooks/html.py b/src/calibre/ebooks/html.py index 4fe46ef262..9457e6a5df 100644 --- a/src/calibre/ebooks/html.py +++ b/src/calibre/ebooks/html.py @@ -313,11 +313,11 @@ def opf_traverse(opf_reader, verbose=0, encoding=None): return ans - +convert_entities = functools.partial(entity_to_unicode, exceptions=['quot', 'apos', 'lt', 'gt', 'amp']) class PreProcessor(object): PREPROCESS = [ # Convert all entities, since lxml doesn't handle them well - (re.compile(r'&(\S+?);'), entity_to_unicode), + (re.compile(r'&(\S+?);'), convert_entities), ] # Fix pdftohtml markup @@ -379,7 +379,6 @@ class PreProcessor(object): rules = [] for rule in self.PREPROCESS + rules: html = rule[0].sub(rule[1], html) - return html class Parser(PreProcessor, LoggingInterface): @@ -801,14 +800,14 @@ class Processor(Parser): for rule in sheet: self.stylesheet.add(rule) css = '' - if self.opts.override_css: - css += '\n\n' + self.opts.override_css css += '\n\n' + 'body {margin-top: 0pt; margin-bottom: 0pt; margin-left: 0pt; margin-right: 0pt;}' css += '\n\n@page {margin-top: %fpt; margin-bottom: %fpt; margin-left: %fpt; margin-right: %fpt}'%(self.opts.margin_top, self.opts.margin_bottom, self.opts.margin_left, self.opts.margin_right) # Workaround for anchor rendering bug in ADE css += '\n\na { color: inherit; text-decoration: inherit; cursor: default; }\na[href] { color: blue; text-decoration: underline; cursor:pointer; }' if self.opts.remove_paragraph_spacing: css += '\n\np {text-indent: 2em; margin-top:1pt; margin-bottom:1pt; padding:0pt; border:0pt;}' + if self.opts.override_css: + css += '\n\n' + self.opts.override_css self.override_css = self.css_parser.parseString(self.preprocess_css(css)) for rule in reversed(self.specified_override_css): self.override_css.insertRule(rule, index=0) diff --git a/src/calibre/ebooks/metadata/opf2.py b/src/calibre/ebooks/metadata/opf2.py index 64b0e88dcb..57a455de25 100644 --- a/src/calibre/ebooks/metadata/opf2.py +++ b/src/calibre/ebooks/metadata/opf2.py @@ -330,7 +330,7 @@ class Guide(ResourceCollection): @staticmethod def from_opf_resource_item(ref, basedir): title, href, type = ref.get('title', ''), ref.get('href'), ref.get('type') - res = Guide.Reference(href, basedir, is_path=False) + res = Guide.Reference(href, basedir, is_path=True) res.title = title res.type = type return res @@ -866,7 +866,7 @@ class OPFCreator(MetaInformation): self.manifest.append(ManifestItem(ncx_manifest_entry, self.base_path)) self.manifest[-1].id = 'ncx' self.manifest[-1].mime_type = 'application/x-dtbncx+xml' - if not self.guide: + if self.guide is None: self.guide = Guide() if self.cover: cover = self.cover @@ -886,7 +886,6 @@ class OPFCreator(MetaInformation): class OPFTest(unittest.TestCase): def setUp(self): - import cStringIO self.stream = cStringIO.StringIO( '''\ diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index 888996d8d2..aa24ec34d9 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -771,7 +771,7 @@ class Main(MainWindow, Ui_MainWindow): d.exec_() return - dir = choose_dir(self, 'save to disk dialog', ('Choose destination directory')) + dir = choose_dir(self, 'save to disk dialog', _('Choose destination directory')) if not dir: return if self.current_view() == self.library_view: diff --git a/src/calibre/library/cli.py b/src/calibre/library/cli.py index 1aae748593..a509e31d60 100644 --- a/src/calibre/library/cli.py +++ b/src/calibre/library/cli.py @@ -22,7 +22,7 @@ from calibre.library.database2 import LibraryDatabase2 from calibre.ebooks.metadata.opf import OPFCreator, OPFReader from calibre.utils.genshi.template import MarkupTemplate -FIELDS = set(['title', 'authors', 'publisher', 'rating', 'timestamp', 'size', 'tags', 'comments', 'series', 'series_index', 'formats', 'isbn', 'cover']) +FIELDS = set(['title', 'authors', 'author_sort', 'publisher', 'rating', 'timestamp', 'size', 'tags', 'comments', 'series', 'series_index', 'formats', 'isbn', 'cover']) XML_TEMPLATE = '''\ @@ -31,7 +31,7 @@ XML_TEMPLATE = '''\ ${record['id']} ${record['title']} - + $author diff --git a/src/calibre/library/database.py b/src/calibre/library/database.py index 1d15c9f838..eeb6bf2180 100644 --- a/src/calibre/library/database.py +++ b/src/calibre/library/database.py @@ -9,7 +9,7 @@ from zlib import compress, decompress from calibre import sanitize_file_name from calibre.ebooks.metadata.meta import set_metadata, metadata_from_formats -from calibre.ebooks.metadata.opf import OPFCreator +from calibre.ebooks.metadata.opf2 import OPFCreator from calibre.ebooks.metadata import MetaInformation from calibre.ebooks import BOOK_EXTENSIONS from calibre.web.feeds.recipes import migrate_automatic_profile_to_automatic_recipe @@ -1283,6 +1283,9 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE; self.set_series(id, mi.series) if mi.cover_data[1] is not None: self.set_cover(id, mi.cover_data[1]) + + + def add_books(self, paths, formats, metadata, uris=[], add_duplicates=True): ''' @@ -1399,7 +1402,7 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE; if not au: au = self.authors(index, index_is_id=index_is_id) if not au: - au = 'Unknown' + au = _('Unknown') au = au.split(',')[0] else: au = au.replace(',', ';') @@ -1421,7 +1424,7 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE; name = au + ' - ' + title if byauthor else title + ' - ' + au name += '_'+id base = dir if single_dir else tpath - mi = OPFCreator(base, self.get_metadata(idx, index_is_id=index_is_id)) + mi = self.get_metadata(idx, index_is_id=index_is_id) cover = self.cover(idx, index_is_id=index_is_id) if cover is not None: cname = sanitize_file_name(name) + '.jpg' @@ -1431,7 +1434,8 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE; f = open(os.path.join(base, sanitize_file_name(name)+'.opf'), 'wb') if not mi.authors: mi.authors = [_('Unknown')] - mi.render(f) + opf = OPFCreator(base, mi) + opf.render(f) f.close() fmts = self.formats(idx, index_is_id=index_is_id) @@ -1458,7 +1462,7 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE; def import_book(self, mi, formats): series_index = 1 if mi.series_index is None else mi.series_index if not mi.authors: - mi.authors = ['Unknown'] + mi.authors = [_('Unknown')] aus = mi.author_sort if mi.author_sort else ', '.join(mi.authors) obj = self.conn.execute('INSERT INTO books(title, uri, series_index, author_sort) VALUES (?, ?, ?, ?)', (mi.title, None, series_index, aus)) @@ -1554,6 +1558,7 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE; return duplicates def export_single_format_to_dir(self, dir, indices, format, index_is_id=False): + dir = os.path.abspath(dir) if not index_is_id: indices = map(self.id, indices) failures = [] @@ -1572,6 +1577,8 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE; au = _('Unknown') fname = '%s - %s.%s'%(title, au, format.lower()) fname = sanitize_file_name(fname) + if not os.path.exists(dir): + os.makedirs(dir) f = open(os.path.join(dir, fname), 'w+b') f.write(data) f.seek(0) diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 87f37416af..cb0c638503 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -284,7 +284,7 @@ class ResultCache(SearchQueryParser): field += 's' if field == 'date': field = 'timestamp' elif field == 'title': field = 'sort' - elif field == 'author': field = 'author_sort' + elif field == 'authors': field = 'author_sort' fcmp = self.seriescmp if field == 'series' else \ functools.partial(self.cmp, FIELD_MAP[field], str=field not in ('size', 'rating', 'timestamp')) @@ -792,6 +792,8 @@ class LibraryDatabase2(LibraryDatabase): self.set_series(id, mi.series, notify=False) if mi.cover_data[1] is not None: self.set_cover(id, mi.cover_data[1]) + elif mi.cover is not None and os.access(mi.cover,os.R_OK): + self.set_cover(id, open(mi.cover, 'rb').read()) if mi.tags: self.set_tags(id, mi.tags, notify=False) if mi.comments: @@ -1105,7 +1107,7 @@ class LibraryDatabase2(LibraryDatabase): ''' if prefix is None: prefix = self.library_path - FIELDS = set(['title', 'authors', 'publisher', 'rating', 'timestamp', 'size', 'tags', 'comments', 'series', 'series_index', 'isbn']) + FIELDS = set(['title', 'authors', 'author_sort', 'publisher', 'rating', 'timestamp', 'size', 'tags', 'comments', 'series', 'series_index', 'isbn']) data = [] for record in self.data: if record is None: continue