mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Content server: Initial implementation of --url-prefix option to ease use of reverse proxying. /browse and /mobile ported, OPDS remains
This commit is contained in:
parent
6681fe6ede
commit
5efad88b63
@ -8,20 +8,20 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=100" />
|
||||
<link rel="icon" type="image/x-icon" href="http://calibre-ebook.com/favicon.ico" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/static/browse/browse.css" />
|
||||
<link type="text/css" href="/static/jquery_ui/css/humanity-custom/jquery-ui-1.8.5.custom.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" type="text/css" href="/static/jquery.multiselect.css" />
|
||||
<link rel="stylesheet" type="text/css" href="{prefix}/static/browse/browse.css" />
|
||||
<link type="text/css" href="{prefix}/static/jquery_ui/css/humanity-custom/jquery-ui-1.8.5.custom.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" type="text/css" href="{prefix}/static/jquery.multiselect.css" />
|
||||
|
||||
<script type="text/javascript" src="/static/jquery.js"></script>
|
||||
<script type="text/javascript" src="/static/jquery.corner.js"></script>
|
||||
<script type="text/javascript" src="{prefix}/static/jquery.js"></script>
|
||||
<script type="text/javascript" src="{prefix}/static/jquery.corner.js"></script>
|
||||
|
||||
<script type="text/javascript"
|
||||
src="/static/jquery_ui/js/jquery-ui-1.8.5.custom.min.js"></script>
|
||||
src="{prefix}/static/jquery_ui/js/jquery-ui-1.8.5.custom.min.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="/static/jquery.multiselect.min.js"></script>
|
||||
src="{prefix}/static/jquery.multiselect.min.js"></script>
|
||||
|
||||
|
||||
<script type="text/javascript" src="/static/browse/browse.js"></script>
|
||||
<script type="text/javascript" src="{prefix}/static/browse/browse.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var sort_cookie_name = "{sort_cookie_name}";
|
||||
@ -39,16 +39,16 @@
|
||||
<div id="header">
|
||||
<div class="area">
|
||||
<div class="bubble">
|
||||
<p><a href="/browse" title="Return to top level"
|
||||
<p><a href="{prefix}/browse" title="Return to top level"
|
||||
>→ home ←</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="nav-container">
|
||||
<ul id="primary-nav">
|
||||
<li><a id="nav-mobile" href="/mobile" title="A version of this website suited for mobile browsers">Mobile</a></li>
|
||||
<li><a id="nav-mobile" href="{prefix}/mobile" title="A version of this website suited for mobile browsers">Mobile</a></li>
|
||||
|
||||
<li><a id="nav-demo" href="/old" title="The old version of this webiste">Old</a></li>
|
||||
<li><a id="nav-download" href="/opds" title="An OPDS feed based version of this website, used in special purpose applications">Feed</a></li>
|
||||
<li><a id="nav-demo" href="{prefix}/old" title="The old version of this webiste">Old</a></li>
|
||||
<li><a id="nav-download" href="{prefix}/opds" title="An OPDS feed based version of this website, used in special purpose applications">Feed</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
<input type="hidden" name="cmd" value="_s-xclick"></input>
|
||||
<input type="hidden" name="hosted_button_id" value="3028915"></input>
|
||||
<input type="image"
|
||||
src="/static/button-donate.png"
|
||||
src="{prefix}/static/button-donate.png"
|
||||
name="submit"></input>
|
||||
<img alt="" src="https://www.paypal.com/en_US/i/scr/pixel.gif"
|
||||
width="1" height="1"></img>
|
||||
@ -76,7 +76,7 @@
|
||||
</select>
|
||||
</div>
|
||||
<div id="search_box">
|
||||
<form name="search_form" action="/browse/search" method="get" accept-charset="UTF-8">
|
||||
<form name="search_form" action="{prefix}/browse/search" method="get" accept-charset="UTF-8">
|
||||
<input value="{initial_search}" type="text" title="Search" name="query"
|
||||
class="search_input" />
|
||||
<input type="submit" value="Search" title="Search" alt="Search" />
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div id="details_{id}" class="details">
|
||||
<div class="left">
|
||||
<img alt="Cover of {title}" src="/get/cover/{id}" />
|
||||
<img alt="Cover of {title}" src="{prefix}/get/cover/{id}" />
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="field formats">{formats}</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div id="summary_{id}" class="summary">
|
||||
<div class="left">
|
||||
<img alt="Cover of {title}" src="/get/thumb_90_120/{id}" />
|
||||
<img alt="Cover of {title}" src="{prefix}/get/thumb_90_120/{id}" />
|
||||
{get_button}
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -8,7 +8,7 @@
|
||||
<span class="rating_container">{stars}</span>
|
||||
<span class="series">{series}</span>
|
||||
<a href="#" onclick="show_details(this); return false;" title="{details_tt}">{details}</a>
|
||||
<a href="/browse/book/{id}" title="{permalink_tt}">{permalink}</a>
|
||||
<a href="{prefix}/browse/book/{id}" title="{permalink_tt}">{permalink}</a>
|
||||
</div>
|
||||
<div class="title"><strong>{title}</strong></div>
|
||||
<div class="authors">{authors}</div>
|
||||
|
@ -44,6 +44,10 @@ def server_config(defaults=None):
|
||||
'by first letter when there are more than this number '
|
||||
'of items. Default: %default. Set to a large number '
|
||||
'to disable grouping.'))
|
||||
c.add_opt('url_prefix', ['--url-prefix'], default='',
|
||||
help=_('Prefix to prepend to all URLs. Useful for reverse'
|
||||
'proxying to this server from Apache/nginx/etc.'))
|
||||
|
||||
return c
|
||||
|
||||
def custom_fields_to_display(db):
|
||||
|
@ -28,16 +28,19 @@ from calibre.library.server.browse import BrowseServer
|
||||
|
||||
class DispatchController(object): # {{{
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, prefix):
|
||||
self.dispatcher = cherrypy.dispatch.RoutesDispatcher()
|
||||
self.funcs = []
|
||||
self.seen = set([])
|
||||
self.prefix = prefix if prefix else ''
|
||||
|
||||
def __call__(self, name, route, func, **kwargs):
|
||||
if name in self.seen:
|
||||
raise NameError('Route name: '+ repr(name) + ' already used')
|
||||
self.seen.add(name)
|
||||
kwargs['action'] = 'f_%d'%len(self.funcs)
|
||||
if route != '/':
|
||||
route = self.prefix + route
|
||||
self.dispatcher.connect(name, route, self, **kwargs)
|
||||
self.funcs.append(expose(func))
|
||||
|
||||
@ -55,7 +58,7 @@ class DispatchController(object): # {{{
|
||||
|
||||
# }}}
|
||||
|
||||
class BonJour(SimplePlugin):
|
||||
class BonJour(SimplePlugin): # {{{
|
||||
|
||||
def __init__(self, engine, port=8080):
|
||||
SimplePlugin.__init__(self, engine)
|
||||
@ -85,6 +88,7 @@ class BonJour(SimplePlugin):
|
||||
|
||||
cherrypy.engine.bonjour = BonJour(cherrypy.engine)
|
||||
|
||||
# }}}
|
||||
|
||||
class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
|
||||
BrowseServer):
|
||||
@ -177,7 +181,7 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
|
||||
|
||||
def start(self):
|
||||
self.is_running = False
|
||||
d = DispatchController()
|
||||
d = DispatchController(self.opts.url_prefix)
|
||||
for x in self.__class__.__bases__:
|
||||
if hasattr(x, 'add_routes'):
|
||||
x.add_routes(self, d)
|
||||
|
@ -22,7 +22,7 @@ from calibre.library.comments import comments_to_html
|
||||
from calibre.library.server import custom_fields_to_display
|
||||
from calibre.library.field_metadata import category_icon_map
|
||||
|
||||
def render_book_list(ids, suffix=''): # {{{
|
||||
def render_book_list(ids, prefix, suffix=''): # {{{
|
||||
pages = []
|
||||
num = len(ids)
|
||||
pos = 0
|
||||
@ -35,11 +35,11 @@ def render_book_list(ids, suffix=''): # {{{
|
||||
page_template = u'''\
|
||||
<div class="page" id="page{0}">
|
||||
<div class="load_data" title="{1}">
|
||||
<span class="url" title="/browse/booklist_page"></span>
|
||||
<span class="url" title="{prefix}/browse/booklist_page"></span>
|
||||
<span class="start" title="{start}"></span>
|
||||
<span class="end" title="{end}"></span>
|
||||
</div>
|
||||
<div class="loading"><img src="/static/loading.gif" /> {2}</div>
|
||||
<div class="loading"><img src="{prefix}/static/loading.gif" /> {2}</div>
|
||||
<div class="loaded"></div>
|
||||
</div>
|
||||
'''
|
||||
@ -49,7 +49,7 @@ def render_book_list(ids, suffix=''): # {{{
|
||||
ld = xml(json.dumps(pg), True)
|
||||
rpages.append(page_template.format(i, ld,
|
||||
xml(_('Loading, please wait')) + '…',
|
||||
start=pos+1, end=pos+len(pg)))
|
||||
start=pos+1, end=pos+len(pg), prefix=prefix))
|
||||
rpages = u'\n\n'.join(rpages)
|
||||
|
||||
templ = u'''\
|
||||
@ -91,7 +91,7 @@ def utf8(x): # {{{
|
||||
return x
|
||||
# }}}
|
||||
|
||||
def render_rating(rating, container='span', prefix=None): # {{{
|
||||
def render_rating(rating, url_prefix, container='span', prefix=None): # {{{
|
||||
if rating < 0.1:
|
||||
return '', ''
|
||||
added = 0
|
||||
@ -108,15 +108,15 @@ def render_rating(rating, container='span', prefix=None): # {{{
|
||||
elif n >= 0.9:
|
||||
x = 'on'
|
||||
ans.append(
|
||||
u'<img alt="{0}" title="{0}" src="/static/star-{1}.png" />'.format(
|
||||
rstring, x))
|
||||
u'<img alt="{0}" title="{0}" src="{2}/static/star-{1}.png" />'.format(
|
||||
rstring, x, url_prefix))
|
||||
added += 1
|
||||
ans.append('</%s>'%container)
|
||||
return u''.join(ans), rstring
|
||||
|
||||
# }}}
|
||||
|
||||
def get_category_items(category, items, restriction, datatype): # {{{
|
||||
def get_category_items(category, items, restriction, datatype, prefix): # {{{
|
||||
|
||||
if category == 'search':
|
||||
items = [x for x in items if x.name != restriction]
|
||||
@ -125,8 +125,8 @@ def get_category_items(category, items, restriction, datatype): # {{{
|
||||
templ = (u'<div title="{4}" class="category-item">'
|
||||
'<div class="category-name">{0}</div><div>{1}</div>'
|
||||
'<div>{2}'
|
||||
'<span class="href">{3}</span></div></div>')
|
||||
rating, rstring = render_rating(i.avg_rating)
|
||||
'<span class="href">{5}{3}</span></div></div>')
|
||||
rating, rstring = render_rating(i.avg_rating, prefix)
|
||||
name = xml(i.name)
|
||||
if datatype == 'rating':
|
||||
name = xml(_('%d stars')%int(i.avg_rating))
|
||||
@ -142,7 +142,7 @@ def get_category_items(category, items, restriction, datatype): # {{{
|
||||
q = category
|
||||
href = '/browse/matches/%s/%s'%(quote(q), quote(id_))
|
||||
return templ.format(xml(name), rating,
|
||||
xml(desc), xml(href), rstring)
|
||||
xml(desc), xml(href), rstring, prefix)
|
||||
|
||||
items = list(map(item, items))
|
||||
return '\n'.join(['<div class="category-container">'] + items + ['</div>'])
|
||||
@ -243,6 +243,7 @@ class BrowseServer(object):
|
||||
|
||||
ans = ans.replace('{sort_select_label}', xml(_('Sort by')+':'))
|
||||
ans = ans.replace('{sort_cookie_name}', scn)
|
||||
ans = ans.replace('{prefix}', self.opts.url_prefix)
|
||||
opts = ['<option %svalue="%s">%s</option>' % (
|
||||
'selected="selected" ' if k==sort else '',
|
||||
xml(k), xml(n), ) for k, n in
|
||||
@ -258,15 +259,14 @@ class BrowseServer(object):
|
||||
ans = ans.replace('{initial_search}', initial_search)
|
||||
return ans
|
||||
|
||||
return self.__browse_template__
|
||||
|
||||
@property
|
||||
def browse_summary_template(self):
|
||||
if not hasattr(self, '__browse_summary_template__') or \
|
||||
self.opts.develop:
|
||||
self.__browse_summary_template__ = \
|
||||
P('content_server/browse/summary.html', data=True).decode('utf-8')
|
||||
return self.__browse_summary_template__
|
||||
return self.__browse_summary_template__.replace('{prefix}',
|
||||
self.opts.url_prefix)
|
||||
|
||||
@property
|
||||
def browse_details_template(self):
|
||||
@ -274,7 +274,8 @@ class BrowseServer(object):
|
||||
self.opts.develop:
|
||||
self.__browse_details_template__ = \
|
||||
P('content_server/browse/details.html', data=True).decode('utf-8')
|
||||
return self.__browse_details_template__
|
||||
return self.__browse_details_template__.replace('{prefix}',
|
||||
self.opts.url_prefix)
|
||||
|
||||
# }}}
|
||||
|
||||
@ -334,11 +335,11 @@ class BrowseServer(object):
|
||||
icon = 'blank.png'
|
||||
cats.append((meta['name'], category, icon))
|
||||
|
||||
cats = [('<li title="{2} {0}"><img src="{src}" alt="{0}" />'
|
||||
cats = [('<li title="{2} {0}"><img src="{3}{src}" alt="{0}" />'
|
||||
'<span class="label">{0}</span>'
|
||||
'<span class="url">/browse/category/{1}</span></li>')
|
||||
'<span class="url">{3}/browse/category/{1}</span></li>')
|
||||
.format(xml(x, True), xml(quote(y)), xml(_('Browse books by')),
|
||||
src='/browse/icon/'+z)
|
||||
self.opts.url_prefix, src='/browse/icon/'+z)
|
||||
for x, y, z in cats]
|
||||
|
||||
main = '<div class="toplevel"><h3>{0}</h3><ul>{1}</ul></div>'\
|
||||
@ -378,7 +379,8 @@ class BrowseServer(object):
|
||||
if len(items) <= self.opts.max_opds_ungrouped_items:
|
||||
script = 'false'
|
||||
items = get_category_items(category, items,
|
||||
self.search_restriction_name, datatype)
|
||||
self.search_restriction_name, datatype,
|
||||
self.opts.url_prefix)
|
||||
else:
|
||||
getter = lambda x: unicode(getattr(x, 'sort', x.name))
|
||||
starts = set([])
|
||||
@ -393,12 +395,13 @@ class BrowseServer(object):
|
||||
getter(y).upper().startswith(x)])
|
||||
items = [(u'<h3 title="{0}">{0} <span>[{2}]</span></h3><div>'
|
||||
u'<div class="loaded" style="display:none"></div>'
|
||||
u'<div class="loading"><img alt="{1}" src="/static/loading.gif" /><em>{1}</em></div>'
|
||||
u'<span class="load_href">{3}</span></div>').format(
|
||||
u'<div class="loading"><img alt="{1}" src="{4}/static/loading.gif" /><em>{1}</em></div>'
|
||||
u'<span class="load_href">{4}{3}</span></div>').format(
|
||||
xml(s, True),
|
||||
xml(_('Loading, please wait'))+'…',
|
||||
unicode(c),
|
||||
xml(u'/browse/category_group/%s/%s'%(category, s)))
|
||||
xml(u'/browse/category_group/%s/%s'%(category, s)),
|
||||
self.opts.url_prefix)
|
||||
for s, c in category_groups.items()]
|
||||
items = '\n\n'.join(items)
|
||||
items = u'<div id="groups">\n{0}</div>'.format(items)
|
||||
@ -410,13 +413,13 @@ class BrowseServer(object):
|
||||
main = u'''
|
||||
<div class="category">
|
||||
<h3>{0}</h3>
|
||||
<a class="navlink" href="/browse"
|
||||
<a class="navlink" href="{3}/browse"
|
||||
title="{2}">{2} ↑</a>
|
||||
{1}
|
||||
</div>
|
||||
'''.format(
|
||||
xml(_('Browsing by')+': ' + category_name), items,
|
||||
xml(_('Up'), True))
|
||||
xml(_('Up'), True), self.opts.url_prefix)
|
||||
|
||||
return self.browse_template(sort).format(title=category_name,
|
||||
script=script, main=main)
|
||||
@ -449,7 +452,8 @@ class BrowseServer(object):
|
||||
|
||||
sort = self.browse_sort_categories(entries, sort)
|
||||
entries = get_category_items(category, entries,
|
||||
self.search_restriction_name, datatype)
|
||||
self.search_restriction_name, datatype,
|
||||
self.opts.url_prefix)
|
||||
return json.dumps(entries, ensure_ascii=False)
|
||||
|
||||
|
||||
@ -459,9 +463,11 @@ class BrowseServer(object):
|
||||
if category == None:
|
||||
ans = self.browse_toplevel()
|
||||
elif category == 'newest':
|
||||
raise cherrypy.InternalRedirect('/browse/matches/newest/dummy')
|
||||
raise cherrypy.InternalRedirect(self.opts.url_prefix +
|
||||
'/browse/matches/newest/dummy')
|
||||
elif category == 'allbooks':
|
||||
raise cherrypy.InternalRedirect('/browse/matches/allbooks/dummy')
|
||||
raise cherrypy.InternalRedirect(self.opts.url_prefix +
|
||||
'/browse/matches/allbooks/dummy')
|
||||
else:
|
||||
ans = self.browse_category(category, category_sort)
|
||||
|
||||
@ -532,7 +538,8 @@ class BrowseServer(object):
|
||||
list_sort = category
|
||||
sort = self.browse_sort_book_list(items, list_sort)
|
||||
ids = [x[0] for x in items]
|
||||
html = render_book_list(ids, suffix=_('in') + ' ' + category_name)
|
||||
html = render_book_list(ids, self.opts.url_prefix,
|
||||
suffix=_('in') + ' ' + category_name)
|
||||
|
||||
return self.browse_template(sort, category=False).format(
|
||||
title=_('Books in') + " " +category_name,
|
||||
@ -580,17 +587,18 @@ class BrowseServer(object):
|
||||
if fmts and fmt:
|
||||
other_fmts = [x for x in fmts if x.lower() != fmt.lower()]
|
||||
if other_fmts:
|
||||
ofmts = [u'<a href="/get/{0}/{1}_{2}.{0}" title="{3}">{3}</a>'\
|
||||
.format(f, fname, id_, f.upper()) for f in
|
||||
ofmts = [u'<a href="{4}/get/{0}/{1}_{2}.{0}" title="{3}">{3}</a>'\
|
||||
.format(f, fname, id_, f.upper(),
|
||||
self.opts.url_prefix) for f in
|
||||
other_fmts]
|
||||
ofmts = ', '.join(ofmts)
|
||||
args['other_formats'] = u'<strong>%s: </strong>' % \
|
||||
_('Other formats') + ofmts
|
||||
|
||||
args['details_href'] = '/browse/details/'+str(id_)
|
||||
args['details_href'] = self.opts.url_prefix + '/browse/details/'+str(id_)
|
||||
|
||||
if fmt:
|
||||
href = '/get/%s/%s_%d.%s'%(
|
||||
href = self.opts.url_prefix + '/get/%s/%s_%d.%s'%(
|
||||
fmt, fname, id_, fmt)
|
||||
rt = xml(_('Read %s in the %s format')%(args['title'],
|
||||
fmt.upper()), True)
|
||||
@ -603,7 +611,8 @@ class BrowseServer(object):
|
||||
args['comments'] = comments_to_html(mi.comments)
|
||||
args['stars'] = ''
|
||||
if mi.rating:
|
||||
args['stars'] = render_rating(mi.rating/2.0, prefix=_('Rating'))[0]
|
||||
args['stars'] = render_rating(mi.rating/2.0,
|
||||
self.opts.url_prefix, prefix=_('Rating'))[0]
|
||||
if args['tags']:
|
||||
args['tags'] = u'<strong>%s: </strong>'%xml(_('Tags')) + \
|
||||
args['tags']
|
||||
@ -628,8 +637,9 @@ class BrowseServer(object):
|
||||
args, fmt, fmts, fname = self.browse_get_book_args(mi, id_)
|
||||
args['formats'] = ''
|
||||
if fmts:
|
||||
ofmts = [u'<a href="/get/{0}/{1}_{2}.{0}" title="{3}">{3}</a>'\
|
||||
.format(fmt, fname, id_, fmt.upper()) for fmt in
|
||||
ofmts = [u'<a href="{4}/get/{0}/{1}_{2}.{0}" title="{3}">{3}</a>'\
|
||||
.format(fmt, fname, id_, fmt.upper(),
|
||||
self.opts.url_prefix) for fmt in
|
||||
fmts]
|
||||
ofmts = ', '.join(ofmts)
|
||||
args['formats'] = ofmts
|
||||
@ -648,7 +658,8 @@ class BrowseServer(object):
|
||||
continue
|
||||
if m['datatype'] == 'rating':
|
||||
r = u'<strong>%s: </strong>'%xml(m['name']) + \
|
||||
render_rating(mi.rating/2.0, prefix=m['name'])[0]
|
||||
render_rating(mi.rating/2.0, self.opts.url_prefix,
|
||||
prefix=m['name'])[0]
|
||||
else:
|
||||
r = u'<strong>%s: </strong>'%xml(m['name']) + \
|
||||
args[field]
|
||||
@ -704,7 +715,8 @@ class BrowseServer(object):
|
||||
items = [self.db.data._data[x] for x in ids]
|
||||
sort = self.browse_sort_book_list(items, list_sort)
|
||||
ids = [x[0] for x in items]
|
||||
html = render_book_list(ids, suffix=_('in search')+': '+query)
|
||||
html = render_book_list(ids, self.opts.url_prefix,
|
||||
suffix=_('in search')+': '+query)
|
||||
return self.browse_template(sort, category=False, initial_search=query).format(
|
||||
title=_('Matching books'),
|
||||
script='booklist();', main=html)
|
||||
|
@ -103,7 +103,11 @@ class ContentServer(object):
|
||||
if self.opts.develop:
|
||||
lm = fromtimestamp(os.stat(path).st_mtime)
|
||||
cherrypy.response.headers['Last-Modified'] = self.last_modified(lm)
|
||||
return open(path, 'rb').read()
|
||||
with open(path, 'rb') as f:
|
||||
ans = f.read()
|
||||
if path.endswith('.css'):
|
||||
ans = ans.replace('/static/', self.opts.url_prefix + '/static/')
|
||||
return ans
|
||||
|
||||
def index(self, **kwargs):
|
||||
'The / URL'
|
||||
|
@ -26,9 +26,9 @@ def CLASS(*args, **kwargs): # class is a reserved word in Python
|
||||
return kwargs
|
||||
|
||||
|
||||
def build_search_box(num, search, sort, order): # {{{
|
||||
def build_search_box(num, search, sort, order, prefix): # {{{
|
||||
div = DIV(id='search_box')
|
||||
form = FORM('Show ', method='get', action='mobile')
|
||||
form = FORM('Show ', method='get', action=prefix+'/mobile')
|
||||
form.set('accept-charset', 'UTF-8')
|
||||
|
||||
div.append(form)
|
||||
@ -89,11 +89,12 @@ def build_navigation(start, num, total, url_base): # {{{
|
||||
|
||||
# }}}
|
||||
|
||||
def build_index(books, num, search, sort, order, start, total, url_base, CKEYS):
|
||||
logo = DIV(IMG(src='/static/calibre.png', alt=__appname__), id='logo')
|
||||
def build_index(books, num, search, sort, order, start, total, url_base, CKEYS,
|
||||
prefix):
|
||||
logo = DIV(IMG(src=prefix+'/static/calibre.png', alt=__appname__), id='logo')
|
||||
|
||||
search_box = build_search_box(num, search, sort, order)
|
||||
navigation = build_navigation(start, num, total, url_base)
|
||||
search_box = build_search_box(num, search, sort, order, prefix)
|
||||
navigation = build_navigation(start, num, total, prefix+url_base)
|
||||
bookt = TABLE(id='listing')
|
||||
|
||||
body = BODY(
|
||||
@ -107,7 +108,8 @@ def build_index(books, num, search, sort, order, start, total, url_base, CKEYS):
|
||||
# Book list {{{
|
||||
for book in books:
|
||||
thumbnail = TD(
|
||||
IMG(type='image/jpeg', border='0', src='/get/thumb/%s' %
|
||||
IMG(type='image/jpeg', border='0',
|
||||
src=prefix+'/get/thumb/%s' %
|
||||
book['id']),
|
||||
CLASS('thumbnail'))
|
||||
|
||||
@ -118,7 +120,7 @@ def build_index(books, num, search, sort, order, start, total, url_base, CKEYS):
|
||||
s = SPAN(
|
||||
A(
|
||||
fmt.lower(),
|
||||
href='/get/%s/%s-%s_%d.%s' % (fmt, a, t,
|
||||
href=prefix+'/get/%s/%s-%s_%d.%s' % (fmt, a, t,
|
||||
book['id'], fmt)
|
||||
),
|
||||
CLASS('button'))
|
||||
@ -154,7 +156,7 @@ def build_index(books, num, search, sort, order, start, total, url_base, CKEYS):
|
||||
TITLE(__appname__ + ' Library'),
|
||||
LINK(rel='icon', href='http://calibre-ebook.com/favicon.ico',
|
||||
type='image/x-icon'),
|
||||
LINK(rel='stylesheet', type='text/css', href='/mobile/style.css')
|
||||
LINK(rel='stylesheet', type='text/css', href=prefix+'/mobile/style.css')
|
||||
), # End head
|
||||
body
|
||||
) # End html
|
||||
@ -174,7 +176,9 @@ class MobileServer(object):
|
||||
cherrypy.response.headers['Content-Type'] = 'text/css; charset=utf-8'
|
||||
updated = utcfromtimestamp(os.stat(path).st_mtime)
|
||||
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
|
||||
return open(path, 'rb').read()
|
||||
with open(path, 'rb') as f:
|
||||
ans = f.read()
|
||||
return ans.replace('{prefix}', self.opts.url_prefix)
|
||||
|
||||
def mobile(self, start='1', num='25', sort='date', search='',
|
||||
_=None, order='descending'):
|
||||
@ -259,7 +263,8 @@ class MobileServer(object):
|
||||
url_base = "/mobile?search=" + search+";order="+order+";sort="+sort+";num="+str(num)
|
||||
|
||||
return html.tostring(build_index(books, num, search, sort, order,
|
||||
start, len(ids), url_base, CKEYS),
|
||||
start, len(ids), url_base, CKEYS,
|
||||
self.opts.url_prefix),
|
||||
encoding='utf-8', include_meta_content_type=True,
|
||||
pretty_print=True)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user