'Convenience method to return metadata as a :class:`Metadata` object.
Note that the list of formats is not verified.'

def get_metadata(self, idx, index_is_id=False, get_cover=False, get_user_categories=True, cover_as_data=False):

    idx = (idx if index_is_id else self.id(idx))
    try:
        row = self.data._data[idx]
    except:
        row = None
    if (row is None):
        raise ValueError(('No    book    with    id:    %d' % idx))
    fm = self.FIELD_MAP
    mi = Metadata(None, template_cache=self.formatter_template_cache)
    aut_list = row[fm['au_map']]
    if aut_list:
        aut_list = [p.split(':::') for p in aut_list.split(':#:') if p]
    else:
        aut_list = []
    aum = []
    aus = {}
    aul = {}
    try:
        for (author, author_sort, link) in aut_list:
            aut = author.replace('|', ',')
            aum.append(aut)
            aus[aut] = author_sort.replace('|', ',')
            aul[aut] = link
    except ValueError:
        for x in row[fm['authors']].split(','):
            aum.append(x.replace('|', ','))
            aul[aum[(-1)]] = ''
            aus[aum[(-1)]] = aum[(-1)]
    mi.title = row[fm['title']]
    mi.authors = aum
    mi.author_sort = row[fm['author_sort']]
    mi.author_sort_map = aus
    mi.author_link_map = aul
    mi.comments = row[fm['comments']]
    mi.publisher = row[fm['publisher']]
    mi.timestamp = row[fm['timestamp']]
    mi.pubdate = row[fm['pubdate']]
    mi.uuid = row[fm['uuid']]
    mi.title_sort = row[fm['sort']]
    mi.last_modified = row[fm['last_modified']]
    formats = row[fm['formats']]
    mi.format_metadata = {}
    if (not formats):
        good_formats = None
    else:
        formats = sorted(formats.split(','))
        mi.format_metadata = FormatMetadata(self, idx, formats)
        good_formats = FormatsList(formats, mi.format_metadata)
    mi.formats = good_formats
    mi.db_approx_formats = formats
    mi._proxy_metadata = p = ProxyMetadata(row[fm['size']], row[fm['ondevice']], formats)
    mi.book_size = p.book_size
    mi.ondevice_col = p.ondevice_col
    tags = row[fm['tags']]
    if tags:
        mi.tags = [i.strip() for i in tags.split(',')]
    languages = row[fm['languages']]
    if languages:
        mi.languages = [i.strip() for i in languages.split(',')]
    mi.series = row[fm['series']]
    if mi.series:
        mi.series_index = row[fm['series_index']]
    mi.rating = row[fm['rating']]
    mi.set_identifiers(self.get_identifiers(idx, index_is_id=True))
    mi.application_id = idx
    mi.id = idx
    mi.set_all_user_metadata(self.field_metadata.custom_field_metadata())
    for (key, meta) in self.field_metadata.custom_iteritems():
        if (meta['datatype'] == 'composite'):
            mi.set(key, val=row[meta['rec_index']])
        else:
            (val, extra) = self.get_custom_and_extra(idx, label=meta['label'], index_is_id=True)
            mi.set(key, val=val, extra=extra)
    user_cats = self.prefs['user_categories']
    user_cat_vals = {}
    if get_user_categories:
        for ucat in user_cats:
            res = []
            for (name, cat, ign) in user_cats[ucat]:
                v = mi.get(cat, None)
                if isinstance(v, list):
                    if (name in v):
                        res.append([name, cat])
                elif (name == v):
                    res.append([name, cat])
            user_cat_vals[ucat] = res
    mi.user_categories = user_cat_vals
    if get_cover:
        if cover_as_data:
            cdata = self.cover(idx, index_is_id=True)
            if cdata:
                mi.cover_data = ('jpeg', cdata)
        else:
            mi.cover = self.cover(idx, index_is_id=True, as_path=True)
    mi.has_cover = (_('Yes') if self.has_cover(idx) else '')
    return mi
