Edit Book: Check Book: Add checks for missing OPF version and toc references. Fixes #1468649 [toc not display in readers/viewer](https://bugs.launchpad.net/calibre/+bug/1468649)

This commit is contained in:
Kovid Goyal 2015-07-16 09:07:43 +05:30
parent 4066ef9655
commit 312696dbf1

View File

@ -80,6 +80,25 @@ class NoHref(BaseError):
container.dirty(container.opf_name) container.dirty(container.opf_name)
return changed return changed
class MissingNCXRef(BaseError):
HELP = _('The <spine> tag has no reference to the NCX table of contents file.'
' Without this reference, the table of contents will not work in most'
' readers. The reference should look like <spine toc="id of manifest item for the ncx file">.')
INDIVIDUAL_FIX = _('Add the reference to the NCX file')
def __init__(self, name, lnum, ncx_id):
BaseError.__init__(self, _('Missing reference to the NCX Table of Contents'), name, lnum)
self.ncx_id = ncx_id
def __call__(self, container):
changed = False
for item in container.opf_xpath('/opf:package/opf:spine'):
if item.get('toc') is None:
item.set('toc', self.ncx_id)
changed = True
container.dirty(container.opf_name)
return changed
class MissingHref(BaseError): class MissingHref(BaseError):
@ -213,11 +232,17 @@ def check_opf(container):
errors = [] errors = []
if container.opf.tag != OPF('package'): if container.opf.tag != OPF('package'):
err = BaseError(_('The OPF does not have the correct root element'), container.opf_name) err = BaseError(_('The OPF does not have the correct root element'), container.opf_name, container.opf.sourceline)
err.HELP = xml(_( err.HELP = xml(_(
'The opf must have the root element <package> in namespace {0}, like this: <package xmlns="{0}">')).format(OPF2_NS) 'The opf must have the root element <package> in namespace {0}, like this: <package xmlns="{0}">')).format(OPF2_NS)
errors.append(err) errors.append(err)
elif container.opf.get('version') is None:
err = BaseError(_('The OPF does not have a version'), container.opf_name, container.opf.sourceline)
err.HELP = xml(_(
'The <package> tag in the OPF must have a version attribute. This is usually version="2.0" for EPUB2 and AZW3 and version="3.0" for EPUB3'))
errors.append(err)
for tag in ('metadata', 'manifest', 'spine'): for tag in ('metadata', 'manifest', 'spine'):
if not container.opf_xpath('/opf:package/opf:' + tag): if not container.opf_xpath('/opf:package/opf:' + tag):
errors.append(MissingSection(container.opf_name, tag)) errors.append(MissingSection(container.opf_name, tag))
@ -269,6 +294,17 @@ def check_opf(container):
errors.append(IncorrectToc(container.opf_name, mitem.sourceline, bad_mimetype=mitem.get('media-type'))) errors.append(IncorrectToc(container.opf_name, mitem.sourceline, bad_mimetype=mitem.get('media-type')))
else: else:
errors.append(IncorrectToc(container.opf_name, spine.sourceline, bad_idref=spine.get('toc'))) errors.append(IncorrectToc(container.opf_name, spine.sourceline, bad_idref=spine.get('toc')))
else:
spine = container.opf_xpath('/opf:package/opf:spine')
if spine:
spine = spine[0]
ncx = container.manifest_type_map.get(guess_type('a.ncx'))
if ncx:
ncx_name = ncx[0]
rmap = {v:k for k, v in container.manifest_id_map.iteritems()}
ncx_id = rmap.get(ncx_name)
if ncx_id:
errors.append(MissingNCXRef(container.opf_name, spine.sourceline, ncx_id))
covers = container.opf_xpath('/opf:package/opf:metadata/opf:meta[@name="cover"]') covers = container.opf_xpath('/opf:package/opf:metadata/opf:meta[@name="cover"]')
if len(covers) > 0: if len(covers) > 0: