Esempio n. 1
0
def urls_from_identifiers(identifiers):  # {{{
    identifiers = {k.lower(): v for k, v in identifiers.iteritems()}
    ans = []
    rules = msprefs['id_link_rules']
    if rules:
        formatter = EvalFormatter()
        for k, val in identifiers.iteritems():
            vals = {
                'id':
                quote(val if isinstance(val, bytes) else val.encode('utf-8')).
                decode('ascii')
            }
            items = rules.get(k) or ()
            for name, template in items:
                try:
                    url = formatter.safe_format(template, vals, '', vals)
                except Exception:
                    import traceback
                    traceback.format_exc()
                    continue
                ans.append((name, k, val, url))
    for plugin in all_metadata_plugins():
        try:
            for id_type, id_val, url in plugin.get_book_urls(identifiers):
                ans.append(
                    (plugin.get_book_url_name(id_type, id_val,
                                              url), id_type, id_val, url))
        except:
            pass
    isbn = identifiers.get('isbn', None)
    if isbn:
        ans.append(
            (isbn, 'isbn', isbn, 'http://www.worldcat.org/isbn/' + isbn))
    doi = identifiers.get('doi', None)
    if doi:
        ans.append(('DOI', 'doi', doi, 'http://dx.doi.org/' + doi))
    arxiv = identifiers.get('arxiv', None)
    if arxiv:
        ans.append(('arXiv', 'arxiv', arxiv, 'http://arxiv.org/abs/' + arxiv))
    oclc = identifiers.get('oclc', None)
    if oclc:
        ans.append(
            ('OCLC', 'oclc', oclc, 'http://www.worldcat.org/oclc/' + oclc))
    issn = check_issn(identifiers.get('issn', None))
    if issn:
        ans.append(
            (issn, 'issn', issn, 'http://www.worldcat.org/issn/' + issn))
    for k, url in identifiers.iteritems():
        if url and re.match(r'ur[il]\d*$', k) is not None:
            url = url[:8].replace('|', ':') + url[8:].replace('|', ',')
            if url.partition(':')[0].lower() in {'http', 'file', 'https'}:
                parts = urlparse(url)
                name = parts.netloc or parts.path
                ans.append((name, k, url, url))
    return ans
Esempio n. 2
0
 def compute_category_name(self, field_key, field_value, field_meta):
     renames = tweaks['sony_collection_renaming_rules']
     field_name = renames.get(field_key, None)
     if field_name is None:
         if field_meta['is_custom']:
             field_name = field_meta['name']
         else:
             field_name = ''
     cat_name = EvalFormatter().safe_format(
                     fmt=tweaks['sony_collection_name_template'],
                     kwargs={'category':field_name, 'value':field_value},
                     error_value='GET_CATEGORY', book=None)
     return cat_name.strip()
Esempio n. 3
0
def urls_from_identifiers(identifiers):  # {{{
    identifiers = {k.lower():v for k, v in identifiers.iteritems()}
    ans = []
    rules = msprefs['id_link_rules']
    if rules:
        formatter = EvalFormatter()
        for k, val in identifiers.iteritems():
            vals = {'id':quote(val if isinstance(val, bytes) else val.encode('utf-8')).decode('ascii')}
            items = rules.get(k) or ()
            for name, template in items:
                try:
                    url = formatter.safe_format(template, vals, '', vals)
                except Exception:
                    import traceback
                    traceback.format_exc()
                    continue
                ans.append((name, k, val, url))
    for plugin in all_metadata_plugins():
        try:
            for id_type, id_val, url in plugin.get_book_urls(identifiers):
                ans.append((plugin.get_book_url_name(id_type, id_val, url), id_type, id_val, url))
        except:
            pass
    isbn = identifiers.get('isbn', None)
    if isbn:
        ans.append((isbn, 'isbn', isbn,
            'http://www.worldcat.org/isbn/'+isbn))
    doi = identifiers.get('doi', None)
    if doi:
        ans.append(('DOI', 'doi', doi,
            'http://dx.doi.org/'+doi))
    arxiv = identifiers.get('arxiv', None)
    if arxiv:
        ans.append(('arXiv', 'arxiv', arxiv,
            'http://arxiv.org/abs/'+arxiv))
    oclc = identifiers.get('oclc', None)
    if oclc:
        ans.append(('OCLC', 'oclc', oclc,
            'http://www.worldcat.org/oclc/'+oclc))
    issn = check_issn(identifiers.get('issn', None))
    if issn:
        ans.append((issn, 'issn', issn,
            'http://www.worldcat.org/issn/'+issn))
    for k, url in identifiers.iteritems():
        if url and re.match(r'ur[il]\d*$', k) is not None:
            url = url[:8].replace('|', ':') + url[8:].replace('|', ',')
            if url.partition(':')[0].lower() in {'http', 'file', 'https'}:
                parts = urlparse(url)
                name = parts.netloc or parts.path
                ans.append((name, k, url, url))
    return ans
Esempio n. 4
0
 def compute_category_name(self, field_key, field_value, field_meta):
     from calibre.utils.formatter import EvalFormatter
     renames = tweaks['sony_collection_renaming_rules']
     field_name = renames.get(field_key, None)
     if field_name is None:
         if field_meta['is_custom']:
             field_name = field_meta['name']
         else:
             field_name = ''
     cat_name = EvalFormatter().safe_format(
                     fmt=tweaks['sony_collection_name_template'],
                     kwargs={'category':field_name, 'value':field_value},
                     error_value='GET_CATEGORY', book=None)
     return cat_name.strip()
Esempio n. 5
0
def fillout_tree(root, items, node_id_map, category_nodes, category_data,
                 field_metadata, opts, book_rating_map):
    eval_formatter = EvalFormatter()
    tag_map, hierarchical_tags, node_to_tag_map = {}, set(), {}
    first, later, collapse_nodes, intermediate_nodes, hierarchical_items = [], [], [], {}, set()
    # User categories have to be processed after normal categories as they can
    # reference hierarchical nodes that were created only during processing of
    # normal categories
    for category_node_id in category_nodes:
        cnode = items[category_node_id]
        coll = later if cnode.get('is_user_category', False) else first
        coll.append(node_id_map[category_node_id])

    for coll in (first, later):
        for cnode in coll:
            process_category_node(cnode, items, category_data, eval_formatter,
                                  field_metadata, opts, tag_map,
                                  hierarchical_tags, node_to_tag_map,
                                  collapse_nodes, intermediate_nodes,
                                  hierarchical_items)

    # Do not store id_set in the tag items as it is a lot of data, with not
    # much use. Instead only update the ratings and counts based on id_set
    for item_id in hierarchical_items:
        item = items[item_id]
        total = count = 0
        for book_id in item['id_set']:
            rating = book_rating_map.get(book_id, 0)
            if rating:
                total += rating / 2.0
                count += 1
        item['avg_rating'] = float(total) / count if count else 0

    for item_id, item in itervalues(tag_map):
        id_len = len(item.pop('id_set', ()))
        if id_len:
            item['count'] = id_len

    for node in collapse_nodes:
        item = items[node['id']]
        item['count'] = sum(1 for _ in iternode_descendants(node))
Esempio n. 6
0
def mi_to_html(mi, field_list=None, default_author_link=None, use_roman_numbers=True, rating_font='Liberation Serif', rtl=False):
    if field_list is None:
        field_list = get_field_list(mi)
    ans = []
    comment_fields = []
    isdevice = not hasattr(mi, 'id')
    row = u'<td class="title">%s</td><td class="value">%s</td>'
    p = prepare_string_for_xml
    a = partial(prepare_string_for_xml, attribute=True)
    book_id = getattr(mi, 'id', 0)

    for field in (field for field, display in field_list if display):
        try:
            metadata = mi.metadata_for_field(field)
        except:
            continue
        if not metadata:
            continue
        if field == 'sort':
            field = 'title_sort'
        if metadata['is_custom'] and metadata['datatype'] in {'bool', 'int', 'float'}:
            isnull = mi.get(field) is None
        else:
            isnull = mi.is_null(field)
        if isnull:
            continue
        name = metadata['name']
        if not name:
            name = field
        name += ':'
        if metadata['datatype'] == 'comments' or field == 'comments':
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                comment_fields.append(comments_to_html(val))
        elif metadata['datatype'] == 'rating':
            val = getattr(mi, field)
            if val:
                val = val/2.0
                ans.append((field,
                    u'<td class="title">%s</td><td class="rating value" '
                    'style=\'font-family:"%s"\'>%s</td>'%(
                        name, rating_font, u'\u2605'*int(val))))
        elif metadata['datatype'] == 'composite':
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                if metadata['display'].get('contains_html', False):
                    ans.append((field, row % (name, comments_to_html(val))))
                else:
                    if not metadata['is_multiple']:
                        val = '<a href="%s" title="%s">%s</a>' % (
                              search_href(field, val),
                              _('Click to see books with {0}: {1}').format(metadata['name'], a(val)), p(val))
                    else:
                        all_vals = [v.strip()
                            for v in val.split(metadata['is_multiple']['list_to_ui']) if v.strip()]
                        links = ['<a href="%s" title="%s">%s</a>' % (
                            search_href(field, x), _('Click to see books with {0}: {1}').format(
                                     metadata['name'], a(x)), p(x)) for x in all_vals]
                        val = metadata['is_multiple']['list_to_ui'].join(links)
                    ans.append((field, row % (name, val)))
        elif field == 'path':
            if mi.path:
                path = force_unicode(mi.path, filesystem_encoding)
                scheme = u'devpath' if isdevice else u'path'
                url = prepare_string_for_xml(path if isdevice else
                        unicode(book_id), True)
                pathstr = _('Click to open')
                extra = ''
                if isdevice:
                    durl = url
                    if durl.startswith('mtp:::'):
                        durl = ':::'.join((durl.split(':::'))[2:])
                    extra = '<br><span style="font-size:smaller">%s</span>'%(
                            prepare_string_for_xml(durl))
                link = u'<a href="%s:%s" title="%s">%s</a>%s' % (scheme, url,
                        prepare_string_for_xml(path, True), pathstr, extra)
                ans.append((field, row % (name, link)))
        elif field == 'formats':
            if isdevice:
                continue
            path = mi.path or ''
            bpath = ''
            if path:
                h, t = os.path.split(path)
                bpath = os.sep.join((os.path.basename(h), t))
            data = ({
                'fmt':x, 'path':a(path or ''), 'fname':a(mi.format_files.get(x, '')),
                'ext':x.lower(), 'id':book_id, 'bpath':bpath, 'sep':os.sep
            } for x in mi.formats)
            fmts = [u'<a data-full-path="{path}{sep}{fname}.{ext}" title="{bpath}{sep}{fname}.{ext}" href="format:{id}:{fmt}">{fmt}</a>'.format(**x)
                    for x in data]
            ans.append((field, row % (name, u', '.join(fmts))))
        elif field == 'identifiers':
            urls = urls_from_identifiers(mi.identifiers)
            links = [u'<a href="%s" title="%s:%s" data-item="%s">%s</a>' % (a(url), a(id_typ), a(id_val), a(item_data(field, id_typ, book_id)), p(namel))
                    for namel, id_typ, id_val, url in urls]
            links = u', '.join(links)
            if links:
                ans.append((field, row % (_('Ids')+':', links)))
        elif field == 'authors' and not isdevice:
            authors = []
            formatter = EvalFormatter()
            for aut in mi.authors:
                link = ''
                if mi.author_link_map[aut]:
                    link = lt = mi.author_link_map[aut]
                elif default_author_link:
                    if default_author_link == 'search-calibre':
                        link = search_href('authors', aut)
                        lt = a(_('Search the calibre library for books by %s') % aut)
                    else:
                        vals = {'author': aut.replace(' ', '+')}
                        try:
                            vals['author_sort'] =  mi.author_sort_map[aut].replace(' ', '+')
                        except:
                            vals['author_sort'] = aut.replace(' ', '+')
                        link = lt = a(formatter.safe_format(default_author_link, vals, '', vals))
                aut = p(aut)
                if link:
                    authors.append(u'<a calibre-data="authors" title="%s" href="%s">%s</a>'%(lt, link, aut))
                else:
                    authors.append(aut)
            ans.append((field, row % (name, u' & '.join(authors))))
        elif field == 'languages':
            if not mi.languages:
                continue
            names = filter(None, map(calibre_langcode_to_name, mi.languages))
            ans.append((field, row % (name, u', '.join(names))))
        elif field == 'publisher':
            if not mi.publisher:
                continue
            val = '<a href="%s" title="%s" data-item="%s">%s</a>' % (
                search_href('publisher', mi.publisher), _('Click to see books with {0}: {1}').format(metadata['name'], a(mi.publisher)),
                a(item_data('publisher', mi.publisher, book_id)), p(mi.publisher))
            ans.append((field, row % (name, val)))
        elif field == 'title':
            # otherwise title gets metadata['datatype'] == 'text'
            # treatment below with a click to search link (which isn't
            # too bad), and a right-click 'Delete' option to delete
            # the title (which is bad).
            val = mi.format_field(field)[-1]
            ans.append((field, row % (name, val)))
        else:
            val = mi.format_field(field)[-1]
            if val is None:
                continue
            val = p(val)
            if metadata['datatype'] == 'series':
                sidx = mi.get(field+'_index')
                if sidx is None:
                    sidx = 1.0
                try:
                    st = metadata['search_terms'][0]
                except Exception:
                    st = field
                series = getattr(mi, field)
                val = _(
                    '%(sidx)s of <a href="%(href)s" title="%(tt)s" data-item="%(data)s">'
                    '<span class="%(cls)s">%(series)s</span></a>') % dict(
                        sidx=fmt_sidx(sidx, use_roman=use_roman_numbers), cls="series_name",
                        series=p(series), href=search_href(st, series),
                        data=a(item_data(field, series, book_id)),
                        tt=p(_('Click to see books in this series')))
            elif metadata['datatype'] == 'datetime':
                aval = getattr(mi, field)
                if is_date_undefined(aval):
                    continue
            elif metadata['datatype'] == 'text' and metadata['is_multiple']:
                try:
                    st = metadata['search_terms'][0]
                except Exception:
                    st = field
                all_vals = mi.get(field)
                if field == 'tags':
                    all_vals = sorted(all_vals, key=sort_key)
                links = ['<a href="%s" title="%s" data-item="%s">%s</a>' % (
                    search_href(st, x), _('Click to see books with {0}: {1}').format(
                        metadata['name'], a(x)), a(item_data(field, x, book_id)), p(x))
                         for x in all_vals]
                val = metadata['is_multiple']['list_to_ui'].join(links)
            elif metadata['datatype'] == 'text' or metadata['datatype'] == 'enumeration':
                # text/is_multiple handled above so no need to add the test to the if
                try:
                    st = metadata['search_terms'][0]
                except Exception:
                    st = field
                val = '<a href="%s" title="%s" data-item="%s">%s</a>' % (
                    search_href(st, val), a(_('Click to see books with {0}: {1}').format(metadata['name'], val)),
                    a(item_data(field, val, book_id)), p(val))

            ans.append((field, row % (name, val)))

    dc = getattr(mi, 'device_collections', [])
    if dc:
        dc = u', '.join(sorted(dc, key=sort_key))
        ans.append(('device_collections',
            row % (_('Collections')+':', dc)))

    def classname(field):
        try:
            dt = mi.metadata_for_field(field)['datatype']
        except:
            dt = 'text'
        return 'datatype_%s'%dt

    ans = [u'<tr id="%s" class="%s">%s</tr>'%(fieldl.replace('#', '_'),
        classname(fieldl), html) for fieldl, html in ans]
    # print '\n'.join(ans)
    direction = 'rtl' if rtl else 'ltr'
    margin = 'left' if rtl else 'right'
    return u'<table class="fields" style="direction: %s; margin-%s:auto">%s</table>'%(direction, margin, u'\n'.join(ans)), comment_fields
Esempio n. 7
0
def render_data(mi, use_roman_numbers=True, all_fields=False):
    ans = []
    isdevice = not hasattr(mi, 'id')
    fm = getattr(mi, 'field_metadata', field_metadata)

    for field, display in get_field_list(fm):
        metadata = fm.get(field, None)
        if field == 'sort':
            field = 'title_sort'
        if all_fields:
            display = True
        if metadata['datatype'] == 'bool':
            isnull = mi.get(field) is None
        else:
            isnull = mi.is_null(field)
        if (not display or not metadata or isnull or field == 'comments'):
            continue
        name = metadata['name']
        if not name:
            name = field
        name += ':'
        if metadata['datatype'] == 'comments':
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                ans.append((field,
                    u'<td class="comments" colspan="2">%s</td>'%comments_to_html(val)))
        elif metadata['datatype'] == 'rating':
            val = getattr(mi, field)
            if val:
                val = val/2.0
                ans.append((field,
                    u'<td class="title">%s</td><td class="rating" '
                    'style=\'font-family:"%s"\'>%s</td>'%(
                        name, rating_font(), u'\u2605'*int(val))))
        elif metadata['datatype'] == 'composite' and \
                            metadata['display'].get('contains_html', False):
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                ans.append((field,
                    u'<td class="title">%s</td><td>%s</td>'%
                        (name, comments_to_html(val))))
        elif field == 'path':
            if mi.path:
                path = force_unicode(mi.path, filesystem_encoding)
                scheme = u'devpath' if isdevice else u'path'
                url = prepare_string_for_xml(path if isdevice else
                        unicode(mi.id), True)
                pathstr = _('Click to open')
                extra = ''
                if isdevice:
                    durl = url
                    if durl.startswith('mtp:::'):
                        durl = ':::'.join((durl.split(':::'))[2:])
                    extra = '<br><span style="font-size:smaller">%s</span>'%(
                            prepare_string_for_xml(durl))
                link = u'<a href="%s:%s" title="%s">%s</a>%s' % (scheme, url,
                        prepare_string_for_xml(path, True), pathstr, extra)
                ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name, link)))
        elif field == 'formats':
            if isdevice:
                continue
            fmts = [u'<a href="format:%s:%s">%s</a>' % (mi.id, x, x) for x
                        in mi.formats]
            ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name,
                u', '.join(fmts))))
        elif field == 'identifiers':
            urls = urls_from_identifiers(mi.identifiers)
            links = [u'<a href="%s" title="%s:%s">%s</a>' % (url, id_typ, id_val, name)
                    for name, id_typ, id_val, url in urls]
            links = u', '.join(links)
            if links:
                ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(
                    _('Ids')+':', links)))
        elif field == 'authors' and not isdevice:
            authors = []
            formatter = EvalFormatter()
            for aut in mi.authors:
                link = ''
                if mi.author_link_map[aut]:
                    link = mi.author_link_map[aut]
                elif gprefs.get('default_author_link'):
                    vals = {'author': aut.replace(' ', '+')}
                    try:
                        vals['author_sort'] =  mi.author_sort_map[aut].replace(' ', '+')
                    except:
                        vals['author_sort'] = aut.replace(' ', '+')
                    link = formatter.safe_format(
                            gprefs.get('default_author_link'), vals, '', vals)
                if link:
                    link = prepare_string_for_xml(link)
                    authors.append(u'<a calibre-data="authors" href="%s">%s</a>'%(link, aut))
                else:
                    authors.append(aut)
            ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name,
                u' & '.join(authors))))
        elif field == 'languages':
            if not mi.languages:
                continue
            names = filter(None, map(calibre_langcode_to_name, mi.languages))
            ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name,
                u', '.join(names))))
        else:
            val = mi.format_field(field)[-1]
            if val is None:
                continue
            val = prepare_string_for_xml(val)
            if metadata['datatype'] == 'series':
                sidx = mi.get(field+'_index')
                if sidx is None:
                    sidx = 1.0
                val = _('Book %(sidx)s of <span class="series_name">%(series)s</span>')%dict(
                        sidx=fmt_sidx(sidx, use_roman=use_roman_numbers),
                        series=prepare_string_for_xml(getattr(mi, field)))
            elif metadata['datatype'] == 'datetime':
                aval = getattr(mi, field)
                if is_date_undefined(aval):
                    continue

            ans.append((field, u'<td class="title">%s</td><td>%s</td>'%(name, val)))

    dc = getattr(mi, 'device_collections', [])
    if dc:
        dc = u', '.join(sorted(dc, key=sort_key))
        ans.append(('device_collections',
            u'<td class="title">%s</td><td>%s</td>'%(
                _('Collections')+':', dc)))

    def classname(field):
        try:
            dt = fm[field]['datatype']
        except:
            dt = 'text'
        return 'datatype_%s'%dt

    ans = [u'<tr id="%s" class="%s">%s</tr>'%(field.replace('#', '_'),
        classname(field), html) for field, html in ans]
    # print '\n'.join(ans)
    return u'<table class="fields">%s</table>'%(u'\n'.join(ans))
Esempio n. 8
0
def mi_to_html(mi,
               field_list=None,
               default_author_link=None,
               use_roman_numbers=True,
               rating_font='Liberation Serif',
               rtl=False):
    if field_list is None:
        field_list = get_field_list(mi)
    ans = []
    comment_fields = []
    isdevice = not hasattr(mi, 'id')
    row = u'<td class="title">%s</td><td class="value">%s</td>'
    p = prepare_string_for_xml
    a = partial(prepare_string_for_xml, attribute=True)
    book_id = getattr(mi, 'id', 0)

    for field in (field for field, display in field_list if display):
        try:
            metadata = mi.metadata_for_field(field)
        except:
            continue
        if not metadata:
            continue
        if field == 'sort':
            field = 'title_sort'
        if metadata['is_custom'] and metadata['datatype'] in {
                'bool', 'int', 'float'
        }:
            isnull = mi.get(field) is None
        else:
            isnull = mi.is_null(field)
        if isnull:
            continue
        name = metadata['name']
        if not name:
            name = field
        name += ':'
        disp = metadata['display']
        if metadata['datatype'] == 'comments' or field == 'comments':
            val = getattr(mi, field)
            if val:
                ctype = disp.get('interpret_as') or 'html'
                val = force_unicode(val)
                if ctype == 'long-text':
                    val = '<pre style="white-space:pre-wrap">%s</pre>' % p(val)
                elif ctype == 'short-text':
                    val = '<span>%s</span>' % p(val)
                elif ctype == 'markdown':
                    val = markdown(val)
                else:
                    val = comments_to_html(val)
                if disp.get('heading_position', 'hide') == 'side':
                    ans.append((field, row % (name, val)))
                else:
                    if disp.get('heading_position', 'hide') == 'above':
                        val = '<h3 class="comments-heading">%s</h3>%s' % (
                            p(name), val)
                    comment_fields.append(
                        '<div id="%s" class="comments">%s</div>' %
                        (field.replace('#', '_'), val))
        elif metadata['datatype'] == 'rating':
            val = getattr(mi, field)
            if val:
                star_string = rating_to_stars(
                    val, disp.get('allow_half_stars', False))
                ans.append(
                    (field,
                     u'<td class="title">%s</td><td class="rating value" '
                     'style=\'font-family:"%s"\'>%s</td>' %
                     (name, rating_font, star_string)))
        elif metadata['datatype'] == 'composite':
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                if disp.get('contains_html', False):
                    ans.append((field, row % (name, comments_to_html(val))))
                else:
                    if not metadata['is_multiple']:
                        val = '<a href="%s" title="%s">%s</a>' % (
                            search_action(field, val),
                            _('Click to see books with {0}: {1}').format(
                                metadata['name'], a(val)), p(val))
                    else:
                        all_vals = [
                            v.strip() for v in val.split(
                                metadata['is_multiple']['list_to_ui'])
                            if v.strip()
                        ]
                        links = [
                            '<a href="%s" title="%s">%s</a>' %
                            (search_action(field, x),
                             _('Click to see books with {0}: {1}').format(
                                 metadata['name'], a(x)), p(x))
                            for x in all_vals
                        ]
                        val = metadata['is_multiple']['list_to_ui'].join(links)
                    ans.append((field, row % (name, val)))
        elif field == 'path':
            if mi.path:
                path = force_unicode(mi.path, filesystem_encoding)
                scheme = u'devpath' if isdevice else u'path'
                loc = path if isdevice else book_id
                pathstr = _('Click to open')
                extra = ''
                if isdevice:
                    durl = path
                    if durl.startswith('mtp:::'):
                        durl = ':::'.join((durl.split(':::'))[2:])
                    extra = '<br><span style="font-size:smaller">%s</span>' % (
                        prepare_string_for_xml(durl))
                link = '<a href="%s" title="%s">%s</a>%s' % (action(
                    scheme, loc=loc), prepare_string_for_xml(
                        path, True), pathstr, extra)
                ans.append((field, row % (name, link)))
        elif field == 'formats':
            if isdevice:
                continue
            path = mi.path or ''
            bpath = ''
            if path:
                h, t = os.path.split(path)
                bpath = os.sep.join((os.path.basename(h), t))
            data = ({
                'fmt':
                x,
                'path':
                a(path or ''),
                'fname':
                a(mi.format_files.get(x, '')),
                'ext':
                x.lower(),
                'id':
                book_id,
                'bpath':
                bpath,
                'sep':
                os.sep,
                'action':
                action('format',
                       book_id=book_id,
                       fmt=x,
                       path=path or '',
                       fname=mi.format_files.get(x, ''))
            } for x in mi.formats)
            fmts = [
                '<a title="{bpath}{sep}{fname}.{ext}" href="{action}">{fmt}</a>'
                .format(**x) for x in data
            ]
            ans.append((field, row % (name, ', '.join(fmts))))
        elif field == 'identifiers':
            urls = urls_from_identifiers(mi.identifiers)
            links = [
                '<a href="%s" title="%s:%s">%s</a>' %
                (action('identifier',
                        url=url,
                        name=namel,
                        id_type=id_typ,
                        value=id_val,
                        field='identifiers',
                        book_id=book_id), a(id_typ), a(id_val), p(namel))
                for namel, id_typ, id_val, url in urls
            ]
            links = u', '.join(links)
            if links:
                ans.append((field, row % (_('Ids') + ':', links)))
        elif field == 'authors':
            authors = []
            formatter = EvalFormatter()
            for aut in mi.authors:
                link = ''
                if mi.author_link_map.get(aut):
                    link = lt = mi.author_link_map[aut]
                elif default_author_link:
                    if isdevice and default_author_link == 'search-calibre':
                        default_author_link = DEFAULT_AUTHOR_LINK
                    if default_author_link.startswith('search-'):
                        which_src = default_author_link.partition('-')[2]
                        link, lt = author_search_href(which_src,
                                                      title=mi.title,
                                                      author=aut)
                    else:
                        vals = {
                            'author': qquote(aut),
                            'title': qquote(mi.title)
                        }
                        try:
                            vals['author_sort'] = qquote(
                                mi.author_sort_map[aut])
                        except KeyError:
                            vals['author_sort'] = qquote(aut)
                        link = lt = formatter.safe_format(
                            default_author_link, vals, '', vals)
                aut = p(aut)
                if link:
                    authors.append(
                        '<a title="%s" href="%s">%s</a>' %
                        (a(lt), action('author', url=link, name=aut,
                                       title=lt), aut))
                else:
                    authors.append(aut)
            ans.append((field, row % (name, ' & '.join(authors))))
        elif field == 'languages':
            if not mi.languages:
                continue
            names = filter(None, map(calibre_langcode_to_name, mi.languages))
            names = [
                '<a href="%s" title="%s">%s</a>' %
                (search_action('languages', n),
                 _('Search calibre for books with the language: {}').format(n),
                 n) for n in names
            ]
            ans.append((field, row % (name, u', '.join(names))))
        elif field == 'publisher':
            if not mi.publisher:
                continue
            val = '<a href="%s" title="%s">%s</a>' % (search_action_with_data(
                'publisher', mi.publisher,
                book_id), _('Click to see books with {0}: {1}').format(
                    metadata['name'], a(mi.publisher)), p(mi.publisher))
            ans.append((field, row % (name, val)))
        elif field == 'title':
            # otherwise title gets metadata['datatype'] == 'text'
            # treatment below with a click to search link (which isn't
            # too bad), and a right-click 'Delete' option to delete
            # the title (which is bad).
            val = mi.format_field(field)[-1]
            ans.append((field, row % (name, val)))
        else:
            val = mi.format_field(field)[-1]
            if val is None:
                continue
            val = p(val)
            if metadata['datatype'] == 'series':
                sidx = mi.get(field + '_index')
                if sidx is None:
                    sidx = 1.0
                try:
                    st = metadata['search_terms'][0]
                except Exception:
                    st = field
                series = getattr(mi, field)
                val = _('%(sidx)s of <a href="%(href)s" title="%(tt)s">'
                        '<span class="%(cls)s">%(series)s</span></a>') % dict(
                            sidx=fmt_sidx(sidx, use_roman=use_roman_numbers),
                            cls="series_name",
                            series=p(series),
                            href=search_action_with_data(
                                st, series, book_id, field),
                            tt=p(_('Click to see books in this series')))
            elif metadata['datatype'] == 'datetime':
                aval = getattr(mi, field)
                if is_date_undefined(aval):
                    continue
            elif metadata['datatype'] == 'text' and metadata['is_multiple']:
                try:
                    st = metadata['search_terms'][0]
                except Exception:
                    st = field
                all_vals = mi.get(field)
                if not metadata.get('display', {}).get('is_names', False):
                    all_vals = sorted(all_vals, key=sort_key)
                links = [
                    '<a href="%s" title="%s">%s</a>' %
                    (search_action_with_data(st, x, book_id, field),
                     _('Click to see books with {0}: {1}').format(
                         metadata['name'], a(x)), p(x)) for x in all_vals
                ]
                val = metadata['is_multiple']['list_to_ui'].join(links)
            elif metadata['datatype'] == 'text' or metadata[
                    'datatype'] == 'enumeration':
                # text/is_multiple handled above so no need to add the test to the if
                try:
                    st = metadata['search_terms'][0]
                except Exception:
                    st = field
                val = '<a href="%s" title="%s">%s</a>' % (
                    search_action_with_data(st, val, book_id, field),
                    a(
                        _('Click to see books with {0}: {1}').format(
                            metadata['name'], val)), p(val))

            ans.append((field, row % (name, val)))

    dc = getattr(mi, 'device_collections', [])
    if dc:
        dc = u', '.join(sorted(dc, key=sort_key))
        ans.append(('device_collections', row % (_('Collections') + ':', dc)))

    def classname(field):
        try:
            dt = mi.metadata_for_field(field)['datatype']
        except:
            dt = 'text'
        return 'datatype_%s' % dt

    ans = [
        u'<tr id="%s" class="%s">%s</tr>' %
        (fieldl.replace('#', '_'), classname(fieldl), html)
        for fieldl, html in ans
    ]
    # print '\n'.join(ans)
    direction = 'rtl' if rtl else 'ltr'
    margin = 'left' if rtl else 'right'
    return u'<style>table.fields td { vertical-align:top}</style>' + \
           u'<table class="fields" style="direction: %s; margin-%s:auto">%s</table>'%(
               direction, margin, u'\n'.join(ans)), comment_fields
Esempio n. 9
0
def render_data(mi, use_roman_numbers=True, all_fields=False):
    ans = []
    isdevice = not hasattr(mi, 'id')
    fm = getattr(mi, 'field_metadata', field_metadata)

    for field, display in get_field_list(fm):
        metadata = fm.get(field, None)
        if field == 'sort':
            field = 'title_sort'
        if all_fields:
            display = True
        if metadata['datatype'] == 'bool':
            isnull = mi.get(field) is None
        else:
            isnull = mi.is_null(field)
        if (not display or not metadata or isnull or field == 'comments'):
            continue
        name = metadata['name']
        if not name:
            name = field
        name += ':'
        if metadata['datatype'] == 'comments':
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                ans.append(
                    (field, u'<td class="comments" colspan="2">%s</td>' %
                     comments_to_html(val)))
        elif metadata['datatype'] == 'rating':
            val = getattr(mi, field)
            if val:
                val = val / 2.0
                ans.append(
                    (field, u'<td class="title">%s</td><td class="rating" '
                     'style=\'font-family:"%s"\'>%s</td>' %
                     (name, rating_font(), u'\u2605' * int(val))))
        elif metadata['datatype'] == 'composite' and \
                            metadata['display'].get('contains_html', False):
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                ans.append((field, u'<td class="title">%s</td><td>%s</td>' %
                            (name, comments_to_html(val))))
        elif field == 'path':
            if mi.path:
                path = force_unicode(mi.path, filesystem_encoding)
                scheme = u'devpath' if isdevice else u'path'
                url = prepare_string_for_xml(
                    path if isdevice else unicode(mi.id), True)
                pathstr = _('Click to open')
                extra = ''
                if isdevice:
                    durl = url
                    if durl.startswith('mtp:::'):
                        durl = ':::'.join((durl.split(':::'))[2:])
                    extra = '<br><span style="font-size:smaller">%s</span>' % (
                        prepare_string_for_xml(durl))
                link = u'<a href="%s:%s" title="%s">%s</a>%s' % (
                    scheme, url, prepare_string_for_xml(path,
                                                        True), pathstr, extra)
                ans.append(
                    (field,
                     u'<td class="title">%s</td><td>%s</td>' % (name, link)))
        elif field == 'formats':
            if isdevice: continue
            fmts = [
                u'<a href="format:%s:%s">%s</a>' % (mi.id, x, x)
                for x in mi.formats
            ]
            ans.append((field, u'<td class="title">%s</td><td>%s</td>' %
                        (name, u', '.join(fmts))))
        elif field == 'identifiers':
            urls = urls_from_identifiers(mi.identifiers)
            links = [
                u'<a href="%s" title="%s:%s">%s</a>' %
                (url, id_typ, id_val, name)
                for name, id_typ, id_val, url in urls
            ]
            links = u', '.join(links)
            if links:
                ans.append((field, u'<td class="title">%s</td><td>%s</td>' %
                            (_('Ids') + ':', links)))
        elif field == 'authors' and not isdevice:
            authors = []
            formatter = EvalFormatter()
            for aut in mi.authors:
                link = ''
                if mi.author_link_map[aut]:
                    link = mi.author_link_map[aut]
                elif gprefs.get('default_author_link'):
                    vals = {'author': aut.replace(' ', '+')}
                    try:
                        vals['author_sort'] = mi.author_sort_map[aut].replace(
                            ' ', '+')
                    except:
                        vals['author_sort'] = aut.replace(' ', '+')
                    link = formatter.safe_format(
                        gprefs.get('default_author_link'), vals, '', vals)
                if link:
                    link = prepare_string_for_xml(link)
                    authors.append(u'<a href="%s">%s</a>' % (link, aut))
                else:
                    authors.append(aut)
            ans.append((field, u'<td class="title">%s</td><td>%s</td>' %
                        (name, u' & '.join(authors))))
        elif field == 'languages':
            if not mi.languages:
                continue
            names = filter(None, map(calibre_langcode_to_name, mi.languages))
            ans.append((field, u'<td class="title">%s</td><td>%s</td>' %
                        (name, u', '.join(names))))
        else:
            val = mi.format_field(field)[-1]
            if val is None:
                continue
            val = prepare_string_for_xml(val)
            if metadata['datatype'] == 'series':
                sidx = mi.get(field + '_index')
                if sidx is None:
                    sidx = 1.0
                val = _(
                    'Book %(sidx)s of <span class="series_name">%(series)s</span>'
                ) % dict(sidx=fmt_sidx(sidx, use_roman=use_roman_numbers),
                         series=prepare_string_for_xml(getattr(mi, field)))
            elif metadata['datatype'] == 'datetime':
                aval = getattr(mi, field)
                if is_date_undefined(aval):
                    continue

            ans.append(
                (field, u'<td class="title">%s</td><td>%s</td>' % (name, val)))

    dc = getattr(mi, 'device_collections', [])
    if dc:
        dc = u', '.join(sorted(dc, key=sort_key))
        ans.append(
            ('device_collections', u'<td class="title">%s</td><td>%s</td>' %
             (_('Collections') + ':', dc)))

    def classname(field):
        try:
            dt = fm[field]['datatype']
        except:
            dt = 'text'
        return 'datatype_%s' % dt

    ans = [
        u'<tr id="%s" class="%s">%s</tr>' %
        (field.replace('#', '_'), classname(field), html)
        for field, html in ans
    ]
    # print '\n'.join(ans)
    return u'<table class="fields">%s</table>' % (u'\n'.join(ans))
Esempio n. 10
0
def mi_to_html(mi, field_list=None, default_author_link=None, use_roman_numbers=True, rating_font='Liberation Serif'):
    if field_list is None:
        field_list = get_field_list(mi)
    ans = []
    comment_fields = []
    isdevice = not hasattr(mi, 'id')
    row = u'<td class="title">%s</td><td class="value">%s</td>'
    p = prepare_string_for_xml
    a = partial(prepare_string_for_xml, attribute=True)

    for field in (field for field, display in field_list if display):
        try:
            metadata = mi.metadata_for_field(field)
        except:
            continue
        if not metadata:
            continue
        if field == 'sort':
            field = 'title_sort'
        if metadata['datatype'] == 'bool':
            isnull = mi.get(field) is None
        else:
            isnull = mi.is_null(field)
        if isnull:
            continue
        name = metadata['name']
        if not name:
            name = field
        name += ':'
        if metadata['datatype'] == 'comments' or field == 'comments':
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                comment_fields.append(comments_to_html(val))
        elif metadata['datatype'] == 'rating':
            val = getattr(mi, field)
            if val:
                val = val/2.0
                ans.append((field,
                    u'<td class="title">%s</td><td class="rating value" '
                    'style=\'font-family:"%s"\'>%s</td>'%(
                        name, rating_font, u'\u2605'*int(val))))
        elif metadata['datatype'] == 'composite' and \
                            metadata['display'].get('contains_html', False):
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                ans.append((field,
                    row % (name, comments_to_html(val))))
        elif field == 'path':
            if mi.path:
                path = force_unicode(mi.path, filesystem_encoding)
                scheme = u'devpath' if isdevice else u'path'
                url = prepare_string_for_xml(path if isdevice else
                        unicode(mi.id), True)
                pathstr = _('Click to open')
                extra = ''
                if isdevice:
                    durl = url
                    if durl.startswith('mtp:::'):
                        durl = ':::'.join((durl.split(':::'))[2:])
                    extra = '<br><span style="font-size:smaller">%s</span>'%(
                            prepare_string_for_xml(durl))
                link = u'<a href="%s:%s" title="%s">%s</a>%s' % (scheme, url,
                        prepare_string_for_xml(path, True), pathstr, extra)
                ans.append((field, row % (name, link)))
        elif field == 'formats':
            if isdevice:
                continue
            path = ''
            if mi.path:
                h, t = os.path.split(mi.path)
                path = '/'.join((os.path.basename(h), t))
            data = ({
                'fmt':x, 'path':a(path or ''), 'fname':a(mi.format_files.get(x, '')),
                'ext':x.lower(), 'id':mi.id
            } for x in mi.formats)
            fmts = [u'<a title="{path}/{fname}.{ext}" href="format:{id}:{fmt}">{fmt}</a>'.format(**x) for x in data]
            ans.append((field, row % (name, u', '.join(fmts))))
        elif field == 'identifiers':
            urls = urls_from_identifiers(mi.identifiers)
            links = [u'<a href="%s" title="%s:%s">%s</a>' % (a(url), a(id_typ), a(id_val), p(name))
                    for name, id_typ, id_val, url in urls]
            links = u', '.join(links)
            if links:
                ans.append((field, row % (_('Ids')+':', links)))
        elif field == 'authors' and not isdevice:
            authors = []
            formatter = EvalFormatter()
            for aut in mi.authors:
                link = ''
                if mi.author_link_map[aut]:
                    link = mi.author_link_map[aut]
                elif default_author_link:
                    vals = {'author': aut.replace(' ', '+')}
                    try:
                        vals['author_sort'] =  mi.author_sort_map[aut].replace(' ', '+')
                    except:
                        vals['author_sort'] = aut.replace(' ', '+')
                    link = formatter.safe_format(
                            default_author_link, vals, '', vals)
                aut = p(aut)
                if link:
                    authors.append(u'<a calibre-data="authors" href="%s">%s</a>'%(a(link), aut))
                else:
                    authors.append(aut)
            ans.append((field, row % (name, u' & '.join(authors))))
        elif field == 'languages':
            if not mi.languages:
                continue
            names = filter(None, map(calibre_langcode_to_name, mi.languages))
            ans.append((field, row % (name, u', '.join(names))))
        else:
            val = mi.format_field(field)[-1]
            if val is None:
                continue
            val = p(val)
            if metadata['datatype'] == 'series':
                sidx = mi.get(field+'_index')
                if sidx is None:
                    sidx = 1.0
                val = _('Book %(sidx)s of <span class="series_name">%(series)s</span>')%dict(
                        sidx=fmt_sidx(sidx, use_roman=use_roman_numbers),
                        series=p(getattr(mi, field)))
            elif metadata['datatype'] == 'datetime':
                aval = getattr(mi, field)
                if is_date_undefined(aval):
                    continue

            ans.append((field, row % (name, val)))

    dc = getattr(mi, 'device_collections', [])
    if dc:
        dc = u', '.join(sorted(dc, key=sort_key))
        ans.append(('device_collections',
            row % (_('Collections')+':', dc)))

    def classname(field):
        try:
            dt = mi.metadata_for_field(field)['datatype']
        except:
            dt = 'text'
        return 'datatype_%s'%dt

    ans = [u'<tr id="%s" class="%s">%s</tr>'%(field.replace('#', '_'),
        classname(field), html) for field, html in ans]
    # print '\n'.join(ans)
    return u'<table class="fields">%s</table>'%(u'\n'.join(ans)), comment_fields
Esempio n. 11
0
def urls_from_identifiers(identifiers, sort_results=False):  # {{{
    identifiers = {k.lower(): v for k, v in iteritems(identifiers)}
    ans = []
    keys_left = set(identifiers)

    def add(name, k, val, url):
        ans.append((name, k, val, url))
        keys_left.discard(k)

    rules = msprefs['id_link_rules']
    if rules:
        formatter = EvalFormatter()
        for k, val in iteritems(identifiers):
            val = val.replace('|', ',')
            vals = {
                'id':
                unicode_type(
                    quote(val if isinstance(val, bytes) else val.encode('utf-8'
                                                                        ))),
                'id_unquoted':
                str(val),
            }
            items = rules.get(k) or ()
            for name, template in items:
                try:
                    url = formatter.safe_format(template, vals, '', vals)
                except Exception:
                    import traceback
                    traceback.format_exc()
                    continue
                add(name, k, val, url)
    for plugin in all_metadata_plugins():
        try:
            for id_type, id_val, url in plugin.get_book_urls(identifiers):
                add(plugin.get_book_url_name(id_type, id_val, url), id_type,
                    id_val, url)
        except Exception:
            pass
    isbn = identifiers.get('isbn', None)
    if isbn:
        add(isbn, 'isbn', isbn, 'https://www.worldcat.org/isbn/' + isbn)
    doi = identifiers.get('doi', None)
    if doi:
        add('DOI', 'doi', doi, 'https://dx.doi.org/' + doi)
    arxiv = identifiers.get('arxiv', None)
    if arxiv:
        add('arXiv', 'arxiv', arxiv, 'https://arxiv.org/abs/' + arxiv)
    oclc = identifiers.get('oclc', None)
    if oclc:
        add('OCLC', 'oclc', oclc, 'https://www.worldcat.org/oclc/' + oclc)
    issn = check_issn(identifiers.get('issn', None))
    if issn:
        add(issn, 'issn', issn, 'https://www.worldcat.org/issn/' + issn)
    q = {'http', 'https', 'file'}
    for k, url in iteritems(identifiers):
        if url and re.match(r'ur[il]\d*$', k) is not None:
            url = url[:8].replace('|', ':') + url[8:].replace('|', ',')
            if url.partition(':')[0].lower() in q:
                parts = urlparse(url)
                name = parts.netloc or parts.path
                add(name, k, url, url)
    for k in tuple(keys_left):
        val = identifiers.get(k)
        if val:
            url = val[:8].replace('|', ':') + val[8:].replace('|', ',')
            if url.partition(':')[0].lower() in q:
                parts = urlparse(url)
                name = parts.netloc or parts.path
                add(name, k, url, url)
    if sort_results:

        def url_key(x):
            return primary_sort_key(str(x[0]))

        ans = sorted(ans, key=url_key)
    return ans
Esempio n. 12
0
def render_data(mi, use_roman_numbers=True, all_fields=False):
    ans = []
    comment_fields = []
    isdevice = not hasattr(mi, "id")
    fm = getattr(mi, "field_metadata", field_metadata)
    row = u'<td class="title">%s</td><td class="value">%s</td>'

    for field, display in get_field_list(fm):
        metadata = fm.get(field, None)
        if field == "sort":
            field = "title_sort"
        if all_fields:
            display = True
        if metadata["datatype"] == "bool":
            isnull = mi.get(field) is None
        else:
            isnull = mi.is_null(field)
        if not display or not metadata or isnull:
            continue
        name = metadata["name"]
        if not name:
            name = field
        name += ":"
        if metadata["datatype"] == "comments" or field == "comments":
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                comment_fields.append(comments_to_html(val))
        elif metadata["datatype"] == "rating":
            val = getattr(mi, field)
            if val:
                val = val / 2.0
                ans.append(
                    (
                        field,
                        u'<td class="title">%s</td><td class="rating value" '
                        "style='font-family:\"%s\"'>%s</td>" % (name, rating_font(), u"\u2605" * int(val)),
                    )
                )
        elif metadata["datatype"] == "composite" and metadata["display"].get("contains_html", False):
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                ans.append((field, row % (name, comments_to_html(val))))
        elif field == "path":
            if mi.path:
                path = force_unicode(mi.path, filesystem_encoding)
                scheme = u"devpath" if isdevice else u"path"
                url = prepare_string_for_xml(path if isdevice else unicode(mi.id), True)
                pathstr = _("Click to open")
                extra = ""
                if isdevice:
                    durl = url
                    if durl.startswith("mtp:::"):
                        durl = ":::".join((durl.split(":::"))[2:])
                    extra = '<br><span style="font-size:smaller">%s</span>' % (prepare_string_for_xml(durl))
                link = u'<a href="%s:%s" title="%s">%s</a>%s' % (
                    scheme,
                    url,
                    prepare_string_for_xml(path, True),
                    pathstr,
                    extra,
                )
                ans.append((field, row % (name, link)))
        elif field == "formats":
            if isdevice:
                continue
            fmts = [u'<a href="format:%s:%s">%s</a>' % (mi.id, x, x) for x in mi.formats]
            ans.append((field, row % (name, u", ".join(fmts))))
        elif field == "identifiers":
            urls = urls_from_identifiers(mi.identifiers)
            links = [
                u'<a href="%s" title="%s:%s">%s</a>' % (url, id_typ, id_val, name) for name, id_typ, id_val, url in urls
            ]
            links = u", ".join(links)
            if links:
                ans.append((field, row % (_("Ids") + ":", links)))
        elif field == "authors" and not isdevice:
            authors = []
            formatter = EvalFormatter()
            for aut in mi.authors:
                link = ""
                if mi.author_link_map[aut]:
                    link = mi.author_link_map[aut]
                elif gprefs.get("default_author_link"):
                    vals = {"author": aut.replace(" ", "+")}
                    try:
                        vals["author_sort"] = mi.author_sort_map[aut].replace(" ", "+")
                    except:
                        vals["author_sort"] = aut.replace(" ", "+")
                    link = formatter.safe_format(gprefs.get("default_author_link"), vals, "", vals)
                if link:
                    link = prepare_string_for_xml(link)
                    authors.append(u'<a calibre-data="authors" href="%s">%s</a>' % (link, aut))
                else:
                    authors.append(aut)
            ans.append((field, row % (name, u" & ".join(authors))))
        elif field == "languages":
            if not mi.languages:
                continue
            names = filter(None, map(calibre_langcode_to_name, mi.languages))
            ans.append((field, row % (name, u", ".join(names))))
        else:
            val = mi.format_field(field)[-1]
            if val is None:
                continue
            val = prepare_string_for_xml(val)
            if metadata["datatype"] == "series":
                sidx = mi.get(field + "_index")
                if sidx is None:
                    sidx = 1.0
                val = _('Book %(sidx)s of <span class="series_name">%(series)s</span>') % dict(
                    sidx=fmt_sidx(sidx, use_roman=use_roman_numbers), series=prepare_string_for_xml(getattr(mi, field))
                )
            elif metadata["datatype"] == "datetime":
                aval = getattr(mi, field)
                if is_date_undefined(aval):
                    continue

            ans.append((field, row % (name, val)))

    dc = getattr(mi, "device_collections", [])
    if dc:
        dc = u", ".join(sorted(dc, key=sort_key))
        ans.append(("device_collections", row % (_("Collections") + ":", dc)))

    def classname(field):
        try:
            dt = fm[field]["datatype"]
        except:
            dt = "text"
        return "datatype_%s" % dt

    ans = [u'<tr id="%s" class="%s">%s</tr>' % (field.replace("#", "_"), classname(field), html) for field, html in ans]
    # print '\n'.join(ans)
    return u'<table class="fields">%s</table>' % (u"\n".join(ans)), comment_fields
Esempio n. 13
0
def mi_to_html(mi,
               field_list=None,
               default_author_link=None,
               use_roman_numbers=True,
               rating_font='Liberation Serif'):
    if field_list is None:
        field_list = get_field_list(mi)
    ans = []
    comment_fields = []
    isdevice = not hasattr(mi, 'id')
    row = u'<td class="title">%s</td><td class="value">%s</td>'
    p = prepare_string_for_xml
    a = partial(prepare_string_for_xml, attribute=True)

    for field in (field for field, display in field_list if display):
        try:
            metadata = mi.metadata_for_field(field)
        except:
            continue
        if not metadata:
            continue
        if field == 'sort':
            field = 'title_sort'
        if metadata['datatype'] == 'bool':
            isnull = mi.get(field) is None
        else:
            isnull = mi.is_null(field)
        if isnull:
            continue
        name = metadata['name']
        if not name:
            name = field
        name += ':'
        if metadata['datatype'] == 'comments' or field == 'comments':
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                comment_fields.append(comments_to_html(val))
        elif metadata['datatype'] == 'rating':
            val = getattr(mi, field)
            if val:
                val = val / 2.0
                ans.append(
                    (field,
                     u'<td class="title">%s</td><td class="rating value" '
                     'style=\'font-family:"%s"\'>%s</td>' %
                     (name, rating_font, u'\u2605' * int(val))))
        elif metadata['datatype'] == 'composite' and \
                            metadata['display'].get('contains_html', False):
            val = getattr(mi, field)
            if val:
                val = force_unicode(val)
                ans.append((field, row % (name, comments_to_html(val))))
        elif field == 'path':
            if mi.path:
                path = force_unicode(mi.path, filesystem_encoding)
                scheme = u'devpath' if isdevice else u'path'
                url = prepare_string_for_xml(
                    path if isdevice else unicode(mi.id), True)
                pathstr = _('Click to open')
                extra = ''
                if isdevice:
                    durl = url
                    if durl.startswith('mtp:::'):
                        durl = ':::'.join((durl.split(':::'))[2:])
                    extra = '<br><span style="font-size:smaller">%s</span>' % (
                        prepare_string_for_xml(durl))
                link = u'<a href="%s:%s" title="%s">%s</a>%s' % (
                    scheme, url, prepare_string_for_xml(path,
                                                        True), pathstr, extra)
                ans.append((field, row % (name, link)))
        elif field == 'formats':
            if isdevice:
                continue
            path = ''
            if mi.path:
                h, t = os.path.split(mi.path)
                path = '/'.join((os.path.basename(h), t))
            data = ({
                'fmt': x,
                'path': a(path or ''),
                'fname': a(mi.format_files.get(x, '')),
                'ext': x.lower(),
                'id': mi.id
            } for x in mi.formats)
            fmts = [
                u'<a title="{path}/{fname}.{ext}" href="format:{id}:{fmt}">{fmt}</a>'
                .format(**x) for x in data
            ]
            ans.append((field, row % (name, u', '.join(fmts))))
        elif field == 'identifiers':
            urls = urls_from_identifiers(mi.identifiers)
            links = [
                u'<a href="%s" title="%s:%s">%s</a>' %
                (a(url), a(id_typ), a(id_val), p(namel))
                for namel, id_typ, id_val, url in urls
            ]
            links = u', '.join(links)
            if links:
                ans.append((field, row % (_('Ids') + ':', links)))
        elif field == 'authors' and not isdevice:
            authors = []
            formatter = EvalFormatter()
            for aut in mi.authors:
                link = ''
                if mi.author_link_map[aut]:
                    link = mi.author_link_map[aut]
                elif default_author_link:
                    vals = {'author': aut.replace(' ', '+')}
                    try:
                        vals['author_sort'] = mi.author_sort_map[aut].replace(
                            ' ', '+')
                    except:
                        vals['author_sort'] = aut.replace(' ', '+')
                    link = formatter.safe_format(default_author_link, vals, '',
                                                 vals)
                aut = p(aut)
                if link:
                    authors.append(
                        u'<a calibre-data="authors" title="%s" href="%s">%s</a>'
                        % (a(link), a(link), aut))
                else:
                    authors.append(aut)
            ans.append((field, row % (name, u' & '.join(authors))))
        elif field == 'languages':
            if not mi.languages:
                continue
            names = filter(None, map(calibre_langcode_to_name, mi.languages))
            ans.append((field, row % (name, u', '.join(names))))
        else:
            val = mi.format_field(field)[-1]
            if val is None:
                continue
            val = p(val)
            if metadata['datatype'] == 'series':
                sidx = mi.get(field + '_index')
                if sidx is None:
                    sidx = 1.0
                val = _(
                    'Book %(sidx)s of <span class="series_name">%(series)s</span>'
                ) % dict(sidx=fmt_sidx(sidx, use_roman=use_roman_numbers),
                         series=p(getattr(mi, field)))
            elif metadata['datatype'] == 'datetime':
                aval = getattr(mi, field)
                if is_date_undefined(aval):
                    continue

            ans.append((field, row % (name, val)))

    dc = getattr(mi, 'device_collections', [])
    if dc:
        dc = u', '.join(sorted(dc, key=sort_key))
        ans.append(('device_collections', row % (_('Collections') + ':', dc)))

    def classname(field):
        try:
            dt = mi.metadata_for_field(field)['datatype']
        except:
            dt = 'text'
        return 'datatype_%s' % dt

    ans = [
        u'<tr id="%s" class="%s">%s</tr>' %
        (fieldl.replace('#', '_'), classname(fieldl), html)
        for fieldl, html in ans
    ]
    # print '\n'.join(ans)
    return u'<table class="fields">%s</table>' % (
        u'\n'.join(ans)), comment_fields