Sync to trunk
@ -21,6 +21,11 @@ mimetypes.add_type('application/epub+zip', '.epub')
|
|||||||
mimetypes.add_type('text/x-sony-bbeb+xml', '.lrs')
|
mimetypes.add_type('text/x-sony-bbeb+xml', '.lrs')
|
||||||
mimetypes.add_type('application/x-sony-bbeb', '.lrf')
|
mimetypes.add_type('application/x-sony-bbeb', '.lrf')
|
||||||
mimetypes.add_type('application/x-dtbncx+xml', '.ncx')
|
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')
|
||||||
|
|
||||||
|
|
||||||
def to_unicode(raw, encoding='utf-8', errors='strict'):
|
def to_unicode(raw, encoding='utf-8', errors='strict'):
|
||||||
if isinstance(raw, unicode):
|
if isinstance(raw, unicode):
|
||||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
__appname__ = 'calibre'
|
__appname__ = 'calibre'
|
||||||
__version__ = '0.4.132'
|
__version__ = '0.4.133'
|
||||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||||
'''
|
'''
|
||||||
Various run time constants.
|
Various run time constants.
|
||||||
|
@ -27,6 +27,7 @@ class KINDLE(USBMS):
|
|||||||
STORAGE_CARD_VOLUME_LABEL = 'Kindle Storage Card'
|
STORAGE_CARD_VOLUME_LABEL = 'Kindle Storage Card'
|
||||||
|
|
||||||
EBOOK_DIR_MAIN = "documents"
|
EBOOK_DIR_MAIN = "documents"
|
||||||
|
EBOOK_DIR_CARD = "documents"
|
||||||
SUPPORTS_SUB_DIRS = True
|
SUPPORTS_SUB_DIRS = True
|
||||||
|
|
||||||
def delete_books(self, paths, end_session=True):
|
def delete_books(self, paths, end_session=True):
|
||||||
|
@ -147,6 +147,7 @@ class PRS505(Device):
|
|||||||
|
|
||||||
|
|
||||||
def open_windows(self):
|
def open_windows(self):
|
||||||
|
time.sleep(6)
|
||||||
drives = []
|
drives = []
|
||||||
wmi = __import__('wmi', globals(), locals(), [], -1)
|
wmi = __import__('wmi', globals(), locals(), [], -1)
|
||||||
c = wmi.WMI()
|
c = wmi.WMI()
|
||||||
|
@ -40,7 +40,7 @@ class Device(_Device):
|
|||||||
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="%(vendor_id)s">
|
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="%(vendor_id)s">
|
||||||
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="%(product_id)s">
|
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="%(product_id)s">
|
||||||
%(BCD_start)s
|
%(BCD_start)s
|
||||||
<match key="volume.is_partition" bool="false">
|
<match key="@info.parent:storage.lun" int="0">
|
||||||
<merge key="volume.label" type="string">%(main_memory)s</merge>
|
<merge key="volume.label" type="string">%(main_memory)s</merge>
|
||||||
<merge key="%(app)s.mainvolume" type="string">%(deviceclass)s</merge>
|
<merge key="%(app)s.mainvolume" type="string">%(deviceclass)s</merge>
|
||||||
</match>
|
</match>
|
||||||
@ -54,7 +54,7 @@ class Device(_Device):
|
|||||||
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="%(vendor_id)s">
|
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="%(vendor_id)s">
|
||||||
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="%(product_id)s">
|
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="%(product_id)s">
|
||||||
%(BCD_start)s
|
%(BCD_start)s
|
||||||
<match key="volume.is_partition" bool="true">
|
<match key="@info.parent:storage.lun" int="1">
|
||||||
<merge key="volume.label" type="string">%(storage_card)s</merge>
|
<merge key="volume.label" type="string">%(storage_card)s</merge>
|
||||||
<merge key="%(app)s.cardvolume" type="string">%(deviceclass)s</merge>
|
<merge key="%(app)s.cardvolume" type="string">%(deviceclass)s</merge>
|
||||||
</match>
|
</match>
|
||||||
@ -172,6 +172,7 @@ class Device(_Device):
|
|||||||
return prefix
|
return prefix
|
||||||
|
|
||||||
def open_windows(self):
|
def open_windows(self):
|
||||||
|
time.sleep(6)
|
||||||
drives = {}
|
drives = {}
|
||||||
wmi = __import__('wmi', globals(), locals(), [], -1)
|
wmi = __import__('wmi', globals(), locals(), [], -1)
|
||||||
c = wmi.WMI()
|
c = wmi.WMI()
|
||||||
|
@ -102,13 +102,23 @@ def config(defaults=None, name='epub'):
|
|||||||
c.remove_opt('zip')
|
c.remove_opt('zip')
|
||||||
|
|
||||||
c.add_opt('output', ['-o', '--output'], default=None,
|
c.add_opt('output', ['-o', '--output'], default=None,
|
||||||
help=_('The output EPUB file. If not specified, it is derived from the input file name.'))
|
help=_('The output EPUB file. If not specified, it is '
|
||||||
|
'derived from the input file name.'))
|
||||||
c.add_opt('profile', ['--profile'], default='PRS505', choices=list(PROFILES.keys()),
|
c.add_opt('profile', ['--profile'], default='PRS505', choices=list(PROFILES.keys()),
|
||||||
help=_('Profile of the target device this EPUB is meant for. Set to None to create a device independent EPUB. The profile is used for device specific restrictions on the EPUB. Choices are: ')+str(list(PROFILES.keys())))
|
help=_('Profile of the target device this EPUB is meant for. '
|
||||||
|
'Set to None to create a device independent EPUB. '
|
||||||
|
'The profile is used for device specific restrictions '
|
||||||
|
'on the EPUB. Choices are: ')+str(list(PROFILES.keys())))
|
||||||
c.add_opt('override_css', ['--override-css'], default=None,
|
c.add_opt('override_css', ['--override-css'], default=None,
|
||||||
help=_('Either the path to a CSS stylesheet or raw CSS. This CSS will override any existing CSS declarations in the source files.'))
|
help=_('Either the path to a CSS stylesheet or raw CSS. '
|
||||||
structure = c.add_group('structure detection', _('Control auto-detection of document structure.'))
|
'This CSS will override any existing CSS '
|
||||||
structure('chapter', ['--chapter'], default="//*[re:match(name(), 'h[1-2]') and re:test(., 'chapter|book|section|part', 'i')] | //*[@class = 'chapter']",
|
'declarations in the source files.'))
|
||||||
|
structure = c.add_group('structure detection',
|
||||||
|
_('Control auto-detection of document structure.'))
|
||||||
|
structure('chapter', ['--chapter'],
|
||||||
|
default="//*[re:match(name(), 'h[1-2]') and "
|
||||||
|
"re:test(., 'chapter|book|section|part', 'i')] | "
|
||||||
|
"//*[@class = 'chapter']",
|
||||||
help=_('''\
|
help=_('''\
|
||||||
An XPath expression to detect chapter titles. The default is to consider <h1> or
|
An XPath expression to detect chapter titles. The default is to consider <h1> or
|
||||||
<h2> tags that contain the words "chapter","book","section" or "part" as chapter titles as
|
<h2> tags that contain the words "chapter","book","section" or "part" as chapter titles as
|
||||||
@ -118,14 +128,31 @@ use the expression "/". See the XPath Tutorial in the calibre User Manual for fu
|
|||||||
help on using this feature.
|
help on using this feature.
|
||||||
''').replace('\n', ' '))
|
''').replace('\n', ' '))
|
||||||
structure('chapter_mark', ['--chapter-mark'], choices=['pagebreak', 'rule', 'both', 'none'],
|
structure('chapter_mark', ['--chapter-mark'], choices=['pagebreak', 'rule', 'both', 'none'],
|
||||||
default='pagebreak', help=_('Specify how to mark detected chapters. A value of "pagebreak" will insert page breaks before chapters. A value of "rule" will insert a line before chapters. A value of "none" will disable chapter marking and a value of "both" will use both page breaks and lines to mark chapters.'))
|
default='pagebreak',
|
||||||
|
help=_('Specify how to mark detected chapters. A value of '
|
||||||
|
'"pagebreak" will insert page breaks before chapters. '
|
||||||
|
'A value of "rule" will insert a line before chapters. '
|
||||||
|
'A value of "none" will disable chapter marking and a '
|
||||||
|
'value of "both" will use both page breaks and lines '
|
||||||
|
'to mark chapters.'))
|
||||||
structure('cover', ['--cover'], default=None,
|
structure('cover', ['--cover'], default=None,
|
||||||
help=_('Path to the cover to be used for this book'))
|
help=_('Path to the cover to be used for this book'))
|
||||||
structure('prefer_metadata_cover', ['--prefer-metadata-cover'], default=False,
|
structure('prefer_metadata_cover', ['--prefer-metadata-cover'], default=False,
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help=_('Use the cover detected from the source file in preference to the specified cover.'))
|
help=_('Use the cover detected from the source file in preference '
|
||||||
|
'to the specified cover.'))
|
||||||
|
structure('remove_first_image', ['--remove-first-image'], default=False,
|
||||||
|
help=_('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.'))
|
||||||
structure('dont_split_on_page_breaks', ['--dont-split-on-page-breaks'], default=False,
|
structure('dont_split_on_page_breaks', ['--dont-split-on-page-breaks'], default=False,
|
||||||
help=_('Turn off splitting at page breaks. Normally, input files are automatically split at every page break into two files. This gives an output ebook that can be parsed faster and with less resources. However, splitting is slow and if your source file contains a very large number of page breaks, you should turn off splitting on page breaks.'))
|
help=_('Turn off splitting at page breaks. Normally, input files '
|
||||||
|
'are automatically split at every page break into '
|
||||||
|
'two files. This gives an output ebook that can be parsed '
|
||||||
|
'faster and with less resources. However, splitting is '
|
||||||
|
'slow and if your source file contains a very large '
|
||||||
|
'number of page breaks, you should turn off splitting '
|
||||||
|
'on page breaks.'))
|
||||||
toc = c.add_group('toc',
|
toc = c.add_group('toc',
|
||||||
_('''\
|
_('''\
|
||||||
Control the automatic generation of a Table of Contents. If an OPF file is detected
|
Control the automatic generation of a Table of Contents. If an OPF file is detected
|
||||||
@ -133,21 +160,36 @@ and it specifies a Table of Contents, then that will be used rather than trying
|
|||||||
to auto-generate a Table of Contents.
|
to auto-generate a Table of Contents.
|
||||||
''').replace('\n', ' '))
|
''').replace('\n', ' '))
|
||||||
toc('max_toc_links', ['--max-toc-links'], default=50,
|
toc('max_toc_links', ['--max-toc-links'], default=50,
|
||||||
help=_('Maximum number of links to insert into the TOC. Set to 0 to disable. Default is: %default. Links are only added to the TOC if less than the --toc-threshold number of chapters were detected.'))
|
help=_('Maximum number of links to insert into the TOC. Set to 0 '
|
||||||
|
'to disable. Default is: %default. Links are only added to the '
|
||||||
|
'TOC if less than the --toc-threshold number of chapters were detected.'))
|
||||||
toc('no_chapters_in_toc', ['--no-chapters-in-toc'], default=False,
|
toc('no_chapters_in_toc', ['--no-chapters-in-toc'], default=False,
|
||||||
help=_("Don't add auto-detected chapters to the Table of Contents."))
|
help=_("Don't add auto-detected chapters to the Table of Contents."))
|
||||||
toc('toc_threshold', ['--toc-threshold'], default=6,
|
toc('toc_threshold', ['--toc-threshold'], default=6,
|
||||||
help=_('If fewer than this number of chapters is detected, then links are added to the Table of Contents. Default: %default'))
|
help=_('If fewer than this number of chapters is detected, then links '
|
||||||
|
'are added to the Table of Contents. Default: %default'))
|
||||||
toc('level1_toc', ['--level1-toc'], default=None,
|
toc('level1_toc', ['--level1-toc'], default=None,
|
||||||
help=_('XPath expression that specifies all tags that should be added to the Table of Contents at level one. If this is specified, it takes precedence over other forms of auto-detection.'))
|
help=_('XPath expression that specifies all tags that should be added '
|
||||||
|
'to the Table of Contents at level one. If this is specified, '
|
||||||
|
'it takes precedence over other forms of auto-detection.'))
|
||||||
toc('level2_toc', ['--level2-toc'], default=None,
|
toc('level2_toc', ['--level2-toc'], default=None,
|
||||||
help=_('XPath expression that specifies all tags that should be added to the Table of Contents at level two. Each entry is added under the previous level one entry.'))
|
help=_('XPath expression that specifies all tags that should be added '
|
||||||
|
'to the Table of Contents at level two. Each entry is added '
|
||||||
|
'under the previous level one entry.'))
|
||||||
toc('level3_toc', ['--level3-toc'], default=None,
|
toc('level3_toc', ['--level3-toc'], default=None,
|
||||||
help=_('XPath expression that specifies all tags that should be added to the Table of Contents at level three. Each entry is added under the previous level two entry.'))
|
help=_('XPath expression that specifies all tags that should be added '
|
||||||
|
'to the Table of Contents at level three. Each entry is added '
|
||||||
|
'under the previous level two entry.'))
|
||||||
toc('from_ncx', ['--from-ncx'], default=None,
|
toc('from_ncx', ['--from-ncx'], default=None,
|
||||||
help=_('Path to a .ncx file that contains the table of contents to use for this ebook. The NCX file should contain links relative to the directory it is placed in. See http://www.niso.org/workrooms/daisy/Z39-86-2005.html#NCX for an overview of the NCX format.'))
|
help=_('Path to a .ncx file that contains the table of contents to use '
|
||||||
|
'for this ebook. The NCX file should contain links relative to '
|
||||||
|
'the directory it is placed in. See '
|
||||||
|
'http://www.niso.org/workrooms/daisy/Z39-86-2005.html#NCX for '
|
||||||
|
'an overview of the NCX format.'))
|
||||||
toc('use_auto_toc', ['--use-auto-toc'], default=False,
|
toc('use_auto_toc', ['--use-auto-toc'], default=False,
|
||||||
help=_('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.'))
|
help=_('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.'))
|
||||||
|
|
||||||
layout = c.add_group('page layout', _('Control page layout'))
|
layout = c.add_group('page layout', _('Control page layout'))
|
||||||
layout('margin_top', ['--margin-top'], default=5.0,
|
layout('margin_top', ['--margin-top'], default=5.0,
|
||||||
@ -159,18 +201,33 @@ to auto-generate a Table of Contents.
|
|||||||
layout('margin_right', ['--margin-right'], default=5.0,
|
layout('margin_right', ['--margin-right'], default=5.0,
|
||||||
help=_('Set the right margin in pts. Default is %default'))
|
help=_('Set the right margin in pts. Default is %default'))
|
||||||
layout('base_font_size2', ['--base-font-size'], default=12.0,
|
layout('base_font_size2', ['--base-font-size'], default=12.0,
|
||||||
help=_('The base font size in pts. Default is %defaultpt. Set to 0 to disable rescaling of fonts.'))
|
help=_('The base font size in pts. Default is %defaultpt. '
|
||||||
|
'Set to 0 to disable rescaling of fonts.'))
|
||||||
layout('remove_paragraph_spacing', ['--remove-paragraph-spacing'], default=False,
|
layout('remove_paragraph_spacing', ['--remove-paragraph-spacing'], default=False,
|
||||||
help=_('Remove spacing between paragraphs. Will not work if the source file forces inter-paragraph spacing.'))
|
help=_('Remove spacing between paragraphs. '
|
||||||
|
'Also sets a indent on paragraphs of 1.5em. '
|
||||||
|
'You can override this by adding p {text-indent: 0cm} to '
|
||||||
|
'--override-css. Spacing removal will not work if the source '
|
||||||
|
'file forces inter-paragraph spacing.'))
|
||||||
|
layout('no_justification', ['--no-justification'], default=False,
|
||||||
|
help=_('Do not force text to be justified in output.'))
|
||||||
|
layout('linearize_tables', ['--linearize-tables'], default=False,
|
||||||
|
help=_('Remove table markup, converting it into paragraphs. '
|
||||||
|
'This is useful if your source file uses a table to manage layout.'))
|
||||||
layout('preserve_tag_structure', ['--preserve-tag-structure'], default=False,
|
layout('preserve_tag_structure', ['--preserve-tag-structure'], default=False,
|
||||||
help=_('Preserve the HTML tag structure while splitting large HTML files. This is only neccessary if the HTML files contain CSS that uses sibling selectors. Enabling this greatly slows down processing of large HTML files.'))
|
help=_('Preserve the HTML tag structure while splitting large HTML files. '
|
||||||
|
'This is only neccessary if the HTML files contain CSS that '
|
||||||
|
'uses sibling selectors. Enabling this greatly slows down '
|
||||||
|
'processing of large HTML files.'))
|
||||||
|
|
||||||
c.add_opt('show_opf', ['--show-opf'], default=False, group='debug',
|
c.add_opt('show_opf', ['--show-opf'], default=False, group='debug',
|
||||||
help=_('Print generated OPF file to stdout'))
|
help=_('Print generated OPF file to stdout'))
|
||||||
c.add_opt('show_ncx', ['--show-ncx'], default=False, group='debug',
|
c.add_opt('show_ncx', ['--show-ncx'], default=False, group='debug',
|
||||||
help=_('Print generated NCX file to stdout'))
|
help=_('Print generated NCX file to stdout'))
|
||||||
c.add_opt('keep_intermediate', ['--keep-intermediate-files'], group='debug', default=False,
|
c.add_opt('keep_intermediate', ['--keep-intermediate-files'], group='debug',
|
||||||
|
default=False,
|
||||||
help=_('Keep intermediate files during processing by html2epub'))
|
help=_('Keep intermediate files during processing by html2epub'))
|
||||||
c.add_opt('extract_to', ['--extract-to'], group='debug', default=None,
|
c.add_opt('extract_to', ['--extract-to'], group='debug', default=None,
|
||||||
help=_('Extract the contents of the produced EPUB file to the specified directory.'))
|
help=_('Extract the contents of the produced EPUB file to the '
|
||||||
|
'specified directory.'))
|
||||||
return c
|
return c
|
@ -194,6 +194,9 @@ class HTMLProcessor(Processor, Rationalizer):
|
|||||||
if not tag.text and not tag.get('src', False):
|
if not tag.text and not tag.get('src', False):
|
||||||
tag.getparent().remove(tag)
|
tag.getparent().remove(tag)
|
||||||
|
|
||||||
|
if self.opts.linearize_tables:
|
||||||
|
for tag in self.root.xpath('//table | //tr | //th | //td'):
|
||||||
|
tag.tag = 'div'
|
||||||
|
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
@ -203,6 +206,13 @@ class HTMLProcessor(Processor, Rationalizer):
|
|||||||
# self.convert_image(img)
|
# self.convert_image(img)
|
||||||
Processor.save(self)
|
Processor.save(self)
|
||||||
|
|
||||||
|
def remove_first_image(self):
|
||||||
|
images = self.root.xpath('//img')
|
||||||
|
if images:
|
||||||
|
images[0].getparent().remove(images[0])
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -224,10 +234,13 @@ def parse_content(filelist, opts, tdir):
|
|||||||
resource_map, stylesheets = {}, {}
|
resource_map, stylesheets = {}, {}
|
||||||
toc = TOC(base_path=tdir, type='root')
|
toc = TOC(base_path=tdir, type='root')
|
||||||
stylesheet_map = {}
|
stylesheet_map = {}
|
||||||
|
first_image_removed = False
|
||||||
for htmlfile in filelist:
|
for htmlfile in filelist:
|
||||||
logging.getLogger('html2epub').debug('Processing %s...'%htmlfile)
|
logging.getLogger('html2epub').debug('Processing %s...'%htmlfile)
|
||||||
hp = HTMLProcessor(htmlfile, opts, os.path.join(tdir, 'content'),
|
hp = HTMLProcessor(htmlfile, opts, os.path.join(tdir, 'content'),
|
||||||
resource_map, filelist, stylesheets)
|
resource_map, filelist, stylesheets)
|
||||||
|
if not first_image_removed and opts.remove_first_image:
|
||||||
|
first_image_removed = hp.remove_first_image()
|
||||||
hp.populate_toc(toc)
|
hp.populate_toc(toc)
|
||||||
hp.save()
|
hp.save()
|
||||||
stylesheet_map[os.path.basename(hp.save_path())] = \
|
stylesheet_map[os.path.basename(hp.save_path())] = \
|
||||||
@ -443,10 +456,7 @@ def convert(htmlfile, opts, notification=None, create_epub=True,
|
|||||||
if os.path.exists(cpath):
|
if os.path.exists(cpath):
|
||||||
opf.add_path_to_manifest(cpath, 'image/jpeg')
|
opf.add_path_to_manifest(cpath, 'image/jpeg')
|
||||||
with open(opf_path, 'wb') as f:
|
with open(opf_path, 'wb') as f:
|
||||||
raw = opf.render()
|
f.write(opf.render())
|
||||||
if not raw.startswith('<?xml '):
|
|
||||||
raw = '<?xml version="1.0" encoding="UTF-8"?>\n'+raw
|
|
||||||
f.write(raw)
|
|
||||||
ncx_path = os.path.join(os.path.dirname(opf_path), 'toc.ncx')
|
ncx_path = os.path.join(os.path.dirname(opf_path), 'toc.ncx')
|
||||||
if os.path.exists(ncx_path) and os.stat(ncx_path).st_size > opts.profile.flow_size:
|
if os.path.exists(ncx_path) and os.stat(ncx_path).st_size > opts.profile.flow_size:
|
||||||
logger.info('Condensing NCX from %d bytes...'%os.stat(ncx_path).st_size)
|
logger.info('Condensing NCX from %d bytes...'%os.stat(ncx_path).st_size)
|
||||||
@ -462,7 +472,7 @@ def convert(htmlfile, opts, notification=None, create_epub=True,
|
|||||||
logger.info(_('Output written to ')+opts.output)
|
logger.info(_('Output written to ')+opts.output)
|
||||||
|
|
||||||
if opts.show_opf:
|
if opts.show_opf:
|
||||||
print open(os.path.join(tdir, 'metadata.opf')).read()
|
print open(opf_path, 'rb').read()
|
||||||
|
|
||||||
if opts.extract_to is not None:
|
if opts.extract_to is not None:
|
||||||
if os.path.exists(opts.extract_to):
|
if os.path.exists(opts.extract_to):
|
||||||
|
@ -9,7 +9,7 @@ directory or zip file. All the action starts in :function:`create_dir`.
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
import sys, re, os, shutil, logging, tempfile, cStringIO, operator, functools
|
import sys, re, os, shutil, logging, tempfile, cStringIO, operator, functools
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse, urlunparse
|
||||||
from urllib import unquote
|
from urllib import unquote
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
@ -98,7 +98,8 @@ class Link(object):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def url_to_local_path(cls, url, base):
|
def url_to_local_path(cls, url, base):
|
||||||
path = url.path
|
path = urlunparse(('', '', url.path, url.params, url.query, ''))
|
||||||
|
path = unquote(path)
|
||||||
if os.path.isabs(path):
|
if os.path.isabs(path):
|
||||||
return path
|
return path
|
||||||
return os.path.abspath(os.path.join(base, path))
|
return os.path.abspath(os.path.join(base, path))
|
||||||
@ -111,11 +112,11 @@ class Link(object):
|
|||||||
'''
|
'''
|
||||||
assert isinstance(url, unicode) and isinstance(base, unicode)
|
assert isinstance(url, unicode) and isinstance(base, unicode)
|
||||||
self.url = url
|
self.url = url
|
||||||
self.parsed_url = urlparse(unquote(self.url))
|
self.parsed_url = urlparse(self.url)
|
||||||
self.is_local = self.parsed_url.scheme in ('', 'file')
|
self.is_local = self.parsed_url.scheme in ('', 'file')
|
||||||
self.is_internal = self.is_local and not bool(self.parsed_url.path)
|
self.is_internal = self.is_local and not bool(self.parsed_url.path)
|
||||||
self.path = None
|
self.path = None
|
||||||
self.fragment = self.parsed_url.fragment
|
self.fragment = unquote(self.parsed_url.fragment)
|
||||||
if self.is_local and not self.is_internal:
|
if self.is_local and not self.is_internal:
|
||||||
self.path = self.url_to_local_path(self.parsed_url, base)
|
self.path = self.url_to_local_path(self.parsed_url, base)
|
||||||
|
|
||||||
@ -594,15 +595,21 @@ class Processor(Parser):
|
|||||||
'''
|
'''
|
||||||
Populate the Table of Contents from detected chapters and links.
|
Populate the Table of Contents from detected chapters and links.
|
||||||
'''
|
'''
|
||||||
|
class Adder(object):
|
||||||
|
|
||||||
def add_item(href, fragment, text, target, type='link'):
|
def __init__(self, toc):
|
||||||
|
self.next_play_order = max([x.play_order for x in toc.flat()])
|
||||||
|
|
||||||
|
def __call__(self, href, fragment, text, target, type='link'):
|
||||||
for entry in toc.flat():
|
for entry in toc.flat():
|
||||||
if entry.href == href and entry.fragment == fragment:
|
if entry.href == href and entry.fragment == fragment:
|
||||||
return entry
|
return entry
|
||||||
if len(text) > 50:
|
if len(text) > 50:
|
||||||
text = text[:50] + u'\u2026'
|
text = text[:50] + u'\u2026'
|
||||||
return target.add_item(href, fragment, text, type=type)
|
self.next_play_order += 1
|
||||||
|
return target.add_item(href, fragment, text, type=type,
|
||||||
|
play_order=self.next_play_order)
|
||||||
|
add_item = Adder(toc)
|
||||||
name = self.htmlfile_map[self.htmlfile.path]
|
name = self.htmlfile_map[self.htmlfile.path]
|
||||||
href = 'content/'+name
|
href = 'content/'+name
|
||||||
|
|
||||||
@ -629,13 +636,15 @@ class Processor(Parser):
|
|||||||
|
|
||||||
if self.opts.level1_toc is not None:
|
if self.opts.level1_toc is not None:
|
||||||
level1 = self.opts.level1_toc(self.root)
|
level1 = self.opts.level1_toc(self.root)
|
||||||
|
level1_order = []
|
||||||
if level1:
|
if level1:
|
||||||
added = {}
|
added = {}
|
||||||
for elem in level1:
|
for elem in level1:
|
||||||
text, _href, frag = elem_to_link(elem, href, counter)
|
text, _href, frag = elem_to_link(elem, href, counter)
|
||||||
counter += 1
|
counter += 1
|
||||||
if text:
|
if text:
|
||||||
added[elem] = add_item(_href, frag, text, toc, type='chapter')
|
level1_order.append(add_item(_href, frag, text, toc, type='chapter'))
|
||||||
|
added[elem] = level1_order[-1]
|
||||||
add_item(_href, frag, 'Top', added[elem], type='chapter')
|
add_item(_href, frag, 'Top', added[elem], type='chapter')
|
||||||
if self.opts.level2_toc is not None:
|
if self.opts.level2_toc is not None:
|
||||||
added2 = {}
|
added2 = {}
|
||||||
@ -665,6 +674,15 @@ class Processor(Parser):
|
|||||||
add_item(_href, frag, text, level2, type='chapter')
|
add_item(_href, frag, text, level2, type='chapter')
|
||||||
|
|
||||||
|
|
||||||
|
if level1_order: # Fix play order
|
||||||
|
next_play_order = level1_order[0].play_order
|
||||||
|
for x in level1_order:
|
||||||
|
for y in x.flat():
|
||||||
|
y.play_order = next_play_order
|
||||||
|
next_play_order += 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if len(toc) > 0:
|
if len(toc) > 0:
|
||||||
return
|
return
|
||||||
# Add chapters to TOC
|
# Add chapters to TOC
|
||||||
@ -867,6 +885,8 @@ class Processor(Parser):
|
|||||||
css += '\n\na { color: inherit; text-decoration: inherit; cursor: default; }\na[href] { color: blue; text-decoration: underline; cursor:pointer; }'
|
css += '\n\na { color: inherit; text-decoration: inherit; cursor: default; }\na[href] { color: blue; text-decoration: underline; cursor:pointer; }'
|
||||||
if self.opts.remove_paragraph_spacing:
|
if self.opts.remove_paragraph_spacing:
|
||||||
css += '\n\np {text-indent: 1.5em; margin-top:0pt; margin-bottom:0pt; padding:0pt; border:0pt;}'
|
css += '\n\np {text-indent: 1.5em; margin-top:0pt; margin-bottom:0pt; padding:0pt; border:0pt;}'
|
||||||
|
if not self.opts.no_justification:
|
||||||
|
css += '\n\nbody {text-align: justify}'
|
||||||
if self.opts.override_css:
|
if self.opts.override_css:
|
||||||
css += '\n\n' + self.opts.override_css
|
css += '\n\n' + self.opts.override_css
|
||||||
self.override_css = self.css_parser.parseString(self.preprocess_css(css))
|
self.override_css = self.css_parser.parseString(self.preprocess_css(css))
|
||||||
@ -987,7 +1007,6 @@ def merge_metadata(htmlfile, opf, opts):
|
|||||||
mi = get_metadata(open(htmlfile, 'rb'), 'html')
|
mi = get_metadata(open(htmlfile, 'rb'), 'html')
|
||||||
except:
|
except:
|
||||||
mi = MetaInformation(None, None)
|
mi = MetaInformation(None, None)
|
||||||
|
|
||||||
if opts.from_opf is not None and os.access(opts.from_opf, os.R_OK):
|
if opts.from_opf is not None and os.access(opts.from_opf, os.R_OK):
|
||||||
mi.smart_update(OPF(open(opts.from_opf, 'rb'), os.path.abspath(os.path.dirname(opts.from_opf))))
|
mi.smart_update(OPF(open(opts.from_opf, 'rb'), os.path.abspath(os.path.dirname(opts.from_opf))))
|
||||||
for attr in ('title', 'authors', 'publisher', 'tags', 'comments'):
|
for attr in ('title', 'authors', 'publisher', 'tags', 'comments'):
|
||||||
|
@ -23,7 +23,7 @@ from urllib import unquote as urlunquote
|
|||||||
from lxml import etree
|
from lxml import etree
|
||||||
from calibre.ebooks.lit.reader import DirectoryEntry
|
from calibre.ebooks.lit.reader import DirectoryEntry
|
||||||
import calibre.ebooks.lit.maps as maps
|
import calibre.ebooks.lit.maps as maps
|
||||||
from calibre.ebooks.oeb.base import OEB_DOCS, OEB_STYLES, OEB_CSS_MIME, \
|
from calibre.ebooks.oeb.base import OEB_DOCS, XHTML_MIME, OEB_STYLES, \
|
||||||
CSS_MIME, OPF_MIME, XML_NS, XML
|
CSS_MIME, OPF_MIME, XML_NS, XML
|
||||||
from calibre.ebooks.oeb.base import namespace, barename, prefixname, \
|
from calibre.ebooks.oeb.base import namespace, barename, prefixname, \
|
||||||
urlnormalize, xpath
|
urlnormalize, xpath
|
||||||
@ -474,7 +474,7 @@ class LitWriter(object):
|
|||||||
name = '/data/' + item.id
|
name = '/data/' + item.id
|
||||||
data = item.data
|
data = item.data
|
||||||
secnum = 0
|
secnum = 0
|
||||||
if not isinstance(data, basestring):
|
if isinstance(data, etree._Element):
|
||||||
self._add_folder(name)
|
self._add_folder(name)
|
||||||
rebin = ReBinary(data, item, self._oeb, map=HTML_MAP)
|
rebin = ReBinary(data, item, self._oeb, map=HTML_MAP)
|
||||||
self._add_file(name + '/ahc', rebin.ahc, 0)
|
self._add_file(name + '/ahc', rebin.ahc, 0)
|
||||||
@ -483,6 +483,8 @@ class LitWriter(object):
|
|||||||
data = rebin.content
|
data = rebin.content
|
||||||
name = name + '/content'
|
name = name + '/content'
|
||||||
secnum = 1
|
secnum = 1
|
||||||
|
elif isinstance(data, unicode):
|
||||||
|
data = data.encode('utf-8')
|
||||||
self._add_file(name, data, secnum)
|
self._add_file(name, data, secnum)
|
||||||
item.size = len(data)
|
item.size = len(data)
|
||||||
|
|
||||||
@ -493,7 +495,7 @@ class LitWriter(object):
|
|||||||
if item.spine_position is not None:
|
if item.spine_position is not None:
|
||||||
key = 'linear' if item.linear else 'nonlinear'
|
key = 'linear' if item.linear else 'nonlinear'
|
||||||
manifest[key].append(item)
|
manifest[key].append(item)
|
||||||
elif item.media_type == CSS_MIME:
|
elif item.media_type in OEB_STYLES:
|
||||||
manifest['css'].append(item)
|
manifest['css'].append(item)
|
||||||
elif item.media_type in LIT_IMAGES:
|
elif item.media_type in LIT_IMAGES:
|
||||||
manifest['images'].append(item)
|
manifest['images'].append(item)
|
||||||
@ -506,6 +508,11 @@ class LitWriter(object):
|
|||||||
data.write(pack('<I', len(items)))
|
data.write(pack('<I', len(items)))
|
||||||
for item in items:
|
for item in items:
|
||||||
id, media_type = item.id, item.media_type
|
id, media_type = item.id, item.media_type
|
||||||
|
if media_type in OEB_DOCS:
|
||||||
|
# Needs to have 'html' in media-type
|
||||||
|
media_type = XHTML_MIME
|
||||||
|
elif media_type in OEB_STYLES:
|
||||||
|
media_type = CSS_MIME
|
||||||
href = urlunquote(item.href)
|
href = urlunquote(item.href)
|
||||||
item.offset = offset \
|
item.offset = offset \
|
||||||
if state in ('linear', 'nonlinear') else 0
|
if state in ('linear', 'nonlinear') else 0
|
||||||
@ -525,7 +532,12 @@ class LitWriter(object):
|
|||||||
pb3 = StringIO()
|
pb3 = StringIO()
|
||||||
pb3cur = 0
|
pb3cur = 0
|
||||||
bits = 0
|
bits = 0
|
||||||
|
linear = []
|
||||||
|
nonlinear = []
|
||||||
for item in self._oeb.spine:
|
for item in self._oeb.spine:
|
||||||
|
dest = linear if item.linear else nonlinear
|
||||||
|
dest.append(item)
|
||||||
|
for item in chain(linear, nonlinear):
|
||||||
page_breaks = copy.copy(item.page_breaks)
|
page_breaks = copy.copy(item.page_breaks)
|
||||||
if not item.linear:
|
if not item.linear:
|
||||||
page_breaks.insert(0, (0, []))
|
page_breaks.insert(0, (0, []))
|
||||||
|
@ -243,6 +243,12 @@ class MetaInformation(object):
|
|||||||
if getattr(mi, 'cover_data', None) and mi.cover_data[0] is not None:
|
if getattr(mi, 'cover_data', None) and mi.cover_data[0] is not None:
|
||||||
self.cover_data = mi.cover_data
|
self.cover_data = mi.cover_data
|
||||||
|
|
||||||
|
def format_series_index(self):
|
||||||
|
try:
|
||||||
|
x = float(self.series_index)
|
||||||
|
except ValueError:
|
||||||
|
x = 1.0
|
||||||
|
return '%d'%x if int(x) == x else '%.2f'%x
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
ans = [ fmt('Title', self.title) ]
|
ans = [ fmt('Title', self.title) ]
|
||||||
@ -265,7 +271,7 @@ class MetaInformation(object):
|
|||||||
if self.tags:
|
if self.tags:
|
||||||
fmt('Tags', u', '.join([unicode(t) for t in self.tags]))
|
fmt('Tags', u', '.join([unicode(t) for t in self.tags]))
|
||||||
if self.series:
|
if self.series:
|
||||||
fmt('Series', self.series + '#%s'%self.series_index)
|
fmt('Series', self.series + ' #%s'%self.format_series_index())
|
||||||
if self.language:
|
if self.language:
|
||||||
fmt('Language', self.language)
|
fmt('Language', self.language)
|
||||||
if self.rating is not None:
|
if self.rating is not None:
|
||||||
@ -280,7 +286,8 @@ class MetaInformation(object):
|
|||||||
ans += [(_('Comments'), unicode(self.comments))]
|
ans += [(_('Comments'), unicode(self.comments))]
|
||||||
ans += [('ISBN', unicode(self.isbn))]
|
ans += [('ISBN', unicode(self.isbn))]
|
||||||
ans += [(_('Tags'), u', '.join([unicode(t) for t in self.tags]))]
|
ans += [(_('Tags'), u', '.join([unicode(t) for t in self.tags]))]
|
||||||
ans += [(_('Series'), unicode(self.series))]
|
if self.series:
|
||||||
|
ans += [(_('Series'), unicode(self.series))+ ' #%s'%self.format_series_index()]
|
||||||
ans += [(_('Language'), unicode(self.language))]
|
ans += [(_('Language'), unicode(self.language))]
|
||||||
for i, x in enumerate(ans):
|
for i, x in enumerate(ans):
|
||||||
ans[i] = u'<tr><td><b>%s</b></td><td>%s</td></tr>'%x
|
ans[i] = u'<tr><td><b>%s</b></td><td>%s</td></tr>'%x
|
||||||
|
@ -789,7 +789,10 @@ class OPF(object):
|
|||||||
return elem
|
return elem
|
||||||
|
|
||||||
def render(self, encoding='utf-8'):
|
def render(self, encoding='utf-8'):
|
||||||
return etree.tostring(self.root, encoding='utf-8', pretty_print=True)
|
raw = etree.tostring(self.root, encoding=encoding, pretty_print=True)
|
||||||
|
if not raw.lstrip().startswith('<?xml '):
|
||||||
|
raw = '<?xml version="1.0" encoding="%s"?>\n'%encoding.upper()+raw
|
||||||
|
return raw
|
||||||
|
|
||||||
def smart_update(self, mi):
|
def smart_update(self, mi):
|
||||||
for attr in ('author_sort', 'title_sort', 'comments', 'category',
|
for attr in ('author_sort', 'title_sort', 'comments', 'category',
|
||||||
@ -877,7 +880,8 @@ class OPFCreator(MetaInformation):
|
|||||||
self.guide = Guide.from_opf_guide(guide_element, self.base_path)
|
self.guide = Guide.from_opf_guide(guide_element, self.base_path)
|
||||||
self.guide.set_basedir(self.base_path)
|
self.guide.set_basedir(self.base_path)
|
||||||
|
|
||||||
def render(self, opf_stream, ncx_stream=None, ncx_manifest_entry=None):
|
def render(self, opf_stream=sys.stdout, ncx_stream=None,
|
||||||
|
ncx_manifest_entry=None):
|
||||||
from calibre.resources import opf_template
|
from calibre.resources import opf_template
|
||||||
from calibre.utils.genshi.template import MarkupTemplate
|
from calibre.utils.genshi.template import MarkupTemplate
|
||||||
template = MarkupTemplate(opf_template)
|
template = MarkupTemplate(opf_template)
|
||||||
|
@ -138,6 +138,7 @@ class MobiMLizer(object):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def mobimlize_content(self, tag, text, bstate, istates):
|
def mobimlize_content(self, tag, text, bstate, istates):
|
||||||
|
if text or tag != 'br':
|
||||||
bstate.content = True
|
bstate.content = True
|
||||||
istate = istates[-1]
|
istate = istates[-1]
|
||||||
para = bstate.para
|
para = bstate.para
|
||||||
@ -188,11 +189,6 @@ class MobiMLizer(object):
|
|||||||
vspace -= 1
|
vspace -= 1
|
||||||
if istate.halign != 'auto':
|
if istate.halign != 'auto':
|
||||||
para.attrib['align'] = istate.halign
|
para.attrib['align'] = istate.halign
|
||||||
if istate.ids:
|
|
||||||
last = bstate.body[-1]
|
|
||||||
for id in istate.ids:
|
|
||||||
last.addprevious(etree.Element(XHTML('a'), attrib={'id': id}))
|
|
||||||
istate.ids.clear()
|
|
||||||
pstate = bstate.istate
|
pstate = bstate.istate
|
||||||
if tag in CONTENT_TAGS:
|
if tag in CONTENT_TAGS:
|
||||||
bstate.inline = para
|
bstate.inline = para
|
||||||
@ -200,6 +196,11 @@ class MobiMLizer(object):
|
|||||||
etree.SubElement(para, XHTML(tag), attrib=istate.attrib)
|
etree.SubElement(para, XHTML(tag), attrib=istate.attrib)
|
||||||
elif tag in TABLE_TAGS:
|
elif tag in TABLE_TAGS:
|
||||||
para.attrib['valign'] = 'top'
|
para.attrib['valign'] = 'top'
|
||||||
|
if istate.ids:
|
||||||
|
last = bstate.body[-1]
|
||||||
|
for id in istate.ids:
|
||||||
|
last.addprevious(etree.Element(XHTML('a'), attrib={'id': id}))
|
||||||
|
istate.ids.clear()
|
||||||
if not text:
|
if not text:
|
||||||
return
|
return
|
||||||
if not pstate or istate != pstate:
|
if not pstate or istate != pstate:
|
||||||
|
@ -121,6 +121,7 @@ class BookHeader(object):
|
|||||||
sublangid = (langcode >> 10) & 0xFF
|
sublangid = (langcode >> 10) & 0xFF
|
||||||
self.language = main_language.get(langid, 'ENGLISH')
|
self.language = main_language.get(langid, 'ENGLISH')
|
||||||
self.sublanguage = sub_language.get(sublangid, 'NEUTRAL')
|
self.sublanguage = sub_language.get(sublangid, 'NEUTRAL')
|
||||||
|
self.mobi_version = struct.unpack('>I', raw[0x68:0x6c])[0]
|
||||||
self.first_image_index = struct.unpack('>L', raw[0x6c:0x6c+4])[0]
|
self.first_image_index = struct.unpack('>L', raw[0x6c:0x6c+4])[0]
|
||||||
|
|
||||||
self.exth_flag, = struct.unpack('>L', raw[0x80:0x84])
|
self.exth_flag, = struct.unpack('>L', raw[0x80:0x84])
|
||||||
@ -132,11 +133,8 @@ class BookHeader(object):
|
|||||||
|
|
||||||
|
|
||||||
class MobiReader(object):
|
class MobiReader(object):
|
||||||
|
|
||||||
PAGE_BREAK_PAT = re.compile(r'(<[/]{0,1}mbp:pagebreak\s*[/]{0,1}>)+', re.IGNORECASE)
|
PAGE_BREAK_PAT = re.compile(r'(<[/]{0,1}mbp:pagebreak\s*[/]{0,1}>)+', re.IGNORECASE)
|
||||||
IMAGE_PATS = map(re.compile, (r'\shirecindex=[\'"]{0,1}(\d+)[\'"]{0,1}',
|
IMAGE_ATTRS = ('lowrecindex', 'recindex', 'hirecindex')
|
||||||
r'\srecindex=[\'"]{0,1}(\d+)[\'"]{0,1}',
|
|
||||||
r'\slorecindex=[\'"]{0,1}(\d+)[\'"]{0,1}'))
|
|
||||||
|
|
||||||
def __init__(self, filename_or_stream, verbose=False):
|
def __init__(self, filename_or_stream, verbose=False):
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
@ -247,6 +245,7 @@ class MobiReader(object):
|
|||||||
self.processed_html = re.sub(r'<div height="0(pt|px|ex|em|%){0,1}"></div>', '', self.processed_html)
|
self.processed_html = re.sub(r'<div height="0(pt|px|ex|em|%){0,1}"></div>', '', self.processed_html)
|
||||||
if self.book_header.ancient and '<html' not in self.mobi_html[:300].lower():
|
if self.book_header.ancient and '<html' not in self.mobi_html[:300].lower():
|
||||||
self.processed_html = '<html><p>'+self.processed_html.replace('\n\n', '<p>')+'</html>'
|
self.processed_html = '<html><p>'+self.processed_html.replace('\n\n', '<p>')+'</html>'
|
||||||
|
self.processed_html = self.processed_html.replace('\r\n', '\n')
|
||||||
self.processed_html = self.processed_html.replace('> <', '>\n<')
|
self.processed_html = self.processed_html.replace('> <', '>\n<')
|
||||||
for t, c in [('b', 'bold'), ('i', 'italic')]:
|
for t, c in [('b', 'bold'), ('i', 'italic')]:
|
||||||
self.processed_html = re.sub(r'(?i)<%s>'%t, r'<span class="%s">'%c, self.processed_html)
|
self.processed_html = re.sub(r'(?i)<%s>'%t, r'<span class="%s">'%c, self.processed_html)
|
||||||
@ -264,6 +263,7 @@ class MobiReader(object):
|
|||||||
'x-large' : '5',
|
'x-large' : '5',
|
||||||
'xx-large' : '6',
|
'xx-large' : '6',
|
||||||
}
|
}
|
||||||
|
mobi_version = self.book_header.mobi_version
|
||||||
for tag in root.iter(etree.Element):
|
for tag in root.iter(etree.Element):
|
||||||
if tag.tag in ('country-region', 'place', 'placetype', 'placename',
|
if tag.tag in ('country-region', 'place', 'placetype', 'placename',
|
||||||
'state', 'city'):
|
'state', 'city'):
|
||||||
@ -290,6 +290,11 @@ class MobiReader(object):
|
|||||||
align = attrib.pop('align').strip()
|
align = attrib.pop('align').strip()
|
||||||
if align:
|
if align:
|
||||||
styles.append('text-align: %s' % align)
|
styles.append('text-align: %s' % align)
|
||||||
|
if mobi_version == 1 and tag.tag == 'hr':
|
||||||
|
tag.tag = 'div'
|
||||||
|
styles.append('page-break-before: always')
|
||||||
|
styles.append('display: block')
|
||||||
|
styles.append('margin: 0')
|
||||||
if styles:
|
if styles:
|
||||||
attrib['style'] = '; '.join(styles)
|
attrib['style'] = '; '.join(styles)
|
||||||
|
|
||||||
@ -300,6 +305,17 @@ class MobiReader(object):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
if sz in size_map.keys():
|
if sz in size_map.keys():
|
||||||
attrib['size'] = size_map[sz]
|
attrib['size'] = size_map[sz]
|
||||||
|
if 'filepos-id' in attrib:
|
||||||
|
attrib['id'] = attrib.pop('filepos-id')
|
||||||
|
if 'filepos' in attrib:
|
||||||
|
filepos = int(attrib.pop('filepos'))
|
||||||
|
attrib['href'] = "#filepos%d" % filepos
|
||||||
|
if tag.tag == 'img':
|
||||||
|
recindex = None
|
||||||
|
for attr in self.IMAGE_ATTRS:
|
||||||
|
recindex = attrib.pop(attr, None) or recindex
|
||||||
|
if recindex is not None:
|
||||||
|
attrib['src'] = 'images/%s.jpg' % recindex
|
||||||
|
|
||||||
def create_opf(self, htmlfile, guide=None):
|
def create_opf(self, htmlfile, guide=None):
|
||||||
mi = self.book_header.exth.mi
|
mi = self.book_header.exth.mi
|
||||||
@ -399,37 +415,39 @@ class MobiReader(object):
|
|||||||
|
|
||||||
|
|
||||||
def replace_page_breaks(self):
|
def replace_page_breaks(self):
|
||||||
self.processed_html = self.PAGE_BREAK_PAT.sub('<br style="page-break-after:always" />',
|
self.processed_html = self.PAGE_BREAK_PAT.sub(
|
||||||
|
'<div style="page-break-after: always; margin: 0; display: block" />',
|
||||||
self.processed_html)
|
self.processed_html)
|
||||||
|
|
||||||
def add_anchors(self):
|
def add_anchors(self):
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
print 'Adding anchors...'
|
print 'Adding anchors...'
|
||||||
positions = set([])
|
positions = set([])
|
||||||
link_pattern = re.compile(r'<[^<>]+filepos=[\'"]{0,1}(\d+)[^<>]*>', re.IGNORECASE)
|
link_pattern = re.compile(r'''<[^<>]+filepos=['"]{0,1}(\d+)[^<>]*>''',
|
||||||
|
re.IGNORECASE)
|
||||||
for match in link_pattern.finditer(self.mobi_html):
|
for match in link_pattern.finditer(self.mobi_html):
|
||||||
positions.add(int(match.group(1)))
|
positions.add(int(match.group(1)))
|
||||||
positions = list(positions)
|
|
||||||
positions.sort()
|
|
||||||
pos = 0
|
pos = 0
|
||||||
self.processed_html = ''
|
self.processed_html = ''
|
||||||
for end in positions:
|
end_tag_re = re.compile(r'<\s*/')
|
||||||
|
for end in sorted(positions):
|
||||||
if end == 0:
|
if end == 0:
|
||||||
continue
|
continue
|
||||||
oend = end
|
oend = end
|
||||||
l = self.mobi_html.find('<', end)
|
l = self.mobi_html.find('<', end)
|
||||||
r = self.mobi_html.find('>', end)
|
r = self.mobi_html.find('>', end)
|
||||||
if r > -1 and r < l: # Move out of tag
|
anchor = '<a id="filepos%d"></a>'
|
||||||
|
if r > -1 and (r < l or l == end or l == -1):
|
||||||
|
p = self.mobi_html.rfind('<', 0, end + 1)
|
||||||
|
if pos < end and p > -1 and \
|
||||||
|
not end_tag_re.match(self.mobi_html[p:r]):
|
||||||
|
anchor = ' filepos-id="filepos%d"'
|
||||||
|
end = r
|
||||||
|
else:
|
||||||
end = r + 1
|
end = r + 1
|
||||||
self.processed_html += self.mobi_html[pos:end] + '<a id="filepos%d" name="filepos%d"></a>'%(oend, oend)
|
self.processed_html += self.mobi_html[pos:end] + (anchor % oend)
|
||||||
pos = end
|
pos = end
|
||||||
|
|
||||||
self.processed_html += self.mobi_html[pos:]
|
self.processed_html += self.mobi_html[pos:]
|
||||||
fpat = re.compile(r'filepos=[\'"]{0,1}(\d+)[\'"]{0,1}', re.IGNORECASE)
|
|
||||||
def fpos_to_href(match):
|
|
||||||
return fpat.sub('href="#filepos%d"'%int(match.group(1)), match.group())
|
|
||||||
self.processed_html = link_pattern.sub(fpos_to_href,
|
|
||||||
self.processed_html)
|
|
||||||
|
|
||||||
def extract_images(self, processed_records, output_dir):
|
def extract_images(self, processed_records, output_dir):
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
@ -455,19 +473,6 @@ class MobiReader(object):
|
|||||||
self.image_names.append(os.path.basename(path))
|
self.image_names.append(os.path.basename(path))
|
||||||
im.convert('RGB').save(open(path, 'wb'), format='JPEG')
|
im.convert('RGB').save(open(path, 'wb'), format='JPEG')
|
||||||
|
|
||||||
def fix_images(match):
|
|
||||||
tag = match.group()
|
|
||||||
for pat in self.IMAGE_PATS:
|
|
||||||
m = pat.search(tag)
|
|
||||||
if m:
|
|
||||||
return pat.sub(' src="images/%s.jpg"'%m.group(1), tag)
|
|
||||||
|
|
||||||
|
|
||||||
if hasattr(self, 'processed_html'):
|
|
||||||
self.processed_html = \
|
|
||||||
re.compile(r'<img (.*?)>', re.IGNORECASE|re.DOTALL)\
|
|
||||||
.sub(fix_images, self.processed_html)
|
|
||||||
|
|
||||||
def get_metadata(stream):
|
def get_metadata(stream):
|
||||||
mr = MobiReader(stream)
|
mr = MobiReader(stream)
|
||||||
if mr.book_header.exth is None:
|
if mr.book_header.exth is None:
|
||||||
|
@ -296,9 +296,11 @@ class Serializer(object):
|
|||||||
class MobiWriter(object):
|
class MobiWriter(object):
|
||||||
COLLAPSE_RE = re.compile(r'[ \t\r\n\v]+')
|
COLLAPSE_RE = re.compile(r'[ \t\r\n\v]+')
|
||||||
|
|
||||||
def __init__(self, compression=None, imagemax=None):
|
def __init__(self, compression=None, imagemax=None,
|
||||||
|
prefer_author_sort=False):
|
||||||
self._compression = compression or UNCOMPRESSED
|
self._compression = compression or UNCOMPRESSED
|
||||||
self._imagemax = imagemax or OTHER_MAX_IMAGE_SIZE
|
self._imagemax = imagemax or OTHER_MAX_IMAGE_SIZE
|
||||||
|
self._prefer_author_sort = prefer_author_sort
|
||||||
|
|
||||||
def dump(self, oeb, path):
|
def dump(self, oeb, path):
|
||||||
if hasattr(path, 'write'):
|
if hasattr(path, 'write'):
|
||||||
@ -457,12 +459,19 @@ class MobiWriter(object):
|
|||||||
for term in oeb.metadata:
|
for term in oeb.metadata:
|
||||||
if term not in EXTH_CODES: continue
|
if term not in EXTH_CODES: continue
|
||||||
code = EXTH_CODES[term]
|
code = EXTH_CODES[term]
|
||||||
for item in oeb.metadata[term]:
|
items = oeb.metadata[term]
|
||||||
|
if term == 'creator':
|
||||||
|
if self._prefer_author_sort:
|
||||||
|
creators = [unicode(c.file_as or c) for c in items]
|
||||||
|
else:
|
||||||
|
creators = [unicode(c) for c in items]
|
||||||
|
items = ['; '.join(creators)]
|
||||||
|
for item in items:
|
||||||
data = self.COLLAPSE_RE.sub(' ', unicode(item))
|
data = self.COLLAPSE_RE.sub(' ', unicode(item))
|
||||||
if term == 'identifier':
|
if term == 'identifier':
|
||||||
if data.lower().startswith('urn:isbn:'):
|
if data.lower().startswith('urn:isbn:'):
|
||||||
data = data[9:]
|
data = data[9:]
|
||||||
elif item.get('scheme', '').lower() == 'isbn':
|
elif item.scheme.lower() == 'isbn':
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
@ -535,6 +544,9 @@ def config(defaults=None):
|
|||||||
help=_('Render HTML tables as blocks of text instead of actual '
|
help=_('Render HTML tables as blocks of text instead of actual '
|
||||||
'tables. This is neccessary if the HTML contains very large '
|
'tables. This is neccessary if the HTML contains very large '
|
||||||
'or complex tables.'))
|
'or complex tables.'))
|
||||||
|
mobi('prefer_author_sort', ['--prefer-author-sort'], default=False,
|
||||||
|
help=_('When present, use the author sorting information for '
|
||||||
|
'generating the Mobipocket author metadata.'))
|
||||||
profiles = c.add_group('profiles', _('Device renderer profiles. '
|
profiles = c.add_group('profiles', _('Device renderer profiles. '
|
||||||
'Affects conversion of font sizes, image rescaling and rasterization '
|
'Affects conversion of font sizes, image rescaling and rasterization '
|
||||||
'of tables. Valid profiles are: %s.') % ', '.join(_profiles))
|
'of tables. Valid profiles are: %s.') % ', '.join(_profiles))
|
||||||
@ -594,7 +606,8 @@ def oeb2mobi(opts, inpath):
|
|||||||
trimmer.transform(oeb, context)
|
trimmer.transform(oeb, context)
|
||||||
mobimlizer = MobiMLizer(ignore_tables=opts.ignore_tables)
|
mobimlizer = MobiMLizer(ignore_tables=opts.ignore_tables)
|
||||||
mobimlizer.transform(oeb, context)
|
mobimlizer.transform(oeb, context)
|
||||||
writer = MobiWriter(compression=compression, imagemax=imagemax)
|
writer = MobiWriter(compression=compression, imagemax=imagemax,
|
||||||
|
prefer_author_sort=opts.prefer_author_sort)
|
||||||
writer.dump(oeb, outpath)
|
writer.dump(oeb, outpath)
|
||||||
run_plugins_on_postprocess(outpath, 'mobi')
|
run_plugins_on_postprocess(outpath, 'mobi')
|
||||||
logger.info(_('Output written to ') + outpath)
|
logger.info(_('Output written to ') + outpath)
|
||||||
|
@ -109,6 +109,7 @@ class Stylizer(object):
|
|||||||
STYLESHEETS = {}
|
STYLESHEETS = {}
|
||||||
|
|
||||||
def __init__(self, tree, path, oeb, profile=PROFILES['PRS505']):
|
def __init__(self, tree, path, oeb, profile=PROFILES['PRS505']):
|
||||||
|
self.oeb = oeb
|
||||||
self.profile = profile
|
self.profile = profile
|
||||||
self.logger = oeb.logger
|
self.logger = oeb.logger
|
||||||
item = oeb.manifest.hrefs[path]
|
item = oeb.manifest.hrefs[path]
|
||||||
@ -117,7 +118,7 @@ class Stylizer(object):
|
|||||||
stylesheets = [HTML_CSS_STYLESHEET]
|
stylesheets = [HTML_CSS_STYLESHEET]
|
||||||
head = xpath(tree, '/h:html/h:head')[0]
|
head = xpath(tree, '/h:html/h:head')[0]
|
||||||
parser = cssutils.CSSParser()
|
parser = cssutils.CSSParser()
|
||||||
parser.setFetcher(lambda path: ('utf-8', oeb.container.read(path)))
|
parser.setFetcher(self._fetch_css_file)
|
||||||
for elem in head:
|
for elem in head:
|
||||||
if elem.tag == XHTML('style') and elem.text \
|
if elem.tag == XHTML('style') and elem.text \
|
||||||
and elem.get('type', CSS_MIME) in OEB_STYLES:
|
and elem.get('type', CSS_MIME) in OEB_STYLES:
|
||||||
@ -138,8 +139,7 @@ class Stylizer(object):
|
|||||||
if path in self.STYLESHEETS:
|
if path in self.STYLESHEETS:
|
||||||
stylesheet = self.STYLESHEETS[path]
|
stylesheet = self.STYLESHEETS[path]
|
||||||
else:
|
else:
|
||||||
data = XHTML_CSS_NAMESPACE
|
data = self._fetch_css_file(path)[1]
|
||||||
data += oeb.manifest.hrefs[path].data
|
|
||||||
stylesheet = parser.parseString(data, href=path)
|
stylesheet = parser.parseString(data, href=path)
|
||||||
stylesheet.namespaces['h'] = XHTML_NS
|
stylesheet.namespaces['h'] = XHTML_NS
|
||||||
self.STYLESHEETS[path] = stylesheet
|
self.STYLESHEETS[path] = stylesheet
|
||||||
@ -167,6 +167,14 @@ class Stylizer(object):
|
|||||||
for elem in xpath(tree, '//h:*[@style]'):
|
for elem in xpath(tree, '//h:*[@style]'):
|
||||||
self.style(elem)._apply_style_attr()
|
self.style(elem)._apply_style_attr()
|
||||||
|
|
||||||
|
def _fetch_css_file(self, path):
|
||||||
|
hrefs = self.oeb.manifest.hrefs
|
||||||
|
if path not in hrefs:
|
||||||
|
return (None, None)
|
||||||
|
data = hrefs[path].data
|
||||||
|
data = XHTML_CSS_NAMESPACE + data
|
||||||
|
return ('utf-8', data)
|
||||||
|
|
||||||
def flatten_rule(self, rule, href, index):
|
def flatten_rule(self, rule, href, index):
|
||||||
results = []
|
results = []
|
||||||
if isinstance(rule, CSSStyleRule):
|
if isinstance(rule, CSSStyleRule):
|
||||||
|
@ -13,13 +13,9 @@ from urlparse import urldefrag
|
|||||||
from lxml import etree
|
from lxml import etree
|
||||||
import cssutils
|
import cssutils
|
||||||
from calibre.ebooks.oeb.base import XPNSMAP, CSS_MIME, OEB_DOCS
|
from calibre.ebooks.oeb.base import XPNSMAP, CSS_MIME, OEB_DOCS
|
||||||
|
from calibre.ebooks.oeb.base import LINK_SELECTORS, CSSURL_RE
|
||||||
from calibre.ebooks.oeb.base import urlnormalize
|
from calibre.ebooks.oeb.base import urlnormalize
|
||||||
|
|
||||||
LINK_SELECTORS = []
|
|
||||||
for expr in ('//h:link/@href', '//h:img/@src', '//h:object/@data',
|
|
||||||
'//*/@xl:href'):
|
|
||||||
LINK_SELECTORS.append(etree.XPath(expr, namespaces=XPNSMAP))
|
|
||||||
|
|
||||||
class ManifestTrimmer(object):
|
class ManifestTrimmer(object):
|
||||||
def transform(self, oeb, context):
|
def transform(self, oeb, context):
|
||||||
oeb.logger.info('Trimming unused files from manifest...')
|
oeb.logger.info('Trimming unused files from manifest...')
|
||||||
@ -53,15 +49,13 @@ class ManifestTrimmer(object):
|
|||||||
if found not in used:
|
if found not in used:
|
||||||
new.add(found)
|
new.add(found)
|
||||||
elif item.media_type == CSS_MIME:
|
elif item.media_type == CSS_MIME:
|
||||||
def replacer(uri):
|
for match in CSSURL_RE.finditer(item.data):
|
||||||
absuri = item.abshref(urlnormalize(uri))
|
href = match.group('url')
|
||||||
if absuri in oeb.manifest.hrefs:
|
href = item.abshref(urlnormalize(href))
|
||||||
|
if href in oeb.manifest.hrefs:
|
||||||
found = oeb.manifest.hrefs[href]
|
found = oeb.manifest.hrefs[href]
|
||||||
if found not in used:
|
if found not in used:
|
||||||
new.add(found)
|
new.add(found)
|
||||||
return uri
|
|
||||||
sheet = cssutils.parseString(item.data, href=item.href)
|
|
||||||
cssutils.replaceUrls(sheet, replacer)
|
|
||||||
used.update(new)
|
used.update(new)
|
||||||
unchecked = new
|
unchecked = new
|
||||||
for item in oeb.manifest.values():
|
for item in oeb.manifest.values():
|
||||||
|
@ -18,7 +18,7 @@ from calibre.gui2 import error_dialog, choose_images, pixmap_to_data, ResizableD
|
|||||||
from calibre.ebooks.epub.from_any import SOURCE_FORMATS, config as epubconfig
|
from calibre.ebooks.epub.from_any import SOURCE_FORMATS, config as epubconfig
|
||||||
from calibre.ebooks.metadata import MetaInformation
|
from calibre.ebooks.metadata import MetaInformation
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.ebooks.metadata.opf import OPFCreator
|
from calibre.ebooks.metadata.opf2 import OPFCreator
|
||||||
from calibre.ebooks.metadata import authors_to_string, string_to_authors
|
from calibre.ebooks.metadata import authors_to_string, string_to_authors
|
||||||
|
|
||||||
|
|
||||||
@ -62,6 +62,7 @@ class Config(ResizableDialog, Ui_Dialog):
|
|||||||
self.toc_title_label.setVisible(False)
|
self.toc_title_label.setVisible(False)
|
||||||
self.opt_rescale_images.setVisible(False)
|
self.opt_rescale_images.setVisible(False)
|
||||||
self.opt_ignore_tables.setVisible(False)
|
self.opt_ignore_tables.setVisible(False)
|
||||||
|
self.opt_prefer_author_sort.setVisible(False)
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.__w = []
|
self.__w = []
|
||||||
|
@ -105,6 +105,36 @@
|
|||||||
<string>Book Cover</string>
|
<string>Book Cover</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="_2" >
|
<layout class="QGridLayout" name="_2" >
|
||||||
|
<item row="0" column="0" >
|
||||||
|
<layout class="QHBoxLayout" name="_3" >
|
||||||
|
<item>
|
||||||
|
<widget class="ImageView" name="cover" >
|
||||||
|
<property name="text" >
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap" >
|
||||||
|
<pixmap resource="../images.qrc" >:/images/book.svg</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents" >
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment" >
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" >
|
||||||
|
<widget class="QCheckBox" name="opt_prefer_metadata_cover" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Use cover from &source file</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked" >
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="1" column="0" >
|
<item row="1" column="0" >
|
||||||
<layout class="QVBoxLayout" name="_4" >
|
<layout class="QVBoxLayout" name="_4" >
|
||||||
<property name="spacing" >
|
<property name="spacing" >
|
||||||
@ -156,36 +186,6 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" >
|
|
||||||
<widget class="QCheckBox" name="opt_prefer_metadata_cover" >
|
|
||||||
<property name="text" >
|
|
||||||
<string>Use cover from &source file</string>
|
|
||||||
</property>
|
|
||||||
<property name="checked" >
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0" >
|
|
||||||
<layout class="QHBoxLayout" name="_3" >
|
|
||||||
<item>
|
|
||||||
<widget class="ImageView" name="cover" >
|
|
||||||
<property name="text" >
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="pixmap" >
|
|
||||||
<pixmap resource="../images.qrc" >:/images/book.svg</pixmap>
|
|
||||||
</property>
|
|
||||||
<property name="scaledContents" >
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="alignment" >
|
|
||||||
<set>Qt::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
<zorder>opt_prefer_metadata_cover</zorder>
|
<zorder>opt_prefer_metadata_cover</zorder>
|
||||||
<zorder></zorder>
|
<zorder></zorder>
|
||||||
@ -486,6 +486,27 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="6" column="0" >
|
||||||
|
<widget class="QCheckBox" name="opt_prefer_author_sort" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>&Use author sort to set author field in output</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0" >
|
||||||
|
<widget class="QCheckBox" name="opt_no_justification" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>No text &justification</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0" >
|
||||||
|
<widget class="QCheckBox" name="opt_linearize_tables" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>&Linearize tables</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -675,11 +696,7 @@
|
|||||||
<item row="0" column="0" colspan="2" >
|
<item row="0" column="0" colspan="2" >
|
||||||
<widget class="QLabel" name="label_8" >
|
<widget class="QLabel" name="label_8" >
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
<string><p>You can control how calibre detects chapters using a XPath expression. To learn how to use XPath expressions see the <a href="http://calibre.kovidgoyal.net/user_manual/xpath.html">XPath tutorial</a></p></string>
|
||||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
|
||||||
p, li { white-space: pre-wrap; }
|
|
||||||
</style></head><body style=" font-family:'DejaVu Sans'; font-size:10pt; font-weight:400; font-style:normal;">
|
|
||||||
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You can control how calibre detects chapters using a XPath expression. To learn how to use XPath expressions see the <a href="https://calibre.kovidgoyal.net/user_manual/xpath.html"><span style=" text-decoration: underline; color:#0000ff;">XPath tutorial</span></a></p></body></html></string>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="textFormat" >
|
<property name="textFormat" >
|
||||||
<enum>Qt::RichText</enum>
|
<enum>Qt::RichText</enum>
|
||||||
@ -687,6 +704,9 @@ p, li { white-space: pre-wrap; }
|
|||||||
<property name="wordWrap" >
|
<property name="wordWrap" >
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="openExternalLinks" >
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1" >
|
<item row="2" column="1" >
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<iconset resource="../images.qrc" >
|
<iconset resource="../images.qrc" >
|
||||||
<normaloff>:/images/view.svg</normaloff>:/images/view.svg</iconset>
|
<normaloff>:/images/view.svg</normaloff>:/images/view.svg</iconset>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" >
|
<layout class="QGridLayout" name="gridLayout" >
|
||||||
<item row="0" column="0" >
|
<item row="0" column="0" >
|
||||||
<widget class="QPlainTextEdit" name="log" >
|
<widget class="QPlainTextEdit" name="log" >
|
||||||
<property name="undoRedoEnabled" >
|
<property name="undoRedoEnabled" >
|
||||||
@ -30,10 +30,34 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="0" >
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||||
|
<property name="standardButtons" >
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../images.qrc" />
|
<include location="../images.qrc" />
|
||||||
</resources>
|
</resources>
|
||||||
<connections/>
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel" >
|
||||||
|
<x>617</x>
|
||||||
|
<y>442</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel" >
|
||||||
|
<x>206</x>
|
||||||
|
<y>-5</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -18,3 +18,5 @@ class Config(_Config):
|
|||||||
self.opt_profile.setVisible(False)
|
self.opt_profile.setVisible(False)
|
||||||
self.opt_dont_split_on_page_breaks.setVisible(False)
|
self.opt_dont_split_on_page_breaks.setVisible(False)
|
||||||
self.opt_preserve_tag_structure.setVisible(False)
|
self.opt_preserve_tag_structure.setVisible(False)
|
||||||
|
self.opt_linearize_tables.setVisible(False)
|
||||||
|
self.opt_no_justification.setVisible(False)
|
@ -10,8 +10,8 @@ Scheduler for automated recipe downloads
|
|||||||
import sys, copy, time
|
import sys, copy, time
|
||||||
from datetime import datetime, timedelta, date
|
from datetime import datetime, timedelta, date
|
||||||
from PyQt4.Qt import QDialog, QApplication, QLineEdit, QPalette, SIGNAL, QBrush, \
|
from PyQt4.Qt import QDialog, QApplication, QLineEdit, QPalette, SIGNAL, QBrush, \
|
||||||
QColor, QAbstractListModel, Qt, QVariant, QFont, QIcon, \
|
QColor, QAbstractItemModel, Qt, QVariant, QFont, QIcon, \
|
||||||
QFile, QObject, QTimer, QMutex, QMenu, QAction, QTime
|
QFile, QObject, QTimer, QMutex, QMenu, QAction, QTime, QModelIndex
|
||||||
|
|
||||||
from calibre import english_sort
|
from calibre import english_sort
|
||||||
from calibre.gui2.dialogs.scheduler_ui import Ui_Dialog
|
from calibre.gui2.dialogs.scheduler_ui import Ui_Dialog
|
||||||
@ -30,6 +30,7 @@ class Recipe(object):
|
|||||||
self.id = id
|
self.id = id
|
||||||
self.title = getattr(recipe_class, 'title', None)
|
self.title = getattr(recipe_class, 'title', None)
|
||||||
self.description = getattr(recipe_class, 'description', None)
|
self.description = getattr(recipe_class, 'description', None)
|
||||||
|
self.language = getattr(recipe_class, 'language', _('Unknown'))
|
||||||
self.last_downloaded = datetime.fromordinal(1)
|
self.last_downloaded = datetime.fromordinal(1)
|
||||||
self.downloading = False
|
self.downloading = False
|
||||||
self.builtin = builtin
|
self.builtin = builtin
|
||||||
@ -86,12 +87,12 @@ def load_recipes():
|
|||||||
recipes.append(r)
|
recipes.append(r)
|
||||||
return recipes
|
return recipes
|
||||||
|
|
||||||
class RecipeModel(QAbstractListModel, SearchQueryParser):
|
class RecipeModel(QAbstractItemModel, SearchQueryParser):
|
||||||
|
|
||||||
LOCATIONS = ['all']
|
LOCATIONS = ['all']
|
||||||
|
|
||||||
def __init__(self, db, *args):
|
def __init__(self, db, *args):
|
||||||
QAbstractListModel.__init__(self, *args)
|
QAbstractItemModel.__init__(self, *args)
|
||||||
SearchQueryParser.__init__(self)
|
SearchQueryParser.__init__(self)
|
||||||
self.default_icon = QIcon(':/images/news.svg')
|
self.default_icon = QIcon(':/images/news.svg')
|
||||||
self.custom_icon = QIcon(':/images/user_profile.svg')
|
self.custom_icon = QIcon(':/images/user_profile.svg')
|
||||||
@ -100,7 +101,10 @@ class RecipeModel(QAbstractListModel, SearchQueryParser):
|
|||||||
recipe = compile_recipe(x[1])
|
recipe = compile_recipe(x[1])
|
||||||
self.recipes.append(Recipe(x[0], recipe, False))
|
self.recipes.append(Recipe(x[0], recipe, False))
|
||||||
self.refresh()
|
self.refresh()
|
||||||
self._map = list(range(len(self.recipes)))
|
self.bold_font = QFont()
|
||||||
|
self.bold_font.setBold(True)
|
||||||
|
self.bold_font = QVariant(self.bold_font)
|
||||||
|
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
sr = load_recipes()
|
sr = load_recipes()
|
||||||
@ -110,6 +114,34 @@ class RecipeModel(QAbstractListModel, SearchQueryParser):
|
|||||||
recipe.last_downloaded = sr[sr.index(recipe)].last_downloaded
|
recipe.last_downloaded = sr[sr.index(recipe)].last_downloaded
|
||||||
|
|
||||||
self.recipes.sort()
|
self.recipes.sort()
|
||||||
|
self.num_of_recipes = len(self.recipes)
|
||||||
|
|
||||||
|
self.category_map = {}
|
||||||
|
for r in self.recipes:
|
||||||
|
category = getattr(r, 'language', _('Unknown'))
|
||||||
|
if not r.builtin:
|
||||||
|
category = _('Custom')
|
||||||
|
if r.schedule is not None:
|
||||||
|
category = _('Scheduled')
|
||||||
|
if category not in self.category_map.keys():
|
||||||
|
self.category_map[category] = []
|
||||||
|
self.category_map[category].append(r)
|
||||||
|
|
||||||
|
self.categories = sorted(self.category_map.keys(), cmp=self.sort_categories)
|
||||||
|
self._map = dict(self.category_map)
|
||||||
|
|
||||||
|
def sort_categories(self, x, y):
|
||||||
|
|
||||||
|
def decorate(x):
|
||||||
|
if x == _('Scheduled'):
|
||||||
|
x = '0' + x
|
||||||
|
elif x == _('Custom'):
|
||||||
|
x = '1' + x
|
||||||
|
else:
|
||||||
|
x = '2' + x
|
||||||
|
return x
|
||||||
|
|
||||||
|
return cmp(decorate(x), decorate(y))
|
||||||
|
|
||||||
|
|
||||||
def universal_set(self):
|
def universal_set(self):
|
||||||
@ -129,36 +161,46 @@ class RecipeModel(QAbstractListModel, SearchQueryParser):
|
|||||||
try:
|
try:
|
||||||
results = self.parse(unicode(query))
|
results = self.parse(unicode(query))
|
||||||
except ParseException:
|
except ParseException:
|
||||||
self._map = list(range(len(self.recipes)))
|
self._map = dict(self.category_map)
|
||||||
else:
|
else:
|
||||||
self._map = []
|
self._map = {}
|
||||||
for i, recipe in enumerate(self.recipes):
|
for category in self.categories:
|
||||||
|
self._map[category] = []
|
||||||
|
for recipe in self.category_map[category]:
|
||||||
if recipe in results:
|
if recipe in results:
|
||||||
self._map.append(i)
|
self._map[category].append(recipe)
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def resort(self):
|
def resort(self):
|
||||||
self.recipes.sort()
|
self.recipes.sort()
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def columnCount(self, *args):
|
def index(self, row, column, parent):
|
||||||
return 1
|
return self.createIndex(row, column, parent.row() if parent.isValid() else -1)
|
||||||
|
|
||||||
def rowCount(self, *args):
|
def parent(self, index):
|
||||||
return len(self._map)
|
if index.internalId() == -1:
|
||||||
|
return QModelIndex()
|
||||||
|
return self.createIndex(index.internalId(), 0, -1)
|
||||||
|
|
||||||
|
def columnCount(self, parent):
|
||||||
|
if not parent.isValid() or not parent.parent().isValid():
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def rowCount(self, parent):
|
||||||
|
if not parent.isValid():
|
||||||
|
return len(self.categories)
|
||||||
|
if not parent.parent().isValid():
|
||||||
|
category = self.categories[parent.row()]
|
||||||
|
return len(self._map[category])
|
||||||
|
return 0
|
||||||
|
|
||||||
def data(self, index, role):
|
def data(self, index, role):
|
||||||
recipe = self.recipes[self._map[index.row()]]
|
if index.parent().isValid():
|
||||||
if role == Qt.FontRole:
|
category = self.categories[index.parent().row()]
|
||||||
if recipe.schedule is not None:
|
recipe = self._map[category][index.row()]
|
||||||
font = QFont()
|
if role == Qt.DisplayRole:
|
||||||
font.setBold(True)
|
|
||||||
return QVariant(font)
|
|
||||||
if not recipe.builtin:
|
|
||||||
font = QFont()
|
|
||||||
font.setItalic(True)
|
|
||||||
return QVariant(font)
|
|
||||||
elif role == Qt.DisplayRole:
|
|
||||||
return QVariant(recipe.title)
|
return QVariant(recipe.title)
|
||||||
elif role == Qt.UserRole:
|
elif role == Qt.UserRole:
|
||||||
return recipe
|
return recipe
|
||||||
@ -170,7 +212,13 @@ class RecipeModel(QAbstractListModel, SearchQueryParser):
|
|||||||
elif QFile().exists(icon_path):
|
elif QFile().exists(icon_path):
|
||||||
icon = QIcon(icon_path)
|
icon = QIcon(icon_path)
|
||||||
return QVariant(icon)
|
return QVariant(icon)
|
||||||
|
else:
|
||||||
|
category = self.categories[index.row()]
|
||||||
|
if role == Qt.DisplayRole:
|
||||||
|
num = len(self._map[category])
|
||||||
|
return QVariant(category + ' [%d]'%num)
|
||||||
|
elif role == Qt.FontRole:
|
||||||
|
return self.bold_font
|
||||||
return NONE
|
return NONE
|
||||||
|
|
||||||
def update_recipe_schedule(self, recipe):
|
def update_recipe_schedule(self, recipe):
|
||||||
@ -241,8 +289,7 @@ class SchedulerDialog(QDialog, Ui_Dialog):
|
|||||||
self._model = RecipeModel(db)
|
self._model = RecipeModel(db)
|
||||||
self.current_recipe = None
|
self.current_recipe = None
|
||||||
self.recipes.setModel(self._model)
|
self.recipes.setModel(self._model)
|
||||||
self.connect(self.recipes, SIGNAL('activated(QModelIndex)'), self.show_recipe)
|
self.recipes.currentChanged = self.currentChanged
|
||||||
self.connect(self.recipes, SIGNAL('clicked(QModelIndex)'), self.show_recipe)
|
|
||||||
self.connect(self.username, SIGNAL('textEdited(QString)'), self.set_account_info)
|
self.connect(self.username, SIGNAL('textEdited(QString)'), self.set_account_info)
|
||||||
self.connect(self.password, SIGNAL('textEdited(QString)'), self.set_account_info)
|
self.connect(self.password, SIGNAL('textEdited(QString)'), self.set_account_info)
|
||||||
self.connect(self.schedule, SIGNAL('stateChanged(int)'), self.do_schedule)
|
self.connect(self.schedule, SIGNAL('stateChanged(int)'), self.do_schedule)
|
||||||
@ -258,11 +305,15 @@ class SchedulerDialog(QDialog, Ui_Dialog):
|
|||||||
self.connect(self.download, SIGNAL('clicked()'), self.download_now)
|
self.connect(self.download, SIGNAL('clicked()'), self.download_now)
|
||||||
self.search.setFocus(Qt.OtherFocusReason)
|
self.search.setFocus(Qt.OtherFocusReason)
|
||||||
self.old_news.setValue(gconf['oldest_news'])
|
self.old_news.setValue(gconf['oldest_news'])
|
||||||
self.rnumber.setText(_('%d recipes')%self._model.rowCount(None))
|
self.rnumber.setText(_('%d recipes')%self._model.num_of_recipes)
|
||||||
for day in (_('day'), _('Monday'), _('Tuesday'), _('Wednesday'),
|
for day in (_('day'), _('Monday'), _('Tuesday'), _('Wednesday'),
|
||||||
_('Thursday'), _('Friday'), _('Saturday'), _('Sunday')):
|
_('Thursday'), _('Friday'), _('Saturday'), _('Sunday')):
|
||||||
self.day.addItem(day)
|
self.day.addItem(day)
|
||||||
|
|
||||||
|
def currentChanged(self, current, previous):
|
||||||
|
if current.parent().isValid():
|
||||||
|
self.show_recipe(current)
|
||||||
|
|
||||||
def download_now(self):
|
def download_now(self):
|
||||||
recipe = self._model.data(self.recipes.currentIndex(), Qt.UserRole)
|
recipe = self._model.data(self.recipes.currentIndex(), Qt.UserRole)
|
||||||
self.emit(SIGNAL('download_now(PyQt_PyObject)'), recipe)
|
self.emit(SIGNAL('download_now(PyQt_PyObject)'), recipe)
|
||||||
@ -305,6 +356,7 @@ class SchedulerDialog(QDialog, Ui_Dialog):
|
|||||||
hour, minute = t.hour(), t.minute()
|
hour, minute = t.hour(), t.minute()
|
||||||
recipe.schedule = encode_schedule(day_of_week, hour, minute)
|
recipe.schedule = encode_schedule(day_of_week, hour, minute)
|
||||||
else:
|
else:
|
||||||
|
recipe.schedule = None
|
||||||
if recipe in recipes:
|
if recipe in recipes:
|
||||||
recipes.remove(recipe)
|
recipes.remove(recipe)
|
||||||
save_recipes(recipes)
|
save_recipes(recipes)
|
||||||
@ -359,7 +411,6 @@ class SchedulerDialog(QDialog, Ui_Dialog):
|
|||||||
else:
|
else:
|
||||||
self.last_downloaded.setText(_('Last downloaded: never'))
|
self.last_downloaded.setText(_('Last downloaded: never'))
|
||||||
|
|
||||||
|
|
||||||
class Scheduler(QObject):
|
class Scheduler(QObject):
|
||||||
|
|
||||||
INTERVAL = 1 # minutes
|
INTERVAL = 1 # minutes
|
||||||
@ -434,7 +485,7 @@ class Scheduler(QObject):
|
|||||||
day_matches = day > 6 or day == now.tm_wday
|
day_matches = day > 6 or day == now.tm_wday
|
||||||
tnow = now.tm_hour*60 + now.tm_min
|
tnow = now.tm_hour*60 + now.tm_min
|
||||||
matches = day_matches and (hour*60+minute) < tnow
|
matches = day_matches and (hour*60+minute) < tnow
|
||||||
if matches and nowt.toordinal() < date.today().toordinal():
|
if matches and recipe.last_downloaded.toordinal() < date.today().toordinal():
|
||||||
needs_downloading.add(recipe)
|
needs_downloading.add(recipe)
|
||||||
|
|
||||||
self.debug('Needs downloading:', needs_downloading)
|
self.debug('Needs downloading:', needs_downloading)
|
||||||
@ -466,7 +517,7 @@ class Scheduler(QObject):
|
|||||||
recipe = self.recipes[self.recipes.index(recipe)]
|
recipe = self.recipes[self.recipes.index(recipe)]
|
||||||
now = datetime.utcnow()
|
now = datetime.utcnow()
|
||||||
d = now - recipe.last_downloaded
|
d = now - recipe.last_downloaded
|
||||||
if recipe.schedule is not None:
|
if recipe.schedule is not None and recipe.schedule < 1e4:
|
||||||
interval = timedelta(days=recipe.schedule)
|
interval = timedelta(days=recipe.schedule)
|
||||||
if abs(d - interval) < timedelta(hours=1):
|
if abs(d - interval) < timedelta(hours=1):
|
||||||
recipe.last_downloaded += interval
|
recipe.last_downloaded += interval
|
||||||
|
@ -24,8 +24,20 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout" >
|
<layout class="QVBoxLayout" name="verticalLayout" >
|
||||||
<item>
|
<item>
|
||||||
<widget class="QListView" name="recipes" >
|
<widget class="QTreeView" name="recipes" >
|
||||||
<property name="alternatingRowColors" >
|
<property name="showDropIndicator" stdset="0" >
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize" >
|
||||||
|
<size>
|
||||||
|
<width>16</width>
|
||||||
|
<height>16</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="animated" >
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="headerHidden" >
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
|
BIN
src/calibre/gui2/images/news/el_mercurio_chile.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
src/calibre/gui2/images/news/elmundo.png
Normal file
After Width: | Height: | Size: 550 B |
BIN
src/calibre/gui2/images/news/estadao.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
src/calibre/gui2/images/news/granma.png
Normal file
After Width: | Height: | Size: 685 B |
BIN
src/calibre/gui2/images/news/jb_online.png
Normal file
After Width: | Height: | Size: 942 B |
BIN
src/calibre/gui2/images/news/la_cuarta.png
Normal file
After Width: | Height: | Size: 514 B |
BIN
src/calibre/gui2/images/news/la_tercera.png
Normal file
After Width: | Height: | Size: 534 B |
BIN
src/calibre/gui2/images/news/lanacion_chile.png
Normal file
After Width: | Height: | Size: 393 B |
BIN
src/calibre/gui2/images/news/o_globo.png
Normal file
After Width: | Height: | Size: 701 B |
BIN
src/calibre/gui2/images/news/the_oz.png
Normal file
After Width: | Height: | Size: 701 B |
BIN
src/calibre/gui2/images/news/vijesti.png
Normal file
After Width: | Height: | Size: 636 B |
@ -575,6 +575,7 @@ class BooksModel(QAbstractTableModel):
|
|||||||
if column == 'rating':
|
if column == 'rating':
|
||||||
val = 0 if val < 0 else 5 if val > 5 else val
|
val = 0 if val < 0 else 5 if val > 5 else val
|
||||||
val *= 2
|
val *= 2
|
||||||
|
self.db.set_rating(id, val)
|
||||||
elif column == 'series':
|
elif column == 'series':
|
||||||
pat = re.compile(r'\[(\d+)\]')
|
pat = re.compile(r'\[(\d+)\]')
|
||||||
match = pat.search(val)
|
match = pat.search(val)
|
||||||
|
@ -294,7 +294,7 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
self.stack.setCurrentIndex(0)
|
self.stack.setCurrentIndex(0)
|
||||||
try:
|
try:
|
||||||
db = LibraryDatabase2(self.library_path)
|
db = LibraryDatabase2(self.library_path)
|
||||||
except OSError, err:
|
except Exception, err:
|
||||||
error_dialog(self, _('Bad database location'), unicode(err)).exec_()
|
error_dialog(self, _('Bad database location'), unicode(err)).exec_()
|
||||||
dir = unicode(QFileDialog.getExistingDirectory(self,
|
dir = unicode(QFileDialog.getExistingDirectory(self,
|
||||||
_('Choose a location for your ebook library.'), os.path.expanduser('~')))
|
_('Choose a location for your ebook library.'), os.path.expanduser('~')))
|
||||||
@ -1426,10 +1426,10 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
def donate(self, *args):
|
def donate(self, *args):
|
||||||
BUTTON = '''
|
BUTTON = '''
|
||||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
||||||
<input type="hidden" name="cmd" value="_s-xclick">
|
<input type="hidden" name="cmd" value="_s-xclick" />
|
||||||
<input type="hidden" name="hosted_button_id" value="1335186">
|
<input type="hidden" name="hosted_button_id" value="3029467" />
|
||||||
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="">
|
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="Donate to support calibre development" />
|
||||||
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
|
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
|
||||||
</form>
|
</form>
|
||||||
'''
|
'''
|
||||||
MSG = _('is the result of the efforts of many volunteers from all over the world. If you find it useful, please consider donating to support its development.')
|
MSG = _('is the result of the efforts of many volunteers from all over the world. If you find it useful, please consider donating to support its development.')
|
||||||
|
@ -355,6 +355,7 @@ class LibraryDatabase2(LibraryDatabase):
|
|||||||
if isinstance(self.dbpath, unicode):
|
if isinstance(self.dbpath, unicode):
|
||||||
self.dbpath = self.dbpath.encode(filesystem_encoding)
|
self.dbpath = self.dbpath.encode(filesystem_encoding)
|
||||||
self.connect()
|
self.connect()
|
||||||
|
self.is_case_sensitive = not os.path.exists(self.dbpath.replace('metadata.db', 'MeTAdAtA.dB'))
|
||||||
# Upgrade database
|
# Upgrade database
|
||||||
while True:
|
while True:
|
||||||
meth = getattr(self, 'upgrade_version_%d'%self.user_version, None)
|
meth = getattr(self, 'upgrade_version_%d'%self.user_version, None)
|
||||||
|
@ -102,7 +102,7 @@ Device Integration
|
|||||||
|
|
||||||
What devices does |app| support?
|
What devices does |app| support?
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
At the moment |app| has full support for the SONY PRS 500/505/700, Cybook Gen 3 as well as the iPhone. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk.
|
At the moment |app| has full support for the SONY PRS 500/505/700, Cybook Gen 3, Amazon Kindle as well as the iPhone. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk.
|
||||||
|
|
||||||
I used |app| to transfer some books to my reader, and now the SONY software hangs every time I connect the reader?
|
I used |app| to transfer some books to my reader, and now the SONY software hangs every time I connect the reader?
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -161,7 +161,7 @@ class WorkerMother(object):
|
|||||||
self.executable = self.gui_executable = sys.executable
|
self.executable = self.gui_executable = sys.executable
|
||||||
self.prefix = ''
|
self.prefix = ''
|
||||||
if isfrozen:
|
if isfrozen:
|
||||||
fd = getattr(sys, 'frameworks_dir')
|
fd = os.path.realpath(getattr(sys, 'frameworks_dir'))
|
||||||
contents = os.path.dirname(fd)
|
contents = os.path.dirname(fd)
|
||||||
self.gui_executable = os.path.join(contents, 'MacOS',
|
self.gui_executable = os.path.join(contents, 'MacOS',
|
||||||
os.path.basename(sys.executable))
|
os.path.basename(sys.executable))
|
||||||
|
@ -196,7 +196,7 @@ class Server(object):
|
|||||||
|
|
||||||
def calculate_month_trend(self, days=31):
|
def calculate_month_trend(self, days=31):
|
||||||
stats = self.get_slice(date.today()-timedelta(days=days-1), date.today())
|
stats = self.get_slice(date.today()-timedelta(days=days-1), date.today())
|
||||||
fig = plt.figure(2, (8, 3), 96)#, facecolor, edgecolor, frameon, FigureClass)
|
fig = plt.figure(2, (12, 4), 96)#, facecolor, edgecolor, frameon, FigureClass)
|
||||||
ax = fig.add_subplot(111)
|
ax = fig.add_subplot(111)
|
||||||
x = list(range(days-1, -1, -1))
|
x = list(range(days-1, -1, -1))
|
||||||
y = stats.daily_totals
|
y = stats.daily_totals
|
||||||
@ -205,6 +205,17 @@ class Server(object):
|
|||||||
ax.set_ylabel('Income ($)')
|
ax.set_ylabel('Income ($)')
|
||||||
ax.hlines([stats.daily_average], 0, days-1)
|
ax.hlines([stats.daily_average], 0, days-1)
|
||||||
ax.set_xlim([0, days-1])
|
ax.set_xlim([0, days-1])
|
||||||
|
text = u'''\
|
||||||
|
Total: $%(total).2f
|
||||||
|
Daily average: $%(da).2f \u00b1 %(dd).2f
|
||||||
|
Average contribution: $%(ac).2f \u00b1 %(ad).2f
|
||||||
|
Donors per day: %(dpd).2f
|
||||||
|
'''%dict(total=stats.total, da=stats.daily_average,
|
||||||
|
dd=stats.daily_deviation, ac=stats.average,
|
||||||
|
ad=stats.average_deviation,
|
||||||
|
dpd=len(stats.totals)/float(stats.period.days),
|
||||||
|
)
|
||||||
|
text = ax.annotate(text, (0.6, 0.65), textcoords='axes fraction')
|
||||||
fig.savefig(self.MONTH_TRENDS)
|
fig.savefig(self.MONTH_TRENDS)
|
||||||
|
|
||||||
def calculate_trend(self):
|
def calculate_trend(self):
|
||||||
@ -223,7 +234,7 @@ class Server(object):
|
|||||||
x = [m.min for m in _months]
|
x = [m.min for m in _months]
|
||||||
y = [m.total for m in _months]
|
y = [m.total for m in _months]
|
||||||
ml = mdates.MonthLocator() # every month
|
ml = mdates.MonthLocator() # every month
|
||||||
fig = plt.figure(1, (8, 3), 96)#, facecolor, edgecolor, frameon, FigureClass)
|
fig = plt.figure(1, (8, 4), 96)#, facecolor, edgecolor, frameon, FigureClass)
|
||||||
ax = fig.add_subplot(111)
|
ax = fig.add_subplot(111)
|
||||||
ax.bar(x, y, align='center', width=20, color='g')
|
ax.bar(x, y, align='center', width=20, color='g')
|
||||||
ax.xaxis.set_major_locator(ml)
|
ax.xaxis.set_major_locator(ml)
|
||||||
|
@ -25,13 +25,12 @@
|
|||||||
<div>
|
<div>
|
||||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
||||||
<input type="hidden" name="cmd" value="_s-xclick" />
|
<input type="hidden" name="cmd" value="_s-xclick" />
|
||||||
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" />
|
<input type="hidden" name="hosted_button_id" value="3029289" />
|
||||||
|
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="Donate to support calibre development" />
|
||||||
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
|
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
|
||||||
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHbwYJKoZIhvcNAQcEoIIHYDCCB1wCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYBn7jneGiSLVO8rcDrBtOUXL+HftY+CiC47hTntwICio6qqpLKezIryyG8tKcjY58Rcocur/kDwljEutIafVG7XRA7BJL9eZdHAZsZdX04f4dApzkWwR9w6GQhj0kwmO2ZNE878UcgGZBve4qQKWM8bf2pMY7vJwCNoo6ozpIi3VTELMAkGBSsOAwIaBQAwgewGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIBTALt7s1gJmAgcjEAwUMRYeIdIOE/yi0Y5vrVKBFxOUCbqTx/lu3Rk4EHsODZXLHT+BDA5WSWYO3AXfv2Lmlv1kJ7jWrjUVirYoQ5M4qdIhY9DtvPioIMMRoTJmYM9JKH8n2TWcjJ1XIzIuDP4zn8/Ya9hap3RHOrj2RBj89g7iSuFRsjoA0PYZgtWAKwR7g3LLpjRachn041JO55BEd3YWUgorNQeo3WEHgowLFfTWgFFePkm8OoWA1klWkYp4S07IhX5NaRc8OegkdshpkiIHGAKCCA4cwggODMIIC7KADAgECAgEAMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTAeFw0wNDAyMTMxMDEzMTVaFw0zNTAyMTMxMDEzMTVaMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwUdO3fxEzEtcnI7ZKZL412XvZPugoni7i7D7prCe0AtaHTc97CYgm7NsAtJyxNLixmhLV8pyIEaiHXWAh8fPKW+R017+EmXrr9EaquPmsVvTywAAE1PMNOKqo2kl4Gxiz9zZqIajOm1fZGWcGS0f5JQ2kBqNbvbg2/Za+GJ/qwUCAwEAAaOB7jCB6zAdBgNVHQ4EFgQUlp98u8ZvF71ZP1LXChvsENZklGswgbsGA1UdIwSBszCBsIAUlp98u8ZvF71ZP1LXChvsENZklGuhgZSkgZEwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAgV86VpqAWuXvX6Oro4qJ1tYVIT5DgWpE692Ag422H7yRIr/9j/iKG4Thia/Oflx4TdL+IFJBAyPK9v6zZNZtBgPBynXb048hsP16l2vi0k5Q2JKiPDsEfBhGI+HnxLXEaUWAcVfCsQFvd2A1sxRr67ip5y2wwBelUecP3AjJ+YcxggGaMIIBlgIBATCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTA4MDQzMDE1MzkyMlowIwYJKoZIhvcNAQkEMRYEFJSI9/zWx7TUlKPY7kLjnvzB1h6sMA0GCSqGSIb3DQEBAQUABIGAikZNCmQdkWPdfmYnGqOb1f65ViaK0zjHf50azvsigWQLlhHqJ3PgB+jEJH3JU9Pm9M4wgiK23Bg2oIGuIsAfQkYO9mw/HjtDtOQHqXyZZbrM32YGtNWUD4ynakLYnaz7OnPl40aTPD4iDApgsGcj1oMdmw7KA2E9J0l2J9iJXF4=-----END PKCS7-----" />
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
|
||||||
<br />
|
<br />
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2>Note</h2>
|
<h2>Note</h2>
|
||||||
<div class="note">$note</div>
|
<div class="note">$note</div>
|
||||||
|
@ -58,9 +58,9 @@ python setup.py build && sudo python setup.py install
|
|||||||
<div>
|
<div>
|
||||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
||||||
<input type="hidden" name="cmd" value="_s-xclick" />
|
<input type="hidden" name="cmd" value="_s-xclick" />
|
||||||
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" />
|
<input type="hidden" name="hosted_button_id" value="3029289" />
|
||||||
|
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="Donate to support calibre development" />
|
||||||
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
|
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
|
||||||
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHbwYJKoZIhvcNAQcEoIIHYDCCB1wCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYBn7jneGiSLVO8rcDrBtOUXL+HftY+CiC47hTntwICio6qqpLKezIryyG8tKcjY58Rcocur/kDwljEutIafVG7XRA7BJL9eZdHAZsZdX04f4dApzkWwR9w6GQhj0kwmO2ZNE878UcgGZBve4qQKWM8bf2pMY7vJwCNoo6ozpIi3VTELMAkGBSsOAwIaBQAwgewGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIBTALt7s1gJmAgcjEAwUMRYeIdIOE/yi0Y5vrVKBFxOUCbqTx/lu3Rk4EHsODZXLHT+BDA5WSWYO3AXfv2Lmlv1kJ7jWrjUVirYoQ5M4qdIhY9DtvPioIMMRoTJmYM9JKH8n2TWcjJ1XIzIuDP4zn8/Ya9hap3RHOrj2RBj89g7iSuFRsjoA0PYZgtWAKwR7g3LLpjRachn041JO55BEd3YWUgorNQeo3WEHgowLFfTWgFFePkm8OoWA1klWkYp4S07IhX5NaRc8OegkdshpkiIHGAKCCA4cwggODMIIC7KADAgECAgEAMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTAeFw0wNDAyMTMxMDEzMTVaFw0zNTAyMTMxMDEzMTVaMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwUdO3fxEzEtcnI7ZKZL412XvZPugoni7i7D7prCe0AtaHTc97CYgm7NsAtJyxNLixmhLV8pyIEaiHXWAh8fPKW+R017+EmXrr9EaquPmsVvTywAAE1PMNOKqo2kl4Gxiz9zZqIajOm1fZGWcGS0f5JQ2kBqNbvbg2/Za+GJ/qwUCAwEAAaOB7jCB6zAdBgNVHQ4EFgQUlp98u8ZvF71ZP1LXChvsENZklGswgbsGA1UdIwSBszCBsIAUlp98u8ZvF71ZP1LXChvsENZklGuhgZSkgZEwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAgV86VpqAWuXvX6Oro4qJ1tYVIT5DgWpE692Ag422H7yRIr/9j/iKG4Thia/Oflx4TdL+IFJBAyPK9v6zZNZtBgPBynXb048hsP16l2vi0k5Q2JKiPDsEfBhGI+HnxLXEaUWAcVfCsQFvd2A1sxRr67ip5y2wwBelUecP3AjJ+YcxggGaMIIBlgIBATCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTA4MDQzMDE1MzkyMlowIwYJKoZIhvcNAQkEMRYEFJSI9/zWx7TUlKPY7kLjnvzB1h6sMA0GCSqGSIb3DQEBAQUABIGAikZNCmQdkWPdfmYnGqOb1f65ViaK0zjHf50azvsigWQLlhHqJ3PgB+jEJH3JU9Pm9M4wgiK23Bg2oIGuIsAfQkYO9mw/HjtDtOQHqXyZZbrM32YGtNWUD4ynakLYnaz7OnPl40aTPD4iDApgsGcj1oMdmw7KA2E9J0l2J9iJXF4=-----END PKCS7-----" />
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
5427
src/calibre/translations/ar.po
Normal file
@ -13,7 +13,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
"Generated-By: pygettext.py 1.5\n"
|
"Generated-By: pygettext.py 1.5\n"
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
"Generated-By: pygettext.py 1.5\n"
|
"Generated-By: pygettext.py 1.5\n"
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -17,7 +17,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -13,7 +13,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
"Generated-By: pygettext.py 1.5\n"
|
"Generated-By: pygettext.py 1.5\n"
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -8,13 +8,13 @@ msgstr ""
|
|||||||
"Project-Id-Version: calibre\n"
|
"Project-Id-Version: calibre\n"
|
||||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"POT-Creation-Date: 2009-01-27 01:54+0000\n"
|
"POT-Creation-Date: 2009-01-27 01:54+0000\n"
|
||||||
"PO-Revision-Date: 2009-01-23 21:22+0000\n"
|
"PO-Revision-Date: 2009-02-04 20:39+0000\n"
|
||||||
"Last-Translator: Molnár Gábor <csirkus@gmail.com>\n"
|
"Last-Translator: Kovid Goyal <Unknown>\n"
|
||||||
"Language-Team: Hungarian <hu@li.org>\n"
|
"Language-Team: Hungarian <hu@li.org>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
@ -142,7 +142,7 @@ msgstr "Tömörített könyvek metaadatait is olvassa be"
|
|||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:196
|
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:196
|
||||||
msgid "Read metadata from ebooks in RAR archives"
|
msgid "Read metadata from ebooks in RAR archives"
|
||||||
msgstr ""
|
msgstr "Metaadatok olvasása a RAR-ral tömörített könyvekből is"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:207
|
#: /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:217
|
||||||
@ -274,7 +274,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:110
|
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:110
|
||||||
msgid "Control auto-detection of document structure."
|
msgid "Control auto-detection of document structure."
|
||||||
msgstr ""
|
msgstr "Dokumentum-struktúra automatikus felismerése."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:112
|
#: /home/kovid/work/calibre/src/calibre/ebooks/epub/__init__.py:112
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -832,6 +832,9 @@ msgid ""
|
|||||||
"FONT_DELTA pts. FONT_DELTA can be a fraction.If FONT_DELTA is negative, the "
|
"FONT_DELTA pts. FONT_DELTA can be a fraction.If FONT_DELTA is negative, the "
|
||||||
"font size is decreased."
|
"font size is decreased."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"A betűméret nővelése 2*FONT_DELTA ponttal, és a sortávolság növelése "
|
||||||
|
"FONT_DELTA ponttal. A FONT_DELTA érték törtszám is lehet, valamint ha "
|
||||||
|
"negatív az értéke, a betűméret csökkenni fog."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:125
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:125
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -1086,6 +1089,8 @@ msgstr "Szerző a fájl metaadataiban. Alapértelmezés: %default"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"Path to output file. By default a file is created in the current directory."
|
"Path to output file. By default a file is created in the current directory."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"A kimeneti fájl útvonala. Alapértelmezés szerint az aktuális könyvtárba "
|
||||||
|
"kerül a fájl."
|
||||||
|
|
||||||
#: /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:299
|
||||||
msgid "Number of colors for grayscale image conversion. Default: %default"
|
msgid "Number of colors for grayscale image conversion. Default: %default"
|
||||||
@ -1134,6 +1139,8 @@ msgid ""
|
|||||||
"Don't sort the files found in the comic alphabetically by name. Instead use "
|
"Don't sort the files found in the comic alphabetically by name. Instead use "
|
||||||
"the order they were added to the comic."
|
"the order they were added to the comic."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"A képregény csomagban talált fájlokat a képregényhez való hozzáadás "
|
||||||
|
"sorrendje alapján rendezze a névsorrend helyett."
|
||||||
|
|
||||||
#: /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:317
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -1185,6 +1192,10 @@ msgid ""
|
|||||||
" \n"
|
" \n"
|
||||||
"%prog converts mybook.epub to mybook.lrf"
|
"%prog converts mybook.epub to mybook.lrf"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Használat: %prog [beállítások] konyv.epub\n"
|
||||||
|
" \n"
|
||||||
|
" \n"
|
||||||
|
"A %prog a konyv.epub fájlt lrf formátumba konvertálja."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:23
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:23
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -1205,7 +1216,7 @@ msgstr "A létrehozott HTML kiírása a kimenetre, majd kilépés."
|
|||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:30
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/fb2/convert_from.py:30
|
||||||
msgid "Keep generated HTML files after completing conversion to LRF."
|
msgid "Keep generated HTML files after completing conversion to LRF."
|
||||||
msgstr ""
|
msgstr "Ne törölje a konvertálásnál keletkező átmeneti HTML fájlokat."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/feeds/convert_from.py:20
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/feeds/convert_from.py:20
|
||||||
msgid "Options to control the behavior of feeds2disk"
|
msgid "Options to control the behavior of feeds2disk"
|
||||||
@ -1225,7 +1236,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: /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:319
|
||||||
msgid "\tParsing HTML..."
|
msgid "\tParsing HTML..."
|
||||||
msgstr ""
|
msgstr "\tHTML beolvasása..."
|
||||||
|
|
||||||
#: /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:342
|
||||||
msgid "\tBaen file detected. Re-parsing..."
|
msgid "\tBaen file detected. Re-parsing..."
|
||||||
@ -1241,71 +1252,79 @@ msgstr "Feldolgozás: %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:390
|
||||||
msgid "\tConverting to BBeB..."
|
msgid "\tConverting to BBeB..."
|
||||||
msgstr ""
|
msgstr "\tKonvertálás BBeB formátumba..."
|
||||||
|
|
||||||
#: /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: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:549
|
||||||
msgid "Could not parse file: %s"
|
msgid "Could not parse file: %s"
|
||||||
msgstr ""
|
msgstr "Nem tudtam feldolgozni a fájlt: %s"
|
||||||
|
|
||||||
#: /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:541
|
||||||
msgid "%s is an empty file"
|
msgid "%s is an empty file"
|
||||||
msgstr ""
|
msgstr "A %s fájl üres!"
|
||||||
|
|
||||||
#: /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:561
|
||||||
msgid "Failed to parse link %s %s"
|
msgid "Failed to parse link %s %s"
|
||||||
msgstr ""
|
msgstr "A link feldolgozása nem sikerült: %s %s"
|
||||||
|
|
||||||
#: /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:605
|
||||||
msgid "Cannot add link %s to TOC"
|
msgid "Cannot add link %s to TOC"
|
||||||
msgstr ""
|
msgstr "Nem tudtam a linket hozzáadni a tartalomjegyzékhez: %s"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:957
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:957
|
||||||
msgid "Unable to process image %s. Error: %s"
|
msgid "Unable to process image %s. Error: %s"
|
||||||
msgstr ""
|
msgstr "Hiba a \"%s\" kép feldolgozása közben: %s"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:995
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:995
|
||||||
msgid "Unable to process interlaced PNG %s"
|
msgid "Unable to process interlaced PNG %s"
|
||||||
msgstr ""
|
msgstr "Nem tudtam feldolgozni a PNG képet: %s"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1010
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1010
|
||||||
msgid ""
|
msgid ""
|
||||||
"Could not process image: %s\n"
|
"Could not process image: %s\n"
|
||||||
"%s"
|
"%s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Nem tudtam feldolgozni a képet: %s\n"
|
||||||
|
"%s"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1763
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1763
|
||||||
msgid ""
|
msgid ""
|
||||||
"An error occurred while processing a table: %s. Ignoring table markup."
|
"An error occurred while processing a table: %s. Ignoring table markup."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Hiba történt a táblázat feldolgozása közben: %s. A táblázat formázást "
|
||||||
|
"figyelmen kívül hagyom."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1765
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1765
|
||||||
msgid ""
|
msgid ""
|
||||||
"Bad table:\n"
|
"Bad table:\n"
|
||||||
"%s"
|
"%s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Hibás táblázat:\n"
|
||||||
|
"%s"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1787
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1787
|
||||||
msgid "Table has cell that is too large"
|
msgid "Table has cell that is too large"
|
||||||
msgstr ""
|
msgstr "A táblázatban olyan cellák vannak, amelyek túl nagyok."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1817
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1817
|
||||||
msgid ""
|
msgid ""
|
||||||
"You have to save the website %s as an html file first and then run html2lrf "
|
"You have to save the website %s as an html file first and then run html2lrf "
|
||||||
"on it."
|
"on it."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Mentsd le a %s weboldalt egy mappába, majd a html fájlon futtasd a html2lrf "
|
||||||
|
"konvertáló programot."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1860
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1860
|
||||||
msgid "Could not read cover image: %s"
|
msgid "Could not read cover image: %s"
|
||||||
msgstr ""
|
msgstr "Nem tudtam a borító képet olvasni: %s"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1863
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1863
|
||||||
msgid "Cannot read from: %s"
|
msgid "Cannot read from: %s"
|
||||||
msgstr ""
|
msgstr "Hiba olvasás közben: %s"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1988
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1988
|
||||||
msgid "Failed to process opf file"
|
msgid "Failed to process opf file"
|
||||||
msgstr ""
|
msgstr "Hiba az opf fájl feldolgozása közben"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1994
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1994
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -1317,6 +1336,13 @@ msgid ""
|
|||||||
"to local files recursively. Thus, you can use it to \n"
|
"to local files recursively. Thus, you can use it to \n"
|
||||||
"convert a whole tree of HTML files."
|
"convert a whole tree of HTML files."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Használat: %prog [beállítások] konyv.html\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"A %prog a konyv.html fájlt LRF formátumba konvertálja. \n"
|
||||||
|
"A %prog minden linket rekurzívan követ ami helyi \n"
|
||||||
|
"html fájlokra hivatkozik, tehát lehetséges sok összefüggő \n"
|
||||||
|
"html fájl konvertálása is."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lit/convert_from.py:15
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lit/convert_from.py:15
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -1325,16 +1351,22 @@ msgid ""
|
|||||||
"\n"
|
"\n"
|
||||||
"%prog converts mybook.lit to mybook.lrf"
|
"%prog converts mybook.lit to mybook.lrf"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Használat: %prog [beállítások] konyv.lit\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"A %prog a konyv.lit fájlt LRF formátumba konvertálja"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:136
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:136
|
||||||
msgid ""
|
msgid ""
|
||||||
"%prog book.lrf\n"
|
"%prog book.lrf\n"
|
||||||
"Convert an LRF file into an LRS (XML UTF-8 encoded) file"
|
"Convert an LRF file into an LRS (XML UTF-8 encoded) file"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"%prog konyv.lrf\n"
|
||||||
|
"A prog a konyv.lrf fájlt LRS formátumba (UTF-8 kódolású XML) konvertálja."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:137
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:137
|
||||||
msgid "Output LRS file"
|
msgid "Output LRS file"
|
||||||
msgstr ""
|
msgstr "Kimeneti LRS fájl"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:139
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:139
|
||||||
msgid "Do not save embedded image and font files to disk"
|
msgid "Do not save embedded image and font files to disk"
|
||||||
@ -1342,42 +1374,44 @@ msgstr ""
|
|||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:158
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:158
|
||||||
msgid "Parsing LRF..."
|
msgid "Parsing LRF..."
|
||||||
msgstr ""
|
msgstr "LRF fájl beolvasása..."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:161
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:161
|
||||||
msgid "Creating XML..."
|
msgid "Creating XML..."
|
||||||
msgstr ""
|
msgstr "XML létrehozása..."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:163
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:163
|
||||||
msgid "LRS written to "
|
msgid "LRS written to "
|
||||||
msgstr ""
|
msgstr "Az LRS fájl helye: "
|
||||||
|
|
||||||
#: /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:249
|
||||||
msgid "Could not read from thumbnail file:"
|
msgid "Could not read from thumbnail file:"
|
||||||
msgstr ""
|
msgstr "Nem tudtam az ikon fájlt olvasni:"
|
||||||
|
|
||||||
#: /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:269
|
||||||
msgid ""
|
msgid ""
|
||||||
"%prog [options] file.lrs\n"
|
"%prog [options] file.lrs\n"
|
||||||
"Compile an LRS file into an LRF file."
|
"Compile an LRS file into an LRF file."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"%prog [beállítások] konyv.lrf\n"
|
||||||
|
"LRS fájlt lefordítása LRF formátumba."
|
||||||
|
|
||||||
#: /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:270
|
||||||
msgid "Path to output file"
|
msgid "Path to output file"
|
||||||
msgstr ""
|
msgstr "A célfájl elérési útja"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrs/convert_from.py:272
|
#: /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/metadata/isbndb.py:115
|
||||||
msgid "Verbose processing"
|
msgid "Verbose processing"
|
||||||
msgstr ""
|
msgstr "Informatívabb üzenetek feldolgozásnál"
|
||||||
|
|
||||||
#: /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:274
|
||||||
msgid "Convert LRS to LRS, useful for debugging."
|
msgid "Convert LRS to LRS, useful for debugging."
|
||||||
msgstr ""
|
msgstr "LRS fájl konvertálása LRS formátumba (hibakeresésnél hasznos)."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:455
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:455
|
||||||
msgid "Invalid LRF file. Could not set metadata."
|
msgid "Invalid LRF file. Could not set metadata."
|
||||||
msgstr ""
|
msgstr "Érvénytelen LRF fájl. Nem tudtam a metadatokat beállítani."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:580
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:580
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -1391,42 +1425,44 @@ msgstr ""
|
|||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:587
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:587
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:43
|
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:43
|
||||||
msgid "Set the book title"
|
msgid "Set the book title"
|
||||||
msgstr ""
|
msgstr "A könyv címe"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:589
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:589
|
||||||
msgid "Set sort key for the title"
|
msgid "Set sort key for the title"
|
||||||
msgstr ""
|
msgstr "Rendezési kulcs a címhez"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:591
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:591
|
||||||
msgid "Set the author"
|
msgid "Set the author"
|
||||||
msgstr ""
|
msgstr "Szerző"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:593
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:593
|
||||||
msgid "Set sort key for the author"
|
msgid "Set sort key for the author"
|
||||||
msgstr ""
|
msgstr "Rendezési kulcs a szerzőhöz"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:595
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:595
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:47
|
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/__init__.py:47
|
||||||
msgid "The category this book belongs to. E.g.: History"
|
msgid "The category this book belongs to. E.g.: History"
|
||||||
msgstr ""
|
msgstr "A kategória, amibe a könyv tartozik. Pl.: történelem"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:598
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:598
|
||||||
msgid "Path to a graphic that will be set as this files' thumbnail"
|
msgid "Path to a graphic that will be set as this files' thumbnail"
|
||||||
msgstr ""
|
msgstr "A fájlhoz használandó ikon elérési útja"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:601
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:601
|
||||||
msgid ""
|
msgid ""
|
||||||
"Path to a txt file containing the comment to be stored in the lrf file."
|
"Path to a txt file containing the comment to be stored in the lrf file."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"A txt fájl útvonala, amelynek tartalma az lrf fájlhoz lesz csatolva "
|
||||||
|
"megjegyzésként."
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:605
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:605
|
||||||
msgid "Extract thumbnail from LRF file"
|
msgid "Extract thumbnail from LRF file"
|
||||||
msgstr ""
|
msgstr "Ikon kinyerése az LRF fájlból"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:606
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:606
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:182
|
#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/mobi.py:182
|
||||||
msgid "Set the publisher"
|
msgid "Set the publisher"
|
||||||
msgstr ""
|
msgstr "Kiadó"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:607
|
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/meta.py:607
|
||||||
msgid "Set the book classification"
|
msgid "Set the book classification"
|
||||||
|
@ -15,7 +15,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
"Generated-By: pygettext.py 1.5\n"
|
"Generated-By: pygettext.py 1.5\n"
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
"Generated-By: pygettext.py 1.5\n"
|
"Generated-By: pygettext.py 1.5\n"
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -13,7 +13,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
"X-Poedit-Country: RUSSIAN FEDERATION\n"
|
"X-Poedit-Country: RUSSIAN FEDERATION\n"
|
||||||
"X-Poedit-Language: Russian\n"
|
"X-Poedit-Language: Russian\n"
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -13,7 +13,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
"Generated-By: pygettext.py 1.5\n"
|
"Generated-By: pygettext.py 1.5\n"
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Launchpad-Export-Date: 2009-01-30 19:20+0000\n"
|
"X-Launchpad-Export-Date: 2009-02-04 21:04+0000\n"
|
||||||
"X-Generator: Launchpad (build Unknown)\n"
|
"X-Generator: Launchpad (build Unknown)\n"
|
||||||
|
|
||||||
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
#: /home/kovid/work/calibre/src/calibre/customize/__init__.py:41
|
||||||
|
@ -47,6 +47,9 @@ class BasicNewsRecipe(object, LoggingInterface):
|
|||||||
#: The author of this recipe
|
#: The author of this recipe
|
||||||
__author__ = __appname__
|
__author__ = __appname__
|
||||||
|
|
||||||
|
#: The language that the news is in
|
||||||
|
language = _('Unknown')
|
||||||
|
|
||||||
#: Maximum number of articles to download from each feed. This is primarily
|
#: Maximum number of articles to download from each feed. This is primarily
|
||||||
#: useful for feeds that don't have article dates. For most feeds, you should
|
#: useful for feeds that don't have article dates. For most feeds, you should
|
||||||
#: use :attr:`BasicNewsRecipe.oldest_article`
|
#: use :attr:`BasicNewsRecipe.oldest_article`
|
||||||
|
@ -24,7 +24,9 @@ recipe_modules = ['recipe_' + r for r in (
|
|||||||
'joelonsoftware', 'telepolis', 'common_dreams', 'nin', 'tomshardware_de',
|
'joelonsoftware', 'telepolis', 'common_dreams', 'nin', 'tomshardware_de',
|
||||||
'pagina12', 'infobae', 'ambito', 'elargentino', 'sueddeutsche', 'the_age',
|
'pagina12', 'infobae', 'ambito', 'elargentino', 'sueddeutsche', 'the_age',
|
||||||
'laprensa', 'amspec', 'freakonomics', 'criticadigital', 'elcronista',
|
'laprensa', 'amspec', 'freakonomics', 'criticadigital', 'elcronista',
|
||||||
'shacknews', 'teleread',
|
'shacknews', 'teleread', 'granma', 'juventudrebelde', 'juventudrebelde_english',
|
||||||
|
'la_tercera', 'el_mercurio_chile', 'la_cuarta', 'lanacion_chile', 'la_segunda',
|
||||||
|
'jb_online', 'estadao', 'o_globo', 'vijesti', 'elmundo', 'the_oz',
|
||||||
)]
|
)]
|
||||||
|
|
||||||
import re, imp, inspect, time, os
|
import re, imp, inspect, time, os
|
||||||
|
@ -18,6 +18,7 @@ class Ambito(BasicNewsRecipe):
|
|||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
encoding = 'iso--8859-1'
|
encoding = 'iso--8859-1'
|
||||||
|
language = _('Spanish')
|
||||||
cover_url = 'http://www.ambito.com/img/logo_.jpg'
|
cover_url = 'http://www.ambito.com/img/logo_.jpg'
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
|
@ -11,7 +11,8 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
|||||||
class TheAmericanSpectator(BasicNewsRecipe):
|
class TheAmericanSpectator(BasicNewsRecipe):
|
||||||
title = 'The American Spectator'
|
title = 'The American Spectator'
|
||||||
__author__ = 'Darko Miletic'
|
__author__ = 'Darko Miletic'
|
||||||
description = 'news from USA'
|
language = _('English')
|
||||||
|
description = 'News from USA'
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
|
@ -8,6 +8,7 @@ class AssociatedPress(BasicNewsRecipe):
|
|||||||
description = 'Global news'
|
description = 'Global news'
|
||||||
__author__ = 'Kovid Goyal'
|
__author__ = 'Kovid Goyal'
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
|
language = _('English')
|
||||||
max_articles_per_feed = 15
|
max_articles_per_feed = 15
|
||||||
html2lrf_options = ['--force-page-break-before-tag="chapter"']
|
html2lrf_options = ['--force-page-break-before-tag="chapter"']
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ class ArsTechnica(BasicNewsRecipe):
|
|||||||
title = 'Ars Technica'
|
title = 'Ars Technica'
|
||||||
description = 'The art of technology'
|
description = 'The art of technology'
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
|
language = _('English')
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
__author__ = 'Michael Warner'
|
__author__ = 'Michael Warner'
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
|
@ -14,7 +14,7 @@ class TheAtlantic(BasicNewsRecipe):
|
|||||||
__author__ = 'Kovid Goyal'
|
__author__ = 'Kovid Goyal'
|
||||||
description = 'Current affairs and politics focussed on the US'
|
description = 'Current affairs and politics focussed on the US'
|
||||||
INDEX = 'http://www.theatlantic.com/doc/current'
|
INDEX = 'http://www.theatlantic.com/doc/current'
|
||||||
|
language = _('English')
|
||||||
remove_tags_before = dict(name='div', id='storytop')
|
remove_tags_before = dict(name='div', id='storytop')
|
||||||
remove_tags = [dict(name='div', id=['seealso', 'storybottom', 'footer', 'ad_banner_top', 'sidebar'])]
|
remove_tags = [dict(name='div', id=['seealso', 'storybottom', 'footer', 'ad_banner_top', 'sidebar'])]
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
|
@ -6,12 +6,13 @@ __copyright__ = '2008, Darko Miletic <darko.miletic at gmail.com>'
|
|||||||
b92.net
|
b92.net
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import string,re
|
import re
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
class B92(BasicNewsRecipe):
|
class B92(BasicNewsRecipe):
|
||||||
title = u'B92'
|
title = u'B92'
|
||||||
__author__ = 'Darko Miletic'
|
__author__ = 'Darko Miletic'
|
||||||
|
language = _('Serbian')
|
||||||
description = 'Dnevne vesti iz Srbije i sveta'
|
description = 'Dnevne vesti iz Srbije i sveta'
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
|
@ -15,6 +15,7 @@ class Barrons(BasicNewsRecipe):
|
|||||||
title = 'Barron\'s'
|
title = 'Barron\'s'
|
||||||
max_articles_per_feed = 50
|
max_articles_per_feed = 50
|
||||||
needs_subscription = True
|
needs_subscription = True
|
||||||
|
language = _('English')
|
||||||
__author__ = 'Kovid Goyal'
|
__author__ = 'Kovid Goyal'
|
||||||
description = 'Weekly publication for investors from the publisher of the Wall Street Journal'
|
description = 'Weekly publication for investors from the publisher of the Wall Street Journal'
|
||||||
timefmt = ' [%a, %b %d, %Y]'
|
timefmt = ' [%a, %b %d, %Y]'
|
||||||
|
@ -13,6 +13,7 @@ class BBC(BasicNewsRecipe):
|
|||||||
__author__ = 'Kovid Goyal'
|
__author__ = 'Kovid Goyal'
|
||||||
description = 'Global news and current affairs from the British Broadcasting Corporation'
|
description = 'Global news and current affairs from the British Broadcasting Corporation'
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
|
language = _('English')
|
||||||
|
|
||||||
remove_tags = [dict(name='div', attrs={'class':'footer'})]
|
remove_tags = [dict(name='div', attrs={'class':'footer'})]
|
||||||
extra_css = '.headline {font-size: x-large;} \n .fact { padding-top: 10pt }'
|
extra_css = '.headline {font-size: x-large;} \n .fact { padding-top: 10pt }'
|
||||||
|
@ -13,6 +13,7 @@ class BusinessWeek(BasicNewsRecipe):
|
|||||||
title = 'Business Week'
|
title = 'Business Week'
|
||||||
description = 'Business News, Stock Market and Financial Advice'
|
description = 'Business News, Stock Market and Financial Advice'
|
||||||
__author__ = 'ChuckEggDotCom'
|
__author__ = 'ChuckEggDotCom'
|
||||||
|
language = _('English')
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
max_articles_per_feed = 10
|
max_articles_per_feed = 10
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ class ChristianScienceMonitor(BasicNewsRecipe):
|
|||||||
description = 'Providing context and clarity on national and international news, peoples and cultures'
|
description = 'Providing context and clarity on national and international news, peoples and cultures'
|
||||||
max_articles_per_feed = 20
|
max_articles_per_feed = 20
|
||||||
__author__ = 'Kovid Goyal'
|
__author__ = 'Kovid Goyal'
|
||||||
|
language = _('English')
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ class Clarin(BasicNewsRecipe):
|
|||||||
description = 'Noticias de Argentina y mundo'
|
description = 'Noticias de Argentina y mundo'
|
||||||
oldest_article = 2
|
oldest_article = 2
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
|
language = _('Spanish')
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
cover_url = strftime('http://www.clarin.com/diario/%Y/%m/%d/portada.jpg')
|
cover_url = strftime('http://www.clarin.com/diario/%Y/%m/%d/portada.jpg')
|
||||||
|
@ -12,6 +12,7 @@ class CNN(BasicNewsRecipe):
|
|||||||
description = 'Global news'
|
description = 'Global news'
|
||||||
timefmt = ' [%d %b %Y]'
|
timefmt = ' [%d %b %Y]'
|
||||||
__author__ = 'Kovid Goyal'
|
__author__ = 'Kovid Goyal'
|
||||||
|
language = _('English')
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
oldest_article = 15
|
oldest_article = 15
|
||||||
|
@ -5,6 +5,7 @@ class CommonDreams(BasicNewsRecipe):
|
|||||||
title = u'Common Dreams'
|
title = u'Common Dreams'
|
||||||
description = u'Progressive news and views'
|
description = u'Progressive news and views'
|
||||||
__author__ = u'XanthanGum'
|
__author__ = u'XanthanGum'
|
||||||
|
language = _('English')
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ class CriticaDigital(BasicNewsRecipe):
|
|||||||
description = 'Noticias de Argentina'
|
description = 'Noticias de Argentina'
|
||||||
oldest_article = 2
|
oldest_article = 2
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
|
language = _('Spanish')
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
encoding = 'cp1252'
|
encoding = 'cp1252'
|
||||||
|
@ -6,6 +6,7 @@ class Cyberpresse(BasicNewsRecipe):
|
|||||||
title = u'Cyberpresse'
|
title = u'Cyberpresse'
|
||||||
__author__ = 'balok'
|
__author__ = 'balok'
|
||||||
description = 'Canadian news in French'
|
description = 'Canadian news in French'
|
||||||
|
language = _('French')
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
|
@ -12,6 +12,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
|||||||
class DailyTelegraph(BasicNewsRecipe):
|
class DailyTelegraph(BasicNewsRecipe):
|
||||||
title = u'Daily Telegraph'
|
title = u'Daily Telegraph'
|
||||||
__author__ = u'AprilHare'
|
__author__ = u'AprilHare'
|
||||||
|
language = _('English')
|
||||||
description = u'News from down under'
|
description = u'News from down under'
|
||||||
oldest_article = 2
|
oldest_article = 2
|
||||||
max_articles_per_feed = 10
|
max_articles_per_feed = 10
|
||||||
|
@ -9,6 +9,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
|||||||
class DeStandaard(BasicNewsRecipe):
|
class DeStandaard(BasicNewsRecipe):
|
||||||
title = u'De Standaard'
|
title = u'De Standaard'
|
||||||
__author__ = u'Darko Miletic'
|
__author__ = u'Darko Miletic'
|
||||||
|
language = _('French')
|
||||||
description = u'News from Belgium'
|
description = u'News from Belgium'
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
|
@ -14,6 +14,7 @@ class DiscoverMagazine(BasicNewsRecipe):
|
|||||||
description = u'Science, Technology and the Future'
|
description = u'Science, Technology and the Future'
|
||||||
__author__ = 'Mike Diaz'
|
__author__ = 'Mike Diaz'
|
||||||
oldest_article = 33
|
oldest_article = 33
|
||||||
|
language = _('English')
|
||||||
max_articles_per_feed = 20
|
max_articles_per_feed = 20
|
||||||
feeds = [
|
feeds = [
|
||||||
(u'Technology', u'http://discovermagazine.com/topics/technology/rss.xml'),
|
(u'Technology', u'http://discovermagazine.com/topics/technology/rss.xml'),
|
||||||
|
@ -14,6 +14,7 @@ from urllib2 import quote
|
|||||||
class Economist(BasicNewsRecipe):
|
class Economist(BasicNewsRecipe):
|
||||||
|
|
||||||
title = 'The Economist'
|
title = 'The Economist'
|
||||||
|
language = _('English')
|
||||||
__author__ = "Kovid Goyal"
|
__author__ = "Kovid Goyal"
|
||||||
description = 'Global news and current affairs from a European perspective'
|
description = 'Global news and current affairs from a European perspective'
|
||||||
oldest_article = 7.0
|
oldest_article = 7.0
|
||||||
|
48
src/calibre/web/feeds/recipes/recipe_el_mercurio_chile.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
|
'''
|
||||||
|
emol.com
|
||||||
|
'''
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class ElMercurio(BasicNewsRecipe):
|
||||||
|
title = 'El Mercurio online'
|
||||||
|
language = _('Spanish')
|
||||||
|
__author__ = 'Darko Miletic'
|
||||||
|
description = 'El sitio de noticias online de Chile'
|
||||||
|
oldest_article = 2
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = False
|
||||||
|
encoding = 'cp1252'
|
||||||
|
cover_url = 'http://www.emol.com/especiales/logo_emol/logo_emol.gif'
|
||||||
|
|
||||||
|
html2lrf_options = [
|
||||||
|
'--comment' , description
|
||||||
|
, '--category' , 'news, Chile'
|
||||||
|
, '--publisher' , title
|
||||||
|
]
|
||||||
|
|
||||||
|
keep_only_tags = [
|
||||||
|
dict(name='div', attrs={'class':'despliegue-txt_750px'})
|
||||||
|
,dict(name='div', attrs={'id':'div_cuerpo_participa'})
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
remove_tags = [
|
||||||
|
dict(name='div', attrs={'class':'contenedor_despliegue-col-left300'})
|
||||||
|
,dict(name='div', attrs={'id':['div_centro_dn_opc','div_cabezera','div_secciones','div_contenidos','div_pie','nav']})
|
||||||
|
]
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'Noticias de ultima hora', u'http://www.emol.com/rss20/rss.asp?canal=0')
|
||||||
|
,(u'Nacional', u'http://www.emol.com/rss20/rss.asp?canal=1')
|
||||||
|
,(u'Mundo', u'http://www.emol.com/rss20/rss.asp?canal=2')
|
||||||
|
,(u'Deportes', u'http://www.emol.com/rss20/rss.asp?canal=4')
|
||||||
|
,(u'Magazine', u'http://www.emol.com/rss20/rss.asp?canal=6')
|
||||||
|
,(u'Tecnologia', u'http://www.emol.com/rss20/rss.asp?canal=5')
|
||||||
|
,(u'La Musica', u'http://www.emol.com/rss20/rss.asp?canal=7')
|
||||||
|
]
|
||||||
|
|
@ -11,6 +11,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
|||||||
|
|
||||||
class ElPais(BasicNewsRecipe):
|
class ElPais(BasicNewsRecipe):
|
||||||
title = u'EL PAIS'
|
title = u'EL PAIS'
|
||||||
|
language = _('Spanish')
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ class ElArgentino(BasicNewsRecipe):
|
|||||||
title = 'ElArgentino.com'
|
title = 'ElArgentino.com'
|
||||||
__author__ = 'Darko Miletic'
|
__author__ = 'Darko Miletic'
|
||||||
description = 'Informacion Libre las 24 horas'
|
description = 'Informacion Libre las 24 horas'
|
||||||
|
language = _('Spanish')
|
||||||
oldest_article = 2
|
oldest_article = 2
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
|
@ -13,6 +13,7 @@ class ElCronista(BasicNewsRecipe):
|
|||||||
__author__ = 'Darko Miletic'
|
__author__ = 'Darko Miletic'
|
||||||
description = 'Noticias de Argentina'
|
description = 'Noticias de Argentina'
|
||||||
oldest_article = 2
|
oldest_article = 2
|
||||||
|
language = _('Spanish')
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
|
46
src/calibre/web/feeds/recipes/recipe_elmundo.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
|
'''
|
||||||
|
elmundo.es
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class ElMundo(BasicNewsRecipe):
|
||||||
|
title = 'El Mundo'
|
||||||
|
__author__ = 'Darko Miletic'
|
||||||
|
description = 'News from Spain'
|
||||||
|
language = _('Spanish')
|
||||||
|
oldest_article = 2
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = False
|
||||||
|
encoding = 'iso8859_15'
|
||||||
|
cover_url = 'http://estaticos02.cache.el-mundo.net/papel/imagenes/v2.0/logoverde.gif'
|
||||||
|
|
||||||
|
html2lrf_options = [
|
||||||
|
'--comment' , description
|
||||||
|
, '--category' , 'news, Spain'
|
||||||
|
, '--publisher' , title
|
||||||
|
]
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'class':'noticia'})]
|
||||||
|
|
||||||
|
remove_tags = [
|
||||||
|
dict(name='div', attrs={'class':['herramientas','publicidad_google','video','herramientasarriba','contenido_noticia_02']})
|
||||||
|
,dict(name='div', attrs={'id':'modulo_multimedia' })
|
||||||
|
,dict(name=['object','script','link', 'a'])
|
||||||
|
,dict(name='ul', attrs={'class':'herramientas'})
|
||||||
|
]
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'Portada' , u'http://rss.elmundo.es/rss/descarga.htm?data2=4' )
|
||||||
|
,(u'Television' , u'http://rss.elmundo.es/rss/descarga.htm?data2=76')
|
||||||
|
,(u'Espana' , u'http://rss.elmundo.es/rss/descarga.htm?data2=8' )
|
||||||
|
,(u'Internacional' , u'http://rss.elmundo.es/rss/descarga.htm?data2=9' )
|
||||||
|
,(u'Cultura' , u'http://rss.elmundo.es/rss/descarga.htm?data2=6' )
|
||||||
|
,(u'Ciencia/Ecologia', u'http://rss.elmundo.es/rss/descarga.htm?data2=5' )
|
||||||
|
,(u'Comunicacion' , u'http://rss.elmundo.es/rss/descarga.htm?data2=26')
|
||||||
|
]
|
@ -13,6 +13,7 @@ class Engadget(BasicNewsRecipe):
|
|||||||
title = u'Engadget'
|
title = u'Engadget'
|
||||||
__author__ = 'Darko Miletic'
|
__author__ = 'Darko Miletic'
|
||||||
description = 'Tech news'
|
description = 'Tech news'
|
||||||
|
language = _('English')
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
|
@ -14,6 +14,7 @@ class ESPN(BasicNewsRecipe):
|
|||||||
title = 'ESPN'
|
title = 'ESPN'
|
||||||
description = 'Sports news'
|
description = 'Sports news'
|
||||||
__author__ = 'Kovid Goyal'
|
__author__ = 'Kovid Goyal'
|
||||||
|
language = _('English')
|
||||||
|
|
||||||
needs_subscription = True
|
needs_subscription = True
|
||||||
remove_tags = [dict(name='font', attrs={'class':'footer'}), dict(name='hr', noshade='noshade')]
|
remove_tags = [dict(name='font', attrs={'class':'footer'}), dict(name='hr', noshade='noshade')]
|
||||||
|
55
src/calibre/web/feeds/recipes/recipe_estadao.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
|
'''
|
||||||
|
estadao.com.br
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
|
||||||
|
class Estadao(BasicNewsRecipe):
|
||||||
|
title = 'O Estado de S. Paulo'
|
||||||
|
__author__ = 'Darko Miletic'
|
||||||
|
description = 'News from Brasil'
|
||||||
|
language = _('Spanish')
|
||||||
|
oldest_article = 2
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = False
|
||||||
|
encoding = 'utf8'
|
||||||
|
cover_url = 'http://www.estadao.com.br/img/logo_estadao.png'
|
||||||
|
|
||||||
|
html2lrf_options = [
|
||||||
|
'--comment' , description
|
||||||
|
, '--category' , 'news, Brasil'
|
||||||
|
, '--publisher' , title
|
||||||
|
]
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'id':'c1'})]
|
||||||
|
|
||||||
|
remove_tags = [
|
||||||
|
dict(name=['script','object','form','ul'])
|
||||||
|
,dict(name='div', attrs={'id':['votacao','estadaohoje']})
|
||||||
|
,dict(name='p', attrs={'id':'ctrl_texto'})
|
||||||
|
,dict(name='p', attrs={'class':'texto'})
|
||||||
|
]
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'Manchetes Estadao', u'http://www.estadao.com.br/rss/manchetes.xml')
|
||||||
|
,(u'Ultimas noticias', u'http://www.estadao.com.br/rss/ultimas.xml')
|
||||||
|
,(u'Nacional', u'http://www.estadao.com.br/rss/nacional.xml')
|
||||||
|
,(u'Internacional', u'http://www.estadao.com.br/rss/internacional.xml')
|
||||||
|
,(u'Cidades', u'http://www.estadao.com.br/rss/cidades.xml')
|
||||||
|
,(u'Esportes', u'http://www.estadao.com.br/rss/esportes.xml')
|
||||||
|
,(u'Arte & Lazer', u'http://www.estadao.com.br/rss/arteelazer.xml')
|
||||||
|
,(u'Economia', u'http://www.estadao.com.br/rss/economia.xml')
|
||||||
|
,(u'Vida &', u'http://www.estadao.com.br/rss/vidae.xml')
|
||||||
|
]
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
ifr = soup.find('iframe')
|
||||||
|
if ifr:
|
||||||
|
ifr.extract()
|
||||||
|
return soup
|
@ -11,8 +11,9 @@ class FazNet(BasicNewsRecipe):
|
|||||||
|
|
||||||
title = 'FAZ NET'
|
title = 'FAZ NET'
|
||||||
__author__ = 'Kovid Goyal'
|
__author__ = 'Kovid Goyal'
|
||||||
description = '"Frankfurter Allgemeine Zeitung'
|
description = 'Frankfurter Allgemeine Zeitung'
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
|
language = _('German')
|
||||||
max_articles_per_feed = 30
|
max_articles_per_feed = 30
|
||||||
|
|
||||||
preprocess_regexps = [
|
preprocess_regexps = [
|
||||||
|
@ -13,6 +13,7 @@ class FinancialTimes(BasicNewsRecipe):
|
|||||||
__author__ = 'Darko Miletic'
|
__author__ = 'Darko Miletic'
|
||||||
description = 'Financial world news'
|
description = 'Financial world news'
|
||||||
oldest_article = 2
|
oldest_article = 2
|
||||||
|
language = _('English')
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
|
@ -7,6 +7,7 @@ class Forbes(BasicNewsRecipe):
|
|||||||
__author__ = 'Darko Miletic'
|
__author__ = 'Darko Miletic'
|
||||||
oldest_article = 30
|
oldest_article = 30
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
|
language = _('English')
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
html2lrf_options = ['--base-font-size', '10']
|
html2lrf_options = ['--base-font-size', '10']
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ class Freakonomics(BasicNewsRecipe):
|
|||||||
title = 'Freakonomics Blog'
|
title = 'Freakonomics Blog'
|
||||||
description = 'The Hidden side of everything'
|
description = 'The Hidden side of everything'
|
||||||
__author__ = 'Kovid Goyal'
|
__author__ = 'Kovid Goyal'
|
||||||
|
language = _('English')
|
||||||
|
|
||||||
feeds = [('Blog', 'http://freakonomics.blogs.nytimes.com/feed/atom/')]
|
feeds = [('Blog', 'http://freakonomics.blogs.nytimes.com/feed/atom/')]
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ class FTheiseDe(BasicNewsRecipe):
|
|||||||
__author__ = 'Oliver Niesner'
|
__author__ = 'Oliver Niesner'
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
timefmt = ' [%d %b %Y]'
|
timefmt = ' [%d %b %Y]'
|
||||||
|
language = _('German')
|
||||||
max_articles_per_feed = 40
|
max_articles_per_feed = 40
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
|||||||
class Fudzilla(BasicNewsRecipe):
|
class Fudzilla(BasicNewsRecipe):
|
||||||
title = u'Fudzilla'
|
title = u'Fudzilla'
|
||||||
__author__ = 'Darko Miletic'
|
__author__ = 'Darko Miletic'
|
||||||
|
language = _('English')
|
||||||
description = 'Tech news'
|
description = 'Tech news'
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
|