Merge from custcol trunk

This commit is contained in:
Charles Haley 2010-05-20 08:40:00 +01:00
commit 07246d842a
9 changed files with 187 additions and 153 deletions

View File

@ -442,7 +442,7 @@ from calibre.devices.irexdr.driver import IREXDR1000, IREXDR800
from calibre.devices.jetbook.driver import JETBOOK
from calibre.devices.kindle.driver import KINDLE, KINDLE2, KINDLE_DX
from calibre.devices.nook.driver import NOOK
from calibre.devices.prs505.driver import PRS505, PRS700
from calibre.devices.prs505.driver import PRS505
from calibre.devices.android.driver import ANDROID, S60
from calibre.devices.nokia.driver import N770, N810
from calibre.devices.eslick.driver import ESLICK
@ -510,7 +510,6 @@ plugins += [
KINDLE_DX,
NOOK,
PRS505,
PRS700,
ANDROID,
S60,
N770,

View File

@ -293,8 +293,7 @@ class DevicePlugin(Plugin):
put the book. len(metadata) == len(files). Apart from the regular
cover (path to cover), there may also be a thumbnail attribute, which should
be used in preference. The thumbnail attribute is of the form
(width, height, cover_data as jpeg). In addition the MetaInformation
objects can have a tag_order attribute.
(width, height, cover_data as jpeg).
'''
raise NotImplementedError()
@ -396,14 +395,6 @@ class BookList(list):
''' Return True if the the device supports tags (collections) for this book list. '''
raise NotImplementedError()
def set_tags(self, book, tags):
'''
Set the tags for C{book} to C{tags}.
@param tags: A list of strings. Can be empty.
@param book: A book object that is in this BookList.
'''
raise NotImplementedError()
def add_book(self, book, replace_metadata):
'''
Add the book to the booklist. Intent is to maintain any device-internal

View File

@ -1,12 +1,9 @@
# -*- coding: utf-8 -*-
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net> ' \
'2009, John Schember <john at nachtimwald.com>'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
'''
Device driver for the SONY PRS-505
Device driver for the SONY devices
'''
import os
@ -20,27 +17,33 @@ from calibre import __appname__
class PRS505(USBMS):
name = 'PRS-300/505 Device Interface'
name = 'SONY Device Interface'
gui_name = 'SONY Reader'
description = _('Communicate with the Sony PRS-300/505/500 eBook reader.')
author = 'Kovid Goyal and John Schember'
description = _('Communicate with all the Sony eBook readers.')
author = 'Kovid Goyal'
supported_platforms = ['windows', 'osx', 'linux']
path_sep = '/'
FORMATS = ['epub', 'lrf', 'lrx', 'rtf', 'pdf', 'txt']
VENDOR_ID = [0x054c] #: SONY Vendor Id
PRODUCT_ID = [0x031e] #: Product Id for the PRS 300/505/new 500
BCD = [0x229, 0x1000, 0x22a]
PRODUCT_ID = [0x031e]
BCD = [0x229, 0x1000, 0x22a, 0x31a]
VENDOR_NAME = 'SONY'
WINDOWS_MAIN_MEM = re.compile('PRS-(505|300|500)')
WINDOWS_CARD_A_MEM = re.compile(r'PRS-(505|500)[#/]\S+:MS')
WINDOWS_CARD_B_MEM = re.compile(r'PRS-(505|500)[#/]\S+:SD')
WINDOWS_MAIN_MEM = re.compile(
r'(PRS-(505|300|500))|'
r'(PRS-((700[#/])|((6|9)00&)))'
)
WINDOWS_CARD_A_MEM = re.compile(
r'(PRS-(505|500)[#/]\S+:MS)|'
r'(PRS-((700[/#]\S+:)|((6|9)00[#_]))MS)'
)
WINDOWS_CARD_B_MEM = re.compile(
r'(PRS-(505|500)[#/]\S+:SD)|'
r'(PRS-((700[/#]\S+:)|((6|9)00[#_]))SD)'
)
OSX_MAIN_MEM = re.compile(r'Sony PRS-(((505|300|500)/[^:]+)|(300)) Media')
OSX_CARD_A_MEM = re.compile(r'Sony PRS-(505|500)/[^:]+:MS Media')
OSX_CARD_B_MEM = re.compile(r'Sony PRS-(505|500)/[^:]+:SD Media')
MAIN_MEMORY_VOLUME_LABEL = 'Sony Reader Main Memory'
STORAGE_CARD_VOLUME_LABEL = 'Sony Reader Storage Card'
@ -101,27 +104,12 @@ class PRS505(USBMS):
opts = self.settings()
collections = ['series', 'tags']
if opts.extra_customization:
collections = opts.extra_customization.split(',')
collections = [x.strip() for x in
opts.extra_customization.split(',')]
c.update(blists, collections)
c.write()
USBMS.sync_booklists(self, booklists, end_session=end_session)
class PRS700(PRS505):
name = 'PRS-600/700/900 Device Interface'
description = _('Communicate with the Sony PRS-600/700/900 eBook reader.')
author = 'Kovid Goyal and John Schember'
gui_name = 'SONY Reader'
supported_platforms = ['windows', 'osx', 'linux']
BCD = [0x31a]
WINDOWS_MAIN_MEM = re.compile('PRS-((700[#/])|((6|9)00&))')
WINDOWS_CARD_A_MEM = re.compile(r'PRS-((700[/#]\S+:)|((6|9)00[#_]))MS')
WINDOWS_CARD_B_MEM = re.compile(r'PRS-((700[/#]\S+:)|((6|9)00[#_]))SD')
OSX_MAIN_MEM = re.compile(r'Sony PRS-((700/[^:]+)|((6|9)00)) Media')
OSX_CARD_A_MEM = re.compile(r'Sony PRS-((700/[^:]+:)|((6|9)00 ))MS Media')
OSX_CARD_B_MEM = re.compile(r'Sony PRS-((700/[^:]+:)|((6|9)00 ))SD Media')

View File

@ -101,16 +101,25 @@ class XMLCache(object):
# Playlist management {{{
def purge_broken_playlist_items(self, root):
for item in root.xpath(
'//*[local-name()="playlist"]/*[local-name()="item"]'):
id_ = item.get('id', None)
if id_ is None or not root.xpath(
'//*[local-name()!="item" and @id="%s"]'%id_):
if DEBUG:
prints('Purging broken playlist item:',
etree.tostring(item, with_tail=False))
item.getparent().remove(item)
for pl in root.xpath('//*[local-name()="playlist"]'):
seen = set([])
for item in list(pl):
id_ = item.get('id', None)
if id_ is None or id_ in seen or not root.xpath(
'//*[local-name()!="item" and @id="%s"]'%id_):
if DEBUG:
if id_ is None:
cause = 'invalid id'
elif id_ in seen:
cause = 'duplicate item'
else:
cause = 'id not found'
prints('Purging broken playlist item:',
id_, 'from playlist:', pl.get('title', None),
'because:', cause)
item.getparent().remove(item)
continue
seen.add(id_)
def prune_empty_playlists(self):
for i, root in self.record_roots.items():
@ -144,7 +153,7 @@ class XMLCache(object):
self.ensure_unique_playlist_titles()
self.prune_empty_playlists()
for i, root in self.record_roots.items():
ans[i] = {}
ans[i] = []
for playlist in root.xpath('//*[local-name()="playlist"]'):
items = []
for item in playlist:
@ -153,7 +162,7 @@ class XMLCache(object):
'//*[local-name()="text" and @id="%s"]'%id_)
if records:
items.append(records[0])
ans[i] = {playlist.get('title'):items}
ans[i].append((playlist.get('title'), items))
return ans
def get_or_create_playlist(self, bl_idx, title):
@ -175,6 +184,8 @@ class XMLCache(object):
# }}}
def fix_ids(self): # {{{
if DEBUG:
prints('Running fix_ids()')
def ensure_numeric_ids(root):
idmap = {}
@ -255,7 +266,19 @@ class XMLCache(object):
def update_booklist(self, bl, bl_index):
if bl_index not in self.record_roots:
return
if DEBUG:
prints('Updating JSON cache:', bl_index)
root = self.record_roots[bl_index]
pmap = self.get_playlist_map()[bl_index]
playlist_map = {}
for title, records in pmap:
for record in records:
path = record.get('path', None)
if path:
if path not in playlist_map:
playlist_map[path] = []
playlist_map[path].append(title)
for book in bl:
record = self.book_by_lpath(book.lpath, root)
if record is not None:
@ -282,6 +305,10 @@ class XMLCache(object):
book.thumbnail = raw
break
break
if book.lpath in playlist_map:
tags = playlist_map[book.lpath]
book.device_collections = tags
# }}}
# Update XML from JSON {{{
@ -290,7 +317,7 @@ class XMLCache(object):
for i, booklist in booklists.items():
if DEBUG:
prints('Updating booklist:', i)
prints('Updating XML Cache:', i)
root = self.record_roots[i]
for book in booklist:
path = os.path.join(self.prefixes[i], *(book.lpath.split('/')))
@ -304,6 +331,10 @@ class XMLCache(object):
self.fix_ids()
# This is needed to update device_collections
for i, booklist in booklists.items():
self.update_booklist(booklist, i)
def update_playlists(self, bl_index, root, booklist, playlist_map,
collections_attributes):
collections = booklist.get_collections(collections_attributes)
@ -340,7 +371,25 @@ class XMLCache(object):
nsmap=playlist.nsmap, attrib={'id':id_})
playlist.append(item)
# Delete playlist entries not in collections
for playlist in root.xpath('//*[local-name()="playlist"]'):
title = playlist.get('title', None)
if title not in collections:
if DEBUG:
prints('Deleting playlist:', playlist.get('title', ''))
playlist.getparent().remove(playlist)
continue
books = collections[title]
records = [self.book_by_lpath(b.lpath, root) for b in books]
records = [x for x in records if x is not None]
ids = [x.get('id', None) for x in records]
ids = [x for x in ids if x is not None]
for item in list(playlist):
if item.get('id', None) not in ids:
if DEBUG:
prints('Deleting item:', item.get('id', ''),
'from playlist:', playlist.get('title', ''))
playlist.remove(item)
def create_text_record(self, root, bl_id, lpath):
namespace = self.namespaces[bl_id]
@ -395,8 +444,19 @@ class XMLCache(object):
child.iterchildren(reversed=True).next().tail = '\n'+'\t'*level
root.iterchildren(reversed=True).next().tail = '\n'+'\t'*(level-1)
def move_playlists_to_bottom(self):
for root in self.record_roots.values():
seen = []
for pl in root.xpath('//*[local-name()="playlist"]'):
pl.getparent().remove(pl)
seen.append(pl)
for pl in seen:
root.append(pl)
def write(self):
for i, path in self.paths.items():
self.move_playlists_to_bottom()
self.cleanup_whitespace(i)
raw = etree.tostring(self.roots[i], encoding='UTF-8',
xml_declaration=True)

View File

@ -14,14 +14,14 @@ from calibre import isbytestring
class Book(MetaInformation):
BOOK_ATTRS = ['lpath', 'size', 'mime']
BOOK_ATTRS = ['lpath', 'size', 'mime', 'device_collections']
JSON_ATTRS = [
'lpath', 'title', 'authors', 'mime', 'size', 'tags', 'author_sort',
'title_sort', 'comments', 'category', 'publisher', 'series',
'series_index', 'rating', 'isbn', 'language', 'application_id',
'book_producer', 'lccn', 'lcc', 'ddc', 'rights', 'publication_type',
'uuid'
'uuid',
]
def __init__(self, prefix, lpath, size=None, other=None):
@ -29,6 +29,7 @@ class Book(MetaInformation):
MetaInformation.__init__(self, '')
self.device_collections = []
self.path = os.path.join(prefix, lpath)
if os.sep == '\\':
self.path = self.path.replace('/', '\\')
@ -45,27 +46,7 @@ class Book(MetaInformation):
self.smart_update(other)
def __eq__(self, other):
spath = self.path
opath = other.path
if not isinstance(self.path, unicode):
try:
spath = unicode(self.path)
except:
try:
spath = self.path.decode(filesystem_encoding)
except:
spath = self.path
if not isinstance(other.path, unicode):
try:
opath = unicode(other.path)
except:
try:
opath = other.path.decode(filesystem_encoding)
except:
opath = other.path
return spath == opath
return self.path == getattr(other, 'path', None)
@dynamic_property
def db_id(self):
@ -119,9 +100,6 @@ class BookList(_BookList):
def supports_tags(self):
return True
def set_tags(self, book, tags):
book.tags = tags
def add_book(self, book, replace_metadata):
if book not in self:
self.append(book)
@ -134,7 +112,9 @@ class BookList(_BookList):
def get_collections(self, collection_attributes):
collections = {}
series_categories = set([])
collection_attributes = list(collection_attributes)+['device_collections']
for attr in collection_attributes:
attr = attr.strip()
for book in self:
val = getattr(book, attr, None)
if not val: continue
@ -145,11 +125,17 @@ class BookList(_BookList):
elif isinstance(val, unicode):
val = [val]
for category in val:
if attr == 'tags' and len(category) > 1 and \
category[0] == '[' and category[-1] == ']':
continue
if category not in collections:
collections[category] = []
collections[category].append(book)
if attr == 'series':
series_categories.add(category)
if book not in collections[category]:
collections[category].append(book)
if attr == 'series':
series_categories.add(category)
# Sort collections
for category, books in collections.items():
def tgetter(x):
return getattr(x, 'title_sort', 'zzzz')

View File

@ -258,7 +258,7 @@ class MetaInformation(object):
'series', 'series_index', 'tags', 'rating', 'isbn', 'language',
'application_id', 'manifest', 'toc', 'spine', 'guide', 'cover',
'book_producer', 'timestamp', 'lccn', 'lcc', 'ddc', 'pubdate',
'rights', 'publication_type', 'uuid', 'tag_order',
'rights', 'publication_type', 'uuid'
):
prints(x, getattr(self, x, 'None'))
@ -278,7 +278,7 @@ class MetaInformation(object):
'isbn', 'application_id', 'manifest', 'spine', 'toc',
'cover', 'language', 'guide', 'book_producer',
'timestamp', 'lccn', 'lcc', 'ddc', 'pubdate', 'rights',
'publication_type', 'uuid', 'tag_order'):
'publication_type', 'uuid'):
if hasattr(mi, attr):
val = getattr(mi, attr)
if val is not None:

View File

@ -102,6 +102,9 @@ class BooksModel(QAbstractTableModel): # {{{
def set_device_connected(self, is_connected):
self.device_connected = is_connected
self.db.refresh_ondevice()
if is_connected and self.sorted_on[0] == 'ondevice':
self.resort()
def set_book_on_device_func(self, func):
self.book_on_device = func
@ -340,9 +343,6 @@ class BooksModel(QAbstractTableModel): # {{{
ans = []
for id in ids:
mi = self.db.get_metadata(id, index_is_id=True, get_cover=True)
if mi.series is not None:
mi.tag_order = { mi.series: self.db.books_in_series_of(id,
index_is_id=True)}
ans.append(mi)
return ans
@ -807,7 +807,7 @@ class DeviceBooksModel(BooksModel): # {{{
'authors' : _('Author(s)'),
'timestamp' : _('Date'),
'size' : _('Size'),
'tags' : _('Tags')
'tags' : _('Collections')
}
self.marked_for_deletion = {}
self.search_engine = OnDeviceSearch(self)
@ -896,7 +896,8 @@ class DeviceBooksModel(BooksModel): # {{{
x, y = int(self.db[x].size), int(self.db[y].size)
return cmp(x, y)
def tagscmp(x, y):
x, y = ','.join(self.db[x].tags), ','.join(self.db[y].tags)
x = ','.join(self.db[x].device_collections)
y = ','.join(self.db[y].device_collections)
return cmp(x, y)
def libcmp(x, y):
x, y = self.db[x].in_library, self.db[y].in_library
@ -966,7 +967,7 @@ class DeviceBooksModel(BooksModel): # {{{
data[_('Path')] = item.path
dt = dt_factory(item.datetime, assume_utc=True)
data[_('Timestamp')] = isoformat(dt, sep=' ', as_utc=False)
data[_('Tags')] = ', '.join(item.tags)
data[_('Collections')] = ', '.join(item.device_collections)
self.new_bookdisplay_data.emit(data)
def paths(self, rows):
@ -1000,7 +1001,7 @@ class DeviceBooksModel(BooksModel): # {{{
dt = dt_factory(dt, assume_utc=True, as_utc=False)
return QVariant(strftime(TIME_FMT, dt.timetuple()))
elif cname == 'tags':
tags = self.db[self.map[row]].tags
tags = self.db[self.map[row]].device_collections
if tags:
return QVariant(', '.join(tags))
elif role == Qt.ToolTipRole and index.isValid():
@ -1047,7 +1048,7 @@ class DeviceBooksModel(BooksModel): # {{{
elif cname == 'tags':
tags = [i.strip() for i in val.split(',')]
tags = [t for t in tags if t]
self.db.set_tags(self.db[idx], tags)
self.db[idx].device_collections = tags
self.dataChanged.emit(index, index)
self.booklist_dirtied.emit()
done = True

View File

@ -578,12 +578,14 @@ class ResultCache(SearchQueryParser):
self._map_filtered = list(self._map)
def seriescmp(self, x, y):
sidx = self.FIELD_MAP['series']
try:
ans = cmp(self._data[x][9].lower(), self._data[y][9].lower())
ans = cmp(self._data[x][sidx].lower(), self._data[y][sidx].lower())
except AttributeError: # Some entries may be None
ans = cmp(self._data[x][9], self._data[y][9])
ans = cmp(self._data[x][sidx], self._data[y][sidx])
if ans != 0: return ans
return cmp(self._data[x][10], self._data[y][10])
sidx = self.FIELD_MAP['series_index']
return cmp(self._data[x][sidx], self._data[y][sidx])
def cmp(self, loc, x, y, asstr=True, subsort=False):
try:

View File

@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
HTTP server for remote access to the calibre database.
'''
import sys, textwrap, operator, os, re, logging, cStringIO
import sys, textwrap, operator, os, re, logging, cStringIO, copy
import __builtin__
from itertools import repeat
from logging.handlers import RotatingFileHandler
@ -63,21 +63,21 @@ class LibraryServer(object):
BOOK = textwrap.dedent('''\
<book xmlns:py="http://genshi.edgewall.org/"
id="${r[0]}"
title="${r[1]}"
sort="${r[11]}"
author_sort="${r[12]}"
id="${r[FM['id']]}"
title="${r[FM['title']]}"
sort="${r[FM['sort']]}"
author_sort="${r[FM['author_sort']]}"
authors="${authors}"
rating="${r[4]}"
rating="${r[FM['rating']]}"
timestamp="${timestamp}"
pubdate="${pubdate}"
size="${r[6]}"
isbn="${r[14] if r[14] else ''}"
formats="${r[13] if r[13] else ''}"
series = "${r[9] if r[9] else ''}"
series_index="${r[10]}"
tags="${r[7] if r[7] else ''}"
publisher="${r[3] if r[3] else ''}">${r[8] if r[8] else ''}
size="${r[FM['size']]}"
isbn="${r[FM['isbn']] if r[FM['isbn']] else ''}"
formats="${r[FM['formats']] if r[FM['formats']] else ''}"
series = "${r[FM['series']] if r[FM['series']] else ''}"
series_index="${r[FM['series_index']]}"
tags="${r[FM['tags']] if r[FM['tags']] else ''}"
publisher="${r[FM['publisher']] if r[FM['publisher']] else ''}">${r[FM['comments']] if r[FM['comments']] else ''}
</book>
''')
@ -86,13 +86,13 @@ class LibraryServer(object):
MOBILE_BOOK = textwrap.dedent('''\
<tr xmlns:py="http://genshi.edgewall.org/">
<td class="thumbnail">
<img type="image/jpeg" src="/get/thumb/${r[0]}" border="0"/>
<img type="image/jpeg" src="/get/thumb/${r[FM['id']]}" border="0"/>
</td>
<td>
<py:for each="format in r[13].split(',')">
<span class="button"><a href="/get/${format}/${authors}-${r[1]}_${r[0]}.${format}">${format.lower()}</a></span>&nbsp;
<py:for each="format in r[FM['formats']].split(',')">
<span class="button"><a href="/get/${format}/${authors}-${r[FM['title']]}_${r[FM['id']]}.${format}">${format.lower()}</a></span>&nbsp;
</py:for>
${r[1]}${(' ['+r[9]+'-'+r[10]+']') if r[9] else ''} by ${authors} - ${r[6]/1024}k - ${r[3] if r[3] else ''} ${pubdate} ${'['+r[7]+']' if r[7] else ''}
${r[FM['title']]}${(' ['+r[FM['series']]+'-'+r[FM['series_index']]+']') if r[FM['series']] else ''} by ${authors} - ${r[FM['size']]/1024}k - ${r[FM['publisher']] if r[FM['publisher']] else ''} ${pubdate} ${'['+r[FM['tags']]+']' if r[FM['tags']] else ''}
</td>
</tr>
''')
@ -628,22 +628,23 @@ class LibraryServer(object):
ids = self.db.data.parse(search) if search and search.strip() else self.db.data.universal_set()
record_list = list(iter(self.db))
FM = self.db.FIELD_MAP
# Sort the record list
if sortby == "bytitle" or authorid or tagid:
record_list.sort(lambda x, y:
cmp(title_sort(x[self.db.FIELD_MAP['title']]),
title_sort(y[self.db.FIELD_MAP['title']])))
cmp(title_sort(x[FM['title']]),
title_sort(y[FM['title']])))
elif seriesid:
record_list.sort(lambda x, y:
cmp(x[self.db.FIELD_MAP['series_index']],
y[self.db.FIELD_MAP['series_index']]))
cmp(x[FM['series_index']],
y[FM['series_index']]))
else: # Sort by date
record_list = reversed(record_list)
fmts = self.db.FIELD_MAP['formats']
fmts = FM['formats']
pat = re.compile(r'EPUB|PDB', re.IGNORECASE)
record_list = [x for x in record_list if x[0] in ids and
record_list = [x for x in record_list if x[FM['id']] in ids and
pat.search(x[fmts] if x[fmts] else '') is not None]
next_offset = offset + self.max_stanza_items
nrecord_list = record_list[offset:next_offset]
@ -663,10 +664,10 @@ class LibraryServer(object):
) % '&amp;'.join(q)
for record in nrecord_list:
r = record[self.db.FIELD_MAP['formats']]
r = record[FM['formats']]
r = r.upper() if r else ''
z = record[self.db.FIELD_MAP['authors']]
z = record[FM['authors']]
if not z:
z = _('Unknown')
authors = ' & '.join([i.replace('|', ',') for i in
@ -674,19 +675,19 @@ class LibraryServer(object):
# Setup extra description
extra = []
rating = record[self.db.FIELD_MAP['rating']]
rating = record[FM['rating']]
if rating > 0:
rating = ''.join(repeat('&#9733;', rating))
extra.append('RATING: %s<br />'%rating)
tags = record[self.db.FIELD_MAP['tags']]
tags = record[FM['tags']]
if tags:
extra.append('TAGS: %s<br />'%\
prepare_string_for_xml(', '.join(tags.split(','))))
series = record[self.db.FIELD_MAP['series']]
series = record[FM['series']]
if series:
extra.append('SERIES: %s [%s]<br />'%\
(prepare_string_for_xml(series),
fmt_sidx(float(record[self.db.FIELD_MAP['series_index']]))))
fmt_sidx(float(record[FM['series_index']]))))
fmt = 'epub' if 'EPUB' in r else 'pdb'
mimetype = guess_type('dummy.'+fmt)[0]
@ -699,17 +700,18 @@ class LibraryServer(object):
authors=authors,
tags=tags,
series=series,
FM=self.db.FIELD_MAP,
FM=FM,
extra='\n'.join(extra),
mimetype=mimetype,
fmt=fmt,
urn=record[self.db.FIELD_MAP['uuid']],
timestamp=strftime('%Y-%m-%dT%H:%M:%S+00:00', record[5])
urn=record[FM['uuid']],
timestamp=strftime('%Y-%m-%dT%H:%M:%S+00:00',
record[FM['timestamp']])
)
books.append(self.STANZA_ENTRY.generate(**data)\
.render('xml').decode('utf8'))
return self.STANZA.generate(subtitle='', data=books, FM=self.db.FIELD_MAP,
return self.STANZA.generate(subtitle='', data=books, FM=FM,
next_link=next_link, updated=updated, id='urn:calibre:main').render('xml')
@ -734,23 +736,25 @@ class LibraryServer(object):
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]
FM = self.db.FIELD_MAP
items = copy.deepcopy([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'))
book, books = MarkupTemplate(self.MOBILE_BOOK), []
for record in items[(start-1):(start-1)+num]:
if record[13] is None:
record[13] = ''
if record[6] is None:
record[6] = 0
aus = record[2] if record[2] else __builtin__._('Unknown')
if record[FM['formats']] is None:
record[FM['formats']] = ''
if record[FM['size']] is None:
record[FM['size']] = 0
aus = record[FM['authors']] if record[FM['authors']] 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[self.db.FIELD_MAP['pubdate']])
record[FM['series_index']] = \
fmt_sidx(float(record[FM['series_index']]))
ts, pd = strftime('%Y/%m/%d %H:%M:%S', record[FM['timestamp']]), \
strftime('%Y/%m/%d %H:%M:%S', record[FM['pubdate']])
books.append(book.generate(r=record, authors=authors, timestamp=ts,
pubdate=pd).render('xml').decode('utf-8'))
pubdate=pd, FM=FM).render('xml').decode('utf-8'))
updated = self.db.last_modified()
cherrypy.response.headers['Content-Type'] = 'text/html; charset=utf-8'
@ -759,8 +763,9 @@ class LibraryServer(object):
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')
return self.MOBILE.generate(books=books, start=start, updated=updated,
search=search, sort=sort, order=order, num=num, FM=FM,
total=len(ids), url_base=url_base).render('html')
@expose
@ -785,25 +790,27 @@ class LibraryServer(object):
order = order.lower().strip() == 'ascending'
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]
FM = self.db.FIELD_MAP
items = copy.deepcopy([r for r in iter(self.db) if r[FM['id']] in ids])
if sort is not None:
self.sort(items, sort, order)
book, books = MarkupTemplate(self.BOOK), []
for record in items[start:start+num]:
aus = record[2] if record[2] else __builtin__._('Unknown')
aus = record[FM['authors']] if record[FM['authors']] 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[self.db.FIELD_MAP['pubdate']])
record[FM['series_index']] = \
fmt_sidx(float(record[FM['series_index']]))
ts, pd = strftime('%Y/%m/%d %H:%M:%S', record[FM['timestamp']]), \
strftime('%Y/%m/%d %H:%M:%S', record[FM['pubdate']])
books.append(book.generate(r=record, authors=authors, timestamp=ts,
pubdate=pd).render('xml').decode('utf-8'))
pubdate=pd, FM=FM).render('xml').decode('utf-8'))
updated = self.db.last_modified()
cherrypy.response.headers['Content-Type'] = 'text/xml'
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
return self.LIBRARY.generate(books=books, start=start, updated=updated,
total=len(ids)).render('xml')
total=len(ids), FM=FM).render('xml')
@expose
def index(self, **kwargs):