def search_result(ctx, rd, db, query, num, offset, sort, sort_order): multisort = [ (sanitize_sort_field_name(db.field_metadata, s), ensure_val(o, 'asc', 'desc') == 'asc') for s, o in zip(sort.split(','), cycle(sort_order.split(','))) ] skeys = db.field_metadata.sortable_field_keys() for sfield, sorder in multisort: if sfield not in skeys: raise HTTPNotFound('%s is not a valid sort field' % sort) if not query: ids = ctx.allowed_book_ids(rd, db) else: ids = ctx.search(rd, db, query) ids = db.multisort(fields=multisort, ids_to_sort=ids) total_num = len(ids) ids = ids[offset:offset + num] return { 'total_num': total_num, 'sort_order': sort_order, 'offset': offset, 'num': len(ids), 'sort': sort, 'base_url': ctx.url_for(search, library_id=db.server_library_id), 'query': query, 'library_id': db.server_library_id, 'book_ids': ids }
def search_result(ctx, rd, db, query, num, offset, sort, sort_order): multisort = [ (sanitize_sort_field_name(db.field_metadata, s), ensure_val(o, "asc", "desc") == "asc") for s, o in zip(sort.split(","), cycle(sort_order.split(","))) ] skeys = db.field_metadata.sortable_field_keys() for sfield, sorder in multisort: if sfield not in skeys: raise HTTPNotFound("%s is not a valid sort field" % sort) if not query: ids = ctx.allowed_book_ids(rd, db) else: ids = ctx.search(rd, db, query) ids = db.multisort(fields=multisort, ids_to_sort=ids) total_num = len(ids) ids = ids[offset : offset + num] return { "total_num": total_num, "sort_order": sort_order, "offset": offset, "num": len(ids), "sort": sort, "base_url": ctx.url_for(search, library_id=db.server_library_id), "query": query, "book_ids": ids, }
def search_result(ctx, rd, db, query, num, offset, sort, sort_order, vl=''): multisort = [ (sanitize_sort_field_name(db.field_metadata, s), ensure_val(o, 'asc', 'desc') == 'asc') for s, o in zip(sort.split(','), cycle(sort_order.split(','))) ] skeys = db.field_metadata.sortable_field_keys() for sfield, sorder in multisort: if sfield not in skeys: raise HTTPNotFound('%s is not a valid sort field' % sort) ids, parse_error = ctx.search(rd, db, query, vl=vl, report_restriction_errors=True) ids = db.multisort(fields=multisort, ids_to_sort=ids) total_num = len(ids) ids = ids[offset:offset + num] ans = { 'total_num': total_num, 'sort_order': sort_order, 'offset': offset, 'num': len(ids), 'sort': sort, 'base_url': ctx.url_for(search, library_id=db.server_library_id), 'query': query, 'library_id': db.server_library_id, 'book_ids': ids, 'vl': vl, } if parse_error is not None: ans['bad_restriction'] = unicode_type(parse_error) return ans
def mobile(ctx, rd): db, library_id, library_map, default_library = get_library_data(ctx, rd) try: start = max(1, int(rd.query.get('start', 1))) except ValueError: raise HTTPBadRequest('start is not an integer') try: num = max(0, int(rd.query.get('num', 25))) except ValueError: raise HTTPBadRequest('num is not an integer') search = rd.query.get('search') or '' with db.safe_read_lock: book_ids = ctx.search(rd, db, search) total = len(book_ids) ascending = rd.query.get('order', '').lower().strip() == 'ascending' sort_by = sanitize_sort_field_name(db.field_metadata, rd.query.get('sort') or 'date') try: book_ids = db.multisort([(sort_by, ascending)], book_ids) except Exception: sort_by = 'date' book_ids = db.multisort([(sort_by, ascending)], book_ids) books = [db.get_metadata(book_id) for book_id in book_ids[(start-1):(start-1)+num]] rd.outheaders['Last-Modified'] = http_date(timestampfromdt(db.last_modified())) order = 'ascending' if ascending else 'descending' q = {b'search':search.encode('utf-8'), b'order':bytes(order), b'sort':sort_by.encode('utf-8'), b'num':bytes(num), 'library_id':library_id} url_base = ctx.url_for('/mobile') + '?' + urlencode(q) lm = {k:v for k, v in library_map.iteritems() if k != library_id} return build_index(books, num, search, sort_by, order, start, total, url_base, db.field_metadata, ctx, lm, library_id)
def get_library_init_data(ctx, rd, db, num, sorts, orders, vl): ans = {} with db.safe_read_lock: try: ans['search_result'] = search_result(ctx, rd, db, rd.query.get('search', ''), num, 0, ','.join(sorts), ','.join(orders), vl) except ParseException: ans['search_result'] = search_result(ctx, rd, db, '', num, 0, ','.join(sorts), ','.join(orders), vl) sf = db.field_metadata.ui_sortable_field_keys() sf.pop('ondevice', None) ans['sortable_fields'] = sorted( ((sanitize_sort_field_name(db.field_metadata, k), v) for k, v in sf.iteritems()), key=lambda field_name: sort_key(field_name[1])) ans['field_metadata'] = db.field_metadata.all_metadata() ans['virtual_libraries'] = db._pref('virtual_libraries', {}) ans['book_display_fields'] = get_field_list(db) mdata = ans['metadata'] = {} try: extra_books = set( int(x) for x in rd.query.get('extra_books', '').split(',')) except Exception: extra_books = () for coll in (ans['search_result']['book_ids'], extra_books): for book_id in coll: if book_id not in mdata: data = book_as_json(db, book_id) if data is not None: mdata[book_id] = data return ans
def mobile(ctx, rd): db, library_id, library_map, default_library = get_library_data(ctx, rd) try: start = max(1, int(rd.query.get('start', 1))) except ValueError: raise HTTPBadRequest('start is not an integer') try: num = max(0, int(rd.query.get('num', 25))) except ValueError: raise HTTPBadRequest('num is not an integer') search = rd.query.get('search') or '' with db.safe_read_lock: book_ids = ctx.search(rd, db, search) total = len(book_ids) ascending = rd.query.get('order', '').lower().strip() == 'ascending' sort_by = sanitize_sort_field_name(db.field_metadata, rd.query.get('sort') or 'date') try: book_ids = db.multisort([(sort_by, ascending)], book_ids) except Exception: sort_by = 'date' book_ids = db.multisort([(sort_by, ascending)], book_ids) books = [db.get_metadata(book_id) for book_id in book_ids[(start-1):(start-1)+num]] rd.outheaders['Last-Modified'] = http_date(timestampfromdt(db.last_modified())) order = 'ascending' if ascending else 'descending' q = {b'search':search.encode('utf-8'), b'order':bytes(order), b'sort':sort_by.encode('utf-8'), b'num':bytes(num), 'library_id':library_id} url_base = ctx.url_for('/mobile') + '?' + urlencode(q) lm = {k:v for k, v in iteritems(library_map) if k != library_id} return build_index(rd, books, num, search, sort_by, order, start, total, url_base, db.field_metadata, ctx, lm, library_id)
def get_library_init_data(ctx, rd, db, num, sorts, orders): ans = {} with db.safe_read_lock: try: ans['search_result'] = search_result(ctx, rd, db, rd.query.get('search', ''), num, 0, ','.join(sorts), ','.join(orders)) except ParseException: ans['search_result'] = search_result(ctx, rd, db, '', num, 0, ','.join(sorts), ','.join(orders)) sf = db.field_metadata.ui_sortable_field_keys() sf.pop('ondevice', None) ans['sortable_fields'] = sorted((( sanitize_sort_field_name(db.field_metadata, k), v) for k, v in sf.iteritems()), key=lambda (field, name):sort_key(name)) ans['field_metadata'] = db.field_metadata.all_metadata() mdata = ans['metadata'] = {} try: extra_books = set(int(x) for x in rd.query.get('extra_books', '').split(',')) except Exception: extra_books = () for coll in (ans['search_result']['book_ids'], extra_books): for book_id in coll: if book_id not in mdata: data = book_as_json(db, book_id) if data is not None: mdata[book_id] = data return ans
def interface_data(ctx, rd): ''' Return the data needed to create the server main UI Optional: ?num=50&sort=timestamp.desc&library_id=<default library> &search=''&extra_books='' ''' ans = { 'username':rd.username, 'output_format':prefs['output_format'].upper(), 'input_formats':{x.upper():True for x in available_input_formats()}, 'gui_pubdate_display_format':tweaks['gui_pubdate_display_format'], 'gui_timestamp_display_format':tweaks['gui_timestamp_display_format'], 'gui_last_modified_display_format':tweaks['gui_last_modified_display_format'], 'use_roman_numerals_for_series_number': get_use_roman(), } ans['library_map'], ans['default_library'] = ctx.library_info(rd) ud = {} if rd.username: # Override session data with stored values for the authenticated user, # if any ud = ctx.user_manager.get_session_data(rd.username) lid = ud.get('library_id') if lid and lid in ans['library_map']: rd.query.set('library_id', lid) usort = ud.get('sort') if usort: rd.query.set('sort', usort) ans['library_id'], db, sorts, orders = get_basic_query_data(ctx, rd) ans['user_session_data'] = ud try: num = int(rd.query.get('num', DEFAULT_NUMBER_OF_BOOKS)) except Exception: raise HTTPNotFound('Invalid number of books: %r' % rd.query.get('num')) with db.safe_read_lock: try: ans['search_result'] = search_result(ctx, rd, db, rd.query.get('search', ''), num, 0, ','.join(sorts), ','.join(orders)) except ParseException: ans['search_result'] = search_result(ctx, rd, db, '', num, 0, ','.join(sorts), ','.join(orders)) sf = db.field_metadata.ui_sortable_field_keys() sf.pop('ondevice', None) ans['sortable_fields'] = sorted((( sanitize_sort_field_name(db.field_metadata, k), v) for k, v in sf.iteritems()), key=lambda (field, name):sort_key(name)) ans['field_metadata'] = db.field_metadata.all_metadata() ans['icon_map'] = icon_map() ans['icon_path'] = ctx.url_for('/icon', which='') mdata = ans['metadata'] = {} try: extra_books = set(int(x) for x in rd.query.get('extra_books', '').split(',')) except Exception: extra_books = () for coll in (ans['search_result']['book_ids'], extra_books): for book_id in coll: if book_id not in mdata: data = book_as_json(db, book_id) if data is not None: mdata[book_id] = data return ans
def search(ctx, rd, library_id): ''' Return the books (as list of ids) matching the specified search query. Optional: ?num=100&offset=0&sort=title&sort_order=asc&query= ''' db = get_db(ctx, library_id) with db.safe_read_lock: query = rd.query.get('query') num, offset = get_pagination(rd.query) sort, sort_order = rd.query.get('sort', 'title'), rd.query.get('sort_order') sort_order = ensure_val(sort_order, 'asc', 'desc') sfield = sanitize_sort_field_name(db.field_metadata, sort) if sfield not in db.field_metadata.sortable_field_keys(): raise HTTPNotFound('%s is not a valid sort field' % sort) if not query: ids = ctx.allowed_book_ids(rd, db) else: ids = ctx.search(rd, db, query) ids = db.multisort(fields=[(sfield, sort_order == 'asc')], ids_to_sort=ids) total_num = len(ids) ids = ids[offset:offset + num] return { 'total_num': total_num, 'sort_order': sort_order, 'offset': offset, 'num': len(ids), 'sort': sort, 'base_url': ctx.url_for(search, library_id=db.server_library_id), 'query': query, 'book_ids': ids }
def get_acquisition_feed(rc, ids, offset, page_url, up_url, id_, sort_by='title', ascending=True, feed_title=None): if not ids: raise HTTPNotFound('No books found') with rc.db.safe_read_lock: sort_by = sanitize_sort_field_name(rc.db.field_metadata, sort_by) items = rc.db.multisort([(sort_by, ascending)], ids) max_items = rc.opts.max_opds_items offsets = Offsets(offset, max_items, len(items)) items = items[offsets.offset:offsets.offset + max_items] lm = rc.last_modified() rc.outheaders['Last-Modified'] = http_date(timestampfromdt(lm)) return AcquisitionFeed(id_, lm, rc, items, offsets, page_url, up_url, title=feed_title).root
def search(ctx, rd, library_id): ''' Return the books (as list of ids) matching the specified search query. Optional: ?num=100&offset=0&sort=title&sort_order=asc&query= ''' db = get_db(ctx, library_id) with db.safe_read_lock: query = rd.query.get('query') num, offset = get_pagination(rd.query) sort, sort_order = rd.query.get('sort', 'title'), rd.query.get('sort_order') sort_order = ensure_val(sort_order, 'asc', 'desc') sfield = sanitize_sort_field_name(db.field_metadata, sort) if sfield not in db.field_metadata.sortable_field_keys(): raise HTTPNotFound('%s is not a valid sort field'%sort) if not query: ids = ctx.allowed_book_ids(rd, db) else: ids = ctx.search(rd, db, query) ids = db.multisort(fields=[(sfield, sort_order == 'asc')], ids_to_sort=ids) total_num = len(ids) ids = ids[offset:offset+num] return { 'total_num': total_num, 'sort_order':sort_order, 'offset':offset, 'num':len(ids), 'sort':sort, 'base_url':ctx.url_for(search, library_id=db.server_library_id), 'query': query, 'book_ids':ids }
def interface_data(ctx, rd): ''' Return the data needed to create the server main UI Optional: ?num=50&sort=timestamp.desc&library_id=<default library> &search=''&extra_books='' ''' ans = { 'username':rd.username, 'output_format':prefs['output_format'].upper(), 'input_formats':{x.upper():True for x in available_input_formats()}, 'gui_pubdate_display_format':tweaks['gui_pubdate_display_format'], 'gui_timestamp_display_format':tweaks['gui_timestamp_display_format'], 'gui_last_modified_display_format':tweaks['gui_last_modified_display_format'], 'use_roman_numerals_for_series_number': get_use_roman(), } ans['library_map'], ans['default_library'] = ctx.library_map ud = {} if rd.username: # Override session data with stored values for the authenticated user, # if any ud = ctx.user_manager.get_session_data(rd.username) lid = ud.get('library_id') if lid and lid in ans['library_map']: rd.query.set('library_id', lid) usort = ud.get('sort') if usort: rd.query.set('sort', usort) ans['library_id'], db, sorts, orders = get_basic_query_data(ctx, rd.query) ans['user_session_data'] = ud try: num = int(rd.query.get('num', DEFAULT_NUMBER_OF_BOOKS)) except Exception: raise HTTPNotFound('Invalid number of books: %r' % rd.query.get('num')) with db.safe_read_lock: try: ans['search_result'] = search_result(ctx, rd, db, rd.query.get('search', ''), num, 0, ','.join(sorts), ','.join(orders)) except ParseException: ans['search_result'] = search_result(ctx, rd, db, '', num, 0, ','.join(sorts), ','.join(orders)) sf = db.field_metadata.ui_sortable_field_keys() sf.pop('ondevice', None) ans['sortable_fields'] = sorted((( sanitize_sort_field_name(db.field_metadata, k), v) for k, v in sf.iteritems()), key=lambda (field, name):sort_key(name)) ans['field_metadata'] = db.field_metadata.all_metadata() ans['icon_map'] = icon_map() ans['icon_path'] = ctx.url_for('/icon', which='') mdata = ans['metadata'] = {} try: extra_books = set(int(x) for x in rd.query.get('extra_books', '').split(',')) except Exception: extra_books = () for coll in (ans['search_result']['book_ids'], extra_books): for book_id in coll: if book_id not in mdata: data = book_as_json(db, book_id) if data is not None: mdata[book_id] = data return ans
def books_in(ctx, rd, encoded_category, encoded_item, library_id): ''' Return the books (as list of ids) present in the specified category. Optional: ?num=100&offset=0&sort=title&sort_order=asc&get_additional_fields= ''' db = get_db(ctx, rd, library_id) with db.safe_read_lock: try: dname, ditem = map(decode_name, (encoded_category, encoded_item)) except: raise HTTPNotFound('Invalid encoded param: %r' % (encoded_category, encoded_item)) num, offset = get_pagination(rd.query) sort, sort_order = rd.query.get('sort', 'title'), rd.query.get('sort_order') sort_order = ensure_val(sort_order, 'asc', 'desc') sfield = sanitize_sort_field_name(db.field_metadata, sort) if sfield not in db.field_metadata.sortable_field_keys(): raise HTTPNotFound('%s is not a valid sort field'%sort) if dname in ('allbooks', 'newest'): ids = ctx.allowed_book_ids(rd, db) elif dname == 'search': try: ids = ctx.search(rd, db, 'search:"%s"'%ditem) except Exception: raise HTTPNotFound('Search: %r not understood'%ditem) else: try: cid = int(ditem) except Exception: raise HTTPNotFound('Category id %r not an integer'%ditem) if dname == 'news': dname = 'tags' ids = db.get_books_for_category(dname, cid).intersection(ctx.allowed_book_ids(rd, db)) ids = db.multisort(fields=[(sfield, sort_order == 'asc')], ids_to_sort=ids) total_num = len(ids) ids = ids[offset:offset+num] result = { 'total_num': total_num, 'sort_order':sort_order, 'offset':offset, 'num':len(ids), 'sort':sort, 'base_url':ctx.url_for(books_in, encoded_category=encoded_category, encoded_item=encoded_item, library_id=db.server_library_id), 'book_ids':ids } get_additional_fields = rd.query.get('get_additional_fields') if get_additional_fields: additional_fields = {} for field in get_additional_fields.split(','): field = field.strip() if field: flist = additional_fields[field] = [] for id_ in ids: flist.append(db.field_for(field, id_, default_value=None)) if additional_fields: result['additional_fields'] = additional_fields return result
def build_search_box(num, search, sort, order, ctx, field_metadata, library_id): # {{{ div = E.div(id='search_box') form = E.form(_('Show '), method='get', action=ctx.url_for('/mobile')) form.set('accept-charset', 'UTF-8') div.append(form) num_select = E.select(name='num') for option in (5, 10, 25, 100): kwargs = {'value': unicode_type(option)} if option == num: kwargs['SELECTED'] = 'SELECTED' num_select.append(E.option(unicode_type(option), **kwargs)) num_select.tail = ' books matching ' form.append(num_select) searchf = E.input(name='search', id='s', value=search if search else '') searchf.tail = _(' sorted by ') form.append(searchf) sort_select = E.select(name='sort') for option in ('date', 'author', 'title', 'rating', 'size', 'tags', 'series'): q = sanitize_sort_field_name(field_metadata, option) kwargs = {'value': option} if q == sanitize_sort_field_name(field_metadata, sort): kwargs['SELECTED'] = 'SELECTED' sort_select.append(E.option(option, **kwargs)) form.append(sort_select) order_select = E.select(name='order') for option in ('ascending', 'descending'): kwargs = {'value': option} if option == order: kwargs['SELECTED'] = 'SELECTED' order_select.append(E.option(option, **kwargs)) form.append(order_select) if library_id: form.append(E.input(name='library_id', type='hidden', value=library_id)) form.append(E.input(id='go', type='submit', value=_('Search'))) return div
def build_search_box(num, search, sort, order, ctx, field_metadata, library_id): # {{{ div = E.div(id='search_box') form = E.form(_('Show '), method='get', action=ctx.url_for('/mobile')) form.set('accept-charset', 'UTF-8') div.append(form) num_select = E.select(name='num') for option in (5, 10, 25, 100): kwargs = {'value':str(option)} if option == num: kwargs['SELECTED'] = 'SELECTED' num_select.append(E.option(str(option), **kwargs)) num_select.tail = ' books matching ' form.append(num_select) searchf = E.input(name='search', id='s', value=search if search else '') searchf.tail = _(' sorted by ') form.append(searchf) sort_select = E.select(name='sort') for option in ('date','author','title','rating','size','tags','series'): q = sanitize_sort_field_name(field_metadata, option) kwargs = {'value':option} if q == sanitize_sort_field_name(field_metadata, sort): kwargs['SELECTED'] = 'SELECTED' sort_select.append(E.option(option, **kwargs)) form.append(sort_select) order_select = E.select(name='order') for option in ('ascending','descending'): kwargs = {'value':option} if option == order: kwargs['SELECTED'] = 'SELECTED' order_select.append(E.option(option, **kwargs)) form.append(order_select) if library_id: form.append(E.input(name='library_id', type='hidden', value=library_id)) form.append(E.input(id='go', type='submit', value=_('Search'))) return div
def get_acquisition_feed(rc, ids, offset, page_url, up_url, id_, sort_by="title", ascending=True, feed_title=None): if not ids: raise HTTPNotFound("No books found") with rc.db.safe_read_lock: sort_by = sanitize_sort_field_name(rc.db.field_metadata, sort_by) items = rc.db.multisort([(sort_by, ascending)], ids) max_items = rc.opts.max_opds_items offsets = Offsets(offset, max_items, len(items)) items = items[offsets.offset : offsets.offset + max_items] lm = rc.last_modified() rc.outheaders["Last-Modified"] = http_date(timestampfromdt(lm)) return AcquisitionFeed(id_, lm, rc, items, offsets, page_url, up_url, title=feed_title).root
def get_basic_query_data(ctx, query): db, library_id, library_map, default_library = get_library_data(ctx, query) skeys = db.field_metadata.sortable_field_keys() sorts, orders = [], [] for x in query.get('sort', '').split(','): if x: s, o = x.partition('.')[::2] if o not in ('asc', 'desc'): o = 'asc' if s.startswith('_'): s = '#' + s[1:] s = sanitize_sort_field_name(db.field_metadata, s) if s in skeys: sorts.append(s), orders.append(o) if not sorts: sorts, orders = ['date'], ['desc'] return library_id, db, sorts, orders
def get_basic_query_data(ctx, query): db, library_id, library_map, default_library = get_library_data(ctx, query) skeys = db.field_metadata.sortable_field_keys() sorts, orders = [], [] for x in query.get("sort", "").split(","): if x: s, o = x.rpartition(".")[::2] if o and not s: s, o = o, "" if o not in ("asc", "desc"): o = "asc" if s.startswith("_"): s = "#" + s[1:] s = sanitize_sort_field_name(db.field_metadata, s) if s in skeys: sorts.append(s), orders.append(o) if not sorts: sorts, orders = ["timestamp"], ["desc"] return library_id, db, sorts, orders
def get_basic_query_data(ctx, query): db, library_id, library_map, default_library = get_library_data(ctx, query) skeys = db.field_metadata.sortable_field_keys() sorts, orders = [], [] for x in query.get('sort', '').split(','): if x: s, o = x.rpartition('.')[::2] if o and not s: s, o = o, '' if o not in ('asc', 'desc'): o = 'asc' if s.startswith('_'): s = '#' + s[1:] s = sanitize_sort_field_name(db.field_metadata, s) if s in skeys: sorts.append(s), orders.append(o) if not sorts: sorts, orders = ['timestamp'], ['desc'] return library_id, db, sorts, orders
def interface_data(ctx, rd): ''' Return the data needed to create the server main UI Optional: ?num=50&sort=timestamp.desc&library_id=<default library> &sort_tags_by=name&partition_method=first letter&collapse_at=25& &dont_collapse= ''' ans = {'username':rd.username} ans['library_map'], ans['default_library'] = ctx.library_map ud = {} if rd.username: # Override session data with stored values for the authenticated user, # if any ud = ctx.user_manager.get_session_data(rd.username) lid = ud.get('library_id') if lid and lid in ans['library_map']: rd.query.set('library_id', lid) usort = ud.get('sort') if usort: rd.query.set('sort', usort) ans['library_id'], db, sorts, orders = get_basic_query_data(ctx, rd.query) ans['user_session_data'] = ud try: num = int(rd.query.get('num', DEFAULT_NUMBER_OF_BOOKS)) except Exception: raise HTTPNotFound('Invalid number of books: %r' % rd.query.get('num')) with db.safe_read_lock: ans['search_result'] = search_result(ctx, rd, db, '', num, 0, ','.join(sorts), ','.join(orders)) sf = db.field_metadata.ui_sortable_field_keys() sf.pop('ondevice', None) ans['sortable_fields'] = sorted((( sanitize_sort_field_name(db.field_metadata, k), v) for k, v in sf.iteritems()), key=lambda (field, name):sort_key(name)) ans['field_metadata'] = db.field_metadata.all_metadata() ans['categories'] = categories_as_json(ctx, rd, db) mdata = ans['metadata'] = {} for book_id in ans['search_result']['book_ids']: data = book_as_json(db, book_id) mdata[book_id] = data return ans
def search_result(ctx, rd, db, query, num, offset, sort, sort_order, vl=''): multisort = [(sanitize_sort_field_name(db.field_metadata, s), ensure_val(o, 'asc', 'desc') == 'asc') for s, o in zip(sort.split(','), cycle(sort_order.split(',')))] skeys = db.field_metadata.sortable_field_keys() for sfield, sorder in multisort: if sfield not in skeys: raise HTTPNotFound('%s is not a valid sort field'%sort) ids = ctx.search(rd, db, query, vl=vl) ids = db.multisort(fields=multisort, ids_to_sort=ids) total_num = len(ids) ids = ids[offset:offset+num] return { 'total_num': total_num, 'sort_order':sort_order, 'offset':offset, 'num':len(ids), 'sort':sort, 'base_url':ctx.url_for(search, library_id=db.server_library_id), 'query': query, 'library_id': db.server_library_id, 'book_ids':ids, 'vl': vl, }
def books_in(ctx, rd, encoded_category, encoded_item, library_id): """ Return the books (as list of ids) present in the specified category. Optional: ?num=100&offset=0&sort=title&sort_order=asc&get_additional_fields= """ db = get_db(ctx, library_id) with db.safe_read_lock: try: dname, ditem = map(decode_name, (encoded_category, encoded_item)) except: raise HTTPNotFound("Invalid encoded param: %r" % (encoded_category, encoded_item)) num, offset = get_pagination(rd.query) sort, sort_order = rd.query.get("sort", "title"), rd.query.get("sort_order") sort_order = ensure_val(sort_order, "asc", "desc") sfield = sanitize_sort_field_name(db.field_metadata, sort) if sfield not in db.field_metadata.sortable_field_keys(): raise HTTPNotFound("%s is not a valid sort field" % sort) if dname in ("allbooks", "newest"): ids = ctx.allowed_book_ids(rd, db) elif dname == "search": try: ids = ctx.search(rd, db, 'search:"%s"' % ditem) except Exception: raise HTTPNotFound("Search: %r not understood" % ditem) else: try: cid = int(ditem) except Exception: raise HTTPNotFound("Category id %r not an integer" % ditem) if dname == "news": dname = "tags" ids = db.get_books_for_category(dname, cid).intersection(ctx.allowed_book_ids(rd, db)) ids = db.multisort(fields=[(sfield, sort_order == "asc")], ids_to_sort=ids) total_num = len(ids) ids = ids[offset : offset + num] result = { "total_num": total_num, "sort_order": sort_order, "offset": offset, "num": len(ids), "sort": sort, "base_url": ctx.url_for( books_in, encoded_category=encoded_category, encoded_item=encoded_item, library_id=db.server_library_id ), "book_ids": ids, } get_additional_fields = rd.query.get("get_additional_fields") if get_additional_fields: additional_fields = {} for field in get_additional_fields.split(","): field = field.strip() if field: flist = additional_fields[field] = [] for id_ in ids: flist.append(db.field_for(field, id_, default_value=None)) if additional_fields: result["additional_fields"] = additional_fields return result
def interface_data(ctx, rd): """ Return the data needed to create the server main UI Optional: ?num=50&sort=timestamp.desc&library_id=<default library> &search=''&extra_books='' """ ans = { "username": rd.username, "output_format": prefs["output_format"].upper(), "input_formats": {x.upper(): True for x in available_input_formats()}, "gui_pubdate_display_format": tweaks["gui_pubdate_display_format"], "gui_timestamp_display_format": tweaks["gui_timestamp_display_format"], "gui_last_modified_display_format": tweaks["gui_last_modified_display_format"], "use_roman_numerals_for_series_number": get_use_roman(), } ans["library_map"], ans["default_library"] = ctx.library_map ud = {} if rd.username: # Override session data with stored values for the authenticated user, # if any ud = ctx.user_manager.get_session_data(rd.username) lid = ud.get("library_id") if lid and lid in ans["library_map"]: rd.query.set("library_id", lid) usort = ud.get("sort") if usort: rd.query.set("sort", usort) ans["library_id"], db, sorts, orders = get_basic_query_data(ctx, rd.query) ans["user_session_data"] = ud try: num = int(rd.query.get("num", DEFAULT_NUMBER_OF_BOOKS)) except Exception: raise HTTPNotFound("Invalid number of books: %r" % rd.query.get("num")) with db.safe_read_lock: try: ans["search_result"] = search_result( ctx, rd, db, rd.query.get("search", ""), num, 0, ",".join(sorts), ",".join(orders) ) except ParseException: ans["search_result"] = search_result(ctx, rd, db, "", num, 0, ",".join(sorts), ",".join(orders)) sf = db.field_metadata.ui_sortable_field_keys() sf.pop("ondevice", None) ans["sortable_fields"] = sorted( ((sanitize_sort_field_name(db.field_metadata, k), v) for k, v in sf.iteritems()), key=lambda (field, name): sort_key(name), ) ans["field_metadata"] = db.field_metadata.all_metadata() ans["icon_map"] = icon_map() ans["icon_path"] = ctx.url_for("/icon", which="") mdata = ans["metadata"] = {} try: extra_books = set(int(x) for x in rd.query.get("extra_books", "").split(",")) except Exception: extra_books = () for coll in (ans["search_result"]["book_ids"], extra_books): for book_id in coll: if book_id not in mdata: data = book_as_json(db, book_id) if data is not None: mdata[book_id] = data return ans