mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
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:
parent
da8958b573
commit
5f313b64af
@ -1163,6 +1163,11 @@ class OPF(object): # {{{
|
|||||||
if k == 'page-progression-direction' or k.endswith('}page-progression-direction'):
|
if k == 'page-progression-direction' or k.endswith('}page-progression-direction'):
|
||||||
return v
|
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):
|
def guess_cover(self):
|
||||||
'''
|
'''
|
||||||
Try to guess a cover. Needed for some old/badly formed OPF files.
|
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)
|
Metadata.__init__(self, title='', other=other)
|
||||||
self.base_path = os.path.abspath(base_path)
|
self.base_path = os.path.abspath(base_path)
|
||||||
self.page_progression_direction = None
|
self.page_progression_direction = None
|
||||||
|
self.primary_writing_mode = None
|
||||||
if self.application_id is None:
|
if self.application_id is None:
|
||||||
self.application_id = str(uuid.uuid4())
|
self.application_id = str(uuid.uuid4())
|
||||||
if not isinstance(self.toc, TOC):
|
if not isinstance(self.toc, TOC):
|
||||||
@ -1546,6 +1552,8 @@ class OPFCreator(Metadata):
|
|||||||
from calibre.ebooks.metadata.book.json_codec import object_to_unicode
|
from calibre.ebooks.metadata.book.json_codec import object_to_unicode
|
||||||
a(CAL_ELEM('calibre:user_categories',
|
a(CAL_ELEM('calibre:user_categories',
|
||||||
json.dumps(object_to_unicode(self.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()
|
manifest = E.manifest()
|
||||||
if self.manifest is not None:
|
if self.manifest is not None:
|
||||||
for ref in self.manifest:
|
for ref in self.manifest:
|
||||||
|
@ -34,6 +34,7 @@ class EXTHHeader(object): # {{{
|
|||||||
self.kf8_header = None
|
self.kf8_header = None
|
||||||
self.uuid = self.cdetype = None
|
self.uuid = self.cdetype = None
|
||||||
self.page_progression_direction = None
|
self.page_progression_direction = None
|
||||||
|
self.primary_writing_mode = None
|
||||||
|
|
||||||
self.decode = lambda x : clean_ascii_chars(x.decode(codec, 'replace'))
|
self.decode = lambda x : clean_ascii_chars(x.decode(codec, 'replace'))
|
||||||
|
|
||||||
@ -83,6 +84,13 @@ class EXTHHeader(object): # {{{
|
|||||||
self.mi.language = lang
|
self.mi.language = lang
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
elif idx == 525:
|
||||||
|
try:
|
||||||
|
pwm = content.decode(codec)
|
||||||
|
if pwm:
|
||||||
|
self.primary_writing_mode = pwm
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
elif idx == 527:
|
elif idx == 527:
|
||||||
try:
|
try:
|
||||||
ppd = content.decode(codec)
|
ppd = content.decode(codec)
|
||||||
@ -336,4 +344,3 @@ class MetadataHeader(BookHeader):
|
|||||||
except OverflowError:
|
except OverflowError:
|
||||||
self.stream.seek(start)
|
self.stream.seek(start)
|
||||||
return self.stream.read()
|
return self.stream.read()
|
||||||
|
|
||||||
|
@ -512,6 +512,9 @@ class Mobi8Reader(object):
|
|||||||
ppd = getattr(self.header.exth, 'page_progression_direction', None)
|
ppd = getattr(self.header.exth, 'page_progression_direction', None)
|
||||||
if ppd in {'ltr', 'rtl', 'default'}:
|
if ppd in {'ltr', 'rtl', 'default'}:
|
||||||
opf.page_progression_direction = ppd
|
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:
|
with open('metadata.opf', 'wb') as of, open('toc.ncx', 'wb') as ncx:
|
||||||
opf.render(of, ncx, 'toc.ncx')
|
opf.render(of, ncx, 'toc.ncx')
|
||||||
|
@ -40,6 +40,7 @@ EXTH_CODES = {
|
|||||||
'lastupdatetime': 502,
|
'lastupdatetime': 502,
|
||||||
'title': 503,
|
'title': 503,
|
||||||
'language': 524,
|
'language': 524,
|
||||||
|
'primary_writing_mode': 525,
|
||||||
'page_progression_direction': 527,
|
'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,
|
share_not_sync=True, cover_offset=None, thumbnail_offset=None,
|
||||||
start_offset=None, mobi_doctype=2, num_of_resources=None,
|
start_offset=None, mobi_doctype=2, num_of_resources=None,
|
||||||
kf8_unknown_count=0, be_kindlegen2=False, kf8_header_index=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()
|
exth = BytesIO()
|
||||||
nrecs = 0
|
nrecs = 0
|
||||||
|
|
||||||
@ -208,6 +209,12 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
|
|||||||
kf8_unknown_count))
|
kf8_unknown_count))
|
||||||
nrecs += 1
|
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'}:
|
if page_progression_direction in {'rtl', 'ltr', 'default'}:
|
||||||
ppd = bytes(page_progression_direction)
|
ppd = bytes(page_progression_direction)
|
||||||
exth.write(pack(b'>II', EXTH_CODES['page_progression_direction'], len(ppd) + 8))
|
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
|
pad = b'\0' * (4 - trail) # Always pad w/ at least 1 byte
|
||||||
exth = [b'EXTH', pack(b'>II', len(exth) + 12, nrecs), exth, pad]
|
exth = [b'EXTH', pack(b'>II', len(exth) + 12, nrecs), exth, pad]
|
||||||
return b''.join(exth)
|
return b''.join(exth)
|
||||||
|
|
||||||
|
|
||||||
|
@ -209,6 +209,7 @@ class MOBIHeader(Header): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
HEADER_FIELDS = {'compression', 'text_length', 'last_text_record', 'book_type',
|
HEADER_FIELDS = {'compression', 'text_length', 'last_text_record', 'book_type',
|
||||||
'first_non_text_record', 'title_length', 'language_code',
|
'first_non_text_record', 'title_length', 'language_code',
|
||||||
'first_resource_record', 'exth_flags', 'fdst_record',
|
'first_resource_record', 'exth_flags', 'fdst_record',
|
||||||
@ -223,6 +224,7 @@ class KF8Book(object):
|
|||||||
self.build_records(writer, for_joint)
|
self.build_records(writer, for_joint)
|
||||||
self.used_images = writer.used_images
|
self.used_images = writer.used_images
|
||||||
self.page_progression_direction = writer.oeb.spine.page_progression_direction
|
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):
|
def build_records(self, writer, for_joint):
|
||||||
metadata = writer.oeb.metadata
|
metadata = writer.oeb.metadata
|
||||||
@ -311,7 +313,8 @@ class KF8Book(object):
|
|||||||
num_of_resources=self.num_of_resources,
|
num_of_resources=self.num_of_resources,
|
||||||
kf8_unknown_count=self.kuc, be_kindlegen2=True,
|
kf8_unknown_count=self.kuc, be_kindlegen2=True,
|
||||||
start_offset=self.start_offset, mobi_doctype=self.book_type,
|
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}
|
kwargs = {field:getattr(self, field) for field in HEADER_FIELDS}
|
||||||
@ -342,4 +345,3 @@ class KF8Book(object):
|
|||||||
|
|
||||||
for rec in records:
|
for rec in records:
|
||||||
f.write(rec)
|
f.write(rec)
|
||||||
|
|
||||||
|
@ -782,6 +782,7 @@ class Metadata(object):
|
|||||||
def __init__(self, oeb):
|
def __init__(self, oeb):
|
||||||
self.oeb = oeb
|
self.oeb = oeb
|
||||||
self.items = defaultdict(list)
|
self.items = defaultdict(list)
|
||||||
|
self.primary_writing_mode = None
|
||||||
|
|
||||||
def add(self, term, value, attrib={}, nsmap={}, **kwargs):
|
def add(self, term, value, attrib={}, nsmap={}, **kwargs):
|
||||||
"""Add a new metadata item."""
|
"""Add a new metadata item."""
|
||||||
@ -864,6 +865,8 @@ class Metadata(object):
|
|||||||
for term in self.items:
|
for term in self.items:
|
||||||
for item in self.items[term]:
|
for item in self.items[term]:
|
||||||
item.to_opf2(elem, nsrmap=nsrmap)
|
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
|
return elem
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,7 +137,11 @@ class OEBReader(object):
|
|||||||
from calibre.ebooks.metadata.opf2 import OPF
|
from calibre.ebooks.metadata.opf2 import OPF
|
||||||
from calibre.ebooks.oeb.transforms.metadata import meta_info_to_oeb_metadata
|
from calibre.ebooks.oeb.transforms.metadata import meta_info_to_oeb_metadata
|
||||||
stream = cStringIO.StringIO(etree.tostring(opf, xml_declaration=True, encoding='utf-8'))
|
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:
|
if not mi.language:
|
||||||
mi.language = get_lang().replace('_', '-')
|
mi.language = get_lang().replace('_', '-')
|
||||||
self.oeb.metadata.add('language', mi.language)
|
self.oeb.metadata.add('language', mi.language)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user