listing of books

This commit is contained in:
Kovid Goyal 2006-11-16 06:15:12 +00:00
parent e456f6e828
commit a44a2e578b
2 changed files with 107 additions and 7 deletions

View File

@ -46,6 +46,11 @@ The public interface of class L{PRS500Device} defines the methods for performing
"""
import usb, sys, os, time
from array import array
from xml.sax.handler import ContentHandler
from xml.sax import make_parser
from xml.sax.handler import feature_namespaces
from base64 import b64decode as decode
from tempfile import TemporaryFile
from prstypes import *
from errors import *
@ -62,6 +67,54 @@ def _log_packet(packet, header, stream=sys.stderr):
print >>stream, packet
print >>stream, "--"
class FindBooks(ContentHandler):
""" Used to parse the cache.xml/media.xml files on the PRS 500 """
class Book(dict):
def __init__(self, src):
dict.__init__(self, src)
if not self.has_key("author") or len(self["author"].rstrip()) == 0:
self["author"] = "Unknown"
self["title"] = self["title"].strip()
def __repr__(self):
return self["title"] + " by " + self["author"] + " at " + self["path"]
def __str__(self):
return self.__repr__()
def __init__(self, type="media", root="/Data/media/"):
ContentHandler.__init__(self)
self.books = []
self.root = root
self.thumbnail = ""
self.in_book = False
self.in_thumbnail = False
self.book_name = "text"
self.thumbnail_name = "thumbnail"
if type == "media":
self.book_name = "xs1:" + self.book_name
self.thumbnail_name = "xs1:" + self.thumbnail_name
def startElement(self, name, attrs):
if name == self.book_name:
data = FindBooks.Book(attrs)
data["path"] = self.root + data["path"]
self.books.append(data)
self.in_book = True
elif self.in_book and name == self.thumbnail_name:
self.in_thumbnail = True
def characters(self, ch):
if self.in_thumbnail:
self.thumbnail += ch
def endElement(self, name):
if self.in_book and name == self.thumbnail_name:
if len(self.books) > 0: self.books[len(self.books)-1]["thumbnail"] = decode(self.thumbnail)
self.thumbnail, self.in_thumbnail = "", False
elif name == self.book_name: self.in_book = False
class File(object):
""" Wrapper that allows easy access to all information about files/directories """
def __init__(self, file):
@ -338,9 +391,9 @@ class PRS500Device(object):
self._send_validated_command(FileClose(id))
raise ProtocolError("Error while reading from " + path + ". Response code: " + hex(res.code))
packets = self._bulk_read(chunk_size+16, command_number=FileIO.RNUMBER, packet_size=4096)
try:
try:
array('B', packets[0][16:]).tofile(outfile) # The first 16 bytes are meta information on the packet stream
for i in range(1, len(packets)):
for i in range(1, len(packets)):
array('B', packets[i]).tofile(outfile)
except IOError, e:
self._send_validated_command(FileClose(id))
@ -529,11 +582,49 @@ class PRS500Device(object):
raise PathError("Cannot delete directory " + path + " as it is not empty")
if res.code != 0:
raise ProtocolError("Failed to delete directory " + path + ". Response code: " + hex(res.code))
@safe
def books(self):
"""
Return a list of all ebooks on the device
@return: A two element tuple. The first element is the books in the main memory and the second is the books on the storage card.
Each element is a list of dictionaries. Important fields in each dictionary are "title", "author", "path" and "thumbnail".
"""
buffer = TemporaryFile()
media = self.get_file("/Data/database/cache/media.xml", buffer, end_session=False)
parser = make_parser()
parser.setFeature(feature_namespaces, 0)
finder = FindBooks()
parser.setContentHandler(finder)
buffer.seek(0)
parser.parse(buffer)
buffer.close()
books = finder.books
root = "a:/"
buffer = TemporaryFile()
cbooks = []
try:
self.get_file("a:/Sony Reader/database/cache.xml", buffer, end_session=False)
except PathError:
try:
self.get_file("b:/Sony Reader/database/cache.xml", buffer, end_session=False)
root = "b:/"
except PathError:
pass
if buffer.tell() > 0:
finder = FindBooks(type="cache", root=root)
buffer.seek(0)
parser.setContentHandler(finder)
parser.parse(buffer)
buffer.close()
cbooks = finder.books
return books, cbooks
#dev = PRS500Device(log_packets=False)
#dev.open()
#print dev.get_file("/etc/sysctl.conf", sys.stdout)
#dev.close()
##dev = PRS500Device(log_packets=False)
##dev.open()
##print dev.books()
##dev.close()

View File

@ -165,7 +165,7 @@ def main():
term = TerminalController()
cols = term.COLS
parser = OptionParser(usage="usage: %prog [options] command args\n\ncommand is one of: info, df, ls, cp, mkdir, touch, cat or rm\n\n"+
parser = OptionParser(usage="usage: %prog [options] command args\n\ncommand is one of: info, books, df, ls, cp, mkdir, touch, cat or rm\n\n"+
"For help on a particular command: %prog command", version="libprs500 version: " + VERSION)
parser.add_option("--log-packets", help="print out packet stream to stdout. "+\
"The numbers in the left column are byte offsets that allow the packet size to be read off easily.",
@ -189,6 +189,15 @@ def main():
total, free, used, percent = human_readable(datum[2]), human_readable(datum[1]), human_readable(datum[2]-datum[1]), \
str(0 if datum[2]==0 else int(100*(datum[2]-datum[1])/(datum[2]*1.)))+"%"
print "%-10s\t%s\t%s\t%s\t%s"%(datum[0], total, used, free, percent)
elif command == "books":
main, card = dev.books()
print "Books in main memory:"
for book in main:
print book
print
print "Books on storage card:"
for book in card:
print book
elif command == "mkdir":
parser = OptionParser(usage="usage: %prog mkdir [options] path\n\npath must begin with /,a:/ or b:/")
if len(args) != 1: