Make EPUB metadata editing more robust and send LRF files to the 505 in preference to EPUB

This commit is contained in:
Kovid Goyal 2008-09-05 21:30:16 -07:00
parent deebf85442
commit c3611c0918
6 changed files with 67 additions and 16 deletions

View File

@ -31,7 +31,7 @@ class PRS505(Device):
PRODUCT_ID = 0x031e #: Product Id for the PRS-505
PRODUCT_NAME = 'PRS-505'
VENDOR_NAME = 'SONY'
FORMATS = ["lrf", 'epub', "rtf", "pdf", "txt"]
FORMATS = ['lrf', 'epub', "rtf", "pdf", "txt"]
MEDIA_XML = 'database/cache/media.xml'
CACHE_XML = 'Sony Reader/database/cache.xml'

View File

@ -22,6 +22,7 @@ __docformat__ = "epytext"
preferred_source_formats = [
'LIT',
'MOBI',
'EPUB',
'HTML',
'HTM',
'XHTM',

View File

@ -7,7 +7,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import sys, os
from calibre.utils.zipfile import ZipFile, BadZipfile
from calibre.utils.zipfile import ZipFile, BadZipfile, safe_replace
from cStringIO import StringIO
from contextlib import closing
@ -73,7 +73,7 @@ class OCFReader(OCF):
class OCFZipReader(OCFReader):
def __init__(self, stream, mode='r'):
try:
self.archive = ZipFile(stream, mode)
self.archive = ZipFile(stream, mode=mode)
except BadZipfile:
raise EPubException("not a ZIP .epub OCF container")
self.root = getattr(stream, 'name', os.getcwd())
@ -82,18 +82,20 @@ class OCFZipReader(OCFReader):
def open(self, name, mode='r'):
return StringIO(self.archive.read(name))
class OCFZipWriter(OCFZipReader):
class OCFZipWriter(object):
def __init__(self, stream):
OCFZipReader.__init__(self, stream, mode='a')
reader = OCFZipReader(stream)
self.opf = reader.container[OPF.MIMETYPE]
self.stream = stream
self.root = getattr(stream, 'name', os.getcwd())
def set_metadata(self, mi):
name = self.container[OPF.MIMETYPE]
stream = StringIO()
opf = OPFCreator(self.root, mi)
opf.render(stream)
self.archive.delete(name)
self.archive.writestr(name, stream.getvalue())
stream.seek(0)
safe_replace(self.stream, self.opf, stream)
class OCFDirReader(OCFReader):
def __init__(self, path):
@ -133,9 +135,8 @@ def main(args=sys.argv):
mi.tags = opts.tags.split(',')
if opts.comment:
mi.comments = opts.comment
set_metadata(stream, mi)
print unicode(mi)
return 0

View File

@ -311,11 +311,14 @@ class BooksModel(QAbstractTableModel):
ans = []
for row in (row.row() for row in rows):
format = None
for f in self.db.formats(row).split(','):
if f.lower() in formats:
db_formats = set(self.db.formats(row).lower().split(','))
available_formats = set([f.lower() for f in formats])
u = available_formats.intersection(db_formats)
for f in formats:
if f.lower() in u:
format = f
break
if format:
if format is not None:
pt = PersistentTemporaryFile(suffix='.'+format)
pt.write(self.db.format(row, format))
pt.flush()

View File

@ -1,3 +1,4 @@
from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
"""
@ -61,4 +62,17 @@ def PersistentTemporaryDirectory(suffix='', prefix='', dir=None):
tdir = tempfile.mkdtemp(suffix, __appname__+"_"+ __version__+"_" +prefix, dir)
atexit.register(shutil.rmtree, tdir, True)
return tdir
class TemporaryDirectory(str):
def __init__(self, suffix='', prefix='', dir=None):
self.suffix = suffix
self.prefix = prefix
self.dir = dir
def __enter__(self):
self.tdir = tempfile.mkdtemp(self.suffix, __appname__+"_"+ __version__+"_" +self.prefix, self.dir)
return self.tdir
def __exit__(self, *args):
shutil.rmtree(self.tdir)

View File

@ -2,6 +2,8 @@
Read and write ZIP files. Modified by Kovid Goyal to support replacing files in
a zip archive.
"""
from __future__ import with_statement
from calibre.ptempfile import TemporaryDirectory
import struct, os, time, sys, shutil
import binascii, cStringIO
@ -653,10 +655,10 @@ class ZipFile:
fp = None # Set here since __del__ checks it
def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=False):
def __init__(self, file, mode="r", compression=ZIP_DEFLATED, allowZip64=False):
"""Open the ZIP file with mode read "r", write "w" or append "a"."""
if mode not in ("r", "w", "a"):
raise RuntimeError('ZipFile() requires mode "r", "w", or "a"')
raise RuntimeError('ZipFile() requires mode "r", "w", or "a" not %s'%mode)
if compression == ZIP_STORED:
pass
@ -856,7 +858,8 @@ class ZipFile:
if self.filelist[j].header_offset > deleted_offset:
self.filelist[j].header_offset -= deleted_size
if self.filelist[j].file_offset > deleted_offset:
self.filelist[j].file_offset -= deleted_size
self.filelist[j].file_offset -= deleted_size
self._didModify = True
return
if self.debug:
print name, "not in archive"
@ -1178,6 +1181,9 @@ class ZipFile:
self.NameToInfo[zinfo.filename] = zinfo
def add_dir(self, path, prefix=''):
'''
Add a directory recursively to the zip file with an optional prefix.
'''
if prefix:
self.writestr(prefix+'/', '', 0700)
cwd = os.path.abspath(os.getcwd())
@ -1303,6 +1309,32 @@ class ZipFile:
self.fp.close()
self.fp = None
def safe_replace(zipstream, name, datastream):
'''
Replace a file in a zip file in a safe manner. This proceeds by extracting
and re-creating the zipfile. This is neccessary because :method:`ZipFile.replace`
sometimes created corrupted zip files.
:param zipstream: Stream from a zip file
:param name: The name of the file to replace
:param datastream: The data to replace the file with.
'''
z = ZipFile(zipstream, 'r')
names = z.namelist()
with TemporaryDirectory('_zipfile_replace') as tdir:
z.extractall(path=tdir)
zipstream.seek(0)
zipstream.truncate()
z = ZipFile(zipstream, 'w')
path = os.path.join(tdir, *name.split('/'))
shutil.copyfileobj(datastream, open(path, 'wb'))
for name in names:
current = os.path.join(tdir, *name.split('/'))
if os.path.isdir(current):
z.writestr(name+'/', '', 0700)
else:
z.write(current, name)
z.close()
class PyZipFile(ZipFile):
"""Class to create ZIP archives with Python library files and packages."""