Example #1
0
class NonLinearItems(BaseError):

    level = WARN
    has_multiple_locations = True

    HELP = xml(
        _('There are items marked as non-linear in the <spine>.'
          ' These will be displayed in random order by different ebook readers.'
          ' Some will ignore the non-linear attribute, some will display'
          ' them at the end or the beginning of the book and some will'
          ' fail to display them at all. Instead of using non-linear items'
          ' simply place the items in the order you want them to be displayed.'
          ))

    INDIVIDUAL_FIX = _('Mark all non-linear items as linear')

    def __init__(self, name, locs):
        BaseError.__init__(self, _('Non-linear items in the spine'), name)
        self.all_locations = [(name, x, None) for x in locs]

    def __call__(self, container):
        [
            elem.attrib.pop('linear')
            for elem in container.opf_xpath('//opf:spine/opf:itemref[@linear]')
        ]
        container.dirty(container.opf_name)
        return True
Example #2
0
 def __init__(self, name, section_name):
     BaseError.__init__(
         self,
         _('The <%s> section is missing from the OPF') % section_name, name)
     self.HELP = xml(
         _('The <%s> section is required in the OPF file. You have to create one.'
           ) % section_name)
Example #3
0
class NoUID(BaseError):

    HELP = xml(
        _('The OPF must have a unique identifier, i.e. a <dc:identifier> element whose id is referenced'
          ' by the <package> element'))
    INDIVIDUAL_FIX = _('Auto-generate a unique identifier')

    def __init__(self, name):
        BaseError.__init__(self, _('The OPF has no unique identifier'), name)

    def __call__(self, container):
        import uuid
        opf = container.opf
        uid = str(uuid.uuid4())
        opf.set('unique-identifier', uid)
        m = container.opf_xpath('/opf:package/opf:metadata')
        if not m:
            m = [
                container.opf.makeelement(OPF('metadata'),
                                          nsmap={'dc': DC11_NS})
            ]
            container.insert_into_xml(container.opf, m[0], 0)
        m = m[0]
        dc = m.makeelement(DC('identifier'), id=uid, nsmap={'opf': OPF2_NS})
        dc.set(OPF('scheme'), 'uuid')
        dc.text = uid
        container.insert_into_xml(m, dc)
        container.dirty(container.opf_name)
        return True
Example #4
0
 def __init__(self, name, idref, lnum):
     BaseError.__init__(self,
                        _('idref="%s" points to unknown id') % idref, name,
                        lnum)
     self.HELP = xml(
         _('The idref="%s" points to an id that does not exist in the OPF')
         % idref)
Example #5
0
 def __init__(self, name, lnum, cover):
     BaseError.__init__(
         self, _('The meta cover tag points to an non-existent item'), name,
         lnum)
     self.HELP = xml(
         _('The meta cover tag points to an item with id="%s" which does not exist in the manifest'
           ) % cover)
Example #6
0
def ACQUISITION_ENTRY(book_id, updated, request_context):
    field_metadata = request_context.db.field_metadata
    mi = request_context.db.get_metadata(book_id)
    extra = []
    if (mi.rating or 0) > 0:
        rating = rating_to_stars(mi.rating)
        extra.append(_('RATING: %s<br />')%rating)
    if mi.tags:
        extra.append(_('TAGS: %s<br />')%xml(format_tag_string(mi.tags, None)))
    if mi.series:
        extra.append(_('SERIES: %(series)s [%(sidx)s]<br />')%
                dict(series=xml(mi.series),
                sidx=fmt_sidx(float(mi.series_index))))
    for key in filter(request_context.ctx.is_field_displayable, field_metadata.ignorable_field_keys()):
        name, val = mi.format_field(key)
        if val:
            fm = field_metadata[key]
            datatype = fm['datatype']
            if datatype == 'text' and fm['is_multiple']:
                extra.append('%s: %s<br />'%
                             (xml(name),
                              xml(format_tag_string(val,
                                    fm['is_multiple']['ui_to_list'],
                                    joinval=fm['is_multiple']['list_to_ui']))))
            elif datatype == 'comments' or (fm['datatype'] == 'composite' and fm['display'].get('contains_html', False)):
                extra.append('%s: %s<br />'%(xml(name), comments_to_html(str(val))))
            else:
                extra.append('%s: %s<br />'%(xml(name), xml(str(val))))
    if mi.comments:
        comments = comments_to_html(mi.comments)
        extra.append(comments)
    if extra:
        extra = html_to_lxml('\n'.join(extra))
    ans = E.entry(TITLE(mi.title), E.author(E.name(authors_to_string(mi.authors))), ID('urn:uuid:' + mi.uuid), UPDATED(mi.last_modified),
                  E.published(mi.timestamp.isoformat()))
    if mi.pubdate and not is_date_undefined(mi.pubdate):
        ans.append(ans.makeelement('{%s}date' % DC_NS))
        ans[-1].text = mi.pubdate.isoformat()
    if len(extra):
        ans.append(E.content(extra, type='xhtml'))
    get = partial(request_context.ctx.url_for, '/get', book_id=book_id, library_id=request_context.library_id)
    if mi.formats:
        fm = mi.format_metadata
        for fmt in mi.formats:
            fmt = fmt.lower()
            mt = guess_type('a.'+fmt)[0]
            if mt:
                link = E.link(type=mt, href=get(what=fmt), rel="http://opds-spec.org/acquisition")
                ffm = fm.get(fmt.upper())
                if ffm:
                    link.set('length', str(ffm['size']))
                    link.set('mtime', ffm['mtime'].isoformat())
                ans.append(link)
    ans.append(E.link(type='image/jpeg', href=get(what='cover'), rel="http://opds-spec.org/cover"))
    ans.append(E.link(type='image/jpeg', href=get(what='thumb'), rel="http://opds-spec.org/thumbnail"))
    ans.append(E.link(type='image/jpeg', href=get(what='cover'), rel="http://opds-spec.org/image"))
    ans.append(E.link(type='image/jpeg', href=get(what='thumb'), rel="http://opds-spec.org/image/thumbnail"))

    return ans
Example #7
0
def ACQUISITION_ENTRY(book_id, updated, request_context):
    field_metadata = request_context.db.field_metadata
    mi = request_context.db.get_metadata(book_id)
    extra = []
    if mi.rating > 0:
        rating = u"".join(repeat(u"\u2605", int(mi.rating / 2.0)))
        extra.append(_("RATING: %s<br />") % rating)
    if mi.tags:
        extra.append(_("TAGS: %s<br />") % xml(format_tag_string(mi.tags, None)))
    if mi.series:
        extra.append(
            _("SERIES: %(series)s [%(sidx)s]<br />")
            % dict(series=xml(mi.series), sidx=fmt_sidx(float(mi.series_index)))
        )
    for key in filter(request_context.ctx.is_field_displayable, field_metadata.ignorable_field_keys()):
        name, val = mi.format_field(key)
        if val:
            fm = field_metadata[key]
            datatype = fm["datatype"]
            if datatype == "text" and fm["is_multiple"]:
                extra.append(
                    "%s: %s<br />"
                    % (
                        xml(name),
                        xml(
                            format_tag_string(
                                val, fm["is_multiple"]["ui_to_list"], joinval=fm["is_multiple"]["list_to_ui"]
                            )
                        ),
                    )
                )
            elif datatype == "comments" or (
                fm["datatype"] == "composite" and fm["display"].get("contains_html", False)
            ):
                extra.append("%s: %s<br />" % (xml(name), comments_to_html(unicode(val))))
            else:
                extra.append("%s: %s<br />" % (xml(name), xml(unicode(val))))
    if mi.comments:
        comments = comments_to_html(mi.comments)
        extra.append(comments)
    if extra:
        extra = html_to_lxml("\n".join(extra))
    ans = E.entry(
        TITLE(mi.title), E.author(E.name(authors_to_string(mi.authors))), ID("urn:uuid:" + mi.uuid), UPDATED(updated)
    )
    if len(extra):
        ans.append(E.content(extra, type="xhtml"))
    get = partial(request_context.ctx.url_for, "/get", book_id=book_id, library_id=request_context.library_id)
    if mi.formats:
        for fmt in mi.formats:
            fmt = fmt.lower()
            mt = guess_type("a." + fmt)[0]
            if mt:
                ans.append(E.link(type=mt, href=get(what=fmt), rel="http://opds-spec.org/acquisition"))
    ans.append(E.link(type="image/jpeg", href=get(what="cover"), rel="http://opds-spec.org/cover"))
    ans.append(E.link(type="image/jpeg", href=get(what="thumb"), rel="http://opds-spec.org/thumbnail"))

    return ans
Example #8
0
def ACQUISITION_ENTRY(book_id, updated, request_context):
    field_metadata = request_context.db.field_metadata
    mi = request_context.db.get_metadata(book_id)
    extra = []
    if mi.rating > 0:
        rating = rating_to_stars(mi.rating)
        extra.append(_('RATING: %s<br />')%rating)
    if mi.tags:
        extra.append(_('TAGS: %s<br />')%xml(format_tag_string(mi.tags, None)))
    if mi.series:
        extra.append(_('SERIES: %(series)s [%(sidx)s]<br />')%
                dict(series=xml(mi.series),
                sidx=fmt_sidx(float(mi.series_index))))
    for key in filter(request_context.ctx.is_field_displayable, field_metadata.ignorable_field_keys()):
        name, val = mi.format_field(key)
        if val:
            fm = field_metadata[key]
            datatype = fm['datatype']
            if datatype == 'text' and fm['is_multiple']:
                extra.append('%s: %s<br />'%
                             (xml(name),
                              xml(format_tag_string(val,
                                    fm['is_multiple']['ui_to_list'],
                                    joinval=fm['is_multiple']['list_to_ui']))))
            elif datatype == 'comments' or (fm['datatype'] == 'composite' and
                            fm['display'].get('contains_html', False)):
                extra.append('%s: %s<br />'%(xml(name), comments_to_html(unicode(val))))
            else:
                extra.append('%s: %s<br />'%(xml(name), xml(unicode(val))))
    if mi.comments:
        comments = comments_to_html(mi.comments)
        extra.append(comments)
    if extra:
        extra = html_to_lxml('\n'.join(extra))
    ans = E.entry(TITLE(mi.title), E.author(E.name(authors_to_string(mi.authors))), ID('urn:uuid:' + mi.uuid), UPDATED(mi.last_modified),
                  E.published(mi.timestamp.isoformat()))
    if mi.pubdate and not is_date_undefined(mi.pubdate):
        ans.append(ans.makeelement('{%s}date' % DC_NS))
        ans[-1].text = mi.pubdate.isoformat()
    if len(extra):
        ans.append(E.content(extra, type='xhtml'))
    get = partial(request_context.ctx.url_for, '/get', book_id=book_id, library_id=request_context.library_id)
    if mi.formats:
        fm = mi.format_metadata
        for fmt in mi.formats:
            fmt = fmt.lower()
            mt = guess_type('a.'+fmt)[0]
            if mt:
                link = E.link(type=mt, href=get(what=fmt), rel="http://opds-spec.org/acquisition")
                ffm = fm.get(fmt.upper())
                if ffm:
                    link.set('length', str(ffm['size']))
                    link.set('mtime', ffm['mtime'].isoformat())
                ans.append(link)
    ans.append(E.link(type='image/jpeg', href=get(what='cover'), rel="http://opds-spec.org/cover"))
    ans.append(E.link(type='image/jpeg', href=get(what='thumb'), rel="http://opds-spec.org/thumbnail"))

    return ans
Example #9
0
class EmptyIdentifier(BaseError):

    HELP = xml(_('The <dc:identifier> element must not be empty.'))
    INDIVIDUAL_FIX = _('Remove empty identifiers')

    def __init__(self, name, lnum):
        BaseError.__init__(self, _('Empty identifier element'), name, lnum)

    def __call__(self, container):
        for dcid in container.opf_xpath(
                '/opf:package/opf:metadata/dc:identifier'):
            if not dcid.text or not dcid.text.strip():
                container.remove_from_xml(dcid)
        container.dirty(container.opf_name)
        return True
Example #10
0
class MultipleCovers(BaseError):

    has_multiple_locations = True
    HELP = xml(_(
        'There is more than one <meta name="cover"> tag defined. There should be only one.'))
    INDIVIDUAL_FIX = _('Remove all but the first meta cover tag')

    def __init__(self, name, locs):
        BaseError.__init__(self, _('There is more than one cover defined'), name)
        self.all_locations = [(name, lnum, None) for lnum in sorted(locs)]

    def __call__(self, container):
        items = [e for e in container.opf_xpath('/opf:package/opf:metadata/opf:meta[@name="cover"]')]
        [container.remove_from_xml(e) for e in items[1:]]
        container.dirty(self.name)
        return True
Example #11
0
def ACQUISITION_ENTRY(book_id, updated, request_context):
    field_metadata = request_context.db.field_metadata
    mi = request_context.db.get_metadata(book_id)
    extra = []
    if mi.rating > 0:
        rating = u''.join(repeat(u'\u2605', int(mi.rating/2.)))
        extra.append(_('RATING: %s<br />')%rating)
    if mi.tags:
        extra.append(_('TAGS: %s<br />')%xml(format_tag_string(mi.tags, None, no_tag_count=True)))
    if mi.series:
        extra.append(_('SERIES: %(series)s [%(sidx)s]<br />')%
                dict(series=xml(mi.series),
                sidx=fmt_sidx(float(mi.series_index))))
    for key in field_metadata.ignorable_field_keys():
        name, val = mi.format_field(key)
        if val:
            fm = field_metadata[key]
            datatype = fm['datatype']
            if datatype == 'text' and fm['is_multiple']:
                extra.append('%s: %s<br />'%
                             (xml(name),
                              xml(format_tag_string(val,
                                    fm['is_multiple']['ui_to_list'],
                                    no_tag_count=True,
                                    joinval=fm['is_multiple']['list_to_ui']))))
            elif datatype == 'comments' or (fm['datatype'] == 'composite' and
                            fm['display'].get('contains_html', False)):
                extra.append('%s: %s<br />'%(xml(name), comments_to_html(unicode(val))))
            else:
                extra.append('%s: %s<br />'%(xml(name), xml(unicode(val))))
    if mi.comments:
        comments = comments_to_html(mi.comments)
        extra.append(comments)
    if extra:
        extra = html_to_lxml('\n'.join(extra))
    ans = E.entry(TITLE(mi.title), E.author(E.name(authors_to_string(mi.authors))), ID('urn:uuid:' + mi.uuid), UPDATED(updated))
    if len(extra):
        ans.append(E.content(extra, type='xhtml'))
    get = partial(request_context.ctx.url_for, '/get', book_id=book_id, library_id=request_context.library_id)
    if mi.formats:
        for fmt in mi.formats:
            fmt = fmt.lower()
            mt = guess_type('a.'+fmt)[0]
            if mt:
                ans.append(E.link(type=mt, href=get(what=fmt), rel="http://opds-spec.org/acquisition"))
    ans.append(E.link(type='image/jpeg', href=get(what='cover'), rel="http://opds-spec.org/cover"))
    ans.append(E.link(type='image/jpeg', href=get(what='thumb'), rel="http://opds-spec.org/thumbnail"))

    return ans
Example #12
0
def ACQUISITION_ENTRY(item, version, db, updated, CFM, CKEYS, prefix):
    FM = db.FIELD_MAP
    title = item[FM['title']]
    if not title:
        title = _('Unknown')
    authors = item[FM['authors']]
    if not authors:
        authors = _('Unknown')
    authors = ' & '.join([i.replace('|', ',') for i in
                                    authors.split(',')])
    extra = []
    rating = item[FM['rating']]
    if rating > 0:
        rating = u''.join(repeat(u'\u2605', int(rating/2.)))
        extra.append(_('RATING: %s<br />')%rating)
    tags = item[FM['tags']]
    if tags:
        extra.append(_('TAGS: %s<br />')%xml(format_tag_string(tags, ',',
                                                           ignore_max=True,
                                                           no_tag_count=True)))
    series = item[FM['series']]
    if series:
        extra.append(_('SERIES: %(series)s [%(sidx)s]<br />')%\
                dict(series=xml(series),
                sidx=fmt_sidx(float(item[FM['series_index']]))))
    for key in CKEYS:
        mi = db.get_metadata(item[CFM['id']['rec_index']], index_is_id=True)
        name, val = mi.format_field(key)
        if val:
            datatype = CFM[key]['datatype']
            if datatype == 'text' and CFM[key]['is_multiple']:
                extra.append('%s: %s<br />'%
                             (xml(name),
                              xml(format_tag_string(val,
                                    CFM[key]['is_multiple']['ui_to_list'],
                                    ignore_max=True, no_tag_count=True,
                                    joinval=CFM[key]['is_multiple']['list_to_ui']))))
            elif datatype == 'comments' or (CFM[key]['datatype'] == 'composite' and
                            CFM[key]['display'].get('contains_html', False)):
                extra.append('%s: %s<br />'%(xml(name), comments_to_html(unicode(val))))
            else:
                extra.append('%s: %s<br />'%(xml(name), xml(unicode(val))))
    comments = item[FM['comments']]
    if comments:
        comments = comments_to_html(comments)
        extra.append(comments)
    if extra:
        extra = html_to_lxml('\n'.join(extra))
    idm = 'calibre' if version == 0 else 'uuid'
    id_ = 'urn:%s:%s'%(idm, item[FM['uuid']])
    ans = E.entry(TITLE(title), E.author(E.name(authors)), ID(id_),
            UPDATED(updated))
    if len(extra):
        ans.append(E.content(extra, type='xhtml'))
    formats = item[FM['formats']]
    if formats:
        for fmt in formats.split(','):
            fmt = fmt.lower()
            mt = guess_type('a.'+fmt)[0]
            href = prefix + '/get/%s/%s'%(fmt, item[FM['id']])
            if mt:
                link = E.link(type=mt, href=href)
                if version > 0:
                    link.set('rel', "http://opds-spec.org/acquisition")
                ans.append(link)
    ans.append(E.link(type='image/jpeg', href=prefix+'/get/cover/%s'%item[FM['id']],
        rel="x-stanza-cover-image" if version == 0 else
        "http://opds-spec.org/cover"))
    ans.append(E.link(type='image/jpeg', href=prefix+'/get/thumb/%s'%item[FM['id']],
        rel="x-stanza-cover-image-thumbnail" if version == 0 else
        "http://opds-spec.org/thumbnail"))

    return ans
Example #13
0
def check_opf(container):
    errors = []

    if container.opf.tag != OPF('package'):
        err = BaseError(_('The OPF does not have the correct root element'), container.opf_name)
        err.HELP = xml(_(
            'The opf must have the root element <package> in namespace {0}, like this: <package xmlns="{0}">')).format(OPF2_NS)
        errors.append(err)

    for tag in ('metadata', 'manifest', 'spine'):
        if not container.opf_xpath('/opf:package/opf:' + tag):
            errors.append(MissingSection(container.opf_name, tag))

    all_ids = set(container.opf_xpath('//*/@id'))
    for elem in container.opf_xpath('//*[@idref]'):
        if elem.get('idref') not in all_ids:
            errors.append(IncorrectIdref(container.opf_name, elem.get('idref'), elem.sourceline))

    nl_items = [elem.sourceline for elem in container.opf_xpath('//opf:spine/opf:itemref[@linear="no"]')]
    if nl_items:
        errors.append(NonLinearItems(container.opf_name, nl_items))

    seen, dups = {}, {}
    for item in container.opf_xpath('/opf:package/opf:manifest/opf:item[@href]'):
        href = item.get('href')
        if not container.exists(container.href_to_name(href, container.opf_name)):
            errors.append(MissingHref(container.opf_name, href, item.sourceline))
        if href in seen:
            if href not in dups:
                dups[href] = [seen[href]]
            dups[href].append(item.sourceline)
        else:
            seen[href] = item.sourceline
    errors.extend(DuplicateHref(container.opf_name, eid, locs) for eid, locs in dups.iteritems())

    seen, dups = {}, {}
    for item in container.opf_xpath('/opf:package/opf:spine/opf:itemref[@idref]'):
        ref = item.get('idref')
        if ref in seen:
            if ref not in dups:
                dups[ref] = [seen[ref]]
            dups[ref].append(item.sourceline)
        else:
            seen[ref] = item.sourceline
    errors.extend(DuplicateHref(container.opf_name, eid, locs, for_spine=True) for eid, locs in dups.iteritems())

    spine = container.opf_xpath('/opf:package/opf:spine[@toc]')
    if spine:
        spine = spine[0]
        mitems = [x for x in container.opf_xpath('/opf:package/opf:manifest/opf:item[@id]') if x.get('id') == spine.get('toc')]
        if mitems:
            mitem = mitems[0]
            if mitem.get('media-type', '') != guess_type('a.ncx'):
                errors.append(IncorrectToc(container.opf_name, mitem.sourceline, bad_mimetype=mitem.get('media-type')))
        else:
            errors.append(IncorrectToc(container.opf_name, spine.sourceline, bad_idref=spine.get('toc')))

    covers = container.opf_xpath('/opf:package/opf:metadata/opf:meta[@name="cover"]')
    if len(covers) > 0:
        if len(covers) > 1:
            errors.append(MultipleCovers(container.opf_name, [c.sourceline for c in covers]))
        manifest_ids = set(container.opf_xpath('/opf:package/opf:manifest/opf:item/@id'))
        for cover in covers:
            if cover.get('content', None) not in manifest_ids:
                errors.append(IncorrectCover(container.opf_name, cover.sourceline, cover.get('content', '')))
            raw = etree.tostring(cover)
            try:
                n, c = raw.index('name="'), raw.index('content="')
            except ValueError:
                n = c = -1
            if n > -1 and c > -1 and n > c:
                errors.append(NookCover(container.opf_name, cover.sourceline))

    uid = container.opf.get('unique-identifier', None)
    if uid is None or not container.opf_xpath('/opf:package/opf:metadata/dc:identifier[@id=%r]' % uid):
        errors.append(NoUID(container.opf_name))

    return errors
Example #14
0
def check_opf(container):
    errors = []
    opf_version = container.opf_version_parsed

    if container.opf.tag != OPF('package'):
        err = BaseError(_('The OPF does not have the correct root element'), container.opf_name, container.opf.sourceline)
        err.HELP = xml(_(
            'The opf must have the root element <package> in namespace {0}, like this: <package xmlns="{0}">')).format(OPF2_NS)
        errors.append(err)

    elif container.opf.get('version') is None and container.book_type == 'epub':
        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'):
        if not container.opf_xpath('/opf:package/opf:' + tag):
            errors.append(MissingSection(container.opf_name, tag))

    all_ids = set(container.opf_xpath('//*/@id'))
    if '' in all_ids:
        for empty_id_tag in container.opf_xpath('//*[@id=""]'):
            errors.append(EmptyID(container.opf_name, empty_id_tag.sourceline))
    all_ids.discard('')
    for elem in container.opf_xpath('//*[@idref]'):
        if elem.get('idref') not in all_ids:
            errors.append(IncorrectIdref(container.opf_name, elem.get('idref'), elem.sourceline))

    nl_items = [elem.sourceline for elem in container.opf_xpath('//opf:spine/opf:itemref[@linear="no"]')]
    if nl_items:
        errors.append(NonLinearItems(container.opf_name, nl_items))

    seen, dups = {}, {}
    for item in container.opf_xpath('/opf:package/opf:manifest/opf:item'):
        href = item.get('href', None)
        if href is None:
            errors.append(NoHref(container.opf_name, item.get('id', None), item.sourceline))
        else:
            hname = container.href_to_name(href, container.opf_name)
            if not hname or not container.exists(hname):
                errors.append(MissingHref(container.opf_name, href, item.sourceline))
            if href in seen:
                if href not in dups:
                    dups[href] = [seen[href]]
                dups[href].append(item.sourceline)
            else:
                seen[href] = item.sourceline
    errors.extend(DuplicateHref(container.opf_name, eid, locs) for eid, locs in iteritems(dups))

    seen, dups = {}, {}
    for item in container.opf_xpath('/opf:package/opf:spine/opf:itemref[@idref]'):
        ref = item.get('idref')
        if ref in seen:
            if ref not in dups:
                dups[ref] = [seen[ref]]
            dups[ref].append(item.sourceline)
        else:
            seen[ref] = item.sourceline
    errors.extend(DuplicateHref(container.opf_name, eid, locs, for_spine=True) for eid, locs in iteritems(dups))

    spine = container.opf_xpath('/opf:package/opf:spine[@toc]')
    if spine:
        spine = spine[0]
        mitems = [x for x in container.opf_xpath('/opf:package/opf:manifest/opf:item[@id]') if x.get('id') == spine.get('toc')]
        if mitems:
            mitem = mitems[0]
            if mitem.get('media-type', '') != guess_type('a.ncx'):
                errors.append(IncorrectToc(container.opf_name, mitem.sourceline, bad_mimetype=mitem.get('media-type')))
        else:
            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 iteritems(container.manifest_id_map)}
                ncx_id = rmap.get(ncx_name)
                if ncx_id:
                    errors.append(MissingNCXRef(container.opf_name, spine.sourceline, ncx_id))

    if opf_version.major > 2:
        existing_nav = find_existing_nav_toc(container)
        if existing_nav is None:
            errors.append(MissingNav(container.opf_name, 0))
        else:
            toc = parse_nav(container, existing_nav)
            if len(toc) == 0:
                errors.append(EmptyNav(existing_nav, 0))

    covers = container.opf_xpath('/opf:package/opf:metadata/opf:meta[@name="cover"]')
    if len(covers) > 0:
        if len(covers) > 1:
            errors.append(MultipleCovers(container.opf_name, [c.sourceline for c in covers]))
        manifest_ids = set(container.opf_xpath('/opf:package/opf:manifest/opf:item/@id'))
        for cover in covers:
            if cover.get('content', None) not in manifest_ids:
                errors.append(IncorrectCover(container.opf_name, cover.sourceline, cover.get('content', '')))
            raw = etree.tostring(cover)
            try:
                n, c = raw.index(b'name="'), raw.index(b'content="')
            except ValueError:
                n = c = -1
            if n > -1 and c > -1 and n > c:
                errors.append(NookCover(container.opf_name, cover.sourceline))

    uid = container.opf.get('unique-identifier', None)
    if uid is None or not container.opf_xpath('/opf:package/opf:metadata/dc:identifier[@id=%r]' % uid):
        errors.append(NoUID(container.opf_name))
    for elem in container.opf_xpath('/opf:package/opf:metadata/dc:identifier'):
        if not elem.text or not elem.text.strip():
            errors.append(EmptyIdentifier(container.opf_name, elem.sourceline))

    for item, name, linear in container.spine_iter:
        mt = container.mime_map[name]
        if mt != XHTML_MIME:
            iid = item.get('idref', None)
            lnum = None
            if iid:
                mitem = container.opf_xpath('/opf:package/opf:manifest/opf:item[@id=%r]' % iid)
                if mitem:
                    lnum = mitem[0].sourceline
                else:
                    iid = None
            errors.append(BadSpineMime(name, iid, mt, lnum, container.opf_name))

    return errors
Example #15
0
 def __init__(self, name, lnum):
     BaseError.__init__(self, _('Empty id attributes are invalid'), name, lnum)
     self.HELP = xml(_(
         'Empty ID attributes are invalid in OPF files.'))
Example #16
0
def sony_metadata(oeb):
    m = oeb.metadata
    title = short_title = str(m.title[0])
    publisher = __appname__ + ' ' + __version__
    try:
        pt = str(oeb.metadata.publication_type[0])
        short_title = ':'.join(pt.split(':')[2:])
    except:
        pass

    try:
        date = parse_date(str(m.date[0]),
                as_utc=False).strftime('%Y-%m-%d')
    except:
        date = strftime('%Y-%m-%d')
    try:
        language = str(m.language[0]).replace('_', '-')
    except:
        language = 'en'
    short_title = xml(short_title, True)

    metadata = SONY_METADATA.format(title=xml(title),
            short_title=short_title,
            publisher=xml(publisher), issue_date=xml(date),
            language=xml(language))

    updated = strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())

    def cal_id(x):
        for k, v in x.attrib.items():
            if k.endswith('scheme') and v == 'uuid':
                return True

    try:
        base_id = str(list(filter(cal_id, m.identifier))[0])
    except:
        base_id = str(uuid4())

    toc = oeb.toc

    if False and toc.depth() < 3:
        # Single section periodical
        # Disabled since I prefer the current behavior
        from calibre.ebooks.oeb.base import TOC
        section = TOC(klass='section', title=_('All articles'),
                    href=oeb.spine[2].href)
        for x in toc:
            section.nodes.append(x)
        toc = TOC(klass='periodical', href=oeb.spine[2].href,
                    title=str(oeb.metadata.title[0]))
        toc.nodes.append(section)

    entries = []
    seen_titles = set()
    for i, section in enumerate(toc):
        if not section.href:
            continue
        secid = 'section%d'%i
        sectitle = section.title
        if not sectitle:
            sectitle = _('Unknown')
        d = 1
        bsectitle = sectitle
        while sectitle in seen_titles:
            sectitle = bsectitle + ' ' + str(d)
            d += 1
        seen_titles.add(sectitle)
        sectitle = xml(sectitle, True)
        secdesc = section.description
        if not secdesc:
            secdesc = ''
        secdesc = xml(secdesc)
        entries.append(SONY_ATOM_SECTION.format(title=sectitle,
            href=section.href, id=xml(base_id)+'/'+secid,
            short_title=short_title, desc=secdesc, updated=updated))

        for j, article in enumerate(section):
            if not article.href:
                continue
            atitle = article.title
            btitle = atitle
            d = 1
            while atitle in seen_titles:
                atitle = btitle + ' ' + str(d)
                d += 1

            auth = article.author if article.author else ''
            desc = section.description
            if not desc:
                desc = ''
            aid = 'article%d'%j

            entries.append(SONY_ATOM_ENTRY.format(
                title=xml(atitle),
                author=xml(auth),
                updated=updated,
                desc=desc,
                short_title=short_title,
                section_title=sectitle,
                href=article.href,
                word_count=str(1),
                id=xml(base_id)+'/'+secid+'/'+aid
            ))

    atom = SONY_ATOM.format(short_title=short_title,
            entries='\n\n'.join(entries), updated=updated,
            id=xml(base_id)).encode('utf-8')

    return metadata, atom
Example #17
0
def ACQUISITION_ENTRY(item, version, db, updated, CFM, CKEYS, prefix):
    FM = db.FIELD_MAP
    title = item[FM["title"]]
    if not title:
        title = _("Unknown")
    authors = item[FM["authors"]]
    if not authors:
        authors = _("Unknown")
    authors = " & ".join([i.replace("|", ",") for i in authors.split(",")])
    extra = []
    rating = item[FM["rating"]]
    if rating > 0:
        rating = u"".join(repeat(u"\u2605", int(rating / 2.0)))
        extra.append(_("RATING: %s<br />") % rating)
    tags = item[FM["tags"]]
    if tags:
        extra.append(_("TAGS: %s<br />") % xml(format_tag_string(tags, ",", ignore_max=True, no_tag_count=True)))
    series = item[FM["series"]]
    if series:
        extra.append(
            _("SERIES: %(series)s [%(sidx)s]<br />")
            % dict(series=xml(series), sidx=fmt_sidx(float(item[FM["series_index"]])))
        )
    for key in CKEYS:
        mi = db.get_metadata(item[CFM["id"]["rec_index"]], index_is_id=True)
        name, val = mi.format_field(key)
        if val:
            datatype = CFM[key]["datatype"]
            if datatype == "text" and CFM[key]["is_multiple"]:
                extra.append(
                    "%s: %s<br />"
                    % (
                        xml(name),
                        xml(
                            format_tag_string(
                                val,
                                CFM[key]["is_multiple"]["ui_to_list"],
                                ignore_max=True,
                                no_tag_count=True,
                                joinval=CFM[key]["is_multiple"]["list_to_ui"],
                            )
                        ),
                    )
                )
            elif datatype == "comments" or (
                CFM[key]["datatype"] == "composite" and CFM[key]["display"].get("contains_html", False)
            ):
                extra.append("%s: %s<br />" % (xml(name), comments_to_html(unicode(val))))
            else:
                extra.append("%s: %s<br />" % (xml(name), xml(unicode(val))))
    comments = item[FM["comments"]]
    if comments:
        comments = comments_to_html(comments)
        extra.append(comments)
    if extra:
        extra = html_to_lxml("\n".join(extra))
    idm = "calibre" if version == 0 else "uuid"
    id_ = "urn:%s:%s" % (idm, item[FM["uuid"]])
    ans = E.entry(TITLE(title), E.author(E.name(authors)), ID(id_), UPDATED(updated))
    if len(extra):
        ans.append(E.content(extra, type="xhtml"))
    formats = item[FM["formats"]]
    if formats:
        for fmt in formats.split(","):
            fmt = fmt.lower()
            mt = guess_type("a." + fmt)[0]
            href = prefix + "/get/%s/%s" % (fmt, item[FM["id"]])
            if mt:
                link = E.link(type=mt, href=href)
                if version > 0:
                    link.set("rel", "http://opds-spec.org/acquisition")
                ans.append(link)
    ans.append(
        E.link(
            type="image/jpeg",
            href=prefix + "/get/cover/%s" % item[FM["id"]],
            rel="x-stanza-cover-image" if version == 0 else "http://opds-spec.org/cover",
        )
    )
    ans.append(
        E.link(
            type="image/jpeg",
            href=prefix + "/get/thumb/%s" % item[FM["id"]],
            rel="x-stanza-cover-image-thumbnail" if version == 0 else "http://opds-spec.org/thumbnail",
        )
    )

    return ans
Example #18
0
def ACQUISITION_ENTRY(book_id, updated, request_context):
    field_metadata = request_context.db.field_metadata
    mi = request_context.db.get_metadata(book_id)
    extra = []
    if mi.rating > 0:
        rating = u''.join(repeat(u'\u2605', int(mi.rating / 2.)))
        extra.append(_('RATING: %s<br />') % rating)
    if mi.tags:
        extra.append(
            _('TAGS: %s<br />') %
            xml(format_tag_string(mi.tags, None, no_tag_count=True)))
    if mi.series:
        extra.append(
            _('SERIES: %(series)s [%(sidx)s]<br />') %
            dict(series=xml(mi.series), sidx=fmt_sidx(float(mi.series_index))))
    for key in field_metadata.ignorable_field_keys():
        name, val = mi.format_field(key)
        if val:
            fm = field_metadata[key]
            datatype = fm['datatype']
            if datatype == 'text' and fm['is_multiple']:
                extra.append(
                    '%s: %s<br />' %
                    (xml(name),
                     xml(
                         format_tag_string(
                             val,
                             fm['is_multiple']['ui_to_list'],
                             no_tag_count=True,
                             joinval=fm['is_multiple']['list_to_ui']))))
            elif datatype == 'comments' or (fm['datatype'] == 'composite'
                                            and fm['display'].get(
                                                'contains_html', False)):
                extra.append('%s: %s<br />' %
                             (xml(name), comments_to_html(unicode(val))))
            else:
                extra.append('%s: %s<br />' % (xml(name), xml(unicode(val))))
    if mi.comments:
        comments = comments_to_html(mi.comments)
        extra.append(comments)
    if extra:
        extra = html_to_lxml('\n'.join(extra))
    ans = E.entry(TITLE(mi.title),
                  E.author(E.name(authors_to_string(mi.authors))),
                  ID('urn:uuid:' + mi.uuid), UPDATED(updated))
    if len(extra):
        ans.append(E.content(extra, type='xhtml'))
    get = partial(request_context.ctx.url_for,
                  '/get',
                  book_id=book_id,
                  library_id=request_context.library_id)
    if mi.formats:
        for fmt in mi.formats:
            fmt = fmt.lower()
            mt = guess_type('a.' + fmt)[0]
            if mt:
                ans.append(
                    E.link(type=mt,
                           href=get(what=fmt),
                           rel="http://opds-spec.org/acquisition"))
    ans.append(
        E.link(type='image/jpeg',
               href=get(what='cover'),
               rel="http://opds-spec.org/cover"))
    ans.append(
        E.link(type='image/jpeg',
               href=get(what='thumb'),
               rel="http://opds-spec.org/thumbnail"))

    return ans
Example #19
0
 def __init__(self, name, idref, lnum):
     BaseError.__init__(self, _('idref="%s" points to unknown id') % idref, name, lnum)
     self.HELP = xml(_(
         'The idref="%s" points to an id that does not exist in the OPF') % idref)
Example #20
0
def check_opf(container):
    errors = []
    opf_version = container.opf_version_parsed

    if container.opf.tag != OPF('package'):
        err = BaseError(_('The OPF does not have the correct root element'), container.opf_name, container.opf.sourceline)
        err.HELP = xml(_(
            'The opf must have the root element <package> in namespace {0}, like this: <package xmlns="{0}">')).format(OPF2_NS)
        errors.append(err)

    elif container.opf.get('version') is None and container.book_type == 'epub':
        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'):
        if not container.opf_xpath('/opf:package/opf:' + tag):
            errors.append(MissingSection(container.opf_name, tag))

    all_ids = set(container.opf_xpath('//*/@id'))
    for elem in container.opf_xpath('//*[@idref]'):
        if elem.get('idref') not in all_ids:
            errors.append(IncorrectIdref(container.opf_name, elem.get('idref'), elem.sourceline))

    nl_items = [elem.sourceline for elem in container.opf_xpath('//opf:spine/opf:itemref[@linear="no"]')]
    if nl_items:
        errors.append(NonLinearItems(container.opf_name, nl_items))

    seen, dups = {}, {}
    for item in container.opf_xpath('/opf:package/opf:manifest/opf:item'):
        href = item.get('href', None)
        if href is None:
            errors.append(NoHref(container.opf_name, item.get('id', None), item.sourceline))
        else:
            hname = container.href_to_name(href, container.opf_name)
            if not hname or not container.exists(hname):
                errors.append(MissingHref(container.opf_name, href, item.sourceline))
            if href in seen:
                if href not in dups:
                    dups[href] = [seen[href]]
                dups[href].append(item.sourceline)
            else:
                seen[href] = item.sourceline
    errors.extend(DuplicateHref(container.opf_name, eid, locs) for eid, locs in dups.iteritems())

    seen, dups = {}, {}
    for item in container.opf_xpath('/opf:package/opf:spine/opf:itemref[@idref]'):
        ref = item.get('idref')
        if ref in seen:
            if ref not in dups:
                dups[ref] = [seen[ref]]
            dups[ref].append(item.sourceline)
        else:
            seen[ref] = item.sourceline
    errors.extend(DuplicateHref(container.opf_name, eid, locs, for_spine=True) for eid, locs in dups.iteritems())

    spine = container.opf_xpath('/opf:package/opf:spine[@toc]')
    if spine:
        spine = spine[0]
        mitems = [x for x in container.opf_xpath('/opf:package/opf:manifest/opf:item[@id]') if x.get('id') == spine.get('toc')]
        if mitems:
            mitem = mitems[0]
            if mitem.get('media-type', '') != guess_type('a.ncx'):
                errors.append(IncorrectToc(container.opf_name, mitem.sourceline, bad_mimetype=mitem.get('media-type')))
        else:
            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))

    if opf_version.major > 2:
        if find_existing_nav_toc(container) is None:
            errors.append(MissingNav(container.opf_name, 0))

    covers = container.opf_xpath('/opf:package/opf:metadata/opf:meta[@name="cover"]')
    if len(covers) > 0:
        if len(covers) > 1:
            errors.append(MultipleCovers(container.opf_name, [c.sourceline for c in covers]))
        manifest_ids = set(container.opf_xpath('/opf:package/opf:manifest/opf:item/@id'))
        for cover in covers:
            if cover.get('content', None) not in manifest_ids:
                errors.append(IncorrectCover(container.opf_name, cover.sourceline, cover.get('content', '')))
            raw = etree.tostring(cover)
            try:
                n, c = raw.index('name="'), raw.index('content="')
            except ValueError:
                n = c = -1
            if n > -1 and c > -1 and n > c:
                errors.append(NookCover(container.opf_name, cover.sourceline))

    uid = container.opf.get('unique-identifier', None)
    if uid is None or not container.opf_xpath('/opf:package/opf:metadata/dc:identifier[@id=%r]' % uid):
        errors.append(NoUID(container.opf_name))

    for item, name, linear in container.spine_iter:
        mt = container.mime_map[name]
        if mt != XHTML_MIME:
            iid = item.get('idref', None)
            lnum = None
            if iid:
                mitem = container.opf_xpath('/opf:package/opf:manifest/opf:item[@id=%r]' % iid)
                if mitem:
                    lnum = mitem[0].sourceline
                else:
                    iid = None
            errors.append(BadSpineMime(name, iid, mt, lnum, container.opf_name))

    return errors
Example #21
0
 def __init__(self, name, section_name):
     BaseError.__init__(self, _('The <%s> section is missing from the OPF') % section_name, name)
     self.HELP = xml(_(
         'The <%s> section is required in the OPF file. You have to create one.') % section_name)
Example #22
0
def ACQUISITION_ENTRY(item, version, db, updated, CFM, CKEYS, prefix):
    FM = db.FIELD_MAP
    title = item[FM['title']]
    if not title:
        title = _('Unknown')
    authors = item[FM['authors']]
    if not authors:
        authors = _('Unknown')
    authors = ' & '.join([i.replace('|', ',') for i in authors.split(',')])
    extra = []
    rating = item[FM['rating']]
    if rating > 0:
        rating = u''.join(repeat(u'\u2605', int(rating / 2.)))
        extra.append(_('RATING: %s<br />') % rating)
    tags = item[FM['tags']]
    if tags:
        extra.append(
            _('TAGS: %s<br />') % xml(
                format_tag_string(
                    tags, ',', ignore_max=True, no_tag_count=True)))
    series = item[FM['series']]
    if series:
        extra.append(
            _('SERIES: %(series)s [%(sidx)s]<br />') %
            dict(series=xml(series),
                 sidx=fmt_sidx(float(item[FM['series_index']]))))
    for key in CKEYS:
        mi = db.get_metadata(item[CFM['id']['rec_index']], index_is_id=True)
        name, val = mi.format_field(key)
        if val:
            datatype = CFM[key]['datatype']
            if datatype == 'text' and CFM[key]['is_multiple']:
                extra.append(
                    '%s: %s<br />' %
                    (xml(name),
                     xml(
                         format_tag_string(
                             val,
                             CFM[key]['is_multiple']['ui_to_list'],
                             ignore_max=True,
                             no_tag_count=True,
                             joinval=CFM[key]['is_multiple']['list_to_ui']))))
            elif datatype == 'comments' or (CFM[key]['datatype'] == 'composite'
                                            and CFM[key]['display'].get(
                                                'contains_html', False)):
                extra.append('%s: %s<br />' %
                             (xml(name), comments_to_html(unicode(val))))
            else:
                extra.append('%s: %s<br />' % (xml(name), xml(unicode(val))))
    comments = item[FM['comments']]
    if comments:
        comments = comments_to_html(comments)
        extra.append(comments)
    if extra:
        extra = html_to_lxml('\n'.join(extra))
    idm = 'calibre' if version == 0 else 'uuid'
    id_ = 'urn:%s:%s' % (idm, item[FM['uuid']])
    ans = E.entry(TITLE(title), E.author(E.name(authors)), ID(id_),
                  UPDATED(updated))
    if len(extra):
        ans.append(E.content(extra, type='xhtml'))
    formats = item[FM['formats']]
    if formats:
        for fmt in formats.split(','):
            fmt = fmt.lower()
            mt = guess_type('a.' + fmt)[0]
            href = prefix + '/get/%s/%s' % (fmt, item[FM['id']])
            if mt:
                link = E.link(type=mt, href=href)
                if version > 0:
                    link.set('rel', "http://opds-spec.org/acquisition")
                ans.append(link)
    ans.append(
        E.link(type='image/jpeg',
               href=prefix + '/get/cover/%s' % item[FM['id']],
               rel="x-stanza-cover-image"
               if version == 0 else "http://opds-spec.org/cover"))
    ans.append(
        E.link(type='image/jpeg',
               href=prefix + '/get/thumb/%s' % item[FM['id']],
               rel="x-stanza-cover-image-thumbnail"
               if version == 0 else "http://opds-spec.org/thumbnail"))

    return ans
Example #23
0
def check_opf(container):
    errors = []

    if container.opf.tag != OPF('package'):
        err = BaseError(_('The OPF does not have the correct root element'),
                        container.opf_name)
        err.HELP = xml(
            _('The opf must have the root element <package> in namespace {0}, like this: <package xmlns="{0}">'
              )).format(OPF2_NS)
        errors.append(err)

    for tag in ('metadata', 'manifest', 'spine'):
        if not container.opf_xpath('/opf:package/opf:' + tag):
            errors.append(MissingSection(container.opf_name, tag))

    all_ids = set(container.opf_xpath('//*/@id'))
    for elem in container.opf_xpath('//*[@idref]'):
        if elem.get('idref') not in all_ids:
            errors.append(
                IncorrectIdref(container.opf_name, elem.get('idref'),
                               elem.sourceline))

    nl_items = [
        elem.sourceline for elem in container.opf_xpath(
            '//opf:spine/opf:itemref[@linear="no"]')
    ]
    if nl_items:
        errors.append(NonLinearItems(container.opf_name, nl_items))

    seen, dups = {}, {}
    for item in container.opf_xpath(
            '/opf:package/opf:manifest/opf:item[@href]'):
        href = item.get('href')
        if not container.exists(
                container.href_to_name(href, container.opf_name)):
            errors.append(
                MissingHref(container.opf_name, href, item.sourceline))
        if href in seen:
            if href not in dups:
                dups[href] = [seen[href]]
            dups[href].append(item.sourceline)
        else:
            seen[href] = item.sourceline
    errors.extend(
        DuplicateHref(container.opf_name, eid, locs)
        for eid, locs in dups.iteritems())

    seen, dups = {}, {}
    for item in container.opf_xpath(
            '/opf:package/opf:spine/opf:itemref[@idref]'):
        ref = item.get('idref')
        if ref in seen:
            if ref not in dups:
                dups[ref] = [seen[ref]]
            dups[ref].append(item.sourceline)
        else:
            seen[ref] = item.sourceline
    errors.extend(
        DuplicateHref(container.opf_name, eid, locs, for_spine=True)
        for eid, locs in dups.iteritems())

    spine = container.opf_xpath('/opf:package/opf:spine[@toc]')
    if spine:
        spine = spine[0]
        mitems = [
            x for x in container.opf_xpath(
                '/opf:package/opf:manifest/opf:item[@id]')
            if x.get('id') == spine.get('toc')
        ]
        if mitems:
            mitem = mitems[0]
            if mitem.get('media-type', '') != guess_type('a.ncx'):
                errors.append(
                    IncorrectToc(container.opf_name,
                                 mitem.sourceline,
                                 bad_mimetype=mitem.get('media-type')))
        else:
            errors.append(
                IncorrectToc(container.opf_name,
                             spine.sourceline,
                             bad_idref=spine.get('toc')))

    covers = container.opf_xpath(
        '/opf:package/opf:metadata/opf:meta[@name="cover"]')
    if len(covers) > 0:
        if len(covers) > 1:
            errors.append(
                MultipleCovers(container.opf_name,
                               [c.sourceline for c in covers]))
        manifest_ids = set(
            container.opf_xpath('/opf:package/opf:manifest/opf:item/@id'))
        for cover in covers:
            if cover.get('content', None) not in manifest_ids:
                errors.append(
                    IncorrectCover(container.opf_name, cover.sourceline,
                                   cover.get('content', '')))
            raw = etree.tostring(cover)
            try:
                n, c = raw.index('name="'), raw.index('content="')
            except ValueError:
                n = c = -1
            if n > -1 and c > -1 and n > c:
                errors.append(NookCover(container.opf_name, cover.sourceline))

    uid = container.opf.get('unique-identifier', None)
    if uid is None or not container.opf_xpath(
            '/opf:package/opf:metadata/dc:identifier[@id=%r]' % uid):
        errors.append(NoUID(container.opf_name))

    for item, name, linear in container.spine_iter:
        mt = container.mime_map[name]
        if mt != XHTML_MIME:
            iid = item.get('idref', None)
            lnum = None
            if iid:
                mitem = container.opf_xpath(
                    '/opf:package/opf:manifest/opf:item[@id=%r]' % iid)
                if mitem:
                    lnum = mitem[0].sourceline
                else:
                    iid = None
            errors.append(BadSpineMime(name, iid, mt, lnum,
                                       container.opf_name))

    return errors
Example #24
0
class EmptyIdentifier(BaseError):

    HELP = xml(_('The <dc:identifier> element must not be empty.'))

    def __init__(self, name, lnum):
        BaseError.__init__(self, _('Empty identifier element'), name, lnum)
Example #25
0
 def __init__(self, name, lnum, cover):
     BaseError.__init__(self, _('The meta cover tag points to an non-existent item'), name, lnum)
     self.HELP = xml(_(
         'The meta cover tag points to an item with id="%s" which does not exist in the manifest') % cover)
Example #26
0
def sony_metadata(oeb):
    m = oeb.metadata
    title = short_title = unicode(m.title[0])
    publisher = __appname__ + ' ' + __version__
    try:
        pt = unicode(oeb.metadata.publication_type[0])
        short_title = u':'.join(pt.split(':')[2:])
    except:
        pass

    try:
        date = parse_date(unicode(m.date[0]),
                as_utc=False).strftime('%Y-%m-%d')
    except:
        date = strftime('%Y-%m-%d')
    try:
        language = unicode(m.language[0]).replace('_', '-')
    except:
        language = 'en'
    short_title = xml(short_title, True)

    metadata = SONY_METADATA.format(title=xml(title),
            short_title=short_title,
            publisher=xml(publisher), issue_date=xml(date),
            language=xml(language))

    updated = strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())

    def cal_id(x):
        for k, v in x.attrib.items():
            if k.endswith('scheme') and v == 'uuid':
                return True

    try:
        base_id = unicode(list(filter(cal_id, m.identifier))[0])
    except:
        base_id = str(uuid4())

    toc = oeb.toc

    if False and toc.depth() < 3:
        # Single section periodical
        # Disabled since I prefer the current behavior
        from calibre.ebooks.oeb.base import TOC
        section = TOC(klass='section', title=_('All articles'),
                    href=oeb.spine[2].href)
        for x in toc:
            section.nodes.append(x)
        toc = TOC(klass='periodical', href=oeb.spine[2].href,
                    title=unicode(oeb.metadata.title[0]))
        toc.nodes.append(section)

    entries = []
    seen_titles = set([])
    for i, section in enumerate(toc):
        if not section.href:
            continue
        secid = 'section%d'%i
        sectitle = section.title
        if not sectitle:
            sectitle = _('Unknown')
        d = 1
        bsectitle = sectitle
        while sectitle in seen_titles:
            sectitle = bsectitle + ' ' + str(d)
            d += 1
        seen_titles.add(sectitle)
        sectitle = xml(sectitle, True)
        secdesc = section.description
        if not secdesc:
            secdesc = ''
        secdesc = xml(secdesc)
        entries.append(SONY_ATOM_SECTION.format(title=sectitle,
            href=section.href, id=xml(base_id)+'/'+secid,
            short_title=short_title, desc=secdesc, updated=updated))

        for j, article in enumerate(section):
            if not article.href:
                continue
            atitle = article.title
            btitle = atitle
            d = 1
            while atitle in seen_titles:
                atitle = btitle + ' ' + str(d)
                d += 1

            auth = article.author if article.author else ''
            desc = section.description
            if not desc:
                desc = ''
            aid = 'article%d'%j

            entries.append(SONY_ATOM_ENTRY.format(
                title=xml(atitle),
                author=xml(auth),
                updated=updated,
                desc=desc,
                short_title=short_title,
                section_title=sectitle,
                href=article.href,
                word_count=str(1),
                id=xml(base_id)+'/'+secid+'/'+aid
            ))

    atom = SONY_ATOM.format(short_title=short_title,
            entries='\n\n'.join(entries), updated=updated,
            id=xml(base_id)).encode('utf-8')

    return metadata, atom