mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
EPUB metadata: When setting metadata in an EPUB file, if it has a well defined image based cover, update it
This commit is contained in:
parent
1b3a799d0d
commit
d7d9fa4141
@ -5,7 +5,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
|
|
||||||
'''Read meta information from epub files'''
|
'''Read meta information from epub files'''
|
||||||
|
|
||||||
import os, re
|
import os, re, posixpath
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
|
|
||||||
@ -126,7 +126,6 @@ class OCFDirReader(OCFReader):
|
|||||||
return open(os.path.join(self.root, path), *args, **kwargs)
|
return open(os.path.join(self.root, path), *args, **kwargs)
|
||||||
|
|
||||||
def get_cover(opf, opf_path, stream, reader=None):
|
def get_cover(opf, opf_path, stream, reader=None):
|
||||||
import posixpath
|
|
||||||
from calibre.ebooks import render_html_svg_workaround
|
from calibre.ebooks import render_html_svg_workaround
|
||||||
from calibre.utils.logging import default_log
|
from calibre.utils.logging import default_log
|
||||||
raster_cover = opf.raster_cover
|
raster_cover = opf.raster_cover
|
||||||
@ -185,7 +184,37 @@ def get_quick_metadata(stream):
|
|||||||
def set_metadata(stream, mi, apply_null=False, update_timestamp=False):
|
def set_metadata(stream, mi, apply_null=False, update_timestamp=False):
|
||||||
stream.seek(0)
|
stream.seek(0)
|
||||||
reader = OCFZipReader(stream, root=os.getcwdu())
|
reader = OCFZipReader(stream, root=os.getcwdu())
|
||||||
|
raster_cover = reader.opf.raster_cover
|
||||||
mi = MetaInformation(mi)
|
mi = MetaInformation(mi)
|
||||||
|
new_cdata = None
|
||||||
|
replacements = {}
|
||||||
|
try:
|
||||||
|
new_cdata = mi.cover_data[1]
|
||||||
|
if not new_cdata:
|
||||||
|
raise Exception('no cover')
|
||||||
|
except:
|
||||||
|
try:
|
||||||
|
new_cdata = open(mi.cover, 'rb').read()
|
||||||
|
except:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
if new_cdata and raster_cover:
|
||||||
|
try:
|
||||||
|
cpath = posixpath.join(posixpath.dirname(reader.opf_path),
|
||||||
|
raster_cover)
|
||||||
|
cover_replacable = not reader.encryption_meta.is_encrypted(cpath) and \
|
||||||
|
os.path.splitext(cpath)[1].lower() in ('.png', '.jpg', '.jpeg')
|
||||||
|
if cover_replacable:
|
||||||
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
|
from calibre.utils.magick_draw import save_cover_data_to
|
||||||
|
new_cover = PersistentTemporaryFile(suffix=os.path.splitext(cpath)[1])
|
||||||
|
new_cover.close()
|
||||||
|
save_cover_data_to(new_cdata, new_cover.name)
|
||||||
|
replacements[cpath] = open(new_cover.name, 'rb')
|
||||||
|
except:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
for x in ('guide', 'toc', 'manifest', 'spine'):
|
for x in ('guide', 'toc', 'manifest', 'spine'):
|
||||||
setattr(mi, x, None)
|
setattr(mi, x, None)
|
||||||
reader.opf.smart_update(mi)
|
reader.opf.smart_update(mi)
|
||||||
@ -200,5 +229,6 @@ def set_metadata(stream, mi, apply_null=False, update_timestamp=False):
|
|||||||
reader.opf.timestamp = mi.timestamp
|
reader.opf.timestamp = mi.timestamp
|
||||||
|
|
||||||
newopf = StringIO(reader.opf.render())
|
newopf = StringIO(reader.opf.render())
|
||||||
safe_replace(stream, reader.container[OPF.MIMETYPE], newopf)
|
safe_replace(stream, reader.container[OPF.MIMETYPE], newopf,
|
||||||
|
extra_replacements=replacements)
|
||||||
|
|
||||||
|
@ -183,7 +183,8 @@ class ContentServer(object):
|
|||||||
fmt = TemporaryFile()
|
fmt = TemporaryFile()
|
||||||
fmt.write(raw)
|
fmt.write(raw)
|
||||||
fmt.seek(0)
|
fmt.seek(0)
|
||||||
set_metadata(fmt, self.db.get_metadata(id, index_is_id=True),
|
set_metadata(fmt, self.db.get_metadata(id, index_is_id=True,
|
||||||
|
get_cover=True),
|
||||||
'epub')
|
'epub')
|
||||||
fmt.seek(0)
|
fmt.seek(0)
|
||||||
mt = guess_type('dummy.'+format.lower())[0]
|
mt = guess_type('dummy.'+format.lower())[0]
|
||||||
|
@ -1362,7 +1362,7 @@ class ZipFile:
|
|||||||
self.fp.close()
|
self.fp.close()
|
||||||
self.fp = None
|
self.fp = None
|
||||||
|
|
||||||
def safe_replace(zipstream, name, datastream):
|
def safe_replace(zipstream, name, datastream, extra_replacements={}):
|
||||||
'''
|
'''
|
||||||
Replace a file in a zip file in a safe manner. This proceeds by extracting
|
Replace a file in a zip file in a safe manner. This proceeds by extracting
|
||||||
and re-creating the zipfile. This is necessary because :method:`ZipFile.replace`
|
and re-creating the zipfile. This is necessary because :method:`ZipFile.replace`
|
||||||
@ -1371,13 +1371,19 @@ def safe_replace(zipstream, name, datastream):
|
|||||||
:param zipstream: Stream from a zip file
|
:param zipstream: Stream from a zip file
|
||||||
:param name: The name of the file to replace
|
:param name: The name of the file to replace
|
||||||
:param datastream: The data to replace the file with.
|
:param datastream: The data to replace the file with.
|
||||||
|
:param extra_replacements: Extra replacements. Mapping of name to file-like
|
||||||
|
objects
|
||||||
|
|
||||||
'''
|
'''
|
||||||
z = ZipFile(zipstream, 'r')
|
z = ZipFile(zipstream, 'r')
|
||||||
|
replacements = {name:datastream}
|
||||||
|
replacements.update(extra_replacements)
|
||||||
|
names = frozenset(replacements.keys())
|
||||||
with SpooledTemporaryFile(max_size=100*1024*1024) as temp:
|
with SpooledTemporaryFile(max_size=100*1024*1024) as temp:
|
||||||
ztemp = ZipFile(temp, 'w')
|
ztemp = ZipFile(temp, 'w')
|
||||||
for obj in z.infolist():
|
for obj in z.infolist():
|
||||||
if obj.filename == name:
|
if obj.filename in names:
|
||||||
ztemp.writestr(obj, datastream.read())
|
ztemp.writestr(obj, replacements[obj.filename].read())
|
||||||
else:
|
else:
|
||||||
ztemp.writestr(obj, z.read_raw(obj), raw_bytes=True)
|
ztemp.writestr(obj, z.read_raw(obj), raw_bytes=True)
|
||||||
ztemp.close()
|
ztemp.close()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user