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
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)
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
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)
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