mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge upstream changes.
This commit is contained in:
commit
fb2c92a574
@ -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'
|
||||
@ -167,6 +178,16 @@ class ComicMetadataReader(MetadataReaderPlugin):
|
||||
ext = os.path.splitext(path)[1][1:]
|
||||
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):
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -1,85 +0,0 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, John Schember <john at nachtimwald.com>'
|
||||
|
||||
'''
|
||||
'''
|
||||
import os, fnmatch, time
|
||||
|
||||
from calibre.devices.interface import BookList as _BookList
|
||||
|
||||
EBOOK_DIR = "eBooks"
|
||||
EBOOK_TYPES = ['mobi', 'prc', 'html', 'pdf', 'rtf', 'txt']
|
||||
|
||||
class Book(object):
|
||||
def __init__(self, path, title, authors):
|
||||
self.title = title
|
||||
self.authors = authors
|
||||
self.size = os.path.getsize(path)
|
||||
self.datetime = time.gmtime(os.path.getctime(path))
|
||||
self.path = path
|
||||
self.thumbnail = None
|
||||
self.tags = []
|
||||
|
||||
@apply
|
||||
def title_sorter():
|
||||
doc = '''String to sort the title. If absent, title is returned'''
|
||||
def fget(self):
|
||||
return re.sub('^\s*A\s+|^\s*The\s+|^\s*An\s+', '', self.title).rstrip()
|
||||
return property(doc=doc, fget=fget)
|
||||
|
||||
@apply
|
||||
def thumbnail():
|
||||
return None
|
||||
|
||||
def __str__(self):
|
||||
""" Return a utf-8 encoded string with title author and path information """
|
||||
return self.title.encode('utf-8') + " by " + \
|
||||
self.authors.encode('utf-8') + " at " + self.path.encode('utf-8')
|
||||
|
||||
|
||||
class BookList(_BookList):
|
||||
def __init__(self, mountpath):
|
||||
self._mountpath = mountpath
|
||||
_BookList.__init__(self)
|
||||
self.return_books(mountpath)
|
||||
|
||||
def return_books(self, mountpath):
|
||||
# Get all books in all directories under the root EBOOK_DIR directory
|
||||
for path, dirs, files in os.walk(os.path.join(mountpath, EBOOK_DIR)):
|
||||
# Filter out anything that isn't in the list of supported ebook types
|
||||
for book_type in EBOOK_TYPES:
|
||||
for filename in fnmatch.filter(files, '*.%s' % (book_type)):
|
||||
book_title = ''
|
||||
book_author = ''
|
||||
# Calibre uses a specific format for file names. They take the form
|
||||
# title_-_author_number.extention We want to see if the file name is
|
||||
# in this format.
|
||||
if fnmatch.fnmatchcase(filename, '*_-_*.*'):
|
||||
# Get the title and author from the file name
|
||||
title, sep, author = filename.rpartition('_-_')
|
||||
author, sep, ext = author.rpartition('_')
|
||||
book_title = title.replace('_', ' ')
|
||||
book_author = author.replace('_', ' ')
|
||||
# if the filename did not match just set the title to
|
||||
# the filename without the extension
|
||||
else:
|
||||
book_title = os.path.splitext(filename)[0].replace('_', ' ')
|
||||
|
||||
self.append(Book(os.path.join(path, filename), book_title, book_author))
|
||||
|
||||
def add_book(self, path, title):
|
||||
self.append(Book(path, title, ""))
|
||||
|
||||
def remove_book(self, path):
|
||||
for book in self:
|
||||
if path.endswith(book.path):
|
||||
self.remove(book)
|
||||
break
|
||||
|
||||
def supports_tags(self):
|
||||
''' Return True if the the device supports tags (collections) for this book list. '''
|
||||
return False
|
||||
|
||||
def set_tags(self, book, tags):
|
||||
pass
|
||||
|
@ -1,188 +1,43 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, John Schember <john at nachtimwald.com>'
|
||||
|
||||
'''
|
||||
Device driver for Bookeen's Cybook Gen 3
|
||||
'''
|
||||
import os, fnmatch, shutil, time
|
||||
from itertools import cycle
|
||||
|
||||
from calibre.devices.interface import Device
|
||||
from calibre.devices.errors import DeviceError, FreeSpaceError
|
||||
import os, fnmatch
|
||||
|
||||
from calibre.devices.cybookg3.books import BookList, EBOOK_DIR, EBOOK_TYPES
|
||||
from calibre import iswindows, islinux, isosx, __appname__
|
||||
from calibre.devices.usbms.driver import USBMS
|
||||
|
||||
class CYBOOKG3(Device):
|
||||
class CYBOOKG3(USBMS):
|
||||
MIME_MAP = {
|
||||
'mobi' : 'application/mobi',
|
||||
'prc' : 'application/prc',
|
||||
'html' : 'application/html',
|
||||
'pdf' : 'application/pdf',
|
||||
'rtf' : 'application/rtf',
|
||||
'txt' : 'text/plain',
|
||||
}
|
||||
# Ordered list of supported formats
|
||||
FORMATS = EBOOK_TYPES
|
||||
FORMATS = MIME_MAP.keys()
|
||||
|
||||
VENDOR_ID = 0x0bda
|
||||
PRODUCT_ID = 0x0703
|
||||
BCD = 0x110
|
||||
|
||||
BCD = [0x110, 0x132]
|
||||
|
||||
VENDOR_NAME = 'BOOKEEN'
|
||||
PRODUCT_NAME = 'CYBOOK_GEN3'
|
||||
|
||||
OSX_NAME_MAIN_MEM = 'Bookeen Cybook Gen3 -FD Media'
|
||||
OSX_NAME_CARD_MEM = 'Bookeen Cybook Gen3 -SD Media'
|
||||
|
||||
MAIN_MEMORY_VOLUME_LABEL = 'Cybook Gen 3 Main Memory'
|
||||
STORAGE_CARD_VOLUME_LABEL = 'Cybook Gen 3 Storage Card'
|
||||
|
||||
FDI_TEMPLATE = \
|
||||
'''
|
||||
<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>
|
||||
</match>
|
||||
</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>
|
||||
</match>
|
||||
</match>
|
||||
</match>
|
||||
</match>
|
||||
</match>
|
||||
</device>
|
||||
'''
|
||||
|
||||
|
||||
def __init__(self, key='-1', log_packets=False, report_progress=None) :
|
||||
self._main_prefix = self._card_prefix = None
|
||||
|
||||
@classmethod
|
||||
def get_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,
|
||||
)
|
||||
|
||||
def set_progress_reporter(self, report_progress):
|
||||
self.report_progress = report_progress
|
||||
|
||||
def get_device_information(self, end_session=True):
|
||||
"""
|
||||
Ask device for device information. See L{DeviceInfoQuery}.
|
||||
@return: (device name, device version, software version on device, mime type)
|
||||
"""
|
||||
return (self.__class__.__name__, '', '', '')
|
||||
|
||||
def card_prefix(self, end_session=True):
|
||||
return self._card_prefix
|
||||
|
||||
@classmethod
|
||||
def _windows_space(cls, prefix):
|
||||
if prefix is None:
|
||||
return 0, 0
|
||||
win32file = __import__('win32file', globals(), locals(), [], -1)
|
||||
try:
|
||||
sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters = \
|
||||
win32file.GetDiskFreeSpace(prefix[:-1])
|
||||
except Exception, err:
|
||||
if getattr(err, 'args', [None])[0] == 21: # Disk not ready
|
||||
time.sleep(3)
|
||||
sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters = \
|
||||
win32file.GetDiskFreeSpace(prefix[:-1])
|
||||
else: raise
|
||||
mult = sectors_per_cluster * bytes_per_sector
|
||||
return total_clusters * mult, free_clusters * mult
|
||||
|
||||
def total_space(self, end_session=True):
|
||||
msz = csz = 0
|
||||
print self._main_prefix
|
||||
if not iswindows:
|
||||
if self._main_prefix is not None:
|
||||
stats = os.statvfs(self._main_prefix)
|
||||
msz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
|
||||
if self._card_prefix is not None:
|
||||
stats = os.statvfs(self._card_prefix)
|
||||
csz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
|
||||
else:
|
||||
msz = self._windows_space(self._main_prefix)[0]
|
||||
csz = self._windows_space(self._card_prefix)[0]
|
||||
|
||||
return (msz, 0, csz)
|
||||
|
||||
def free_space(self, end_session=True):
|
||||
msz = csz = 0
|
||||
if not iswindows:
|
||||
if self._main_prefix is not None:
|
||||
stats = os.statvfs(self._main_prefix)
|
||||
msz = stats.f_frsize * stats.f_bavail
|
||||
if self._card_prefix is not None:
|
||||
stats = os.statvfs(self._card_prefix)
|
||||
csz = stats.f_frsize * stats.f_bavail
|
||||
else:
|
||||
msz = self._windows_space(self._main_prefix)[1]
|
||||
csz = self._windows_space(self._card_prefix)[1]
|
||||
|
||||
return (msz, 0, csz)
|
||||
|
||||
def books(self, oncard=False, end_session=True):
|
||||
if oncard and self._card_prefix is None:
|
||||
return []
|
||||
prefix = self._card_prefix if oncard else self._main_prefix
|
||||
bl = BookList(prefix)
|
||||
return bl
|
||||
|
||||
def upload_books(self, files, names, on_card=False, end_session=True):
|
||||
if on_card and not self._card_prefix:
|
||||
raise ValueError(_('The reader has no storage card connected.'))
|
||||
|
||||
if not on_card:
|
||||
path = os.path.join(self._main_prefix, EBOOK_DIR)
|
||||
else:
|
||||
path = os.path.join(self._card_prefix, EBOOK_DIR)
|
||||
|
||||
sizes = map(os.path.getsize, files)
|
||||
size = sum(sizes)
|
||||
|
||||
if on_card and size > self.free_space()[2] - 1024*1024:
|
||||
raise FreeSpaceError("There is insufficient free space "+\
|
||||
"on the storage card")
|
||||
if not on_card and size > self.free_space()[0] - 2*1024*1024:
|
||||
raise FreeSpaceError("There is insufficient free space " +\
|
||||
"in main memory")
|
||||
EBOOK_DIR = "eBooks"
|
||||
|
||||
paths = []
|
||||
names = iter(names)
|
||||
|
||||
for infile in files:
|
||||
filepath = os.path.join(path, names.next())
|
||||
paths.append(filepath)
|
||||
|
||||
shutil.copy2(infile, filepath)
|
||||
|
||||
return zip(paths, cycle([on_card]))
|
||||
|
||||
@classmethod
|
||||
def add_books_to_metadata(cls, locations, metadata, booklists):
|
||||
for location in locations:
|
||||
path = location[0]
|
||||
on_card = 1 if location[1] else 0
|
||||
booklists[on_card].add_book(path, os.path.basename(path))
|
||||
|
||||
def delete_books(self, paths, end_session=True):
|
||||
for path in paths:
|
||||
if os.path.exists(path):
|
||||
# Delete the ebook
|
||||
os.unlink(path)
|
||||
|
||||
filepath, ext = os.path.splitext(path)
|
||||
@ -196,137 +51,4 @@ class CYBOOKG3(Device):
|
||||
for p, d, files in os.walk(basepath):
|
||||
for filen in fnmatch.filter(files, filename + "*.t2b"):
|
||||
os.unlink(os.path.join(p, filen))
|
||||
|
||||
@classmethod
|
||||
def remove_books_from_metadata(cls, paths, booklists):
|
||||
for path in paths:
|
||||
for bl in booklists:
|
||||
bl.remove_book(path)
|
||||
|
||||
def sync_booklists(self, booklists, end_session=True):
|
||||
# There is no meta data on the device to update. The device is treated
|
||||
# as a mass storage device and does not use a meta data xml file like
|
||||
# the Sony Readers.
|
||||
pass
|
||||
|
||||
def get_file(self, path, outfile, end_session=True):
|
||||
path = self.munge_path(path)
|
||||
src = open(path, 'rb')
|
||||
shutil.copyfileobj(src, outfile, 10*1024*1024)
|
||||
|
||||
def munge_path(self, path):
|
||||
if path.startswith('/') and not (path.startswith(self._main_prefix) or \
|
||||
(self._card_prefix and path.startswith(self._card_prefix))):
|
||||
path = self._main_prefix + path[1:]
|
||||
elif path.startswith('card:'):
|
||||
path = path.replace('card:', self._card_prefix[:-1])
|
||||
return path
|
||||
|
||||
@classmethod
|
||||
def windows_match_device(cls, device_id):
|
||||
device_id = device_id.upper()
|
||||
if 'VEN_'+cls.VENDOR_NAME in device_id and \
|
||||
'PROD_'+cls.PRODUCT_NAME in device_id:
|
||||
return True
|
||||
|
||||
vid, pid = hex(cls.VENDOR_ID)[2:], hex(cls.PRODUCT_ID)[2:]
|
||||
while len(vid) < 4: vid = '0' + vid
|
||||
while len(pid) < 4: pid = '0' + pid
|
||||
if 'VID_'+vid in device_id and 'PID_'+pid in device_id:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
# This only supports Windows >= 2000
|
||||
def open_windows(self):
|
||||
drives = []
|
||||
wmi = __import__('wmi', globals(), locals(), [], -1)
|
||||
c = wmi.WMI()
|
||||
for drive in c.Win32_DiskDrive():
|
||||
if self.__class__.windows_match_device(str(drive.PNPDeviceID)):
|
||||
if drive.Partitions == 0:
|
||||
continue
|
||||
try:
|
||||
partition = drive.associators("Win32_DiskDriveToDiskPartition")[0]
|
||||
logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0]
|
||||
prefix = logical_disk.DeviceID+os.sep
|
||||
drives.append((drive.Index, prefix))
|
||||
except IndexError:
|
||||
continue
|
||||
|
||||
if not drives:
|
||||
raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%self.__class__.__name__)
|
||||
|
||||
drives.sort(cmp=lambda a, b: cmp(a[0], b[0]))
|
||||
self._main_prefix = drives[0][1]
|
||||
if len(drives) > 1:
|
||||
self._card_prefix = drives[1][1]
|
||||
|
||||
def open_osx(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def open_linux(self):
|
||||
import dbus
|
||||
bus = dbus.SystemBus()
|
||||
hm = dbus.Interface(bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager"), "org.freedesktop.Hal.Manager")
|
||||
|
||||
def conditional_mount(dev):
|
||||
mmo = bus.get_object("org.freedesktop.Hal", dev)
|
||||
label = mmo.GetPropertyString('volume.label', dbus_interface='org.freedesktop.Hal.Device')
|
||||
is_mounted = mmo.GetPropertyString('volume.is_mounted', dbus_interface='org.freedesktop.Hal.Device')
|
||||
mount_point = mmo.GetPropertyString('volume.mount_point', dbus_interface='org.freedesktop.Hal.Device')
|
||||
fstype = mmo.GetPropertyString('volume.fstype', dbus_interface='org.freedesktop.Hal.Device')
|
||||
if is_mounted:
|
||||
return str(mount_point)
|
||||
mmo.Mount(label, fstype, ['umask=077', 'uid='+str(os.getuid()), 'sync'],
|
||||
dbus_interface='org.freedesktop.Hal.Device.Volume')
|
||||
return os.path.normpath('/media/'+label)+'/'
|
||||
|
||||
mm = hm.FindDeviceStringMatch(__appname__+'.mainvolume', self.__class__.__name__)
|
||||
if not mm:
|
||||
raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%(self.__class__.__name__,))
|
||||
self._main_prefix = None
|
||||
for dev in mm:
|
||||
try:
|
||||
self._main_prefix = conditional_mount(dev)+os.sep
|
||||
break
|
||||
except dbus.exceptions.DBusException:
|
||||
continue
|
||||
|
||||
if not self._main_prefix:
|
||||
raise DeviceError('Could not open device for reading. Try a reboot.')
|
||||
|
||||
self._card_prefix = None
|
||||
cards = hm.FindDeviceStringMatch(__appname__+'.cardvolume', self.__class__.__name__)
|
||||
|
||||
for dev in cards:
|
||||
try:
|
||||
self._card_prefix = conditional_mount(dev)+os.sep
|
||||
break
|
||||
except:
|
||||
import traceback
|
||||
print traceback
|
||||
continue
|
||||
|
||||
def open(self):
|
||||
time.sleep(5)
|
||||
self._main_prefix = self._card_prefix = None
|
||||
if islinux:
|
||||
try:
|
||||
self.open_linux()
|
||||
except DeviceError:
|
||||
time.sleep(3)
|
||||
self.open_linux()
|
||||
if iswindows:
|
||||
try:
|
||||
self.open_windows()
|
||||
except DeviceError:
|
||||
time.sleep(3)
|
||||
self.open_windows()
|
||||
if isosx:
|
||||
try:
|
||||
self.open_osx()
|
||||
except DeviceError:
|
||||
time.sleep(3)
|
||||
self.open_osx()
|
||||
|
||||
|
@ -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) :
|
||||
|
@ -1,122 +0,0 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
'''
|
||||
'''
|
||||
import re, time, functools
|
||||
import os
|
||||
|
||||
|
||||
from calibre.devices.interface import BookList as _BookList
|
||||
from calibre.devices import strftime as _strftime
|
||||
|
||||
strftime = functools.partial(_strftime, zone=time.localtime)
|
||||
MIME_MAP = {
|
||||
"azw" : "application/azw",
|
||||
"prc" : "application/prc",
|
||||
"txt" : "text/plain",
|
||||
'mobi': 'application/mobi',
|
||||
}
|
||||
|
||||
def sortable_title(title):
|
||||
return re.sub('^\s*A\s+|^\s*The\s+|^\s*An\s+', '', title).rstrip()
|
||||
|
||||
class Book(object):
|
||||
|
||||
@apply
|
||||
def title_sorter():
|
||||
doc = '''String to sort the title. If absent, title is returned'''
|
||||
def fget(self):
|
||||
src = self.title
|
||||
return src
|
||||
def fset(self, val):
|
||||
self.elem.setAttribute('titleSorter', sortable_title(unicode(val)))
|
||||
return property(doc=doc, fget=fget, fset=fset)
|
||||
|
||||
@apply
|
||||
def thumbnail():
|
||||
return 0
|
||||
|
||||
|
||||
@apply
|
||||
def path():
|
||||
doc = """ Absolute path to book on device. Setting not supported. """
|
||||
def fget(self):
|
||||
return self.mountpath + self.rpath
|
||||
return property(fget=fget, doc=doc)
|
||||
|
||||
@apply
|
||||
def db_id():
|
||||
doc = '''The database id in the application database that this file corresponds to'''
|
||||
def fget(self):
|
||||
match = re.search(r'_(\d+)$', self.rpath.rpartition('.')[0])
|
||||
if match:
|
||||
return int(match.group(1))
|
||||
return property(fget=fget, doc=doc)
|
||||
|
||||
def __init__(self, mountpath, title, authors ):
|
||||
self.mountpath = mountpath
|
||||
self.title = title
|
||||
self.authors = authors
|
||||
self.mime = ""
|
||||
self.rpath = "documents//" + title
|
||||
self.id = 0
|
||||
self.sourceid = 0
|
||||
self.size = 0
|
||||
self.datetime = time.gmtime()
|
||||
self.tags = []
|
||||
|
||||
|
||||
def __str__(self):
|
||||
""" Return a utf-8 encoded string with title author and path information """
|
||||
return self.title.encode('utf-8') + " by " + \
|
||||
self.authors.encode('utf-8') + " at " + self.path.encode('utf-8')
|
||||
|
||||
|
||||
class BookList(_BookList):
|
||||
_mountpath = ""
|
||||
|
||||
def __init__(self, mountpath):
|
||||
self._mountpath = mountpath
|
||||
_BookList.__init__(self)
|
||||
self.return_books(mountpath)
|
||||
|
||||
def return_books(self,mountpath):
|
||||
docs = mountpath + "documents"
|
||||
for f in os.listdir(docs):
|
||||
m = re.match(".*azw", f)
|
||||
if m:
|
||||
self.append_book(mountpath,f)
|
||||
m = re.match(".*prc", f)
|
||||
if m:
|
||||
self.append_book(mountpath,f)
|
||||
m = re.match(".*txt", f)
|
||||
if m:
|
||||
self.append_book(mountpath,f)
|
||||
|
||||
def append_book(self,mountpath,f):
|
||||
b = Book(mountpath,f,"")
|
||||
b.size = os.stat(mountpath + "//documents//" + f)[6]
|
||||
b.datetime = time.gmtime(os.stat(mountpath + "//documents//" + f)[8])
|
||||
b.rpath = "//documents//" + f
|
||||
self.append(b)
|
||||
|
||||
def supports_tags(self):
|
||||
return False
|
||||
|
||||
def add_book(self, name, size, ctime):
|
||||
book = Book(self._mountpath, name, "")
|
||||
book.datetime = time.gmtime(ctime)
|
||||
book.size = size
|
||||
'''remove book if already in db'''
|
||||
self.remove_book(self._mountpath + "//documents//" + name)
|
||||
self.append(book)
|
||||
|
||||
|
||||
def remove_book(self, path):
|
||||
for book in self:
|
||||
if path.startswith(book.mountpath):
|
||||
if path.endswith(book.rpath):
|
||||
self.remove(book)
|
||||
break
|
||||
|
||||
|
@ -1,360 +1,32 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
'''
|
||||
Device driver for the Amazon Kindle
|
||||
'''
|
||||
import sys, os, shutil, time, subprocess, re
|
||||
from itertools import cycle
|
||||
|
||||
from calibre.devices.interface import Device
|
||||
from calibre.devices.errors import DeviceError, FreeSpaceError
|
||||
from calibre.devices.kindle.books import BookList
|
||||
from calibre import iswindows, islinux, isosx
|
||||
from calibre.devices.errors import PathError
|
||||
|
||||
class File(object):
|
||||
def __init__(self, path):
|
||||
stats = os.stat(path)
|
||||
self.is_dir = os.path.isdir(path)
|
||||
self.is_readonly = not os.access(path, os.W_OK)
|
||||
self.ctime = stats.st_ctime
|
||||
self.wtime = stats.st_mtime
|
||||
self.size = stats.st_size
|
||||
if path.endswith(os.sep):
|
||||
path = path[:-1]
|
||||
self.path = path
|
||||
self.name = os.path.basename(path)
|
||||
|
||||
|
||||
class KINDLE(Device):
|
||||
FORMATS = ["azw", "prc", "txt", 'mobi']
|
||||
VENDOR_ID = 0x1949 #: Amazon Vendor Id
|
||||
PRODUCT_ID = 0x001 #: Product Id for the Kindle
|
||||
INTERNAL_STORAGE = 'INTERNAL_STORAGE'
|
||||
CARD_STORAGE = 'CARD_STORAGE'
|
||||
PRODUCT_NAME = 'KINDLE'
|
||||
VENDOR_NAME = 'AMAZON'
|
||||
|
||||
|
||||
MAIN_MEMORY_VOLUME_LABEL = 'Kindle Internal Storage USB Device'
|
||||
STORAGE_CARD_VOLUME_LABEL = 'Kindle Card Storage USB Device'
|
||||
|
||||
#OSX_MAIN_NAME = 'Sony PRS-505/UC Media'
|
||||
#OSX_SD_NAME = 'Sony PRS-505/UC:SD Media'
|
||||
#OSX_MS_NAME = 'Sony PRS-505/UC:MS Media'
|
||||
|
||||
FDI_TEMPLATE = \
|
||||
'''
|
||||
<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="volume.is_partition" bool="false">
|
||||
<merge key="volume.label" type="string">%(main_memory)s</merge>
|
||||
<merge key="kindle.mainvolume" type="string">%(deviceclass)s</merge>
|
||||
</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="volume.is_partition" bool="true">
|
||||
<merge key="volume.label" type="string">%(storage_card)s</merge>
|
||||
<merge key="kindle.cardvolume" type="string">%(deviceclass)s</merge>
|
||||
</match>
|
||||
</match>
|
||||
</match>
|
||||
</match>
|
||||
</device>
|
||||
'''
|
||||
|
||||
|
||||
def __init__(self, log_packets=False):
|
||||
self._main_prefix = self._card_prefix = None
|
||||
|
||||
@classmethod
|
||||
def get_fdi(cls):
|
||||
return cls.FDI_TEMPLATE%dict(
|
||||
deviceclass=cls.__name__,
|
||||
vendor_id=hex(cls.VENDOR_ID),
|
||||
product_id=hex(cls.PRODUCT_ID),
|
||||
main_memory=cls.MAIN_MEMORY_VOLUME_LABEL,
|
||||
storage_card=cls.STORAGE_CARD_VOLUME_LABEL,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def is_device(cls, device_id):
|
||||
'''print "mimi in is device"'''
|
||||
if not hasattr(device_id, 'upper'):
|
||||
return False
|
||||
|
||||
if 'VEN_'+cls.VENDOR_NAME in device_id.upper() and \
|
||||
'PROD_'+cls.INTERNAL_STORAGE in device_id.upper():
|
||||
return True
|
||||
if 'VEN_'+cls.VENDOR_NAME in device_id.upper() and \
|
||||
'PROD_'+cls.CARD_STORAGE in device_id.upper():
|
||||
return True
|
||||
|
||||
vid, pid = hex(cls.VENDOR_ID)[2:], hex(cls.PRODUCT_ID)[2:]
|
||||
if len(vid) < 4: vid = '0'+vid
|
||||
if len(pid) < 4: pid = '0'+pid
|
||||
if len(pid) < 4: pid = '0'+pid
|
||||
if 'VID_'+vid in device_id.upper() and \
|
||||
'PID_'+pid in device_id.upper():
|
||||
return True
|
||||
return False
|
||||
|
||||
def open_osx(self):
|
||||
mount = subprocess.Popen('mount', shell=True,
|
||||
stdout=subprocess.PIPE).stdout.read()
|
||||
src = subprocess.Popen('ioreg -n "%s"'%(self.OSX_MAIN_NAME,),
|
||||
shell=True, stdout=subprocess.PIPE).stdout.read()
|
||||
try:
|
||||
devname = re.search(r'BSD Name.*=\s+"(\S+)"', src).group(1)
|
||||
self._main_prefix = re.search('/dev/%s(\w*)\s+on\s+([^\(]+)\s+'%(devname,), mount).group(2) + os.sep
|
||||
except:
|
||||
raise DeviceError('Unable to find %s. Is it connected?'%(self.__class__.__name__,))
|
||||
try:
|
||||
src = subprocess.Popen('ioreg -n "%s"'%(self.OSX_SD_NAME,),
|
||||
shell=True, stdout=subprocess.PIPE).stdout.read()
|
||||
devname = re.search(r'BSD Name.*=\s+"(\S+)"', src).group(1)
|
||||
except:
|
||||
try:
|
||||
src = subprocess.Popen('ioreg -n "%s"'%(self.OSX_MS_NAME,),
|
||||
shell=True, stdout=subprocess.PIPE).stdout.read()
|
||||
devname = re.search(r'BSD Name.*=\s+"(\S+)"', src).group(1)
|
||||
except:
|
||||
devname = None
|
||||
if devname is not None:
|
||||
self._card_prefix = re.search('/dev/%s(\w*)\s+on\s+([^\(]+)\s+'%(devname,), mount).group(2) + os.sep
|
||||
|
||||
|
||||
def open_windows(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def open_linux(self):
|
||||
import dbus
|
||||
bus = dbus.SystemBus()
|
||||
hm = dbus.Interface(bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager"), "org.freedesktop.Hal.Manager")
|
||||
try:
|
||||
mm = hm.FindDeviceStringMatch('kindle.mainvolume', self.__class__.__name__)[0]
|
||||
except:
|
||||
raise DeviceError('Unable to find %s. Is it connected?'%(self.__class__.__name__,))
|
||||
try:
|
||||
sc = hm.FindDeviceStringMatch('kindle.cardvolume', self.__class__.__name__)[0]
|
||||
except:
|
||||
sc = None
|
||||
|
||||
def conditional_mount(dev):
|
||||
mmo = bus.get_object("org.freedesktop.Hal", dev)
|
||||
label = mmo.GetPropertyString('volume.label', dbus_interface='org.freedesktop.Hal.Device')
|
||||
is_mounted = mmo.GetPropertyString('volume.is_mounted', dbus_interface='org.freedesktop.Hal.Device')
|
||||
mount_point = mmo.GetPropertyString('volume.mount_point', dbus_interface='org.freedesktop.Hal.Device')
|
||||
fstype = mmo.GetPropertyString('volume.fstype', dbus_interface='org.freedesktop.Hal.Device')
|
||||
if is_mounted:
|
||||
return str(mount_point)
|
||||
mmo.Mount(label, fstype, ['umask=077', 'uid='+str(os.getuid()), 'sync'],
|
||||
dbus_interface='org.freedesktop.Hal.Device.Volume')
|
||||
return os.path.normpath('/media/'+label)+'/'
|
||||
|
||||
self._main_prefix = conditional_mount(mm)+os.sep
|
||||
self._card_prefix = None
|
||||
if sc is not None:
|
||||
self._card_prefix = conditional_mount(sc)+os.sep
|
||||
|
||||
def open(self):
|
||||
time.sleep(5)
|
||||
self._main_prefix = self._card_prefix = None
|
||||
if islinux:
|
||||
try:
|
||||
self.open_linux()
|
||||
except DeviceError:
|
||||
time.sleep(3)
|
||||
self.open_linux()
|
||||
if iswindows:
|
||||
try:
|
||||
self.open_windows()
|
||||
except DeviceError:
|
||||
time.sleep(3)
|
||||
self.open_windows()
|
||||
if isosx:
|
||||
try:
|
||||
self.open_osx()
|
||||
except DeviceError:
|
||||
time.sleep(3)
|
||||
self.open_osx()
|
||||
|
||||
|
||||
def set_progress_reporter(self, pr):
|
||||
self.report_progress = pr
|
||||
|
||||
def get_device_information(self, end_session=True):
|
||||
return ('Kindle', '', '', '')
|
||||
|
||||
def card_prefix(self, end_session=True):
|
||||
return self._card_prefix
|
||||
|
||||
@classmethod
|
||||
def _windows_space(cls, prefix):
|
||||
if prefix is None:
|
||||
return 0, 0
|
||||
import win32file
|
||||
sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters = \
|
||||
win32file.GetDiskFreeSpace(prefix[:-1])
|
||||
mult = sectors_per_cluster * bytes_per_sector
|
||||
return total_clusters * mult, free_clusters * mult
|
||||
|
||||
def total_space(self, end_session=True):
|
||||
msz = csz = 0
|
||||
if not iswindows:
|
||||
if self._main_prefix is not None:
|
||||
stats = os.statvfs(self._main_prefix)
|
||||
msz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
|
||||
if self._card_prefix is not None:
|
||||
stats = os.statvfs(self._card_prefix)
|
||||
csz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
|
||||
else:
|
||||
msz = self._windows_space(self._main_prefix)[0]
|
||||
csz = self._windows_space(self._card_prefix)[0]
|
||||
|
||||
return (msz, 0, csz)
|
||||
|
||||
def free_space(self, end_session=True):
|
||||
msz = csz = 0
|
||||
if not iswindows:
|
||||
if self._main_prefix is not None:
|
||||
stats = os.statvfs(self._main_prefix)
|
||||
msz = stats.f_bsize * stats.f_bavail
|
||||
if self._card_prefix is not None:
|
||||
stats = os.statvfs(self._card_prefix)
|
||||
csz = stats.f_bsize * stats.f_bavail
|
||||
else:
|
||||
msz = self._windows_space(self._main_prefix)[1]
|
||||
csz = self._windows_space(self._card_prefix)[1]
|
||||
|
||||
return (msz, 0, csz)
|
||||
|
||||
def books(self, oncard=False, end_session=True):
|
||||
if oncard and self._card_prefix is None:
|
||||
return []
|
||||
prefix = self._card_prefix if oncard else self._main_prefix
|
||||
bl = BookList(prefix)
|
||||
return bl
|
||||
|
||||
def munge_path(self, path):
|
||||
if path.startswith('/') and not (path.startswith(self._main_prefix) or \
|
||||
(self._card_prefix and path.startswith(self._card_prefix))):
|
||||
path = self._main_prefix + path[1:]
|
||||
elif path.startswith('card:'):
|
||||
path = path.replace('card:', self._card_prefix[:-1])
|
||||
return path
|
||||
|
||||
def mkdir(self, path, end_session=True):
|
||||
""" Make directory """
|
||||
path = self.munge_path(path)
|
||||
os.mkdir(path)
|
||||
|
||||
def list(self, path, recurse=False, end_session=True, munge=True):
|
||||
if munge:
|
||||
path = self.munge_path(path)
|
||||
if os.path.isfile(path):
|
||||
return [(os.path.dirname(path), [File(path)])]
|
||||
entries = [File(os.path.join(path, f)) for f in os.listdir(path)]
|
||||
dirs = [(path, entries)]
|
||||
for _file in entries:
|
||||
if recurse and _file.is_dir:
|
||||
dirs[len(dirs):] = self.list(_file.path, recurse=True, munge=False)
|
||||
return dirs
|
||||
|
||||
def get_file(self, path, outfile, end_session=True):
|
||||
path = self.munge_path(path)
|
||||
src = open(path, 'rb')
|
||||
shutil.copyfileobj(src, outfile, 10*1024*1024)
|
||||
|
||||
def put_file(self, infile, path, replace_file=False, end_session=True):
|
||||
path = self.munge_path(path)
|
||||
if os.path.isdir(path):
|
||||
path = os.path.join(path, infile.name)
|
||||
if not replace_file and os.path.exists(path):
|
||||
raise PathError('File already exists: '+path)
|
||||
dest = open(path, 'wb')
|
||||
shutil.copyfileobj(infile, dest, 10*1024*1024)
|
||||
dest.flush()
|
||||
dest.close()
|
||||
|
||||
def rm(self, path, end_session=True):
|
||||
path = self.munge_path(path)
|
||||
os.unlink(path)
|
||||
|
||||
def touch(self, path, end_session=True):
|
||||
path = self.munge_path(path)
|
||||
if not os.path.exists(path):
|
||||
open(path, 'w').close()
|
||||
if not os.path.isdir(path):
|
||||
os.utime(path, None)
|
||||
|
||||
def upload_books(self, files, names, on_card=False, end_session=True):
|
||||
path = os.path.join(self._card_prefix, "documents") if on_card \
|
||||
else os.path.join(self._main_prefix, 'documents')
|
||||
infiles = [file if hasattr(file, 'read') else open(file, 'rb') for file in files]
|
||||
for f in infiles: f.seek(0, 2)
|
||||
sizes = [f.tell() for f in infiles]
|
||||
size = sum(sizes)
|
||||
space = self.free_space()
|
||||
mspace = space[0]
|
||||
cspace = space[2]
|
||||
if on_card and size > cspace - 1024*1024:
|
||||
raise FreeSpaceError("There is insufficient free space "+\
|
||||
"on the storage card")
|
||||
if not on_card and size > mspace - 2*1024*1024:
|
||||
raise FreeSpaceError("There is insufficient free space " +\
|
||||
"in main memory")
|
||||
|
||||
paths, ctimes = [], []
|
||||
|
||||
names = iter(names)
|
||||
for infile in infiles:
|
||||
infile.seek(0)
|
||||
name = names.next()
|
||||
paths.append(os.path.join(path, name))
|
||||
if on_card and not os.path.exists(os.path.dirname(paths[-1])):
|
||||
os.mkdir(os.path.dirname(paths[-1]))
|
||||
self.put_file(infile, paths[-1], replace_file=True)
|
||||
ctimes.append(os.path.getctime(paths[-1]))
|
||||
return zip(paths, sizes, ctimes, cycle([on_card]))
|
||||
|
||||
@classmethod
|
||||
def add_books_to_metadata(cls, locations, metadata, booklists):
|
||||
metadata = iter(metadata)
|
||||
for location in locations:
|
||||
#info = metadata.next()
|
||||
path = location[0]
|
||||
on_card = 1 if location[3] else 0
|
||||
name = path.rpartition(os.sep)[2]
|
||||
name = name.replace('//', '/')
|
||||
booklists[on_card].add_book(name,*location[1:-1])
|
||||
|
||||
def delete_books(self, paths, end_session=True):
|
||||
for path in paths:
|
||||
os.unlink(path)
|
||||
|
||||
@classmethod
|
||||
def remove_books_from_metadata(cls, paths, booklists):
|
||||
for path in paths:
|
||||
for bl in booklists:
|
||||
bl.remove_book(path)
|
||||
|
||||
|
||||
def sync_booklists(self, booklists, end_session=True):
|
||||
return 0;
|
||||
|
||||
|
||||
def main(args=sys.argv):
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
__copyright__ = '2009, John Schember <john at nachtimwald.com>'
|
||||
'''
|
||||
Device driver for Amazon's Kindle
|
||||
'''
|
||||
|
||||
import os, fnmatch
|
||||
|
||||
from calibre.devices.usbms.driver import USBMS
|
||||
|
||||
class KINDLE(USBMS):
|
||||
MIME_MAP = {
|
||||
'azw' : 'application/azw',
|
||||
'mobi' : 'application/mobi',
|
||||
'prc' : 'application/prc',
|
||||
'txt' : 'text/plain',
|
||||
}
|
||||
# Ordered list of supported formats
|
||||
FORMATS = MIME_MAP.keys()
|
||||
|
||||
VENDOR_ID = 0x1949
|
||||
PRODUCT_ID = 0x0001
|
||||
BCD = 0x399
|
||||
|
||||
VENDOR_NAME = 'AMAZON'
|
||||
PRODUCT_NAME = 'KINDLE'
|
||||
|
||||
MAIN_MEMORY_VOLUME_LABEL = 'Kindle Main Memory'
|
||||
STORAGE_CARD_VOLUME_LABEL = 'Kindle Storage Card'
|
||||
|
||||
EBOOK_DIR = "documents"
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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'
|
||||
|
||||
|
@ -39,20 +39,37 @@ class DeviceScanner(object):
|
||||
'''Fetch list of connected USB devices from operating system'''
|
||||
self.devices = self.scanner()
|
||||
|
||||
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:
|
||||
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:
|
||||
return True
|
||||
return False
|
||||
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
|
||||
return False
|
||||
|
||||
|
||||
def main(args=sys.argv):
|
||||
|
0
src/calibre/devices/usbms/__init__.py
Normal file
0
src/calibre/devices/usbms/__init__.py
Normal file
44
src/calibre/devices/usbms/books.py
Normal file
44
src/calibre/devices/usbms/books.py
Normal file
@ -0,0 +1,44 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, John Schember <john at nachtimwald.com>'
|
||||
'''
|
||||
'''
|
||||
|
||||
import os, fnmatch, re, time
|
||||
|
||||
from calibre.devices.interface import BookList as _BookList
|
||||
|
||||
class Book(object):
|
||||
def __init__(self, path, title, authors, mime):
|
||||
self.title = title
|
||||
self.authors = authors
|
||||
self.mime = mime
|
||||
self.size = os.path.getsize(path)
|
||||
self.datetime = time.gmtime(os.path.getctime(path))
|
||||
self.path = path
|
||||
self.thumbnail = None
|
||||
self.tags = []
|
||||
|
||||
@apply
|
||||
def title_sorter():
|
||||
doc = '''String to sort the title. If absent, title is returned'''
|
||||
def fget(self):
|
||||
return re.sub('^\s*A\s+|^\s*The\s+|^\s*An\s+', '', self.title).rstrip()
|
||||
return property(doc=doc, fget=fget)
|
||||
|
||||
@apply
|
||||
def thumbnail():
|
||||
return None
|
||||
|
||||
def __str__(self):
|
||||
""" Return a utf-8 encoded string with title author and path information """
|
||||
return self.title.encode('utf-8') + " by " + \
|
||||
self.authors.encode('utf-8') + " at " + self.path.encode('utf-8')
|
||||
|
||||
class BookList(_BookList):
|
||||
def supports_tags(self):
|
||||
return False
|
||||
|
||||
def set_tags(self, book, tags):
|
||||
pass
|
||||
|
||||
|
295
src/calibre/devices/usbms/device.py
Normal file
295
src/calibre/devices/usbms/device.py
Normal file
@ -0,0 +1,295 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, John Schember <john at nachtimwald.com>'
|
||||
'''
|
||||
Generic device driver. This is not a complete stand alone driver. It is
|
||||
intended to be subclassed with the relevant parts implemented for a particular
|
||||
device. This class handles devive detection.
|
||||
'''
|
||||
|
||||
import os, time
|
||||
|
||||
from calibre.devices.interface import Device as _Device
|
||||
from calibre.devices.errors import DeviceError
|
||||
from calibre import iswindows, islinux, isosx, __appname__
|
||||
|
||||
class Device(_Device):
|
||||
'''
|
||||
This class provides logic common to all drivers for devices that export themselves
|
||||
as USB Mass Storage devices. If you are writing such a driver, inherit from this
|
||||
class.
|
||||
'''
|
||||
|
||||
VENDOR_ID = 0x0
|
||||
PRODUCT_ID = 0x0
|
||||
BCD = None
|
||||
|
||||
VENDOR_NAME = ''
|
||||
PRODUCT_NAME = ''
|
||||
|
||||
OSX_NAME_MAIN_MEM = ''
|
||||
OSX_NAME_CARD_MEM = ''
|
||||
|
||||
MAIN_MEMORY_VOLUME_LABEL = ''
|
||||
STORAGE_CARD_VOLUME_LABEL = ''
|
||||
|
||||
FDI_TEMPLATE = \
|
||||
'''
|
||||
<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">
|
||||
%(BCD_start)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>
|
||||
</match>
|
||||
%(BCD_end)s
|
||||
</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">
|
||||
%(BCD_start)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>
|
||||
</match>
|
||||
%(BCD_end)s
|
||||
</match>
|
||||
</match>
|
||||
</match>
|
||||
</device>
|
||||
'''
|
||||
FDI_BCD_TEMPLATE = '<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.device_revision_bcd" int="%(bcd)s">'
|
||||
|
||||
|
||||
def __init__(self, key='-1', log_packets=False, report_progress=None) :
|
||||
self._main_prefix = self._card_prefix = None
|
||||
|
||||
@classmethod
|
||||
def get_fdi(cls):
|
||||
fdi = ''
|
||||
|
||||
fdi_base_values = dict(
|
||||
app=__appname__,
|
||||
deviceclass=cls.__name__,
|
||||
vendor_id=hex(cls.VENDOR_ID),
|
||||
product_id=hex(cls.PRODUCT_ID),
|
||||
main_memory=cls.MAIN_MEMORY_VOLUME_LABEL,
|
||||
storage_card=cls.STORAGE_CARD_VOLUME_LABEL,
|
||||
)
|
||||
if cls.BCD is None:
|
||||
fdi_base_values['BCD_start'] = ''
|
||||
fdi_base_values['BCD_end'] = ''
|
||||
fdi = cls.FDI_TEMPLATE % fdi_base_values
|
||||
else:
|
||||
for bcd in cls.BCD:
|
||||
fdi_bcd_values = fdi_base_values
|
||||
fdi_bcd_values['BCD_start'] = cls.FDI_BCD_TEMPLATE % dict(bcd=hex(bcd))
|
||||
fdi_bcd_values['BCD_end'] = '</match>'
|
||||
fdi += cls.FDI_TEMPLATE % fdi_bcd_values
|
||||
|
||||
return fdi
|
||||
|
||||
def set_progress_reporter(self, report_progress):
|
||||
self.report_progress = report_progress
|
||||
|
||||
def card_prefix(self, end_session=True):
|
||||
return self._card_prefix
|
||||
|
||||
@classmethod
|
||||
def _windows_space(cls, prefix):
|
||||
if prefix is None:
|
||||
return 0, 0
|
||||
win32file = __import__('win32file', globals(), locals(), [], -1)
|
||||
try:
|
||||
sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters = \
|
||||
win32file.GetDiskFreeSpace(prefix[:-1])
|
||||
except Exception, err:
|
||||
if getattr(err, 'args', [None])[0] == 21: # Disk not ready
|
||||
time.sleep(3)
|
||||
sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters = \
|
||||
win32file.GetDiskFreeSpace(prefix[:-1])
|
||||
else: raise
|
||||
mult = sectors_per_cluster * bytes_per_sector
|
||||
return total_clusters * mult, free_clusters * mult
|
||||
|
||||
def total_space(self, end_session=True):
|
||||
msz = csz = 0
|
||||
print self._main_prefix
|
||||
if not iswindows:
|
||||
if self._main_prefix is not None:
|
||||
stats = os.statvfs(self._main_prefix)
|
||||
msz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
|
||||
if self._card_prefix is not None:
|
||||
stats = os.statvfs(self._card_prefix)
|
||||
csz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
|
||||
else:
|
||||
msz = self._windows_space(self._main_prefix)[0]
|
||||
csz = self._windows_space(self._card_prefix)[0]
|
||||
|
||||
return (msz, 0, csz)
|
||||
|
||||
def free_space(self, end_session=True):
|
||||
msz = csz = 0
|
||||
if not iswindows:
|
||||
if self._main_prefix is not None:
|
||||
stats = os.statvfs(self._main_prefix)
|
||||
msz = stats.f_frsize * stats.f_bavail
|
||||
if self._card_prefix is not None:
|
||||
stats = os.statvfs(self._card_prefix)
|
||||
csz = stats.f_frsize * stats.f_bavail
|
||||
else:
|
||||
msz = self._windows_space(self._main_prefix)[1]
|
||||
csz = self._windows_space(self._card_prefix)[1]
|
||||
|
||||
return (msz, 0, csz)
|
||||
|
||||
@classmethod
|
||||
def windows_match_device(cls, device_id):
|
||||
device_id = device_id.upper()
|
||||
if 'VEN_'+cls.VENDOR_NAME in device_id and \
|
||||
'PROD_'+cls.PRODUCT_NAME in device_id:
|
||||
return True
|
||||
vid, pid = hex(cls.VENDOR_ID)[2:], hex(cls.PRODUCT_ID)[2:]
|
||||
while len(vid) < 4: vid = '0' + vid
|
||||
while len(pid) < 4: pid = '0' + pid
|
||||
if 'VID_'+vid in device_id and 'PID_'+pid in device_id:
|
||||
return True
|
||||
return False
|
||||
|
||||
# This only supports Windows >= 2000
|
||||
def open_windows(self):
|
||||
drives = []
|
||||
wmi = __import__('wmi', globals(), locals(), [], -1)
|
||||
c = wmi.WMI()
|
||||
for drive in c.Win32_DiskDrive():
|
||||
if self.__class__.windows_match_device(str(drive.PNPDeviceID)):
|
||||
if drive.Partitions == 0:
|
||||
continue
|
||||
try:
|
||||
partition = drive.associators("Win32_DiskDriveToDiskPartition")[0]
|
||||
logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0]
|
||||
prefix = logical_disk.DeviceID+os.sep
|
||||
drives.append((drive.Index, prefix))
|
||||
except IndexError:
|
||||
continue
|
||||
|
||||
if not drives:
|
||||
raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%self.__class__.__name__)
|
||||
|
||||
drives.sort(cmp=lambda a, b: cmp(a[0], b[0]))
|
||||
self._main_prefix = drives[0][1]
|
||||
if len(drives) > 1:
|
||||
self._card_prefix = drives[1][1]
|
||||
|
||||
@classmethod
|
||||
def get_osx_mountpoints(self, raw=None):
|
||||
if raw is None:
|
||||
ioreg = '/usr/sbin/ioreg'
|
||||
if not os.access(ioreg, os.X_OK):
|
||||
ioreg = 'ioreg'
|
||||
raw = subprocess.Popen((ioreg+' -w 0 -S -c IOMedia').split(), stdout=subprocess.PIPE).stdout.read()
|
||||
lines = raw.splitlines()
|
||||
names = {}
|
||||
|
||||
def get_dev_node(lines, loc):
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if line.endswith('}'):
|
||||
break
|
||||
match = re.search(r'"BSD Name"\s+=\s+"(.*?)"', line)
|
||||
if match is not None:
|
||||
names[loc] = match.group(1)
|
||||
break
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
if line.strip().endswith('<class IOMedia>') and self.OSX_NAME_MAIN_MEM in line:
|
||||
get_dev_node(lines[i+1:], 'main')
|
||||
if line.strip().endswith('<class IOMedia>') and self.OSX_NAME_CARD_MEM in line:
|
||||
get_dev_node(lines[i+1:], 'card')
|
||||
if len(names.keys()) == 2:
|
||||
break
|
||||
return names
|
||||
|
||||
def open_osx(self):
|
||||
mount = subprocess.Popen('mount', shell=True, stdout=subprocess.PIPE).stdout.read()
|
||||
names = self.get_osx_mountpoints()
|
||||
dev_pat = r'/dev/%s(\w*)\s+on\s+([^\(]+)\s+'
|
||||
if 'main' not in names.keys():
|
||||
raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%self.__class__.__name__)
|
||||
main_pat = dev_pat%names['main']
|
||||
self._main_prefix = re.search(main_pat, mount).group(2) + os.sep
|
||||
card_pat = names['card'] if 'card' in names.keys() else None
|
||||
if card_pat is not None:
|
||||
card_pat = dev_pat%card_pat
|
||||
self._card_prefix = re.search(card_pat, mount).group(2) + os.sep
|
||||
|
||||
def open_linux(self):
|
||||
import dbus
|
||||
bus = dbus.SystemBus()
|
||||
hm = dbus.Interface(bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager"), "org.freedesktop.Hal.Manager")
|
||||
|
||||
def conditional_mount(dev):
|
||||
mmo = bus.get_object("org.freedesktop.Hal", dev)
|
||||
label = mmo.GetPropertyString('volume.label', dbus_interface='org.freedesktop.Hal.Device')
|
||||
is_mounted = mmo.GetPropertyString('volume.is_mounted', dbus_interface='org.freedesktop.Hal.Device')
|
||||
mount_point = mmo.GetPropertyString('volume.mount_point', dbus_interface='org.freedesktop.Hal.Device')
|
||||
fstype = mmo.GetPropertyString('volume.fstype', dbus_interface='org.freedesktop.Hal.Device')
|
||||
if is_mounted:
|
||||
return str(mount_point)
|
||||
mmo.Mount(label, fstype, ['umask=077', 'uid='+str(os.getuid()), 'sync'],
|
||||
dbus_interface='org.freedesktop.Hal.Device.Volume')
|
||||
return os.path.normpath('/media/'+label)+'/'
|
||||
|
||||
mm = hm.FindDeviceStringMatch(__appname__+'.mainvolume', self.__class__.__name__)
|
||||
if not mm:
|
||||
raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%(self.__class__.__name__,))
|
||||
self._main_prefix = None
|
||||
for dev in mm:
|
||||
try:
|
||||
self._main_prefix = conditional_mount(dev)+os.sep
|
||||
break
|
||||
except dbus.exceptions.DBusException:
|
||||
continue
|
||||
|
||||
if not self._main_prefix:
|
||||
raise DeviceError('Could not open device for reading. Try a reboot.')
|
||||
|
||||
self._card_prefix = None
|
||||
cards = hm.FindDeviceStringMatch(__appname__+'.cardvolume', self.__class__.__name__)
|
||||
|
||||
for dev in cards:
|
||||
try:
|
||||
self._card_prefix = conditional_mount(dev)+os.sep
|
||||
break
|
||||
except:
|
||||
import traceback
|
||||
print traceback
|
||||
continue
|
||||
|
||||
def open(self):
|
||||
time.sleep(5)
|
||||
self._main_prefix = self._card_prefix = None
|
||||
if islinux:
|
||||
try:
|
||||
self.open_linux()
|
||||
except DeviceError:
|
||||
time.sleep(3)
|
||||
self.open_linux()
|
||||
if iswindows:
|
||||
try:
|
||||
self.open_windows()
|
||||
except DeviceError:
|
||||
time.sleep(3)
|
||||
self.open_windows()
|
||||
if isosx:
|
||||
try:
|
||||
self.open_osx()
|
||||
except DeviceError:
|
||||
time.sleep(3)
|
||||
self.open_osx()
|
||||
|
146
src/calibre/devices/usbms/driver.py
Normal file
146
src/calibre/devices/usbms/driver.py
Normal file
@ -0,0 +1,146 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2009, John Schember <john at nachtimwald.com>'
|
||||
'''
|
||||
Generic USB Mass storage device driver. This is not a complete stand alone
|
||||
driver. It is intended to be subclassed with the relevant parts implemented
|
||||
for a particular device.
|
||||
'''
|
||||
|
||||
import os, fnmatch, shutil
|
||||
from itertools import cycle
|
||||
|
||||
from calibre.devices.usbms.device import Device
|
||||
from calibre.devices.usbms.books import BookList, Book
|
||||
from calibre.devices.errors import FreeSpaceError
|
||||
|
||||
class USBMS(Device):
|
||||
EBOOK_DIR = ''
|
||||
MIME_MAP = {}
|
||||
FORMATS = []
|
||||
|
||||
def __init__(self, key='-1', log_packets=False, report_progress=None):
|
||||
pass
|
||||
|
||||
def get_device_information(self, end_session=True):
|
||||
"""
|
||||
Ask device for device information. See L{DeviceInfoQuery}.
|
||||
@return: (device name, device version, software version on device, mime type)
|
||||
"""
|
||||
return (self.__class__.__name__, '', '', '')
|
||||
|
||||
def books(self, oncard=False, end_session=True):
|
||||
bl = BookList()
|
||||
|
||||
if oncard and self._card_prefix is None:
|
||||
return bl
|
||||
|
||||
prefix = self._card_prefix if oncard else self._main_prefix
|
||||
|
||||
# Get all books in all directories under the root EBOOK_DIR directory
|
||||
for path, dirs, files in os.walk(os.path.join(prefix, self.EBOOK_DIR)):
|
||||
# Filter out anything that isn't in the list of supported ebook types
|
||||
for book_type in self.MIME_MAP.keys():
|
||||
for filename in fnmatch.filter(files, '*.%s' % (book_type)):
|
||||
title, author, mime = self.__class__.extract_book_metadata_by_filename(filename)
|
||||
|
||||
bl.append(Book(os.path.join(path, filename), title, author, mime))
|
||||
return bl
|
||||
|
||||
def upload_books(self, files, names, on_card=False, end_session=True):
|
||||
if on_card and not self._card_prefix:
|
||||
raise ValueError(_('The reader has no storage card connected.'))
|
||||
|
||||
if not on_card:
|
||||
path = os.path.join(self._main_prefix, self.EBOOK_DIR)
|
||||
else:
|
||||
path = os.path.join(self._card_prefix, self.EBOOK_DIR)
|
||||
|
||||
sizes = map(os.path.getsize, files)
|
||||
size = sum(sizes)
|
||||
|
||||
if on_card and size > self.free_space()[2] - 1024*1024:
|
||||
raise FreeSpaceError(_("There is insufficient free space on the storage card"))
|
||||
if not on_card and size > self.free_space()[0] - 2*1024*1024:
|
||||
raise FreeSpaceError(_("There is insufficient free space in main memory"))
|
||||
|
||||
paths = []
|
||||
names = iter(names)
|
||||
|
||||
for infile in files:
|
||||
filepath = os.path.join(path, names.next())
|
||||
paths.append(filepath)
|
||||
|
||||
shutil.copy2(infile, filepath)
|
||||
|
||||
return zip(paths, cycle([on_card]))
|
||||
|
||||
@classmethod
|
||||
def add_books_to_metadata(cls, locations, metadata, booklists):
|
||||
for location in locations:
|
||||
path = location[0]
|
||||
on_card = 1 if location[1] else 0
|
||||
|
||||
title, author, mime = cls.extract_book_metadata_by_filename(os.path.basename(path))
|
||||
booklists[on_card].append(Book(path, title, author, mime))
|
||||
|
||||
def delete_books(self, paths, end_session=True):
|
||||
for path in paths:
|
||||
if os.path.exists(path):
|
||||
# Delete the ebook
|
||||
os.unlink(path)
|
||||
|
||||
@classmethod
|
||||
def remove_books_from_metadata(cls, paths, booklists):
|
||||
for path in paths:
|
||||
for bl in booklists:
|
||||
for book in bl:
|
||||
if path.endswith(book.path):
|
||||
bl.remove(book)
|
||||
break
|
||||
|
||||
def sync_booklists(self, booklists, end_session=True):
|
||||
# There is no meta data on the device to update. The device is treated
|
||||
# as a mass storage device and does not use a meta data xml file like
|
||||
# the Sony Readers.
|
||||
pass
|
||||
|
||||
def get_file(self, path, outfile, end_session=True):
|
||||
path = self.munge_path(path)
|
||||
src = open(path, 'rb')
|
||||
shutil.copyfileobj(src, outfile, 10*1024*1024)
|
||||
|
||||
def munge_path(self, path):
|
||||
if path.startswith('/') and not (path.startswith(self._main_prefix) or \
|
||||
(self._card_prefix and path.startswith(self._card_prefix))):
|
||||
path = self._main_prefix + path[1:]
|
||||
elif path.startswith('card:'):
|
||||
path = path.replace('card:', self._card_prefix[:-1])
|
||||
return path
|
||||
|
||||
@classmethod
|
||||
def extract_book_metadata_by_filename(cls, filename):
|
||||
book_title = ''
|
||||
book_author = ''
|
||||
book_mime = ''
|
||||
# Calibre uses a specific format for file names. They take the form
|
||||
# title_-_author_number.extention We want to see if the file name is
|
||||
# in this format.
|
||||
if fnmatch.fnmatchcase(filename, '*_-_*.*'):
|
||||
# Get the title and author from the file name
|
||||
title, sep, author = filename.rpartition('_-_')
|
||||
author, sep, ext = author.rpartition('_')
|
||||
book_title = title.replace('_', ' ')
|
||||
book_author = author.replace('_', ' ')
|
||||
# if the filename did not match just set the title to
|
||||
# the filename without the extension
|
||||
else:
|
||||
book_title = os.path.splitext(filename)[0].replace('_', ' ')
|
||||
|
||||
fileext = os.path.splitext(filename)[1]
|
||||
if fileext in cls.MIME_MAP.keys():
|
||||
book_mime = cls.MIME_MAP[fileext]
|
||||
|
||||
return book_title, book_author, book_mime
|
||||
|
||||
# ls, rm, cp, mkdir, touch, cat
|
||||
|
@ -122,7 +122,8 @@ help on using this feature.
|
||||
structure('prefer_metadata_cover', ['--prefer-metadata-cover'], default=False,
|
||||
action='store_true',
|
||||
help=_('Use the cover detected from the source file in preference to the specified cover.'))
|
||||
|
||||
structure('dont_split_on_page_breaks', ['--dont-split-on-page-breaks'], default=False,
|
||||
help=_('Turn off splitting at page breaks. Normally, input files are automatically split at every page break into two files. This gives an output ebook that can be parsed faster and with less resources. However, splitting is slow and if your source file contains a very large number of page breaks, you should turn off splitting on page breaks.'))
|
||||
toc = c.add_group('toc',
|
||||
_('''\
|
||||
Control the automatic generation of a Table of Contents. If an OPF file is detected
|
||||
|
@ -50,11 +50,15 @@ class Splitter(LoggingInterface):
|
||||
self.split_size = 0
|
||||
|
||||
# Split on page breaks
|
||||
self.log_info('\tSplitting on page breaks...')
|
||||
if self.path in stylesheet_map:
|
||||
self.find_page_breaks(stylesheet_map[self.path], root)
|
||||
self.split_on_page_breaks(root.getroottree())
|
||||
trees = list(self.trees)
|
||||
if not opts.dont_split_on_page_breaks:
|
||||
self.log_info('\tSplitting on page breaks...')
|
||||
if self.path in stylesheet_map:
|
||||
self.find_page_breaks(stylesheet_map[self.path], root)
|
||||
self.split_on_page_breaks(root.getroottree())
|
||||
trees = list(self.trees)
|
||||
else:
|
||||
self.trees = [root.getroottree()]
|
||||
trees = list(self.trees)
|
||||
|
||||
# Split any remaining over-sized trees
|
||||
if self.opts.profile.flow_size < sys.maxint:
|
||||
|
@ -10,6 +10,14 @@ Based on ideas from comiclrf created by FangornUK.
|
||||
import os, sys, shutil, traceback, textwrap
|
||||
from uuid import uuid4
|
||||
|
||||
try:
|
||||
from reportlab.pdfgen import canvas
|
||||
_reportlab = True
|
||||
except:
|
||||
_reportlab = False
|
||||
|
||||
|
||||
|
||||
from calibre import extract, terminal_controller, __appname__, __version__
|
||||
from calibre.utils.config import Config, StringConfig
|
||||
from calibre.ptempfile import PersistentTemporaryDirectory
|
||||
@ -43,7 +51,7 @@ PROFILES = {
|
||||
# Name : (width, height) in pixels
|
||||
'prs500':(584, 754),
|
||||
# The SONY's LRF renderer (on the PRS500) only uses the first 800x600 block of the image
|
||||
#'prs500-landscape': (784, 1200-92)
|
||||
'prs500-landscape': (784, 1012)
|
||||
}
|
||||
|
||||
def extract_comic(path_to_comic_file):
|
||||
@ -279,7 +287,7 @@ def process_pages(pages, opts, update):
|
||||
failures += failures_
|
||||
return ans, failures, tdir
|
||||
|
||||
def config(defaults=None):
|
||||
def config(defaults=None,output_format='lrf'):
|
||||
desc = _('Options to control the conversion of comics (CBR, CBZ) files into ebooks')
|
||||
if defaults is None:
|
||||
c = Config('comic', desc)
|
||||
@ -316,10 +324,13 @@ def config(defaults=None):
|
||||
help=_('Be verbose, useful for debugging. Can be specified multiple times for greater verbosity.'))
|
||||
c.add_opt('no_progress_bar', ['--no-progress-bar'], default=False,
|
||||
help=_("Don't show progress bar."))
|
||||
if output_format == 'pdf':
|
||||
c.add_opt('no_process',['--no_process'], default=False,
|
||||
help=_("Apply no processing to the image"))
|
||||
return c
|
||||
|
||||
def option_parser():
|
||||
c = config()
|
||||
def option_parser(output_format='lrf'):
|
||||
c = config(output_format=output_format)
|
||||
return c.option_parser(usage=_('''\
|
||||
%prog [options] comic.cb[z|r]
|
||||
|
||||
@ -382,6 +393,24 @@ def create_lrf(pages, profile, opts, thumbnail=None):
|
||||
book.renderLrf(open(opts.output, 'wb'))
|
||||
print _('Output written to'), opts.output
|
||||
|
||||
|
||||
def create_pdf(pages, profile, opts, thumbnail=None):
|
||||
width, height = PROFILES[profile]
|
||||
|
||||
if not _reportlab:
|
||||
raise RuntimeError('Failed to load reportlab')
|
||||
|
||||
pdf = canvas.Canvas(filename=opts.output, pagesize=(width,height+15))
|
||||
pdf.setAuthor(opts.author)
|
||||
pdf.setTitle(opts.title)
|
||||
|
||||
|
||||
for page in pages:
|
||||
pdf.drawImage(page, x=0,y=0,width=width, height=height)
|
||||
pdf.showPage()
|
||||
# Write the document to disk
|
||||
pdf.save()
|
||||
|
||||
|
||||
def do_convert(path_to_file, opts, notification=lambda m, p: p, output_format='lrf'):
|
||||
path_to_file = run_plugins_on_preprocess(path_to_file)
|
||||
@ -393,29 +422,33 @@ def do_convert(path_to_file, opts, notification=lambda m, p: p, output_format='l
|
||||
opts.output = os.path.abspath(os.path.splitext(os.path.basename(source))[0]+'.'+output_format)
|
||||
tdir = extract_comic(source)
|
||||
pages = find_pages(tdir, sort_on_mtime=opts.no_sort, verbose=opts.verbose)
|
||||
thumbnail = None
|
||||
if not pages:
|
||||
raise ValueError('Could not find any pages in the comic: %s'%source)
|
||||
pages, failures, tdir2 = process_pages(pages, opts, notification)
|
||||
if not pages:
|
||||
raise ValueError('Could not find any valid pages in the comic: %s'%source)
|
||||
if failures:
|
||||
print 'Could not process the following pages (run with --verbose to see why):'
|
||||
for f in failures:
|
||||
print '\t', f
|
||||
thumbnail = os.path.join(tdir2, 'thumbnail.png')
|
||||
if not os.access(thumbnail, os.R_OK):
|
||||
thumbnail = None
|
||||
|
||||
if not opts.no_process:
|
||||
pages, failures, tdir2 = process_pages(pages, opts, notification)
|
||||
if not pages:
|
||||
raise ValueError('Could not find any valid pages in the comic: %s'%source)
|
||||
if failures:
|
||||
print 'Could not process the following pages (run with --verbose to see why):'
|
||||
for f in failures:
|
||||
print '\t', f
|
||||
thumbnail = os.path.join(tdir2, 'thumbnail.png')
|
||||
if not os.access(thumbnail, os.R_OK):
|
||||
thumbnail = None
|
||||
if output_format == 'lrf':
|
||||
create_lrf(pages, opts.profile, opts, thumbnail=thumbnail)
|
||||
else:
|
||||
if output_format == 'epub':
|
||||
create_epub(pages, opts.profile, opts, thumbnail=thumbnail)
|
||||
if output_format == 'pdf':
|
||||
create_pdf(pages, opts.profile, opts, thumbnail=thumbnail)
|
||||
shutil.rmtree(tdir)
|
||||
shutil.rmtree(tdir2)
|
||||
if not opts.no_process:
|
||||
shutil.rmtree(tdir2)
|
||||
|
||||
|
||||
def main(args=sys.argv, notification=None, output_format='lrf'):
|
||||
parser = option_parser()
|
||||
parser = option_parser(output_format=output_format)
|
||||
opts, args = parser.parse_args(args)
|
||||
if len(args) < 2:
|
||||
parser.print_help()
|
||||
@ -429,7 +462,6 @@ def main(args=sys.argv, notification=None, output_format='lrf'):
|
||||
|
||||
source = os.path.abspath(args[1])
|
||||
do_convert(source, opts, notification, output_format=output_format)
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
24
src/calibre/ebooks/metadata/zip.py
Normal file
24
src/calibre/ebooks/metadata/zip.py
Normal 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')
|
||||
|
||||
|
@ -12,15 +12,17 @@ try:
|
||||
except ImportError:
|
||||
import Image as PILImage
|
||||
|
||||
from lxml import html, etree
|
||||
|
||||
from calibre import __appname__, entity_to_unicode
|
||||
from calibre.ebooks import DRMError
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag
|
||||
from calibre.ebooks.chardet import ENCODING_PATS
|
||||
from calibre.ebooks.mobi import MobiError
|
||||
from calibre.ebooks.mobi.huffcdic import HuffReader
|
||||
from calibre.ebooks.mobi.palmdoc import decompress_doc
|
||||
from calibre.ebooks.mobi.langcodes import main_language, sub_language
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
from calibre.ebooks.metadata.opf import OPFCreator
|
||||
from calibre.ebooks.metadata.opf2 import OPFCreator
|
||||
from calibre.ebooks.metadata.toc import TOC
|
||||
from calibre import sanitize_file_name
|
||||
|
||||
@ -176,6 +178,8 @@ class MobiReader(object):
|
||||
processed_records = self.extract_text()
|
||||
self.add_anchors()
|
||||
self.processed_html = self.processed_html.decode(self.book_header.codec, 'ignore')
|
||||
for pat in ENCODING_PATS:
|
||||
self.processed_html = pat.sub('', self.processed_html)
|
||||
self.extract_images(processed_records, output_dir)
|
||||
self.replace_page_breaks()
|
||||
self.cleanup_html()
|
||||
@ -185,7 +189,6 @@ class MobiReader(object):
|
||||
self.processed_html = \
|
||||
re.compile('<head>', re.IGNORECASE).sub(
|
||||
'\n<head>\n'
|
||||
'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\n'
|
||||
'<style type="text/css">\n'
|
||||
'blockquote { margin: 0em 0em 0em 1.25em; text-align: justify; }\n'
|
||||
'p { margin: 0em; text-align: justify; }\n'
|
||||
@ -196,23 +199,33 @@ class MobiReader(object):
|
||||
|
||||
if self.verbose:
|
||||
print 'Parsing HTML...'
|
||||
soup = BeautifulSoup(self.processed_html)
|
||||
self.cleanup_soup(soup)
|
||||
guide = soup.find('guide')
|
||||
for elem in soup.findAll(['metadata', 'guide']):
|
||||
elem.extract()
|
||||
root = html.fromstring(self.processed_html)
|
||||
self.upshift_markup(root)
|
||||
guides = root.xpath('//guide')
|
||||
guide = guides[0] if guides else None
|
||||
for elem in guides + root.xpath('//metadata'):
|
||||
elem.getparent().remove(elem)
|
||||
htmlfile = os.path.join(output_dir,
|
||||
sanitize_file_name(self.name)+'.html')
|
||||
try:
|
||||
for ref in guide.findAll('reference', href=True):
|
||||
ref['href'] = os.path.basename(htmlfile)+ref['href']
|
||||
for ref in guide.xpath('descendant::reference'):
|
||||
if ref.attrib.has_key('href'):
|
||||
ref.attrib['href'] = os.path.basename(htmlfile)+ref.attrib['href']
|
||||
except AttributeError:
|
||||
pass
|
||||
if self.verbose:
|
||||
print 'Serializing...'
|
||||
with open(htmlfile, 'wb') as f:
|
||||
f.write(unicode(soup).encode('utf8'))
|
||||
raw = html.tostring(root, encoding='utf-8', method='xml',
|
||||
include_meta_content_type=True, pretty_print=True)
|
||||
raw = raw.replace('<head>',
|
||||
'<head>\n<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\n')
|
||||
f.write(raw)
|
||||
self.htmlfile = htmlfile
|
||||
|
||||
if self.book_header.exth is not None:
|
||||
if self.verbose:
|
||||
print 'Creating OPF...'
|
||||
ncx = cStringIO.StringIO()
|
||||
opf = self.create_opf(htmlfile, guide)
|
||||
opf.render(open(os.path.splitext(htmlfile)[0]+'.opf', 'wb'), ncx)
|
||||
@ -231,9 +244,9 @@ class MobiReader(object):
|
||||
self.processed_html = re.sub(r'(?i)<%s>'%t, r'<span class="%s">'%c, self.processed_html)
|
||||
self.processed_html = re.sub(r'(?i)</%s>'%t, r'</span>', self.processed_html)
|
||||
|
||||
def cleanup_soup(self, soup):
|
||||
def upshift_markup(self, root):
|
||||
if self.verbose:
|
||||
print 'Replacing height, width and align attributes'
|
||||
print 'Converting style information to CSS...'
|
||||
size_map = {
|
||||
'xx-small' : '0.5',
|
||||
'x-small' : '1',
|
||||
@ -243,41 +256,36 @@ class MobiReader(object):
|
||||
'x-large' : '5',
|
||||
'xx-large' : '6',
|
||||
}
|
||||
for tag in soup.recursiveChildGenerator():
|
||||
if not isinstance(tag, Tag): continue
|
||||
styles = []
|
||||
try:
|
||||
styles.append(tag['style'])
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
styles.append('margin-top: %s' % tag['height'])
|
||||
del tag['height']
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
styles.append('text-indent: %s' % tag['width'])
|
||||
if tag['width'].startswith('-'):
|
||||
styles.append('margin-left: %s'%(tag['width'][1:]))
|
||||
del tag['width']
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
styles.append('text-align: %s' % tag['align'])
|
||||
del tag['align']
|
||||
except KeyError:
|
||||
pass
|
||||
for tag in root.iter(etree.Element):
|
||||
styles, attrib = [], tag.attrib
|
||||
if attrib.has_key('style'):
|
||||
style = attrib.pop('style').strip()
|
||||
if style:
|
||||
styles.append(style)
|
||||
if attrib.has_key('height'):
|
||||
height = attrib.pop('height').strip()
|
||||
if height:
|
||||
styles.append('margin-top: %s' % height)
|
||||
if attrib.has_key('width'):
|
||||
width = attrib.pop('width').strip()
|
||||
if width:
|
||||
styles.append('text-indent: %s' % width)
|
||||
if width.startswith('-'):
|
||||
styles.append('margin-left: %s'%(width[1:]))
|
||||
if attrib.has_key('align'):
|
||||
align = attrib.pop('align').strip()
|
||||
if align:
|
||||
styles.append('text-align: %s' % align)
|
||||
if styles:
|
||||
tag['style'] = '; '.join(styles)
|
||||
attrib['style'] = '; '.join(styles)
|
||||
|
||||
if tag.name.lower() == 'font':
|
||||
sz = tag.get('size', '')
|
||||
if tag.tag.lower() == 'font':
|
||||
sz = tag.get('size', '').lower()
|
||||
try:
|
||||
float(sz)
|
||||
except ValueError:
|
||||
sz = sz.lower()
|
||||
if sz in size_map.keys():
|
||||
tag['size'] = size_map[sz]
|
||||
attrib['size'] = size_map[sz]
|
||||
|
||||
def create_opf(self, htmlfile, guide=None):
|
||||
mi = self.book_header.exth.mi
|
||||
@ -292,7 +300,7 @@ class MobiReader(object):
|
||||
opf.create_manifest(manifest)
|
||||
opf.create_spine([os.path.basename(htmlfile)])
|
||||
toc = None
|
||||
if guide:
|
||||
if guide is not None:
|
||||
opf.create_guide(guide)
|
||||
for ref in opf.guide:
|
||||
if ref.type.lower() == 'toc':
|
||||
@ -303,16 +311,16 @@ class MobiReader(object):
|
||||
ent_pat = re.compile(r'&(\S+?);')
|
||||
if index > -1:
|
||||
raw = '<html><body>'+self.processed_html[index:]
|
||||
soup = BeautifulSoup(raw)
|
||||
root = html.fromstring(raw)
|
||||
tocobj = TOC()
|
||||
for a in soup.findAll('a', href=True):
|
||||
for a in root.xpath('//a[@href]'):
|
||||
try:
|
||||
text = u''.join(a.findAll(text=True)).strip()
|
||||
text = u' '.join([t.strip() for t in a.xpath('descendant::text()')])
|
||||
except:
|
||||
text = ''
|
||||
text = ent_pat.sub(entity_to_unicode, text)
|
||||
if a['href'].startswith('#'):
|
||||
tocobj.add_item(toc.partition('#')[0], a['href'][1:], text)
|
||||
if a.get('href', '').startswith('#'):
|
||||
tocobj.add_item(toc.partition('#')[0], a.attrib['href'][1:], text)
|
||||
if tocobj is not None:
|
||||
opf.set_toc(tocobj)
|
||||
|
||||
|
9
src/calibre/ebooks/pdf/__init__.py
Normal file
9
src/calibre/ebooks/pdf/__init__.py
Normal file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
'''
|
||||
Used for pdf output for comic2pdf
|
||||
'''
|
||||
|
21
src/calibre/ebooks/pdf/from_comic.py
Normal file
21
src/calibre/ebooks/pdf/from_comic.py
Normal file
@ -0,0 +1,21 @@
|
||||
from __future__ import with_statement
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
'Convert a comic in CBR/CBZ format to pdf'
|
||||
|
||||
import sys
|
||||
from functools import partial
|
||||
from calibre.ebooks.lrf.comic.convert_from import do_convert, option_parser, config, main as _main
|
||||
|
||||
convert = partial(do_convert, output_format='pdf')
|
||||
main = partial(_main, output_format='pdf')
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
||||
if False:
|
||||
option_parser
|
||||
config
|
||||
|
81
src/calibre/ebooks/pdf/pdftrim.py
Normal file
81
src/calibre/ebooks/pdf/pdftrim.py
Normal 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())
|
@ -77,7 +77,7 @@
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stack" >
|
||||
<property name="currentIndex" >
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="metadata_page" >
|
||||
<layout class="QGridLayout" name="gridLayout_4" >
|
||||
@ -89,6 +89,36 @@
|
||||
<string>Book Cover</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="_2" >
|
||||
<item row="0" column="0" >
|
||||
<layout class="QHBoxLayout" name="_3" >
|
||||
<item>
|
||||
<widget class="ImageView" name="cover" >
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap resource="../images.qrc" >:/images/book.svg</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QCheckBox" name="opt_prefer_metadata_cover" >
|
||||
<property name="text" >
|
||||
<string>Use cover from &source file</string>
|
||||
</property>
|
||||
<property name="checked" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<layout class="QVBoxLayout" name="_4" >
|
||||
<property name="spacing" >
|
||||
@ -140,36 +170,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QCheckBox" name="opt_prefer_metadata_cover" >
|
||||
<property name="text" >
|
||||
<string>Use cover from &source file</string>
|
||||
</property>
|
||||
<property name="checked" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<layout class="QHBoxLayout" name="_3" >
|
||||
<item>
|
||||
<widget class="ImageView" name="cover" >
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap resource="../images.qrc" >:/images/book.svg</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>opt_prefer_metadata_cover</zorder>
|
||||
<zorder></zorder>
|
||||
@ -586,6 +586,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" >
|
||||
<widget class="QCheckBox" name="opt_dont_split_on_page_breaks" >
|
||||
<property name="text" >
|
||||
<string>Do not &split on page breaks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="chapterdetection_page" >
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -59,11 +59,13 @@ entry_points = {
|
||||
'oeb2lit = calibre.ebooks.lit.writer:main',
|
||||
'comic2lrf = calibre.ebooks.lrf.comic.convert_from:main',
|
||||
'comic2epub = calibre.ebooks.epub.from_comic:main',
|
||||
'comic2pdf = calibre.ebooks.pdf.from_comic:main',
|
||||
'calibre-debug = calibre.debug:main',
|
||||
'calibredb = calibre.library.cli:main',
|
||||
'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',
|
||||
@ -228,6 +230,7 @@ def setup_completion(fatal_errors):
|
||||
f.write(opts_and_exts('lit2oeb', lit2oeb, ['lit']))
|
||||
f.write(opts_and_exts('comic2lrf', comicop, ['cbz', 'cbr']))
|
||||
f.write(opts_and_exts('comic2epub', comic2epub, ['cbz', 'cbr']))
|
||||
f.write(opts_and_exts('comic2pdf', comic2epub, ['cbz', 'cbr']))
|
||||
f.write(opts_and_words('feeds2disk', feeds2disk, feed_titles))
|
||||
f.write(opts_and_words('feeds2lrf', feeds2lrf, feed_titles))
|
||||
f.write(opts_and_words('feeds2lrf', feeds2epub, feed_titles))
|
||||
|
@ -63,7 +63,7 @@ def check_for_critical_bugs():
|
||||
shutil.rmtree('.errors')
|
||||
pofilter = ('pofilter', '-i', '.', '-o', '.errors',
|
||||
'-t', 'accelerators', '-t', 'escapes', '-t', 'variables',
|
||||
'-t', 'xmltags')
|
||||
'-t', 'xmltags', '-t', 'printf')
|
||||
subprocess.check_call(pofilter)
|
||||
errs = os.listdir('.errors')
|
||||
if errs:
|
||||
|
@ -13,7 +13,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
@ -17,7 +17,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||
|
@ -14,7 +14,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||
|
@ -8,13 +8,13 @@ msgstr ""
|
||||
"Project-Id-Version: de\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2008-12-30 15:33+0000\n"
|
||||
"PO-Revision-Date: 2009-01-04 01:11+0000\n"
|
||||
"Last-Translator: S. Dorscht <Unknown>\n"
|
||||
"PO-Revision-Date: 2009-01-07 18:09+0000\n"
|
||||
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||
"Language-Team: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
@ -1945,7 +1945,7 @@ msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:49
|
||||
msgid "Set options for converting %s"
|
||||
msgstr "Einstellungen für das Konvertieren &s setzen"
|
||||
msgstr "Einstellungen für das Konvertieren %s setzen"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:89
|
||||
msgid "&Title:"
|
||||
@ -4641,7 +4641,7 @@ msgstr "V"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:350
|
||||
msgid "Open containing folder"
|
||||
msgstr "Öffne enthaltenes Verzeichnis"
|
||||
msgstr "Öffne Speicherort"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:351
|
||||
msgid "Show book details"
|
||||
|
@ -14,7 +14,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||
|
@ -11,13 +11,13 @@ msgstr ""
|
||||
"Project-Id-Version: es\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2008-12-30 15:33+0000\n"
|
||||
"PO-Revision-Date: 2008-12-28 11:11+0000\n"
|
||||
"Last-Translator: Paco Molinero <paco@byasl.com>\n"
|
||||
"PO-Revision-Date: 2009-01-07 18:17+0000\n"
|
||||
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||
"Language-Team: Spanish\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||
@ -125,7 +125,7 @@ msgstr "Leer metadatos desde archivos %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:155
|
||||
msgid "Extract cover from comic files"
|
||||
msgstr ""
|
||||
msgstr "Extraer portada de los archivos del cómic"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:175
|
||||
msgid "Set metadata in EPUB files"
|
||||
@ -407,6 +407,8 @@ msgid ""
|
||||
"takes from\n"
|
||||
"the <spine> element of the OPF file. \n"
|
||||
msgstr ""
|
||||
"%prog [options] file.html|opf\n"
|
||||
"\n"
|
||||
"Convertir un archivo HTML a ebook en formato EPUB. Seguir los enlaces del "
|
||||
"archivo HTML de manera recursiva.\n"
|
||||
"Si especifica un archivo OPF en lugar de un archivo HTML, la lista de "
|
||||
@ -1547,6 +1549,8 @@ msgid ""
|
||||
"\n"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"%prog [options] key\n"
|
||||
"\n"
|
||||
"Se han adquirido los metadatos desde isndb.com. Puede indicar el ISBN de los "
|
||||
"libros, o los títulos y autores.\n"
|
||||
"Si especifica titulo y autor, es posible que aparezca mas de una "
|
||||
@ -3327,7 +3331,7 @@ msgstr "El feed ha de tener una URL"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:116
|
||||
msgid "The feed %s must have a URL"
|
||||
msgstr "el Feed debe tener una dirección"
|
||||
msgstr "el Feed %s debe tener una dirección"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:121
|
||||
msgid "Already exists"
|
||||
@ -5163,7 +5167,7 @@ msgid ""
|
||||
"s"
|
||||
msgstr ""
|
||||
"Intervalo minimo de segundos entre adquisiciones de datos consecutivas. Por "
|
||||
"omisión %s segundos"
|
||||
"omisión %default segundos"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/web/feeds/main.py:24
|
||||
#: /home/kovid/work/calibre/src/calibre/web/fetch/simple.py:452
|
||||
|
@ -13,7 +13,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
@ -14,7 +14,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||
|
@ -9,13 +9,13 @@ msgstr ""
|
||||
"Project-Id-Version: calibre_calibre-it\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2008-12-30 15:33+0000\n"
|
||||
"PO-Revision-Date: 2009-01-01 18:58+0000\n"
|
||||
"Last-Translator: Iacopo Benesperi <Unknown>\n"
|
||||
"PO-Revision-Date: 2009-01-07 18:21+0000\n"
|
||||
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||
"Language-Team: italiano\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
@ -439,7 +439,11 @@ msgid ""
|
||||
"\n"
|
||||
"Convert any of a large number of ebook formats to a %s file. Supported "
|
||||
"formats are: %s\n"
|
||||
msgstr "%%prog [opzioni] nomefile\n"
|
||||
msgstr ""
|
||||
"%%prog [opzioni] nomefile\n"
|
||||
"\n"
|
||||
"Converte un grande numero di formati di libro in un file %s. Formati "
|
||||
"supportati: %s\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:100
|
||||
msgid "Could not find an ebook inside the archive"
|
||||
@ -711,7 +715,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Specifica la dimensione del testo base in punti. Tutti i caratteri saranno "
|
||||
"scalati in accordo. Questa opzione rende obsoleta l'opzione --font-delta e "
|
||||
"ha precedenza su quest'ultima. Per usare --font-delta, impostare questa a 0"
|
||||
"ha precedenza su quest'ultima. Per usare --font-delta, impostare questa a 0. "
|
||||
"Default: %default pt"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:101
|
||||
msgid "Enable autorotation of images that are wider than the screen width."
|
||||
@ -1236,7 +1241,7 @@ msgstr "Impossibile analizzare il file: %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:542
|
||||
msgid "%s is an empty file"
|
||||
msgstr "%S è un file vuoto"
|
||||
msgstr "%s è un file vuoto"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:562
|
||||
msgid "Failed to parse link %s %s"
|
||||
@ -3504,7 +3509,7 @@ msgstr "Il feed deve avere una URL"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:116
|
||||
msgid "The feed %s must have a URL"
|
||||
msgstr "Il feed %S deve avere una URL"
|
||||
msgstr "Il feed %s deve avere una URL"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:121
|
||||
msgid "Already exists"
|
||||
|
@ -8,13 +8,13 @@ msgstr ""
|
||||
"Project-Id-Version: calibre\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2008-12-30 15:33+0000\n"
|
||||
"PO-Revision-Date: 2008-12-05 23:40+0000\n"
|
||||
"Last-Translator: Helene Klungvik <Unknown>\n"
|
||||
"PO-Revision-Date: 2009-01-07 18:22+0000\n"
|
||||
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||
"Language-Team: Norwegian Bokmal <nb@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||
@ -559,7 +559,7 @@ msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:849
|
||||
msgid "%prog [options] LITFILE"
|
||||
msgstr "%applikasjon [opsjoner] LITFIL"
|
||||
msgstr "%prog [opsjoner] LITFIL"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:852
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:444
|
||||
|
@ -8,13 +8,13 @@ msgstr ""
|
||||
"Project-Id-Version: de\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2008-12-30 15:33+0000\n"
|
||||
"PO-Revision-Date: 2009-01-04 01:54+0000\n"
|
||||
"Last-Translator: S. Dorscht <Unknown>\n"
|
||||
"PO-Revision-Date: 2009-01-07 18:10+0000\n"
|
||||
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||
"Language-Team: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
@ -1945,7 +1945,7 @@ msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:49
|
||||
msgid "Set options for converting %s"
|
||||
msgstr "Einstellungen für das Konvertieren &s setzen"
|
||||
msgstr "Einstellungen für das Konvertieren %s setzen"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:89
|
||||
msgid "&Title:"
|
||||
@ -4641,7 +4641,7 @@ msgstr "V"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:350
|
||||
msgid "Open containing folder"
|
||||
msgstr "Öffne enthaltenes Verzeichnis"
|
||||
msgstr "Öffne Speicherort"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:351
|
||||
msgid "Show book details"
|
||||
|
@ -14,7 +14,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||
|
@ -8,13 +8,13 @@ msgstr ""
|
||||
"Project-Id-Version: calibre\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2008-12-30 15:33+0000\n"
|
||||
"PO-Revision-Date: 2009-01-03 20:09+0000\n"
|
||||
"Last-Translator: Radian <Unknown>\n"
|
||||
"PO-Revision-Date: 2009-01-07 18:24+0000\n"
|
||||
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||
"Language-Team: Polish <pl@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||
@ -167,6 +167,10 @@ msgid ""
|
||||
" Customize calibre by loading external plugins.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
" %prog opcje\n"
|
||||
" \n"
|
||||
" Dostosuj calibre poprzez załadowanie zewnętrznych wtyczek.\n"
|
||||
" "
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:253
|
||||
msgid "Add a plugin by specifying the path to the zip file containing it."
|
||||
@ -455,6 +459,8 @@ msgid ""
|
||||
"takes from\n"
|
||||
"the <spine> element of the OPF file. \n"
|
||||
msgstr ""
|
||||
"%prog [options] file.html|opf\n"
|
||||
"\n"
|
||||
"Konwertuj plik HTML na e-book EPUB. Rekurencyjnie podąża za odnośnikami w "
|
||||
"pliku HTML. \n"
|
||||
"Jeśli wybierzesz plik OPF zamiast pliku HTML, lista odnośników będzie brana "
|
||||
@ -695,6 +701,8 @@ msgid ""
|
||||
"Render HTML tables as blocks of text instead of actual tables. This is "
|
||||
"neccessary if the HTML contains very large or complex tables."
|
||||
msgstr ""
|
||||
"Wyświetlaj tabele HTML jako bloki tekstu zamiast właściwych tabel. To jest "
|
||||
"konieczne jeśli HTML zawiera bardzo duże lub złożone tabele."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:99
|
||||
msgid ""
|
||||
@ -726,7 +734,7 @@ msgid ""
|
||||
"title. Default is %default"
|
||||
msgstr ""
|
||||
"Ustaw format nagłówka. %a jest zastępowane nazwiskiem autora, %t - tytułem "
|
||||
"książki. Styl domyślny: &default"
|
||||
"książki. Styl domyślny: %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:112
|
||||
msgid ""
|
||||
@ -1025,6 +1033,8 @@ msgid ""
|
||||
"Keep aspect ratio and scale image using screen height as image width for "
|
||||
"viewing in landscape mode."
|
||||
msgstr ""
|
||||
"Zachowaj format i skalę obrazu używając wysokości ekranu jako szerokość "
|
||||
"obrazu podczas wyświetlania w trybie panoramicznym."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:308
|
||||
msgid ""
|
||||
@ -1416,11 +1426,11 @@ msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:42
|
||||
msgid "Set the authors"
|
||||
msgstr ""
|
||||
msgstr "Ustaw autorów"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:46
|
||||
msgid "Set the comment"
|
||||
msgstr ""
|
||||
msgstr "Ustaw komentarz"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:273
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:69
|
||||
@ -1484,7 +1494,7 @@ msgstr "Język"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/epub.py:199
|
||||
msgid "A comma separated list of tags to set"
|
||||
msgstr "Lista etykiet do ustawienia odzielonych przecinkiem"
|
||||
msgstr "Lista etykiet do ustawienia oddzielonych przecinkami"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/epub.py:201
|
||||
msgid "The series to which this book belongs"
|
||||
@ -1601,7 +1611,7 @@ msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/odt/to_oeb.py:57
|
||||
msgid "The output directory. Defaults to the current directory."
|
||||
msgstr ""
|
||||
msgstr "Folder wyjściowy. Domyślnie jest to bieżący folder."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:25
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:424
|
||||
@ -1611,6 +1621,7 @@ msgstr "Ostatnio używane foldery"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:27
|
||||
msgid "Send file to storage card instead of main memory by default"
|
||||
msgstr ""
|
||||
"Wyślij plik do karty pamięci zamiast domyślnie ustawionej głównej pamięci."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:29
|
||||
msgid "The format to use when saving single files to disk"
|
||||
@ -1646,11 +1657,11 @@ msgstr "Sortuj etykiety według popularności"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:45
|
||||
msgid "Number of covers to show in the cover browsing mode"
|
||||
msgstr ""
|
||||
msgstr "Liczba okładek wyświetlanych w trybie przeglądania okładek"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:47
|
||||
msgid "Defaults for conversion to LRF"
|
||||
msgstr ""
|
||||
msgstr "Domyślne wartości dla konwersji do LRF"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:49
|
||||
msgid "Options for the LRF ebook viewer"
|
||||
@ -1946,10 +1957,12 @@ msgid ""
|
||||
"&Location of ebooks (The ebooks are stored in folders sorted by author and "
|
||||
"metadata is stored in the file metadata.db)"
|
||||
msgstr ""
|
||||
"&Lokalizacja książek (Książki są przechowywane w folderach posortowanych "
|
||||
"według autorów a metadane znajdują się w pliku metadata.db)"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:410
|
||||
msgid "Browse for the new database location"
|
||||
msgstr ""
|
||||
msgstr "Wybierz nową lokalizację bazy danych"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:411
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:426
|
||||
@ -2046,6 +2059,8 @@ msgstr "Używaj numeracji &rzymskiej do numerowania serii"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:430
|
||||
msgid "&Number of covers to show in browse mode (after restart):"
|
||||
msgstr ""
|
||||
"&Liczba wyświetlanych okładek podczas przeglądania (po ponownym "
|
||||
"uruchomieniu):"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:431
|
||||
msgid "Toolbar"
|
||||
@ -2082,6 +2097,7 @@ msgstr "Użyj wewnętrznej &przeglądarki do wyświetlania poniższych formatów
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:441
|
||||
msgid "Enable system &tray icon (needs restart)"
|
||||
msgstr ""
|
||||
"Aktywuj ikonę w &zasobniku systemowym (wymaga ponownego uruchomienia)"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:442
|
||||
msgid "Automatically send downloaded &news to ebook reader"
|
||||
@ -2109,6 +2125,9 @@ msgid ""
|
||||
"collection using a browser from anywhere in the world. Any changes to the "
|
||||
"settings will only take effect after a server restart."
|
||||
msgstr ""
|
||||
"calibre zawiera serwer, który daje ci dostęp do twojej kolekcji książek za "
|
||||
"pomocą przeglądarki z dowolnego miejsca na świecie. Jakiekolwiek zmiany w "
|
||||
"ustawieniach zostaną zatwierdzone po ponownym uruchomieniu serwera."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:448
|
||||
msgid "Server &port:"
|
||||
@ -2364,7 +2383,7 @@ msgstr "Zmień grafikę &okładki:"
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:508
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:317
|
||||
msgid "Browse for an image to use as the cover of this book."
|
||||
msgstr ""
|
||||
msgstr "Wybierz obraz, który będzie użyty jako okładka tej książki."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:374
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:510
|
||||
@ -3717,7 +3736,7 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:168
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:170
|
||||
msgid "Send to storage card"
|
||||
msgstr ""
|
||||
msgstr "Wyślij do karty pamięci."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:169
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:170
|
||||
@ -3726,7 +3745,7 @@ msgstr "i usuń z biblioteki"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:172
|
||||
msgid "Send to storage card by default"
|
||||
msgstr ""
|
||||
msgstr "Wysyłaj do karty pamięci domyślnie."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:185
|
||||
msgid "Edit metadata individually"
|
||||
@ -4313,13 +4332,15 @@ msgstr "Kliknij, aby przeglądać książki po okładkach"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/status.py:153
|
||||
msgid "Click to turn off Cover Browsing"
|
||||
msgstr ""
|
||||
msgstr "Kliknij aby wyłączyć Przeglądanie Okładek"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/status.py:158
|
||||
msgid ""
|
||||
"<p>Browsing books by their covers is disabled.<br>Import of pictureflow "
|
||||
"module failed:<br>"
|
||||
msgstr ""
|
||||
"<p>Przeglądanie książek za pomocą ich okładek jest wyłączone.<br>Załadowanie "
|
||||
"modułu pictureflow nie powiodło się:<br>"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/status.py:166
|
||||
msgid "Click to browse books by tags"
|
||||
@ -4638,6 +4659,7 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:148
|
||||
msgid "Click to see the list of books on the storage card in your reader"
|
||||
msgstr ""
|
||||
"Kliknij aby zobaczyć listę książek na karcie pamięci w twoim czytniku."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/library/__init__.py:16
|
||||
msgid "Settings to control the calibre content server"
|
||||
|
@ -8,18 +8,18 @@ msgstr ""
|
||||
"Project-Id-Version: calibre\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2008-12-30 15:33+0000\n"
|
||||
"PO-Revision-Date: 2008-12-18 18:01+0000\n"
|
||||
"Last-Translator: Fabio Malcher Miranda <mirand863@hotmail.com>\n"
|
||||
"PO-Revision-Date: 2009-01-07 00:01+0000\n"
|
||||
"Last-Translator: ricdiogo <ricardofdiogo@gmail.com>\n"
|
||||
"Language-Team: Portuguese <pt@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||
msgid "Does absolutely nothing"
|
||||
msgstr ""
|
||||
msgstr "Não faz absolutamente nada"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:44
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_any.py:44
|
||||
@ -77,23 +77,23 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:808
|
||||
#: /home/kovid/work/calibre/src/calibre/library/database2.py:841
|
||||
msgid "Unknown"
|
||||
msgstr ""
|
||||
msgstr "Desconhecido"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:62
|
||||
msgid "Base"
|
||||
msgstr ""
|
||||
msgstr "Base"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:148
|
||||
msgid "File type"
|
||||
msgstr ""
|
||||
msgstr "Tipo de ficheiro"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:182
|
||||
msgid "Metadata reader"
|
||||
msgstr ""
|
||||
msgstr "Leitor de metadados"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:209
|
||||
msgid "Metadata writer"
|
||||
msgstr ""
|
||||
msgstr "Editor de metadados"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:12
|
||||
msgid ""
|
||||
@ -101,6 +101,9 @@ msgid ""
|
||||
"linked files. This plugin is run every time you add an HTML file to the "
|
||||
"library."
|
||||
msgstr ""
|
||||
"Siga todas as ligações locais num ficheiro HTML e crie um ficheiro ZIP "
|
||||
"contendo todos os ficheiros para os quais são feitas ligações. Este plugin "
|
||||
"corre cada vez que você acrescenta um ficheiro HTML à bilbioteca."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:32
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:42
|
||||
@ -115,27 +118,27 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:135
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:145
|
||||
msgid "Read metadata from %s files"
|
||||
msgstr ""
|
||||
msgstr "Ler metadados dos ficheiros %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:155
|
||||
msgid "Extract cover from comic files"
|
||||
msgstr ""
|
||||
msgstr "Extrair a capa de ficheiros de banda desenhada"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:175
|
||||
msgid "Set metadata in EPUB files"
|
||||
msgstr ""
|
||||
msgstr "Definir metadados em ficheiros EPUB"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:185
|
||||
msgid "Set metadata in LRF files"
|
||||
msgstr ""
|
||||
msgstr "Definir metadados em ficheiros LRF"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:195
|
||||
msgid "Set metadata in RTF files"
|
||||
msgstr ""
|
||||
msgstr "Definir metadados em ficheiros RTF"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:28
|
||||
msgid "Installed plugins"
|
||||
msgstr ""
|
||||
msgstr "Plugins instalados"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:29
|
||||
msgid "Mapping for filetype plugins"
|
||||
@ -143,19 +146,19 @@ msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:30
|
||||
msgid "Local plugin customization"
|
||||
msgstr ""
|
||||
msgstr "Personalização de plugin local"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:31
|
||||
msgid "Disabled plugins"
|
||||
msgstr ""
|
||||
msgstr "Plugins desactivados"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:66
|
||||
msgid "No valid plugin found in "
|
||||
msgstr ""
|
||||
msgstr "Nenhum plugin válido encontrado em "
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:170
|
||||
msgid "Initialization of plugin %s failed with traceback:"
|
||||
msgstr ""
|
||||
msgstr "A inicialização do plugin %s falhou, deixando o seguinte relatório:"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:247
|
||||
msgid ""
|
||||
@ -164,43 +167,53 @@ msgid ""
|
||||
" Customize calibre by loading external plugins.\n"
|
||||
" "
|
||||
msgstr ""
|
||||
" opções do %prog\n"
|
||||
" \n"
|
||||
" Personalizar o Calibre carregando plugins externos.\n"
|
||||
" "
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:253
|
||||
msgid "Add a plugin by specifying the path to the zip file containing it."
|
||||
msgstr ""
|
||||
"Acrescentar um plugin especificando um caminho para o ficheiro zip que o "
|
||||
"contém."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:255
|
||||
msgid "Remove a custom plugin by name. Has no effect on builtin plugins"
|
||||
msgstr ""
|
||||
"Remover um plugin predefenido pelo seu nome. Não tem qualquer efeito sobre "
|
||||
"os plugins integrados"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:257
|
||||
msgid ""
|
||||
"Customize plugin. Specify name of plugin and customization string separated "
|
||||
"by a comma."
|
||||
msgstr ""
|
||||
"Personalizar plugin. Especifique o nome do plugin e uma expressão "
|
||||
"identificadora, separados por uma vírgula."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:259
|
||||
msgid "List all installed plugins"
|
||||
msgstr ""
|
||||
msgstr "Listar todos os 'plugins' instalados"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:261
|
||||
msgid "Enable the named plugin"
|
||||
msgstr ""
|
||||
msgstr "Activar o plugin mencionado"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:263
|
||||
msgid "Disable the named plugin"
|
||||
msgstr ""
|
||||
msgstr "Desactivar o plugin mencionado"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:140
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:158
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:196
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:224
|
||||
msgid "Unable to detect the %s disk drive. Try rebooting."
|
||||
msgstr "Incapaz de detectar o disco %s. Tente reinicializar"
|
||||
msgstr "Incapaz de detectar o disco %s. Tente reiniciar"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:412
|
||||
msgid "The reader has no storage card connected."
|
||||
msgstr "O leitor não tem cartão de armazenamento conectado"
|
||||
msgstr "O leitor não tem um cartão de armazenamento conectado."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:92
|
||||
msgid "Options to control the conversion to EPUB"
|
||||
@ -212,7 +225,7 @@ msgid ""
|
||||
"name."
|
||||
msgstr ""
|
||||
"O arquivo de saída EPUB. Se não especificado, ele será herdado do nome do "
|
||||
"arquivo aberto"
|
||||
"arquivo aberto."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:105
|
||||
msgid ""
|
||||
@ -220,21 +233,22 @@ msgid ""
|
||||
"device independent EPUB. The profile is used for device specific "
|
||||
"restrictions on the EPUB. Choices are: "
|
||||
msgstr ""
|
||||
"Perfil do disco para o qual este EPUB foi especificado. Selecione nenhum "
|
||||
"para criar um EPUB diferente. Este perfil é usado para especificar "
|
||||
"restrições no EPUB. As escolhas são: "
|
||||
"Perfil do dispositivo para o qual este EPUB foi especificado. Selecione "
|
||||
"Nenhum para criar um EPUB independente de quaiquer dispositivos. Este perfil "
|
||||
"é usado para definir restrições específicas de cada dispositivo quanto ao "
|
||||
"EPUB. As escolhas são: "
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:107
|
||||
msgid ""
|
||||
"Either the path to a CSS stylesheet or raw CSS. This CSS will override any "
|
||||
"existing CSS declarations in the source files."
|
||||
msgstr ""
|
||||
"Ou o caminho para uma folha de estilos CSS ou raw CSS. Este CSS irá "
|
||||
"substituir qualquer declaração CSS existente nos arquivos fontes"
|
||||
"O caminho para uma folha de estilos CSS ou CSS puro. Esta CSS vai reescrever "
|
||||
"quaisquer indicações CSS existentes nos ficheiros de origem."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:108
|
||||
msgid "Control auto-detection of document structure."
|
||||
msgstr "Controlar auto detecção da estrutura do documento"
|
||||
msgstr "Controlar a autodetecção da estrutura de um documento."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:110
|
||||
msgid ""
|
||||
@ -279,7 +293,7 @@ msgstr "Caminho para a capa a ser usada por este livro"
|
||||
msgid ""
|
||||
"Use the cover detected from the source file in preference to the specified "
|
||||
"cover."
|
||||
msgstr ""
|
||||
msgstr "Usa a capa detectada no ficheiro-fonte em vez da capa especificada."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:127
|
||||
msgid ""
|
||||
@ -289,6 +303,11 @@ msgid ""
|
||||
"trying\n"
|
||||
"to auto-generate a Table of Contents.\n"
|
||||
msgstr ""
|
||||
"Controle a criação automática de uma Tabela de Conteúdos. Se for detectado "
|
||||
"um ficheiro OPF\n"
|
||||
"que especifique uma Tabela de Conteúdos, esse ficheiro será utilizado em vez "
|
||||
"de se tentar\n"
|
||||
"gerar automaticamente uma Tabela de Conteúdos.\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:133
|
||||
msgid ""
|
||||
@ -296,16 +315,22 @@ msgid ""
|
||||
"is: %default. Links are only added to the TOC if less than the --toc-"
|
||||
"threshold number of chapters were detected."
|
||||
msgstr ""
|
||||
"Número máximo de ligações a inserir uma Tabela de Conteúdos. A predefinição "
|
||||
"é: %default. As ligações apenas são acrescentadas à TdC se forem detectados "
|
||||
"menos capítulos do que o limite."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:135
|
||||
msgid "Don't add auto-detected chapters to the Table of Contents."
|
||||
msgstr ""
|
||||
"Não acrescentar à Tabela de Conteúdos capítulos detectados automaticamente."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:137
|
||||
msgid ""
|
||||
"If fewer than this number of chapters is detected, then links are added to "
|
||||
"the Table of Contents. Default: %default"
|
||||
msgstr ""
|
||||
"Se forem detectados menos capítulos do que este número, as ligações são "
|
||||
"acrescentadas à Tabela de Conteúdos. Predefinição: %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:139
|
||||
msgid ""
|
||||
@ -313,6 +338,9 @@ msgid ""
|
||||
"of Contents at level one. If this is specified, it takes precedence over "
|
||||
"other forms of auto-detection."
|
||||
msgstr ""
|
||||
"Expressão XPath que especifica todas as etiquetas que devem ser "
|
||||
"acrescentadas à Tabela de Conteúdos com o nível 1. Se isto for especificado, "
|
||||
"assume prevalência sobre outras formas de auto-detecção."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:141
|
||||
msgid ""
|
||||
@ -320,6 +348,9 @@ msgid ""
|
||||
"of Contents at level two. Each entry is added under the previous level one "
|
||||
"entry."
|
||||
msgstr ""
|
||||
"Expressão xPath que especifica todas as etiquetas que devem ser "
|
||||
"acrescentadas à Tabela de Conteúdos com o nível 2. Cada entrada é "
|
||||
"acrescentada abaixo da entrada antecedente com o nível 1."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:143
|
||||
msgid ""
|
||||
@ -328,6 +359,10 @@ msgid ""
|
||||
"placed in. See http://www.niso.org/workrooms/daisy/Z39-86-2005.html#NCX for "
|
||||
"an overview of the NCX format."
|
||||
msgstr ""
|
||||
"Caminho para um ficheiro .ncx que contém a tabela de conteúdos a utilizar "
|
||||
"neste ebook. O ficheiro NCX contém ligações relativas à directoria na qual é "
|
||||
"colocado. Visite a página http://www.niso.org/workrooms/daisy/Z39-86-"
|
||||
"2005.html#NCX para ter uma visão geral sobre o formato NCX."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:145
|
||||
msgid ""
|
||||
@ -335,26 +370,29 @@ msgid ""
|
||||
"preference to the autodetected one. With this option, the autodetected one "
|
||||
"is always used."
|
||||
msgstr ""
|
||||
"Normalmente, se o ficheiro de origem já tem uma Tabela de Conteúdos, ela é "
|
||||
"usada preferencialmente, em vez de uma autodetectada. Com esta opção, a "
|
||||
"autodetectada é sempre utilizada."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:147
|
||||
msgid "Control page layout"
|
||||
msgstr ""
|
||||
msgstr "Controlar a aparência da página"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:149
|
||||
msgid "Set the top margin in pts. Default is %default"
|
||||
msgstr ""
|
||||
msgstr "Definir a margem superior em pontos. A predefinição é: %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:151
|
||||
msgid "Set the bottom margin in pts. Default is %default"
|
||||
msgstr ""
|
||||
msgstr "Definir a margem inferior em pontos. A predefinição é: %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:153
|
||||
msgid "Set the left margin in pts. Default is %default"
|
||||
msgstr ""
|
||||
msgstr "Definir a margem esquerda em pontos. A predefinição é: %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:155
|
||||
msgid "Set the right margin in pts. Default is %default"
|
||||
msgstr ""
|
||||
msgstr "Definir a margem direita em pontos. A predefinição é: %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:157
|
||||
msgid ""
|
||||
@ -367,6 +405,8 @@ msgid ""
|
||||
"Remove spacing between paragraphs. Will not work if the source file forces "
|
||||
"inter-paragraph spacing."
|
||||
msgstr ""
|
||||
"Remover espaçamento entre parágrafos. Não irá funcionar se o ficheiro de "
|
||||
"origem forçar o espaçamento entre parágrafos."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:161
|
||||
msgid ""
|
||||
@ -377,20 +417,23 @@ msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:164
|
||||
msgid "Print generated OPF file to stdout"
|
||||
msgstr ""
|
||||
msgstr "Mostrar o ficheiro OPF gerado no stdout"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:166
|
||||
msgid "Print generated NCX file to stdout"
|
||||
msgstr ""
|
||||
msgstr "Mostrar o ficheiro NCX gerado no stdout"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:168
|
||||
msgid "Keep intermediate files during processing by html2epub"
|
||||
msgstr ""
|
||||
"Manter os ficheiros intermédios durante o processamento pelo html2epub"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:170
|
||||
msgid ""
|
||||
"Extract the contents of the produced EPUB file to the specified directory."
|
||||
msgstr ""
|
||||
"Extrair os conteúdos do ficheiro EPUB produzido para a directoria "
|
||||
"especificada."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_any.py:156
|
||||
msgid ""
|
||||
@ -399,10 +442,14 @@ msgid ""
|
||||
"Convert any of a large number of ebook formats to a %s file. Supported "
|
||||
"formats are: %s\n"
|
||||
msgstr ""
|
||||
"%%prog [options] filename\n"
|
||||
"\n"
|
||||
"Converter um grande númedo de formatos de ebook para um ficheiro %s. Os "
|
||||
"formatos suportados são: %s\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:100
|
||||
msgid "Could not find an ebook inside the archive"
|
||||
msgstr ""
|
||||
msgstr "Foi impossível localizar um ebook dentro do arquivo"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:158
|
||||
msgid ""
|
||||
@ -418,31 +465,35 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:391
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/writer.py:739
|
||||
msgid "Output written to "
|
||||
msgstr ""
|
||||
msgstr "Resultado escrito para "
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:413
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:1046
|
||||
msgid "You must specify an input HTML file"
|
||||
msgstr ""
|
||||
msgstr "Deve especificar um ficheiro para importação em HTML"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/iterator.py:36
|
||||
msgid "%s format books are not supported"
|
||||
msgstr ""
|
||||
msgstr "Os livros em formato %s não são suportados"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/split.py:30
|
||||
msgid ""
|
||||
"Could not find reasonable point at which to split: %s Sub-tree size: %d KB"
|
||||
msgstr ""
|
||||
"Não foi possível encontrar um ponto razoável no qual dividir: %s Tamanho da "
|
||||
"sub-árvore: %d KB"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/split.py:136
|
||||
msgid ""
|
||||
"\t\tToo much markup. Re-splitting without structure preservation. This may "
|
||||
"cause incorrect rendering."
|
||||
msgstr ""
|
||||
"\t\tDemasiada formatação. Dividindo novamente sem preservação da estrutura. "
|
||||
"Isto pode levar a uma representação incorrecta."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:490
|
||||
msgid "Written processed HTML to "
|
||||
msgstr ""
|
||||
msgstr "HTML processado escrito no "
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:831
|
||||
msgid "Options to control the traversal of HTML"
|
||||
@ -450,21 +501,25 @@ msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:838
|
||||
msgid "The output directory. Default is the current directory."
|
||||
msgstr ""
|
||||
msgstr "Directoria de saída. A directoria actual é a predefinida."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:840
|
||||
msgid "Character encoding for HTML files. Default is to auto detect."
|
||||
msgstr ""
|
||||
"Codificação de caracteres para os ficheiros HTML. A predefinição é auto-"
|
||||
"detectar."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:842
|
||||
msgid ""
|
||||
"Create the output in a zip file. If this option is specified, the --output "
|
||||
"should be the name of a file not a directory."
|
||||
msgstr ""
|
||||
"Criar a saída num ficheiro zip. Se esta opção for especificada a --output "
|
||||
"deve ser o nome de um ficheiro, não de uma directoria."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:844
|
||||
msgid "Control the following of links in HTML files."
|
||||
msgstr ""
|
||||
msgstr "Controlar a sequência das ligações nos ficheiros HTML."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:846
|
||||
msgid ""
|
||||
@ -480,41 +535,43 @@ msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:850
|
||||
msgid "Set metadata of the generated ebook"
|
||||
msgstr ""
|
||||
msgstr "Definir metadados do ebook gerado"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:852
|
||||
msgid "Set the title. Default is to autodetect."
|
||||
msgstr ""
|
||||
msgstr "Definir o título. A predefinição é auto-detectar."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:854
|
||||
msgid "The author(s) of the ebook, as a comma separated list."
|
||||
msgstr ""
|
||||
msgstr "O(s) autor(es) do ebooks, como uma lista separada por vírgulas."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:856
|
||||
msgid "The subject(s) of this book, as a comma separated list."
|
||||
msgstr ""
|
||||
msgstr "O(s) assunto(s) deste ebook, como uma lista separada por vírgulas."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:858
|
||||
msgid "Set the publisher of this book."
|
||||
msgstr ""
|
||||
msgstr "Defina a editora deste livro."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:860
|
||||
msgid "A summary of this book."
|
||||
msgstr ""
|
||||
msgstr "Um resumo deste livro."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:862
|
||||
msgid "Load metadata from the specified OPF file"
|
||||
msgstr ""
|
||||
msgstr "Carregar metadados a partir de um ficheiro OPF especificado"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:864
|
||||
msgid "Options useful for debugging"
|
||||
msgstr ""
|
||||
msgstr "Opções úteis para depurar"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:866
|
||||
msgid ""
|
||||
"Be more verbose while processing. Can be specified multiple times to "
|
||||
"increase verbosity."
|
||||
msgstr ""
|
||||
"Apresentar mais indicações durante o processamento. Pode ser especificado "
|
||||
"mais do que uma vez para aumentar a prolixidez."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:868
|
||||
msgid "Output HTML is \"pretty printed\" for easier parsing by humans"
|
||||
@ -535,16 +592,16 @@ msgstr ""
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/from_any.py:44
|
||||
msgid "Creating LIT file from EPUB..."
|
||||
msgstr ""
|
||||
msgstr "Criando ficheiro LIT a partir de um EPUB..."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:849
|
||||
msgid "%prog [options] LITFILE"
|
||||
msgstr ""
|
||||
msgstr "%prog [options] LITFILE"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:852
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:444
|
||||
msgid "Output directory. Defaults to current directory."
|
||||
msgstr ""
|
||||
msgstr "Directoria de saída. A predefinição é a directoria actual."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:855
|
||||
msgid "Legibly format extracted markup. May modify meaningful whitespace."
|
||||
@ -553,73 +610,80 @@ msgstr ""
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:858
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/writer.py:724
|
||||
msgid "Useful for debugging."
|
||||
msgstr ""
|
||||
msgstr "Útil para depurar."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:869
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:468
|
||||
msgid "OEB ebook created in"
|
||||
msgstr ""
|
||||
msgstr "Ebook em OEB criado em"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/writer.py:718
|
||||
msgid "%prog [options] OPFFILE"
|
||||
msgstr ""
|
||||
msgstr "%prog [options] OPFFILE"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/writer.py:721
|
||||
msgid "Output file. Default is derived from input filename."
|
||||
msgstr ""
|
||||
msgstr "Ficheiro de saída. A predefinição é o nome do ficheiro de origem."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:74
|
||||
msgid "Set the title. Default: filename."
|
||||
msgstr ""
|
||||
msgstr "Defina o título. Predefinição: nome do ficheiro."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:76
|
||||
msgid ""
|
||||
"Set the author(s). Multiple authors should be set as a comma separated list. "
|
||||
"Default: %default"
|
||||
msgstr ""
|
||||
"Defina o(s) autor(es). Múltiplos autores devem ser definidos como uma lista "
|
||||
"separada por vírgulas. Predefenição: %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:79
|
||||
msgid "Set the comment."
|
||||
msgstr ""
|
||||
msgstr "Defina um comentário."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:81
|
||||
msgid "Set the category"
|
||||
msgstr ""
|
||||
msgstr "Defina uma categoria"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:83
|
||||
msgid "Sort key for the title"
|
||||
msgstr ""
|
||||
msgstr "Palavra do título para a listagem"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:85
|
||||
msgid "Sort key for the author"
|
||||
msgstr ""
|
||||
msgstr "Palavra do nome do autor para a listagem"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:87
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:275
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:39
|
||||
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:97
|
||||
msgid "Publisher"
|
||||
msgstr ""
|
||||
msgstr "Editora"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:89
|
||||
msgid "Path to file containing image to be used as cover"
|
||||
msgstr ""
|
||||
msgstr "Caminho para o ficheiro que contém a imagem a usar como capa"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:91
|
||||
msgid ""
|
||||
"If there is a cover graphic detected in the source file, use that instead of "
|
||||
"the specified cover."
|
||||
msgstr ""
|
||||
"Se uma imagem de capa for detectada no ficheiro de origem, usa essa em vez "
|
||||
"da capa especificada."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:94
|
||||
msgid "Output file name. Default is derived from input filename"
|
||||
msgstr ""
|
||||
"Nome do ficheiro de saída. A predefinição é o nome do ficheiro de origem."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:96
|
||||
msgid ""
|
||||
"Render HTML tables as blocks of text instead of actual tables. This is "
|
||||
"neccessary if the HTML contains very large or complex tables."
|
||||
msgstr ""
|
||||
"Mostrar as tabelas em HTML como blocos de texto em vez de tabelas reais. "
|
||||
"Isto é necessário se o HMTL contiver tabelas muito grandes ou complexas."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:99
|
||||
msgid ""
|
||||
@ -627,28 +691,35 @@ msgid ""
|
||||
"option obsoletes the --font-delta option and takes precedence over it. To "
|
||||
"use --font-delta, set this to 0. Default: %defaultpt"
|
||||
msgstr ""
|
||||
"Especificar tamanho de letra base em pontos. Todas os tipos de letra são "
|
||||
"redimensionados em conformidade. Esta opção torna obsoleta a opção --font-"
|
||||
"delta e tem prevalência sobre ela. Para usar --font-delta, defina isto como "
|
||||
"0. Predefinição: %defaultpt"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:101
|
||||
msgid "Enable autorotation of images that are wider than the screen width."
|
||||
msgstr ""
|
||||
"Activar a rotação automática de imagens mais largas do que a largura do ecrã."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:104
|
||||
msgid "Set the space between words in pts. Default is %default"
|
||||
msgstr ""
|
||||
msgstr "Defina o espaço entre palavras em pontos. A predefinição é %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:106
|
||||
msgid "Separate paragraphs by blank lines."
|
||||
msgstr ""
|
||||
msgstr "Separar parágrafos por linhas em branco."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:108
|
||||
msgid "Add a header to all the pages with title and author."
|
||||
msgstr ""
|
||||
msgstr "Acrescentar um cabeçalho com o título e o autor em todas as páginas."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:110
|
||||
msgid ""
|
||||
"Set the format of the header. %a is replaced by the author and %t by the "
|
||||
"title. Default is %default"
|
||||
msgstr ""
|
||||
"Definir o formato do cabeçalho. %a é substituído pelo autor e %t pelo "
|
||||
"título. A predefinição é %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:112
|
||||
msgid ""
|
||||
@ -662,12 +733,17 @@ msgid ""
|
||||
"the HTML files are appended to the LRF. The .opf file must be in the same "
|
||||
"directory as the base HTML file."
|
||||
msgstr ""
|
||||
"Use o elemento <spine> do ficheiro OPF para determinar a ordem pela qual os "
|
||||
"ficheiros HTML são apensardos ao LRF. O ficheiro .opt deve estar na mesma "
|
||||
"directoria que o ficheiro HTML base."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:116
|
||||
msgid ""
|
||||
"Minimum paragraph indent (the indent of the first line of a paragraph) in "
|
||||
"pts. Default: %default"
|
||||
msgstr ""
|
||||
"Avanço mínimo do parágrafo (avanço da primeira linha do parágrafo) em "
|
||||
"pontos. Predefinição: %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:118
|
||||
msgid ""
|
||||
@ -675,12 +751,17 @@ msgid ""
|
||||
"FONT_DELTA pts. FONT_DELTA can be a fraction.If FONT_DELTA is negative, the "
|
||||
"font size is decreased."
|
||||
msgstr ""
|
||||
"Aumentar o tamanho da letra em 2 * FONT_DELTA pontos e o espaçamento entre "
|
||||
"as linhas em FONT_DELTA pontos. Se FONT_DELTA for negativo, o tamanho da "
|
||||
"letra diminui."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:123
|
||||
msgid ""
|
||||
"Render all content as black on white instead of the colors specified by the "
|
||||
"HTML or CSS."
|
||||
msgstr ""
|
||||
"Apresenta todo o conteúdo como preto sobre fundo branco em vez das cores "
|
||||
"especificadas pelo HTML ou CSS."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:129
|
||||
msgid ""
|
||||
@ -688,34 +769,41 @@ msgid ""
|
||||
"profile determines things like the resolution and screen size of the target "
|
||||
"device. Default: %s Supported profiles: "
|
||||
msgstr ""
|
||||
"Perfil do dispositivo de destino para o qual este LRF está a ser gerado. O "
|
||||
"perfil determina coisas como a relolução e o tamanho do ecrã do dispositivo "
|
||||
"de destino. Predefinição: %s Perfis suportados: "
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:135
|
||||
msgid "Left margin of page. Default is %default px."
|
||||
msgstr ""
|
||||
msgstr "Margem esquerda da página. A predefinição é %default px."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:137
|
||||
msgid "Right margin of page. Default is %default px."
|
||||
msgstr ""
|
||||
msgstr "Margem direita da página. A predefinição é %default px."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:139
|
||||
msgid "Top margin of page. Default is %default px."
|
||||
msgstr ""
|
||||
msgstr "Margem superior da página. A predefinição é %default px."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:141
|
||||
msgid "Bottom margin of page. Default is %default px."
|
||||
msgstr ""
|
||||
msgstr "Margem inferior da página. A predefinição é %default px."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:143
|
||||
msgid ""
|
||||
"Render tables in the HTML as images (useful if the document has large or "
|
||||
"complex tables)"
|
||||
msgstr ""
|
||||
"Apresenta as tabelas existentes no HTML como imagens (útil se o documento "
|
||||
"tem tabelas grandes ou complexas)"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:145
|
||||
msgid ""
|
||||
"Multiply the size of text in rendered tables by this factor. Default is "
|
||||
"%default"
|
||||
msgstr ""
|
||||
"Multiplica o tamanho do texto nas tabelas a apresentar por este factor. A "
|
||||
"predefinição é %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:150
|
||||
msgid ""
|
||||
@ -729,20 +817,24 @@ msgid ""
|
||||
"A regular expression. <a> tags whose href matches will be ignored. Defaults "
|
||||
"to %default"
|
||||
msgstr ""
|
||||
"Uma expressão regular. As etiquetas <a> que encontram correspondência com "
|
||||
"href serão ignoradas. A predefinição é %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:158
|
||||
msgid "Don't add links to the table of contents."
|
||||
msgstr ""
|
||||
msgstr "Não acrescente ligações à tabela de conteúdos."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:162
|
||||
msgid "Prevent the automatic detection chapters."
|
||||
msgstr ""
|
||||
msgstr "Impede a detecção automática de capítulos."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:165
|
||||
msgid ""
|
||||
"The regular expression used to detect chapter titles. It is searched for in "
|
||||
"heading tags (h1-h6). Defaults to %default"
|
||||
msgstr ""
|
||||
"A expressão regular utilizada para detectar os títulos dos capítulos. É "
|
||||
"procurada nas etiquetas de cabeçalho (h1-h6). A predefinição é %default"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:168
|
||||
msgid ""
|
||||
@ -764,11 +856,21 @@ msgid ""
|
||||
"turn performance of the LRF. Thus this option is ignored if the current page "
|
||||
"has only a few elements."
|
||||
msgstr ""
|
||||
"Se o html2lrf não encontrar nenhuma quebra de página no ficheiro html e não "
|
||||
"conseguir detectar os títulos dos capítulos, inserirá automaticamente "
|
||||
"quebras de linha antes de etiquetas cujos nomes correspondam a esta "
|
||||
"expressão regular.A predefinição é %default. Você pode desactivar isto "
|
||||
"definindo a expressão regular como\"$\". A finalidade desta opção é tentar "
|
||||
"assegurar que não existem de facto páginas longas uma vez que isso diminui o "
|
||||
"desempenho do LRF nas mudanças de página. Deste modo, esta opção é ignorada "
|
||||
"se a página actual tiver apenas alguns elementos."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:180
|
||||
msgid ""
|
||||
"Force a page break before tags whose names match this regular expression."
|
||||
msgstr ""
|
||||
"Força uma quebra de página antes das etiquetas cujos nomes correspondam a "
|
||||
"esta expressão regular."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:182
|
||||
msgid ""
|
||||
|
5077
src/calibre/translations/ro.po
Normal file
5077
src/calibre/translations/ro.po
Normal file
File diff suppressed because it is too large
Load Diff
@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: calibre 0.4.55\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2008-12-30 15:33+0000\n"
|
||||
"PO-Revision-Date: 2009-01-03 17:58+0000\n"
|
||||
"PO-Revision-Date: 2009-01-07 18:26+0000\n"
|
||||
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||
"Language-Team: American English <kde-i18n-doc@lists.kde.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:33+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
"X-Poedit-Country: RUSSIAN FEDERATION\n"
|
||||
"X-Poedit-Language: Russian\n"
|
||||
@ -444,6 +444,8 @@ msgid ""
|
||||
"takes from\n"
|
||||
"the <spine> element of the OPF file. \n"
|
||||
msgstr ""
|
||||
"%prog [options] file.html|opf\n"
|
||||
"\n"
|
||||
"Преобразование файла HTML в EPUB книгу. Рекурсивно отслеживает линки в файле "
|
||||
"HTML.\n"
|
||||
"Если вы задаете файл OPF вместо HTML, список ссылок содержится в элементе "
|
||||
@ -1103,7 +1105,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Выбрать профайл устройства для которого вы преобразуете файл. По умолчанию "
|
||||
"SONY PRS-500 имеет размер экрана 584x754 пикселей. Это соответствует многим "
|
||||
"ридерам с таким же разрешением экрана."
|
||||
"ридерам с таким же разрешением экрана. Choices are %s"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:316
|
||||
msgid ""
|
||||
|
@ -8,13 +8,13 @@ msgstr ""
|
||||
"Project-Id-Version: calibre\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2008-12-30 15:33+0000\n"
|
||||
"PO-Revision-Date: 2008-12-15 22:58+0000\n"
|
||||
"Last-Translator: Michael Gallo <michael.gallo@tiscali.it>\n"
|
||||
"PO-Revision-Date: 2009-01-07 18:36+0000\n"
|
||||
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||
"Language-Team: Slovak <sk@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||
@ -441,7 +441,7 @@ msgid ""
|
||||
"takes from\n"
|
||||
"the <spine> element of the OPF file. \n"
|
||||
msgstr ""
|
||||
"%%prog [možnosti] súbor.html|opf\n"
|
||||
"%prog [možnosti] súbor.html|opf\n"
|
||||
"\n"
|
||||
"Konverzia HTML súboru na elektronickú knihu vo formáte EPUB. Rekurzívne "
|
||||
"sleduje odkazy v HTML súbore.\n"
|
||||
@ -1263,7 +1263,7 @@ msgid ""
|
||||
"You have to save the website %s as an html file first and then run html2lrf "
|
||||
"on it."
|
||||
msgstr ""
|
||||
"Webovú stránku je potrebné najprv uložiť ako HTML súbor, potom previesť "
|
||||
"Webovú %s stránku je potrebné najprv uložiť ako HTML súbor, potom previesť "
|
||||
"programom html2lrf."
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1865
|
||||
|
@ -7,13 +7,13 @@ msgstr ""
|
||||
"Project-Id-Version: calibre 0.4.17\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2008-12-30 15:33+0000\n"
|
||||
"PO-Revision-Date: 2008-12-30 07:52+0000\n"
|
||||
"Last-Translator: Janko Slatenšek <Unknown>\n"
|
||||
"PO-Revision-Date: 2009-01-07 18:38+0000\n"
|
||||
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||
"Language-Team: sl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
@ -3865,11 +3865,11 @@ msgstr ""
|
||||
" <li>Izklopite reader iz računalnika. Počakajte da konča s "
|
||||
"ponovnim generiranjem baze (npr. počakajte dokler ni pripravljen za "
|
||||
"uporabo). Vklopite reader nazaj v računalnik. Sedaj bi moral delovati z "
|
||||
"%(app). Če ne deluje poskusite naslednji korak.</li>\n"
|
||||
" <li>Končajte %(app). Poiščite datoteko media.xml v glavnem "
|
||||
"%(app)s. Če ne deluje poskusite naslednji korak.</li>\n"
|
||||
" <li>Končajte %(app)s. Poiščite datoteko media.xml v glavnem "
|
||||
"spominu reader-ja. Izbrišite jo in izklopite reader iz računalnika. "
|
||||
"Počakajte da datoteko ponovno ustvari. Ponovno priklopite reader in zaženite "
|
||||
"%(app).</li>\n"
|
||||
"%(app)s.</li>\n"
|
||||
" </ol>\n"
|
||||
" "
|
||||
|
||||
|
@ -14,7 +14,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||
|
@ -14,7 +14,7 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-04 04:32+0000\n"
|
||||
"X-Launchpad-Export-Date: 2009-01-07 18:40+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||
|
@ -5,6 +5,7 @@ __copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
joelonsoftware.com
|
||||
'''
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class Joelonsoftware(BasicNewsRecipe):
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user