diff --git a/setup.py b/setup.py
index ad56a0c9e4..b0ff04a983 100644
--- a/setup.py
+++ b/setup.py
@@ -52,7 +52,8 @@ if __name__ == '__main__':
resources, clean, gui, translations, update, \
tag_release, upload_demo, build_linux, build_windows, \
build_osx, upload_installers, upload_user_manual, \
- upload_to_pypi, stage3, stage2, stage1, upload
+ upload_to_pypi, stage3, stage2, stage1, upload, \
+ upload_rss
entry_points['console_scripts'].append(
'calibre_postinstall = calibre.linux:post_install')
@@ -170,6 +171,7 @@ if __name__ == '__main__':
'upload_installers': upload_installers,
'upload_user_manual': upload_user_manual,
'upload_to_pypi': upload_to_pypi,
+ 'upload_rss' : upload_rss,
'stage3' : stage3,
'stage2' : stage2,
'stage1' : stage1,
diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py
index de133ddb57..807ce1def5 100644
--- a/src/calibre/__init__.py
+++ b/src/calibre/__init__.py
@@ -3,11 +3,13 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal '
__docformat__ = 'restructuredtext en'
import sys, os, re, logging, time, subprocess, atexit, mimetypes, \
- __builtin__
+ __builtin__, warnings
__builtin__.__dict__['dynamic_property'] = lambda(func): func(None)
from htmlentitydefs import name2codepoint
from math import floor
-from logging import Formatter
+
+warnings.simplefilter('ignore', DeprecationWarning)
+
from PyQt4.QtCore import QUrl
from PyQt4.QtGui import QDesktopServices
@@ -24,11 +26,17 @@ mimetypes.add_type('text/x-sony-bbeb+xml', '.lrs')
mimetypes.add_type('application/xhtml+xml', '.xhtml')
mimetypes.add_type('image/svg+xml', '.svg')
mimetypes.add_type('application/x-sony-bbeb', '.lrf')
+mimetypes.add_type('application/x-sony-bbeb', '.lrx')
mimetypes.add_type('application/x-dtbncx+xml', '.ncx')
mimetypes.add_type('application/adobe-page-template+xml', '.xpgt')
mimetypes.add_type('application/x-font-opentype', '.otf')
mimetypes.add_type('application/x-font-truetype', '.ttf')
mimetypes.add_type('application/oebps-package+xml', '.opf')
+mimetypes.add_type('application/ereader', '.pdb')
+mimetypes.add_type('application/mobi', '.mobi')
+mimetypes.add_type('application/mobi', '.prc')
+mimetypes.add_type('application/mobi', '.azw')
+guess_type = mimetypes.guess_type
import cssutils
cssutils.log.setLevel(logging.WARN)
@@ -86,6 +94,8 @@ def prints(*args, **kwargs):
for i, arg in enumerate(args):
if isinstance(arg, unicode):
arg = arg.encode(preferred_encoding)
+ if not isinstance(arg, str):
+ arg = str(arg)
file.write(arg)
if i != len(args)-1:
file.write(sep)
@@ -318,24 +328,6 @@ def english_sort(x, y):
'''
return cmp(_spat.sub('', x), _spat.sub('', y))
-class ColoredFormatter(Formatter):
-
- def format(self, record):
- ln = record.__dict__['levelname']
- col = ''
- if ln == 'CRITICAL':
- col = terminal_controller.YELLOW
- elif ln == 'ERROR':
- col = terminal_controller.RED
- elif ln in ['WARN', 'WARNING']:
- col = terminal_controller.BLUE
- elif ln == 'INFO':
- col = terminal_controller.GREEN
- elif ln == 'DEBUG':
- col = terminal_controller.CYAN
- record.__dict__['levelname'] = col + record.__dict__['levelname'] + terminal_controller.NORMAL
- return Formatter.format(self, record)
-
def walk(dir):
''' A nice interface to os.walk '''
for record in os.walk(dir):
diff --git a/src/calibre/constants.py b/src/calibre/constants.py
index aebcb35dc0..6950c66526 100644
--- a/src/calibre/constants.py
+++ b/src/calibre/constants.py
@@ -2,7 +2,7 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
__appname__ = 'calibre'
-__version__ = '0.4.143'
+__version__ = '0.5.1'
__author__ = "Kovid Goyal "
'''
Various run time constants.
diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py
index fafe8e5afa..d37e241891 100644
--- a/src/calibre/customize/builtins.py
+++ b/src/calibre/customize/builtins.py
@@ -132,13 +132,24 @@ class HTMLMetadataReader(MetadataReaderPlugin):
class MOBIMetadataReader(MetadataReaderPlugin):
name = 'Read MOBI metadata'
- file_types = set(['mobi', 'prc', '.azw'])
+ file_types = set(['mobi', 'prc', 'azw'])
description = _('Read metadata from %s files')%'MOBI'
def get_metadata(self, stream, ftype):
from calibre.ebooks.mobi.reader import get_metadata
return get_metadata(stream)
+
+class TOPAZMetadataReader(MetadataReaderPlugin):
+
+ name = 'Read Topaz metadata'
+ file_types = set(['tpz', 'azw1'])
+ description = _('Read metadata from %s files')%'MOBI'
+
+ def get_metadata(self, stream, ftype):
+ from calibre.ebooks.metadata.topaz import get_metadata
+ return get_metadata(stream)
+
class ODTMetadataReader(MetadataReaderPlugin):
name = 'Read ODT metadata'
@@ -244,11 +255,12 @@ class MOBIMetadataWriter(MetadataWriterPlugin):
from calibre.ebooks.epub.input import EPUBInput
from calibre.ebooks.mobi.input import MOBIInput
-from calibre.customize.profiles import input_profiles
+from calibre.ebooks.oeb.output import OEBOutput
+from calibre.customize.profiles import input_profiles, output_profiles
-plugins = [HTML2ZIP, EPUBInput, MOBIInput]
+plugins = [HTML2ZIP, EPUBInput, MOBIInput, OEBOutput]
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
x.__name__.endswith('MetadataReader')]
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
x.__name__.endswith('MetadataWriter')]
-plugins += input_profiles
\ No newline at end of file
+plugins += input_profiles + output_profiles
\ No newline at end of file
diff --git a/src/calibre/customize/conversion.py b/src/calibre/customize/conversion.py
index aa7b0c1dea..a77e32beee 100644
--- a/src/calibre/customize/conversion.py
+++ b/src/calibre/customize/conversion.py
@@ -24,7 +24,7 @@ class ConversionOption(object):
self.choices = choices
if self.long_switch is None:
- self.long_switch = '--'+self.name.replace('_', '-')
+ self.long_switch = self.name.replace('_', '-')
self.validate_parameters()
@@ -37,19 +37,24 @@ class ConversionOption(object):
if not self.help:
raise ValueError('You must set the help text')
+ def __hash__(self):
+ return hash(self.name)
+
+ def __eq__(self, other):
+ return hash(self) == hash(other)
class OptionRecommendation(object):
LOW = 1
MED = 2
HIGH = 3
- def __init__(self, recommeded_value, level=LOW, **kwargs):
+ def __init__(self, recommended_value=None, level=LOW, **kwargs):
'''
An option recommendation. That is, an option as well as its recommended
value and the level of the recommendation.
'''
self.level = level
- self.recommended_value = recommeded_value
+ self.recommended_value = recommended_value
self.option = kwargs.pop('option', None)
if self.option is None:
self.option = ConversionOption(**kwargs)
@@ -59,10 +64,12 @@ class OptionRecommendation(object):
def validate_parameters(self):
if self.option.choices and self.recommended_value not in \
self.option.choices:
- raise ValueError('Recommended value not in choices')
+ raise ValueError('OpRec: %s: Recommended value not in choices'%
+ self.option.name)
if not (isinstance(self.recommended_value, (int, float, str, unicode))\
- or self.default is None):
- raise ValueError(unicode(self.default) +
+ or self.recommended_value is None):
+ raise ValueError('OpRec: %s:'%self.option.name +
+ repr(self.recommended_value) +
' is not a string or a number')
@@ -110,7 +117,11 @@ class InputFormatPlugin(Plugin):
#: instance of :class:`OptionRecommendation`.
options = set([])
- def convert(self, stream, options, file_ext, parse_cache, log):
+ #: A set of 3-tuples of the form
+ #: (option_name, recommended_value, recommendation_level)
+ recommendations = set([])
+
+ def convert(self, stream, options, file_ext, parse_cache, log, accelerators):
'''
This method must be implemented in sub-classes. It must return
the path to the created OPF file. All output should be contained in
@@ -146,10 +157,16 @@ class InputFormatPlugin(Plugin):
:param log: A :class:`calibre.utils.logging.Log` object. All output
should use this object.
+
+ :param accelarators: A dictionary of various information that the input
+ plugin can get easily that would speed up the
+ subsequent stages of the conversion.
+
'''
raise NotImplementedError
- def __call__(self, stream, options, file_ext, parse_cache, log, output_dir):
+ def __call__(self, stream, options, file_ext, parse_cache, log,
+ accelerators, output_dir):
log('InputFormatPlugin: %s running'%self.name, end=' ')
if hasattr(stream, 'name'):
log('on', stream.name)
@@ -159,7 +176,8 @@ class InputFormatPlugin(Plugin):
shutil.rmtree(x) if os.path.isdir(x) else os.remove(x)
- ret = self.convert(stream, options, file_ext, parse_cache, log)
+ ret = self.convert(stream, options, file_ext, parse_cache,
+ log, accelerators)
for key in list(parse_cache.keys()):
if os.path.abspath(key) != key:
log.warn(('InputFormatPlugin: %s returned a '
@@ -186,4 +204,38 @@ class InputFormatPlugin(Plugin):
return ret
+
+
+class OutputFormatPlugin(Plugin):
+ '''
+ OutputFormatPlugins are responsible for converting an OEB document
+ (OPF+HTML) into an output ebook.
+
+ The OEB document can be assumed to be encoded in UTF-8.
+ The main action happens in :method:`convert`.
+ '''
+
+ type = _('Conversion Output')
+ can_be_disabled = False
+ supported_platforms = ['windows', 'osx', 'linux']
+
+ #: The file type (extension without leading period) that this
+ #: plugin outputs
+ file_type = None
+
+ #: Options shared by all Input format plugins. Do not override
+ #: in sub-classes. Use :member:`options` instead. Every option must be an
+ #: instance of :class:`OptionRecommendation`.
+ common_options = set([])
+
+ #: Options to customize the behavior of this plugin. Every option must be an
+ #: instance of :class:`OptionRecommendation`.
+ options = set([])
+
+ #: A set of 3-tuples of the form
+ #: (option_name, recommended_value, recommendation_level)
+ recommendations = set([])
+
+ def convert(self, oeb_book, input_plugin, options, parse_cache, log):
+ raise NotImplementedError
diff --git a/src/calibre/customize/profiles.py b/src/calibre/customize/profiles.py
index 002f56879f..a3a7e22298 100644
--- a/src/calibre/customize/profiles.py
+++ b/src/calibre/customize/profiles.py
@@ -3,6 +3,7 @@ __license__ = 'GPL 3'
__copyright__ = '2009, Kovid Goyal '
__docformat__ = 'restructuredtext en'
+import sys, re
from calibre.customize import Plugin
class InputProfile(Plugin):
@@ -16,12 +17,43 @@ class InputProfile(Plugin):
# inherit from this profile and override as needed
name = 'Default Input Profile'
- short_name = 'default' # Used in the CLI so dont spaces etc. in it
+ short_name = 'default' # Used in the CLI so dont use spaces etc. in it
description = _('This profile tries to provide sane defaults and is useful '
'if you know nothing about the input document.')
input_profiles = [InputProfile]
-
+class OutputProfile(Plugin):
+ author = 'Kovid Goyal'
+ supported_platforms = set(['windows', 'osx', 'linux'])
+ can_be_disabled = False
+ type = _('Output profile')
+
+ name = 'Default Output Profile'
+ short_name = 'default' # Used in the CLI so dont use spaces etc. in it
+ description = _('This profile tries to provide sane defaults and is useful '
+ 'if you want to produce a document intended to be read at a '
+ 'computer or on a range of devices.')
+
+ epub_flow_size = sys.maxint
+ screen_size = None
+ remove_special_chars = False
+ remove_object_tags = False
+
+class SonyReader(OutputProfile):
+
+ name = 'Sony Reader'
+ short_name = 'sony'
+ description = _('This profile is intended for the SONY PRS line. '
+ 'The 500/505/700 etc.')
+
+ epub_flow_size = 270000
+ screen_size = (590, 765)
+ remove_special_chars = re.compile(u'[\u200b\u00ad]')
+ remove_object_tags = True
+
+
+
+output_profiles = [OutputProfile, SonyReader]
\ No newline at end of file
diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py
index 1cdafae4f0..d8b7ebf6d8 100644
--- a/src/calibre/customize/ui.py
+++ b/src/calibre/customize/ui.py
@@ -6,8 +6,8 @@ import os, shutil, traceback, functools, sys
from calibre.customize import Plugin, FileTypePlugin, MetadataReaderPlugin, \
MetadataWriterPlugin
-from calibre.customize.conversion import InputFormatPlugin
-from calibre.customize.profiles import InputProfile
+from calibre.customize.conversion import InputFormatPlugin, OutputFormatPlugin
+from calibre.customize.profiles import InputProfile, OutputProfile
from calibre.customize.builtins import plugins as builtin_plugins
from calibre.constants import __version__, iswindows, isosx
from calibre.ebooks.metadata import MetaInformation
@@ -76,6 +76,12 @@ def input_profiles():
if isinstance(plugin, InputProfile):
yield plugin
+def output_profiles():
+ for plugin in _initialized_plugins:
+ if isinstance(plugin, OutputProfile):
+ yield plugin
+
+
def reread_filetype_plugins():
global _on_import
global _on_preprocess
@@ -245,9 +251,19 @@ def input_format_plugins():
def plugin_for_input_format(fmt):
for plugin in input_format_plugins():
- if fmt in plugin.file_types:
+ if fmt.lower() in plugin.file_types:
return plugin
-
+
+def output_format_plugins():
+ for plugin in _initialized_plugins:
+ if isinstance(plugin, OutputFormatPlugin):
+ yield plugin
+
+def plugin_for_output_format(fmt):
+ for plugin in output_format_plugins():
+ if fmt.lower() == plugin.file_type:
+ return plugin
+
def disable_plugin(plugin_or_name):
x = getattr(plugin_or_name, 'name', plugin_or_name)
diff --git a/src/calibre/devices/kindle/driver.py b/src/calibre/devices/kindle/driver.py
index e35d5f8cd3..14b056944b 100755
--- a/src/calibre/devices/kindle/driver.py
+++ b/src/calibre/devices/kindle/driver.py
@@ -4,9 +4,9 @@ __copyright__ = '2009, John Schember '
Device driver for Amazon's Kindle
'''
-import os
+import os, re
-from calibre.devices.usbms.driver import USBMS
+from calibre.devices.usbms.driver import USBMS, metadata_from_formats
class KINDLE(USBMS):
# Ordered list of supported formats
@@ -29,6 +29,9 @@ class KINDLE(USBMS):
EBOOK_DIR_MAIN = "documents"
EBOOK_DIR_CARD = "documents"
SUPPORTS_SUB_DIRS = True
+
+ WIRELESS_FILE_NAME_PATTERN = re.compile(
+ r'(?P[^-]+)-asin_(?P[a-zA-Z\d]{10,})-type_(?P\w{4})-v_(?P\d+).*')
def delete_books(self, paths, end_session=True):
for path in paths:
@@ -40,6 +43,16 @@ class KINDLE(USBMS):
# Delete the ebook auxiliary file
if os.path.exists(filepath + '.mbp'):
os.unlink(filepath + '.mbp')
+
+ @classmethod
+ def metadata_from_path(cls, path):
+ mi = metadata_from_formats([path])
+ if mi.title == _('Unknown') or ('-asin' in mi.title and '-type' in mi.title):
+ match = cls.WIRELESS_FILE_NAME_PATTERN.match(os.path.basename(path))
+ if match is not None:
+ mi.title = match.group('title')
+ return mi
+
class KINDLE2(KINDLE):
diff --git a/src/calibre/devices/mime.py b/src/calibre/devices/mime.py
index 0035a7b8d7..140c822ca9 100644
--- a/src/calibre/devices/mime.py
+++ b/src/calibre/devices/mime.py
@@ -1,19 +1,20 @@
-__license__ = 'GPL v3'
-__copyright__ = '2009, John Schember '
-'''
-Global Mime mapping of ebook types.
-'''
+from __future__ import with_statement
+__license__ = 'GPL 3'
+__copyright__ = '2009, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
-MIME_MAP = {
- 'azw' : 'application/azw',
- 'epub' : 'application/epub+zip',
- 'html' : 'text/html',
- 'lrf' : 'application/x-sony-bbeb',
- 'lrx' : 'application/x-sony-bbeb',
- 'mobi' : 'application/mobi',
- 'pdf' : 'application/pdf',
- 'prc' : 'application/prc',
- 'rtf' : 'application/rtf',
- 'txt' : 'text/plain',
- }
+from calibre import guess_type
+def _mt(path):
+ mt = guess_type(path)[0]
+ if not mt:
+ mt = 'application/octet-stream'
+ return mt
+
+def mime_type_ext(ext):
+ if not ext.startswith('.'):
+ ext = '.'+ext
+ return _mt('a'+ext)
+
+def mime_type_path(path):
+ return _mt(path)
\ No newline at end of file
diff --git a/src/calibre/devices/usbms/driver.py b/src/calibre/devices/usbms/driver.py
index bf231c1ffe..4285881447 100644
--- a/src/calibre/devices/usbms/driver.py
+++ b/src/calibre/devices/usbms/driver.py
@@ -15,7 +15,7 @@ from calibre.ebooks.metadata import authors_to_string
from calibre.devices.usbms.device import Device
from calibre.devices.usbms.books import BookList, Book
from calibre.devices.errors import FreeSpaceError, PathError
-from calibre.devices.mime import MIME_MAP
+from calibre.devices.mime import mime_type_ext
class File(object):
def __init__(self, path):
@@ -226,14 +226,17 @@ class USBMS(Device):
if not os.path.isdir(path):
os.utime(path, None)
+ @classmethod
+ def metadata_from_path(cls, path):
+ return metadata_from_formats([path])
+
@classmethod
def book_from_path(cls, path):
fileext = path_to_ext(path)
-
- mi = metadata_from_formats([path])
- mime = MIME_MAP[fileext] if fileext in MIME_MAP.keys() else 'Unknown'
-
+ mi = cls.metadata_from_path(path)
+ mime = mime_type_ext(fileext)
authors = authors_to_string(mi.authors)
- return Book(path, mi.title, authors, mime)
+ book = Book(path, mi.title, authors, mime)
+ return book
diff --git a/src/calibre/ebooks/BeautifulSoup.py b/src/calibre/ebooks/BeautifulSoup.py
index 24cd5fe3dd..cb2fe950fd 100644
--- a/src/calibre/ebooks/BeautifulSoup.py
+++ b/src/calibre/ebooks/BeautifulSoup.py
@@ -1306,7 +1306,10 @@ class BeautifulStoneSoup(Tag, SGMLParser):
if self.convertEntities:
if ref.lower().startswith('x'): #
ref = int(ref[1:], 16) # Added by Kovid to handle hex numeric entities
- data = unichr(int(ref))
+ try:
+ data = unichr(int(ref))
+ except ValueError: # Bad numerical entity. Added by Kovid
+ data = u''
else:
data = '%s;' % ref
self.handle_data(data)
diff --git a/src/calibre/ebooks/chardet/__init__.py b/src/calibre/ebooks/chardet/__init__.py
index af6d724883..2e8cdcb67c 100644
--- a/src/calibre/ebooks/chardet/__init__.py
+++ b/src/calibre/ebooks/chardet/__init__.py
@@ -97,9 +97,12 @@ def xml_to_unicode(raw, verbose=False, strip_encoding_pats=False,
if encoding is None:
encoding = force_encoding(raw, verbose)
try:
+ if encoding.lower().strip() == 'macintosh':
+ encoding = 'mac-roman'
raw = raw.decode(encoding, 'replace')
except LookupError:
- raw = raw.decode('utf-8', 'replace')
+ encoding = 'utf-8'
+ raw = raw.decode(encoding, 'replace')
if strip_encoding_pats:
raw = strip_encoding_declarations(raw)
diff --git a/src/calibre/ebooks/conversion/cli.py b/src/calibre/ebooks/conversion/cli.py
new file mode 100644
index 0000000000..f52264f8d0
--- /dev/null
+++ b/src/calibre/ebooks/conversion/cli.py
@@ -0,0 +1,167 @@
+from __future__ import with_statement
+__license__ = 'GPL 3'
+__copyright__ = '2009, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+'''
+Command line interface to conversion sub-system
+'''
+
+USAGE = '%prog ' + _('''\
+input_file output_file [options]
+
+Convert an ebook from one format to another.
+
+input_file is the input and output_file is the output. Both must be \
+specified as the first two arguments to the command.
+
+The output ebook format is guessed from the file extension of \
+output_file. output_file can also be of the special format .EXT where \
+EXT is the output file extension. In this case, the name of the output \
+file is derived the name of the input file. Note that the filenames must \
+not start with a hyphen. Finally, if output_file has no extension, then \
+it is treated as a directory and an "open ebook" (OEB) consisting of HTML \
+files is written to that directory. These files are the files that would \
+normally have been passed to the output plugin.
+
+After specifying the input \
+and output file you can customize the conversion by specifying various \
+options. the available options depend on the input and output file types. \
+To get help on them specify the input and output file and then use the -h \
+option.
+
+For full documentation of the conversion system see
+''') + 'http://calibre.kovidgoyal.net/user_manual/conversion.html'
+
+import sys, os
+from optparse import OptionGroup, Option
+
+from calibre.utils.config import OptionParser
+from calibre.utils.logging import Log
+from calibre.constants import preferred_encoding
+from calibre.customize.conversion import OptionRecommendation
+
+def print_help(parser, log):
+ help = parser.format_help().encode(preferred_encoding, 'replace')
+ log(help)
+
+def check_command_line_options(parser, args, log):
+ if len(args) < 3 or args[1].startswith('-') or args[2].startswith('-'):
+ print_help(parser)
+ log.error('\n\nYou must specify the input AND output files')
+ raise SystemExit(1)
+
+ input = os.path.abspath(args[1])
+ if not os.access(input, os.R_OK):
+ log.error('Cannot read from', input)
+ raise SystemExit(1)
+
+ output = args[2]
+ if output.startswith('.'):
+ output = os.path.splitext(os.path.basename(input))[0]+output
+ output = os.path.abspath(output)
+
+ if '.' in output:
+ if os.path.exists(output):
+ log.warn('WARNING:', output, 'exists. Deleting.')
+ os.remove(output)
+
+ return input, output
+
+def option_recommendation_to_cli_option(add_option, rec):
+ opt = rec.option
+ switches = ['-'+opt.short_switch] if opt.short_switch else []
+ switches.append('--'+opt.long_switch)
+ attrs = dict(dest=opt.name, help=opt.help,
+ choices=opt.choices, default=rec.recommended_value)
+ add_option(Option(*switches, **attrs))
+
+def add_input_output_options(parser, plumber):
+ input_options, output_options = \
+ plumber.input_options, plumber.output_options
+
+ def add_options(group, options):
+ for opt in options:
+ option_recommendation_to_cli_option(group, opt)
+
+ if input_options:
+ title = _('INPUT OPTIONS')
+ io = OptionGroup(parser, title, _('Options to control the processing'
+ ' of the input %s file')%plumber.input_fmt)
+ add_options(io.add_option, input_options)
+ parser.add_option_group(io)
+
+ if output_options:
+ title = plumber.output_fmt.upper() + ' ' + _('OPTIONS')
+ oo = OptionGroup(parser, title, _('Options to control the processing'
+ ' of the output %s file')%plumber.input_fmt)
+ add_options(oo.add_option, output_options)
+ parser.add_option_group(oo)
+
+def add_pipeline_options(parser, plumber):
+ groups = {
+ '' : ('',
+ [
+ 'input_profile',
+ 'output_profile',
+ ]
+ ),
+
+ 'METADATA' : (_('Options to set metadata in the output'),
+ plumber.metadata_option_names,
+ ),
+ 'DEBUG': (_('Options to help with debugging the conversion'),
+ [
+ 'verbose',
+ ]),
+
+
+ }
+
+ group_order = ['', 'METADATA', 'DEBUG']
+
+ for group in group_order:
+ desc, options = groups[group]
+ if group:
+ group = OptionGroup(parser, group, desc)
+ parser.add_option_group(group)
+ add_option = group.add_option if group != '' else parser.add_option
+
+ for name in options:
+ rec = plumber.get_option_by_name(name)
+ if rec.level < rec.HIGH:
+ option_recommendation_to_cli_option(add_option, rec)
+
+def option_parser():
+ return OptionParser(usage=USAGE)
+
+def main(args=sys.argv):
+ log = Log()
+ parser = option_parser()
+ if len(args) < 3:
+ print_help(parser, log)
+ return 1
+
+ input, output = check_command_line_options(parser, args, log)
+
+ from calibre.ebooks.conversion.plumber import Plumber
+
+ plumber = Plumber(input, output, log)
+ add_input_output_options(parser, plumber)
+ add_pipeline_options(parser, plumber)
+
+ opts = parser.parse_args(args)[0]
+ recommendations = [(n.dest, getattr(opts, n.dest),
+ OptionRecommendation.HIGH) \
+ for n in parser.options_iter()
+ if n.dest]
+ plumber.merge_ui_recommendations(recommendations)
+
+ plumber.run()
+
+ log(_('Output saved to'), ' ', plumber.output)
+
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/src/calibre/ebooks/conversion/plumber.py b/src/calibre/ebooks/conversion/plumber.py
index ac7490bd39..75a6687c4e 100644
--- a/src/calibre/ebooks/conversion/plumber.py
+++ b/src/calibre/ebooks/conversion/plumber.py
@@ -3,11 +3,29 @@ __license__ = 'GPL 3'
__copyright__ = '2009, Kovid Goyal '
__docformat__ = 'restructuredtext en'
+import os
from calibre.customize.conversion import OptionRecommendation
-from calibre.customize.ui import input_profiles
+from calibre.customize.ui import input_profiles, output_profiles, \
+ plugin_for_input_format, plugin_for_output_format
-pipeline_options = [
+class OptionValues(object):
+ pass
+
+class Plumber(object):
+
+ metadata_option_names = [
+ 'title', 'authors', 'title_sort', 'author_sort', 'cover', 'comments',
+ 'publisher', 'series', 'series_index', 'rating', 'isbn',
+ 'tags', 'book_producer', 'language'
+ ]
+
+ def __init__(self, input, output, log):
+ self.input = input
+ self.output = output
+ self.log = log
+
+ self.pipeline_options = [
OptionRecommendation(name='verbose',
recommended_value=0, level=OptionRecommendation.LOW,
@@ -16,7 +34,6 @@ OptionRecommendation(name='verbose',
'verbosity.')
),
-
OptionRecommendation(name='input_profile',
recommended_value='default', level=OptionRecommendation.LOW,
choices=[x.short_name for x in input_profiles()],
@@ -27,4 +44,193 @@ OptionRecommendation(name='input_profile',
'pixels).')
),
-]
\ No newline at end of file
+OptionRecommendation(name='output_profile',
+ recommended_value='default', level=OptionRecommendation.LOW,
+ choices=[x.short_name for x in output_profiles()],
+ help=_('Specify the output profile. The output profile '
+ 'tells the conversion system how to optimize the '
+ 'created document for the specified device. In some cases, '
+ 'an output profile is required to produce documents that '
+ 'will work on a device. For example EPUB on the SONY reader.'
+ )
+ ),
+
+OptionRecommendation(name='read_metadata_from_opf',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ short_switch='m',
+ help=_('Read metadata from the specified OPF file. Metadata read '
+ 'from this file will override any metadata in the source '
+ 'file.')
+ ),
+
+OptionRecommendation(name='title',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('Set the title.')),
+
+OptionRecommendation(name='authors',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('Set the authors. Multiple authors should be separated ')),
+
+OptionRecommendation(name='title_sort',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('The version of the title to be used for sorting. ')),
+
+OptionRecommendation(name='author_sort',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('String to be used when sorting by author. ')),
+
+OptionRecommendation(name='cover',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('Set the cover to the specified file.')),
+
+OptionRecommendation(name='comments',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('Set the ebook description.')),
+
+OptionRecommendation(name='publisher',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('Set the ebook publisher.')),
+
+OptionRecommendation(name='series',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('Set the series this ebook belongs to.')),
+
+OptionRecommendation(name='series_index',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('Set the index of the book in this series.')),
+
+OptionRecommendation(name='rating',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('Set the rating. Should be a number between 1 and 5.')),
+
+OptionRecommendation(name='isbn',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('Set the ISBN of the book.')),
+
+OptionRecommendation(name='tags',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('Set the tags for the book. Should be a comma separated list.')),
+
+OptionRecommendation(name='book_producer',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('Set the book producer.')),
+
+OptionRecommendation(name='language',
+ recommended_value=None, level=OptionRecommendation.LOW,
+ help=_('Set the language.')),
+]
+
+
+ input_fmt = os.path.splitext(input)[1]
+ if not input_fmt:
+ raise ValueError('Input file must have an extension')
+ input_fmt = input_fmt[1:].lower()
+
+ output_fmt = os.path.splitext(output)[1]
+ if not output_fmt:
+ output_fmt = '.oeb'
+ output_fmt = output_fmt[1:].lower()
+
+ self.input_plugin = plugin_for_input_format(input_fmt)
+ self.output_plugin = plugin_for_output_format(output_fmt)
+
+ if self.input_plugin is None:
+ raise ValueError('No plugin to handle input format: '+input_fmt)
+
+ if self.output_plugin is None:
+ raise ValueError('No plugin to handle output format: '+output_fmt)
+
+ self.input_fmt = input_fmt
+ self.output_fmt = output_fmt
+
+ self.input_options = self.input_plugin.options.union(
+ self.input_plugin.common_options)
+ self.output_options = self.output_plugin.options.union(
+ self.output_plugin.common_options)
+
+ self.merge_plugin_recommendations()
+
+ def get_option_by_name(self, name):
+ for group in (self.input_options, self.pipeline_options,
+ self.output_options):
+ for rec in group:
+ if rec.option == name:
+ return rec
+
+ def merge_plugin_recommendations(self):
+ for source in (self.input_plugin, self.output_plugin):
+ for name, val, level in source.recommendations:
+ rec = self.get_option_by_name(name)
+ if rec is not None and rec.level <= level:
+ rec.recommended_value = val
+
+ def merge_ui_recommendations(self, recommendations):
+ for name, val, level in recommendations:
+ rec = self.get_option_by_name(name)
+ if rec is not None and rec.level <= level and rec.level < rec.HIGH:
+ rec.recommended_value = val
+
+ def read_user_metadata(self):
+ from calibre.ebooks.metadata import MetaInformation, string_to_authors
+ from calibre.ebooks.metadata.opf2 import OPF
+ mi = MetaInformation(None, [])
+ if self.opts.read_metadata_from_opf is not None:
+ self.opts.read_metadata_from_opf = os.path.abspath(
+ self.opts.read_metadata_from_opf)
+ opf = OPF(open(self.opts.read_metadata_from_opf, 'rb'),
+ os.path.dirname(self.opts.read_metadata_from_opf))
+ mi = MetaInformation(opf)
+ for x in self.metadata_option_names:
+ val = getattr(self.opts, x, None)
+ if val is not None:
+ if x == 'authors':
+ val = string_to_authors(val)
+ elif x == 'tags':
+ val = [i.strip() for i in val.split(',')]
+ elif x in ('rating', 'series_index'):
+ val = float(val)
+ setattr(mi, x, val)
+ if mi.cover:
+ mi.cover_data = ('', open(mi.cover, 'rb').read())
+ mi.cover = None
+ self.user_metadata = mi
+
+
+ def setup_options(self):
+ self.opts = OptionValues()
+ for group in (self.input_options, self.pipeline_options,
+ self.output_options):
+ for rec in group:
+ setattr(self.opts, rec.option.name, rec.recommended_value)
+
+ for x in input_profiles():
+ if x.short_name == self.opts.input_profile:
+ self.opts.input_profile = x
+ break
+
+ for x in output_profiles():
+ if x.short_name == self.opts.output_profile:
+ self.opts.output_profile = x
+ break
+
+ self.read_user_metadata()
+
+ def run(self):
+ self.setup_options()
+ from calibre.customize.ui import run_plugins_on_preprocess
+ self.input = run_plugins_on_preprocess(self.input)
+
+ from calibre.ebooks.oeb.reader import OEBReader
+ from calibre.ebooks.oeb.base import OEBBook
+ parse_cache, accelerators = {}, {}
+
+ opfpath = self.input_plugin(open(self.input, 'rb'), self.opts,
+ self.input_fmt, parse_cache, self.log,
+ accelerators)
+
+ self.reader = OEBReader()
+ self.oeb = OEBBook(self.log, parse_cache=parse_cache)
+ self.reader(self.oeb, opfpath)
+
+
+
\ No newline at end of file
diff --git a/src/calibre/ebooks/epub/from_any.py b/src/calibre/ebooks/epub/from_any.py
index 9a8e251108..b3e5281525 100644
--- a/src/calibre/ebooks/epub/from_any.py
+++ b/src/calibre/ebooks/epub/from_any.py
@@ -12,7 +12,7 @@ from contextlib import nested
from calibre import extract, walk
from calibre.ebooks import DRMError
-from calibre.ebooks.epub import config as common_config, process_encryption
+from calibre.ebooks.epub import config as common_config
from calibre.ebooks.epub.from_html import convert as html2epub, find_html_index
from calibre.ptempfile import TemporaryDirectory
from calibre.ebooks.metadata import MetaInformation
diff --git a/src/calibre/ebooks/epub/from_html.py b/src/calibre/ebooks/epub/from_html.py
index ffe402538f..47d278a2b6 100644
--- a/src/calibre/ebooks/epub/from_html.py
+++ b/src/calibre/ebooks/epub/from_html.py
@@ -197,6 +197,9 @@ class HTMLProcessor(Processor, Rationalizer):
if not tag.text and not tag.get('src', False):
tag.getparent().remove(tag)
+ for tag in self.root.xpath('//form'):
+ tag.getparent().remove(tag)
+
if self.opts.linearize_tables:
for tag in self.root.xpath('//table | //tr | //th | //td'):
tag.tag = 'div'
diff --git a/src/calibre/ebooks/epub/input.py b/src/calibre/ebooks/epub/input.py
index 1b69424a9e..4c1cdbfcf5 100644
--- a/src/calibre/ebooks/epub/input.py
+++ b/src/calibre/ebooks/epub/input.py
@@ -51,7 +51,8 @@ class EPUBInput(InputFormatPlugin):
traceback.print_exc()
return False
- def convert(self, stream, options, file_ext, parse_cache, log):
+ def convert(self, stream, options, file_ext, parse_cache, log,
+ accelerators):
from calibre.utils.zipfile import ZipFile
from calibre import walk
from calibre.ebooks import DRMError
diff --git a/src/calibre/ebooks/epub/iterator.py b/src/calibre/ebooks/epub/iterator.py
index 82b9aa09ef..8e0936e708 100644
--- a/src/calibre/ebooks/epub/iterator.py
+++ b/src/calibre/ebooks/epub/iterator.py
@@ -118,10 +118,16 @@ class EbookIterator(object):
self.spine = [SpineItem(i.path) for i in self.opf.spine]
cover = self.opf.cover
- if os.path.splitext(self.pathtoebook)[1].lower() in ('.lit', '.mobi', '.prc') and cover:
+ if os.path.splitext(self.pathtoebook)[1].lower() in \
+ ('.lit', '.mobi', '.prc') and cover:
cfile = os.path.join(os.path.dirname(self.spine[0]), 'calibre_ei_cover.html')
open(cfile, 'wb').write(TITLEPAGE%cover)
self.spine[0:0] = [SpineItem(cfile)]
+
+ if self.opf.path_to_html_toc is not None and \
+ self.opf.path_to_html_toc not in self.spine:
+ self.spine.append(SpineItem(self.opf.path_to_html_toc))
+
sizes = [i.character_count for i in self.spine]
self.pages = [math.ceil(i/float(self.CHARACTERS_PER_PAGE)) for i in sizes]
diff --git a/src/calibre/ebooks/epub/pages.py b/src/calibre/ebooks/epub/pages.py
index 1ab5edde86..4737107a6c 100644
--- a/src/calibre/ebooks/epub/pages.py
+++ b/src/calibre/ebooks/epub/pages.py
@@ -11,7 +11,7 @@ __docformat__ = 'restructuredtext en'
import os, re
from itertools import count, chain
from calibre.ebooks.oeb.base import XHTML, XHTML_NS
-from calibre.ebooks.oeb.base import OEBBook, DirWriter
+from calibre.ebooks.oeb.base import OEBBook
from lxml import etree, html
from lxml.etree import XPath
diff --git a/src/calibre/ebooks/epub/split.py b/src/calibre/ebooks/epub/split.py
index 9814c40df5..c3099c1682 100644
--- a/src/calibre/ebooks/epub/split.py
+++ b/src/calibre/ebooks/epub/split.py
@@ -15,7 +15,7 @@ from lxml.cssselect import CSSSelector
from calibre.ebooks.metadata.opf2 import OPF
from calibre.ebooks.epub import tostring, rules
-from calibre import CurrentDir, LoggingInterface
+from calibre import CurrentDir
XPath = functools.partial(_XPath, namespaces={'re':'http://exslt.org/regular-expressions'})
content = functools.partial(os.path.join, 'content')
@@ -32,10 +32,9 @@ class SplitError(ValueError):
-class Splitter(LoggingInterface):
+class Splitter(object):
def __init__(self, path, opts, stylesheet_map, opf):
- LoggingInterface.__init__(self, logging.getLogger('htmlsplit'))
self.setup_cli_handler(opts.verbose)
self.path = path
self.always_remove = not opts.preserve_tag_structure or \
diff --git a/src/calibre/ebooks/html.py b/src/calibre/ebooks/html.py
index 710b544007..da64e58684 100644
--- a/src/calibre/ebooks/html.py
+++ b/src/calibre/ebooks/html.py
@@ -19,11 +19,10 @@ from lxml.html import HtmlElementClassLookup, HTMLParser as _HTMLParser, \
from lxml.etree import XPath
get_text = XPath("//text()")
-from calibre import LoggingInterface, unicode_path, entity_to_unicode
+from calibre import unicode_path, entity_to_unicode
from calibre.ebooks.chardet import xml_to_unicode, ENCODING_PATS
from calibre.utils.config import Config, StringConfig
from calibre.ebooks.metadata import MetaInformation
-from calibre.ebooks.metadata.meta import get_metadata
from calibre.ebooks.metadata.opf2 import OPF, OPFCreator
from calibre.ptempfile import PersistentTemporaryDirectory, PersistentTemporaryFile
from calibre.utils.zipfile import ZipFile
@@ -401,7 +400,7 @@ class PreProcessor(object):
html = rule[0].sub(rule[1], html)
return html
-class Parser(PreProcessor, LoggingInterface):
+class Parser(PreProcessor):
# SELF_CLOSING_TAGS = 'hr|br|link|img|meta|input|area|base|basefont'
# SELF_CLOSING_RULES = [re.compile(p[0]%SELF_CLOSING_TAGS, re.IGNORECASE) for p in
# [
@@ -412,7 +411,6 @@ class Parser(PreProcessor, LoggingInterface):
# ]
def __init__(self, htmlfile, opts, tdir, resource_map, htmlfiles, name='htmlparser'):
- LoggingInterface.__init__(self, logging.getLogger(name))
self.setup_cli_handler(opts.verbose)
self.htmlfile = htmlfile
self.opts = opts
@@ -859,7 +857,7 @@ class Processor(Parser):
except ValueError:
setting = ''
face = font.attrib.pop('face', None)
- if face is not None:
+ if face:
faces = []
for face in face.split(','):
face = face.strip()
@@ -1038,6 +1036,7 @@ def merge_metadata(htmlfile, opf, opts):
if opf:
mi = MetaInformation(opf)
elif htmlfile:
+ from calibre.ebooks.metadata.meta import get_metadata
try:
mi = get_metadata(open(htmlfile, 'rb'), 'html')
except:
diff --git a/src/calibre/ebooks/lrf/comic/convert_from.py b/src/calibre/ebooks/lrf/comic/convert_from.py
index 45254f7b87..50f5e1e72e 100755
--- a/src/calibre/ebooks/lrf/comic/convert_from.py
+++ b/src/calibre/ebooks/lrf/comic/convert_from.py
@@ -143,7 +143,8 @@ class PageProcessor(list):
MagickRotateImage(wand, pw, -90)
# 25 percent fuzzy trim?
- MagickTrimImage(wand, 25*65535/100)
+ if not self.opts.disable_trim:
+ MagickTrimImage(wand, 25*65535/100)
MagickSetImagePage(wand, 0,0,0,0) #Clear page after trim, like a "+repage"
# Do the Photoshop "Auto Levels" equivalent
if not self.opts.dont_normalize:
@@ -303,6 +304,9 @@ def config(defaults=None,output_format='lrf'):
help=_('Maintain picture aspect ratio. Default is to fill the screen.'))
c.add_opt('dont_sharpen', ['-s', '--disable-sharpen'], default=False,
help=_('Disable sharpening.'))
+ c.add_opt('disable_trim', ['--disable-trim'], default=False,
+ help=_('Disable trimming of comic pages. For some comics, '
+ 'trimming might remove content as well as borders.'))
c.add_opt('landscape', ['-l', '--landscape'], default=False,
help=_("Don't split landscape images into two portrait images"))
c.add_opt('wide', ['-w', '--wide-aspect'], default=False,
diff --git a/src/calibre/ebooks/lrf/html/convert_from.py b/src/calibre/ebooks/lrf/html/convert_from.py
index 2bd63d1d8f..9ec4857126 100644
--- a/src/calibre/ebooks/lrf/html/convert_from.py
+++ b/src/calibre/ebooks/lrf/html/convert_from.py
@@ -31,7 +31,7 @@ from calibre.ebooks.lrf import option_parser as lrf_option_parser
from calibre.ebooks import ConversionError
from calibre.ebooks.lrf.html.table import Table
from calibre import filename_to_utf8, setup_cli_handlers, __appname__, \
- fit_image, LoggingInterface, preferred_encoding
+ fit_image, preferred_encoding
from calibre.ptempfile import PersistentTemporaryFile
from calibre.devices.interface import Device
from calibre.ebooks.lrf.html.color_map import lrs_color
@@ -78,7 +78,7 @@ def tag_regex(tagname):
return dict(open=r'(?:<\s*%(t)s\s+[^<>]*?>|<\s*%(t)s\s*>)'%dict(t=tagname), \
close=r'\s*%(t)s\s*>'%dict(t=tagname))
-class HTMLConverter(object, LoggingInterface):
+class HTMLConverter(object):
SELECTOR_PAT = re.compile(r"([A-Za-z0-9\-\_\:\.]+[A-Za-z0-9\-\_\:\.\s\,]*)\s*\{([^\}]*)\}")
PAGE_BREAK_PAT = re.compile(r'page-break-(?:after|before)\s*:\s*(\w+)', re.IGNORECASE)
IGNORED_TAGS = (Comment, Declaration, ProcessingInstruction)
@@ -99,6 +99,10 @@ class HTMLConverter(object, LoggingInterface):
# Replace common line break patterns with line breaks
(re.compile(r'
( |\s)*
', re.IGNORECASE), lambda m: ' '),
+ # Replace empty headers with line breaks
+ (re.compile(r'( |\s)*',
+ re.IGNORECASE), lambda m: ' '),
+
# Replace entities
(re.compile(ur'&(\S+?);'), partial(entity_to_unicode,
exceptions=['lt', 'gt', 'amp'])),
@@ -209,7 +213,6 @@ class HTMLConverter(object, LoggingInterface):
'''
# Defaults for various formatting tags
object.__setattr__(self, 'options', options)
- LoggingInterface.__init__(self, logger)
self.fonts = fonts #: dict specifying font families to use
# Memory
self.scaled_images = {} #: Temporary files with scaled version of images
diff --git a/src/calibre/ebooks/lrf/lrs/convert_from.py b/src/calibre/ebooks/lrf/lrs/convert_from.py
index 495d9adb50..86a97aa70b 100644
--- a/src/calibre/ebooks/lrf/lrs/convert_from.py
+++ b/src/calibre/ebooks/lrf/lrs/convert_from.py
@@ -28,8 +28,9 @@ class LrsParser(object):
def __init__(self, stream, logger):
self.logger = logger
src = stream.read()
- self.soup = BeautifulStoneSoup(xml_to_unicode(src)[0],
- selfClosingTags=self.SELF_CLOSING_TAGS)
+ self.soup = BeautifulStoneSoup(xml_to_unicode(src)[0],
+ convertEntities=BeautifulStoneSoup.XML_ENTITIES,
+ selfClosingTags=self.SELF_CLOSING_TAGS)
self.objects = {}
for obj in self.soup.findAll(objid=True):
self.objects[obj['objid']] = obj
diff --git a/src/calibre/ebooks/lrf/meta.py b/src/calibre/ebooks/lrf/meta.py
index 322835f470..6ec87892d6 100644
--- a/src/calibre/ebooks/lrf/meta.py
+++ b/src/calibre/ebooks/lrf/meta.py
@@ -530,7 +530,7 @@ class LRFMetaFile(object):
""" See L{file.write} """
self._file.write(val)
- def objects(self):
+ def _objects(self):
self._file.seek(self.object_index_offset)
c = self.number_of_objects
while c > 0:
@@ -543,7 +543,7 @@ class LRFMetaFile(object):
def get_objects_by_type(self, type):
from calibre.ebooks.lrf.tags import Tag
objects = []
- for id, offset, size in self.objects():
+ for id, offset, size in self._objects():
self._file.seek(offset)
tag = Tag(self._file)
if tag.id == 0xF500:
@@ -554,7 +554,7 @@ class LRFMetaFile(object):
def get_object_by_id(self, tid):
from calibre.ebooks.lrf.tags import Tag
- for id, offset, size in self.objects():
+ for id, offset, size in self._objects():
self._file.seek(offset)
tag = Tag(self._file)
if tag.id == 0xF500:
diff --git a/src/calibre/ebooks/metadata/isbndb.py b/src/calibre/ebooks/metadata/isbndb.py
index 3cf5f92eaf..487a52335b 100644
--- a/src/calibre/ebooks/metadata/isbndb.py
+++ b/src/calibre/ebooks/metadata/isbndb.py
@@ -112,7 +112,8 @@ key is the account key you generate after signing up for a free account from isb
default=None, help=_('The title of the book to search for.'))
parser.add_option('-p', '--publisher', default=None, dest='publisher',
help=_('The publisher of the book to search for.'))
- parser.add_option('--verbose', default=False, action='store_true', help=_('Verbose processing'))
+ parser.add_option('-v', '--verbose', default=False,
+ action='store_true', help=_('Verbose processing'))
return parser
diff --git a/src/calibre/ebooks/metadata/lit.py b/src/calibre/ebooks/metadata/lit.py
index 7b3c873b38..071111e0f7 100644
--- a/src/calibre/ebooks/metadata/lit.py
+++ b/src/calibre/ebooks/metadata/lit.py
@@ -19,14 +19,22 @@ def get_metadata(stream):
for item in opf.iterguide():
if 'cover' not in item.get('type', '').lower():
continue
+ ctype = item.get('type')
href = item.get('href', '')
candidates = [href, href.replace('&', '%26')]
for item in litfile.manifest.values():
if item.path in candidates:
- covers.append(item.internal)
+ try:
+ covers.append((litfile.get_file('/data/'+item.internal),
+ ctype))
+ except:
+ pass
break
- covers = [litfile.get_file('/data/' + i) for i in covers]
- covers.sort(cmp=lambda x, y:cmp(len(x), len(y)))
- mi.cover_data = ('jpg', covers[-1])
+ covers.sort(cmp=lambda x, y:cmp(len(x[0]), len(y[0])), reverse=True)
+ idx = 0
+ if len(covers) > 1:
+ if covers[1][1] == covers[1][0]+'-standard':
+ idx = 1
+ mi.cover_data = ('jpg', covers[idx][0])
return mi
diff --git a/src/calibre/ebooks/metadata/meta.py b/src/calibre/ebooks/metadata/meta.py
index 43053a43b9..de7ac8eeea 100644
--- a/src/calibre/ebooks/metadata/meta.py
+++ b/src/calibre/ebooks/metadata/meta.py
@@ -15,7 +15,7 @@ _METADATA_PRIORITIES = [
'html', 'htm', 'xhtml', 'xhtm',
'rtf', 'fb2', 'pdf', 'prc', 'odt',
'epub', 'lit', 'lrx', 'lrf', 'mobi',
- 'rb', 'imp'
+ 'rb', 'imp', 'azw'
]
# The priorities for loading metadata from different file types
@@ -41,7 +41,9 @@ def metadata_from_formats(formats):
for path, ext in zip(formats, extensions):
with open(path, 'rb') as stream:
try:
- mi.smart_update(get_metadata(stream, stream_type=ext, use_libprs_metadata=True))
+ newmi = get_metadata(stream, stream_type=ext,
+ use_libprs_metadata=True)
+ mi.smart_update(newmi)
except:
continue
if getattr(mi, 'application_id', None) is not None:
@@ -58,7 +60,7 @@ def get_metadata(stream, stream_type='lrf', use_libprs_metadata=False):
if stream_type: stream_type = stream_type.lower()
if stream_type in ('html', 'html', 'xhtml', 'xhtm', 'xml'):
stream_type = 'html'
- if stream_type in ('mobi', 'prc'):
+ if stream_type in ('mobi', 'prc', 'azw'):
stream_type = 'mobi'
if stream_type in ('odt', 'ods', 'odp', 'odg', 'odf'):
stream_type = 'odt'
diff --git a/src/calibre/ebooks/metadata/opf2.py b/src/calibre/ebooks/metadata/opf2.py
index 0cec3e979c..74b6804845 100644
--- a/src/calibre/ebooks/metadata/opf2.py
+++ b/src/calibre/ebooks/metadata/opf2.py
@@ -444,6 +444,7 @@ class OPF(object):
if not hasattr(stream, 'read'):
stream = open(stream, 'rb')
self.basedir = self.base_dir = basedir
+ self.path_to_html_toc = None
raw, self.encoding = xml_to_unicode(stream.read(), strip_encoding_pats=True, resolve_entities=True)
raw = raw[raw.find('<'):]
self.root = etree.fromstring(raw, self.PARSER)
@@ -495,6 +496,7 @@ class OPF(object):
if f:
self.toc.read_ncx_toc(f[0])
else:
+ self.path_to_html_toc = toc
self.toc.read_html_toc(toc)
except:
pass
diff --git a/src/calibre/ebooks/metadata/topaz.py b/src/calibre/ebooks/metadata/topaz.py
new file mode 100644
index 0000000000..55eb9d6e69
--- /dev/null
+++ b/src/calibre/ebooks/metadata/topaz.py
@@ -0,0 +1,40 @@
+from __future__ import with_statement
+__license__ = 'GPL 3'
+__copyright__ = '2009, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+''' Read metadata from Amazon's topaz format '''
+
+def read_record(raw, name):
+ idx = raw.find(name)
+ if idx > -1:
+ length = ord(raw[idx+len(name)])
+ return raw[idx+len(name)+1:idx+len(name)+1+length]
+
+def get_metadata(stream):
+ raw = stream.read(8*1024)
+ if not raw.startswith('TPZ'):
+ raise ValueError('Not a Topaz file')
+ first = raw.find('metadata')
+ if first < 0:
+ raise ValueError('Invalid Topaz file')
+ second = raw.find('metadata', first+10)
+ if second < 0:
+ raise ValueError('Invalid Topaz file')
+ raw = raw[second:second+1000]
+ authors = read_record(raw, 'Authors')
+ if authors:
+ authors = authors.decode('utf-8', 'replace').split(';')
+ else:
+ authors = [_('Unknown')]
+ title = read_record(raw, 'Title')
+ if title:
+ title = title.decode('utf-8', 'replace')
+ else:
+ raise ValueError('No metadata in file')
+ from calibre.ebooks.metadata import MetaInformation
+ return MetaInformation(title, authors)
+
+if __name__ == '__main__':
+ import sys
+ print get_metadata(open(sys.argv[1], 'rb'))
\ No newline at end of file
diff --git a/src/calibre/ebooks/mobi/input.py b/src/calibre/ebooks/mobi/input.py
index 1ce9950677..b3400c54e1 100644
--- a/src/calibre/ebooks/mobi/input.py
+++ b/src/calibre/ebooks/mobi/input.py
@@ -3,8 +3,6 @@ __license__ = 'GPL 3'
__copyright__ = '2009, Kovid Goyal '
__docformat__ = 'restructuredtext en'
-import os
-
from calibre.customize.conversion import InputFormatPlugin
class MOBIInput(InputFormatPlugin):
@@ -14,16 +12,19 @@ class MOBIInput(InputFormatPlugin):
description = 'Convert MOBI files (.mobi, .prc, .azw) to HTML'
file_types = set(['mobi', 'prc', 'azw'])
- def convert(self, stream, options, file_ext, parse_cache, log):
+ def convert(self, stream, options, file_ext, parse_cache, log,
+ accelerators):
from calibre.ebooks.mobi.reader import MobiReader
mr = MobiReader(stream, log, options.input_encoding,
options.debug_input)
- mr.extract_content(output_dir=os.getcwdu(), parse_cache)
+ mr.extract_content('.', parse_cache)
raw = parse_cache.get('calibre_raw_mobi_markup', False)
if raw:
if isinstance(raw, unicode):
raw = raw.encode('utf-8')
open('debug-raw.html', 'wb').write(raw)
-
- return mr.created_opf_path
-
+ for f, root in parse_cache.items():
+ if '.' in f:
+ accelerators[f] = {'pagebreaks':root.xpath(
+ '//div[@class="mbp_pagebreak"]')}
+ return mr.created_opf_path
\ No newline at end of file
diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py
index a72eb7716a..3b9085adca 100644
--- a/src/calibre/ebooks/mobi/reader.py
+++ b/src/calibre/ebooks/mobi/reader.py
@@ -92,6 +92,8 @@ class BookHeader(object):
self.sublanguage = 'NEUTRAL'
self.exth_flag, self.exth = 0, None
self.ancient = True
+ self.first_image_index = -1
+ self.mobi_version = 1
else:
self.ancient = False
self.doctype = raw[16:20]
@@ -312,7 +314,7 @@ class MobiReader(object):
mobi_version = self.book_header.mobi_version
for i, tag in enumerate(root.iter(etree.Element)):
if tag.tag in ('country-region', 'place', 'placetype', 'placename',
- 'state', 'city'):
+ 'state', 'city', 'street', 'address'):
tag.tag = 'span'
for key in tag.attrib.keys():
tag.attrib.pop(key)
@@ -389,7 +391,13 @@ class MobiReader(object):
opf.cover = 'images/%05d.jpg'%(self.book_header.exth.cover_offset+1)
elif mi.cover is not None:
opf.cover = mi.cover
- manifest = [(htmlfile, 'text/x-oeb1-document'),
+ else:
+ opf.cover = 'images/%05d.jpg'%1
+ if not os.path.exists(os.path.join(os.path.dirname(htmlfile),
+ *opf.cover.split('/'))):
+ opf.cover = None
+
+ manifest = [(htmlfile, 'text/x-oeb1-document'),
(os.path.abspath('styles.css'), 'text/css')]
bp = os.path.dirname(htmlfile)
for i in getattr(self, 'image_names', []):
@@ -531,7 +539,7 @@ class MobiReader(object):
os.makedirs(output_dir)
image_index = 0
self.image_names = []
- start = self.book_header.first_image_index
+ start = getattr(self.book_header, 'first_image_index', -1)
if start > self.num_sections or start < 0:
# BAEN PRC files have bad headers
start=0
diff --git a/src/calibre/ebooks/mobi/writer.py b/src/calibre/ebooks/mobi/writer.py
index fdabfaa618..d3ab12489c 100644
--- a/src/calibre/ebooks/mobi/writer.py
+++ b/src/calibre/ebooks/mobi/writer.py
@@ -9,7 +9,6 @@ __copyright__ = '2008, Marshall T. Vandegrift '
import sys
import os
from struct import pack
-import functools
import time
import random
from cStringIO import StringIO
@@ -18,13 +17,12 @@ from itertools import izip, count
from collections import defaultdict
from urlparse import urldefrag
import logging
-from lxml import etree
from PIL import Image
from calibre.ebooks.oeb.base import XML_NS, XHTML, XHTML_NS, OEB_DOCS, \
OEB_RASTER_IMAGES
-from calibre.ebooks.oeb.base import xpath, barename, namespace, prefixname
+from calibre.ebooks.oeb.base import namespace, prefixname
from calibre.ebooks.oeb.base import urlnormalize
-from calibre.ebooks.oeb.base import Logger, OEBBook
+from calibre.ebooks.oeb.base import OEBBook
from calibre.ebooks.oeb.profile import Context
from calibre.ebooks.oeb.transforms.flatcss import CSSFlattener
from calibre.ebooks.oeb.transforms.rasterize import SVGRasterizer
@@ -33,7 +31,7 @@ from calibre.ebooks.oeb.transforms.htmltoc import HTMLTOCAdder
from calibre.ebooks.oeb.transforms.manglecase import CaseMangler
from calibre.ebooks.mobi.palmdoc import compress_doc
from calibre.ebooks.mobi.langcodes import iana2mobi
-from calibre.ebooks.mobi.mobiml import MBP_NS, MBP, MobiMLizer
+from calibre.ebooks.mobi.mobiml import MBP_NS, MobiMLizer
from calibre.customize.ui import run_plugins_on_postprocess
from calibre.utils.config import Config, StringConfig
@@ -162,7 +160,7 @@ class Serializer(object):
hrefs = self.oeb.manifest.hrefs
buffer.write('')
for ref in self.oeb.guide.values():
- path, frag = urldefrag(ref.href)
+ path = urldefrag(ref.href)[0]
if hrefs[path].media_type not in OEB_DOCS:
continue
buffer.write(''
+__docformat__ = 'restructuredtext en'
+
+from calibre.customize.conversion import OutputFormatPlugin
+
+class OEBOutput(OutputFormatPlugin):
+
+ name = 'OEB Output'
+ author = 'Kovid Goyal'
+ file_type = 'oeb'
+
+
+ def convert(self, oeb_book, input_plugin, options, parse_cache, log):
+ pass
+
diff --git a/src/calibre/ebooks/oeb/reader.py b/src/calibre/ebooks/oeb/reader.py
index 0fce1c2b0d..dbafa5afac 100644
--- a/src/calibre/ebooks/oeb/reader.py
+++ b/src/calibre/ebooks/oeb/reader.py
@@ -19,9 +19,9 @@ from calibre.ebooks.oeb.base import OEB_DOCS, OEB_STYLES, OEB_IMAGES, \
PAGE_MAP_MIME, JPEG_MIME, NCX_MIME, SVG_MIME
from calibre.ebooks.oeb.base import XMLDECL_RE, COLLAPSE_RE, CSSURL_RE, \
ENTITY_RE, LINK_SELECTORS, MS_COVER_TYPE
-from calibre.ebooks.oeb.base import namespace, barename, qname, XPath, xpath
-from calibre.ebooks.oeb.base import urlnormalize, xml2str
-from calibre.ebooks.oeb.base import OEBError, OEBBook, DirContainer
+from calibre.ebooks.oeb.base import namespace, barename, qname, XPath, xpath, \
+ urlnormalize, BINARY_MIME, \
+ OEBError, OEBBook, DirContainer
from calibre.ebooks.oeb.writer import OEBWriter
from calibre.ebooks.oeb.entitydefs import ENTITYDEFS
from calibre.ebooks.metadata.epub import CoverRenderer
@@ -45,9 +45,6 @@ class OEBReader(object):
TRANSFORMS = []
"""List of transforms to apply to content read with this Reader."""
- def __init__(self):
- return
-
@classmethod
def config(cls, cfg):
"""Add any book-reading options to the :class:`Config` object
@@ -65,7 +62,7 @@ class OEBReader(object):
:param:`oeb`.
"""
self.oeb = oeb
- self.logger = oeb.logger
+ self.logger = self.log = oeb.logger
oeb.container = self.Container(path)
opf = self._read_opf()
self._all_from_opf(opf)
diff --git a/src/calibre/ebooks/oeb/stylizer.py b/src/calibre/ebooks/oeb/stylizer.py
index 64ed2a45e8..3b5c3e19d0 100644
--- a/src/calibre/ebooks/oeb/stylizer.py
+++ b/src/calibre/ebooks/oeb/stylizer.py
@@ -19,7 +19,7 @@ from cssutils.css import CSSStyleRule, CSSPageRule, CSSStyleDeclaration, \
CSSValueList, cssproperties
from cssutils.profiles import profiles as cssprofiles
from lxml import etree
-from lxml.cssselect import css_to_xpath, ExpressionError
+from lxml.cssselect import css_to_xpath, ExpressionError, SelectorSyntaxError
from calibre.ebooks.oeb.base import XHTML, XHTML_NS, CSS_MIME, OEB_STYLES
from calibre.ebooks.oeb.base import XPNSMAP, xpath, urlnormalize
from calibre.ebooks.oeb.profile import PROFILES
@@ -159,7 +159,9 @@ class Stylizer(object):
for _, _, cssdict, text, _ in rules:
try:
selector = CSSSelector(text)
- except ExpressionError:
+ except (AssertionError, ExpressionError, etree.XPathSyntaxError,\
+ NameError, # gets thrown on OS X instead of SelectorSyntaxError
+ SelectorSyntaxError):
continue
for elem in selector(tree):
self.style(elem)._update_cssdict(cssdict)
diff --git a/src/calibre/ebooks/oeb/transforms/flatcss.py b/src/calibre/ebooks/oeb/transforms/flatcss.py
index ede2a027ed..9833b3b4d0 100644
--- a/src/calibre/ebooks/oeb/transforms/flatcss.py
+++ b/src/calibre/ebooks/oeb/transforms/flatcss.py
@@ -6,18 +6,14 @@ from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2008, Marshall T. Vandegrift '
-import sys
-import os
import re
import operator
import math
-from itertools import chain
from collections import defaultdict
from lxml import etree
from calibre.ebooks.oeb.base import XHTML, XHTML_NS
from calibre.ebooks.oeb.base import CSS_MIME, OEB_STYLES
from calibre.ebooks.oeb.base import namespace, barename
-from calibre.ebooks.oeb.base import OEBBook
from calibre.ebooks.oeb.stylizer import Stylizer
COLLAPSE = re.compile(r'[ \t\r\n\v]+')
diff --git a/src/calibre/ebooks/oeb/transforms/htmltoc.py b/src/calibre/ebooks/oeb/transforms/htmltoc.py
index 0040f39c14..7f3391e72b 100644
--- a/src/calibre/ebooks/oeb/transforms/htmltoc.py
+++ b/src/calibre/ebooks/oeb/transforms/htmltoc.py
@@ -6,9 +6,6 @@ from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2008, Marshall T. Vandegrift '
-import sys
-import os
-from lxml import etree
from calibre.ebooks.oeb.base import XML, XHTML, XHTML_NS
from calibre.ebooks.oeb.base import XHTML_MIME, CSS_MIME
from calibre.ebooks.oeb.base import element
@@ -66,6 +63,8 @@ class HTMLTOCAdder(object):
def __call__(self, oeb, context):
if 'toc' in oeb.guide:
return
+ if not getattr(getattr(oeb, 'toc', False), 'nodes', False):
+ return
oeb.logger.info('Generating in-line TOC...')
title = self.title or oeb.translate(DEFAULT_TITLE)
style = self.style
diff --git a/src/calibre/ebooks/oeb/transforms/manglecase.py b/src/calibre/ebooks/oeb/transforms/manglecase.py
index c819475a4d..4b852db6c4 100644
--- a/src/calibre/ebooks/oeb/transforms/manglecase.py
+++ b/src/calibre/ebooks/oeb/transforms/manglecase.py
@@ -6,13 +6,6 @@ from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2008, Marshall T. Vandegrift '
-import sys
-import os
-import re
-import operator
-import math
-from itertools import chain
-from collections import defaultdict
from lxml import etree
from calibre.ebooks.oeb.base import XHTML, XHTML_NS
from calibre.ebooks.oeb.base import CSS_MIME
diff --git a/src/calibre/ebooks/oeb/transforms/rasterize.py b/src/calibre/ebooks/oeb/transforms/rasterize.py
index aef5c2c98b..2d86fe63b5 100644
--- a/src/calibre/ebooks/oeb/transforms/rasterize.py
+++ b/src/calibre/ebooks/oeb/transforms/rasterize.py
@@ -6,7 +6,6 @@ from __future__ import with_statement
__license__ = 'GPL v3'
__copyright__ = '2008, Marshall T. Vandegrift '
-import sys
import os
from urlparse import urldefrag
import base64
@@ -20,9 +19,9 @@ from PyQt4.QtGui import QImage
from PyQt4.QtGui import QPainter
from PyQt4.QtSvg import QSvgRenderer
from PyQt4.QtGui import QApplication
-from calibre.ebooks.oeb.base import XHTML_NS, XHTML, SVG_NS, SVG, XLINK
-from calibre.ebooks.oeb.base import SVG_MIME, PNG_MIME, JPEG_MIME
-from calibre.ebooks.oeb.base import xml2str, xpath, namespace, barename
+from calibre.ebooks.oeb.base import XHTML, XLINK
+from calibre.ebooks.oeb.base import SVG_MIME, PNG_MIME
+from calibre.ebooks.oeb.base import xml2str, xpath
from calibre.ebooks.oeb.base import urlnormalize
from calibre.ebooks.oeb.stylizer import Stylizer
@@ -88,7 +87,7 @@ class SVGRasterizer(object):
hrefs = self.oeb.manifest.hrefs
for elem in xpath(svg, '//svg:*[@xl:href]'):
href = urlnormalize(elem.attrib[XLINK('href')])
- path, frag = urldefrag(href)
+ path = urldefrag(href)[0]
if not path:
continue
abshref = item.abshref(path)
diff --git a/src/calibre/gui2/add.py b/src/calibre/gui2/add.py
index 2f4ba281fd..948cf4f3af 100644
--- a/src/calibre/gui2/add.py
+++ b/src/calibre/gui2/add.py
@@ -224,7 +224,10 @@ class AddRecursive(Add):
files = _('
Books with the same title as the following already '
'exist in the database. Add them anyway?
')
for mi in self.duplicates:
- files += '
'+mi[0].title+'
\n'
+ title = mi[0].title
+ if not isinstance(title, unicode):
+ title = title.decode(preferred_encoding, 'replace')
+ files += '
'+title+'
\n'
d = WarningDialog (_('Duplicates found!'),
_('Duplicates found!'),
files+'
', parent=self._parent)
diff --git a/src/calibre/gui2/dialogs/comicconf.ui b/src/calibre/gui2/dialogs/comicconf.ui
index 36af85764a..acab125d57 100644
--- a/src/calibre/gui2/dialogs/comicconf.ui
+++ b/src/calibre/gui2/dialogs/comicconf.ui
@@ -1,154 +1,162 @@
-
+
+Dialog
-
-
+
+ 00646
- 468
+ 503
-
+ Dialog
-
-
+
+ :/images/convert.svg:/images/convert.svg
-
-
-
-
+
+
+
+ &Title:
-
+ opt_title
-
-
+
+
-
-
-
+
+
+ &Author(s):
-
+ opt_author
-
-
+
+
-
-
-
+
+
+ &Number of Colors:
-
+ opt_colors
-
-
-
+
+
+ 8
-
+ 3200000
-
+ 8
-
-
-
+
+
+ &Profile:
-
+ opt_profile
-
-
+
+
-
-
-
+
+
+ Disable &normalize
-
-
-
+
+
+ Keep &aspect ratio
-
-
-
+
+
+ Disable &Sharpening
-
-
-
+
+
+ &Landscape
-
-
-
+
+
+ Don't so&rt
-
-
-
+
+
+ Qt::Horizontal
-
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
+
+
+ &Right to left
-
-
-
+
+
+ De&speckle
-
-
-
+
+
+ &Wide
+
+
+
+ Disable &Trimming
+
+
+
-
+
@@ -157,11 +165,11 @@
Dialogaccept()
-
+ 248254
-
+ 157274
@@ -173,11 +181,11 @@
Dialogreject()
-
+ 316260
-
+ 286274
diff --git a/src/calibre/gui2/dialogs/config.py b/src/calibre/gui2/dialogs/config.py
index 5353f24544..9958ce53fa 100644
--- a/src/calibre/gui2/dialogs/config.py
+++ b/src/calibre/gui2/dialogs/config.py
@@ -196,7 +196,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
self.language.addItem(language_codes[lang], QVariant(lang))
else:
lang = 'en'
- self.language.addItem('English', 'en')
+ self.language.addItem('English', QVariant('en'))
items = [(l, language_codes[l]) for l in translations.keys() \
if l != lang]
if lang != 'en':
diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py
index 519314782a..694fec21f3 100644
--- a/src/calibre/gui2/dialogs/metadata_single.py
+++ b/src/calibre/gui2/dialogs/metadata_single.py
@@ -346,19 +346,22 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
pix = QPixmap()
pix.loadFromData(cover_data)
if pix.isNull():
- error_dialog(self.window, "The cover is not a valid picture").exec_()
+ error_dialog(self.window, _('Bad cover'),
+ _('The cover is not a valid picture')).exec_()
else:
self.cover.setPixmap(pix)
self.cover_changed = True
self.cpixmap = pix
except LibraryThingError, err:
- error_dialog(self, _('Could not fetch cover'), _('Could not fetch cover. ')+repr(err)).exec_()
+ error_dialog(self, _('Cannot fetch cover'),
+ _('Could not fetch cover. ')+repr(err)).exec_()
finally:
self.fetch_cover_button.setEnabled(True)
self.unsetCursor()
else:
- error_dialog(self, _('Cannot fetch cover'), _('You must specify the ISBN identifier for this book.')).exec_()
+ error_dialog(self, _('Cannot fetch cover'),
+ _('You must specify the ISBN identifier for this book.')).exec_()
def fetch_metadata(self):
diff --git a/src/calibre/gui2/dialogs/metadata_single.ui b/src/calibre/gui2/dialogs/metadata_single.ui
index c693cf3eea..8a5fc4f99d 100644
--- a/src/calibre/gui2/dialogs/metadata_single.ui
+++ b/src/calibre/gui2/dialogs/metadata_single.ui
@@ -1,7 +1,8 @@
-
+
+MetadataSingleDialog
-
-
+
+ 00
@@ -9,36 +10,36 @@
750
-
-
+
+ 00
-
+ Edit Meta Information
-
-
+
+ :/images/edit_input.svg:/images/edit_input.svg
-
+ true
-
+ true
-
+
-
-
+
+ QFrame::NoFrame
-
+ true
-
-
+
+ 00
@@ -46,65 +47,65 @@
710
-
-
+
+ 0
-
-
+
+ 800665
-
+
-
-
+
+ Qt::Horizontal
-
-
+
+
-
-
+
+ Meta information
-
-
-
-
+
+
+
+ &Title:
-
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+ title
-
-
-
+
+
+ Change the title of this book
-
-
-
+
+
+ Swap the author and title
-
+ ...
-
-
+
+ :/images/swap.svg:/images/swap.svg
-
+ 1616
@@ -112,305 +113,305 @@
-
-
-
+
+
+ &Author(s):
-
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+ authors
-
-
-
+
+
+ Author S&ort:
-
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+ author_sort
-
-
+
+
-
-
+
+ Specify how the author(s) of this book should be sorted. For example Charles Dickens should be sorted as Dickens, Charles.
-
-
+
+ Automatically create the author sort entry based on the current author entry
-
+ ...
-
-
+
+ :/images/auto_author_sort.svg:/images/auto_author_sort.svg
-
-
-
+
+
+ &Rating:
-
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+ rating
-
-
-
+
+
+ Rating of this book. 0-5 stars
-
+ Rating of this book. 0-5 stars
-
+ QAbstractSpinBox::PlusMinus
-
+ stars
-
+ 5
-
-
-
+
+
+ &Publisher:
-
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+ publisher
-
-
-
+
+
+ Ta&gs:
-
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+ tags
-
-
+
+
-
-
- Tags categorize the book. This is particularly useful while searching. <br><br>They can be any words or phrases, separated by commas.
+
+
+ Tags categorize the book. This is particularly useful while searching. <br><br>They can be any words or phrases, separated by commas.
-
-
+
+ Open Tag Editor
-
+ Open Tag Editor
-
-
+
+ :/images/chapters.svg:/images/chapters.svg
-
-
-
+
+
+ &Series:
-
+ Qt::PlainText
-
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+ series
-
-
-
+
+
+ 5
-
-
-
+
+
+ 00
-
+ List of known series. You can add new series.
-
+ List of known series. You can add new series.
-
+ true
-
+ QComboBox::InsertAlphabetically
-
+ QComboBox::AdjustToContents
-
-
+
+ Remove unused series (Series that have no books)
-
+ ...
-
-
+
+ :/images/trash.svg:/images/trash.svg
-
-
-
+
+
+ false
-
+ Series index.
-
+ Series index.
-
+ Book
-
+ 1
-
+ 10000
-
-
-
+
+
+ IS&BN:
-
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+ isbn
-
-
+
+
-
-
-
+
+
+ true
-
-
+
+
-
-
+
+ Comments
-
-
-
+
+
+
-
-
- Fetch metadata from server
+
+
+ &Fetch metadata from server
-
-
+
+
-
-
-
+
+
+ 00
-
+ Available Formats
-
+
-
-
-
-
-
+
+
+
+
+ 00
-
+ 16777215130
-
+ 6464
@@ -418,19 +419,19 @@
-
-
-
+
+
+ Add a new format for this book to the database
-
+ ...
-
-
+
+ :/images/add_book.svg:/images/add_book.svg
-
+ 3232
@@ -438,19 +439,19 @@
-
-
-
+
+
+ Remove the selected formats for this book from the database.
-
+ ...
-
-
+
+ :/images/trash.svg:/images/trash.svg
-
+ 3232
@@ -458,19 +459,19 @@
-
-
-
+
+
+ Set the cover for the book from the selected format
-
+ ...
-
-
+
+ :/images/book.svg:/images/book.svg
-
+ 3232
@@ -485,96 +486,96 @@
-
-
-
+
+
+ 010
-
+ Book Cover
-
+
-
-
-
+
+
+ 00
-
+
-
- :/images/book.svg
+
+ :/images/book.svg
-
+ true
-
-
+
+ 6
-
+ QLayout::SetMaximumSize
-
+ 0
-
-
+
+ Change &cover image:
-
+ cover_path
-
-
+
+ 6
-
+ 0
-
-
+
+ true
-
-
+
+ Browse for an image to use as the cover of this book.
-
+ ...
-
-
+
+ :/images/document_open.svg:/images/document_open.svg
-
-
+
+ Reset cover to default
-
+ ...
-
-
+
+ :/images/trash.svg:/images/trash.svg
@@ -584,21 +585,21 @@
-
+
-
-
- Fetch cover image from server
+
+
+ Fetch &cover image from server
-
-
+
+ Change the username and/or password for your account at LibraryThing.com
-
- Change password
+
+ Change &password
@@ -619,11 +620,11 @@
-
-
+
+ Qt::Horizontal
-
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
@@ -666,7 +667,7 @@
button_box
-
+
@@ -675,11 +676,11 @@
MetadataSingleDialogaccept()
-
+ 261710
-
+ 157274
@@ -691,11 +692,11 @@
MetadataSingleDialogreject()
-
+ 329710
-
+ 286274
diff --git a/src/calibre/gui2/images/news/nytimes_sub.png b/src/calibre/gui2/images/news/nytimes_sub.png
new file mode 100644
index 0000000000..17282300fe
Binary files /dev/null and b/src/calibre/gui2/images/news/nytimes_sub.png differ
diff --git a/src/calibre/gui2/images/news/politico.png b/src/calibre/gui2/images/news/politico.png
new file mode 100644
index 0000000000..6d5f0d055b
Binary files /dev/null and b/src/calibre/gui2/images/news/politico.png differ
diff --git a/src/calibre/gui2/images/news/wikinews_en.png b/src/calibre/gui2/images/news/wikinews_en.png
new file mode 100644
index 0000000000..489061b923
Binary files /dev/null and b/src/calibre/gui2/images/news/wikinews_en.png differ
diff --git a/src/calibre/gui2/library.py b/src/calibre/gui2/library.py
index c0f8eac796..bfa1ec501f 100644
--- a/src/calibre/gui2/library.py
+++ b/src/calibre/gui2/library.py
@@ -94,6 +94,7 @@ class DateDelegate(QStyledItemDelegate):
def createEditor(self, parent, option, index):
qde = QStyledItemDelegate.createEditor(self, parent, option, index)
qde.setDisplayFormat('MM/dd/yyyy')
+ qde.setMinimumDate(QDate(100,1,1))
return qde
class BooksModel(QAbstractTableModel):
@@ -420,6 +421,7 @@ class BooksModel(QAbstractTableModel):
def get_preferred_formats(self, rows, formats, paths=False,
set_metadata=False, specific_format=None):
ans = []
+ need_auto = []
if specific_format is not None:
formats = [specific_format.lower()]
for row in (row.row() for row in rows):
@@ -444,8 +446,9 @@ class BooksModel(QAbstractTableModel):
pt.close() if paths else pt.seek(0)
ans.append(pt)
else:
+ need_auto.append(row)
ans.append(None)
- return ans
+ return ans, need_auto
def id(self, row):
return self.db.id(getattr(row, 'row', lambda:row)())
@@ -1069,3 +1072,4 @@ class SearchBox(QLineEdit):
self.emit(SIGNAL('search(PyQt_PyObject, PyQt_PyObject)'), txt, False)
self.end(False)
self.initial_state = False
+
diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py
index 163a9d8bd0..f040eac362 100644
--- a/src/calibre/gui2/main.py
+++ b/src/calibre/gui2/main.py
@@ -38,7 +38,8 @@ from calibre.gui2.dialogs.metadata_bulk import MetadataBulkDialog
from calibre.gui2.dialogs.jobs import JobsDialog
from calibre.gui2.dialogs.conversion_error import ConversionErrorDialog
from calibre.gui2.tools import convert_single_ebook, convert_bulk_ebooks, \
- set_conversion_defaults, fetch_scheduled_recipe
+ set_conversion_defaults, fetch_scheduled_recipe, \
+ auto_convert_ebook
from calibre.gui2.dialogs.config import ConfigDialog
from calibre.gui2.dialogs.search import SearchDialog
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
@@ -237,6 +238,7 @@ class Main(MainWindow, Ui_MainWindow):
QObject.connect(self.config_button, SIGNAL('clicked(bool)'), self.do_config)
self.connect(self.preferences_action, SIGNAL('triggered(bool)'), self.do_config)
+ self.connect(self.action_preferences, SIGNAL('triggered(bool)'), self.do_config)
QObject.connect(self.advanced_search_button, SIGNAL('clicked(bool)'), self.do_advanced_search)
####################### Library view ########################
@@ -818,7 +820,8 @@ class Main(MainWindow, Ui_MainWindow):
rows = self.library_view.selectionModel().selectedRows()
previous = self.library_view.currentIndex()
if not rows or len(rows) == 0:
- d = error_dialog(self, _('Cannot edit metadata'), _('No books selected'))
+ d = error_dialog(self, _('Cannot edit metadata'),
+ _('No books selected'))
d.exec_()
return
@@ -904,9 +907,8 @@ class Main(MainWindow, Ui_MainWindow):
on_card = config['send_to_storage_card_by_default']
self.sync_to_device(on_card, False, specific_format=fmt)
-
- def sync_to_device(self, on_card, delete_from_library, specific_format=None):
- rows = self.library_view.selectionModel().selectedRows()
+ def sync_to_device(self, on_card, delete_from_library, specific_format=None, send_rows=None, auto_convert=True):
+ rows = self.library_view.selectionModel().selectedRows() if send_rows is None else send_rows
if not self.device_manager or not rows or len(rows) == 0:
return
ids = iter(self.library_view.model().id(r) for r in rows)
@@ -917,7 +919,7 @@ class Main(MainWindow, Ui_MainWindow):
if cdata:
mi['cover'] = self.cover_to_thumbnail(cdata)
metadata, full_metadata = iter(metadata), iter(full_metadata)
- _files = self.library_view.model().get_preferred_formats(rows,
+ _files, _auto_rows = self.library_view.model().get_preferred_formats(rows,
self.device_manager.device_class.FORMATS,
paths=True, set_metadata=True,
specific_format=specific_format)
@@ -952,10 +954,29 @@ class Main(MainWindow, Ui_MainWindow):
remove = remove_ids if delete_from_library else []
self.upload_books(gf, names, good, on_card, memory=(_files, remove))
self.status_bar.showMessage(_('Sending books to device.'), 5000)
+
if bad:
+ if specific_format is None:
+ if 'epub' in self.device_manager.device_class.FORMATS:
+ format = 'epub'
+ elif 'mobi' in self.device_manager.device_class.FORMATS or 'prc' in self.device_manager.device_class.FORMATS:
+ format = 'mobi'
+ elif 'lrf' in self.device_manager.device_class.FORMATS:
+ format = 'lrf'
+ else:
+ format = specific_format
+
+ if format not in ('epub', 'mobi'):
+ auto_convert = False
+
bad = '\n'.join('
%s
'%(i,) for i in bad)
- d = warning_dialog(self, _('No suitable formats'),
- _('Could not upload the following books to the device, as no suitable formats were found:
%s
')%(bad,))
+ if auto_convert:
+ d = info_dialog(self, _('No suitable formats'),
+ _('Auto converting the following books before uploading to the device:
%s
')%(bad,))
+ self.auto_convert(_auto_rows, on_card, format)
+ else:
+ d = warning_dialog(self, _('No suitable formats'),
+ _('Could not upload the following books to the device, as no suitable formats were found:
%s
')%(bad,))
d.exec_()
@@ -1048,6 +1069,32 @@ class Main(MainWindow, Ui_MainWindow):
############################### Convert ####################################
+ def auto_convert(self, rows, on_card, format):
+ previous = self.library_view.currentIndex()
+
+ comics, others = [], []
+ db = self.library_view.model().db
+ for r in rows:
+ formats = db.formats(r)
+ if not formats: continue
+ formats = formats.lower().split(',')
+ if 'cbr' in formats or 'cbz' in formats:
+ comics.append(r)
+ else:
+ others.append(r)
+
+ jobs, changed, bad_rows = auto_convert_ebook(format, self, self.library_view.model().db, comics, others)
+ for func, args, desc, fmt, id, temp_files in jobs:
+ if id not in bad_rows:
+ job = self.job_manager.run_job(Dispatcher(self.book_auto_converted),
+ func, args=args, description=desc)
+ self.conversion_jobs[job] = (temp_files, fmt, id, on_card)
+
+ if changed:
+ self.library_view.model().refresh_rows(rows)
+ current = self.library_view.currentIndex()
+ self.library_view.model().current_changed(current, previous)
+
def get_books_for_conversion(self):
rows = [r.row() for r in self.library_view.selectionModel().selectedRows()]
if not rows or len(rows) == 0:
@@ -1108,7 +1155,32 @@ class Main(MainWindow, Ui_MainWindow):
self.library_view.model().refresh_rows(rows)
current = self.library_view.currentIndex()
self.library_view.model().current_changed(current, previous)
-
+
+ def book_auto_converted(self, job):
+ temp_files, fmt, book_id, on_card = self.conversion_jobs.pop(job)
+ try:
+ if job.exception is not None:
+ self.job_exception(job)
+ return
+ data = open(temp_files[-1].name, 'rb')
+ self.library_view.model().db.add_format(book_id, fmt, data, index_is_id=True)
+ data.close()
+ self.status_bar.showMessage(job.description + (' completed'), 2000)
+ finally:
+ for f in temp_files:
+ try:
+ if os.path.exists(f.name):
+ os.remove(f.name)
+ except:
+ pass
+ self.tags_view.recount()
+ if self.current_view() is self.library_view:
+ current = self.library_view.currentIndex()
+ self.library_view.model().current_changed(current, QModelIndex())
+
+ r = self.library_view.model().index(self.library_view.model().db.row(book_id), 0)
+ self.sync_to_device(on_card, False, specific_format=fmt, send_rows=[r], auto_convert=False)
+
def book_converted(self, job):
temp_files, fmt, book_id = self.conversion_jobs.pop(job)
try:
@@ -1149,10 +1221,14 @@ class Main(MainWindow, Ui_MainWindow):
if ext in config['internally_viewed_formats']:
if ext == 'LRF':
args = ['lrfviewer', name]
- self.job_manager.server.run_free_job('lrfviewer', kwdargs=dict(args=args))
+ self.job_manager.server.run_free_job('lrfviewer',
+ kwdargs=dict(args=args))
else:
args = ['ebook-viewer', name]
- self.job_manager.server.run_free_job('ebook-viewer', kwdargs=dict(args=args))
+ if isosx:
+ args.append('--raise-window')
+ self.job_manager.server.run_free_job('ebook-viewer',
+ kwdargs=dict(args=args))
else:
QDesktopServices.openUrl(QUrl('file:'+name))#launch(name)
time.sleep(5) # User feedback
@@ -1247,7 +1323,7 @@ class Main(MainWindow, Ui_MainWindow):
############################### Do config ##################################
- def do_config(self):
+ def do_config(self, *args):
if self.job_manager.has_jobs():
d = error_dialog(self, _('Cannot configure'), _('Cannot configure while there are running jobs.'))
d.exec_()
@@ -1406,7 +1482,15 @@ class Main(MainWindow, Ui_MainWindow):
dir = os.path.expanduser('~/Library')
self.library_path = os.path.abspath(dir)
if not os.path.exists(self.library_path):
- os.makedirs(self.library_path)
+ try:
+ os.makedirs(self.library_path)
+ except:
+ self.library_path = os.path.expanduser('~/Library')
+ error_dialog(self, _('Invalid library location'),
+ _('Could not access %s. Using %s as the library.')%
+ (repr(self.library_path), repr(self.library_path))
+ ).exec_()
+ os.makedirs(self.library_path)
def read_settings(self):
@@ -1610,3 +1694,4 @@ if __name__ == '__main__':
log = open(logfile).read().decode('utf-8', 'ignore')
d = QErrorMessage('Error:%s Traceback: %sLog: '%(unicode(err), unicode(tb), log))
d.exec_()
+
diff --git a/src/calibre/gui2/main.ui b/src/calibre/gui2/main.ui
index ad8c450d1a..c4bea8d886 100644
--- a/src/calibre/gui2/main.ui
+++ b/src/calibre/gui2/main.ui
@@ -1,149 +1,150 @@
-
+
+Kovid GoyalMainWindow
-
-
+
+ 00
- 865
+ 1012822
-
-
+
+ 00
-
+ Qt::NoContextMenu
-
+ __appname__
-
-
+
+ :/library:/library
-
-
-
-
+
+
+
+
-
-
-
+
+
+ 00
-
+ 16777215100
-
+ Qt::ScrollBarAlwaysOff
-
+ Qt::ScrollBarAsNeeded
-
+ true
-
+ true
-
+ 4040
-
+ QListView::Static
-
+ QListView::LeftToRight
-
+ 17590
-
+ QListView::ListMode
-
+ true
-
-
+
+ PointingHandCursor
-
+ ...
-
-
+
+ :/images/donate.svg:/images/donate.svg
-
+ 6464
-
+ true
-
+
-
-
-
+
+
+ 00
-
+ 1677721590
-
+
-
+ Qt::RichText
-
+ true
-
+
-
-
+
+ Output:
-
-
+
+ Set the output format that is used when converting ebooks and downloading news
@@ -154,99 +155,99 @@
-
-
-
+
+
+ 6
-
+ 0
-
-
+
+ Advanced search
-
+ ...
-
-
+
+ :/images/search.svg:/images/search.svg
-
+ Alt+S
-
-
+
+ &Search:
-
+ search
-
-
+
+ true
-
-
+
+ 10
-
+ false
-
- Search the list of books by title or author<br><br>Words separated by spaces are ANDed
+
+ Search the list of books by title or author<br><br>Words separated by spaces are ANDed
-
- Search the list of books by title, author, publisher, tags and comments<br><br>Words separated by spaces are ANDed
+
+ Search the list of books by title, author, publisher, tags and comments<br><br>Words separated by spaces are ANDed
-
+ false
-
+
-
+ true
-
-
+
+ Reset Quick Search
-
+ ...
-
-
+
+ :/images/clear_left.svg:/images/clear_left.svg
-
-
+
+ Qt::Vertical
-
+ Qt::Horizontal
-
+ 2020
@@ -255,77 +256,77 @@
-
-
+
+ Configuration
-
+ ...
-
-
+
+ :/images/config.svg:/images/config.svg
-
-
-
-
+
+
+
+ 100100
-
+ 0
-
-
+
+
-
+
-
+
-
-
+
+ Match any
-
+ false
-
-
+
+ Match all
-
+ true
-
-
+
+ Sort by &popularity
-
-
+
+ true
-
+ true
-
+ true
-
+ true
@@ -333,35 +334,35 @@
-
-
-
+
+
+ 10010
-
+ true
-
+ true
-
+ false
-
+ QAbstractItemView::DragDrop
-
+ true
-
+ QAbstractItemView::SelectRows
-
+ false
-
+ false
@@ -370,76 +371,76 @@
-
-
-
-
-
-
+
+
+
+
+
+ 10010
-
+ true
-
+ true
-
+ false
-
+ QAbstractItemView::DragDrop
-
+ true
-
+ QAbstractItemView::SelectRows
-
+ false
-
+ false
-
-
-
-
-
-
+
+
+
+
+
+ 1010
-
+ true
-
+ true
-
+ false
-
+ QAbstractItemView::DragDrop
-
+ true
-
+ QAbstractItemView::SelectRows
-
+ false
-
+ false
@@ -450,221 +451,237 @@
-
-
+
+ 00
-
+ Qt::PreventContextMenu
-
+ false
-
+ Qt::Horizontal
-
+ 4848
-
+ Qt::ToolButtonTextUnderIcon
-
+ TopToolBarArea
-
+ false
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+ true
-
-
-
+
+
+ :/images/add_book.svg:/images/add_book.svg
-
+ Add books
-
+ A
-
+ false
-
-
-
+
+
+ :/images/trash.svg:/images/trash.svg
-
+ Remove books
-
+ Remove books
-
+ Del
-
-
-
+
+
+ :/images/edit_input.svg:/images/edit_input.svg
-
+ Edit meta information
-
+ E
-
+ false
-
-
+
+ false
-
-
+
+ :/images/sync.svg:/images/sync.svg
-
+ Send to device
-
-
-
+
+
+ :/images/save.svg:/images/save.svg
-
+ Save to disk
-
+ S
-
-
-
+
+
+ :/images/news.svg:/images/news.svg
-
+ Fetch news
-
+ F
-
-
-
+
+
+ :/images/convert.svg:/images/convert.svg
-
+ Convert E-books
-
+ C
-
-
-
+
+
+ :/images/view.svg:/images/view.svg
-
+ View
-
+ V
-
-
-
+
+
+ :/images/document_open.svg:/images/document_open.svg
-
+ Open containing folder
-
-
-
+
+
+ :/images/dialog_information.svg:/images/dialog_information.svg
-
+ Show book details
-
-
-
+
+
+ :/images/user_profile.svg:/images/user_profile.svg
-
+ Books by same author
-
-
-
+
+
+ :/images/books_in_series.svg:/images/books_in_series.svg
-
+ Books in this series
-
-
-
+
+
+ :/images/publisher.png:/images/publisher.png
-
+ Books by this publisher
-
-
-
+
+
+ :/images/tags.svg:/images/tags.svg
-
+ Books with the same tags
-
-
-
+
+
+ :/images/book.svg:/images/book.svg
-
+ Send specific format to device
+
+
+
+ :/images/config.svg:/images/config.svg
+
+
+ Preferences
+
+
+ Configure calibre
+
+
+ Ctrl+P
+
+
@@ -694,7 +711,7 @@
-
+
@@ -703,11 +720,11 @@
searchclear()
-
+ 787215
-
+ 755213
diff --git a/src/calibre/gui2/tools.py b/src/calibre/gui2/tools.py
index aca2da74e2..0bf78ffaa7 100644
--- a/src/calibre/gui2/tools.py
+++ b/src/calibre/gui2/tools.py
@@ -18,7 +18,9 @@ from calibre.gui2 import warning_dialog
from calibre.ptempfile import PersistentTemporaryFile
from calibre.ebooks.lrf import preferred_source_formats as LRF_PREFERRED_SOURCE_FORMATS
from calibre.ebooks.metadata.opf import OPFCreator
-from calibre.ebooks.epub.from_any import SOURCE_FORMATS as EPUB_PREFERRED_SOURCE_FORMATS
+from calibre.ebooks.epub.from_any import SOURCE_FORMATS as EPUB_PREFERRED_SOURCE_FORMATS, config as epubconfig
+from calibre.ebooks.mobi.from_any import config as mobiconfig
+from calibre.ebooks.lrf.comic.convert_from import config as comicconfig
def get_dialog(fmt):
return {
@@ -26,6 +28,122 @@ def get_dialog(fmt):
'mobi':MOBIConvert,
}[fmt]
+def get_config(fmt):
+ return {
+ 'epub':epubconfig,
+ 'mobi':mobiconfig,
+ }[fmt]
+
+def auto_convert(fmt, parent, db, comics, others):
+ changed = False
+ jobs = []
+
+ total = sum(map(len, (others, comics)))
+ if total == 0:
+ return
+ parent.status_bar.showMessage(_('Starting auto conversion of %d books')%total, 2000)
+
+ i = 0
+ bad_rows = []
+
+ for i, row in enumerate(others+comics):
+ row_id = db.id(row)
+
+ if row in others:
+ temp_files = []
+
+ data = None
+ for _fmt in EPUB_PREFERRED_SOURCE_FORMATS:
+ try:
+ data = db.format(row, _fmt.upper())
+ if data is not None:
+ break
+ except:
+ continue
+ if data is None:
+ bad_rows.append(row)
+ continue
+
+ defaults = db.conversion_options(db.id(row), fmt)
+ defaults = defaults if defaults else ''
+ options = get_config(fmt)(defaults=defaults).parse()
+
+ mi = db.get_metadata(row)
+ opf = OPFCreator(os.getcwdu(), mi)
+ opf_file = PersistentTemporaryFile('.opf')
+ opf.render(opf_file)
+ opf_file.close()
+ pt = PersistentTemporaryFile('.'+_fmt.lower())
+ pt.write(data)
+ pt.close()
+ of = PersistentTemporaryFile('.'+fmt)
+ of.close()
+ cover = db.cover(row)
+ cf = None
+ if cover:
+ cf = PersistentTemporaryFile('.jpeg')
+ cf.write(cover)
+ cf.close()
+ options.cover = cf.name
+ options.output = of.name
+ options.from_opf = opf_file.name
+ args = [options, pt.name]
+ desc = _('Auto convert book %d of %d (%s)')%(i+1, total, repr(mi.title))
+ temp_files = [cf] if cf is not None else []
+ temp_files.extend([opf_file, pt, of])
+ jobs.append(('any2'+fmt, args, desc, fmt.upper(), row_id, temp_files))
+
+ changed = True
+ else:
+ defaults = db.conversion_options(db.id(row), fmt)
+ defaults = defaults if defaults else ''
+ options = comicconfig(defaults=defaults).parse()
+
+ mi = db.get_metadata(row)
+ if mi.title:
+ options.title = mi.title
+ if mi.authors:
+ options.author = ','.join(mi.authors)
+ data = None
+ for _fmt in ['cbz', 'cbr']:
+ try:
+ data = db.format(row, _fmt.upper())
+ if data is not None:
+ break
+ except:
+ continue
+
+ if data is None:
+ bad_rows.append(row)
+ continue
+
+ pt = PersistentTemporaryFile('.'+_fmt.lower())
+ pt.write(data)
+ pt.close()
+ of = PersistentTemporaryFile('.'+fmt)
+ of.close()
+ setattr(options, 'output', of.name)
+ options.verbose = 1
+ args = [pt.name, options]
+ desc = _('Convert book %d of %d (%s)')%(i+1, total, repr(mi.title))
+ jobs.append(('comic2'+fmt, args, desc, fmt.upper(), row_id, [pt, of]))
+
+ changed = True
+
+ if bad_rows:
+ res = []
+ for row in bad_rows:
+ title = db.title(row)
+ res.append('
%s
'%title)
+
+ msg = _('
Could not convert %d of %d books, because no suitable source format was found.
%s
')%(len(res), total, '\n'.join(res))
+ warning_dialog(parent, _('Could not convert some books'), msg).exec_()
+
+ return jobs, changed, bad_rows
+
+def auto_convert_lrf(fmt, parent, db, comics, others):
+ pass
+
def convert_single(fmt, parent, db, comics, others):
changed = False
jobs = []
@@ -386,6 +504,12 @@ def fetch_scheduled_recipe(recipe, script):
args.append(script)
return 'feeds2'+fmt, [args], _('Fetch news from ')+recipe.title, fmt.upper(), [pt]
+def auto_convert_ebook(*args):
+ fmt = args[0] if args[0] else 'epub'
+ if fmt == 'lrf':
+ return auto_convert_lrf()
+ elif fmt in ('epub', 'mobi'):
+ return auto_convert(*args)
def convert_single_ebook(*args):
fmt = prefs['output_format'].lower()
@@ -410,4 +534,5 @@ def set_conversion_defaults(comic, parent, db):
def fetch_news(data):
fmt = prefs['output_format'].lower()
- return _fetch_news(data, fmt)
\ No newline at end of file
+ return _fetch_news(data, fmt)
+
diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py
index b694562d97..161bc69aad 100644
--- a/src/calibre/gui2/viewer/documentview.py
+++ b/src/calibre/gui2/viewer/documentview.py
@@ -450,7 +450,9 @@ class DocumentView(QWebView):
self.manager.scrolled(self.scroll_fraction)
def wheel_event(self, down=True):
- QWebView.wheelEvent(self, QWheelEvent(QPoint(100, 100), (-120 if down else 120), Qt.NoButton, Qt.NoModifier))
+ QWebView.wheelEvent(self,
+ QWheelEvent(QPoint(100, 100), (-120 if down else 120),
+ Qt.NoButton, Qt.NoModifier))
def next_page(self):
if self.document.at_bottom:
@@ -538,6 +540,26 @@ class DocumentView(QWebView):
self.next_page()
elif key in [Qt.Key_PageUp, Qt.Key_Backspace, Qt.Key_Up]:
self.previous_page()
+ elif key in [Qt.Key_Home]:
+ if event.modifiers() & Qt.ControlModifier:
+ if self.manager is not None:
+ self.manager.goto_start()
+ else:
+ self.scroll_to(0)
+ elif key in [Qt.Key_End]:
+ if event.modifiers() & Qt.ControlModifier:
+ if self.manager is not None:
+ self.manager.goto_end()
+ else:
+ self.scroll_to(1)
+ elif key in [Qt.Key_J]:
+ self.wheel_event()
+ elif key in [Qt.Key_K]:
+ self.wheel_event(down=False)
+ elif key in [Qt.Key_H]:
+ self.scroll_by(x=-15)
+ elif key in [Qt.Key_L]:
+ self.scroll_by(x=15)
else:
return QWebView.keyPressEvent(self, event)
diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py
index c6277ff902..3738ba9114 100644
--- a/src/calibre/gui2/viewer/main.py
+++ b/src/calibre/gui2/viewer/main.py
@@ -341,6 +341,12 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
pos = self.history.forward()
if pos is not None:
self.goto_page(pos)
+
+ def goto_start(self):
+ self.goto_page(1)
+
+ def goto_end(self):
+ self.goto_page(self.pos.maximum())
def goto_page(self, new_page):
if self.current_page is not None:
@@ -604,6 +610,10 @@ def config(defaults=None):
c = Config('viewer', desc)
else:
c = StringConfig(defaults, desc)
+
+ c.add_opt('raise_window', ['--raise-window'], default=False,
+ help=_('If specified, viewer window will try to come to the '
+ 'front when started.'))
return c
def option_parser():
@@ -617,7 +627,7 @@ View an ebook.
def main(args=sys.argv):
parser = option_parser()
- args = parser.parse_args(args)[-1]
+ opts, args = parser.parse_args(args)
pid = os.fork() if False and islinux else -1
if pid <= 0:
app = Application(args)
@@ -627,6 +637,8 @@ def main(args=sys.argv):
main = EbookViewer(args[1] if len(args) > 1 else None)
sys.excepthook = main.unhandled_exception
main.show()
+ if opts.raise_window:
+ main.raise_()
with main:
return app.exec_()
return 0
diff --git a/src/calibre/library/cli.py b/src/calibre/library/cli.py
index ceae3094c4..08a18fbe60 100644
--- a/src/calibre/library/cli.py
+++ b/src/calibre/library/cli.py
@@ -244,7 +244,10 @@ def do_add(db, paths, one_book_per_directory, recurse, add_duplicates):
if os.path.isdir(path):
dirs.append(path)
else:
- files.append(path)
+ if os.path.exists(path):
+ files.append(path)
+ else:
+ print path, 'not found'
formats, metadata = [], []
for book in files:
@@ -261,12 +264,14 @@ def do_add(db, paths, one_book_per_directory, recurse, add_duplicates):
formats.append(format)
metadata.append(mi)
-
- file_duplicates = db.add_books(files, formats, metadata, add_duplicates=add_duplicates)
- if not file_duplicates[0]:
- file_duplicates = []
- else:
- file_duplicates = file_duplicates[0]
+
+ file_duplicates = []
+ if files:
+ file_duplicates = db.add_books(files, formats, metadata,
+ add_duplicates=add_duplicates)
+ if file_duplicates:
+ file_duplicates = file_duplicates[0]
+
dir_dups = []
for dir in dirs:
@@ -286,7 +291,9 @@ def do_add(db, paths, one_book_per_directory, recurse, add_duplicates):
db.import_book(mi, formats)
else:
if dir_dups or file_duplicates:
- print >>sys.stderr, _('The following books were not added as they already exist in the database (see --duplicates option):')
+ print >>sys.stderr, _('The following books were not added as '
+ 'they already exist in the database '
+ '(see --duplicates option):')
for mi, formats in dir_dups:
title = mi.title
if isinstance(title, unicode):
diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py
index f8b63f1124..28f861ae3a 100644
--- a/src/calibre/library/database2.py
+++ b/src/calibre/library/database2.py
@@ -15,7 +15,7 @@ from PyQt4.QtCore import QCoreApplication, QThread, QReadWriteLock
from PyQt4.QtGui import QApplication, QImage
__app = None
-from calibre.library import title_sort
+from calibre.ebooks.metadata import title_sort
from calibre.library.database import LibraryDatabase
from calibre.library.sqlite import connect, IntegrityError
from calibre.utils.search_query_parser import SearchQueryParser
@@ -1567,3 +1567,4 @@ books_series_link feeds
break
return duplicates
+
diff --git a/src/calibre/library/server.py b/src/calibre/library/server.py
index ba81151517..4ba6253819 100644
--- a/src/calibre/library/server.py
+++ b/src/calibre/library/server.py
@@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
HTTP server for remote access to the calibre database.
'''
-import sys, textwrap, mimetypes, operator, os, re, logging
+import sys, textwrap, operator, os, re, logging
from itertools import repeat
from logging.handlers import RotatingFileHandler
from datetime import datetime
@@ -18,11 +18,13 @@ from PyQt4.Qt import QImage, QApplication, QByteArray, Qt, QBuffer
from calibre.constants import __version__, __appname__
from calibre.utils.genshi.template import MarkupTemplate
-from calibre import fit_image
+from calibre import fit_image, guess_type
from calibre.resources import jquery, server_resources, build_time
from calibre.library import server_config as config
from calibre.library.database2 import LibraryDatabase2, FIELD_MAP
from calibre.utils.config import config_dir
+from calibre.utils.mdns import publish as publish_zeroconf, \
+ stop_server as stop_zeroconf
build_time = datetime.strptime(build_time, '%d %m %Y %H%M%S')
server_resources['jquery.js'] = jquery
@@ -77,7 +79,7 @@ class LibraryServer(object):
urn:calibre:${record[FM['id']]}${authors}${record[FM['timestamp']].strftime('%Y-%m-%dT%H:%M:%S+00:00')}
-
+
@@ -171,11 +173,14 @@ class LibraryServer(object):
try:
cherrypy.engine.start()
self.is_running = True
+ publish_zeroconf('Books in calibre', '_stanza._tcp',
+ self.opts.port, {'path':'/stanza'})
cherrypy.engine.block()
except Exception, e:
self.exception = e
finally:
self.is_running = False
+ stop_zeroconf()
def exit(self):
cherrypy.engine.exit()
@@ -218,7 +223,7 @@ class LibraryServer(object):
fmt = self.db.format(id, format, index_is_id=True, as_file=True, mode='rb')
if fmt is None:
raise cherrypy.HTTPError(404, 'book: %d does not have format: %s'%(id, format))
- mt = mimetypes.guess_type('dummy.'+format.lower())[0]
+ mt = guess_type('dummy.'+format.lower())[0]
if mt is None:
mt = 'application/octet-stream'
cherrypy.response.headers['Content-Type'] = mt
@@ -258,8 +263,9 @@ class LibraryServer(object):
for record in iter(self.db):
r = record[FIELD_MAP['formats']]
r = r.upper() if r else ''
- if 'EPUB' in r:
- authors = ' & '.join([i.replace('|', ',') for i in record[FIELD_MAP['authors']].split(',')])
+ if 'EPUB' in r or 'PDB' in r:
+ authors = ' & '.join([i.replace('|', ',') for i in
+ record[FIELD_MAP['authors']].split(',')])
extra = []
rating = record[FIELD_MAP['rating']]
if rating > 0:
@@ -270,12 +276,18 @@ class LibraryServer(object):
extra.append('TAGS: %s '%', '.join(tags.split(',')))
series = record[FIELD_MAP['series']]
if series:
- extra.append('SERIES: %s [%d] '%(series, record[FIELD_MAP['series_index']]))
- books.append(self.STANZA_ENTRY.generate(authors=authors,
- record=record, FM=FIELD_MAP,
- port=self.opts.port,
- extra = ''.join(extra),
- ).render('xml').decode('utf8'))
+ extra.append('SERIES: %s [%d] '%(series,
+ record[FIELD_MAP['series_index']]))
+ fmt = 'epub' if 'EPUB' in r else 'pdb'
+ mimetype = guess_type('dummy.'+fmt)[0]
+ books.append(self.STANZA_ENTRY.generate(
+ authors=authors,
+ record=record, FM=FIELD_MAP,
+ port=self.opts.port,
+ extra = ''.join(extra),
+ mimetype=mimetype,
+ fmt=fmt,
+ ).render('xml').decode('utf8'))
updated = self.db.last_modified()
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
@@ -325,7 +337,11 @@ class LibraryServer(object):
@expose
def index(self, **kwargs):
'The / URL'
- return self.static('index.html')
+ stanza = cherrypy.request.headers.get('Stanza-Device-Name', 919)
+ if stanza == 919:
+ return self.static('index.html')
+ return self.stanza()
+
@expose
def get(self, what, id):
diff --git a/src/calibre/linux.py b/src/calibre/linux.py
index 427b41ca5f..e08222ed3a 100644
--- a/src/calibre/linux.py
+++ b/src/calibre/linux.py
@@ -1,9 +1,8 @@
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal '
''' Post installation script for linux '''
-import sys, os, re, shutil
+import sys, os, shutil
from subprocess import check_call, call
-from tempfile import NamedTemporaryFile
from calibre import __version__, __appname__
from calibre.devices import devices
@@ -18,15 +17,8 @@ entry_points = {
'console_scripts': [ \
'ebook-device = calibre.devices.prs500.cli.main:main',
'ebook-meta = calibre.ebooks.metadata.cli:main',
- 'txt2lrf = calibre.ebooks.lrf.txt.convert_from:main',
- 'html2lrf = calibre.ebooks.lrf.html.convert_from:main',
- 'html2oeb = calibre.ebooks.html:main',
- 'html2epub = calibre.ebooks.epub.from_html:main',
- 'odt2oeb = calibre.ebooks.odt.to_oeb:main',
+ 'ebook-convert = calibre.ebooks.conversion.cli:main',
'markdown-calibre = calibre.ebooks.markdown.markdown:main',
- 'lit2lrf = calibre.ebooks.lrf.lit.convert_from:main',
- 'epub2lrf = calibre.ebooks.lrf.epub.convert_from:main',
- 'rtf2lrf = calibre.ebooks.lrf.rtf.convert_from:main',
'web2disk = calibre.web.fetch.simple:main',
'feeds2disk = calibre.web.feeds.main:main',
'calibre-server = calibre.library.server:main',
@@ -34,22 +26,10 @@ entry_points = {
'feeds2epub = calibre.ebooks.epub.from_feeds:main',
'feeds2mobi = calibre.ebooks.mobi.from_feeds:main',
'web2lrf = calibre.ebooks.lrf.web.convert_from:main',
- 'pdf2lrf = calibre.ebooks.lrf.pdf.convert_from:main',
- 'mobi2lrf = calibre.ebooks.lrf.mobi.convert_from:main',
- 'fb22lrf = calibre.ebooks.lrf.fb2.convert_from:main',
- 'any2lrf = calibre.ebooks.lrf.any.convert_from:main',
- 'any2epub = calibre.ebooks.epub.from_any:main',
- 'any2lit = calibre.ebooks.lit.from_any:main',
- 'any2mobi = calibre.ebooks.mobi.from_any:main',
'lrf2lrs = calibre.ebooks.lrf.lrfparser:main',
'lrs2lrf = calibre.ebooks.lrf.lrs.convert_from:main',
- 'pdfreflow = calibre.ebooks.lrf.pdf.reflow:main',
'isbndb = calibre.ebooks.metadata.isbndb:main',
'librarything = calibre.ebooks.metadata.library_thing:main',
- 'mobi2oeb = calibre.ebooks.mobi.reader:main',
- 'oeb2mobi = calibre.ebooks.mobi.writer:main',
- 'lit2oeb = calibre.ebooks.lit.reader:main',
- 'oeb2lit = calibre.ebooks.lit.writer:main',
'comic2lrf = calibre.ebooks.lrf.comic.convert_from:main',
'comic2epub = calibre.ebooks.epub.from_comic:main',
'comic2mobi = calibre.ebooks.mobi.from_comic:main',
@@ -60,7 +40,6 @@ entry_points = {
'calibre-parallel = calibre.parallel:main',
'calibre-customize = calibre.customize.ui:main',
'pdftrim = calibre.ebooks.pdf.pdftrim:main' ,
- 'any2pdf = calibre.ebooks.pdf.from_any:main',
],
'gui_scripts' : [
__appname__+' = calibre.gui2.main:main',
@@ -171,25 +150,16 @@ def setup_completion(fatal_errors):
from calibre.ebooks.lrf.lrfparser import option_parser as lrf2lrsop
from calibre.gui2.lrf_renderer.main import option_parser as lrfviewerop
from calibre.ebooks.lrf.pdf.reflow import option_parser as pdfhtmlop
- from calibre.ebooks.mobi.reader import option_parser as mobioeb
- from calibre.ebooks.lit.reader import option_parser as lit2oeb
from calibre.web.feeds.main import option_parser as feeds2disk
from calibre.web.feeds.recipes import titles as feed_titles
from calibre.ebooks.lrf.feeds.convert_from import option_parser as feeds2lrf
from calibre.ebooks.lrf.comic.convert_from import option_parser as comicop
- from calibre.ebooks.epub.from_html import option_parser as html2epub
- from calibre.ebooks.html import option_parser as html2oeb
- from calibre.ebooks.odt.to_oeb import option_parser as odt2oeb
from calibre.ebooks.epub.from_feeds import option_parser as feeds2epub
from calibre.ebooks.mobi.from_feeds import option_parser as feeds2mobi
- from calibre.ebooks.epub.from_any import option_parser as any2epub
- from calibre.ebooks.lit.from_any import option_parser as any2lit
from calibre.ebooks.epub.from_comic import option_parser as comic2epub
- from calibre.ebooks.mobi.from_any import option_parser as any2mobi
- from calibre.ebooks.mobi.writer import option_parser as oeb2mobi
- from calibre.gui2.main import option_parser as guiop
+ from calibre.gui2.main import option_parser as guiop
any_formats = ['epub', 'htm', 'html', 'xhtml', 'xhtm', 'rar', 'zip',
- 'txt', 'lit', 'rtf', 'pdf', 'prc', 'mobi', 'fb2', 'odt']
+ 'txt', 'lit', 'rtf', 'pdf', 'prc', 'mobi', 'fb2', 'odt']
f = open_file('/etc/bash_completion.d/libprs500')
f.close()
os.remove(f.name)
@@ -209,16 +179,10 @@ def setup_completion(fatal_errors):
f.write(opts_and_exts('pdf2lrf', htmlop, ['pdf']))
f.write(opts_and_exts('any2lrf', htmlop, any_formats))
f.write(opts_and_exts('calibre', guiop, any_formats))
- f.write(opts_and_exts('any2epub', any2epub, any_formats))
- f.write(opts_and_exts('any2lit', any2lit, any_formats))
- f.write(opts_and_exts('any2mobi', any2mobi, any_formats))
- f.write(opts_and_exts('oeb2mobi', oeb2mobi, ['opf']))
f.write(opts_and_exts('lrf2lrs', lrf2lrsop, ['lrf']))
f.write(opts_and_exts('ebook-meta', metaop, list(meta_filetypes())))
f.write(opts_and_exts('lrfviewer', lrfviewerop, ['lrf']))
f.write(opts_and_exts('pdfrelow', pdfhtmlop, ['pdf']))
- f.write(opts_and_exts('mobi2oeb', mobioeb, ['mobi', 'prc']))
- 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('comic2mobi', comic2epub, ['cbz', 'cbr']))
@@ -227,9 +191,6 @@ def setup_completion(fatal_errors):
f.write(opts_and_words('feeds2lrf', feeds2lrf, feed_titles))
f.write(opts_and_words('feeds2epub', feeds2epub, feed_titles))
f.write(opts_and_words('feeds2mobi', feeds2mobi, feed_titles))
- f.write(opts_and_exts('html2epub', html2epub, ['html', 'htm', 'xhtm', 'xhtml', 'opf']))
- f.write(opts_and_exts('html2oeb', html2oeb, ['html', 'htm', 'xhtm', 'xhtml']))
- f.write(opts_and_exts('odt2oeb', odt2oeb, ['odt']))
f.write('''
_prs500_ls()
{
@@ -392,43 +353,27 @@ def option_parser():
help='Save a manifest of all installed files to the specified location')
return parser
-def install_man_pages(fatal_errors):
- from bz2 import compress
- import subprocess
+def install_man_pages(fatal_errors, use_destdir=False):
+ from calibre.utils.help2man import create_man_page
+ prefix = os.environ.get('DESTDIR', '/') if use_destdir else '/'
+ manpath = os.path.join(prefix, 'usr/share/man/man1')
+ if not os.path.exists(manpath):
+ os.makedirs(manpath)
print 'Installing MAN pages...'
- manpath = '/usr/share/man/man1'
- f = NamedTemporaryFile()
- f.write('[see also]\nhttp://%s.kovidgoyal.net\n'%__appname__)
- f.flush()
manifest = []
- os.environ['PATH'] += ':'+os.path.expanduser('~/bin')
for src in entry_points['console_scripts']:
- prog = src[:src.index('=')].strip()
- if prog in ('ebook-device', 'markdown-calibre',
- 'calibre-fontconfig', 'calibre-parallel'):
+ prog, right = src.split('=')
+ prog = prog.strip()
+ module = __import__(right.split(':')[0].strip(), fromlist=['a'])
+ parser = getattr(module, 'option_parser', None)
+ if parser is None:
continue
-
- help2man = ('help2man', prog, '--name', 'part of %s'%__appname__,
- '--section', '1', '--no-info', '--include',
- f.name, '--manual', __appname__)
+ parser = parser()
+ raw = create_man_page(prog, parser)
manfile = os.path.join(manpath, prog+'.1'+__appname__+'.bz2')
print '\tInstalling MAN page for', prog
- try:
- p = subprocess.Popen(help2man, stdout=subprocess.PIPE)
- except OSError, err:
- import errno
- if err.errno != errno.ENOENT:
- raise
- print 'Failed to install MAN pages as help2man is missing from your system'
- break
- o = p.stdout.read()
- raw = re.compile(r'^\.IP\s*^([A-Z :]+)$', re.MULTILINE).sub(r'.SS\n\1', o)
- if not raw.strip():
- print 'Unable to create MAN page for', prog
- continue
- f2 = open_file(manfile)
- manifest.append(f2.name)
- f2.write(compress(raw))
+ open(manfile, 'wb').write(raw)
+ manifest.append(manfile)
return manifest
def post_install():
@@ -440,9 +385,9 @@ def post_install():
manifest = []
setup_desktop_integration(opts.fatal_errors)
if opts.no_root or os.geteuid() == 0:
+ manifest += install_man_pages(opts.fatal_errors, use_destdir)
manifest += setup_udev_rules(opts.group_file, not opts.dont_reload, opts.fatal_errors)
manifest += setup_completion(opts.fatal_errors)
- manifest += install_man_pages(opts.fatal_errors)
else:
print "Skipping udev, completion, and man-page install for non-root user."
diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst
index bb1eb9ba02..7ca4b1b876 100644
--- a/src/calibre/manual/faq.rst
+++ b/src/calibre/manual/faq.rst
@@ -34,6 +34,8 @@ What formats does |app| support conversion to/from?
| | | | | |
| | ODT | ✔ | ✔ | ✔ |
| | | | | |
+| | FB2 | ✔ | ✔ | ✔ |
+| | | | | |
| | HTML | ✔ | ✔ | ✔ |
| | | | | |
| **Input formats** | CBR | ✔ | ✔ | ✔ |
@@ -121,13 +123,12 @@ turned into a collection on the reader. Note that the PRS-500 does not support c
How do I use |app| with my iPhone?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
First install the Stanza reader on your iPhone from http://www.lexcycle.com . Then,
- * Set the output format for calibre to EPUB (this can be done in the configuration dialog accessed by the little hammer icon next to the search bar)
+
+ * Set the output format for calibre to EPUB (The output format can be set next to the big red heart)
* Convert the books you want to read on your iPhone to EPUB format by selecting them and clicking the Convert button.
- * Turn on the Content Server in the configurations dialog and leave |app| running.
- * In the Stanza reader on your iPhone, add a new catalog. The URL of the catalog is of the form
- ``http://10.34.56.89:8080/stanza``, where you should replace the IP address ``10.34.56.89``
- with the IP address of your computer. Stanza will the use the |app| content server to access all the
- EPUB books in your |app| database.
+ * Turn on the Content Server in |app|'s preferences and leave |app| running.
+
+Now you should be able to access your books on your iPhone.
Library Management
------------------
diff --git a/src/calibre/parallel.py b/src/calibre/parallel.py
index 7bdb606642..3480a01a89 100644
--- a/src/calibre/parallel.py
+++ b/src/calibre/parallel.py
@@ -227,7 +227,8 @@ class WorkerMother(object):
return env
def spawn_free_spirit_osx(self, arg, type='free_spirit'):
- script = 'from calibre.parallel import main; main(args=["calibre-parallel", %s]);'%repr(arg)
+ script = ('from calibre.parallel import main; '
+ 'main(args=["calibre-parallel", %s]);')%repr(arg)
exe = self.gui_executable if type == 'free_spirit' else self.executable
cmdline = [exe, '-c', self.prefix+script]
child = WorkerStatus(subprocess.Popen(cmdline, env=self.get_env()))
diff --git a/src/calibre/trac/donations/server.py b/src/calibre/trac/donations/server.py
index 8e7a096353..24174db801 100644
--- a/src/calibre/trac/donations/server.py
+++ b/src/calibre/trac/donations/server.py
@@ -196,7 +196,7 @@ class Server(object):
def calculate_month_trend(self, days=31):
stats = self.get_slice(date.today()-timedelta(days=days-1), date.today())
- fig = plt.figure(2, (12, 4), 96)#, facecolor, edgecolor, frameon, FigureClass)
+ fig = plt.figure(2, (10, 4), 96)#, facecolor, edgecolor, frameon, FigureClass)
fig.clear()
ax = fig.add_subplot(111)
x = list(range(days-1, -1, -1))
@@ -216,7 +216,7 @@ Donors per day: %(dpd).2f
ad=stats.average_deviation,
dpd=len(stats.totals)/float(stats.period.days),
)
- text = ax.annotate(text, (0.6, 0.65), textcoords='axes fraction')
+ text = ax.annotate(text, (0.5, 0.65), textcoords='axes fraction')
fig.savefig(self.MONTH_TRENDS)
def calculate_trend(self):
diff --git a/src/calibre/trac/plugins/download.py b/src/calibre/trac/plugins/download.py
index 9c852c554e..00bea7d65f 100644
--- a/src/calibre/trac/plugins/download.py
+++ b/src/calibre/trac/plugins/download.py
@@ -18,7 +18,6 @@ DEPENDENCIES = [
('lxml', '2.1.5', 'lxml', 'python-lxml', 'python-lxml'),
('python-dateutil', '1.4.1', 'python-dateutil', 'python-dateutil', 'python-dateutil'),
('BeautifulSoup', '3.0.5', 'beautifulsoup', 'python-beautifulsoup', 'python-BeautifulSoup'),
- ('help2man', '1.36.4', 'help2man', 'help2man', 'help2man'),
]
@@ -34,9 +33,10 @@ def get_linux_data(version='1.0.0'):
data['title'] = 'Download calibre for linux'
data['supported'] = []
for name, title in [
- ('ubuntu', 'Ubuntu Jaunty Jackalope'),
('debian', 'Debian Sid'),
('exherbo', 'Exherbo'),
+ ('foresight', 'Foresight 2.1'),
+ ('ubuntu', 'Ubuntu Jaunty Jackalope'),
]:
data['supported'].append(CoolDistro(name, title,
prefix='http://calibre.kovidgoyal.net'))
@@ -177,11 +177,11 @@ else:
compatibility='%s works on OS X Tiger and above.'%(__appname__,),
path=MOBILEREAD+file, app=__appname__,
note=Markup(\
- '''
+ u'''
Before trying to use the command line tools, you must run the app at least once. This will ask you for you password and then setup the symbolic links for the command line tools.
The app cannot be run from within the dmg. You must drag it to a folder on your filesystem (The Desktop, Applications, wherever).
-
In order for localization of the user interface in your language, select your language in the configuration dialog (by clicking the hammer icon next to the search bar) and select your language.
+
In order for localization of the user interface in your language, select your language in the preferences (by pressing u\2318+P) and select your language.
- You must have help2man and xdg-utils installed
+ You must have xdg-utils installed
on your system before running the installer.
diff --git a/src/calibre/translations/ar.po b/src/calibre/translations/ar.po
index 5838f96530..b356411597 100644
--- a/src/calibre/translations/ar.po
+++ b/src/calibre/translations/ar.po
@@ -7,33 +7,33 @@ msgid ""
msgstr ""
"Project-Id-Version: calibre\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
-"POT-Creation-Date: 2009-02-26 19:09+0000\n"
-"PO-Revision-Date: 2009-02-04 10:04+0000\n"
-"Last-Translator: عبد الله شلي (Abdellah Chelli) \n"
+"POT-Creation-Date: 2009-03-11 20:09+0000\n"
+"PO-Revision-Date: 2009-03-13 14:18+0000\n"
+"Last-Translator: صقر بن عبدالله \n"
"Language-Team: Arabic \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2009-03-06 17:12+0000\n"
+"X-Launchpad-Export-Date: 2009-03-14 02:16+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
msgid "Does absolutely nothing"
-msgstr ""
+msgstr "لا يفعل شيءً"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:44
#: /home/kovid/work/calibre/src/calibre/devices/prs505/books.py:58
#: /home/kovid/work/calibre/src/calibre/devices/prs505/books.py:196
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_any.py:71
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:520
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:1036
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:1052
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:1054
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:525
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:1049
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:1065
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:1067
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:79
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:81
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:83
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:88
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:295
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:296
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:62
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:96
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:98
@@ -59,7 +59,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:36
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:60
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:118
-#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:491
+#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:545
#: /home/kovid/work/calibre/src/calibre/ebooks/odt/to_oeb.py:46
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:569
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:574
@@ -70,8 +70,8 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:180
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:187
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:48
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:170
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:172
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:171
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:173
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:366
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:33
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:38
@@ -86,23 +86,23 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:123
#: /home/kovid/work/calibre/src/calibre/library/cli.py:260
#: /home/kovid/work/calibre/src/calibre/library/database.py:916
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:473
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:485
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:867
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:902
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:1209
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:1211
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:1391
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:1414
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:1465
-#: /home/kovid/work/calibre/src/calibre/library/server.py:315
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:478
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:490
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:872
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:907
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:1214
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:1216
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:1396
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:1419
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:1470
+#: /home/kovid/work/calibre/src/calibre/library/server.py:322
#: /home/kovid/work/calibre/src/calibre/web/feeds/news.py:51
msgid "Unknown"
msgstr "مجهول"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:62
msgid "Base"
-msgstr "أساس"
+msgstr "قاعدة"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:148
msgid "File type"
@@ -110,11 +110,11 @@ msgstr "نوع الملف"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:182
msgid "Metadata reader"
-msgstr ""
+msgstr "قارئ الميتاداتا"
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:209
msgid "Metadata writer"
-msgstr "كاتب البيانات الوصفية"
+msgstr "كاتب الميتاداتا"
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:12
msgid ""
@@ -122,6 +122,8 @@ msgid ""
"linked files. This plugin is run every time you add an HTML file to the "
"library."
msgstr ""
+"إلتحاق بكل الوصلات المحلية في ملف HTML وإنشاء ملف ZIP ليحتوي كل الملفات "
+"الموصولة. هذا الملحق ينفّذ كل مرة تضيف ملف HTML إلى المكتبة."
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:32
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:43
@@ -137,26 +139,26 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:146
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:156
msgid "Read metadata from %s files"
-msgstr "إقرأ البيانات الوصفية من الملفات %s"
+msgstr "يقرأ الميتاداتا من الملفات %s"
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:166
msgid "Extract cover from comic files"
-msgstr ""
+msgstr "استخرج الغلاف من ملف الرسومات"
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:186
msgid "Read metadata from ebooks in ZIP archives"
-msgstr "إقرأ البيانات الوصفية من كتب إلكترونية في محفوظات ZIP"
+msgstr "إقرأ ميتاداتا لكتب في أرشيفات ZIP"
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:196
msgid "Read metadata from ebooks in RAR archives"
-msgstr ""
+msgstr "إقرأ ميتاداتا لكتب في أرشيفات RAR"
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:207
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:217
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:227
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:237
msgid "Set metadata in %s files"
-msgstr ""
+msgstr "ضبط الميتاداتا في الملفات %s"
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:28
msgid "Installed plugins"
@@ -164,11 +166,11 @@ msgstr "ملحقات مثبتة"
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:29
msgid "Mapping for filetype plugins"
-msgstr ""
+msgstr "تعيين لملحقات أنواع الملفات"
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:30
msgid "Local plugin customization"
-msgstr "تخصيص ملحقات محلية"
+msgstr "تخصيص الملحقات المحلية"
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:31
msgid "Disabled plugins"
@@ -176,7 +178,7 @@ msgstr "ملحقات معطلة"
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:66
msgid "No valid plugin found in "
-msgstr "لم يعثر على أي ملحق صالح في "
+msgstr "لا يجد ملحق صالح "
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:185
msgid "Initialization of plugin %s failed with traceback:"
@@ -189,46 +191,50 @@ msgid ""
" Customize calibre by loading external plugins.\n"
" "
msgstr ""
+" %prog options\n"
+" \n"
+"تخصيص كاليبر بتحميل ملحقات خارجية.\n"
+" "
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:268
msgid "Add a plugin by specifying the path to the zip file containing it."
-msgstr "أضف ملحقا بتعيين المسار إلى ملف zip الذي يحتويه."
+msgstr "إضافة ملحق يتخصيص مسار إلى ملف zip الذي يحتويه."
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:270
msgid "Remove a custom plugin by name. Has no effect on builtin plugins"
-msgstr ""
+msgstr "حذف الملحق المخصص عن طريق اسمه. لا يؤثر على الملحقات المضمنة"
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:272
msgid ""
"Customize plugin. Specify name of plugin and customization string separated "
"by a comma."
-msgstr ""
+msgstr "تخصيص الملحق حدد اسم الملحق وسلسلة التخصيص وفرقهما بفاصلة."
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:274
msgid "List all installed plugins"
-msgstr "أسرد كل الملحقات المثبتة"
+msgstr "قائمة كل الملحقات المثبتة"
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:276
msgid "Enable the named plugin"
-msgstr "شغل الملحق المسمى"
+msgstr "تمكين الملحق المسمى"
#: /home/kovid/work/calibre/src/calibre/customize/ui.py:278
msgid "Disable the named plugin"
-msgstr "عطل الملحق المسمى"
+msgstr "تعطيل الملحق المسمى"
#: /home/kovid/work/calibre/src/calibre/devices/cybookg3/driver.py:42
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:390
-#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:70
+#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:71
msgid "The reader has no storage card connected."
-msgstr ""
+msgstr "ليس للقارئ بطاقة تخزين."
#: /home/kovid/work/calibre/src/calibre/devices/cybookg3/driver.py:61
-#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:89
+#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:90
msgid "There is insufficient free space on the storage card"
msgstr "لا توجد مساحة كافية في بطاقة التخزين"
#: /home/kovid/work/calibre/src/calibre/devices/cybookg3/driver.py:63
-#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:91
+#: /home/kovid/work/calibre/src/calibre/devices/usbms/driver.py:92
msgid "There is insufficient free space in main memory"
msgstr "لا توجد مساحة كافية في الذاكرة الرئيسية"
@@ -239,17 +245,17 @@ msgstr "لا توجد مساحة كافية في الذاكرة الرئيسية
#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:231
#: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:258
msgid "Unable to detect the %s disk drive. Try rebooting."
-msgstr ""
+msgstr "لم يتمكن من كشف القرص %s. حاول إعادة التشغيل."
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:94
msgid "Options to control the conversion to EPUB"
-msgstr ""
+msgstr "الخيارات للتحكّم على التحويل لتهيئة EPUB"
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:105
msgid ""
"The output EPUB file. If not specified, it is derived from the input file "
"name."
-msgstr ""
+msgstr "خرج الملف EPUB. إذا لم يتم التحديد، سوف يستخرج من اسم ملف الدخل."
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:108
msgid ""
@@ -266,7 +272,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:117
msgid "Control auto-detection of document structure."
-msgstr ""
+msgstr "تحكّم بالكشف الآلي لبناء المستند"
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:122
msgid ""
@@ -292,19 +298,22 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:139
msgid "Path to the cover to be used for this book"
-msgstr ""
+msgstr "المسار إلى الغلاف الذي سيستخدم لهذا الكتاب"
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:142
msgid ""
"Use the cover detected from the source file in preference to the specified "
"cover."
msgstr ""
+"استخدم الغلاف التي تم كشفه في ملف المصدر بدلاً من الغلاف الذي تم تخصيصه."
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:145
msgid ""
"Remove the first image from the input ebook. Useful if the first image in "
"the source file is a cover and you are specifying an external cover."
msgstr ""
+"حذف أول صورة من دخل الكتاب الإلكتروني. هذا يفيد حين تريد استخدام غلاف مختلف "
+"من الغلاف المضمون."
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:149
msgid ""
@@ -346,13 +355,15 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:175
msgid "Don't add auto-detected chapters to the Table of Contents."
-msgstr ""
+msgstr "لا تضف الفصول المكشوفة آلياً إلى قائمة المحتويات."
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:177
msgid ""
"If fewer than this number of chapters is detected, then links are added to "
"the Table of Contents. Default: %default"
msgstr ""
+"إذا يتم كشف عدد أقل من هذا بين الفصول فسوف يضيف وصلات إلى قائمة المحتويات. "
+"الإفتراضي هو: %default"
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:180
msgid ""
@@ -386,35 +397,39 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:198
msgid ""
"Normally, if the source file already has a Table of Contents, it is used in "
-"preference to the autodetected one. With this option, the autodetected one "
-"is always used."
+"preference to the auto-generated one. With this option, the auto-generated "
+"one is always used."
msgstr ""
+"عادةً، إذا يوجد قائمة محتويات في الملف المصدر، يتم استخدامه بدلاً من القائمة "
+"التي تم إنشاءه آلياً. بهذا الخيار، يتم استخدام القائمة المنشئة آلياً دوماً."
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:202
msgid "Control page layout"
-msgstr ""
+msgstr "تحكّم بتخطيط الصفحة"
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:204
msgid "Set the top margin in pts. Default is %default"
-msgstr ""
+msgstr "ضبط الهامش الأعلى بنقاط. الإفتراضي هو %default"
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:206
msgid "Set the bottom margin in pts. Default is %default"
-msgstr ""
+msgstr "ضبط الهامش الأسفل بنقاط. الإفتراضي هو %default"
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:208
msgid "Set the left margin in pts. Default is %default"
-msgstr ""
+msgstr "ضبط الهامش الأيسر بنقاط. الإفتراضي هو %default"
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:210
msgid "Set the right margin in pts. Default is %default"
-msgstr ""
+msgstr "ضبط الهامش الأيمن بنقاط. الإفتراضي هو %default"
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:212
msgid ""
"The base font size in pts. Default is %defaultpt. Set to 0 to disable "
"rescaling of fonts."
msgstr ""
+"حجم الخطوط الأساسية بنقاط. الإفتراضي هو %defaultpt. اضبطه بـ0 كي يعطّل تحجيم "
+"الخطوط."
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:215
msgid ""
@@ -426,13 +441,15 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:221
msgid "Do not force text to be justified in output."
-msgstr ""
+msgstr "لا تلزم النصّ بأن يكون مساوى في الخرج."
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:223
msgid ""
"Remove table markup, converting it into paragraphs. This is useful if your "
"source file uses a table to manage layout."
msgstr ""
+"حذف توسيم الجداول، وتحيلها إلى فقرات. هذا يفيد إذا الملف المصدر يستخدم "
+"الجداول لترتيب تخطيط النصّ."
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:226
msgid ""
@@ -456,7 +473,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:239
msgid ""
"Extract the contents of the produced EPUB file to the specified directory."
-msgstr ""
+msgstr "استخراج المحتوى من ملف EPUB المنتج إلى الدليل المخصص."
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_any.py:186
msgid ""
@@ -465,12 +482,16 @@ msgid ""
"Convert any of a large number of ebook formats to a %s file. Supported "
"formats are: %s\n"
msgstr ""
+"%%prog [خيارات] اسم الملف\n"
+"\n"
+"يحوّل أي نوع من أنواع تهيئات الكتاب الإلكتروني إلى ملف %s. التهيئات المدعومة "
+"هي: %s.\n"
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:105
msgid "Could not find an ebook inside the archive"
-msgstr ""
+msgstr "لم يتمكّن من الحصول على كتاب داخل الأرشيف"
-#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:226
+#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:229
msgid ""
"%prog [options] file.html|opf\n"
"\n"
@@ -481,20 +502,20 @@ msgid ""
"the element of the OPF file. \n"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:479
+#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:482
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/writer.py:758
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:623
msgid "Output written to "
-msgstr ""
+msgstr "تم كتابة الخرج في "
-#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:501
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:1139
+#: /home/kovid/work/calibre/src/calibre/ebooks/epub/from_html.py:504
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:1152
msgid "You must specify an input HTML file"
-msgstr ""
+msgstr "يجب أن تخصص ملف HTML لتدخيله"
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/iterator.py:36
msgid "%s format books are not supported"
-msgstr ""
+msgstr "الكتب بتهيئة %s ليست مدعومة"
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/split.py:30
msgid ""
@@ -506,89 +527,91 @@ msgid ""
"\t\tToo much markup. Re-splitting without structure preservation. This may "
"cause incorrect rendering."
msgstr ""
+"\t\tيوجد هناك الكثير من التوسيم. سيتم التقسيم بدون الاحتفاظ على التخطيط. قد "
+"يتسبب هذا بتصوير خاطئ."
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:532
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:537
msgid "Written processed HTML to "
-msgstr ""
+msgstr "تم كتابة الـHTML المنفّذ "
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:920
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:933
msgid "Options to control the traversal of HTML"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:927
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:940
msgid "The output directory. Default is the current directory."
-msgstr ""
+msgstr "دليل الخرج. الإفتراض هو الدليل الحالي."
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:929
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:942
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:570
msgid "Character encoding for HTML files. Default is to auto detect."
-msgstr ""
+msgstr "ترميز الحروف لملفات HTML. الإفتراضي هو للكشف الآلي."
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:931
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:944
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 ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:933
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:946
msgid "Control the following of links in HTML files."
-msgstr ""
+msgstr "تحكّم بالوصلات التالية في ملفات HTML."
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:935
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:948
msgid ""
"Traverse links in HTML files breadth first. Normally, they are traversed "
"depth first"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:937
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:950
msgid ""
"Maximum levels of recursion when following links in HTML files. Must be non-"
"negative. 0 implies that no links in the root HTML file are followed."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:939
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:952
msgid "Set metadata of the generated ebook"
-msgstr ""
+msgstr "ضبط الميتاداتا للكتاب المنشئ"
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:941
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:954
msgid "Set the title. Default is to autodetect."
-msgstr ""
+msgstr "ضبط العنوان. الإفتراضي هو ما يكشف آلياً."
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:943
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:956
msgid "The author(s) of the ebook, as a & separated list."
-msgstr ""
+msgstr "مؤلفون الكتاب، قائمة مفرّقة بـ&."
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:945
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:958
msgid "The subject(s) of this book, as a comma separated list."
-msgstr ""
+msgstr "مواضيع الكتاب، قائمة مفرّقة بفاصلة."
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:947
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:960
msgid "Set the publisher of this book."
-msgstr ""
+msgstr "ضبط ناشر هذا الكتاب."
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:949
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:962
msgid "A summary of this book."
-msgstr ""
+msgstr "تلخيص عن هذا الكتاب."
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:951
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:964
msgid "Load metadata from the specified OPF file"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:953
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:966
msgid "Options useful for debugging"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:955
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:968
msgid ""
"Be more verbose while processing. Can be specified multiple times to "
"increase verbosity."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:957
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:970
msgid "Output HTML is \"pretty printed\" for easier parsing by humans"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:963
+#: /home/kovid/work/calibre/src/calibre/ebooks/html.py:976
msgid ""
"%prog [options] file.html|opf\n"
"\n"
@@ -602,31 +625,31 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/from_any.py:47
msgid "Creating LIT file from EPUB..."
-msgstr ""
+msgstr "إنشاء ملف LIT من EPUB..."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:855
+#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:892
msgid "%prog [options] LITFILE"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:858
-#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:515
+#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:895
+#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:569
msgid "Output directory. Defaults to current directory."
-msgstr ""
+msgstr "دليل الخرج. الإفتراضي هو الدليل الحالي."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:861
+#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:898
msgid "Legibly format extracted markup. May modify meaningful whitespace."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:864
+#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:901
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/writer.py:731
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:582
msgid "Useful for debugging."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:875
-#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:539
+#: /home/kovid/work/calibre/src/calibre/ebooks/lit/reader.py:912
+#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:593
msgid "OEB ebook created in"
-msgstr ""
+msgstr "تم إنشاء كتاب OEB في"
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/writer.py:725
msgid "%prog [options] OPFFILE"
@@ -640,50 +663,54 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:76
msgid "Set the title. Default: filename."
-msgstr ""
+msgstr "تحديد العنوان. الإفتراضي: اسم الملف."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:78
msgid ""
"Set the author(s). Multiple authors should be set as a comma separated list. "
"Default: %default"
msgstr ""
+"تحديد المؤلف، إن كان هناك أكثر من مؤلف واحد، فرق بين أسماءهم بفاصلة. "
+"الإفتراضي هو: %default"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:81
msgid "Set the comment."
-msgstr ""
+msgstr "تحديد التعليق."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:83
msgid "Set the category"
-msgstr ""
+msgstr "تحديد التصنيف"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:85
msgid "Sort key for the title"
-msgstr ""
+msgstr "مفتاح الترتيب للعنوان"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:87
msgid "Sort key for the author"
-msgstr ""
+msgstr "مفتاح الترتيب للمؤلف"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:89
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:288
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:39
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:111
msgid "Publisher"
-msgstr "ناشر"
+msgstr "الناشر"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:91
msgid "Path to file containing image to be used as cover"
-msgstr ""
+msgstr "المسار إلى الملف الذي يحتوي صورة الغلاف"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:93
msgid ""
"If there is a cover graphic detected in the source file, use that instead of "
"the specified cover."
msgstr ""
+"إذا هناك صورة غلاف متوفرة في الملف المصدر، استخدمها بدلاً من الغلاف الذي تم "
+"تخصيصه."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:96
msgid "Output file name. Default is derived from input filename"
-msgstr ""
+msgstr "اسم ملف الخرج. الإفتراضي يستخرج من ملف الدخل"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:98
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:554
@@ -691,6 +718,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 ""
+"تصوير جداول HTML كقطع نصّية بدلاً من جداول حقيقية. يلزم هذا إذا الـHTML "
+"يحتوي على جداول معقّدة أو كبيرة جداً."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:101
msgid ""
@@ -705,11 +734,11 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:106
msgid "Set the space between words in pts. Default is %default"
-msgstr ""
+msgstr "ضبط المساحة بين الكلمات بنقاط. الإفتراضي هو %default"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:108
msgid "Separate paragraphs by blank lines."
-msgstr ""
+msgstr "فرّق بين الفقرات بأسطر فارغة."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:110
msgid "Add a header to all the pages with title and author."
@@ -756,6 +785,8 @@ msgid ""
"Render all content as black on white instead of the colors specified by the "
"HTML or CSS."
msgstr ""
+"تصوير كل المحتويات كأسود على أبيض بدلاً من الألوان كما يوجد في الـHTML أو "
+"CSS."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:133
msgid ""
@@ -766,25 +797,27 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:139
msgid "Left margin of page. Default is %default px."
-msgstr ""
+msgstr "الهامش الأيسر من الصفحة. الإفتراضي هو %default px."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:141
msgid "Right margin of page. Default is %default px."
-msgstr ""
+msgstr "الهامش الأيمن من الصفحة. الإفتراضي هو %default px."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:143
msgid "Top margin of page. Default is %default px."
-msgstr ""
+msgstr "الهامش الأعلى من الصفحة. الإفتراضي هو %default px."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:145
msgid "Bottom margin of page. Default is %default px."
-msgstr ""
+msgstr "الهامش الأسفل من الصفحة. الإفتراضي هو %default px."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:147
msgid ""
"Render tables in the HTML as images (useful if the document has large or "
"complex tables)"
msgstr ""
+"تحويل الجداول في الـHTML كصور (هذا يفيد إذا كان للمستند جداول كبيرة أو "
+"معقّدة)"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:149
msgid ""
@@ -807,11 +840,11 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:162
msgid "Don't add links to the table of contents."
-msgstr ""
+msgstr "لا تضف وصلات في قائمة المحتويات."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:166
msgid "Prevent the automatic detection chapters."
-msgstr ""
+msgstr "منع كشف آلي للفصول."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:169
msgid ""
@@ -855,7 +888,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:189
msgid "Add detected chapters to the table of contents."
-msgstr ""
+msgstr "إضافة فصول مكشوفة إلى قائمة المحتويات."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:192
msgid "Preprocess Baen HTML files to improve generated LRF."
@@ -869,7 +902,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:196
msgid "Use this option on html0 files from Book Designer."
-msgstr ""
+msgstr "استخدم هذا الخيار على ملفات html0 من Book Designer."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:199
msgid ""
@@ -897,7 +930,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:219
msgid "Convert to LRS"
-msgstr ""
+msgstr "حول إلى LRS"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:221
msgid ""
@@ -915,7 +948,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/any/convert_from.py:164
msgid "Converting from %s to LRF is not supported."
-msgstr ""
+msgstr "تحويل من %s إلى LRF غير مدعوم."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/any/convert_from.py:175
msgid ""
@@ -930,125 +963,143 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/any/convert_from.py:190
msgid "No file to convert specified."
-msgstr ""
+msgstr "لم يتم تحديد الملف لتحويله."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:224
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:225
msgid "Rendered %s"
-msgstr ""
+msgstr "تم تصوير %s"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:227
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:228
msgid "Failed %s"
-msgstr ""
+msgstr "فشل %s"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:279
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:280
msgid ""
"Failed to process comic: %s\n"
"\n"
"%s"
msgstr ""
+"فشل في تنفيذ الرسومات: %s\n"
+"\n"
+"%s"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:286
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:287
msgid ""
"Options to control the conversion of comics (CBR, CBZ) files into ebooks"
-msgstr ""
+msgstr "خيارات للتحكّم بتحويل ملفات الرسومات (CBR, CBZ) إلى كتب إلكترونية."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:292
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:293
msgid "Title for generated ebook. Default is to use the filename."
-msgstr ""
+msgstr "تم إنشاء عنوان للكتاب. الإفتراضي يؤخذ من اسم الملف."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:294
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:295
msgid ""
"Set the author in the metadata of the generated ebook. Default is %default"
msgstr ""
+"تحديد المؤلف في ميتاداتا الكتاب الذي تم إنشاءه. الإفتراضي هو %default"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:297
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:298
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:22
msgid ""
"Path to output file. By default a file is created in the current directory."
-msgstr ""
+msgstr "مسار إلى ملف الخرج. الإفتراضي أن يكون الملف منشئ في الدليل الحالي."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:299
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:300
msgid "Number of colors for grayscale image conversion. Default: %default"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:301
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:302
msgid ""
"Disable normalize (improve contrast) color range for pictures. Default: False"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:303
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:304
msgid "Maintain picture aspect ratio. Default is to fill the screen."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:305
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:306
msgid "Disable sharpening."
-msgstr ""
+msgstr "تعطيل التشحيذ."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:307
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:308
+msgid ""
+"Disable trimming of comic pages. For some comics, trimming might remove "
+"content as well as borders."
+msgstr ""
+"تعطيل اقتصاص صفحات الرسم. لبعضهم، الاقتصاص قد يتسبب بحذف محتوى وحدود."
+
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:311
msgid "Don't split landscape images into two portrait images"
-msgstr ""
+msgstr "لا تقسم صور عرضية إلى صورتين طوليتين."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:309
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:313
msgid ""
"Keep aspect ratio and scale image using screen height as image width for "
"viewing in landscape mode."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:311
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:315
msgid ""
"Used for right-to-left publications like manga. Causes landscape pages to be "
"split into portrait pages from right to left."
msgstr ""
+"تستخدم لمنشورات يمين إلى يسار مثل المانغا اليابانية، إلخ. يتسبب بتقسيم صور "
+"عرضية إلى صور طولية من اليمين إلى اليسار."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:313
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:317
msgid ""
"Enable Despeckle. Reduces speckle noise. May greatly increase processing "
"time."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:315
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:319
msgid ""
"Don't sort the files found in the comic alphabetically by name. Instead use "
"the order they were added to the comic."
msgstr ""
+"لا ترتّب ملفات موجودة في الرسومات أبجدياً، بل استخدم الترتيب المستخدم في "
+"الرسومات."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:317
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:321
msgid ""
"Choose a profile for the device you are generating this file for. The "
"default is the SONY PRS-500 with a screen size of 584x754 pixels. This is "
"suitable for any reader with the same screen size. Choices are %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:319
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:323
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:20
msgid ""
"Be verbose, useful for debugging. Can be specified multiple times for "
"greater verbosity."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:321
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:325
msgid "Don't show progress bar."
-msgstr ""
+msgstr "لا تظهر شريط التقدّم."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:324
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:328
msgid "Apply no processing to the image"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:329
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:333
msgid ""
"%prog [options] comic.cb[z|r]\n"
"\n"
"Convert a comic in a CBZ or CBR file to an ebook. \n"
msgstr ""
+"%prog [options] comic.cb[z|r]\n"
+"\n"
+"يحوّل رسومات موجودة في ملف CBR أو CBZ إلى كتاب إلكتروني. \n"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:389
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:393
msgid "Output written to"
-msgstr ""
+msgstr "تم كتابة الخرج إلى"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:549
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/comic/convert_from.py:553
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/from_comic.py:35
msgid "Rendering comic pages..."
-msgstr ""
+msgstr "تصوير صفحات الرسومات..."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/epub/convert_from.py:17
msgid ""
@@ -1073,109 +1124,113 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:30
msgid "Keep generated HTML files after completing conversion to LRF."
-msgstr ""
+msgstr "احتفظ بملفات HTML المنشئة بعد إنتهاء من تحويل لـLRF."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/feeds/convert_from.py:20
msgid "Options to control the behavior of feeds2disk"
-msgstr ""
+msgstr "الخيارات للتحكّم بسلوك feeds2disk"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/feeds/convert_from.py:22
msgid "Options to control the behavior of html2lrf"
-msgstr ""
+msgstr "الخيارات للتحكّم بسلوك html2lrf"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/feeds/convert_from.py:44
msgid "Fetching of recipe failed: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:317
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:321
msgid "\tBook Designer file detected."
-msgstr ""
+msgstr "\tتم اكتشاف ملف Book Designer."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:319
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:323
msgid "\tParsing HTML..."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:342
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:346
msgid "\tBaen file detected. Re-parsing..."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:358
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:362
msgid "Written preprocessed HTML to "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:376
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:380
msgid "Processing %s"
-msgstr ""
+msgstr "يعالج %s"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:390
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:394
msgid "\tConverting to BBeB..."
-msgstr ""
+msgstr "\tتحويل لـBBeB..."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:536
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:549
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:540
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:553
msgid "Could not parse file: %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:541
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:545
msgid "%s is an empty file"
-msgstr ""
+msgstr "%s ملف فارغ"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:561
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:565
msgid "Failed to parse link %s %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:605
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:609
msgid "Cannot add link %s to TOC"
-msgstr ""
+msgstr "لا يمكن إضافة وصلات %s لقائمة المحتويات"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:954
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:958
msgid "Unable to process image %s. Error: %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:999
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1003
msgid "Unable to process interlaced PNG %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1014
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1018
msgid ""
"Could not process image: %s\n"
"%s"
msgstr ""
+"لم يتمكن من معالجة: %s\n"
+"%s"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1768
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1772
msgid ""
"An error occurred while processing a table: %s. Ignoring table markup."
-msgstr ""
+msgstr "حدث خطأ حين تنفيذ الجدول: %s. سيتم تجاهل توسيم الجدول."
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1770
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1774
msgid ""
"Bad table:\n"
"%s"
msgstr ""
+"جدول غير صالح:\n"
+"%s"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1792
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1796
msgid "Table has cell that is too large"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1822
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1826
msgid ""
"You have to save the website %s as an html file first and then run html2lrf "
"on it."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1865
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1869
msgid "Could not read cover image: %s"
-msgstr ""
+msgstr "لم يتمكن من قراءة صورة الغلاف: %s"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1868
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1872
msgid "Cannot read from: %s"
-msgstr ""
+msgstr "لا يمكن القراءة من: %s"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1993
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1997
msgid "Failed to process opf file"
-msgstr ""
+msgstr "فشل في معالجة ملف opf"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1999
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:2003
msgid ""
"Usage: %prog [options] mybook.html\n"
"\n"
@@ -1202,11 +1257,11 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:137
msgid "Output LRS file"
-msgstr ""
+msgstr "خرج ملف LRS"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:139
msgid "Do not save embedded image and font files to disk"
-msgstr ""
+msgstr "لا تحفظ ملفات الصور والخظوظ المضمنة في القرص"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:158
msgid "Parsing LRF..."
@@ -1214,38 +1269,38 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:161
msgid "Creating XML..."
-msgstr ""
+msgstr "إنشاء XML..."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:163
msgid "LRS written to "
-msgstr ""
+msgstr "تم كتابة LRS في "
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:249
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:266
msgid "Could not read from thumbnail file:"
-msgstr ""
+msgstr "لم يتمكّن من قراءة ملف الصورة المصغّرة:"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:269
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:286
msgid ""
"%prog [options] file.lrs\n"
"Compile an LRS file into an LRF file."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:270
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:287
msgid "Path to output file"
-msgstr ""
+msgstr "المسار إلى ملف الخرج"
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:272
-#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:115
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:289
+#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:116
msgid "Verbose processing"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:274
+#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:291
msgid "Convert LRS to LRS, useful for debugging."
-msgstr ""
+msgstr "تحويل LRS إلى LRS، يفيد في التنقيح."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:455
msgid "Invalid LRF file. Could not set metadata."
-msgstr ""
+msgstr "ملف LRF غير صالح. لم يتمكّن ضبط الميتاداتا."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:580
msgid ""
@@ -1255,28 +1310,33 @@ msgid ""
"Show/edit the metadata in an LRF file.\n"
"\n"
msgstr ""
+"%prog [options] mybook.lrf\n"
+"\n"
+"\n"
+"إظهار/تحرير الميتاداتا في ملف LRF.\n"
+"\n"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:587
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:43
msgid "Set the book title"
-msgstr ""
+msgstr "تحديد عنوان الكتاب"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:589
msgid "Set sort key for the title"
-msgstr ""
+msgstr "ضبط مفتاح الترتيب للعنوان"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:591
msgid "Set the author"
-msgstr ""
+msgstr "تحديد المؤلف"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:593
msgid "Set sort key for the author"
-msgstr ""
+msgstr "ضبط مفتاح الترتيب للمؤلف"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:595
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:47
msgid "The category this book belongs to. E.g.: History"
-msgstr ""
+msgstr "تصنيف الكتاب. مثلاً: تاريخ"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:598
msgid "Path to a graphic that will be set as this files' thumbnail"
@@ -1289,34 +1349,36 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:605
msgid "Extract thumbnail from LRF file"
-msgstr ""
+msgstr "استخراج الصورة المصغّرة من ملف LRF"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:606
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:191
msgid "Set the publisher"
-msgstr ""
+msgstr "تحديد الناشر"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:607
msgid "Set the book classification"
-msgstr ""
+msgstr "ضبط تصنيف الكتاب"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:608
msgid "Set the book creator"
-msgstr ""
+msgstr "ضبط منشئ الكتاب"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:609
msgid "Set the book producer"
-msgstr ""
+msgstr "تحديد منتج الكتاب"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:611
msgid ""
"Extract cover from LRF file. Note that the LRF format has no defined cover, "
"so we use some heuristics to guess the cover."
msgstr ""
+"استخراج الغلاف من ملف LRF. لاحظ أن تهيئة LRF لا يستخدم غلاف مخصص، فنستخدم "
+"بعض الشروط لتخمينه."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:613
msgid "Set book ID"
-msgstr ""
+msgstr "تحديد هوية الكتاب"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/mobi/convert_from.py:43
msgid ""
@@ -1348,6 +1410,7 @@ msgid ""
"Path to output directory in which to create the HTML file. Defaults to "
"current directory."
msgstr ""
+"المسار إلى دليل الخرج لإنشاء ملف HTML فيه. الإفتراضي هو الدليل الحالي."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/pdf/reflow.py:405
msgid "Be more verbose."
@@ -1355,7 +1418,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/pdf/reflow.py:417
msgid "You must specify a single PDF file."
-msgstr ""
+msgstr "يجب أن تحدد ملف PDF واحد."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/rtf/convert_from.py:21
msgid ""
@@ -1381,11 +1444,11 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:45
msgid "Set the authors"
-msgstr ""
+msgstr "تحديد المؤلفين"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:49
msgid "Set the comment"
-msgstr ""
+msgstr "تحديد التعليق"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:286
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:69
@@ -1395,7 +1458,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:359
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:966
msgid "Title"
-msgstr ""
+msgstr "العنوان"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:287
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:37
@@ -1403,11 +1466,11 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:364
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:967
msgid "Author(s)"
-msgstr ""
+msgstr "المؤلف أو المؤلفون"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:289
msgid "Producer"
-msgstr ""
+msgstr "المنتج"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:290
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:71
@@ -1418,7 +1481,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:320
#: /home/kovid/work/calibre/src/calibre/gui2/status.py:58
msgid "Comments"
-msgstr ""
+msgstr "التعليقات"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:292
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:112
@@ -1428,7 +1491,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/status.py:60
#: /home/kovid/work/calibre/src/calibre/gui2/tags.py:50
msgid "Tags"
-msgstr ""
+msgstr "الوسوم"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:294
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:113
@@ -1436,50 +1499,50 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/status.py:59
#: /home/kovid/work/calibre/src/calibre/gui2/tags.py:50
msgid "Series"
-msgstr ""
+msgstr "السلسلة"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:295
msgid "Language"
-msgstr ""
+msgstr "اللغة"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:297
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:909
msgid "Timestamp"
-msgstr ""
+msgstr "ختم التوقيت"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/epub.py:202
msgid "A comma separated list of tags to set"
-msgstr ""
+msgstr "ضبط قائمة من الوسوم المفرقة بفاصلة"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/epub.py:204
msgid "The series to which this book belongs"
-msgstr ""
+msgstr "السلسلة التي تحتوي الكتاب"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/epub.py:206
msgid "The series index"
-msgstr ""
+msgstr "فهرس السلسلة"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/epub.py:208
msgid "The book language"
-msgstr ""
+msgstr "لغة الكتاب"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/epub.py:210
msgid "Extract the cover"
-msgstr ""
+msgstr "استخراج الغلاف"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fb2.py:54
msgid "Usage:"
-msgstr ""
+msgstr "الاستخدام:"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/imp.py:53
msgid "Usage: imp-meta file.imp"
-msgstr ""
+msgstr "الاستخدام: imp-meta file.imp"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/imp.py:54
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/pdf.py:59
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/rb.py:60
msgid "No filename specified."
-msgstr ""
+msgstr "لم يتم تحديد اسم الملف."
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:97
msgid ""
@@ -1501,19 +1564,19 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:110
msgid "The author whose book to search for."
-msgstr ""
+msgstr "المؤلف الذي تريد البحث عنه."
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:112
msgid "The title of the book to search for."
-msgstr ""
+msgstr "العنوان الذي تريد البحث عنه."
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:114
msgid "The publisher of the book to search for."
-msgstr ""
+msgstr "الناشر الذي تريد البحث عنه."
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/library_thing.py:46
msgid "LibraryThing.com timed out. Try again later."
-msgstr ""
+msgstr "LibraryThing.com لم يرد. حاول لاحقاً."
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/library_thing.py:53
msgid ""
@@ -1523,12 +1586,12 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/library_thing.py:54
msgid " not found."
-msgstr ""
+msgstr " لم يوجد."
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/library_thing.py:57
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/library_thing.py:88
msgid "LibraryThing.com server error. Try again later."
-msgstr ""
+msgstr "خطأ في خادم LibraryThing.com. حاول لاحقاً."
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/library_thing.py:66
msgid ""
@@ -1538,26 +1601,26 @@ msgid ""
"Fetch a cover image for the book identified by ISBN from LibraryThing.com\n"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/lit.py:35
+#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/lit.py:43
msgid "Usage: %s file.lit"
-msgstr ""
+msgstr "الاستخدام: %s file.lit"
-#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/lit.py:45
+#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/lit.py:53
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:236
msgid "Cover saved to"
-msgstr ""
+msgstr "تم حفظ الغلاف في"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:187
msgid "Set the subject tags"
-msgstr ""
+msgstr "تحديد وسوم الموضوع"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:189
msgid "Set the language"
-msgstr ""
+msgstr "تحديد اللغة"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:193
msgid "Set the ISBN"
-msgstr ""
+msgstr "تحديد الـISBN"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/opf2.py:1014
msgid "Set the dc:language field"
@@ -1565,21 +1628,21 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/pdf.py:58
msgid "Usage: pdf-meta file.pdf"
-msgstr ""
+msgstr "الاستخدام: pdf-meta file.pdf"
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/rb.py:59
msgid "Usage: rb-meta file.rb"
-msgstr ""
+msgstr "الاستخدام: rb-meta file.rb"
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/from_any.py:55
msgid "Creating Mobipocket file from EPUB..."
-msgstr ""
+msgstr "إنشاء ملف Mobipocket من EPUB..."
-#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:513
+#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:567
msgid "%prog [options] myebook.mobi"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:537
+#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:591
msgid "Raw MOBI HTML saved in"
msgstr ""
@@ -1610,6 +1673,7 @@ msgid ""
"When present, use the author sorting information for generating the "
"Mobipocket author metadata."
msgstr ""
+"حين يوجد، استخدم معلومات ترتيب المؤلف لإنشاء ميتاداتا المؤلف في Mobipocket."
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:560
msgid ""
@@ -1627,7 +1691,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:576
msgid "[options]"
-msgstr ""
+msgstr "[الخيارات]"
#: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer.py:594
msgid "Unknown source profile %r"
@@ -1639,38 +1703,38 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/odt/to_oeb.py:57
msgid "The output directory. Defaults to the current directory."
-msgstr ""
+msgstr "دليل الخرج. الإفتراضي هو الدليل الحالي."
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:822
msgid "Cover"
-msgstr ""
+msgstr "الغلاف"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:823
msgid "Title Page"
-msgstr ""
+msgstr "صقحة العنوان"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:824
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/htmltoc.py:18
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:47
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:160
msgid "Table of Contents"
-msgstr ""
+msgstr "المحتويات"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:825
msgid "Index"
-msgstr ""
+msgstr "الفهرس"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:826
msgid "Glossary"
-msgstr ""
+msgstr "المسرد"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:827
msgid "Acknowledgements"
-msgstr ""
+msgstr "شكر وتقدير"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:828
msgid "Bibliography"
-msgstr ""
+msgstr "ببليوغرافيا"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:829
msgid "Colophon"
@@ -1678,11 +1742,11 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:830
msgid "Copyright"
-msgstr ""
+msgstr "حقوق المؤلف"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:831
msgid "Dedication"
-msgstr ""
+msgstr "الإهداء"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:832
msgid "Epigraph"
@@ -1690,27 +1754,27 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:833
msgid "Foreword"
-msgstr ""
+msgstr "افتتاحية"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:834
msgid "List of Illustrations"
-msgstr ""
+msgstr "قائمة الرسوم"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:835
msgid "List of Tables"
-msgstr ""
+msgstr "قائمة الجداول"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:836
msgid "Notes"
-msgstr ""
+msgstr "الملاحظات"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:837
msgid "Preface"
-msgstr ""
+msgstr "افتتاحية"
#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:838
msgid "Main Text"
-msgstr ""
+msgstr "النصّ الرئيسي"
#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/pdftrim.py:13
msgid "Options to control the transformation of pdf"
@@ -1757,19 +1821,19 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:32
msgid "The format to use when saving single files to disk"
-msgstr ""
+msgstr "التهيئة لاتسخدامها في حفظ ملفات لوحدها في القرص"
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:34
msgid "Confirm before deleting"
-msgstr ""
+msgstr "تأكيد قبل الحذف"
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:36
msgid "Toolbar icon size"
-msgstr ""
+msgstr "حجم أيقونات شريط الأدوات"
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:38
msgid "Show button labels in the toolbar"
-msgstr ""
+msgstr "إظهار تسميات الأزرار في شريط الأدوات"
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:40
msgid "Main window geometry"
@@ -1777,7 +1841,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:42
msgid "Notify when a new version is available"
-msgstr ""
+msgstr "Notify when a new version is available"
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:44
msgid "Use Roman numerals for series number"
@@ -1785,7 +1849,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:46
msgid "Sort tags list by popularity"
-msgstr ""
+msgstr "ترتيب الوسوم حسب الشهرة"
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:48
msgid "Number of covers to show in the cover browsing mode"
@@ -1793,15 +1857,15 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:50
msgid "Defaults for conversion to LRF"
-msgstr ""
+msgstr "الإفتراضي للتحويل إلى LRF"
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:52
msgid "Options for the LRF ebook viewer"
-msgstr ""
+msgstr "الخيارات لمستعرض كتب LRF"
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:54
msgid "Formats that are viewed using the internal viewer"
-msgstr ""
+msgstr "تهيئات التي تعرض عن طريق المستعرض الداخلي"
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:56
msgid "Columns to be displayed in the book list"
@@ -1817,15 +1881,15 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:59
msgid "Show system tray icon"
-msgstr ""
+msgstr "إظهار أيقونة صينية النظام"
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:61
msgid "Upload downloaded news to device"
-msgstr ""
+msgstr "رفع أخبار تم تنزيلها إلى الجهاز"
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:63
msgid "Delete books from library after uploading to device"
-msgstr ""
+msgstr "حذف كتب من المكتبة بعد رفعها إلى الجهاز"
#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:65
msgid ""
@@ -1839,12 +1903,12 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:87
msgid "Added %s to library"
-msgstr ""
+msgstr "تم إضافة %s إلى المكتبة"
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:89
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:162
msgid "Read metadata from "
-msgstr ""
+msgstr "إقرأ الميتاداتا من "
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:116
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:224
@@ -1852,6 +1916,7 @@ msgid ""
"
Books with the same title as the following already exist in the database. "
"Add them anyway?
"
msgstr ""
+"
توجد كتب بنفس العنوان في قائمة البيانات. هل تريد إضافتهم بأية حال؟
"
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:120
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:121
@@ -1875,11 +1940,11 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:183
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:703
msgid "Reading metadata..."
-msgstr ""
+msgstr "قراءة الميتاداتا..."
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:193
msgid "Searching in"
-msgstr ""
+msgstr "يتم البحث في"
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:72
msgid "Device no longer connected."
@@ -1887,31 +1952,31 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:117
msgid "Get device information"
-msgstr ""
+msgstr "احصل على معلومات الجهاز"
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:128
msgid "Get list of books on device"
-msgstr ""
+msgstr "احصل على قائمة الكتب على الجهاز"
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:137
msgid "Send metadata to device"
-msgstr ""
+msgstr "ارسل الميتاداتا إلى الجهاز"
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:146
msgid "Upload %d books to device"
-msgstr ""
+msgstr "رفع %d كتاب إلى الجهاز"
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:161
msgid "Delete books from device"
-msgstr ""
+msgstr "حذف كتب من الجهاز"
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:176
msgid "Download books from device"
-msgstr ""
+msgstr "تنزيل الكتب من الجهاز"
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:186
msgid "View book on device"
-msgstr ""
+msgstr "عرض كتاب على الجهاز"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:84
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:85
@@ -1920,7 +1985,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:905
#: /home/kovid/work/calibre/src/calibre/gui2/status.py:56
msgid "Path"
-msgstr ""
+msgstr "المسار"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:87
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:88
@@ -1930,14 +1995,14 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/status.py:57
#: /home/kovid/work/calibre/src/calibre/gui2/tags.py:50
msgid "Formats"
-msgstr ""
+msgstr "التهيئات"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:61
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:88
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:91
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress_ui.py:48
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/warning_ui.py:52
msgid "Dialog"
-msgstr ""
+msgstr "حوار"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:62
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:63
@@ -1948,81 +2013,85 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress_ui.py:50
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/warning_ui.py:53
msgid "TextLabel"
-msgstr ""
+msgstr "تسمية النصّ"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:65
msgid "&Previous"
-msgstr ""
+msgstr "ال&سابق"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:66
msgid "&Next"
-msgstr ""
+msgstr "ال&تالي"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_format_ui.py:40
msgid "Choose Format"
-msgstr ""
+msgstr "إختيار التهيئة"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:34
msgid "Set defaults for conversion of comics (CBR/CBZ files)"
-msgstr ""
+msgstr "ضبط الإفتراضي في تحويل الرسومات (ملفات CBZ/CBR)"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:49
msgid "Set options for converting %s"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:89
-msgid "&Title:"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:90
-msgid "&Author(s):"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:91
-msgid "&Number of Colors:"
-msgstr ""
+msgstr "ضبط الخيارات لتحويل %s"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:92
+msgid "&Title:"
+msgstr ":ال&عنوان"
+
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:93
+msgid "&Author(s):"
+msgstr "ال&مؤلف:"
+
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:94
+msgid "&Number of Colors:"
+msgstr "&عدد الألوان:"
+
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:95
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:502
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:540
msgid "&Profile:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:93
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:96
msgid "Disable &normalize"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:94
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:97
msgid "Keep &aspect ratio"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:95
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:98
msgid "Disable &Sharpening"
-msgstr ""
+msgstr "تعطيل تشحيذ&"
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:96
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:99
msgid "&Landscape"
-msgstr ""
+msgstr "&عرضي"
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:97
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:100
msgid "Don't so&rt"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:98
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:101
msgid "&Right to left"
-msgstr ""
+msgstr "&يمين إلى يسار"
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:99
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:102
msgid "De&speckle"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:100
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:103
msgid "&Wide"
msgstr ""
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf_ui.py:104
+msgid "Disable &Trimming"
+msgstr "تعطيل اقتصاص&"
+
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:100
msgid " plugins"
-msgstr ""
+msgstr " ملحقات"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:106
msgid "by"
@@ -2030,116 +2099,118 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:123
msgid "Advanced"
-msgstr ""
+msgstr "متقدّم"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:123
msgid "General"
-msgstr ""
+msgstr "عام"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:123
msgid "Interface"
-msgstr ""
+msgstr "الواجهة"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:124
msgid ""
"Content\n"
"Server"
msgstr ""
+"محتوى\n"
+"خادم"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:124
msgid "Plugins"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:258
-msgid "No valid plugin path"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:259
-msgid "%s is not a valid plugin path"
-msgstr ""
+msgstr "الملحقات"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:262
+msgid "No valid plugin path"
+msgstr "مسار الملحق غير صالح"
+
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:263
+msgid "%s is not a valid plugin path"
+msgstr "%s ليس مسار لملحق صالح"
+
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:266
msgid "Choose plugin"
-msgstr ""
+msgstr "إختيار الملحق"
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:273
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:277
msgid "Plugin cannot be disabled"
-msgstr ""
+msgstr "لا يمكن تعطيل الملحق"
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:274
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:278
msgid "The plugin: %s cannot be disabled"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:284
-msgid "Plugin not customizable"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:285
-msgid "Plugin: %s does not need customization"
-msgstr ""
+msgstr "الملحق: %s لا يمكن تعطيله"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:288
+msgid "Plugin not customizable"
+msgstr "لا يمكن تخصيص الملحق"
+
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:289
+msgid "Plugin: %s does not need customization"
+msgstr "الملحق: %s لا يحتاج التخصيص"
+
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:292
msgid "Customize %s"
-msgstr ""
+msgstr "تخصيص %s"
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:298
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:302
msgid "Cannot remove builtin plugin"
-msgstr ""
+msgstr "لم يمكن حذف الملحق المضمن"
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:299
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:303
msgid " cannot be removed. It is a builtin plugin. Try disabling it instead."
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:320
-msgid "Error log:"
-msgstr ""
+msgstr " لا يمكن حذفه. هذا ملحق مضمن في البرنامج. حاول تعطيله بدلاً من حذفه."
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:324
-msgid "Access log:"
-msgstr ""
+msgid "Error log:"
+msgstr "سجل الأخطاء:"
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:346
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:331
+msgid "Access log:"
+msgstr "سجل النفاذ:"
+
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:356
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:409
msgid "Failed to start content server"
-msgstr ""
+msgstr "فشل في تشغيل خادم المحتوى"
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:386
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:396
msgid "Invalid size"
-msgstr ""
+msgstr "حجم غير صالح"
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:386
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:396
msgid "The size %s is invalid. must be of the form widthxheight"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:424
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:428
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:434
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:438
msgid "Invalid database location"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:425
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:435
msgid " Must be a directory."
-msgstr ""
+msgstr " يجب أن يكون دليل."
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:425
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:435
msgid "Invalid database location "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:429
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:439
msgid "Invalid database location. Cannot write to "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:441
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:451
msgid "Compacting database. This may take a while."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:441
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config.py:451
msgid "Compacting..."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:417
#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:345
msgid "Configuration"
-msgstr ""
+msgstr "إعدادات"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:418
msgid ""
@@ -2179,7 +2250,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:344
#: /home/kovid/work/calibre/src/calibre/gui2/main_ui.py:346
msgid "..."
-msgstr ""
+msgstr "..."
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:421
msgid "Show notification when &new version is available"
@@ -2193,7 +2264,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:423
msgid "Read &metadata from files"
-msgstr ""
+msgstr "إقرأ ال&ميتاداتا من الملفات"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:424
msgid "Format for &single file save:"
@@ -2211,23 +2282,23 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:427
msgid " seconds"
-msgstr ""
+msgstr " ثانية"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:428
msgid "Choose &language (requires restart):"
-msgstr ""
+msgstr "إختر ال&لغة (يحتاج إعادة تشغيل):"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:429
msgid "Normal"
-msgstr ""
+msgstr "عادي"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:430
msgid "High"
-msgstr ""
+msgstr "مرتفع"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:431
msgid "Low"
-msgstr ""
+msgstr "منخفض"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:432
msgid "Job &priority:"
@@ -2235,11 +2306,11 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:434
msgid "Add a directory to the frequently used directories list"
-msgstr ""
+msgstr "إضافة دليلاً إلى قائمة الدلائل المستخدمة كثيراً"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:436
msgid "Remove a directory from the frequently used directories list"
-msgstr ""
+msgstr "حذف الدليل من قائمة الدلائل المستخدمة كثيراً"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:438
msgid "Use &Roman numerals for series number"
@@ -2259,7 +2330,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:442
msgid "Automatically send downloaded &news to ebook reader"
-msgstr ""
+msgstr "إرسال الأخبار& التي تم تنزيلها آلياً إلى قارئ الكتب الإلكترونية"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:443
msgid "&Delete news from library when it is sent to reader"
@@ -2271,27 +2342,27 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:445
msgid "Toolbar"
-msgstr ""
+msgstr "شريط الأدوات"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:446
msgid "Large"
-msgstr ""
+msgstr "كبير"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:447
msgid "Medium"
-msgstr ""
+msgstr "متوسط"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:448
msgid "Small"
-msgstr ""
+msgstr "صغير"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:449
msgid "&Button size in toolbar"
-msgstr ""
+msgstr "&حجم الأزرار على شريط الأدوات"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:450
msgid "Show &text in toolbar buttons"
-msgstr ""
+msgstr "إظهار النص& على أزرار شريط الأدوات"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:451
msgid "Select visible &columns in library view"
@@ -2299,7 +2370,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:454
msgid "Use internal &viewer for:"
-msgstr ""
+msgstr "استخدم المستعرض& الداخلي في:"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:455
msgid "Free unused diskspace from the database"
@@ -2311,7 +2382,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:457
msgid "&Metadata from file name"
-msgstr ""
+msgstr "&ميتاداتا من اسم الملف"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:458
msgid ""
@@ -2326,15 +2397,15 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:460
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:57
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:178
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:173
msgid "&Username:"
-msgstr ""
+msgstr "&اسم المستخدم:"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:461
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:58
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:179
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:174
msgid "&Password:"
-msgstr ""
+msgstr "&كلمة السرّ"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:462
msgid ""
@@ -2344,9 +2415,9 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:463
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/password_ui.py:59
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:180
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:175
msgid "&Show password"
-msgstr ""
+msgstr "إظهار& كلمة السرّ"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:464
msgid ""
@@ -2399,27 +2470,27 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:474
msgid "&Customize plugin"
-msgstr ""
+msgstr "ت&خصيص الملحق"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:475
msgid "&Remove plugin"
-msgstr ""
+msgstr "&حذف الملحق"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:476
msgid "Add new plugin"
-msgstr ""
+msgstr "إضافة ملحق جديد"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:477
msgid "Plugin &file:"
-msgstr ""
+msgstr "&ملف الملحق:"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:479
msgid "&Add"
-msgstr ""
+msgstr "&إضافة"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:48
msgid "Are you sure?"
-msgstr ""
+msgstr "هل أنت متأكّد؟"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/confirm_delete_ui.py:50
msgid "&Show this warning again"
@@ -2427,15 +2498,15 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/conversion_error_ui.py:41
msgid "ERROR"
-msgstr ""
+msgstr "خطأ"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:52
msgid "Bulk convert to "
-msgstr ""
+msgstr "تحويل جماعي إلى "
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:54
msgid "Convert %s to "
-msgstr ""
+msgstr "حول %s إلى "
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:70
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:97
@@ -2444,7 +2515,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:143
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:161
msgid "Metadata"
-msgstr ""
+msgstr "ميتاداتا"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:72
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:98
@@ -2458,14 +2529,14 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:59
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:299
msgid "Page Setup"
-msgstr ""
+msgstr "ضبط الصفحة"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:76
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:100
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:61
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:300
msgid "Chapter Detection"
-msgstr ""
+msgstr "كشف الفصول"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:97
msgid ""
@@ -2481,7 +2552,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:99
msgid "Specify the page layout settings like margins."
-msgstr ""
+msgstr "تخصيص إعدادات تخطيط الصفحة مثل الهوامش."
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:100
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:300
@@ -2491,13 +2562,13 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:106
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:167
msgid "Choose cover for "
-msgstr ""
+msgstr "إختار الغلاف لـ "
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:113
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:174
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:59
msgid "Cannot read"
-msgstr ""
+msgstr "لا يمكن القراءة"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:114
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:175
@@ -2506,10 +2577,11 @@ msgid "You do not have permission to read the file: "
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:122
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:129
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:183
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:68
msgid "Error reading file"
-msgstr ""
+msgstr "خطأ في قراءة الملف"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:123
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:184
@@ -2517,57 +2589,57 @@ msgstr ""
msgid "
There was an error reading from file: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:129
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:130
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:190
msgid " is not a valid picture"
-msgstr ""
-
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:241
-#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1054
-msgid "Cannot convert"
-msgstr ""
+msgstr " ليست صورة صالحة"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:242
-msgid "This book has no available formats"
-msgstr ""
+#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1054
+msgid "Cannot convert"
+msgstr "لا يمكن تحويله"
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:247
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:93
-msgid "No available formats"
-msgstr ""
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:243
+msgid "This book has no available formats"
+msgstr "هذا الكتاب ليس له تهيئات متوفرة"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:248
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:93
+msgid "No available formats"
+msgstr "لم يتوفر التهيئات"
+
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:249
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:94
msgid "Cannot convert %s as this book has no supported formats"
-msgstr ""
+msgstr "لا يمكن تحويل %s لأن هذا الكتاب ليس له تهيئات مدعومة"
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:252
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:253
msgid "Choose the format to convert to "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:264
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:265
msgid "Invalid XPath expression"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:265
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub.py:266
msgid "The expression %s is invalid. Error: %s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:467
msgid "Convert to EPUB"
-msgstr ""
+msgstr "تحويل لـEPUB"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:468
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:496
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:366
msgid "Book Cover"
-msgstr ""
+msgstr "غلاف الكتاب"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:469
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:497
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:367
msgid "Change &cover image:"
-msgstr ""
+msgstr "تغيير صورة الغلاف&:"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:470
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:498
@@ -2578,26 +2650,26 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:472
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:500
msgid "Use cover from &source file"
-msgstr ""
+msgstr "استخدم غلاف من المصدر&"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:473
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:501
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:330
msgid "&Title: "
-msgstr ""
+msgstr ":ال&عنوان "
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:474
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:502
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:331
msgid "Change the title of this book"
-msgstr ""
+msgstr "تغيير عنوان هذا الكتاب"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:475
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:503
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:128
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:334
msgid "&Author(s): "
-msgstr ""
+msgstr "ال&مؤلف: "
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:476
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:504
@@ -2624,19 +2696,19 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:136
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:343
msgid "&Publisher: "
-msgstr ""
+msgstr "&الناشر: "
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:480
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:508
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:137
msgid "Change the publisher of this book"
-msgstr ""
+msgstr "تغيير ناشر هذا الكتاب"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:481
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:509
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:344
msgid "Ta&gs: "
-msgstr ""
+msgstr "الو&سوم: "
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/epub_ui.py:482
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:510
@@ -2646,13 +2718,15 @@ msgid ""
"Tags categorize the book. This is particularly useful while searching. "
"
They can be any words or phrases, separated by commas."
msgstr ""
+"الوسوم تصنّف الكتاب. هذا يفيد كثيراً في البحث.