AZW3: Preserve the primary-writing-mopde EXTH header field when round-tripping AZW3 files. Should fix editing/conversion of RTL AZW3 files causing page turning to become left-to-right on the Kindle

This commit is contained in:
Kovid Goyal 2017-04-24 17:48:10 +05:30
parent da8958b573
commit 5f313b64af
7 changed files with 39 additions and 7 deletions

View File

@ -1163,6 +1163,11 @@ class OPF(object): # {{{
if k == 'page-progression-direction' or k.endswith('}page-progression-direction'):
return v
@property
def primary_writing_mode(self):
for m in self.XPath('//*[local-name()="meta" and @name="primary-writing-mode" and @content]')(self.root):
return m.get('content')
def guess_cover(self):
'''
Try to guess a cover. Needed for some old/badly formed OPF files.
@ -1384,6 +1389,7 @@ class OPFCreator(Metadata):
Metadata.__init__(self, title='', other=other)
self.base_path = os.path.abspath(base_path)
self.page_progression_direction = None
self.primary_writing_mode = None
if self.application_id is None:
self.application_id = str(uuid.uuid4())
if not isinstance(self.toc, TOC):
@ -1546,6 +1552,8 @@ class OPFCreator(Metadata):
from calibre.ebooks.metadata.book.json_codec import object_to_unicode
a(CAL_ELEM('calibre:user_categories',
json.dumps(object_to_unicode(self.user_categories))))
if self.primary_writing_mode:
a(M.meta(name='primary-writing-mode', content=self.primary_writing_mode))
manifest = E.manifest()
if self.manifest is not None:
for ref in self.manifest:

View File

@ -34,6 +34,7 @@ class EXTHHeader(object): # {{{
self.kf8_header = None
self.uuid = self.cdetype = None
self.page_progression_direction = None
self.primary_writing_mode = None
self.decode = lambda x : clean_ascii_chars(x.decode(codec, 'replace'))
@ -83,6 +84,13 @@ class EXTHHeader(object): # {{{
self.mi.language = lang
except:
pass
elif idx == 525:
try:
pwm = content.decode(codec)
if pwm:
self.primary_writing_mode = pwm
except Exception:
pass
elif idx == 527:
try:
ppd = content.decode(codec)
@ -336,4 +344,3 @@ class MetadataHeader(BookHeader):
except OverflowError:
self.stream.seek(start)
return self.stream.read()

View File

@ -512,6 +512,9 @@ class Mobi8Reader(object):
ppd = getattr(self.header.exth, 'page_progression_direction', None)
if ppd in {'ltr', 'rtl', 'default'}:
opf.page_progression_direction = ppd
pwm = getattr(self.header.exth, 'primary_writing_mode', None)
if pwm is not None:
opf.primary_writing_mode = pwm
with open('metadata.opf', 'wb') as of, open('toc.ncx', 'wb') as ncx:
opf.render(of, ncx, 'toc.ncx')

View File

@ -40,6 +40,7 @@ EXTH_CODES = {
'lastupdatetime': 502,
'title': 503,
'language': 524,
'primary_writing_mode': 525,
'page_progression_direction': 527,
}
@ -50,7 +51,7 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
share_not_sync=True, cover_offset=None, thumbnail_offset=None,
start_offset=None, mobi_doctype=2, num_of_resources=None,
kf8_unknown_count=0, be_kindlegen2=False, kf8_header_index=None,
page_progression_direction=None):
page_progression_direction=None, primary_writing_mode=None):
exth = BytesIO()
nrecs = 0
@ -208,6 +209,12 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
kf8_unknown_count))
nrecs += 1
if primary_writing_mode:
pwm = primary_writing_mode.encode('utf-8')
exth.write(pack(b'>II', EXTH_CODES['primary_writing_mode'], len(pwm) + 8))
exth.write(pwm)
nrecs += 1
if page_progression_direction in {'rtl', 'ltr', 'default'}:
ppd = bytes(page_progression_direction)
exth.write(pack(b'>II', EXTH_CODES['page_progression_direction'], len(ppd) + 8))
@ -219,5 +226,3 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
pad = b'\0' * (4 - trail) # Always pad w/ at least 1 byte
exth = [b'EXTH', pack(b'>II', len(exth) + 12, nrecs), exth, pad]
return b''.join(exth)

View File

@ -209,6 +209,7 @@ class MOBIHeader(Header): # {{{
# }}}
HEADER_FIELDS = {'compression', 'text_length', 'last_text_record', 'book_type',
'first_non_text_record', 'title_length', 'language_code',
'first_resource_record', 'exth_flags', 'fdst_record',
@ -223,6 +224,7 @@ class KF8Book(object):
self.build_records(writer, for_joint)
self.used_images = writer.used_images
self.page_progression_direction = writer.oeb.spine.page_progression_direction
self.primary_writing_mode = writer.oeb.metadata.primary_writing_mode
def build_records(self, writer, for_joint):
metadata = writer.oeb.metadata
@ -311,7 +313,8 @@ class KF8Book(object):
num_of_resources=self.num_of_resources,
kf8_unknown_count=self.kuc, be_kindlegen2=True,
start_offset=self.start_offset, mobi_doctype=self.book_type,
page_progression_direction=self.page_progression_direction
page_progression_direction=self.page_progression_direction,
primary_writing_mode=self.primary_writing_mode
)
kwargs = {field:getattr(self, field) for field in HEADER_FIELDS}
@ -342,4 +345,3 @@ class KF8Book(object):
for rec in records:
f.write(rec)

View File

@ -782,6 +782,7 @@ class Metadata(object):
def __init__(self, oeb):
self.oeb = oeb
self.items = defaultdict(list)
self.primary_writing_mode = None
def add(self, term, value, attrib={}, nsmap={}, **kwargs):
"""Add a new metadata item."""
@ -864,6 +865,8 @@ class Metadata(object):
for term in self.items:
for item in self.items[term]:
item.to_opf2(elem, nsrmap=nsrmap)
if self.primary_writing_mode:
elem.append(elem.makeelement(OPF('meta'), attrib={'name':'primary-writing-mode', 'content':self.primary_writing_mode}))
return elem

View File

@ -137,7 +137,11 @@ class OEBReader(object):
from calibre.ebooks.metadata.opf2 import OPF
from calibre.ebooks.oeb.transforms.metadata import meta_info_to_oeb_metadata
stream = cStringIO.StringIO(etree.tostring(opf, xml_declaration=True, encoding='utf-8'))
mi = OPF(stream).to_book_metadata()
o = OPF(stream)
pwm = o.primary_writing_mode
if pwm:
self.oeb.metadata.primary_writing_mode = pwm
mi = o.to_book_metadata()
if not mi.language:
mi.language = get_lang().replace('_', '-')
self.oeb.metadata.add('language', mi.language)