Implement picking a random book

This commit is contained in:
Kovid Goyal 2016-02-13 16:12:39 +05:30
parent 585acda8cb
commit c1b41b14fc
3 changed files with 27 additions and 13 deletions

View File

@ -4,7 +4,7 @@
from __future__ import (unicode_literals, division, absolute_import, from __future__ import (unicode_literals, division, absolute_import,
print_function) print_function)
import re, hashlib import re, hashlib, random
from functools import partial from functools import partial
from threading import Lock from threading import Lock
from json import load as load_json_file from json import load as load_json_file
@ -216,17 +216,27 @@ def get_books(ctx, rd):
mdata[book_id] = data mdata[book_id] = data
return ans return ans
@endpoint('/interface-data/book-metadata/{book_id}', postprocess=json, types={'book_id': int}) @endpoint('/interface-data/book-metadata/{book_id=0}', postprocess=json)
def book_metadata(ctx, rd, book_id): def book_metadata(ctx, rd, book_id):
''' '''
Get metadata for the specified book Get metadata for the specified book. If no book_id is specified, return metadata for a random book.
Optional: ?library_id=<default library> Optional: ?library_id=<default library>
''' '''
library_id, db = get_basic_query_data(ctx, rd.query)[:2] library_id, db = get_basic_query_data(ctx, rd.query)[:2]
book_ids = ctx.allowed_book_ids(rd, db)
def notfound():
raise HTTPNotFound(_('No book with id: %d in library') % book_id)
if not book_ids:
notfound()
if not book_id:
book_id = random.choice(tuple(book_ids))
elif book_id not in book_ids:
notfound()
data = book_as_json(db, book_id) data = book_as_json(db, book_id)
if data is None: if data is None:
raise HTTPNotFound('No book with id: %d in library' % book_id) notfound()
data['id'] = book_id
return data return data
@endpoint('/interface-data/tag-browser') @endpoint('/interface-data/tag-browser')

View File

@ -58,17 +58,15 @@ class BookDetailsPanel:
def fetch_metadata(self, book_id): def fetch_metadata(self, book_id):
if self.is_fetching: if self.is_fetching:
self.is_fetching.abort() self.is_fetching.abort()
def fetched(end_type, xhr, ev): self.is_fetching = ajax('interface-data/book-metadata/' + book_id, self.metadata_fetched.bind(self),
self.metadata_fetched(book_id, end_type, xhr, ev) query={'library_id':self.interface_data.library_id})
self.is_fetching = ajax('interface-data/book-metadata/' + book_id, fetched,
query={'library_id':self.interface_data.library_id})
self.is_fetching.send() self.is_fetching.send()
self.container.appendChild(E.div( self.container.appendChild(E.div(
style='margin: 1ex 1em', style='margin: 1ex 1em',
create_spinner(), '\xa0' + _('Fetching metadata for the book, please wait') + '…', create_spinner(), '\xa0' + _('Fetching metadata for the book, please wait') + '…',
)) ))
def metadata_fetched(self, book_id, end_type, xhr, event): def metadata_fetched(self, end_type, xhr, event):
if self.is_fetching is None or self.is_fetching is not xhr: if self.is_fetching is None or self.is_fetching is not xhr:
return # Fetching was aborted return # Fetching was aborted
self.is_fetching = None self.is_fetching = None
@ -80,6 +78,7 @@ class BookDetailsPanel:
error_dialog(_('Could not fetch metadata for book'), _('Server returned an invalid response'), err.stack or err.toString()) error_dialog(_('Could not fetch metadata for book'), _('Server returned an invalid response'), err.stack or err.toString())
return return
clear(c) clear(c)
book_id = data['id']
self.interface_data.metadata[book_id] = data self.interface_data.metadata[book_id] = data
self.render_book(book_id) self.render_book(book_id)
elif end_type != 'abort': elif end_type != 'abort':
@ -98,12 +97,13 @@ class BookDetailsPanel:
alt = str.format(_('{} by {}'), metadata['title'], metadata['authors'].join(' & ')) alt = str.format(_('{} by {}'), metadata['title'], metadata['authors'].join(' & '))
img = E.img( img = E.img(
src=cover_url, alt=alt, title=alt, data_title=metadata['title'], data_authors=metadata['authors'].join(' & '), src=cover_url, alt=alt, title=alt, data_title=metadata['title'], data_authors=metadata['authors'].join(' & '),
style='margin-left: 1em; max-width: 45vw; max-height: 95vh; display: block; width:auto; height:auto' style='max-width: 45vw; max-height: 93vh; display: block; width:auto; height:auto'
) )
img.onerror = self.on_img_err.bind(self) img.onerror = self.on_img_err.bind(self)
c = self.container c = self.container
c.appendChild(E.div( c.appendChild(E.div(
E.div(), style='display:flex; flex-wrap: wrap; align-items:flex-start; padding: 1ex 1em',
E.div(style='margin-right: 1em'),
img img
)) ))

View File

@ -67,6 +67,9 @@ def create_book_view_top_bar_state(books_view):
ibs.add_button(icon_name='ellipsis-v', tooltip=_('More actions'), action=show_panel_action('more-actions-menu')) ibs.add_button(icon_name='ellipsis-v', tooltip=_('More actions'), action=show_panel_action('more-actions-menu'))
return ibs return ibs
def random_book():
get_boss().ui.replace_panel('book-details', extra_query_data={'book-id':'0'})
class UI: class UI:
ROOT_PANEL = 'books' ROOT_PANEL = 'books'
@ -85,6 +88,7 @@ class UI:
self.panel_map['more-actions-menu'] = UIState(ClosePanelBar(_('More actions')), panel_data=[ self.panel_map['more-actions-menu'] = UIState(ClosePanelBar(_('More actions')), panel_data=[
create_item(_('Book List Mode'), replace_panel_action('booklist-mode-menu'), _('Change how the list of books is displayed')), create_item(_('Book List Mode'), replace_panel_action('booklist-mode-menu'), _('Change how the list of books is displayed')),
create_item(_('A Random Book'), random_book, _('Choose a random book from your library')),
]) ])
self.panel_map['booklist-mode-menu'] = UIState(ClosePanelBar(_('Book List Mode')), panel_data=[]) self.panel_map['booklist-mode-menu'] = UIState(ClosePanelBar(_('Book List Mode')), panel_data=[])
@ -132,11 +136,11 @@ class UI:
else: else:
self.show_panel(self.ROOT_PANEL) self.show_panel(self.ROOT_PANEL)
def replace_panel(self, panel_name, force=False): def replace_panel(self, panel_name, force=False, extra_query_data=None):
action_needed = force or panel_name != self.current_panel action_needed = force or panel_name != self.current_panel
if action_needed: if action_needed:
self.current_panel = panel_name or self.ROOT_PANEL self.current_panel = panel_name or self.ROOT_PANEL
get_boss().push_state(replace=True) get_boss().push_state(replace=True, extra_query_data=extra_query_data)
if action_needed: if action_needed:
self.apply_state() self.apply_state()