merge from trunk

This commit is contained in:
ldolse 2011-01-20 10:03:30 +08:00
commit 7e0e3fbaf1
15 changed files with 1202 additions and 854 deletions

View File

@ -0,0 +1,64 @@
__license__ = 'GPL v3'
__copyright__ = '2011, Darko Miletic <darko.miletic at gmail.com>'
'''
gulfnews.com
'''
from calibre.web.feeds.news import BasicNewsRecipe
class GulfNews(BasicNewsRecipe):
title = 'Gulf News'
__author__ = 'Darko Miletic'
description = 'News from United Arab Emirrates, persian gulf and rest of the world'
publisher = 'Al Nisr Publishing LLC'
category = 'news, politics, UAE, world'
oldest_article = 2
max_articles_per_feed = 200
no_stylesheets = True
encoding = 'utf8'
use_embedded_content = False
language = 'en'
remove_empty_feeds = True
publication_type = 'newsportal'
masthead_url = 'http://gulfnews.com/media/img/gulf_news_logo.jpg'
extra_css = """
body{font-family: Arial,Helvetica,sans-serif }
img{margin-bottom: 0.4em; display:block}
h1{font-family: Georgia, 'Times New Roman', Times, serif}
ol,ul{list-style: none}
.synopsis{font-size: small}
.details{font-size: x-small}
.image{font-size: xx-small}
"""
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
remove_tags = [
dict(name=['meta','link','object','embed'])
,dict(attrs={'class':['quickLinks','ratings']})
,dict(attrs={'id':'imageSelector'})
]
remove_attributes=['lang']
keep_only_tags=[
dict(name='h1')
,dict(attrs={'class':['synopsis','details','image','article']})
]
feeds = [
(u'UAE News' , u'http://gulfnews.com/cmlink/1.446094')
,(u'Business' , u'http://gulfnews.com/cmlink/1.446098')
,(u'Entertainment' , u'http://gulfnews.com/cmlink/1.446095')
,(u'Sport' , u'http://gulfnews.com/cmlink/1.446096')
,(u'Life' , u'http://gulfnews.com/cmlink/1.446097')
]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -3,12 +3,17 @@ from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1274742400(BasicNewsRecipe): class AdvancedUserRecipe1274742400(BasicNewsRecipe):
title = u'Las Vegas Review Journal' title = u'Las Vegas Review Journal'
__author__ = 'Joel' __author__ = 'Kovid Goyal'
language = 'en' language = 'en'
oldest_article = 7 oldest_article = 7
max_articles_per_feed = 100 max_articles_per_feed = 100
keep_only_tags = [dict(id='content-main')]
remove_tags = [dict(id=['right-col-content', 'trending-topics']),
{'class':['ppy-outer']}
]
no_stylesheets = True
feeds = [ feeds = [
(u'News', u'http://www.lvrj.com/news.rss'), (u'News', u'http://www.lvrj.com/news.rss'),

View File

@ -20,8 +20,8 @@ class LaVanguardia(BasicNewsRecipe):
max_articles_per_feed = 100 max_articles_per_feed = 100
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
delay = 1 delay = 5
encoding = 'cp1252' # encoding = 'cp1252'
language = 'es' language = 'es'
direction = 'ltr' direction = 'ltr'
@ -35,7 +35,7 @@ class LaVanguardia(BasicNewsRecipe):
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
feeds = [ feeds = [
(u'Ciudadanos' , u'http://feeds.feedburner.com/lavanguardia/ciudadanos' ) (u'Portada' , u'http://feeds.feedburner.com/lavanguardia/home' )
,(u'Cultura' , u'http://feeds.feedburner.com/lavanguardia/cultura' ) ,(u'Cultura' , u'http://feeds.feedburner.com/lavanguardia/cultura' )
,(u'Deportes' , u'http://feeds.feedburner.com/lavanguardia/deportes' ) ,(u'Deportes' , u'http://feeds.feedburner.com/lavanguardia/deportes' )
,(u'Economia' , u'http://feeds.feedburner.com/lavanguardia/economia' ) ,(u'Economia' , u'http://feeds.feedburner.com/lavanguardia/economia' )
@ -45,17 +45,17 @@ class LaVanguardia(BasicNewsRecipe):
,(u'Internet y tecnologia', u'http://feeds.feedburner.com/lavanguardia/internet' ) ,(u'Internet y tecnologia', u'http://feeds.feedburner.com/lavanguardia/internet' )
,(u'Motor' , u'http://feeds.feedburner.com/lavanguardia/motor' ) ,(u'Motor' , u'http://feeds.feedburner.com/lavanguardia/motor' )
,(u'Politica' , u'http://feeds.feedburner.com/lavanguardia/politica' ) ,(u'Politica' , u'http://feeds.feedburner.com/lavanguardia/politica' )
,(u'Sucessos' , u'http://feeds.feedburner.com/lavanguardia/sucesos' ) ,(u'Sucesos' , u'http://feeds.feedburner.com/lavanguardia/sucesos' )
] ]
keep_only_tags = [ keep_only_tags = [
dict(name='div', attrs={'class':'element1_3'}) dict(name='div', attrs={'class':'detalle noticia'})
] ]
remove_tags = [ remove_tags = [
dict(name=['object','link','script']) dict(name=['object','link','script'])
,dict(name='div', attrs={'class':['colC','peu']}) ,dict(name='div', attrs={'class':['colC','peu','jstoolbar']})
] ]
remove_tags_after = [dict(name='div', attrs={'class':'text'})] remove_tags_after = [dict(name='div', attrs={'class':'text'})]
@ -67,4 +67,3 @@ class LaVanguardia(BasicNewsRecipe):
for item in soup.findAll(style=True): for item in soup.findAll(style=True):
del item['style'] del item['style']
return soup return soup

View File

@ -98,6 +98,9 @@ class PRS505(USBMS):
THUMBNAIL_HEIGHT = 200 THUMBNAIL_HEIGHT = 200
MAX_PATH_LEN = 201 # 250 - (max(len(CACHE_THUMBNAIL), len(MEDIA_THUMBNAIL)) +
# len('main_thumbnail.jpg') + 1)
def windows_filter_pnp_id(self, pnp_id): def windows_filter_pnp_id(self, pnp_id):
return '_LAUNCHER' in pnp_id return '_LAUNCHER' in pnp_id
@ -201,10 +204,13 @@ class PRS505(USBMS):
self._card_b_prefix if idx == 2 \ self._card_b_prefix if idx == 2 \
else self._main_prefix else self._main_prefix
for book in bl: for book in bl:
try:
p = os.path.join(prefix, book.lpath) p = os.path.join(prefix, book.lpath)
self._upload_cover(os.path.dirname(p), self._upload_cover(os.path.dirname(p),
os.path.splitext(os.path.basename(p))[0], os.path.splitext(os.path.basename(p))[0],
book, p) book, p)
except:
debug_print('FAILED to upload cover', p)
else: else:
debug_print('PRS505: NOT uploading covers in sync_booklists') debug_print('PRS505: NOT uploading covers in sync_booklists')
@ -232,8 +238,7 @@ class PRS505(USBMS):
try: try:
self._upload_cover(path, filename, metadata, filepath) self._upload_cover(path, filename, metadata, filepath)
except: except:
import traceback debug_print('FAILED to upload cover', filepath)
traceback.print_exc()
def _upload_cover(self, path, filename, metadata, filepath): def _upload_cover(self, path, filename, metadata, filepath):
if metadata.thumbnail and metadata.thumbnail[-1]: if metadata.thumbnail and metadata.thumbnail[-1]:

View File

@ -98,6 +98,9 @@ class Device(DeviceConfig, DevicePlugin):
# copy these back to the library # copy these back to the library
BACKLOADING_ERROR_MESSAGE = None BACKLOADING_ERROR_MESSAGE = None
#: The maximum length of paths created on the device
MAX_PATH_LEN = 250
def reset(self, key='-1', log_packets=False, report_progress=None, def reset(self, key='-1', log_packets=False, report_progress=None,
detected_device=None): detected_device=None):
self._main_prefix = self._card_a_prefix = self._card_b_prefix = None self._main_prefix = self._card_a_prefix = self._card_b_prefix = None
@ -875,7 +878,7 @@ class Device(DeviceConfig, DevicePlugin):
def create_upload_path(self, path, mdata, fname, create_dirs=True): def create_upload_path(self, path, mdata, fname, create_dirs=True):
path = os.path.abspath(path) path = os.path.abspath(path)
extra_components = [] maxlen = self.MAX_PATH_LEN
special_tag = None special_tag = None
if mdata.tags: if mdata.tags:
@ -902,7 +905,7 @@ class Device(DeviceConfig, DevicePlugin):
app_id = str(getattr(mdata, 'application_id', '')) app_id = str(getattr(mdata, 'application_id', ''))
# The db id will be in the created filename # The db id will be in the created filename
extra_components = get_components(template, mdata, fname, extra_components = get_components(template, mdata, fname,
timefmt=opts.send_timefmt, length=250-len(app_id)-1) timefmt=opts.send_timefmt, length=maxlen-len(app_id)-1)
if not extra_components: if not extra_components:
extra_components.append(sanitize(self.filename_callback(fname, extra_components.append(sanitize(self.filename_callback(fname,
mdata))) mdata)))
@ -937,12 +940,11 @@ class Device(DeviceConfig, DevicePlugin):
return ans return ans
extra_components = list(map(remove_trailing_periods, extra_components)) extra_components = list(map(remove_trailing_periods, extra_components))
components = shorten_components_to(250 - len(path), extra_components) components = shorten_components_to(maxlen - len(path), extra_components)
components = self.sanitize_path_components(components) components = self.sanitize_path_components(components)
filepath = os.path.join(path, *components) filepath = os.path.join(path, *components)
filedir = os.path.dirname(filepath) filedir = os.path.dirname(filepath)
if create_dirs and not os.path.exists(filedir): if create_dirs and not os.path.exists(filedir):
os.makedirs(filedir) os.makedirs(filedir)

View File

@ -42,6 +42,12 @@ option.
For full documentation of the conversion system see For full documentation of the conversion system see
''') + 'http://calibre-ebook.com/user_manual/conversion.html' ''') + 'http://calibre-ebook.com/user_manual/conversion.html'
HEURISTIC_OPTIONS = ['markup_chapter_headings',
'italicize_common_cases', 'fix_indents',
'html_unwrap_factor', 'unwrap_lines',
'delete_blank_paragraphs', 'format_scene_breaks',
'dehyphenate', 'renumber_headings']
def print_help(parser, log): def print_help(parser, log):
help = parser.format_help().encode(preferred_encoding, 'replace') help = parser.format_help().encode(preferred_encoding, 'replace')
log(help) log(help)
@ -83,6 +89,8 @@ def option_recommendation_to_cli_option(add_option, rec):
if opt.long_switch == 'verbose': if opt.long_switch == 'verbose':
attrs['action'] = 'count' attrs['action'] = 'count'
attrs.pop('type', '') attrs.pop('type', '')
if opt.name in HEURISTIC_OPTIONS and rec.recommended_value is True:
switches = ['--disable-'+opt.long_switch]
add_option(Option(*switches, **attrs)) add_option(Option(*switches, **attrs))
def add_input_output_options(parser, plumber): def add_input_output_options(parser, plumber):
@ -131,14 +139,11 @@ def add_pipeline_options(parser, plumber):
), ),
'HEURISTIC PROCESSING' : ( 'HEURISTIC PROCESSING' : (
_('Modify the document text and structure using common patterns.'), _('Modify the document text and structure using common'
[ ' patterns. Disabled by default. Use %s to enable. '
'enable_heuristics', 'markup_chapter_headings', ' Individual actions can be disabled with the %s options.')
'italicize_common_cases', 'fix_indents', % ('--enable-heuristics', '--disable-*'),
'html_unwrap_factor', 'unwrap_lines', ['enable_heuristics'] + HEURISTIC_OPTIONS
'delete_blank_paragraphs', 'format_scene_breaks',
'dehyphenate', 'renumber_headings',
]
), ),
'SEARCH AND REPLACE' : ( 'SEARCH AND REPLACE' : (

View File

@ -490,19 +490,19 @@ OptionRecommendation(name='enable_heuristics',
'heuristic processing to take place.')), 'heuristic processing to take place.')),
OptionRecommendation(name='markup_chapter_headings', OptionRecommendation(name='markup_chapter_headings',
recommended_value=False, level=OptionRecommendation.LOW, recommended_value=True, level=OptionRecommendation.LOW,
help=_('Detect unformatted chapter headings and sub headings. Change ' help=_('Detect unformatted chapter headings and sub headings. Change '
'them to h2 and h3 tags. This setting will not create a TOC, ' 'them to h2 and h3 tags. This setting will not create a TOC, '
'but can be used in conjunction with structure detection to create ' 'but can be used in conjunction with structure detection to create '
'one.')), 'one.')),
OptionRecommendation(name='italicize_common_cases', OptionRecommendation(name='italicize_common_cases',
recommended_value=False, level=OptionRecommendation.LOW, recommended_value=True, level=OptionRecommendation.LOW,
help=_('Look for common words and patterns that denote ' help=_('Look for common words and patterns that denote '
'italics and italicize them.')), 'italics and italicize them.')),
OptionRecommendation(name='fix_indents', OptionRecommendation(name='fix_indents',
recommended_value=False, level=OptionRecommendation.LOW, recommended_value=True, level=OptionRecommendation.LOW,
help=_('Turn indentation created from multiple non-breaking space entities ' help=_('Turn indentation created from multiple non-breaking space entities '
'into CSS indents.')), 'into CSS indents.')),
@ -515,28 +515,28 @@ OptionRecommendation(name='html_unwrap_factor',
'be reduced')), 'be reduced')),
OptionRecommendation(name='unwrap_lines', OptionRecommendation(name='unwrap_lines',
recommended_value=False, level=OptionRecommendation.LOW, recommended_value=True, level=OptionRecommendation.LOW,
help=_('Unwrap lines using punctuation and other formatting clues.')), help=_('Unwrap lines using punctuation and other formatting clues.')),
OptionRecommendation(name='delete_blank_paragraphs', OptionRecommendation(name='delete_blank_paragraphs',
recommended_value=False, level=OptionRecommendation.LOW, recommended_value=True, level=OptionRecommendation.LOW,
help=_('Remove empty paragraphs from the document when they exist between ' help=_('Remove empty paragraphs from the document when they exist between '
'every other paragraph')), 'every other paragraph')),
OptionRecommendation(name='format_scene_breaks', OptionRecommendation(name='format_scene_breaks',
recommended_value=False, level=OptionRecommendation.LOW, recommended_value=True, level=OptionRecommendation.LOW,
help=_('Left aligned scene break markers are center aligned. ' help=_('Left aligned scene break markers are center aligned. '
'Replace soft scene breaks that use multiple blank lines with' 'Replace soft scene breaks that use multiple blank lines with'
'horizontal rules.')), 'horizontal rules.')),
OptionRecommendation(name='dehyphenate', OptionRecommendation(name='dehyphenate',
recommended_value=False, level=OptionRecommendation.LOW, recommended_value=True, level=OptionRecommendation.LOW,
help=_('Analyze hyphenated words throughout the document. The ' help=_('Analyze hyphenated words throughout the document. The '
'document itself is used as a dictionary to determine whether hyphens ' 'document itself is used as a dictionary to determine whether hyphens '
'should be retained or removed.')), 'should be retained or removed.')),
OptionRecommendation(name='renumber_headings', OptionRecommendation(name='renumber_headings',
recommended_value=False, level=OptionRecommendation.LOW, recommended_value=True, level=OptionRecommendation.LOW,
help=_('Looks for occurrences of sequential <h1> or <h2> tags. ' help=_('Looks for occurrences of sequential <h1> or <h2> tags. '
'The tags are renumbered to prevent splitting in the middle ' 'The tags are renumbered to prevent splitting in the middle '
'of chapter headings.')), 'of chapter headings.')),

View File

@ -35,7 +35,7 @@
</size> </size>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Sections to include in catalog. All catalogs include 'Books by Author'.</string> <string>Sections to include in catalog.</string>
</property> </property>
<property name="title"> <property name="title">
<string>Included sections</string> <string>Included sections</string>
@ -79,13 +79,13 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QCheckBox" name="generate_authors"> <widget class="QCheckBox" name="generate_authors">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>true</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Books by Author</string> <string>Books by Author</string>
</property> </property>
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>false</bool>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -12,7 +12,7 @@ from calibre.gui2 import error_dialog
class SearchAndReplaceWidget(Widget, Ui_Form): class SearchAndReplaceWidget(Widget, Ui_Form):
TITLE = _(u'Search\u00a0&\nReplace') TITLE = _('Search\n&\nReplace')
HELP = _('Modify the document text and structure using user defined patterns.') HELP = _('Modify the document text and structure using user defined patterns.')
COMMIT_NAME = 'search_and_replace' COMMIT_NAME = 'search_and_replace'
ICON = I('search.png') ICON = I('search.png')

View File

@ -599,7 +599,7 @@ class BulkEnumeration(BulkBase, Enumeration):
value = None value = None
ret_value = None ret_value = None
dialog_shown = False dialog_shown = False
for book_id in book_ids: for i,book_id in enumerate(book_ids):
val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True) val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True)
if val and val not in self.col_metadata['display']['enum_values']: if val and val not in self.col_metadata['display']['enum_values']:
if not dialog_shown: if not dialog_shown:
@ -610,7 +610,7 @@ class BulkEnumeration(BulkBase, Enumeration):
show=True, show_copy_button=False) show=True, show_copy_button=False)
dialog_shown = True dialog_shown = True
ret_value = ' nochange ' ret_value = ' nochange '
elif value is not None and value != val: elif (value is not None and value != val) or (val and i != 0):
ret_value = ' nochange ' ret_value = ' nochange '
value = val value = val
if ret_value is None: if ret_value is None:

View File

@ -29,7 +29,6 @@ FIELDS = ['all', 'author_sort', 'authors', 'comments',
'series_index', 'series', 'size', 'tags', 'timestamp', 'title', 'series_index', 'series', 'size', 'tags', 'timestamp', 'title',
'uuid'] 'uuid']
#Allowed fields for template #Allowed fields for template
TEMPLATE_ALLOWED_FIELDS = [ 'author_sort', 'authors', 'id', 'isbn', 'pubdate', TEMPLATE_ALLOWED_FIELDS = [ 'author_sort', 'authors', 'id', 'isbn', 'pubdate',
'publisher', 'series_index', 'series', 'tags', 'timestamp', 'title', 'uuid' ] 'publisher', 'series_index', 'series', 'tags', 'timestamp', 'title', 'uuid' ]
@ -605,43 +604,42 @@ class EPUB_MOBI(CatalogPlugin):
"Default: '%default'\n" "Default: '%default'\n"
"Applies to: ePub, MOBI output formats")), "Applies to: ePub, MOBI output formats")),
Option('--generate-authors', Option('--generate-authors',
default=True, default=False,
dest='generate_authors', dest='generate_authors',
action = 'store_true', action = 'store_true',
help=_("Include 'Authors' section in catalog." help=_("Include 'Authors' section in catalog.\n"
"This switch is ignored - Books By Author section is always generated."
"Default: '%default'\n" "Default: '%default'\n"
"Applies to: ePub, MOBI output formats")), "Applies to: ePub, MOBI output formats")),
Option('--generate-descriptions', Option('--generate-descriptions',
default=True, default=False,
dest='generate_descriptions', dest='generate_descriptions',
action = 'store_true', action = 'store_true',
help=_("Include book descriptions in catalog.\n" help=_("Include 'Descriptions' section in catalog.\n"
"Default: '%default'\n" "Default: '%default'\n"
"Applies to: ePub, MOBI output formats")), "Applies to: ePub, MOBI output formats")),
Option('--generate-genres', Option('--generate-genres',
default=True, default=False,
dest='generate_genres', dest='generate_genres',
action = 'store_true', action = 'store_true',
help=_("Include 'Genres' section in catalog.\n" help=_("Include 'Genres' section in catalog.\n"
"Default: '%default'\n" "Default: '%default'\n"
"Applies to: ePub, MOBI output formats")), "Applies to: ePub, MOBI output formats")),
Option('--generate-titles', Option('--generate-titles',
default=True, default=False,
dest='generate_titles', dest='generate_titles',
action = 'store_true', action = 'store_true',
help=_("Include 'Titles' section in catalog.\n" help=_("Include 'Titles' section in catalog.\n"
"Default: '%default'\n" "Default: '%default'\n"
"Applies to: ePub, MOBI output formats")), "Applies to: ePub, MOBI output formats")),
Option('--generate-series', Option('--generate-series',
default=True, default=False,
dest='generate_series', dest='generate_series',
action = 'store_true', action = 'store_true',
help=_("Include 'Series' section in catalog.\n" help=_("Include 'Series' section in catalog.\n"
"Default: '%default'\n" "Default: '%default'\n"
"Applies to: ePub, MOBI output formats")), "Applies to: ePub, MOBI output formats")),
Option('--generate-recently-added', Option('--generate-recently-added',
default=True, default=False,
dest='generate_recently_added', dest='generate_recently_added',
action = 'store_true', action = 'store_true',
help=_("Include 'Recently Added' section in catalog.\n" help=_("Include 'Recently Added' section in catalog.\n"
@ -976,7 +974,7 @@ class EPUB_MOBI(CatalogPlugin):
self.__thumbWidth = 0 self.__thumbWidth = 0
self.__thumbHeight = 0 self.__thumbHeight = 0
self.__title = opts.catalog_title self.__title = opts.catalog_title
self.__totalSteps = 8.0 self.__totalSteps = 6.0
self.__useSeriesPrefixInTitlesSection = False self.__useSeriesPrefixInTitlesSection = False
self.__verbose = opts.verbose self.__verbose = opts.verbose
@ -1014,17 +1012,21 @@ class EPUB_MOBI(CatalogPlugin):
(self.__archive_path, float(cached_thumb_width))) (self.__archive_path, float(cached_thumb_width)))
# Tweak build steps based on optional sections: 1 call for HTML, 1 for NCX # Tweak build steps based on optional sections: 1 call for HTML, 1 for NCX
incremental_jobs = 0
if self.opts.generate_authors:
incremental_jobs += 2
if self.opts.generate_titles: if self.opts.generate_titles:
self.__totalSteps += 2 incremental_jobs += 2
if self.opts.generate_recently_added: if self.opts.generate_recently_added:
self.__totalSteps += 2 incremental_jobs += 2
if self.generateRecentlyRead: if self.generateRecentlyRead:
self.__totalSteps += 2 incremental_jobs += 2
if self.opts.generate_series: if self.opts.generate_series:
self.__totalSteps += 2 incremental_jobs += 2
if self.opts.generate_descriptions: if self.opts.generate_descriptions:
# +1 thumbs # +1 thumbs
self.__totalSteps += 3 incremental_jobs += 3
self.__totalSteps += incremental_jobs
# Load section list templates # Load section list templates
templates = [] templates = []
@ -1358,6 +1360,7 @@ class EPUB_MOBI(CatalogPlugin):
if self.opts.generate_descriptions: if self.opts.generate_descriptions:
self.generateThumbnails() self.generateThumbnails()
self.generateHTMLDescriptions() self.generateHTMLDescriptions()
if self.opts.generate_authors:
self.generateHTMLByAuthor() self.generateHTMLByAuthor()
if self.opts.generate_titles: if self.opts.generate_titles:
self.generateHTMLByTitle() self.generateHTMLByTitle()
@ -1365,6 +1368,13 @@ class EPUB_MOBI(CatalogPlugin):
self.generateHTMLBySeries() self.generateHTMLBySeries()
if self.opts.generate_genres: if self.opts.generate_genres:
self.generateHTMLByTags() self.generateHTMLByTags()
# If this is the only Section, and there are no genres, bail
if self.opts.section_list == ['Genres'] and not self.genres:
error_msg = _("No Genres found to catalog.\nCheck 'Excluded genres'\nin E-book options.\n")
self.opts.log.error(error_msg)
self.error.append(_('No books available to catalog'))
self.error.append(error_msg)
return False
if self.opts.generate_recently_added: if self.opts.generate_recently_added:
self.generateHTMLByDateAdded() self.generateHTMLByDateAdded()
if self.generateRecentlyRead: if self.generateRecentlyRead:
@ -1372,6 +1382,7 @@ class EPUB_MOBI(CatalogPlugin):
self.generateOPF() self.generateOPF()
self.generateNCXHeader() self.generateNCXHeader()
if self.opts.generate_authors:
self.generateNCXByAuthor("Authors") self.generateNCXByAuthor("Authors")
if self.opts.generate_titles: if self.opts.generate_titles:
self.generateNCXByTitle("Titles") self.generateNCXByTitle("Titles")
@ -1508,7 +1519,6 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
for tag in exclude_tags: for tag in exclude_tags:
search_terms.append("tag:=%s" % tag) search_terms.append("tag:=%s" % tag)
search_phrase = "not (%s)" % " or ".join(search_terms) search_phrase = "not (%s)" % " or ".join(search_terms)
# If a list of ids are provided, don't use search_text # If a list of ids are provided, don't use search_text
if self.opts.ids: if self.opts.ids:
self.opts.search_text = search_phrase self.opts.search_text = search_phrase
@ -1879,6 +1889,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
# Link to author # Link to author
emTag = Tag(soup, "em") emTag = Tag(soup, "em")
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
if self.opts.generate_authors:
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(book['author'])) aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(book['author']))
aTag.insert(0, NavigableString(book['author'])) aTag.insert(0, NavigableString(book['author']))
emTag.insert(0,aTag) emTag.insert(0,aTag)
@ -2149,6 +2160,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
pAuthorTag = Tag(soup, "p") pAuthorTag = Tag(soup, "p")
pAuthorTag['class'] = "author_index" pAuthorTag['class'] = "author_index"
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
if self.opts.generate_authors:
aTag['name'] = "%s" % self.generateAuthorAnchor(current_author) aTag['name'] = "%s" % self.generateAuthorAnchor(current_author)
aTag.insert(0,NavigableString(current_author)) aTag.insert(0,NavigableString(current_author))
pAuthorTag.insert(0,aTag) pAuthorTag.insert(0,aTag)
@ -2276,6 +2288,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
# Link to author # Link to author
emTag = Tag(soup, "em") emTag = Tag(soup, "em")
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
if self.opts.generate_authors:
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author'])) aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author']))
aTag.insert(0, NavigableString(new_entry['author'])) aTag.insert(0, NavigableString(new_entry['author']))
emTag.insert(0,aTag) emTag.insert(0,aTag)
@ -2425,6 +2438,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
# Link to author # Link to author
emTag = Tag(soup, "em") emTag = Tag(soup, "em")
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
if self.opts.generate_authors:
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author'])) aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author']))
aTag.insert(0, NavigableString(new_entry['author'])) aTag.insert(0, NavigableString(new_entry['author']))
emTag.insert(0,aTag) emTag.insert(0,aTag)
@ -2473,6 +2487,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
# Link to author # Link to author
emTag = Tag(soup, "em") emTag = Tag(soup, "em")
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
if self.opts.generate_authors:
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author'])) aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author']))
aTag.insert(0, NavigableString(new_entry['author'])) aTag.insert(0, NavigableString(new_entry['author']))
emTag.insert(0,aTag) emTag.insert(0,aTag)
@ -2692,6 +2707,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
# Link to author # Link to author
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
if self.opts.generate_authors:
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor",
self.generateAuthorAnchor(escape(' & '.join(book['authors'])))) self.generateAuthorAnchor(escape(' & '.join(book['authors']))))
aTag.insert(0, NavigableString(' &amp; '.join(book['authors']))) aTag.insert(0, NavigableString(' &amp; '.join(book['authors'])))
@ -3074,10 +3090,34 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
textTag.insert(0, NavigableString(self.title)) textTag.insert(0, NavigableString(self.title))
navLabelTag.insert(0, textTag) navLabelTag.insert(0, textTag)
navPointTag.insert(0, navLabelTag) navPointTag.insert(0, navLabelTag)
if self.opts.generate_authors:
contentTag = Tag(soup, 'content') contentTag = Tag(soup, 'content')
#contentTag['src'] = "content/book_%d.html" % int(self.booksByTitle[0]['id'])
contentTag['src'] = "content/ByAlphaAuthor.html" contentTag['src'] = "content/ByAlphaAuthor.html"
navPointTag.insert(1, contentTag) navPointTag.insert(1, contentTag)
elif self.opts.generate_titles:
contentTag = Tag(soup, 'content')
contentTag['src'] = "content/ByAlphaTitle.html"
navPointTag.insert(1, contentTag)
elif self.opts.generate_series:
contentTag = Tag(soup, 'content')
contentTag['src'] = "content/BySeries.html"
navPointTag.insert(1, contentTag)
elif self.opts.generate_genres:
contentTag = Tag(soup, 'content')
contentTag['src'] = "content/ByGenres.html"
navPointTag.insert(1, contentTag)
elif self.opts.generate_recently_added:
contentTag = Tag(soup, 'content')
contentTag['src'] = "content/ByDateAdded.html"
navPointTag.insert(1, contentTag)
else:
sort_descriptions_by = self.booksByAuthor if self.opts.sort_descriptions_by_author \
else self.booksByTitle
contentTag = Tag(soup, 'content')
contentTag['src'] = "content/book_%d.html" % int(sort_descriptions_by[0]['id'])
navPointTag.insert(1, contentTag)
cmiTag = Tag(soup, '%s' % 'calibre:meta-img') cmiTag = Tag(soup, '%s' % 'calibre:meta-img')
cmiTag['name'] = "mastheadImage" cmiTag['name'] = "mastheadImage"
cmiTag['src'] = "images/mastheadImage.gif" cmiTag['src'] = "images/mastheadImage.gif"
@ -4140,6 +4180,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
pAuthorTag = Tag(soup, "p") pAuthorTag = Tag(soup, "p")
pAuthorTag['class'] = "author_index" pAuthorTag['class'] = "author_index"
aTag = Tag(soup, "a") aTag = Tag(soup, "a")
if self.opts.generate_authors:
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(book['author'])) aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(book['author']))
aTag.insert(0, book['author']) aTag.insert(0, book['author'])
pAuthorTag.insert(0,aTag) pAuthorTag.insert(0,aTag)
@ -4371,6 +4412,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
# Insert the author link (always) # Insert the author link (always)
aTag = body.find('a', attrs={'class':'author'}) aTag = body.find('a', attrs={'class':'author'})
if self.opts.generate_authors:
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor",
self.generateAuthorAnchor(book['author'])) self.generateAuthorAnchor(book['author']))
@ -4860,6 +4902,8 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
opts.basename = "Catalog" opts.basename = "Catalog"
opts.cli_environment = not hasattr(opts,'sync') opts.cli_environment = not hasattr(opts,'sync')
# Hard-wired to always sort descriptions by author, with series after non-series
opts.sort_descriptions_by_author = True opts.sort_descriptions_by_author = True
build_log = [] build_log = []
@ -4898,14 +4942,13 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
if opts_dict['ids']: if opts_dict['ids']:
build_log.append(" book count: %d" % len(opts_dict['ids'])) build_log.append(" book count: %d" % len(opts_dict['ids']))
'''
sections_list = [] sections_list = []
if opts.generate_authors: if opts.generate_authors:
sections_list.append('Authors') sections_list.append('Authors')
'''
sections_list = ['Authors']
if opts.generate_titles: if opts.generate_titles:
sections_list.append('Titles') sections_list.append('Titles')
if opts.generate_series:
sections_list.append('Series')
if opts.generate_genres: if opts.generate_genres:
sections_list.append('Genres') sections_list.append('Genres')
if opts.generate_recently_added: if opts.generate_recently_added:
@ -4913,7 +4956,21 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
if opts.generate_descriptions: if opts.generate_descriptions:
sections_list.append('Descriptions') sections_list.append('Descriptions')
if not sections_list:
if opts.cli_environment:
opts.log.warn('*** No Section switches specified, enabling all Sections ***')
opts.generate_authors = True
opts.generate_titles = True
opts.generate_series = True
opts.generate_genres = True
opts.generate_recently_added = True
opts.generate_descriptions = True
sections_list = ['Authors','Titles','Series','Genres','Recently Added','Descriptions']
else:
opts.log.warn('\n*** No enabled Sections, terminating catalog generation ***')
return ["No Included Sections","No enabled Sections.\nCheck E-book options tab\n'Included sections'\n"]
build_log.append(u" Sections: %s" % ', '.join(sections_list)) build_log.append(u" Sections: %s" % ', '.join(sections_list))
opts.section_list = sections_list
# Limit thumb_width to 1.0" - 2.0" # Limit thumb_width to 1.0" - 2.0"
try: try:
@ -4948,6 +5005,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
# Launch the Catalog builder # Launch the Catalog builder
catalog = self.CatalogBuilder(db, opts, self, report_progress=notification) catalog = self.CatalogBuilder(db, opts, self, report_progress=notification)
if opts.verbose: if opts.verbose:
log.info(" Begin catalog source generation") log.info(" Begin catalog source generation")
catalog.createDirectoryStructure() catalog.createDirectoryStructure()

File diff suppressed because it is too large Load Diff

View File

@ -42,30 +42,44 @@ def supports_long_names(path):
else: else:
return True return True
def shorten_components_to(length, components): def shorten_component(s, by_what):
l = len(s)
if l < by_what:
return s
l = (l - by_what)//2
if l <= 0:
return s
return s[:l] + s[-l:]
def shorten_components_to(length, components, more_to_take=0):
filepath = os.sep.join(components) filepath = os.sep.join(components)
extra = len(filepath) - length extra = len(filepath) - (length - more_to_take)
if extra < 1: if extra < 1:
return components return components
delta = int(ceil(extra/float(len(components)))) deltas = []
ans = []
for x in components: for x in components:
pct = len(x)/float(len(filepath))
deltas.append(int(ceil(pct*extra)))
ans = []
for i, x in enumerate(components):
delta = deltas[i]
if delta > len(x): if delta > len(x):
r = x[0] if x is components[-1] else '' r = x[0] if x is components[-1] else ''
else: else:
if x is components[-1]: if x is components[-1]:
b, e = os.path.splitext(x) b, e = os.path.splitext(x)
if e == '.': e = '' if e == '.': e = ''
r = b[:-delta]+e r = shorten_component(b, delta)+e
if r.startswith('.'): r = x[0]+r if r.startswith('.'): r = x[0]+r
else: else:
r = x[:-delta] r = shorten_component(x, delta)
r = r.strip() r = r.strip()
if not r: if not r:
r = x.strip()[0] if x.strip() else 'x' r = x.strip()[0] if x.strip() else 'x'
ans.append(r) ans.append(r)
if len(os.sep.join(ans)) > length: if len(os.sep.join(ans)) > length:
return shorten_components_to(length, ans) return shorten_components_to(length, components, more_to_take+2)
return ans return ans
def find_executable_in_path(name, path=None): def find_executable_in_path(name, path=None):

View File

@ -75,7 +75,7 @@ class FormatterFunction(object):
exc_type, exc_value, exc_traceback = sys.exc_info() exc_type, exc_value, exc_traceback = sys.exc_info()
info = ': '.join(traceback.format_exception(exc_type, exc_value, info = ': '.join(traceback.format_exception(exc_type, exc_value,
exc_traceback)[-2:]).replace('\n', '') exc_traceback)[-2:]).replace('\n', '')
return _('Exception ' + info) return _('Exception ') + info
all_builtin_functions = [] all_builtin_functions = []
class BuiltinFormatterFunction(FormatterFunction): class BuiltinFormatterFunction(FormatterFunction):