diff --git a/src/calibre/ebooks/metadata/opf3.py b/src/calibre/ebooks/metadata/opf3.py index fa805a8de4..bc0721eaa0 100644 --- a/src/calibre/ebooks/metadata/opf3.py +++ b/src/calibre/ebooks/metadata/opf3.py @@ -115,6 +115,9 @@ def simple_text(f): def wrapper(*args, **kw): return normalize_whitespace(f(*args, **kw)) return wrapper + +def items_with_property(root, q): + return XPath("./opf:manifest/opf:item[@properties and contains(concat(' ', normalize-space(@properties), ' '), ' %s ')]" % q)(root) # }}} # Prefixes {{{ @@ -782,6 +785,8 @@ def set_user_metadata(root, prefixes, refines, val): # }}} +# Reading/setting Metadata objects {{{ + def read_metadata(root): ans = Metadata(_('Unknown'), [_('Unknown')]) prefixes, refines = read_prefixes(root), read_refines(root) @@ -911,6 +916,46 @@ def set_metadata(stream, mi, cover_prefix='', cover_data=None, apply_null=False, root, mi, cover_prefix=cover_prefix, cover_data=cover_data, apply_null=apply_null, update_timestamp=update_timestamp, force_identifiers=force_identifiers) +# }}} + +# Covers {{{ + +def raster_cover(root): + + def get_href(item): + mt = item.get('media-type') + if mt and 'xml' not in mt and 'html' not in mt: + href = item.get('href') + if href: + return href + + for item in items_with_property(root, 'cover-image'): + href = get_href(item) + if href: + return href + + for item_id in XPath('./opf:metadata/opf:meta[@name="cover"]/@content')(root): + for item in XPath('./opf:manifest/opf:item[@id and @href and @media-type]')(root): + if item.get('id') == item_id: + href = get_href(item) + if href: + return href + +def ensure_is_only_raster_cover(root, raster_cover_item_href): + refines = read_refines(root) + for item in XPath('./opf:metadata/opf:meta[@name="cover"]')(root): + remove_element(item, refines) + for item in items_with_property(root, 'cover-image'): + prop = normalize_whitespace(item.get('properties').replace('cover-image', '')) + if prop: + item.set('properties', prop) + else: + del item.attrib['properties'] + for item in XPath('./opf:manifest/opf:item')(root): + if item.get('href') == raster_cover_item_href: + item.set('properties', normalize_whitespace((item.get('properties') or '') + ' cover-image')) + +# }}} if __name__ == '__main__': import sys diff --git a/src/calibre/ebooks/metadata/opf3_test.py b/src/calibre/ebooks/metadata/opf3_test.py index 5cd6cd8116..b6bc3d9688 100644 --- a/src/calibre/ebooks/metadata/opf3_test.py +++ b/src/calibre/ebooks/metadata/opf3_test.py @@ -22,22 +22,22 @@ from calibre.ebooks.metadata.opf3 import ( set_comments, read_publisher, set_publisher, read_tags, set_tags, read_rating, set_rating, read_series, set_series, read_user_metadata, set_user_metadata, read_author_link_map, read_user_categories, set_author_link_map, set_user_categories, - apply_metadata + apply_metadata, raster_cover, ensure_is_only_raster_cover ) # This import is needed to prevent a test from running slowly from calibre.ebooks.oeb.polish.pretty import pretty_opf, pretty_xml_tree # noqa read_author_link_map, read_user_categories, set_author_link_map, set_user_categories -TEMPLATE = '''{metadata}''' % CALIBRE_PREFIX # noqa +TEMPLATE = '''{metadata}{manifest}''' % CALIBRE_PREFIX # noqa default_refines = defaultdict(list) class TestOPF3(unittest.TestCase): ae = unittest.TestCase.assertEqual - def get_opf(self, metadata=''): - return etree.fromstring(TEMPLATE.format(metadata=metadata)) + def get_opf(self, metadata='', manifest=''): + return etree.fromstring(TEMPLATE.format(metadata=metadata, manifest=manifest)) def test_prefix_parsing(self): # {{{ self.ae(parse_prefixes('foaf: http://xmlns.com/foaf/spec/\n dbp: http://dbpedia.org/ontology/'), @@ -205,6 +205,20 @@ class TestOPF3(unittest.TestCase): self.ae('p', st(root, 'p ')) # }}} + def test_raster_cover(self): # {{{ + def rt(root): + return raster_cover(root) + root = self.get_opf('', '') + self.ae('x.jpg', rt(root)) + root = self.get_opf('', + '') + self.ae('y.jpg', rt(root)) + ensure_is_only_raster_cover(root, 'x.jpg') + self.ae('x.jpg', rt(root)) + self.ae(['x.jpg'], root.xpath('//*[@properties="cover-image"]/@href')) + self.assertFalse(root.xpath('//*[@name]')) + # }}} + def test_tags(self): # {{{ def rt(root): return read_tags(root, read_prefixes(root), read_refines(root))