diff --git a/src/calibre/library/server.py b/src/calibre/library/server.py
index f615827cde..015df2b017 100644
--- a/src/calibre/library/server.py
+++ b/src/calibre/library/server.py
@@ -24,7 +24,7 @@ except ImportError:
from calibre.constants import __version__, __appname__
from calibre.utils.genshi.template import MarkupTemplate
from calibre import fit_image, guess_type, prepare_string_for_xml, \
- strftime as _strftime
+ strftime as _strftime, prints
from calibre.library import server_config as config
from calibre.library.database2 import LibraryDatabase2, FIELD_MAP
from calibre.utils.config import config_dir
@@ -77,6 +77,159 @@ class LibraryServer(object):
''')
+ MOBILE_UA = re.compile('(?i)(?:iPhone|Opera Mini|NetFront|webOS|Mobile|Android|imode|DoCoMo|Minimo|Blackberry|MIDP|Symbian)')
+
+ MOBILE_BOOK = textwrap.dedent('''\
+
+
+
+ |
+
+
+ ${format.lower()}
+
+ ${r[1]} by ${authors} - ${r[6]/1024}k - ${r[3] if r[3] else ''} ${pubdate} ${'['+r[7]+']' if r[7] else ''}
+ |
+
+ ''')
+
+ MOBILE = MarkupTemplate(textwrap.dedent('''\
+
+
+
+
+
+
+
+

+
+
+
+
Books ${start} to ${ min((start+num-1) , total) } of ${total}
+
+
+
+
+
+
+ '''))
+
LIBRARY = MarkupTemplate(textwrap.dedent('''\
@@ -534,6 +687,52 @@ class LibraryServer(object):
next_link=next_link, updated=updated, id='urn:calibre:main').render('xml')
+ @expose
+ 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)
+ ids = self.db.data.parse(search) if search and search.strip() else self.db.data.universal_set()
+ ids = sorted(ids)
+ items = [r for r in iter(self.db) if r[0] in ids]
+ if sort is not None:
+ self.sort(items, sort, (order.lower().strip() == 'ascending'))
+
+ book, books = MarkupTemplate(self.MOBILE_BOOK), []
+ for record in items[(start-1):(start-1)+num]:
+ aus = record[2] if record[2] else __builtin__._('Unknown')
+ authors = '|'.join([i.replace('|', ',') for i in aus.split(',')])
+ record[10] = fmt_sidx(float(record[10]))
+ ts, pd = strftime('%Y/%m/%d %H:%M:%S', record[5]), \
+ strftime('%Y/%m/%d %H:%M:%S', record[FIELD_MAP['pubdate']])
+ books.append(book.generate(r=record, authors=authors, timestamp=ts,
+ pubdate=pd).render('xml').decode('utf-8'))
+ 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)
+
+ return self.MOBILE.generate(books=books, start=start, updated=updated, search=search, sort=sort, order=order, num=num,
+ total=len(ids), url_base=url_base).render('html')
+
+
@expose
def library(self, start='0', num='50', sort=None, search=None,
_=None, order='ascending'):
@@ -584,10 +783,22 @@ class LibraryServer(object):
cherrypy.request.headers.get('Stanza-Device-Name', 919) != 919 or \
cherrypy.request.headers.get('Want-OPDS-Catalog', 919) != 919 or \
ua.startswith('Stanza')
- return self.stanza(search=kwargs.get('search', None), sortby=kwargs.get('sortby',None), authorid=kwargs.get('authorid',None),
+
+ # A better search would be great
+ want_mobile = self.MOBILE_UA.search(ua) is not None
+ if self.opts.develop and not want_mobile:
+ prints('User agent:', ua)
+
+ if want_opds:
+ return self.stanza(search=kwargs.get('search', None), sortby=kwargs.get('sortby',None), authorid=kwargs.get('authorid',None),
tagid=kwargs.get('tagid',None),
seriesid=kwargs.get('seriesid',None),
- offset=kwargs.get('offset', 0)) if want_opds else self.static('index.html')
+ offset=kwargs.get('offset', 0))
+
+ if want_mobile:
+ return self.mobile()
+
+ return self.static('index.html')
@expose