Fix #1002708 (FB2 metadata save: cover image update)

This commit is contained in:
Kovid Goyal 2012-05-22 14:49:00 +05:30
commit 277783be65

View File

@ -5,11 +5,15 @@ __copyright__ = '2011, Roman Mukhin <ramses_ru at hotmail.com>, '\
'2008, Anatoly Shipitsin <norguhtar at gmail.com>' '2008, Anatoly Shipitsin <norguhtar at gmail.com>'
'''Read meta information from fb2 files''' '''Read meta information from fb2 files'''
import os import os, random, datetime
import datetime
from functools import partial from functools import partial
from string import ascii_letters, digits
from base64 import b64encode
from lxml import etree from lxml import etree
from calibre.utils.date import parse_date from calibre.utils.date import parse_date
from calibre.utils.magick.draw import save_cover_data_to
from calibre import guess_type, guess_all_extensions, prints, force_unicode from calibre import guess_type, guess_all_extensions, prints, force_unicode
from calibre.ebooks.metadata import MetaInformation, check_isbn from calibre.ebooks.metadata import MetaInformation, check_isbn
from calibre.ebooks.chardet import xml_to_unicode from calibre.ebooks.chardet import xml_to_unicode
@ -25,6 +29,9 @@ tostring = partial(etree.tostring, method='text', encoding=unicode)
def FB2(tag): def FB2(tag):
return '{%s}%s'%(NAMESPACES['fb2'], tag) return '{%s}%s'%(NAMESPACES['fb2'], tag)
def XLINK(tag):
return '{%s}%s'%(NAMESPACES['xlink'], tag)
def get_metadata(stream): def get_metadata(stream):
''' Return fb2 metadata as a L{MetaInformation} object ''' ''' Return fb2 metadata as a L{MetaInformation} object '''
@ -308,20 +315,48 @@ def _set_series(title_info, mi):
except: except:
seq.set('number', '1') seq.set('number', '1')
def _create_tag(parent, tag, at_start=True): def _rnd_name(size=8, chars=ascii_letters + digits):
return ''.join(random.choice(chars) for x in range(size))
def _rnd_pic_file_name(prefix='calibre_cover_', size=32, ext='jpg'):
return prefix + _rnd_name(size=size) + '.' + ext
def _encode_into_jpeg(data):
data = save_cover_data_to(data, 'cover.jpg', return_data=True)
return b64encode(data)
def _set_cover(title_info, mi):
if not mi.is_null('cover_data') and mi.cover_data[1]:
coverpage = _get_or_create(title_info, 'coverpage')
cim_tag = _get_or_create(coverpage, 'image')
if cim_tag.attrib.has_key(XLINK('href')):
cim_filename = cim_tag.attrib[XLINK('href')][1:]
else:
cim_filename = _rnd_pic_file_name('cover')
cim_tag.attrib[XLINK('href')] = '#' + cim_filename
fb2_root = cim_tag.getroottree().getroot()
cim_binary = _get_or_create(fb2_root, 'binary', attribs={'id': cim_filename}, at_start=False)
cim_binary.attrib['content-type'] = 'image/jpeg'
cim_binary.text = _encode_into_jpeg(mi.cover_data[1])
def _create_tag(parent, tag, attribs={}, at_start=True):
ans = parent.makeelement(FB2(tag)) ans = parent.makeelement(FB2(tag))
ans.attrib.update(attribs)
if at_start: if at_start:
parent.insert(0, ans) parent.insert(0, ans)
else: else:
parent.append(ans) parent.append(ans)
return ans return ans
def _get_or_create(parent, tag, at_start=True): def _get_or_create(parent, tag, attribs={}, at_start=True):
ans = XPath('./fb2:'+tag)(parent) xpathstr='./fb2:'+tag
for n, v in attribs.items():
xpathstr += '[@%s="%s"]' % (n, v)
ans = XPath(xpathstr)(parent)
if ans: if ans:
ans = ans[0] ans = ans[0]
else: else:
ans = _create_tag(parent, tag, at_start) ans = _create_tag(parent, tag, attribs, at_start)
return ans return ans
def set_metadata(stream, mi, apply_null=False, update_timestamp=False): def set_metadata(stream, mi, apply_null=False, update_timestamp=False):
@ -337,6 +372,7 @@ def set_metadata(stream, mi, apply_null=False, update_timestamp=False):
_set_tags(ti, mi) _set_tags(ti, mi)
_set_authors(ti, mi) _set_authors(ti, mi)
_set_title(ti, mi) _set_title(ti, mi)
_set_cover(ti, mi)
for child in ti: for child in ti:
child.tail = indent child.tail = indent