sync to trunk

This commit is contained in:
John Schember 2009-01-08 18:46:26 -05:00
commit f64ef65e7f
13 changed files with 177 additions and 25 deletions

View File

@ -25,6 +25,17 @@ every time you add an HTML file to the library.\
html2oeb(htmlfile, of)
return of.name
class OPFMetadataReader(MetadataReaderPlugin):
name = 'Read OPF metadata'
file_types = set(['opf'])
description = _('Read metadata from %s files')%'OPF'
def get_metadata(self, stream, ftype):
from calibre.ebooks.metadata.opf2 import OPF
from calibre.ebooks.metadata import MetaInformation
return MetaInformation(OPF(stream, os.getcwd()))
class RTFMetadataReader(MetadataReaderPlugin):
name = 'Read RTF metadata'
@ -168,6 +179,16 @@ class ComicMetadataReader(MetadataReaderPlugin):
mi.cover_data = (ext.lower(), data)
return mi
class ZipMetadataReader(MetadataReaderPlugin):
name = 'Read ZIP metadata'
file_types = set(['zip', 'oebzip'])
description = _('Read metadata from ebooks in ZIP archives')
def get_metadata(self, stream, ftype):
from calibre.ebooks.metadata.zip import get_metadata
return get_metadata(stream)
class EPUBMetadataWriter(MetadataWriterPlugin):
name = 'Set EPUB metadata'

View File

@ -127,6 +127,7 @@ def get_file_type_metadata(stream, ftype):
mi = plugin.get_metadata(stream, ftype.lower().strip())
break
except:
traceback.print_exc()
continue
return mi

View File

@ -20,7 +20,9 @@ class Device(object):
FORMATS = ["lrf", "rtf", "pdf", "txt"]
VENDOR_ID = 0x0000
PRODUCT_ID = 0x0000
BCD = 0x0000
# BCD can be either None to not distinguish between devices based on BCD, or
# it can be a list of the BCD numbers of all devices supported by this driver.
BCD = None
THUMBNAIL_HEIGHT = 68 # Height for thumbnails on device
def __init__(self, key='-1', log_packets=False, report_progress=None) :

View File

@ -85,7 +85,7 @@ class PRS500(Device):
VENDOR_ID = 0x054c #: SONY Vendor Id
PRODUCT_ID = 0x029b #: Product Id for the PRS-500
BCD = 0x100
BCD = [0x100]
PRODUCT_NAME = 'PRS-500'
VENDOR_NAME = 'SONY'
INTERFACE_ID = 0 #: The interface we use to talk to the device

View File

@ -29,7 +29,7 @@ class File(object):
class PRS505(Device):
VENDOR_ID = 0x054c #: SONY Vendor Id
PRODUCT_ID = 0x031e #: Product Id for the PRS-505
BCD = 0x229 #: Needed to disambiguate 505 and 700 on linux
BCD = [0x229] #: Needed to disambiguate 505 and 700 on linux
PRODUCT_NAME = 'PRS-505'
VENDOR_NAME = 'SONY'
FORMATS = ['lrf', 'epub', "rtf", "pdf", "txt"]
@ -86,7 +86,7 @@ class PRS505(Device):
deviceclass=cls.__name__,
vendor_id=hex(cls.VENDOR_ID),
product_id=hex(cls.PRODUCT_ID),
bcd=hex(cls.BCD),
bcd=hex(cls.BCD[0]),
main_memory=cls.MAIN_MEMORY_VOLUME_LABEL,
storage_card=cls.STORAGE_CARD_VOLUME_LABEL,
)

View File

@ -9,7 +9,7 @@ from calibre.devices.prs505.driver import PRS505
class PRS700(PRS505):
BCD = 0x31a
BCD = [0x31a]
PRODUCT_NAME = 'PRS-700'
OSX_NAME = 'Sony PRS-700'

View File

@ -39,18 +39,35 @@ class DeviceScanner(object):
'''Fetch list of connected USB devices from operating system'''
self.devices = self.scanner()
def is_device_connected(self, device):
if iswindows:
for device_id in self.devices:
vid, pid = 'vid_%4.4x'%device.VENDOR_ID, 'pid_%4.4x'%device.PRODUCT_ID
rev = ('rev_%4.4x'%device.BCD).replace('a', ':') # Bug in winutil.get_usb_devices converts a to :
if vid in device_id and pid in device_id and rev in device_id:
def test_bcd_windows(self, device_id, bcd):
if bcd is None or len(bcd) == 0:
return True
for c in bcd:
# Bug in winutil.get_usb_devices converts a to :
rev = ('rev_%4.4x'%c).replace('a', ':')
if rev in device_id:
return True
return False
def test_bcd(self, bcdDevice, bcd):
if bcd is None or len(bcd) == 0:
return True
for c in bcd:
if c == bcdDevice:
return True
return False
def is_device_connected(self, device):
if iswindows:
vid, pid = 'vid_%4.4x'%device.VENDOR_ID, 'pid_%4.4x'%device.PRODUCT_ID
for device_id in self.devices:
if vid in device_id and pid in device_id:
if self.test_bcd_windows(device_id, getattr(device, 'BCD', None)):
return True
else:
for vendor, product, bcdDevice in self.devices:
if device.VENDOR_ID == vendor and device.PRODUCT_ID == product:
if hasattr(device, 'BCD') and device.BCD == bcdDevice:
if self.test_bcd(bcdDevice, getattr(device, 'BCD', None)):
return True
return False

View File

@ -21,7 +21,7 @@ class Device(_Device):
VENDOR_ID = 0x0
PRODUCT_ID = 0x0
BCD = 0x0
BCD = None
VENDOR_NAME = ''
PRODUCT_NAME = ''
@ -38,7 +38,6 @@ class Device(_Device):
<match key="info.category" string="volume">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="%(vendor_id)s">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="%(product_id)s">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.device_revision_bcd" int="%(bcd)s">
<match key="volume.is_partition" bool="false">
<merge key="volume.label" type="string">%(main_memory)s</merge>
<merge key="%(app)s.mainvolume" type="string">%(deviceclass)s</merge>
@ -46,13 +45,11 @@ class Device(_Device):
</match>
</match>
</match>
</match>
</device>
<device>
<match key="info.category" string="volume">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="%(vendor_id)s">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="%(product_id)s">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.device_revision_bcd" int="%(bcd)s">
<match key="volume.is_partition" bool="true">
<merge key="volume.label" type="string">%(storage_card)s</merge>
<merge key="%(app)s.cardvolume" type="string">%(deviceclass)s</merge>
@ -60,7 +57,6 @@ class Device(_Device):
</match>
</match>
</match>
</match>
</device>
'''
@ -68,17 +64,22 @@ class Device(_Device):
self._main_prefix = self._card_prefix = None
@classmethod
def get_fdi(cls):
def get_bcd_less_fdi(cls):
return cls.FDI_TEMPLATE%dict(
app=__appname__,
deviceclass=cls.__name__,
vendor_id=hex(cls.VENDOR_ID),
product_id=hex(cls.PRODUCT_ID),
bcd=hex(cls.BCD),
main_memory=cls.MAIN_MEMORY_VOLUME_LABEL,
storage_card=cls.STORAGE_CARD_VOLUME_LABEL,
)
@classmethod
def get_fdi(cls):
if cls.BCD is None:
return cls.get_bcd_less_fdi()
raise NotImplementedError('TODO:')
def set_progress_reporter(self, report_progress):
self.report_progress = report_progress

View File

@ -0,0 +1,24 @@
from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import os
from zipfile import ZipFile
from cStringIO import StringIO
def get_metadata(stream):
stream_type = None
zf = ZipFile(stream, 'r')
for f in zf.namelist():
stream_type = os.path.splitext(f)[1].lower()
if stream_type:
stream_type = stream_type[1:]
if stream_type in ('lit', 'opf', 'prc', 'mobi', 'fb2', 'epub',
'rb', 'imp', 'pdf', 'lrf'):
from calibre.ebooks.metadata.meta import get_metadata
stream = StringIO(zf.read(f))
return get_metadata(stream, stream_type)
raise ValueError('No ebook found in ZIP archive')

View File

@ -0,0 +1,81 @@
from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2009, James Beal, james_@catbus.co.uk'
__docformat__ = 'restructuredtext en'
'crop a pdf file'
import os, sys, re
from calibre.utils.config import Config, StringConfig
from pyPdf import PdfFileWriter, PdfFileReader
def config(defaults=None):
desc = _('Options to control the transformation of pdf')
default_crop=10
if defaults is None:
c = Config('trimpdf', desc)
else:
c = StringConfig(defaults, desc)
c.add_opt('verbose', ['-v', '--verbose'], default=0, action='count',
help=_('Be verbose, useful for debugging. Can be specified multiple times for greater verbosity.'))
c.add_opt('output', ['-o', '--output'],default='cropped.pdf',
help=_('Path to output file. By default a file is created in the current directory.'))
c.add_opt('bottom_left_x', [ '-x', '--leftx'], default=default_crop,
help=_('Number of pixels to crop from the left most x (default is %d) ')%default_crop )
c.add_opt('bottom_left_y', [ '-y', '--lefty'], default=default_crop,
help=_('Number of pixels to crop from the left most y (default is %d) ')%default_crop )
c.add_opt('top_right_x', [ '-v', '--rightx'], default=default_crop,
help=_('Number of pixels to crop from the right most x (default is %d) ')%default_crop )
c.add_opt('top_right_y', [ '-w', '--righty'], default=default_crop,
help=_('Number of pixels to crop from the right most y (default is %d)')%default_crop )
c.add_opt('bounding', ['-b', '--bounding'],
help=_('A file generated by ghostscript which allows each page to be individually cropped'))
return c
def option_parser():
c = config()
return c.option_parser(usage=_('''\
%prog [options] file.pdf
Crop a pdf.
'''))
def main(args=sys.argv):
parser = option_parser()
opts, args = parser.parse_args(args)
source = os.path.abspath(args[1])
input_pdf = PdfFileReader(file(source, "rb"))
if opts.bounding != None:
try:
bounding = open( opts.bounding , 'r' )
bounding_regex= re.compile('%%BoundingBox: (?P<bottom_x>[0-9]+) (?P<bottom_y>[0-9]+) (?P<top_x>[0-9]+) (?P<top_y>[0-9]+)')
except:
print 'Error opening %s' % opts.bounding
return 1
output_pdf = PdfFileWriter()
for page_number in range (0, input_pdf.getNumPages() ):
page = input_pdf.getPage(page_number)
if opts.bounding != None:
while True:
line=bounding.readline()
match=bounding_regex.search(line)
if match !=None:
break
page.mediaBox.upperRight = (match.group('top_x'),match.group('top_y'))
page.mediaBox.lowerLeft = (match.group('bottom_x'),match.group('bottom_y'))
else:
page.mediaBox.upperRight = (page.bleedBox.getUpperRight_x()-opts.top_right_x,page.bleedBox.getUpperRight_y()-opts.top_right_y)
page.mediaBox.lowerLeft = (page.bleedBox.getLowerLeft_x()+opts.bottom_left_x,page.bleedBox.getLowerLeft_y()+opts.bottom_left_y)
output_pdf.addPage(page)
if opts.bounding != None:
bounding.close()
output_file = file(opts.output, "wb")
output_pdf.write(output_file)
output_file.close()
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@ -314,6 +314,8 @@ def main(args=sys.argv, logger=None):
sys.excepthook = main.unhandled_exception
main.show()
main.render()
main.activateWindow()
main.raise_()
return app.exec_()
return 0

View File

@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
HTTP server for remote access to the calibre database.
'''
import sys, textwrap, cStringIO, mimetypes, operator, os, re, logging
import sys, textwrap, mimetypes, operator, os, re, logging
from itertools import repeat
from logging.handlers import RotatingFileHandler
from datetime import datetime
@ -285,7 +285,8 @@ class LibraryServer(object):
updated=updated, id='urn:calibre:main').render('xml')
@expose
def library(self, start='0', num='50', sort=None, search=None, _=None, order='ascending'):
def library(self, start='0', num='50', sort=None, search=None,
_=None, order='ascending'):
'''
Serves metadata from the calibre database as XML.
@ -321,7 +322,7 @@ class LibraryServer(object):
total=len(ids)).render('xml')
@expose
def index(self):
def index(self, **kwargs):
'The / URL'
return self.static('index.html')
@ -357,7 +358,8 @@ class LibraryServer(object):
'' : 'application/octet-stream',
}[name.rpartition('.')[-1].lower()]
cherrypy.response.headers['Last-Modified'] = self.last_modified(build_time)
if self.opts.develop and name in ('gui.js', 'gui.css', 'index.html'):
if self.opts.develop and not getattr(sys, 'frozen', False) and \
name in ('gui.js', 'gui.css', 'index.html'):
path = os.path.join(os.path.dirname(__file__), 'static', name)
lm = datetime.fromtimestamp(os.stat(path).st_mtime)
cherrypy.response.headers['Last-Modified'] = self.last_modified(lm)

View File

@ -65,6 +65,7 @@ entry_points = {
'calibre-fontconfig = calibre.utils.fontconfig:main',
'calibre-parallel = calibre.parallel:main',
'calibre-customize = calibre.customize.ui:main',
'pdftrim = calibre.ebooks.pdf.pdftrim:main' ,
],
'gui_scripts' : [
__appname__+' = calibre.gui2.main:main',