mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
EPUB metadata: When setting a cover image for an EPUB file that has no cover image defined, add the new cover image instead of aborting.
Note that this is not a full EPUB cover, for that you still have to convert/use book polishing. However, this limited support should at least allow the cover image to work with those applications that support the EPUB raster cover metadata standard.
This commit is contained in:
parent
46f9c7c780
commit
78be5af05a
@ -276,7 +276,7 @@ def set_metadata(stream, mi, apply_null=False, update_timestamp=False, force_ide
|
||||
pass
|
||||
|
||||
opfbytes, ver, raster_cover = set_metadata_opf(
|
||||
reader.read_bytes(reader.opf_path), mi,
|
||||
reader.read_bytes(reader.opf_path), posixpath.dirname(reader.opf_path), mi,
|
||||
cover_data=new_cdata, apply_null=apply_null, update_timestamp=update_timestamp, force_identifiers=force_identifiers)
|
||||
cpath = None
|
||||
replacements = {}
|
||||
@ -294,10 +294,10 @@ def set_metadata(stream, mi, apply_null=False, update_timestamp=False, force_ide
|
||||
|
||||
if isinstance(reader.archive, LocalZipFile):
|
||||
reader.archive.safe_replace(reader.container[OPF.MIMETYPE], opfbytes,
|
||||
extra_replacements=replacements)
|
||||
extra_replacements=replacements, add_missing=True)
|
||||
else:
|
||||
safe_replace(stream, reader.container[OPF.MIMETYPE], opfbytes,
|
||||
extra_replacements=replacements)
|
||||
extra_replacements=replacements, add_missing=True)
|
||||
try:
|
||||
if cpath is not None:
|
||||
replacements[cpath].close()
|
||||
|
@ -6,8 +6,8 @@ from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
from calibre.ebooks.metadata import parse_opf_version
|
||||
from calibre.ebooks.metadata.opf2 import OPF
|
||||
from calibre.ebooks.metadata.utils import parse_opf, normalize_languages
|
||||
from calibre.ebooks.metadata.opf2 import OPF, pretty_print
|
||||
from calibre.ebooks.metadata.utils import parse_opf, normalize_languages, create_manifest_item
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
|
||||
class DummyFile(object):
|
||||
@ -26,7 +26,7 @@ def get_metadata(stream):
|
||||
opf = OPF(None, preparsed_opf=root, read_toc=False)
|
||||
return opf.to_book_metadata(), ver, opf.raster_cover, opf.first_spine_item()
|
||||
|
||||
def set_metadata_opf2(root, mi, cover_data=None, apply_null=False, update_timestamp=False, force_identifiers=False):
|
||||
def set_metadata_opf2(root, cover_prefix, mi, opf_version, cover_data=None, apply_null=False, update_timestamp=False, force_identifiers=False):
|
||||
mi = MetaInformation(mi)
|
||||
for x in ('guide', 'toc', 'manifest', 'spine'):
|
||||
setattr(mi, x, None)
|
||||
@ -45,13 +45,29 @@ def set_metadata_opf2(root, mi, cover_data=None, apply_null=False, update_timest
|
||||
opf.set_identifiers({k:v for k, v in orig.iteritems() if k and v})
|
||||
if update_timestamp and mi.timestamp is not None:
|
||||
opf.timestamp = mi.timestamp
|
||||
return opf.render(), opf.raster_cover
|
||||
raster_cover = opf.raster_cover
|
||||
if raster_cover is None and cover_data is not None:
|
||||
if cover_prefix and not cover_prefix.endswith('/'):
|
||||
cover_prefix += '/'
|
||||
name = cover_prefix + 'cover.jpg'
|
||||
i = create_manifest_item(opf.root, name, 'cover')
|
||||
if i is not None:
|
||||
if opf_version.major < 3:
|
||||
[x.getparent().remove(x) for x in opf.root.xpath('//*[local-name()="meta" and @name="cover"]')]
|
||||
m = opf.create_metadata_element('meta', is_dc=False)
|
||||
m.set('name', 'cover'), m.set('content', i.get('id'))
|
||||
else:
|
||||
i.set('properties', 'cover-image')
|
||||
raster_cover = name
|
||||
|
||||
def set_metadata(stream, mi, cover_data=None, apply_null=False, update_timestamp=False, force_identifiers=False):
|
||||
with pretty_print:
|
||||
return opf.render(), raster_cover
|
||||
|
||||
def set_metadata(stream, cover_prefix, mi, cover_data=None, apply_null=False, update_timestamp=False, force_identifiers=False):
|
||||
if isinstance(stream, bytes):
|
||||
stream = DummyFile(stream)
|
||||
root = parse_opf(stream)
|
||||
ver = parse_opf_version(root.get('version'))
|
||||
opfbytes, raster_cover = set_metadata_opf2(
|
||||
root, mi, cover_data=cover_data, apply_null=apply_null, update_timestamp=update_timestamp, force_identifiers=force_identifiers)
|
||||
root, cover_prefix, mi, ver, cover_data=cover_data, apply_null=apply_null, update_timestamp=update_timestamp, force_identifiers=force_identifiers)
|
||||
return opfbytes, ver, raster_cover
|
||||
|
@ -1172,7 +1172,8 @@ class OPF(object): # {{{
|
||||
return item.get('href', None)
|
||||
elif self.package_version >= 3.0:
|
||||
for item in self.itermanifest():
|
||||
if item.get('properties') == 'cover-image':
|
||||
props = set((item.get('properties') or '').lower().split())
|
||||
if 'cover-image' in props:
|
||||
mt = item.get('media-type', '')
|
||||
if mt and 'xml' not in mt and 'html' not in mt:
|
||||
return item.get('href', None)
|
||||
|
@ -9,6 +9,8 @@ from future_builtins import map
|
||||
from lxml import etree
|
||||
|
||||
from calibre.ebooks.chardet import xml_to_unicode
|
||||
from calibre.ebooks.oeb.base import OPF
|
||||
from calibre.ebooks.oeb.polish.utils import guess_type
|
||||
from calibre.spell import parse_lang_code
|
||||
from calibre.utils.localization import lang_as_iso639_1
|
||||
|
||||
@ -48,3 +50,26 @@ def normalize_languages(opf_languages, mi_languages):
|
||||
return lc
|
||||
return list(map(norm, mi_languages))
|
||||
|
||||
def ensure_unique(template, existing):
|
||||
b, e = template.rpartition('.')[::2]
|
||||
if e:
|
||||
e = '.' + e
|
||||
q = template
|
||||
c = 0
|
||||
while q in existing:
|
||||
c += 1
|
||||
q = '%s-%d%s' % (b, c, e)
|
||||
return q
|
||||
|
||||
def create_manifest_item(root, href_template, id_template, media_type=None):
|
||||
all_ids = frozenset(root.xpath('//*/@id'))
|
||||
all_hrefs = frozenset(root.xpath('//*/@href'))
|
||||
href = ensure_unique(href_template, all_hrefs)
|
||||
item_id = ensure_unique(id_template, all_ids)
|
||||
manifest = root.find(OPF('manifest'))
|
||||
if manifest is not None:
|
||||
i = manifest.makeelement(OPF('item'))
|
||||
i.set('href', href), i.set('id', item_id)
|
||||
i.set('media-type', media_type or guess_type(href_template))
|
||||
manifest.append(i)
|
||||
return i
|
||||
|
Loading…
x
Reference in New Issue
Block a user