diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py index c22d24a6a7..47036a7b6d 100644 --- a/resources/default_tweaks.py +++ b/resources/default_tweaks.py @@ -245,19 +245,6 @@ sony_collection_name_template='{value}{category:| (|)}' sony_collection_sorting_rules = [] -#: Create search terms to apply a query across several built-in search terms. -# Syntax: {'new term':['existing term 1', 'term 2', ...], 'new':['old'...] ...} -# Example: create the term 'myseries' that when used as myseries:foo would -# search all of the search categories 'series', '#myseries', and '#myseries2': -# grouped_search_terms={'myseries':['series','#myseries', '#myseries2']} -# Example: two search terms 'a' and 'b' both that search 'tags' and '#mytags': -# grouped_search_terms={'a':['tags','#mytags'], 'b':['tags','#mytags']} -# Note: You cannot create a search term that is a duplicate of an existing term. -# Such duplicates will be silently ignored. Also note that search terms ignore -# case. 'MySearch' and 'mysearch' are the same term. -grouped_search_terms = {} - - #: Control how tags are applied when copying books to another library # Set this to True to ensure that tags in 'Tags to add when adding # a book' are added when copying books to another library diff --git a/resources/recipes/adevarul.recipe b/resources/recipes/adevarul.recipe new file mode 100644 index 0000000000..ea0f2826ce --- /dev/null +++ b/resources/recipes/adevarul.recipe @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = u'2011, Silviu Cotoar\u0103' +''' +adevarul.ro +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class Adevarul(BasicNewsRecipe): + title = u'Adev\u0103rul' + language = 'ro' + __author__ = u'Silviu Cotoar\u0103' + description = u'\u0218tiri din Rom\u00e2nia' + publisher = 'Adevarul' + category = 'Ziare,Stiri,Romania' + oldest_article = 5 + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + encoding = 'utf-8' + remove_javascript = True + cover_url = 'http://upload.wikimedia.org/wikipedia/en/d/d6/Logo_noul_adevarul.png' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [ dict(name='div', attrs={'class':'article_header'}) + ,dict(name='div', attrs={'class':'bd'}) + ] + + + remove_tags = [ dict(name='div', attrs={'class':'bb-wg-article_related_attachements'}) + ,dict(name='div', attrs={'class':'bb-md bb-md-article_comments'}) + ,dict(name='form', attrs={'id':'bb-comment-create-form'}) + ] + + remove_tags_after = [ dict(name='form', attrs={'id':'bb-comment-create-form'}) ] + + feeds = [ (u'\u0218tiri', u'http://www.adevarul.ro/rss/latest') ] + + def preprocess_html(self, soup): + return self.adeify_images(soup) + diff --git a/resources/recipes/aprospect.recipe b/resources/recipes/aprospect.recipe old mode 100755 new mode 100644 diff --git a/resources/recipes/capital.recipe b/resources/recipes/capital.recipe new file mode 100644 index 0000000000..b8fc839a06 --- /dev/null +++ b/resources/recipes/capital.recipe @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = u'2011, Silviu Cotoar\u0103' +''' +capital.ro +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class Capital(BasicNewsRecipe): + title = 'Capital' + __author__ = u'Silviu Cotoar\u0103' + description = u'\u0218tiri din Rom\u00e2nia' + oldest_article = 5 + language = 'ro' + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + category = 'Ziare,Stiri,Romania' + encoding = 'utf-8' + remove_javascript = True + publisher = 'Capital' + cover_url = 'http://www.mediapress.ro/imagini/sigla-capital-s16.gif' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [ dict(name='div', attrs={'class':'single one_article'}) + ] + + remove_tags = [ dict(name='div', attrs={'class':'single_details'}) + , dict(name='div', attrs={'class':'tx-addoceansbanners-pi1'}) + ] + + feeds = [(u'\u0218tiri', u'http://www.capital.ro/rss.html') ] + + def preprocess_html(self, soup): + return self.adeify_images(soup) diff --git a/resources/recipes/catavencu.recipe b/resources/recipes/catavencu.recipe new file mode 100644 index 0000000000..5f056825b5 --- /dev/null +++ b/resources/recipes/catavencu.recipe @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = u'2011, Silviu Cotoar\u0103' +''' +catavencu.ro +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class Catavencu(BasicNewsRecipe): + title = u'Academia Ca\u0163avencu' + __author__ = u'Silviu Cotoar\u0103' + description = 'Tagma cum laude' + publisher = 'Catavencu' + oldest_article = 5 + language = 'ro' + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + category = 'Ziare' + encoding = 'utf-8' + cover_url = 'http://upload.wikimedia.org/wikipedia/en/1/1e/Academia_Catavencu.jpg' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [ + dict(name='ul', attrs={'class':'articles'}) + ] + + remove_tags = [ + dict(name='div', attrs={'class':['tools']}) + , dict(name='div', attrs={'class':['share']}) + , dict(name='div', attrs={'class':['category']}) + , dict(name='div', attrs={'id':['comments']}) + ] + + remove_tags_after = [ + dict(name='div', attrs={'id':'comments'}) + ] + + feeds = [ + (u'Feeds', u'http://catavencu.ro/feed/rss') + ] + + def preprocess_html(self, soup): + return self.adeify_images(soup) diff --git a/resources/recipes/gandul.recipe b/resources/recipes/gandul.recipe new file mode 100644 index 0000000000..774843f568 --- /dev/null +++ b/resources/recipes/gandul.recipe @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = u'2011, Silviu Cotoar\u0103' +''' +gandul.info +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class Gandul(BasicNewsRecipe): + title = u'G\u00E2ndul' + __author__ = u'Silviu Cotoar\u0103' + publisher = 'Gandul' + description = 'Cotidian Online' + oldest_article = 5 + language = 'ro' + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + category = 'Ziare,Stiri,Romania' + encoding = 'utf-8' + cover_url = 'http://storage0.dms.mpinteractiv.ro/media/1/1/1706/1064063/1/logo.jpg?width=400' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [ + dict(name='div', attrs={'class':'article'}) + ] + + remove_tags = [ + dict(name='a', attrs={'class':'photo'}) + , dict(name='div', attrs={'class':'ad'}) + ] + + feeds = [ + (u'\u0218tiri', u'http://www.gandul.info/rss-stiri-prima-pagina.xml') + ] + + def preprocess_html(self, soup): + return self.adeify_images(soup) diff --git a/resources/recipes/hotnews.recipe b/resources/recipes/hotnews.recipe new file mode 100644 index 0000000000..44b6f0f57b --- /dev/null +++ b/resources/recipes/hotnews.recipe @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = u'2011, Silviu Cotoar\u0103' +''' +hotnews.ro +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class Hotnews(BasicNewsRecipe): + title = 'Hotnews' + __author__ = u'Silviu Cotoar\u0103' + description = u'\u0218tiri din Rom\u00e2nia' + publisher = 'Hotnews' + oldest_article = 5 + language = 'ro' + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + category = 'Ziare,Stiri,Romania' + encoding = 'utf-8' + cover_url = 'http://www.hotnews.ro/images/new/logo.gif' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [ + dict(name='h1', attrs={'class':'title'}) + ,dict(name='div', attrs={'id':'articleContent'}) + ] + + feeds = [ (u'\u0218tiri', u'http://www.hotnews.ro/rss/actualitate') + ,(u'English', u'http://www.hotnews.ro/rss/english') + ] + + def preprocess_html(self, soup): + return self.adeify_images(soup) + + + diff --git a/resources/recipes/jurnalulnational.recipe b/resources/recipes/jurnalulnational.recipe new file mode 100644 index 0000000000..ea3ba9c734 --- /dev/null +++ b/resources/recipes/jurnalulnational.recipe @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = u'2011, Silviu Cotoar\u0103' +''' +jurnalul.ro +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class JurnalulNational(BasicNewsRecipe): + title = u'Jurnalul Na\u0163ional' + __author__ = u'Silviu Cotoar\u0103' + description = u'\u0218tiri din Rom\u00e2nia' + publisher = 'Jurnalul National' + oldest_article = 5 + language = 'ro' + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + category = 'Ziare,Stiri,Romania' + encoding = 'utf-8' + cover_url = 'http://www.jurnalul.ro/images/sigla.png' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [ + dict(name='h1', attrs={'class':'h3 art_title'}) + ,dict(name='div', attrs={'class':'only_text'}) + ] + + feeds = [ + (u'\u0218tiri', u'http://www.jurnalul.ro/rss/stiri-3028.html') + ,(u'Special', u'http://www.jurnalul.ro/rss/special-3001.html') + ,(u'Sport', u'http://www.jurnalul.ro/rss/sport-3035.html') + ,(u'Bani Afaceri', u'http://www.jurnalul.ro/rss/bani-afaceri-3006.html') + ,(u'Viata Sanatoasa', u'http://www.jurnalul.ro/rss/viata-sanatoasa-3010.html') + ,(u'Stiinta Tehnica', u'http://www.jurnalul.ro/rss/stiinta-tehnica-3019.html') + ,(u'Timp Liber', u'http://www.jurnalul.ro/rss/timp-liber-3022.html') + ,(u'Fun', u'http://www.jurnalul.ro/rss/fun-3038.html') + ,(u'Acum 20 de ani', u'http://www.jurnalul.ro/rss/acum-20-de-ani-3073.html') + ] + + def preprocess_html(self, soup): + return self.adeify_images(soup) + + + diff --git a/resources/recipes/mediafax.recipe b/resources/recipes/mediafax.recipe new file mode 100644 index 0000000000..3d8a5b34a3 --- /dev/null +++ b/resources/recipes/mediafax.recipe @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = u'2011, Silviu Cotoar\u0103' +''' +mediafax.ro +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class Mediafax(BasicNewsRecipe): + title = 'Mediafax' + __author__ = u'Silviu Cotoar\u0103' + description = u'\u0218tiri din Rom\u00e2nia' + publisher = 'Mediafax' + oldest_article = 5 + language = 'ro' + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + category = 'Ziare,Stiri,Romania' + encoding = 'utf-8' + cover_url = 'http://storage0.dms.mpinteractiv.ro/media/1/1/1706/4134575/2/logo-mediafax-mass-media-news.jpg?width=400' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + + } + + keep_only_tags = [ + dict(name='div', attrs={'class':'news tabs-container'}) + ] + + remove_tags = [ + dict(name='ul', attrs={'class':['CategoryNews']}) + ,dict(name='div', attrs={'class':['read']}) + ] + + remove_tags_after = [ dict(name='div', attrs={'class':'cmsItemViews'}) ] + + + feeds = [ + (u'Actualitate', u'http://www.mediafax.ro/rss/') + ] + + + def preprocess_html(self, soup): + return self.adeify_images(soup) diff --git a/resources/recipes/moneyro.recipe b/resources/recipes/moneyro.recipe new file mode 100644 index 0000000000..4a280207ed --- /dev/null +++ b/resources/recipes/moneyro.recipe @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = u'2011, Silviu Cotoar\u0103' +''' +money.ro +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class MoneyRo(BasicNewsRecipe): + title = 'Money Ro' + __author__ = u'Silviu Cotoar\u0103' + description = u'\u0218tiri din Rom\u00e2nia' + publisher = 'MoneyRo' + oldest_article = 5 + language = 'ro' + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + category = 'Ziare,Stiri,Romania' + encoding = 'utf-8' + remove_javascript = True + cover_url = 'http://assets.moneyweb.ro/images/logo_money.jpg' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [ dict(name='div', attrs={'id':'titluArticol'}) + , dict(name='img', attrs={'id':'objImage'}) + , dict(name='div', attrs={'class':'leftColumnArticle'}) + ] + + remove_tags_after = [ dict(name='div', attrs={'id':'articleTags'}) ] + + remove_tags = [ dict(name='div', attrs={'id':'ads'}) + , dict(name='div', attrs={'id':'aus'}) + , dict(name='div', attrs={'id':'bb-comment-create-form'}) + , dict(name='div', attrs={'id':'articleTags'}) + , dict(name='div', attrs={'class':'breadcrumb'}) + ] + + feeds = [(u'\u0218tiri', u'http://moneyro.feedsportal.com/c/32533/fe.ed/rss.money.ro/stiri.xml') ] + + def preprocess_html(self, soup): + return self.adeify_images(soup) + + + diff --git a/resources/recipes/nrc.nl.recipe b/resources/recipes/nrc.nl.recipe index 60522ff90e..7ba56e8fc9 100644 --- a/resources/recipes/nrc.nl.recipe +++ b/resources/recipes/nrc.nl.recipe @@ -21,8 +21,8 @@ class Pagina12(BasicNewsRecipe): country = 'NL' remove_empty_feeds = True masthead_url = 'http://www.nrc.nl/nrc.nl/images/logo_nrc.png' - extra_css = """ - body{font-family: Georgia,serif } + extra_css = """ + body{font-family: Georgia,serif } img{margin-bottom: 0.4em; display: block} .bijschrift,.sectie{font-size: x-small} .sectie{color: gray} @@ -38,10 +38,10 @@ class Pagina12(BasicNewsRecipe): keep_only_tags = [dict(attrs={'class':'uitstekendekeus'})] remove_tags = [ dict(name=['meta','base','link','object','embed']) - ,dict(attrs={'class':['reclamespace','tags-and-sharing']}) + ,dict(attrs={'class':['reclamespace','tags-and-sharing','sharing-is-caring']}) ] remove_attributes=['lang'] - + feeds = [ (u'Voor nieuws', u'http://www.nrc.nl/nieuws/categorie/nieuws/rss.php' ) ,(u'Binnenland' , u'http://www.nrc.nl/nieuws/categorie/binnenland/rss.php' ) @@ -69,8 +69,8 @@ class Pagina12(BasicNewsRecipe): del item[atit] else: str = self.tag_to_string(item) - item.replaceWith(str) + item.replaceWith(str) for item in soup.findAll('img'): if not item.has_key('alt'): - item['alt'] = 'image' + item['alt'] = 'image' return soup diff --git a/resources/recipes/prosport.recipe b/resources/recipes/prosport.recipe new file mode 100644 index 0000000000..d1be8bd1f2 --- /dev/null +++ b/resources/recipes/prosport.recipe @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = u'2011, Silviu Cotoar\u0103' +''' +prosport.ro +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class Prosport(BasicNewsRecipe): + title = 'Prosport' + __author__ = u'Silviu Cotoar\u0103' + publisher = 'Prosport' + description = u'\u0218tiri Sportive din Rom\u00e2nia' + oldest_article = 5 + language = 'ro' + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + category = 'Ziare,Stiri,Romania,Sport' + encoding = 'utf-8' + cover_url = 'http://storage0.dms.mpinteractiv.ro/media/401/581/7946/3688311/1/logo-pro.jpg?width=610' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [ + dict(name='h1', attrs={'class':'a-title'}) + ,dict(name='div', attrs={'class':'a-entry'}) + ] + + remove_tags = [ dict(name='div', attrs={'class':'utils'}) + ,dict(name='div', attrs={'class':'g-slide'}) + ] + + + feeds = [ (u'\u0218tiri', u'http://www.prosport.ro/rss.xml')] + + def preprocess_html(self, soup): + return self.adeify_images(soup) + + + diff --git a/resources/recipes/realitatea.recipe b/resources/recipes/realitatea.recipe new file mode 100644 index 0000000000..ae5b7d8688 --- /dev/null +++ b/resources/recipes/realitatea.recipe @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = u'2011, Silviu Cotoar\u0103' +''' +realitatea.net +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class Realitatea(BasicNewsRecipe): + title = 'Realitatea' + __author__ = u'Silviu Cotoar\u0103' + publisher = 'Realitatea' + description = u'\u0218tiri din Rom\u00e2nia' + oldest_article = 5 + language = 'ro' + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + category = 'Ziare,Stiri,Romania' + encoding = 'utf-8' + cover_url = 'http://assets.realitatea.ro/images/logo.jpg' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [ + dict(name='div', attrs={'class':'articleTitle '}) + ,dict(name='div', attrs={'class':'articleBody'}) + ] + + remove_tags = [ dict(name='div', attrs={'id':'aus'}) ] + feeds = [ (u'\u0218tiri', u'http://realitatea.feedsportal.com/c/32533/fe.ed/rss.realitatea.net/stiri.xml') ] + + def preprocess_html(self, soup): + return self.adeify_images(soup) + + + diff --git a/resources/recipes/standardmoney.recipe b/resources/recipes/standardmoney.recipe new file mode 100644 index 0000000000..b02abde447 --- /dev/null +++ b/resources/recipes/standardmoney.recipe @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = u'2011, Silviu Cotoar\u0103' +''' +standard.money.ro +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class StandardMoneyRo(BasicNewsRecipe): + title = 'Standard Money Ro' + __author__ = u'Silviu Cotoar\u0103' + publisher = 'Standard Money' + description = 'Portal de Business' + oldest_article = 5 + language = 'ro' + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + category = 'Ziare,Stiri,Romania' + encoding = 'utf-8' + cover_url = 'http://assets.standard.ro/wp-content/themes/standard/images/standard-logo.gif' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [ + dict(name='h1', attrs={'class':'post-title'}) + , dict(name='div', attrs={'class':'content_post'}) + ] + + feeds = [ + (u'Actualitate', u'http://standard.money.ro/feed') + ] + + def preprocess_html(self, soup): + return self.adeify_images(soup) + + + diff --git a/resources/recipes/ziarulfinanciar.recipe b/resources/recipes/ziarulfinanciar.recipe new file mode 100644 index 0000000000..0b10d997b0 --- /dev/null +++ b/resources/recipes/ziarulfinanciar.recipe @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python + +__license__ = 'GPL v3' +__copyright__ = u'2011, Silviu Cotoar\u0103' +''' +zf.ro +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class ZiarulFinanciar(BasicNewsRecipe): + title = 'Ziarul Financiar' + __author__ = u'Silviu Cotoar\u0103' + description = u'\u0218tiri din Business' + publisher = 'Ziarul Financiar' + oldest_article = 5 + language = 'ro' + max_articles_per_feed = 100 + no_stylesheets = True + use_embedded_content = False + category = 'Ziare,Stiri,Romania' + encoding = 'utf-8' + cover_url = 'http://storage0.dms.mpinteractiv.ro/media/1/1/1706/7462721/1/ziarul-financiar-big.jpg?width=400' + + conversion_options = { + 'comments' : description + ,'tags' : category + ,'language' : language + ,'publisher' : publisher + } + + keep_only_tags = [ + dict(name='div', attrs={'class':'article'}) + ] + + feeds = [ + (u'\u0218tiri', u'http://www.zf.ro/rss/zf-24/') + ] + + def preprocess_html(self, soup): + return self.adeify_images(soup) + + + diff --git a/src/calibre/devices/apple/driver.py b/src/calibre/devices/apple/driver.py index cc4d39d3c5..5a0496e863 100644 --- a/src/calibre/devices/apple/driver.py +++ b/src/calibre/devices/apple/driver.py @@ -24,6 +24,7 @@ from calibre.utils.logging import Log from calibre.utils.zipfile import ZipFile from PIL import Image as PILImage +from lxml import etree if isosx: try: @@ -2515,23 +2516,23 @@ class ITUNES(DriverBase): fnames = zf_opf.namelist() opf = [x for x in fnames if '.opf' in x][0] if opf: - opf_raw = cStringIO.StringIO(zf_opf.read(opf)) - soup = BeautifulSoup(opf_raw.getvalue()) - opf_raw.close() - - # Touch existing calibre timestamp - md = soup.find('metadata') - if md: - ts = md.find('meta',attrs={'name':'calibre:timestamp'}) - if ts: - timestamp = ts['content'] - old_ts = parse_date(timestamp) - metadata.timestamp = datetime.datetime(old_ts.year, old_ts.month, old_ts.day, old_ts.hour, - old_ts.minute, old_ts.second, old_ts.microsecond+1, old_ts.tzinfo) - else: - metadata.timestamp = now() - if DEBUG: - self.log.info(" add timestamp: %s" % metadata.timestamp) + opf_tree = etree.fromstring(zf_opf.read(opf)) + ns_map = opf_tree.nsmap.keys() + for item in ns_map: + ns = opf_tree.nsmap[item] + md_el = opf_tree.find(".//{%s}metadata" % ns) + if md_el is not None: + ts = md_el.find('.//{%s}meta[@name="calibre:timestamp"]') + if ts: + timestamp = ts.get('content') + old_ts = parse_date(timestamp) + metadata.timestamp = datetime.datetime(old_ts.year, old_ts.month, old_ts.day, old_ts.hour, + old_ts.minute, old_ts.second, old_ts.microsecond+1, old_ts.tzinfo) + else: + metadata.timestamp = now() + if DEBUG: + self.log.info(" add timestamp: %s" % metadata.timestamp) + break else: metadata.timestamp = now() if DEBUG: @@ -2839,7 +2840,7 @@ class ITUNES(DriverBase): def _xform_metadata_via_plugboard(self, book, format): ''' Transform book metadata from plugboard templates ''' if DEBUG: - self.log.info(" ITUNES._update_metadata_from_plugboard()") + self.log.info(" ITUNES._xform_metadata_via_plugboard()") if self.plugboard_func: pb = self.plugboard_func(self.DEVICE_PLUGBOARD_NAME, format, self.plugboards) diff --git a/src/calibre/devices/kindle/apnx.py b/src/calibre/devices/kindle/apnx.py index c98fe7a7fa..178c1091f3 100644 --- a/src/calibre/devices/kindle/apnx.py +++ b/src/calibre/devices/kindle/apnx.py @@ -25,7 +25,7 @@ class APNXBuilder(object): with open(mobi_file_path, 'rb') as mf: ident = PdbHeaderReader(mf).identity() if ident != 'BOOKMOBI': - raise Exception(_('Not a valid MOBI file. Reports identity of %s' % ident)) + raise Exception(_('Not a valid MOBI file. Reports identity of %s') % ident) # Get the pages depending on the chosen parser pages = [] diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index e839ed4b9c..909afd01df 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -825,7 +825,7 @@ class BooksModel(QAbstractTableModel): # {{{ return False val = int(value.toInt()[0]) if column == 'rating' else \ value.toDate() if column in ('timestamp', 'pubdate') else \ - unicode(value.toString()) + unicode(value.toString()).strip() id = self.db.id(row) books_to_refresh = set([id]) if column == 'rating': diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 61161cd5e6..c62936a46f 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -551,8 +551,10 @@ class BooksView(QTableView): # {{{ return mods & Qt.ControlModifier or mods & Qt.ShiftModifier def mousePressEvent(self, event): - if event.button() == Qt.LeftButton and not self.event_has_mods(): - self.drag_start_pos = event.pos() + ep = event.pos() + if self.indexAt(ep) in self.selectionModel().selectedIndexes() and \ + event.button() == Qt.LeftButton and not self.event_has_mods(): + self.drag_start_pos = ep return QTableView.mousePressEvent(self, event) def mouseMoveEvent(self, event): diff --git a/src/calibre/gui2/preferences/search.py b/src/calibre/gui2/preferences/search.py index 749a7c8de0..db93cbd525 100644 --- a/src/calibre/gui2/preferences/search.py +++ b/src/calibre/gui2/preferences/search.py @@ -10,13 +10,15 @@ from PyQt4.Qt import QApplication from calibre.gui2.preferences import ConfigWidgetBase, test_widget, \ CommaSeparatedList from calibre.gui2.preferences.search_ui import Ui_Form -from calibre.gui2 import config +from calibre.gui2 import config, error_dialog from calibre.utils.config import prefs class ConfigWidget(ConfigWidgetBase, Ui_Form): def genesis(self, gui): self.gui = gui + db = gui.library_view.model().db + self.db = db r = self.register @@ -24,11 +26,153 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): r('highlight_search_matches', config) r('limit_search_columns', prefs) r('limit_search_columns_to', prefs, setting=CommaSeparatedList) - fl = gui.library_view.model().db.field_metadata.get_search_terms() + fl = db.field_metadata.get_search_terms() self.opt_limit_search_columns_to.update_items_cache(fl) self.clear_history_button.clicked.connect(self.clear_histories) + self.gst_explanation.setText('
' + _(
+ "Grouped search terms are search names that permit a query to automatically "
+ "search across more than one column. For example, if you create a grouped "
+ "search term allseries
with the value "
+ "series, #myseries, #myseries2
, then "
+ "the query allseries:adhoc
will find 'adhoc' in any of the "
+ "columns series
, #myseries
, and "
+ "#myseries2
.
Enter the name of the " + "grouped search term in the drop-down box, enter the list of columns " + "to search in the value box, then push the Save button. " + "
Note: Search terms are forced to lower case; MySearch
"
+ "and mysearch
are the same term."
+ "
You can have your grouped search term show up as user categories in " + " the Tag Browser. Just add the grouped search term names to the Make user " + "categories from box. You can add multiple terms separated by commas. " + "The new user category will be automatically " + "populated with all the items in the categories included in the grouped " + "search term.
Automatic user categories permit you to see easily "
+ "all the category items that "
+ "are in the columns contained in the grouped search term. Using the above "
+ " Cannot upload books to device there is no more free space available "
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget.py:118
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget.py:124
+msgid "Unknown formats"
+msgstr ""
+
+#:
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget.py:125
+msgid "You have enabled the {0} formats for your {1}. The {1} may not support them. If you send these formats to your {1} they may not work. Are you sure?"
+msgstr ""
+
+#:
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget.py:137
#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:403
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugboard.py:255
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:61
@@ -6419,7 +6444,7 @@ msgid "Invalid template"
msgstr ""
#:
-#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget.py:119
+#: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget.py:138
#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:404
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugboard.py:256
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:62
@@ -6595,53 +6620,53 @@ msgid ""
" "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:218
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:220
msgid "&Run the check again"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:221
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:223
msgid "Copy &to clipboard"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:228
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:230
msgid "Delete marked files (checked subitems)"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:234
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:236
msgid "Fix marked sections (checked fixable items)"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:244
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:246
msgid "Names to ignore:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:249
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:251
msgid "Enter comma-separated standard file name wildcards, such as synctoy*.dat"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:252
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:254
msgid "Extensions to ignore"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:257
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:259
msgid "Enter comma-separated extensions without a leading dot. Used only in book folders"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:306
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:308
msgid "(fixable)"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:329
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:331
msgid "Path from library"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:329
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:331
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/bookmarkmanager.py:89
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:253
msgid "Name"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:354
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:360
msgid "The marked files and folders will be permanently deleted. Are you sure?"
msgstr ""
@@ -6654,7 +6679,7 @@ msgstr ""
#:
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/choose_format_device_ui.py:49
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:76
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1175
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1174
msgid "Format"
msgstr ""
@@ -6831,7 +6856,7 @@ msgstr ""
#:
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:76
#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:69
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:985
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:984
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:33
#: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:295
#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:589
@@ -6859,13 +6884,13 @@ msgstr ""
#:
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:117
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:893
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:912
msgid "Invalid author name"
msgstr ""
#:
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:118
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:894
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:913
msgid "Author names cannot contain & characters."
msgstr ""
@@ -7128,108 +7153,108 @@ msgid ""
"Phase {0} {1}%%."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:920
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:560
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:921
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:561
msgid "Delete saved search/replace"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:921
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:922
msgid "The selected saved search/replace will be deleted. Are you sure?"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:938
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:946
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:939
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:947
msgid "Save search/replace"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:939
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:940
msgid "Search/replace name:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:947
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:948
msgid "That saved search/replace already exists and will be overwritten. Are you sure?"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:497
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:498
msgid "Edit Meta information"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:499
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:500
msgid "A&utomatically set author sort"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:500
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:501
msgid "&Swap title and author"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:501
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:502
msgid "Author s&ort: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:502
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:503
msgid "Specify how the author(s) of this book should be sorted. For example Charles Dickens should be sorted as Dickens, Charles."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:503
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:504
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:424
#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:786
msgid "&Rating:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:504
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:505
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:506
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:425
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:426
#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:787
msgid "Rating of this book. 0-5 stars"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:506
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:507
msgid "No change"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:507
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:508
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:427
msgid " stars"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:509
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:510
msgid "Add ta&gs: "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:511
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:512
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:513
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:431
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:432
#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:140
msgid "Open Tag Editor"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:513
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:514
msgid "&Remove tags:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:514
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:515
msgid "Comma separated list of tags to remove from the books. "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:515
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:516
msgid "Check this box to remove all tags from the books."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:516
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:517
msgid "Remove &all"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:520
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:521
msgid "If checked, the series will be cleared"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:521
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:522
msgid "&Clear series"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:522
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:523
msgid ""
"If not checked, the series number for the books will be set to 1.\n"
"If checked, selected books will be automatically numbered, in the order\n"
@@ -7237,244 +7262,244 @@ msgid ""
"Book A will have series number 1 and Book B series number 2."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:526
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:527
msgid "&Automatically number books in this series"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:527
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:528
msgid ""
"Series will normally be renumbered from the highest number in the database\n"
"for that series. Checking this box will tell calibre to start numbering\n"
"from the value in the box"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:530
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:531
msgid "&Force numbers to start with:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:531
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:532
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:440
#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:978
msgid "&Date:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:532
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:533
msgid "d MMM yyyy"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:534
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:539
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:535
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:540
msgid "&Apply date"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:535
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:536
msgid "&Published:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:537
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:538
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:444
msgid "Clear published date"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:540
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:541
msgid "Remove &format:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:541
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:542
msgid ""
"Force the title to be in title case. If both this and swap authors are checked,\n"
"title and author are swapped before the title case is set"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:543
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:544
msgid "Change title to title &case"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:544
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:545
msgid "Update title sort based on the current title. This will be applied only after other changes to title."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:545
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:546
msgid "Update &title sort"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:546
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:547
msgid ""
"Remove stored conversion settings for the selected books.\n"
"\n"
"Future conversion of these books will use the default settings."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:549
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:550
msgid "Remove &stored conversion settings for the selected books"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:550
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:551
msgid "Change &cover"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:551
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:552
msgid "&Generate default cover"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:552
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:553
msgid "&Remove cover"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:553
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:554
msgid "Set from &ebook file(s)"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:554
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:555
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:465
#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:392
#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:521
msgid "&Basic metadata"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:555
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:556
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:466
#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:399
msgid "&Custom metadata"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:556
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:557
msgid "Load searc&h/replace:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:557
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:558
msgid "Select saved search/replace to load."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:558
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:559
msgid "Save current search/replace"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:559
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:560
msgid "Sa&ve"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:561
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:562
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/bookmarkmanager_ui.py:64
msgid "Delete"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:562
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:563
msgid "Search &field:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:563
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:564
msgid "The name of the field that you want to search"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:564
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:565
msgid "Search &mode:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:565
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:566
msgid "Choose whether to use basic text matching or advanced regular expression matching"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:566
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:567
msgid "Te&mplate:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:567
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:568
msgid "Enter a template to be used as the source for the search/replace"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:568
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:569
msgid "&Search for:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:569
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:570
msgid "Enter the what you are looking for, either plain text or a regular expression, depending on the mode"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:570
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:571
msgid "Check this box if the search string must match exactly upper and lower case. Uncheck it if case is to be ignored"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:571
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:572
msgid "Cas&e sensitive"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:572
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:573
msgid "&Replace with:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:573
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:574
msgid "The replacement text. The matched search text will be replaced with this string"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:574
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:575
msgid "&Apply function after replace:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:575
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:576
msgid ""
"Specify how the text is to be processed after matching and replacement. In character mode, the entire\n"
"field is processed. In regular expression mode, only the matched text is processed"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:577
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:578
msgid "&Destination field:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:578
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:579
msgid ""
"The field that the text will be put into after all replacements.\n"
"If blank, the source field is used if the field is modifiable"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:580
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:581
msgid "M&ode:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:581
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:582
msgid "Specify how the text should be copied into the destination."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:582
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:583
msgid ""
"Specifies whether result items should be split into multiple values or\n"
"left as single values. This option has the most effect when the source field is\n"
"not multiple and the destination field is multiple"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:585
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:586
msgid "Split &result"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:586
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:587
msgid "For multiple-valued fields, sho&w"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:587
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:588
msgid "values starting a&t"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:588
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:589
msgid "with values separated b&y"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:589
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:590
msgid "Used when displaying test results to separate values in multiple-valued fields"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:590
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:591
msgid "Test text"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:591
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:592
msgid "Test result"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:592
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:593
msgid "Your test:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:593
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:594
msgid "&Search and replace"
msgstr ""
@@ -8323,12 +8348,12 @@ msgid "%s (was %s)"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:83
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:883
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:902
msgid "Item is blank"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:84
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:884
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:903
msgid "An item cannot be set to nothing. Delete it instead."
msgstr ""
@@ -8844,7 +8869,7 @@ msgid "Show books in the main memory of the device"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:67
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:906
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:913
msgid "Card A"
msgstr ""
@@ -8853,7 +8878,7 @@ msgid "Show books in storage card A"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/layout.py:69
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:908
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:915
msgid "Card B"
msgstr ""
@@ -8927,38 +8952,38 @@ msgstr ""
msgid "Size (MB)"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:387
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:386
msgid "Book %s of %s."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:736
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1295
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:589
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:735
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1294
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:599
msgid "The lookup/search name is \"{0}\""
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:742
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1297
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:741
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1296
msgid "This book's UUID is \"{0}\""
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:982
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:981
msgid "In Library"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:986
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:985
msgid "Size"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1195
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1194
msgid "Book %s of %s."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1275
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1274
msgid "Marked for deletion"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1278
+#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1277
msgid "Double click to edit me Enter the name of the grouped search term in the drop-down box, enter the list of columns to search in the value box, then push the Save button. Note: Search terms are forced to lower case; You can have your grouped search term show up as user categories in the Tag Browser. Just add the grouped search term names to the Make user categories from box. You can add multiple terms separated by commas. The new user category will be automatically populated with all the items in the categories included in the grouped search term. Automatic user categories permit you to see easily all the category items that are in the columns contained in the grouped search term. Using the above Click Find again to go to first match"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1378
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1397
msgid "Sort by name"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1378
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1397
msgid "Sort by popularity"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1379
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1398
msgid "Sort by average rating"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1382
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1401
msgid "Set the sort order for entries in the Tag Browser"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1388
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1407
msgid "Match all"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1388
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1407
msgid "Match any"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1393
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1412
msgid "When selecting multiple entries in the Tag Browser match any or all of them"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1397
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1416
msgid "Manage &user categories"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1400
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1419
msgid "Add your own categories to the Tag Browser"
msgstr ""
@@ -11144,7 +11252,7 @@ msgid "Options to customize the ebook viewer"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/documentview.py:47
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:729
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:767
msgid "Remember last used window size"
msgstr ""
@@ -11302,87 +11410,87 @@ msgstr ""
msgid "Book format"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:190
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:196
msgid "Position in book"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:197
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:203
msgid "Go to a reference. To get reference numbers, use the reference mode."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:205
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:211
msgid "Search for text in book"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:278
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:284
msgid "Print Preview"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:315
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:339
msgid "Connecting to dict.org to lookup: %s…"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:421
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:445
msgid "Choose ebook"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:422
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:446
msgid "Ebooks"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:455
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:482
msgid "No matches found for: %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:498
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:525
msgid "Loading flow..."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:536
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:563
msgid "Laying out %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:567
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:594
msgid "Bookmark #%d"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:571
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:598
msgid "Add bookmark"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:572
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:599
msgid "Enter title for bookmark:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:582
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:609
msgid "Manage Bookmarks"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:622
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:649
msgid "Loading ebook..."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:634
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:661
msgid "Could not open ebook"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:716
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:754
msgid "Options to control the ebook viewer"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:723
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:761
msgid "If specified, viewer window will try to come to the front when started."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:726
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:764
msgid "If specified, viewer window will try to open full screen when started."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:731
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:769
msgid "Print javascript alert and console messages to the console"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:737
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:775
msgid ""
"%prog [options] file\n"
"\n"
@@ -11765,33 +11873,33 @@ msgstr ""
msgid "daysago"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/library/caches.py:548
-#: /home/kovid/work/calibre/src/calibre/library/caches.py:558
+#: /home/kovid/work/calibre/src/calibre/library/caches.py:559
+#: /home/kovid/work/calibre/src/calibre/library/caches.py:569
msgid "unchecked"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/library/caches.py:548
-#: /home/kovid/work/calibre/src/calibre/library/caches.py:558
+#: /home/kovid/work/calibre/src/calibre/library/caches.py:559
+#: /home/kovid/work/calibre/src/calibre/library/caches.py:569
#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:192
msgid "no"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/library/caches.py:551
-#: /home/kovid/work/calibre/src/calibre/library/caches.py:561
+#: /home/kovid/work/calibre/src/calibre/library/caches.py:562
+#: /home/kovid/work/calibre/src/calibre/library/caches.py:572
msgid "checked"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/library/caches.py:551
-#: /home/kovid/work/calibre/src/calibre/library/caches.py:561
+#: /home/kovid/work/calibre/src/calibre/library/caches.py:562
+#: /home/kovid/work/calibre/src/calibre/library/caches.py:572
#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:192
msgid "yes"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/library/caches.py:555
+#: /home/kovid/work/calibre/src/calibre/library/caches.py:566
msgid "blank"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/library/caches.py:555
+#: /home/kovid/work/calibre/src/calibre/library/caches.py:566
msgid "empty"
msgstr ""
@@ -12011,28 +12119,34 @@ msgstr ""
msgid "No books available to catalog"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/library/catalog.py:1486
+#: /home/kovid/work/calibre/src/calibre/library/catalog.py:1487
msgid ""
+"Inconsistent Author Sort values for\n"
+"Author '{0}':\n"
+"'{1}' <> '{2}'\n"
+"Unable to build MOBI catalog.\n"
"\n"
-"Inconsistent Author Sort values for Author '{0}':\n"
-"'{1}' <> '{2}',\n"
-"unable to build catalog.\n"
-"\n"
-"Select all books by '{0}', apply correct Author Sort value in Edit Metadata dialog,\n"
-"then rebuild the catalog.\n"
+"Select all books by '{0}', apply correct Author Sort value in Edit Metadata dialog, then rebuild the catalog.\n"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/library/catalog.py:1687
+#: /home/kovid/work/calibre/src/calibre/library/catalog.py:1504
+msgid ""
+"Warning: inconsistent Author Sort values for\n"
+"Author '{0}':\n"
+"'{1}' <> '{2}'\n"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/library/catalog.py:1700
msgid ""
"No books found to catalog.\n"
"Check 'Excluded books' criteria in E-book options.\n"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/library/catalog.py:1689
+#: /home/kovid/work/calibre/src/calibre/library/catalog.py:1702
msgid "No books available to include in catalog"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/library/catalog.py:5017
+#: /home/kovid/work/calibre/src/calibre/library/catalog.py:5030
msgid ""
"\n"
"*** Adding 'By Authors' Section required for MOBI output ***"
@@ -12543,19 +12657,19 @@ msgstr ""
msgid "%sAverage rating is %3.1f"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:904
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:911
msgid "Main"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:2704
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:2722
msgid " Migrating old database to ebook library in %sallseries
example, the automatically-generated user category "
+ "will contain all the series mentioned in series
, "
+ "#myseries
, and #myseries2
. This "
+ "can be useful to check for duplicates, to find which column contains "
+ "a particular item, or to have hierarchical categories (categories "
+ "that contain categories)."))
+ self.gst = db.prefs.get('grouped_search_terms', {})
+ self.orig_gst_keys = self.gst.keys()
+
+ fl = []
+ for f in db.all_field_keys():
+ fm = db.metadata_for_field(f)
+ if not fm['search_terms']:
+ continue
+ if not fm['is_category']:
+ continue
+ fl.append(f)
+ self.gst_value.update_items_cache(fl)
+ self.fill_gst_box(select=None)
+
+ self.gst_delete_button.setEnabled(False)
+ self.gst_save_button.setEnabled(False)
+ self.gst_names.currentIndexChanged[int].connect(self.gst_index_changed)
+ self.gst_names.editTextChanged.connect(self.gst_text_changed)
+ self.gst_value.textChanged.connect(self.gst_text_changed)
+ self.gst_save_button.clicked.connect(self.gst_save_clicked)
+ self.gst_delete_button.clicked.connect(self.gst_delete_clicked)
+ self.gst_changed = False
+
+ if db.prefs.get('grouped_search_make_user_categories', None) is None:
+ db.prefs.set('grouped_search_make_user_categories', [])
+ r('grouped_search_make_user_categories', db.prefs, setting=CommaSeparatedList)
+ self.muc_changed = False
+ self.opt_grouped_search_make_user_categories.editingFinished.connect(
+ self.muc_box_changed)
+
+ def muc_box_changed(self):
+ self.muc_changed = True
+
+ def gst_save_clicked(self):
+ idx = self.gst_names.currentIndex()
+ name = icu_lower(unicode(self.gst_names.currentText()))
+ if not name:
+ return error_dialog(self.gui, _('Grouped Search Terms'),
+ _('The search term cannot be blank'),
+ show=True)
+ if idx != 0:
+ orig_name = unicode(self.gst_names.itemData(idx).toString())
+ else:
+ orig_name = ''
+ if name != orig_name:
+ if name in self.db.field_metadata.get_search_terms() and \
+ name not in self.orig_gst_keys:
+ return error_dialog(self.gui, _('Grouped Search Terms'),
+ _('That name is already used for a column or grouped search term'),
+ show=True)
+ if name in [icu_lower(p) for p in self.db.prefs.get('user_categories', {})]:
+ return error_dialog(self.gui, _('Grouped Search Terms'),
+ _('That name is already used for user category'),
+ show=True)
+
+ val = [v.strip() for v in unicode(self.gst_value.text()).split(',') if v.strip()]
+ if not val:
+ return error_dialog(self.gui, _('Grouped Search Terms'),
+ _('The value box cannot be empty'), show=True)
+
+ if orig_name and name != orig_name:
+ del self.gst[orig_name]
+ self.gst_changed = True
+ self.gst[name] = val
+ self.fill_gst_box(select=name)
+ self.changed_signal.emit()
+
+ def gst_delete_clicked(self):
+ if self.gst_names.currentIndex() == 0:
+ return error_dialog(self.gui, _('Grouped Search Terms'),
+ _('The empty grouped search term cannot be deleted'), show=True)
+ name = unicode(self.gst_names.currentText())
+ if name in self.gst:
+ del self.gst[name]
+ self.fill_gst_box(select='')
+ self.changed_signal.emit()
+ self.gst_changed = True
+
+ def fill_gst_box(self, select=None):
+ terms = sorted(self.gst.keys())
+ self.opt_grouped_search_make_user_categories.update_items_cache(terms)
+ self.gst_names.blockSignals(True)
+ self.gst_names.clear()
+ self.gst_names.addItem('', '')
+ for t in terms:
+ self.gst_names.addItem(t, t)
+ self.gst_names.blockSignals(False)
+ if select is not None:
+ if select == '':
+ self.gst_index_changed(0)
+ elif select in terms:
+ self.gst_names.setCurrentIndex(self.gst_names.findText(select))
+
+ def gst_text_changed(self):
+ self.gst_delete_button.setEnabled(False)
+ self.gst_save_button.setEnabled(True)
+
+ def gst_index_changed(self, idx):
+ self.gst_delete_button.setEnabled(idx != 0)
+ self.gst_save_button.setEnabled(False)
+ self.gst_value.blockSignals(True)
+ if idx == 0:
+ self.gst_value.setText('')
+ else:
+ name = unicode(self.gst_names.itemData(idx).toString())
+ self.gst_value.setText(','.join(self.gst[name]))
+ self.gst_value.blockSignals(False)
+
+ def commit(self):
+ if self.gst_changed:
+ self.db.prefs.set('grouped_search_terms', self.gst)
+ self.db.field_metadata.add_grouped_search_terms(self.gst)
+ return ConfigWidgetBase.commit(self)
+
def refresh_gui(self, gui):
+ if self.muc_changed:
+ gui.tags_view.set_new_model()
gui.search.search_as_you_type(config['search_as_you_type'])
gui.library_view.model().set_highlight_only(config['highlight_search_matches'])
gui.search.do_search()
diff --git a/src/calibre/gui2/preferences/search.ui b/src/calibre/gui2/preferences/search.ui
index 7d40f723ea..3f5b43bbb6 100644
--- a/src/calibre/gui2/preferences/search.ui
+++ b/src/calibre/gui2/preferences/search.ui
@@ -7,7 +7,7 @@
They can be any words or phrases, separated by commas."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:172
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:517
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:518
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:433
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/search_ui.py:214
#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:293
@@ -5571,8 +5586,8 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:173
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:174
-#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:518
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:519
+#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:520
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:434
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:435
#: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:292
@@ -6154,10 +6169,10 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:150
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:184
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:294
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:554
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:584
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:607
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:658
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:558
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:599
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:622
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:673
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:306
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:311
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:503
@@ -6172,22 +6187,22 @@ msgid "Undefined"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:127
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:615
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:630
msgid "star(s)"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:128
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:616
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:631
msgid "Unrated"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:171
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:645
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:660
msgid "Set '%s' to today"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:173
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:647
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:662
msgid "Clear '%s'"
msgstr ""
@@ -6203,31 +6218,31 @@ msgstr ""
msgid "Apply changes"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:691
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:706
msgid "Remove series"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:694
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:709
msgid "Automatically number books"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:697
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:712
msgid "Force numbers to start with "
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:768
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:783
msgid "The enumeration \"{0}\" contains invalid values that will not appear in the list"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:811
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:826
msgid "Remove all tags"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:831
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:846
msgid "tags to add"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:837
+#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:852
msgid "tags to remove"
msgstr ""
@@ -6411,7 +6426,17 @@ msgid "
"
msgstr ""
@@ -9002,7 +9027,7 @@ msgstr ""
msgid "Restore default layout"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:781
+#: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:783
msgid "Dropping onto a device is not supported. First add the book to the calibre library."
msgstr ""
@@ -9031,7 +9056,7 @@ msgid "No matches for the search phrase %s were found."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main.py:160
-#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:454
+#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:481
msgid "No matches found"
msgstr ""
@@ -10224,34 +10249,113 @@ msgstr ""
msgid "Save metadata in &OPF file"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:60
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:33
+msgid "Grouped search terms are search names that permit a query to automatically search across more than one column. For example, if you create a grouped search term allseries
with the value series, #myseries, #myseries2
, then the query allseries:adhoc
will find 'adhoc' in any of the columns series
, #myseries
, and #myseries2
.MySearch
and mysearch
are the same term.allseries
example, the automatically-generated user category will contain all the series mentioned in series
, #myseries
, and #myseries2
. This can be useful to check for duplicates, to find which column contains a particular item, or to have hierarchical categories (categories that contain categories)."
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:96
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:106
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:110
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:116
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:128
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:119
+msgid "Grouped Search Terms"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:97
+msgid "The search term cannot be blank"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:107
+msgid "That name is already used for a column or grouped search term"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:111
+msgid "That name is already used for user category"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:117
+msgid "The value box cannot be empty"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search.py:129
+msgid "The empty grouped search term cannot be deleted"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:110
msgid "Search as you &type"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:61
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:111
msgid "&Highlight search results instead of restricting the book list to the results"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:62
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:112
msgid "What to search by default"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:63
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:113
msgid "When you enter a search term without a prefix, by default calibre will search all metadata for matches. For example, entering, \"asimov\" will search not just authors but title/tags/series/comments/etc. Use these options if you would like to change this behavior."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:64
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:114
msgid "&Limit the searched metadata"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:65
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:115
msgid "&Columns that non-prefixed searches are limited to:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:66
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:116
msgid "Note that this option affects all searches, including saved searches and restrictions. Therefore, if you use this option, it is best to ensure that you always use prefixes in your saved searches. For example, use \"series:Foundation\" rather than just \"Foundation\" in a saved search"
msgstr ""
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:117
+msgid "Clear search histories from all over calibre. Including the book list, e-book viewer, fetch news dialog, etc."
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:118
+msgid "Clear search &histories"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:120
+msgid "&Names:"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:121
+msgid ""
+"Contains the names of the currently-defined group search terms.\n"
+"Create a new name by entering it into the empty box, then\n"
+"pressing Save. Rename a search term by selecting it then\n"
+"changing the name and pressing Save. Change the value of\n"
+"a search term by changing the value box then pressing Save."
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:126
+msgid "Delete the current search term"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:128
+msgid ""
+"Save the current search term. You can rename a search term by\n"
+"changing the name then pressing Save. You can change the value\n"
+"of a search term by changing the value box then pressing Save."
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:131
+msgid "&Save"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:132
+msgid "Make &user categories from:"
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/preferences/search_ui.py:133
+msgid ""
+"Enter the names of any grouped search terms you wish\n"
+"to be shown as user categories"
+msgstr ""
+
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/sending.py:28
#: /home/kovid/work/calibre/src/calibre/gui2/preferences/sending_ui.py:70
msgid "Manual management"
@@ -10621,25 +10725,25 @@ msgid "Apply any changes you made to this tweak"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:93
-#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:270
+#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:273
#: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:616
#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:277
msgid "Search"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:314
+#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:317
msgid "The selected search will be permanently deleted. Are you sure?"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:357
+#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:360
msgid "Search (For Advanced Search click the button to the left)"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:424
+#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:427
msgid "Saved Searches"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:426
+#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:429
msgid "Choose saved search or enter name for new saved search"
msgstr ""
@@ -10715,86 +10819,90 @@ msgstr ""
msgid "&Alternate shortcut:"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:273
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:280
msgid "Rename %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:277
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:284
msgid "Edit sort for %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:282
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:289
msgid "Search for %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:287
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:294
msgid "Search for everything but %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:293
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:300
msgid "Hide category %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:296
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:303
msgid "Show category"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:304
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:311
msgid "Search for books in category %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:308
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:315
msgid "Search for books not in category %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:315
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:319
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:322
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:326
msgid "Manage %s"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:322
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:329
msgid "Manage Saved Searches"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:329
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:333
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:336
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:340
msgid "Manage User Categories"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:340
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:347
msgid "Show all categories"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:343
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:350
msgid "Change sub-categorization scheme"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:677
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:595
+msgid "The grouped search term name is \"{0}\""
+msgstr ""
+
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:687
msgid "Changing the authors for several books can take a while. Are you sure?"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:682
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:692
msgid "Changing the metadata for that many books can take a while. Are you sure?"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:743
-#: /home/kovid/work/calibre/src/calibre/library/database2.py:350
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:768
+#: /home/kovid/work/calibre/src/calibre/library/database2.py:361
msgid "Searches"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:898
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:917
msgid "Duplicate search name"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:899
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:918
msgid "The saved search name %s is already used."
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1320
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1339
msgid "Find item in tag browser"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1323
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1342
msgid ""
"Search for items. This is a \"contains\" search; items containing the\n"
"text anywhere in the name will be found. You can limit the search\n"
@@ -10804,59 +10912,59 @@ msgid ""
"containing the text \"foo\""
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1332
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1351
msgid "ALT+f"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1336
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1355
msgid "F&ind"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1337
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1356
msgid "Find the first/next matching item"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1344
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1363
msgid "Collapse all categories"
msgstr ""
-#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1365
+#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:1384
msgid "No More Matches.