Ejemplo n.º 1
0
    def mobile(self,
               start='1',
               num='25',
               sort='date',
               search='',
               _=None,
               order='descending'):
        '''
        Serves metadata from the calibre database as XML.

        :param sort: Sort results by ``sort``. Can be one of `title,author,rating`.
        :param search: Filter results by ``search`` query. See :class:`SearchQueryParser` for query syntax
        :param start,num: Return the slice `[start:start+num]` of the sorted and filtered results
        :param _: Firefox seems to sometimes send this when using XMLHttpRequest with no caching
        '''
        try:
            start = int(start)
        except ValueError:
            raise cherrypy.HTTPError(400,
                                     'start: %s is not an integer' % start)
        try:
            num = int(num)
        except ValueError:
            raise cherrypy.HTTPError(400, 'num: %s is not an integer' % num)
        if not search:
            search = ''
        if isbytestring(search):
            search = search.decode('UTF-8')
        ids = self.db.search_getting_ids(search.strip(),
                                         self.search_restriction)
        FM = self.db.FIELD_MAP
        items = [r for r in iter(self.db) if r[FM['id']] in ids]
        if sort is not None:
            self.sort(items, sort, (order.lower().strip() == 'ascending'))

        CFM = self.db.field_metadata
        CKEYS = [
            key for key in sorted(custom_fields_to_display(self.db),
                                  key=lambda x: sort_key(CFM[x]['name']))
        ]
        # This method uses its own book dict, not the Metadata dict. The loop
        # below could be changed to use db.get_metadata instead of reading
        # info directly from the record made by the view, but it doesn't seem
        # worth it at the moment.
        books = []
        for record in items[(start - 1):(start - 1) + num]:
            book = {
                'formats': record[FM['formats']],
                'size': record[FM['size']]
            }
            if not book['formats']:
                book['formats'] = ''
            if not book['size']:
                book['size'] = 0
            book['size'] = human_readable(book['size'])

            aus = record[FM['authors']] if record[
                FM['authors']] else __builtin__._('Unknown')
            aut_is = CFM['authors']['is_multiple']
            authors = aut_is['list_to_ui'].join(
                [i.replace('|', ',') for i in aus.split(',')])
            book['authors'] = authors
            book['series_index'] = fmt_sidx(float(record[FM['series_index']]))
            book['series'] = record[FM['series']]
            book['tags'] = format_tag_string(record[FM['tags']],
                                             ',',
                                             no_tag_count=True)
            book['title'] = record[FM['title']]
            for x in ('timestamp', 'pubdate'):
                book[x] = strftime('%d %b, %Y', record[FM[x]])
            book['id'] = record[FM['id']]
            books.append(book)
            for key in CKEYS:

                def concat(name, val):
                    return '%s:#:%s' % (name, unicode(val))

                mi = self.db.get_metadata(record[CFM['id']['rec_index']],
                                          index_is_id=True)
                name, val = mi.format_field(key)
                if not val:
                    continue
                datatype = CFM[key]['datatype']
                if datatype in ['comments']:
                    continue
                if datatype == 'text' and CFM[key]['is_multiple']:
                    book[key] = concat(
                        name,
                        format_tag_string(
                            val,
                            CFM[key]['is_multiple']['ui_to_list'],
                            no_tag_count=True,
                            joinval=CFM[key]['is_multiple']['list_to_ui']))
                else:
                    book[key] = concat(name, val)

        updated = self.db.last_modified()

        cherrypy.response.headers['Content-Type'] = 'text/html; charset=utf-8'
        cherrypy.response.headers['Last-Modified'] = self.last_modified(
            updated)

        url_base = "/mobile?search=" + search + ";order=" + order + ";sort=" + sort + ";num=" + str(
            num)

        raw = html.tostring(build_index(books, num, search, sort, order, start,
                                        len(ids), url_base, CKEYS,
                                        self.opts.url_prefix),
                            encoding='utf-8',
                            pretty_print=True)
        # tostring's include_meta_content_type is broken
        raw = raw.replace(
            '<head>', '<head>\n'
            '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
        )
        return raw
Ejemplo n.º 2
0
    def xml(self, start='0', num='50', sort=None, search=None,
                _=None, order='ascending'):
        '''
        Serves metadata from the calibre database as XML.

        :param sort: Sort results by ``sort``. Can be one of `title,author,rating`.
        :param search: Filter results by ``search`` query. See :class:`SearchQueryParser` for query syntax
        :param start,num: Return the slice `[start:start+num]` of the sorted and filtered results
        :param _: Firefox seems to sometimes send this when using XMLHttpRequest with no caching
        '''
        try:
            start = int(start)
        except ValueError:
            raise cherrypy.HTTPError(400, 'start: %s is not an integer'%start)
        try:
            num = int(num)
        except ValueError:
            raise cherrypy.HTTPError(400, 'num: %s is not an integer'%num)

        order = order.lower().strip() == 'ascending'

        if not search:
            search = ''
        if isbytestring(search):
            search = search.decode('UTF-8')

        ids = self.search_for_books(search)

        FM = self.db.FIELD_MAP

        items = [r for r in iter(self.db) if r[FM['id']] in ids]
        if sort is not None:
            self.sort(items, sort, order)

        books = []

        def serialize(x):
            if isinstance(x, unicode):
                return x
            if isbytestring(x):
                return x.decode(preferred_encoding, 'replace')
            return unicode(x)

        # This method uses its own book dict, not the Metadata dict. The loop
        # below could be changed to use db.get_metadata instead of reading
        # info directly from the record made by the view, but it doesn't seem
        # worth it at the moment.
        for record in items[start:start+num]:
            kwargs = {}
            aus = record[FM['authors']] if record[FM['authors']] else __builtin__._('Unknown')
            authors = '|'.join([i.replace('|', ',') for i in aus.split(',')])
            kwargs['authors'] = authors

            kwargs['series_index'] = \
                fmt_sidx(float(record[FM['series_index']]))

            for x in ('timestamp', 'pubdate'):
                kwargs[x] = strftime('%Y/%m/%d %H:%M:%S', record[FM[x]])

            for x in ('id', 'title', 'sort', 'author_sort', 'rating', 'size'):
                kwargs[x] = serialize(record[FM[x]])

            for x in ('formats', 'series', 'tags', 'publisher',
                    'comments', 'identifiers'):
                y = record[FM[x]]
                if x == 'tags':
                    y = format_tag_string(y, ',', ignore_max=True)
                kwargs[x] = serialize(y) if y else ''

            isbn = self.db.isbn(record[FM['id']], index_is_id=True)
            kwargs['isbn'] = serialize(isbn if isbn else '')

            kwargs['safe_title'] = ascii_filename(kwargs['title'])

            c = kwargs.pop('comments')

            CFM = self.db.field_metadata
            CKEYS = [key for key in sorted(custom_fields_to_display(self.db),
                                           key=lambda x: sort_key(CFM[x]['name']))]
            custcols = []
            for key in CKEYS:
                def concat(name, val):
                    return '%s:#:%s'%(name, unicode(val))
                mi = self.db.get_metadata(record[CFM['id']['rec_index']], index_is_id=True)
                name, val = mi.format_field(key)
                if not val:
                    continue
                datatype = CFM[key]['datatype']
                if datatype in ['comments']:
                    continue
                k = str('CF_'+key[1:])
                name = CFM[key]['name']
                custcols.append(k)
                if datatype == 'text' and CFM[key]['is_multiple']:
                    kwargs[k] = \
                        concat('#T#'+name,
                               format_tag_string(val,
                                   CFM[key]['is_multiple']['ui_to_list'],
                                   ignore_max=True,
                                   joinval=CFM[key]['is_multiple']['list_to_ui']))
                else:
                    kwargs[k] = concat(name, val)
            kwargs['custcols'] = ','.join(custcols)
            books.append(E.book(c, **kwargs))

        updated = self.db.last_modified()
        kwargs = dict(
                start=str(start),
                updated=updated.strftime('%Y-%m-%dT%H:%M:%S+00:00'),
                total=str(len(ids)),
                num=str(len(books)))
        ans = E.library(*books, **kwargs)

        cherrypy.response.headers['Content-Type'] = 'text/xml'
        cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)

        return etree.tostring(ans, encoding='utf-8', pretty_print=True,
                xml_declaration=True)
Ejemplo n.º 3
0
    def mobile(self, start='1', num='25', sort='date', search='',
                _=None, order='descending'):
        '''
        Serves metadata from the calibre database as XML.

        :param sort: Sort results by ``sort``. Can be one of `title,author,rating`.
        :param search: Filter results by ``search`` query. See :class:`SearchQueryParser` for query syntax
        :param start,num: Return the slice `[start:start+num]` of the sorted and filtered results
        :param _: Firefox seems to sometimes send this when using XMLHttpRequest with no caching
        '''
        try:
            start = int(start)
        except ValueError:
            raise cherrypy.HTTPError(400, 'start: %s is not an integer'%start)
        try:
            num = int(num)
        except ValueError:
            raise cherrypy.HTTPError(400, 'num: %s is not an integer'%num)
        if not search:
            search = ''
        if isbytestring(search):
            search = search.decode('UTF-8')
        ids = self.db.search_getting_ids(search.strip(), self.search_restriction)
        FM = self.db.FIELD_MAP
        items = [r for r in iter(self.db) if r[FM['id']] in ids]
        if sort is not None:
            self.sort(items, sort, (order.lower().strip() == 'ascending'))

        CFM = self.db.field_metadata
        CKEYS = [key for key in sorted(custom_fields_to_display(self.db),
                                       key=lambda x:sort_key(CFM[x]['name']))]
        # This method uses its own book dict, not the Metadata dict. The loop
        # below could be changed to use db.get_metadata instead of reading
        # info directly from the record made by the view, but it doesn't seem
        # worth it at the moment.
        books = []
        for record in items[(start-1):(start-1)+num]:
            book = {'formats':record[FM['formats']], 'size':record[FM['size']]}
            if not book['formats']:
                book['formats'] = ''
            if not book['size']:
                book['size'] = 0
            book['size'] = human_readable(book['size'])

            aus = record[FM['authors']] if record[FM['authors']] else __builtin__._('Unknown')
            aut_is = CFM['authors']['is_multiple']
            authors = aut_is['list_to_ui'].join([i.replace('|', ',') for i in aus.split(',')])
            book['authors'] = authors
            book['series_index'] = fmt_sidx(float(record[FM['series_index']]))
            book['series'] = record[FM['series']]
            book['tags'] = format_tag_string(record[FM['tags']], ',',
                                             no_tag_count=True)
            book['title'] = record[FM['title']]
            for x in ('timestamp', 'pubdate'):
                book[x] = strftime('%d %b, %Y', record[FM[x]])
            book['id'] = record[FM['id']]
            books.append(book)
            for key in CKEYS:
                def concat(name, val):
                    return '%s:#:%s'%(name, unicode(val))
                mi = self.db.get_metadata(record[CFM['id']['rec_index']], index_is_id=True)
                name, val = mi.format_field(key)
                if not val:
                    continue
                datatype = CFM[key]['datatype']
                if datatype in ['comments']:
                    continue
                if datatype == 'text' and CFM[key]['is_multiple']:
                    book[key] = concat(name,
                                       format_tag_string(val,
                                           CFM[key]['is_multiple']['ui_to_list'],
                                           no_tag_count=True,
                                           joinval=CFM[key]['is_multiple']['list_to_ui']))
                else:
                    book[key] = concat(name, val)

        updated = self.db.last_modified()

        cherrypy.response.headers['Content-Type'] = 'text/html; charset=utf-8'
        cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)

        url_base = "/mobile?search=" + search+";order="+order+";sort="+sort+";num="+str(num)

        raw = html.tostring(build_index(books, num, search, sort, order,
                             start, len(ids), url_base, CKEYS,
                             self.opts.url_prefix),
                             encoding='utf-8',
                             pretty_print=True)
        # tostring's include_meta_content_type is broken
        raw = raw.replace('<head>', '<head>\n'
                '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">')
        return raw
Ejemplo n.º 4
0
    def xml(self,
            start='0',
            num='50',
            sort=None,
            search=None,
            _=None,
            order='ascending'):
        '''
        Serves metadata from the calibre database as XML.

        :param sort: Sort results by ``sort``. Can be one of `title,author,rating`.
        :param search: Filter results by ``search`` query. See :class:`SearchQueryParser` for query syntax
        :param start,num: Return the slice `[start:start+num]` of the sorted and filtered results
        :param _: Firefox seems to sometimes send this when using XMLHttpRequest with no caching
        '''
        try:
            start = int(start)
        except ValueError:
            raise cherrypy.HTTPError(400,
                                     'start: %s is not an integer' % start)
        try:
            num = int(num)
        except ValueError:
            raise cherrypy.HTTPError(400, 'num: %s is not an integer' % num)

        order = order.lower().strip() == 'ascending'

        if not search:
            search = ''
        if isbytestring(search):
            search = search.decode('UTF-8')

        ids = self.search_for_books(search)

        FM = self.db.FIELD_MAP

        items = [r for r in iter(self.db) if r[FM['id']] in ids]
        if sort is not None:
            self.sort(items, sort, order)

        books = []

        def serialize(x):
            if isinstance(x, unicode):
                return x
            if isbytestring(x):
                return x.decode(preferred_encoding, 'replace')
            return unicode(x)

        # This method uses its own book dict, not the Metadata dict. The loop
        # below could be changed to use db.get_metadata instead of reading
        # info directly from the record made by the view, but it doesn't seem
        # worth it at the moment.
        for record in items[start:start + num]:
            kwargs = {}
            aus = record[FM['authors']] if record[
                FM['authors']] else __builtin__._('Unknown')
            authors = '|'.join([i.replace('|', ',') for i in aus.split(',')])
            kwargs['authors'] = authors

            kwargs['series_index'] = \
                fmt_sidx(float(record[FM['series_index']]))

            for x in ('timestamp', 'pubdate'):
                kwargs[x] = strftime('%Y/%m/%d %H:%M:%S', record[FM[x]])

            for x in ('id', 'title', 'sort', 'author_sort', 'rating', 'size'):
                kwargs[x] = serialize(record[FM[x]])

            for x in ('formats', 'series', 'tags', 'publisher', 'comments',
                      'identifiers'):
                y = record[FM[x]]
                if x == 'tags':
                    y = format_tag_string(y, ',', ignore_max=True)
                kwargs[x] = serialize(y) if y else ''

            isbn = self.db.isbn(record[FM['id']], index_is_id=True)
            kwargs['isbn'] = serialize(isbn if isbn else '')

            kwargs['safe_title'] = ascii_filename(kwargs['title'])

            c = kwargs.pop('comments')

            CFM = self.db.field_metadata
            CKEYS = [
                key for key in sorted(custom_fields_to_display(self.db),
                                      key=lambda x: sort_key(CFM[x]['name']))
            ]
            custcols = []
            for key in CKEYS:

                def concat(name, val):
                    return '%s:#:%s' % (name, unicode(val))

                mi = self.db.get_metadata(record[CFM['id']['rec_index']],
                                          index_is_id=True)
                name, val = mi.format_field(key)
                if not val:
                    continue
                datatype = CFM[key]['datatype']
                if datatype in ['comments']:
                    continue
                k = str('CF_' + key[1:])
                name = CFM[key]['name']
                custcols.append(k)
                if datatype == 'text' and CFM[key]['is_multiple']:
                    kwargs[k] = \
                        concat('#T#'+name,
                               format_tag_string(val,
                                   CFM[key]['is_multiple']['ui_to_list'],
                                   ignore_max=True,
                                   joinval=CFM[key]['is_multiple']['list_to_ui']))
                else:
                    kwargs[k] = concat(name, val)
            kwargs['custcols'] = ','.join(custcols)
            books.append(E.book(c, **kwargs))

        updated = self.db.last_modified()
        kwargs = dict(start=str(start),
                      updated=updated.strftime('%Y-%m-%dT%H:%M:%S+00:00'),
                      total=str(len(ids)),
                      num=str(len(books)))
        ans = E.library(*books, **kwargs)

        cherrypy.response.headers['Content-Type'] = 'text/xml'
        cherrypy.response.headers['Last-Modified'] = self.last_modified(
            updated)

        return etree.tostring(ans,
                              encoding='utf-8',
                              pretty_print=True,
                              xml_declaration=True)
Ejemplo n.º 5
0
    def mobile(self, start="1", num="25", sort="date", search="", _=None, order="descending"):
        """
        Serves metadata from the calibre database as XML.

        :param sort: Sort results by ``sort``. Can be one of `title,author,rating`.
        :param search: Filter results by ``search`` query. See :class:`SearchQueryParser` for query syntax
        :param start,num: Return the slice `[start:start+num]` of the sorted and filtered results
        :param _: Firefox seems to sometimes send this when using XMLHttpRequest with no caching
        """
        try:
            start = int(start)
        except ValueError:
            raise cherrypy.HTTPError(400, "start: %s is not an integer" % start)
        try:
            num = int(num)
        except ValueError:
            raise cherrypy.HTTPError(400, "num: %s is not an integer" % num)
        if not search:
            search = ""
        if isbytestring(search):
            search = search.decode("UTF-8")
        ids = self.search_for_books(search)
        FM = self.db.FIELD_MAP
        items = [r for r in iter(self.db) if r[FM["id"]] in ids]
        if sort is not None:
            self.sort(items, sort, (order.lower().strip() == "ascending"))

        CFM = self.db.field_metadata
        CKEYS = [key for key in sorted(custom_fields_to_display(self.db), key=lambda x: sort_key(CFM[x]["name"]))]
        # This method uses its own book dict, not the Metadata dict. The loop
        # below could be changed to use db.get_metadata instead of reading
        # info directly from the record made by the view, but it doesn't seem
        # worth it at the moment.
        books = []
        for record in items[(start - 1) : (start - 1) + num]:
            book = {"formats": record[FM["formats"]], "size": record[FM["size"]]}
            if not book["formats"]:
                book["formats"] = ""
            if not book["size"]:
                book["size"] = 0
            book["size"] = human_readable(book["size"])

            aus = record[FM["authors"]] if record[FM["authors"]] else __builtin__._("Unknown")
            aut_is = CFM["authors"]["is_multiple"]
            authors = aut_is["list_to_ui"].join([i.replace("|", ",") for i in aus.split(",")])
            book["authors"] = authors
            book["series_index"] = fmt_sidx(float(record[FM["series_index"]]))
            book["series"] = record[FM["series"]]
            book["tags"] = format_tag_string(record[FM["tags"]], ",", no_tag_count=True)
            book["title"] = record[FM["title"]]
            for x in ("timestamp", "pubdate"):
                book[x] = strftime("%d %b, %Y", as_local_time(record[FM[x]]))
            book["id"] = record[FM["id"]]
            books.append(book)
            for key in CKEYS:

                def concat(name, val):
                    return "%s:#:%s" % (name, unicode(val))

                mi = self.db.get_metadata(record[CFM["id"]["rec_index"]], index_is_id=True)
                name, val = mi.format_field(key)
                if not val:
                    continue
                datatype = CFM[key]["datatype"]
                if datatype in ["comments"]:
                    continue
                if datatype == "text" and CFM[key]["is_multiple"]:
                    book[key] = concat(
                        name,
                        format_tag_string(
                            val,
                            CFM[key]["is_multiple"]["ui_to_list"],
                            no_tag_count=True,
                            joinval=CFM[key]["is_multiple"]["list_to_ui"],
                        ),
                    )
                else:
                    book[key] = concat(name, val)

        updated = self.db.last_modified()

        cherrypy.response.headers["Content-Type"] = "text/html; charset=utf-8"
        cherrypy.response.headers["Last-Modified"] = self.last_modified(updated)

        q = {
            b"search": search.encode("utf-8"),
            b"order": order.encode("utf-8"),
            b"sort": sort.encode("utf-8"),
            b"num": str(num).encode("utf-8"),
        }
        url_base = "/mobile?" + urlencode(q)
        ua = cherrypy.request.headers.get("User-Agent", "").strip()
        have_kobo_browser = self.is_kobo_browser(ua)

        raw = html.tostring(
            build_index(
                books,
                num,
                search,
                sort,
                order,
                start,
                len(ids),
                url_base,
                CKEYS,
                self.opts.url_prefix,
                have_kobo_browser=have_kobo_browser,
            ),
            encoding="utf-8",
            pretty_print=True,
        )
        # tostring's include_meta_content_type is broken
        raw = raw.replace("<head>", "<head>\n" '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">')
        return raw