diff --git a/src/calibre/ebooks/metadata/opf.py b/src/calibre/ebooks/metadata/opf.py
index dcec6c06d4..ce93c09531 100644
--- a/src/calibre/ebooks/metadata/opf.py
+++ b/src/calibre/ebooks/metadata/opf.py
@@ -5,7 +5,10 @@
from __future__ import (unicode_literals, division, absolute_import,
print_function)
+from lxml import etree
+
from calibre.ebooks.metadata.opf2 import OPF, pretty_print
+from calibre.ebooks.metadata.opf3 import apply_metadata
from calibre.ebooks.metadata.utils import parse_opf, normalize_languages, create_manifest_item, parse_opf_version
from calibre.ebooks.metadata import MetaInformation
@@ -72,6 +75,14 @@ def set_metadata_opf2(root, cover_prefix, mi, opf_version,
with pretty_print:
return opf.render(), raster_cover
+def set_metadata_opf3(root, cover_prefix, mi, opf_version,
+ cover_data=None, apply_null=False, update_timestamp=False, force_identifiers=False, add_missing_cover=True):
+ raster_cover = apply_metadata(
+ root, mi, cover_prefix=cover_prefix, cover_data=cover_data,
+ apply_null=apply_null, update_timestamp=update_timestamp,
+ force_identifiers=force_identifiers, add_missing_cover=add_missing_cover)
+ return etree.tostring(root, encoding='utf-8'), raster_cover
+
def set_metadata(stream, mi, cover_prefix='', cover_data=None, apply_null=False, update_timestamp=False, force_identifiers=False, add_missing_cover=True):
if isinstance(stream, bytes):
stream = DummyFile(stream)
diff --git a/src/calibre/ebooks/metadata/opf3.py b/src/calibre/ebooks/metadata/opf3.py
index bc0721eaa0..9e944f0efa 100644
--- a/src/calibre/ebooks/metadata/opf3.py
+++ b/src/calibre/ebooks/metadata/opf3.py
@@ -15,7 +15,7 @@ from calibre import prints
from calibre.ebooks.metadata import check_isbn, authors_to_string, string_to_authors
from calibre.ebooks.metadata.book.base import Metadata
from calibre.ebooks.metadata.book.json_codec import object_to_unicode, decode_is_multiple, encode_is_multiple
-from calibre.ebooks.metadata.utils import parse_opf, pretty_print_opf, ensure_unique, normalize_languages
+from calibre.ebooks.metadata.utils import parse_opf, pretty_print_opf, ensure_unique, normalize_languages, create_manifest_item
from calibre.ebooks.oeb.base import OPF2_NSMAP, OPF, DC
from calibre.utils.config import from_json, to_json
from calibre.utils.date import parse_date as parse_date_, fix_only_date, is_date_undefined, isoformat
@@ -785,6 +785,44 @@ def set_user_metadata(root, prefixes, refines, val):
# }}}
+# Covers {{{
+
+def read_raster_cover(root, prefixes, refines):
+
+ 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, prefixes, refines, raster_cover_item_href):
+ 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'))
+
+# }}}
+
# Reading/setting Metadata objects {{{
def read_metadata(root):
@@ -837,7 +875,7 @@ def get_metadata(stream):
root = parse_opf(stream)
return read_metadata(root)
-def apply_metadata(root, mi, cover_prefix='', cover_data=None, apply_null=False, update_timestamp=False, force_identifiers=False):
+def apply_metadata(root, mi, cover_prefix='', cover_data=None, apply_null=False, update_timestamp=False, force_identifiers=False, add_missing_cover=True):
prefixes, refines = read_prefixes(root), read_refines(root)
current_mi = read_metadata(root)
if apply_null:
@@ -907,8 +945,18 @@ def apply_metadata(root, mi, cover_prefix='', cover_data=None, apply_null=False,
current_user_metadata[key] = meta
set_user_metadata(root, prefixes, refines, current_user_metadata)
+ raster_cover = read_raster_cover(root, prefixes, refines)
+ if not raster_cover and cover_data and add_missing_cover:
+ if cover_prefix and not cover_prefix.endswith('/'):
+ cover_prefix += '/'
+ name = cover_prefix + 'cover.jpg'
+ i = create_manifest_item(root, name, 'cover')
+ if i is not None:
+ ensure_is_only_raster_cover(root, prefixes, refines, name)
+ raster_cover = name
pretty_print_opf(root)
+ return raster_cover
def set_metadata(stream, mi, cover_prefix='', cover_data=None, apply_null=False, update_timestamp=False, force_identifiers=False, add_missing_cover=True):
root = parse_opf(stream)
@@ -918,44 +966,6 @@ def set_metadata(stream, mi, cover_prefix='', cover_data=None, apply_null=False,
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 b6bc3d9688..947a4b8847 100644
--- a/src/calibre/ebooks/metadata/opf3_test.py
+++ b/src/calibre/ebooks/metadata/opf3_test.py
@@ -22,7 +22,7 @@ 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, raster_cover, ensure_is_only_raster_cover
+ apply_metadata, read_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
@@ -207,13 +207,13 @@ class TestOPF3(unittest.TestCase):
def test_raster_cover(self): # {{{
def rt(root):
- return raster_cover(root)
+ return read_raster_cover(root, read_prefixes(root), read_refines(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')
+ ensure_is_only_raster_cover(root, read_prefixes(root), read_refines(root), 'x.jpg')
self.ae('x.jpg', rt(root))
self.ae(['x.jpg'], root.xpath('//*[@properties="cover-image"]/@href'))
self.assertFalse(root.xpath('//*[@name]'))
@@ -486,7 +486,7 @@ class TestOPF3(unittest.TestCase):
"label": "date", "table":
"custom_column_2", "is_multiple": null,
"is_category": false}"/>
-
+
''' # }}}
def compare_metadata(mi2, mi3):
@@ -520,6 +520,8 @@ class TestOPF3(unittest.TestCase):
self.assertFalse(nmi.tags)
self.assertFalse(nmi.get('#tags'))
self.assertFalse(nmi.get('#commetns'))
+ self.assertIsNone(apply_metadata(root, mi3, cover_data=b'x', cover_prefix='xxx', add_missing_cover=False))
+ self.ae('xxx/cover.jpg', apply_metadata(root, mi3, cover_data=b'x', cover_prefix='xxx'))
# }}}
# Run tests {{{