diff --git a/resources/recipes/le_monde.recipe b/resources/recipes/le_monde.recipe index 38360ce48e..18be6ca711 100644 --- a/resources/recipes/le_monde.recipe +++ b/resources/recipes/le_monde.recipe @@ -1,106 +1,89 @@ -#!/usr/bin/env python - -__license__ = 'GPL v3' -__copyright__ = '2008, Mathieu Godlewski ' -''' -lemonde.fr -''' - import re -from calibre.web.feeds.news import BasicNewsRecipe - +from calibre.web.feeds.recipes import BasicNewsRecipe class LeMonde(BasicNewsRecipe): - title = 'LeMonde.fr' - __author__ = 'Mathieu Godlewski and Sujata Raman' - description = 'Global news in french' - oldest_article = 3 - language = 'fr' + title = 'Le Monde' + __author__ = 'veezh' + description = 'Actualités' + oldest_article = 1 + max_articles_per_feed = 100 + no_stylesheets = True + #delay = 1 + use_embedded_content = False + encoding = 'cp1252' + publisher = 'lemonde.fr' + language = 'fr' + conversion_options = { + 'comments' : description + ,'language' : language + ,'publisher' : publisher + ,'linearize_tables': True + } - max_articles_per_feed = 30 - no_stylesheets = True - remove_javascript = True + remove_empty_feeds = True + filterDuplicates = True - # cover_url='http://abonnes.lemonde.fr/titresdumonde/'+date.today().strftime("%y%m%d")+'/1.jpg' + def preprocess_html(self, soup): + for alink in soup.findAll('a'): + if alink.string is not None: + tstr = alink.string + alink.replaceWith(tstr) + return soup - - extra_css = ''' - .dateline{color:#666666;font-family:verdana,sans-serif;font-size:x-small;} - .author{font-family:verdana,sans-serif;font-size:x-small;color:#222222;} - .articleImage{color:#666666;font-family:verdana,sans-serif;font-size:x-small;} - .mainText{font-family:Georgia,serif;color:#222222;} - .LM_articleText{font-family:Arial,Helvetica,sans-serif;} - .LM_titleZone{font-family:Arial,Helvetica,sans-serif;} - .mainContent{font-family:Georgia,serif;} - .LM_content{font-family:Georgia,serif;} - .LM_caption{font-family:Georgia,serif;font-size:-small;} - .LM_imageSource{font-family:Arial,Helvetica,sans-serif;font-size:x-small;color:#666666;} - h1{font-family:Arial,Helvetica,sans-serif;font-size:medium;color:#000000;} - .post{font-family:Arial,Helvetica,sans-serif;} - .mainTitle{font-family:Georgia,serif;} - .content{font-family:Georgia,serif;} - .entry{font-family:Georgia,serif;} - h2{font-family:Arial,Helvetica,sans-serif;font-size:large;} - small{font-family:Arial,Helvetica,sans-serif; color:#ED1B23;} - ''' - - feeds = [ - ('A la Une', 'http://www.lemonde.fr/rss/une.xml'), - ('International', 'http://www.lemonde.fr/rss/sequence/0,2-3210,1-0,0.xml'), - ('Europe', 'http://www.lemonde.fr/rss/sequence/0,2-3214,1-0,0.xml'), - ('Societe', 'http://www.lemonde.fr/rss/sequence/0,2-3224,1-0,0.xml'), - ('Economie', 'http://www.lemonde.fr/rss/sequence/0,2-3234,1-0,0.xml'), - ('Medias', 'http://www.lemonde.fr/rss/sequence/0,2-3236,1-0,0.xml'), - ('Rendez-vous', 'http://www.lemonde.fr/rss/sequence/0,2-3238,1-0,0.xml'), - ('Sports', 'http://www.lemonde.fr/rss/sequence/0,2-3242,1-0,0.xml'), - ('Planete', 'http://www.lemonde.fr/rss/sequence/0,2-3244,1-0,0.xml'), - ('Culture', 'http://www.lemonde.fr/rss/sequence/0,2-3246,1-0,0.xml'), - ('Technologies', 'http://www.lemonde.fr/rss/sequence/0,2-651865,1-0,0.xml'), - ('Cinema', 'http://www.lemonde.fr/rss/sequence/0,2-3476,1-0,0.xml'), - ('Voyages', 'http://www.lemonde.fr/rss/sequence/0,2-3546,1-0,0.xml'), - ('Livres', 'http://www.lemonde.fr/rss/sequence/0,2-3260,1-0,0.xml'), - ('Examens', 'http://www.lemonde.fr/rss/sequence/0,2-3404,1-0,0.xml'), - ('Opinions', 'http://www.lemonde.fr/rss/sequence/0,2-3232,1-0,0.xml') - ] - keep_only_tags = [dict(name='div', attrs={'id':["mainTitle","mainContent","LM_content","content"]}), - dict(name='div', attrs={'class':["post"]}) - ] - - remove_tags = [dict(name='img', attrs={'src':'http://medias.lemonde.fr/mmpub/img/lgo/lemondefr_pet.gif'}), - dict(name='div', attrs={'id':'xiti-logo-noscript'}), - dict(name='br', attrs={}), - dict(name='iframe', attrs={}), - dict(name='table', attrs={'id':["toolBox"]}), - dict(name='table', attrs={'class':["bottomToolBox"]}), - dict(name='div', attrs={'class':["pageNavigation","LM_pagination","fenetreBoxesContainer","breakingNews","LM_toolsBottom","LM_comments","LM_tools","pave_meme_sujet_hidden","boxMemeSujet"]}), - dict(name='div', attrs={'id':["miniUne","LM_sideBar"]}), - ] - - preprocess_regexps = [ (re.compile(i[0], re.IGNORECASE|re.DOTALL), i[1]) for i in - [ - (r'.*?.*?
.*?
).*You can start editing here.*', lambda match : ''+match.group(1)+''), - (r'

 

', lambda match : ''), - (r']*>
', lambda match : '
'+match.group(1).upper()), - (r']*>
', lambda match : '
"'+match.group(1).upper()), - (r'(
.*
).*', lambda match : match.group(1)), + preprocess_regexps = [ + (re.compile(r' \''), lambda match: ' ‘'), + (re.compile(r'\''), lambda match: '’'), + (re.compile(r'"<'), lambda match: ' »<'), + (re.compile(r'>"'), lambda match: '>« '), + (re.compile(r'’"'), lambda match: '’« '), + (re.compile(r' "'), lambda match: ' « '), + (re.compile(r'" '), lambda match: ' » '), + (re.compile(r'\("'), lambda match: '(« '), + (re.compile(r'"\)'), lambda match: ' »)'), + (re.compile(r'"\.'), lambda match: ' ».'), + (re.compile(r'",'), lambda match: ' »,'), + (re.compile(r'"\?'), lambda match: ' »?'), + (re.compile(r'":'), lambda match: ' »:'), + (re.compile(r'";'), lambda match: ' »;'), + (re.compile(r'"\!'), lambda match: ' »!'), + (re.compile(r' :'), lambda match: ' :'), + (re.compile(r' ;'), lambda match: ' ;'), + (re.compile(r' \?'), lambda match: ' ?'), + (re.compile(r' \!'), lambda match: ' !'), + (re.compile(r'\s»'), lambda match: ' »'), + (re.compile(r'«\s'), lambda match: '« '), + (re.compile(r' %'), lambda match: ' %'), + (re.compile(r'\.jpg » border='), lambda match: '.jpg'), + (re.compile(r'\.png » border='), lambda match: '.png'), ] - ] - article_match_regexps = [ (re.compile(i)) for i in - [ - (r'http://www\.lemonde\.fr/\S+/article/.*'), - (r'http://www\.lemonde\.fr/\S+/portfolio/.*'), - (r'http://www\.lemonde\.fr/\S+/article_interactif/.*'), - (r'http://\S+\.blog\.lemonde\.fr/.*'), - ] - ] + keep_only_tags = [ + dict(name='div', attrs={'class':['contenu']}) + ] - # def print_version(self, url): - # return re.sub('http://www\.lemonde\.fr/.*_([0-9]+)_[0-9]+\.html.*','http://www.lemonde.fr/web/imprimer_element/0,40-0,50-\\1,0.html' ,url) + remove_tags_after = [dict(id='appel_temoignage')] - # Used to filter duplicated articles - articles_list = [] + def get_article_url(self, article): + link = article.get('link') + if 'blog' not in link: + return link + + + + feeds = [ + ('A la une', 'http://www.lemonde.fr/rss/une.xml'), + ('International', 'http://www.lemonde.fr/rss/tag/international.xml'), + ('Europe', 'http://www.lemonde.fr/rss/tag/europe.xml'), + (u'Société', 'http://www.lemonde.fr/rss/tag/societe.xml'), + ('Economie', 'http://www.lemonde.fr/rss/tag/economie.xml'), + (u'Médias', 'http://www.lemonde.fr/rss/tag/actualite-medias.xml'), + (u'Planète', 'http://www.lemonde.fr/rss/tag/planete.xml'), + ('Culture', 'http://www.lemonde.fr/rss/tag/culture.xml'), + ('Technologies', 'http://www.lemonde.fr/rss/tag/technologies.xml'), + ('Livres', 'http://www.lemonde.fr/rss/tag/livres.xml'), + + ] def get_cover_url(self): cover_url = None @@ -111,42 +94,3 @@ class LeMonde(BasicNewsRecipe): cover_url = link_item.img['src'] return cover_url - - def get_article_url(self, article): - url=article.get('link', None) - url=url[0:url.find("#")] - if url in self.articles_list: - self.log_debug(_('Skipping duplicated article: %s')%url) - return False - if self.is_article_wanted(url): - self.articles_list.append(url) - if '/portfolio/' in url or '/video/' in url: - url = None - return url - self.log_debug(_('Skipping filtered article: %s')%url) - url = article.get('guid', None) - - - return False - - - def is_article_wanted(self, url): - if self.article_match_regexps: - for m in self.article_match_regexps: - if m.search(url): - return True - return False - return False - - def preprocess_html(self, soup): - - for item in soup.findAll(style=True): - del item['style'] - - for item in soup.findAll(face=True): - del item['face'] - for tag in soup.findAll(name=['ul','li']): - tag.name = 'div' - - return soup - diff --git a/resources/recipes/mainichi_it_news.recipe b/resources/recipes/mainichi_it_news.recipe index 4c285a2c01..eddab149cd 100644 --- a/resources/recipes/mainichi_it_news.recipe +++ b/resources/recipes/mainichi_it_news.recipe @@ -1,4 +1,5 @@ from calibre.web.feeds.news import BasicNewsRecipe +import re class MainichiDailyITNews(BasicNewsRecipe): title = u'\u6bce\u65e5\u65b0\u805e(IT&\u5bb6\u96fb)' @@ -14,6 +15,7 @@ class MainichiDailyITNews(BasicNewsRecipe): remove_tags_before = {'class':"NewsTitle"} remove_tags = [{'class':"RelatedArticle"}] + remove_tags_after = {'class':"Credit"} def parse_feeds(self): @@ -29,4 +31,4 @@ class MainichiDailyITNews(BasicNewsRecipe): index = curfeed.articles.index(d) curfeed.articles[index:index+1] = [] - return feeds remove_tags_after = {'class':"Credit"} + return feeds diff --git a/resources/recipes/ming_pao.recipe b/resources/recipes/ming_pao.recipe index 385dbdbdb7..726181f57b 100644 --- a/resources/recipes/ming_pao.recipe +++ b/resources/recipes/ming_pao.recipe @@ -1,8 +1,9 @@ __license__ = 'GPL v3' __copyright__ = '2010, Eddie Lau' ''' -modified from Singtao Toronto calibre recipe by rty Change Log: +2010/12/07: add entertainment section, use newspaper front page as ebook cover, suppress date display in section list + (to avoid wrong date display in case the user generates the ebook in a time zone different from HKT) 2010/11/22: add English section, remove eco-news section which is not updated daily, correct ordering of articles 2010/11/12: add news image and eco-news section @@ -17,14 +18,15 @@ from calibre.web.feeds.recipes import BasicNewsRecipe from contextlib import nested -from calibre import __appname__, strftime +from calibre import __appname__ from calibre.ebooks.BeautifulSoup import BeautifulSoup from calibre.ebooks.metadata.opf2 import OPFCreator from calibre.ebooks.metadata.toc import TOC from calibre.ebooks.metadata import MetaInformation -from calibre.utils.date import now as nowf class MPHKRecipe(BasicNewsRecipe): + IsKindleUsed = True # to avoid generating periodical in which CJK characters can't be displayed in section/article view + title = 'Ming Pao - Hong Kong' oldest_article = 1 max_articles_per_feed = 100 @@ -39,13 +41,13 @@ class MPHKRecipe(BasicNewsRecipe): encoding = 'Big5-HKSCS' recursions = 0 conversion_options = {'linearize_tables':True} - extra_css = 'img {display: block; margin-left: auto; margin-right: auto; margin-top: 10px; margin-bottom: 10px;}' - #extra_css = 'img {float:right; margin:4px;}' + timefmt = '' + extra_css = 'img {display: block; margin-left: auto; margin-right: auto; margin-top: 10px; margin-bottom: 10px;} font>b {font-size:200%; font-weight:bold;}' masthead_url = 'http://news.mingpao.com/image/portals_top_logo_news.gif' keep_only_tags = [dict(name='h1'), - #dict(name='font', attrs={'style':['font-size:14pt; line-height:160%;']}), # for entertainment page + dict(name='font', attrs={'style':['font-size:14pt; line-height:160%;']}), # for entertainment page title dict(attrs={'class':['photo']}), - dict(attrs={'id':['newscontent']}), + dict(attrs={'id':['newscontent']}), # entertainment page content dict(attrs={'id':['newscontent01','newscontent02']})] remove_tags = [dict(name='style'), dict(attrs={'id':['newscontent135']})] # for the finance page @@ -55,51 +57,68 @@ class MPHKRecipe(BasicNewsRecipe): lambda match: '

'), (re.compile(r'

', re.DOTALL|re.IGNORECASE), lambda match: ''), + (re.compile(r'

', re.DOTALL|re.IGNORECASE), # for entertainment page + lambda match: '') ] def image_url_processor(cls, baseurl, url): # trick: break the url at the first occurance of digit, add an additional # '_' at the front # not working, may need to move this to preprocess_html() method - #minIdx = 10000 - #i0 = url.find('0') - #if i0 >= 0 and i0 < minIdx: - # minIdx = i0 - #i1 = url.find('1') - #if i1 >= 0 and i1 < minIdx: - # minIdx = i1 - #i2 = url.find('2') - #if i2 >= 0 and i2 < minIdx: - # minIdx = i2 - #i3 = url.find('3') - #if i3 >= 0 and i0 < minIdx: - # minIdx = i3 - #i4 = url.find('4') - #if i4 >= 0 and i4 < minIdx: - # minIdx = i4 - #i5 = url.find('5') - #if i5 >= 0 and i5 < minIdx: - # minIdx = i5 - #i6 = url.find('6') - #if i6 >= 0 and i6 < minIdx: - # minIdx = i6 - #i7 = url.find('7') - #if i7 >= 0 and i7 < minIdx: - # minIdx = i7 - #i8 = url.find('8') - #if i8 >= 0 and i8 < minIdx: - # minIdx = i8 - #i9 = url.find('9') - #if i9 >= 0 and i9 < minIdx: - # minIdx = i9 - #return url[0:minIdx] + '_' + url[minIdx+1:] +# minIdx = 10000 +# i0 = url.find('0') +# if i0 >= 0 and i0 < minIdx: +# minIdx = i0 +# i1 = url.find('1') +# if i1 >= 0 and i1 < minIdx: +# minIdx = i1 +# i2 = url.find('2') +# if i2 >= 0 and i2 < minIdx: +# minIdx = i2 +# i3 = url.find('3') +# if i3 >= 0 and i0 < minIdx: +# minIdx = i3 +# i4 = url.find('4') +# if i4 >= 0 and i4 < minIdx: +# minIdx = i4 +# i5 = url.find('5') +# if i5 >= 0 and i5 < minIdx: +# minIdx = i5 +# i6 = url.find('6') +# if i6 >= 0 and i6 < minIdx: +# minIdx = i6 +# i7 = url.find('7') +# if i7 >= 0 and i7 < minIdx: +# minIdx = i7 +# i8 = url.find('8') +# if i8 >= 0 and i8 < minIdx: +# minIdx = i8 +# i9 = url.find('9') +# if i9 >= 0 and i9 < minIdx: +# minIdx = i9 return url - def get_fetchdate(self): + def get_dtlocal(self): dt_utc = datetime.datetime.utcnow() # convert UTC to local hk time - at around HKT 6.00am, all news are available dt_local = dt_utc - datetime.timedelta(-2.0/24) - return dt_local.strftime("%Y%m%d") + return dt_local + + def get_fetchdate(self): + return self.get_dtlocal().strftime("%Y%m%d") + + def get_fetchday(self): + # convert UTC to local hk time - at around HKT 6.00am, all news are available + return self.get_dtlocal().strftime("%d") + + def get_cover_url(self): + cover = 'http://news.mingpao.com/' + self.get_fetchdate() + '/' + self.get_fetchdate() + '_' + self.get_fetchday() + 'gacov.jpg' + br = BasicNewsRecipe.get_browser() + try: + br.open(cover) + except: + cover = None + return cover def parse_index(self): feeds = [] @@ -127,9 +146,9 @@ class MPHKRecipe(BasicNewsRecipe): # if eco_articles: # feeds.append((u'\u74b0\u4fdd Eco News', eco_articles)) # special - entertainment - #ent_articles = self.parse_ent_section('http://ol.mingpao.com/cfm/star1.cfm') - #if ent_articles: - # feeds.append(('Entertainment', ent_articles)) + ent_articles = self.parse_ent_section('http://ol.mingpao.com/cfm/star1.cfm') + if ent_articles: + feeds.append((u'\u5f71\u8996 Entertainment', ent_articles)) return feeds def parse_section(self, url): @@ -164,6 +183,7 @@ class MPHKRecipe(BasicNewsRecipe): return current_articles def parse_eco_section(self, url): + dateStr = self.get_fetchdate() soup = self.index_to_soup(url) divs = soup.findAll(attrs={'class': ['bullet']}) current_articles = [] @@ -173,23 +193,25 @@ class MPHKRecipe(BasicNewsRecipe): title = self.tag_to_string(a) url = a.get('href', False) url = 'http://tssl.mingpao.com/htm/marketing/eco/cfm/' +url - if url not in included_urls and url.rfind('Redirect') == -1: + if url not in included_urls and url.rfind('Redirect') == -1 and not url.rfind('.txt') == -1 and not url.rfind(dateStr) == -1: current_articles.append({'title': title, 'url': url, 'description':''}) included_urls.append(url) return current_articles - #def parse_ent_section(self, url): - # dateStr = self.get_fetchdate() - # soup = self.index_to_soup(url) - # a = soup.findAll('a', href=True) - # current_articles = [] - # included_urls = [] - # for i in a: - # title = self.tag_to_string(i) - # url = 'http://ol.mingpao.com/cfm/' + i.get('href', False) - # if url not in included_urls and not url.rfind('.txt') == -1 and not url.rfind(dateStr) == -1 and not title == '': - # current_articles.append({'title': title, 'url': url, 'description': ''}) - # return current_articles + def parse_ent_section(self, url): + soup = self.index_to_soup(url) + a = soup.findAll('a', href=True) + a.reverse() + current_articles = [] + included_urls = [] + for i in a: + title = self.tag_to_string(i) + url = 'http://ol.mingpao.com/cfm/' + i.get('href', False) + if (url not in included_urls) and (not url.rfind('.txt') == -1) and (not url.rfind('star') == -1): + current_articles.append({'title': title, 'url': url, 'description': ''}) + included_urls.append(url) + current_articles.reverse() + return current_articles def preprocess_html(self, soup): for item in soup.findAll(style=True): @@ -201,21 +223,26 @@ class MPHKRecipe(BasicNewsRecipe): return soup def create_opf(self, feeds, dir=None): - #super(MPHKRecipe,self).create_opf(feeds, dir) + if self.IsKindleUsed == False: + super(MPHKRecipe,self).create_opf(feeds, dir) + return if dir is None: dir = self.output_dir title = self.short_title() - if self.output_profile.periodical_date_in_title: - title += strftime(self.timefmt) + title += ' ' + self.get_fetchdate() + #if self.output_profile.periodical_date_in_title: + # title += strftime(self.timefmt) mi = MetaInformation(title, [__appname__]) mi.publisher = __appname__ mi.author_sort = __appname__ mi.publication_type = self.publication_type+':'+self.short_title() - mi.timestamp = nowf() + #mi.timestamp = nowf() + mi.timestamp = self.get_dtlocal() mi.comments = self.description if not isinstance(mi.comments, unicode): mi.comments = mi.comments.decode('utf-8', 'replace') - mi.pubdate = nowf() + #mi.pubdate = nowf() + mi.pubdate = self.get_dtlocal() opf_path = os.path.join(dir, 'index.opf') ncx_path = os.path.join(dir, 'index.ncx') opf = OPFCreator(dir, mi) diff --git a/resources/recipes/the_h.recipe b/resources/recipes/the_h.recipe index dbfad7e32a..28a1571dc5 100644 --- a/resources/recipes/the_h.recipe +++ b/resources/recipes/the_h.recipe @@ -14,7 +14,7 @@ class TheHeiseOnline(BasicNewsRecipe): oldest_article = 3 description = 'In association with Heise Online' publisher = 'Heise Media UK Ltd.' - category = 'news, technology, security' + category = 'news, technology, security, OSS, internet' max_articles_per_feed = 100 language = 'en' encoding = 'utf-8' @@ -27,6 +27,12 @@ class TheHeiseOnline(BasicNewsRecipe): feeds = [ (u'The H News Feed', u'http://www.h-online.com/news/atom.xml') ] + cover_url = 'http://www.h-online.com/icons/logo_theH.gif' + + remove_tags = [ + dict(id="logo"), + dict(id="footer") + ] def print_version(self, url): return url + '?view=print' diff --git a/resources/recipes/toyokeizai.recipe b/resources/recipes/toyokeizai.recipe new file mode 100644 index 0000000000..395a8bb9b7 --- /dev/null +++ b/resources/recipes/toyokeizai.recipe @@ -0,0 +1,68 @@ +__license__ = 'GPL v3' +__copyright__ = '2010, Hiroshi Miura ' +''' +www.toyokeizai.net +''' + +from calibre.web.feeds.news import BasicNewsRecipe +import re + +class Toyokeizai(BasicNewsRecipe): + title = u'ToyoKeizai News' + __author__ = 'Hiroshi Miura' + oldest_article = 1 + max_articles_per_feed = 50 + description = 'Japanese traditional economy and business magazine, only for advanced subscribers supported' + publisher = 'Toyokeizai Shinbun Sha' + category = 'economy, magazine, japan' + language = 'ja' + encoding = 'euc-jp' + index = 'http://member.toyokeizai.net/news/' + remove_javascript = True + no_stylesheets = True + masthead_title = u'TOYOKEIZAI' + needs_subscription = True + timefmt = '[%y/%m/%d]' + recursions = 5 + match_regexps =[ r'page/\d+'] + + keep_only_tags = [ + dict(name='div', attrs={'class':['news']}), + dict(name='div', attrs={'class':["news_cont"]}), + dict(name='div', attrs={'class':["news_con"]}), +# dict(name='div', attrs={'class':["norightsMessage"]}) + ] + remove_tags = [{'class':"mt35 mgz"}, + {'class':"mt20 newzia"}, + {'class':"mt20 fontS"}, + {'class':"bk_btn_m"}, + dict(id='newzia_connect_member') + ] + + def parse_index(self): + feeds = [] + soup = self.index_to_soup(self.index) + topstories = soup.find('ul',attrs={'class':'list6'}) + if topstories: + newsarticles = [] + for itt in topstories.findAll('li'): + itema = itt.find('a',href=True) + itemd = itt.find('span') + newsarticles.append({ + 'title' :itema.string + ,'date' :re.compile(r"\- ").sub("",itemd.string) + ,'url' :'http://member.toyokeizai.net' + itema['href'] + ,'description':itema['title'] + }) + feeds.append(('news', newsarticles)) + return feeds + + def get_browser(self): + br = BasicNewsRecipe.get_browser() + if self.username is not None and self.password is not None: + br.open('http://member.toyokeizai.net/norights/form/') + br.select_form(nr=0) + br['kaiin_id'] = self.username + br['password'] = self.password + res = br.submit() + return br diff --git a/src/calibre/ebooks/epub/periodical.py b/src/calibre/ebooks/epub/periodical.py index b46bea3719..0c9b029c51 100644 --- a/src/calibre/ebooks/epub/periodical.py +++ b/src/calibre/ebooks/epub/periodical.py @@ -9,6 +9,7 @@ from uuid import uuid4 from calibre.constants import __appname__, __version__ from calibre import strftime, prepare_string_for_xml as xml +from calibre.utils.date import parse_date SONY_METADATA = u'''\ @@ -87,7 +88,8 @@ def sony_metadata(oeb): pass try: - date = unicode(m.date[0]).split('T')[0] + date = parse_date(unicode(m.date[0]), + as_utc=False).strftime('%Y-%m-%d') except: date = strftime('%Y-%m-%d') try: diff --git a/src/calibre/ebooks/oeb/reader.py b/src/calibre/ebooks/oeb/reader.py index 0f61969373..8e11ac6498 100644 --- a/src/calibre/ebooks/oeb/reader.py +++ b/src/calibre/ebooks/oeb/reader.py @@ -544,7 +544,7 @@ class OEBReader(object): data = render_html_svg_workaround(path, self.logger) if not data: data = '' - id, href = self.oeb.manifest.generate('cover', 'cover.jpeg') + id, href = self.oeb.manifest.generate('cover', 'cover.jpg') item = self.oeb.manifest.add(id, href, JPEG_MIME, data=data) return item diff --git a/src/calibre/gui2/actions/add.py b/src/calibre/gui2/actions/add.py index 9b348d8285..014fa573d2 100644 --- a/src/calibre/gui2/actions/add.py +++ b/src/calibre/gui2/actions/add.py @@ -61,6 +61,7 @@ class AddAction(InterfaceAction): self._adder = Adder(self.gui, self.gui.library_view.model().db, self.Dispatcher(self._files_added), spare_server=self.gui.spare_server) + self.gui.tags_view.disable_recounting = True self._adder.add_recursive(root, single) def add_recursive_single(self, *args): @@ -201,9 +202,11 @@ class AddAction(InterfaceAction): self._adder = Adder(self.gui, None if to_device else self.gui.library_view.model().db, self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server) + self.gui.tags_view.disable_recounting = True self._adder.add(paths) def _files_added(self, paths=[], names=[], infos=[], on_card=None): + self.gui.tags_view.disable_recounting = False if paths: self.gui.upload_books(paths, list(map(ascii_filename, names)), @@ -214,6 +217,7 @@ class AddAction(InterfaceAction): self.gui.library_view.model().books_added(self._adder.number_of_books_added) if hasattr(self.gui, 'db_images'): self.gui.db_images.reset() + self.gui.tags_view.recount() if getattr(self._adder, 'merged_books', False): books = u'\n'.join([x if isinstance(x, unicode) else x.decode(preferred_encoding, 'replace') for x in diff --git a/src/calibre/gui2/actions/delete.py b/src/calibre/gui2/actions/delete.py index a541590fd1..a0f49a7e9a 100644 --- a/src/calibre/gui2/actions/delete.py +++ b/src/calibre/gui2/actions/delete.py @@ -5,13 +5,67 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from PyQt4.Qt import QMenu +from functools import partial + +from PyQt4.Qt import QMenu, QObject, QTimer from calibre.gui2 import error_dialog from calibre.gui2.dialogs.delete_matching_from_device import DeleteMatchingFromDeviceDialog from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.actions import InterfaceAction +single_shot = partial(QTimer.singleShot, 10) + +class MultiDeleter(QObject): + + def __init__(self, gui, rows, callback): + from calibre.gui2.dialogs.progress import ProgressDialog + QObject.__init__(self, gui) + self.model = gui.library_view.model() + self.ids = list(map(self.model.id, rows)) + self.gui = gui + self.failures = [] + self.deleted_ids = [] + self.callback = callback + single_shot(self.delete_one) + self.pd = ProgressDialog(_('Deleting...'), parent=gui, + cancelable=False, min=0, max=len(self.ids)) + self.pd.setModal(True) + self.pd.show() + + def delete_one(self): + if not self.ids: + self.cleanup() + return + id_ = self.ids.pop() + title = 'id:%d'%id_ + try: + title_ = self.model.db.title(id_, index_is_id=True) + if title_: + title = title_ + self.model.db.delete_book(id_, notify=False, commit=False) + self.deleted_ids.append(id_) + except: + import traceback + self.failures.append((id_, title, traceback.format_exc())) + single_shot(self.delete_one) + self.pd.value += 1 + self.pd.set_msg(_('Deleted') + ' ' + title) + + def cleanup(self): + self.pd.hide() + self.pd = None + self.model.db.commit() + self.model.db.clean() + self.model.books_deleted() + self.gui.tags_view.recount() + self.callback(self.deleted_ids) + if self.failures: + msg = ['==> '+x[1]+'\n'+x[2] for x in self.failures] + error_dialog(self.gui, _('Failed to delete'), + _('Failed to delete some books, click the Show Details button' + ' for details.'), det_msg='\n\n'.join(msg), show=True) + class DeleteAction(InterfaceAction): name = 'Remove Books' @@ -179,8 +233,13 @@ class DeleteAction(InterfaceAction): row = None if ci.isValid(): row = ci.row() - ids_deleted = view.model().delete_books(rows) - self.library_ids_deleted(ids_deleted, row) + if len(rows) < 5: + ids_deleted = view.model().delete_books(rows) + self.library_ids_deleted(ids_deleted, row) + else: + self.__md = MultiDeleter(self.gui, rows, + partial(self.library_ids_deleted, current_row=row)) + else: if not confirm('

'+_('The selected books will be ' 'permanently deleted ' diff --git a/src/calibre/gui2/add.py b/src/calibre/gui2/add.py index 5f41f3a8e0..5f555ef138 100644 --- a/src/calibre/gui2/add.py +++ b/src/calibre/gui2/add.py @@ -3,41 +3,55 @@ UI for adding books to the database and saving books to disk ''' import os, shutil, time from Queue import Queue, Empty -from threading import Thread +from functools import partial -from PyQt4.Qt import QThread, SIGNAL, QObject, QTimer, Qt, \ - QProgressDialog +from PyQt4.Qt import QThread, QObject, Qt, QProgressDialog, pyqtSignal, QTimer from calibre.gui2.dialogs.progress import ProgressDialog from calibre.gui2 import question_dialog, error_dialog, info_dialog from calibre.ebooks.metadata.opf2 import OPF from calibre.ebooks.metadata import MetaInformation -from calibre.constants import preferred_encoding, filesystem_encoding +from calibre.constants import preferred_encoding, filesystem_encoding, DEBUG from calibre.utils.config import prefs +from calibre import prints + +single_shot = partial(QTimer.singleShot, 75) + +class DuplicatesAdder(QObject): # {{{ + + added = pyqtSignal(object) + adding_done = pyqtSignal() -class DuplicatesAdder(QThread): # {{{ - # Add duplicate books def __init__(self, parent, db, duplicates, db_adder): - QThread.__init__(self, parent) + QObject.__init__(self, parent) self.db, self.db_adder = db, db_adder - self.duplicates = duplicates + self.duplicates = list(duplicates) + self.count = 0 + single_shot(self.add_one) + + def add_one(self): + if not self.duplicates: + self.adding_done.emit() + return + + mi, cover, formats = self.duplicates.pop() + formats = [f for f in formats if not f.lower().endswith('.opf')] + id = self.db.create_book_entry(mi, cover=cover, + add_duplicates=True) + # here we add all the formats for dupe book record created above + self.db_adder.add_formats(id, formats) + self.db_adder.number_of_books_added += 1 + self.count += 1 + self.added.emit(self.count) + single_shot(self.add_one) - def run(self): - count = 1 - for mi, cover, formats in self.duplicates: - formats = [f for f in formats if not f.lower().endswith('.opf')] - id = self.db.create_book_entry(mi, cover=cover, - add_duplicates=True) - # here we add all the formats for dupe book record created above - self.db_adder.add_formats(id, formats) - self.db_adder.number_of_books_added += 1 - self.emit(SIGNAL('added(PyQt_PyObject)'), count) - count += 1 - self.emit(SIGNAL('adding_done()')) # }}} class RecursiveFind(QThread): # {{{ + update = pyqtSignal(object) + found = pyqtSignal(object) + def __init__(self, parent, db, root, single): QThread.__init__(self, parent) self.db = db @@ -50,8 +64,8 @@ class RecursiveFind(QThread): # {{{ for dirpath in os.walk(root): if self.canceled: return - self.emit(SIGNAL('update(PyQt_PyObject)'), - _('Searching in')+' '+dirpath[0]) + self.update.emit( + _('Searching in')+' '+dirpath[0]) self.books += list(self.db.find_books_in_directory(dirpath[0], self.single_book_per_directory)) @@ -71,46 +85,55 @@ class RecursiveFind(QThread): # {{{ msg = unicode(err) except: msg = repr(err) - self.emit(SIGNAL('found(PyQt_PyObject)'), msg) + self.found.emit(msg) return self.books = [formats for formats in self.books if formats] if not self.canceled: - self.emit(SIGNAL('found(PyQt_PyObject)'), self.books) + self.found.emit(self.books) # }}} -class DBAdder(Thread): # {{{ +class DBAdder(QObject): # {{{ + + def __init__(self, parent, db, ids, nmap): + QObject.__init__(self, parent) - def __init__(self, db, ids, nmap): self.db, self.ids, self.nmap = db, dict(**ids), dict(**nmap) - self.end = False self.critical = {} self.number_of_books_added = 0 self.duplicates = [] self.names, self.paths, self.infos = [], [], [] - Thread.__init__(self) - self.daemon = True self.input_queue = Queue() self.output_queue = Queue() self.merged_books = set([]) - def run(self): - while not self.end: - try: - id, opf, cover = self.input_queue.get(True, 0.2) - except Empty: - continue - name = self.nmap.pop(id) - title = None - try: - title = self.add(id, opf, cover, name) - except: - import traceback - self.critical[name] = traceback.format_exc() - title = name - self.output_queue.put(title) + def end(self): + self.input_queue.put((None, None, None)) + + def start(self): + try: + id, opf, cover = self.input_queue.get_nowait() + except Empty: + single_shot(self.start) + return + if id is None and opf is None and cover is None: + return + name = self.nmap.pop(id) + title = None + if DEBUG: + st = time.time() + try: + title = self.add(id, opf, cover, name) + except: + import traceback + self.critical[name] = traceback.format_exc() + title = name + self.output_queue.put(title) + if DEBUG: + prints('Added', title, 'to db in:', time.time() - st, 'seconds') + single_shot(self.start) def process_formats(self, opf, formats): imp = opf[:-4]+'.import' @@ -201,10 +224,10 @@ class Adder(QObject): # {{{ self.pd.setModal(True) self.pd.show() self._parent = parent - self.rfind = self.worker = self.timer = None + self.rfind = self.worker = None self.callback = callback self.callback_called = False - self.connect(self.pd, SIGNAL('canceled()'), self.canceled) + self.pd.canceled_signal.connect(self.canceled) def add_recursive(self, root, single=True): self.path = root @@ -213,10 +236,8 @@ class Adder(QObject): # {{{ self.pd.set_max(0) self.pd.value = 0 self.rfind = RecursiveFind(self, self.db, root, single) - self.connect(self.rfind, SIGNAL('update(PyQt_PyObject)'), - self.pd.set_msg, Qt.QueuedConnection) - self.connect(self.rfind, SIGNAL('found(PyQt_PyObject)'), - self.add, Qt.QueuedConnection) + self.rfind.update.connect(self.pd.set_msg, type=Qt.QueuedConnection) + self.rfind.found.connect(self.add, type=Qt.QueuedConnection) self.rfind.start() def add(self, books): @@ -246,12 +267,12 @@ class Adder(QObject): # {{{ self.pd.set_min(0) self.pd.set_max(len(self.ids)) self.pd.value = 0 - self.db_adder = DBAdder(self.db, self.ids, self.nmap) + self.db_adder = DBAdder(self, self.db, self.ids, self.nmap) self.db_adder.start() self.last_added_at = time.time() self.entry_count = len(self.ids) self.continue_updating = True - QTimer.singleShot(200, self.update) + single_shot(self.update) def canceled(self): self.continue_updating = False @@ -260,14 +281,14 @@ class Adder(QObject): # {{{ if self.worker is not None: self.worker.canceled = True if hasattr(self, 'db_adder'): - self.db_adder.end = True + self.db_adder.end() self.pd.hide() if not self.callback_called: self.callback(self.paths, self.names, self.infos) self.callback_called = True def duplicates_processed(self): - self.db_adder.end = True + self.db_adder.end() if not self.callback_called: self.callback(self.paths, self.names, self.infos) self.callback_called = True @@ -300,7 +321,7 @@ class Adder(QObject): # {{{ if (time.time() - self.last_added_at) > self.ADD_TIMEOUT: self.continue_updating = False self.pd.hide() - self.db_adder.end = True + self.db_adder.end() if not self.callback_called: self.callback([], [], []) self.callback_called = True @@ -311,7 +332,7 @@ class Adder(QObject): # {{{ 'find the problem book.'), show=True) if self.continue_updating: - QTimer.singleShot(200, self.update) + single_shot(self.update) def process_duplicates(self): @@ -332,11 +353,8 @@ class Adder(QObject): # {{{ self.__p_d = pd self.__d_a = DuplicatesAdder(self._parent, self.db, duplicates, self.db_adder) - self.connect(self.__d_a, SIGNAL('added(PyQt_PyObject)'), - pd.setValue) - self.connect(self.__d_a, SIGNAL('adding_done()'), - self.duplicates_processed) - self.__d_a.start() + self.__d_a.added.connect(pd.setValue) + self.__d_a.adding_done.connect(self.duplicates_processed) else: return self.duplicates_processed() @@ -407,14 +425,12 @@ class Saver(QObject): # {{{ self.worker = SaveWorker(self.rq, db, self.ids, path, self.opts, spare_server=self.spare_server) self.pd.canceled_signal.connect(self.canceled) - self.timer = QTimer(self) - self.connect(self.timer, SIGNAL('timeout()'), self.update) - self.timer.start(200) + self.continue_updating = True + single_shot(self.update) def canceled(self): - if self.timer is not None: - self.timer.stop() + self.continue_updating = False if self.worker is not None: self.worker.canceled = True self.pd.hide() @@ -424,27 +440,35 @@ class Saver(QObject): # {{{ def update(self): - if not self.ids or not self.worker.is_alive(): - self.timer.stop() - self.pd.hide() + if not self.continue_updating: + return + if not self.worker.is_alive(): + # Check that all ids were processed while self.ids: + # Get all queued results since worker is dead before = len(self.ids) self.get_result() if before == len(self.ids): + # No results available => worker died unexpectedly for i in list(self.ids): self.failures.add(('id:%d'%i, 'Unknown error')) self.ids.remove(i) - break + + if not self.ids: + self.continue_updating = False + self.pd.hide() if not self.callback_called: try: - self.worker.join(1.5) + # Give the worker time to clean up and set worker.error + self.worker.join(2) except: pass # The worker was not yet started - self.callback(self.worker.path, self.failures, self.worker.error) self.callback_called = True - return + self.callback(self.worker.path, self.failures, self.worker.error) - self.get_result() + if self.continue_updating: + self.get_result() + single_shot(self.update) def get_result(self): diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 2bf521283f..a2e7bdfa33 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -223,21 +223,22 @@ class BooksModel(QAbstractTableModel): # {{{ def by_author(self): return self.sorted_on[0] == 'authors' + def books_deleted(self): + self.count_changed() + self.clear_caches() + self.reset() + def delete_books(self, indices): ids = map(self.id, indices) for id in ids: self.db.delete_book(id, notify=False) - self.count_changed() - self.clear_caches() - self.reset() + self.books_deleted() return ids def delete_books_by_id(self, ids): for id in ids: self.db.delete_book(id) - self.count_changed() - self.clear_caches() - self.reset() + self.books_deleted() def books_added(self, num): if num > 0: diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index fdae1bdbc9..2ede698c85 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -73,6 +73,7 @@ class TagsView(QTreeView): # {{{ def __init__(self, parent=None): QTreeView.__init__(self, parent=None) self.tag_match = None + self.disable_recounting = False self.setUniformRowHeights(True) self.setCursor(Qt.PointingHandCursor) self.setIconSize(QSize(30, 30)) @@ -299,6 +300,8 @@ class TagsView(QTreeView): # {{{ return self.isExpanded(idx) def recount(self, *args): + if self.disable_recounting: + return self.refresh_signal_processed = True ci = self.currentIndex() if not ci.isValid(): diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py index 5b6b79e3df..a99c9df125 100644 --- a/src/calibre/library/caches.py +++ b/src/calibre/library/caches.py @@ -129,6 +129,7 @@ class CoverCache(Thread): # {{{ self.keep_running = True self.cache = {} self.lock = RLock() + self.allowed_ids = frozenset([]) self.null_image = QImage() def stop(self): @@ -175,6 +176,11 @@ class CoverCache(Thread): # {{{ break for id_ in ids: time.sleep(0.050) # Limit 20/second to not overwhelm the GUI + if not self.keep_running: + return + with self.lock: + if id_ not in self.allowed_ids: + continue try: img = self._image_for_id(id_) except: @@ -193,6 +199,7 @@ class CoverCache(Thread): # {{{ def set_cache(self, ids): with self.lock: + self.allowed_ids = frozenset(ids) already_loaded = set([]) for id in self.cache.keys(): if id in ids: @@ -213,8 +220,9 @@ class CoverCache(Thread): # {{{ def refresh(self, ids): with self.lock: for id_ in ids: - self.cache.pop(id_, None) - self.load_queue.put(id_) + cover = self.cache.pop(id_, None) + if cover is not None: + self.load_queue.put(id_) # }}} ### Global utility function for get_match here and in gui2/library.py diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 4efb5e6233..1229b60577 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -953,23 +953,24 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.notify('metadata', [id]) return True - def delete_book(self, id, notify=True): + def delete_book(self, id, notify=True, commit=True): ''' Removes book from the result cache and the underlying database. + If you set commit to False, you must call clean() manually afterwards ''' try: path = os.path.join(self.library_path, self.path(id, index_is_id=True)) except: path = None - self.data.remove(id) if path and os.path.exists(path): self.rmtree(path) parent = os.path.dirname(path) if len(os.listdir(parent)) == 0: self.rmtree(parent) self.conn.execute('DELETE FROM books WHERE id=?', (id,)) - self.conn.commit() - self.clean() + if commit: + self.conn.commit() + self.clean() self.data.books_deleted([id]) if notify: self.notify('delete', [id]) diff --git a/src/calibre/translations/calibre.pot b/src/calibre/translations/calibre.pot index 0eeae72c07..11eb9cad49 100644 --- a/src/calibre/translations/calibre.pot +++ b/src/calibre/translations/calibre.pot @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: calibre 0.7.32\n" -"POT-Creation-Date: 2010-12-03 10:53+MST\n" -"PO-Revision-Date: 2010-12-03 10:53+MST\n" +"POT-Creation-Date: 2010-12-09 08:47+MST\n" +"PO-Revision-Date: 2010-12-09 08:47+MST\n" "Last-Translator: Automatically generated\n" "Language-Team: LANGUAGE\n" "MIME-Version: 1.0\n" @@ -77,9 +77,9 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader.py:839 #: /home/kovid/work/calibre/src/calibre/ebooks/odt/input.py:49 #: /home/kovid/work/calibre/src/calibre/ebooks/odt/input.py:51 -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:913 -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:918 -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:984 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:914 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:919 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:985 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/reader.py:143 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/reader.py:150 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:64 @@ -109,44 +109,44 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/writer.py:98 #: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:305 #: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:307 -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:355 -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:362 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:302 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:305 -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:137 -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:144 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:357 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:364 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:308 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:311 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:160 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/convert/__init__.py:42 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:114 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:139 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:141 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:115 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:140 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:142 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:1039 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:1042 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/comicconf.py:47 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:120 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:155 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:671 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:128 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:163 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:675 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:193 #: /home/kovid/work/calibre/src/calibre/gui2/email.py:235 #: /home/kovid/work/calibre/src/calibre/gui2/email.py:244 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:376 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:395 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:922 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1116 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:379 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:398 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:925 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1118 #: /home/kovid/work/calibre/src/calibre/gui2/metadata.py:112 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:190 #: /home/kovid/work/calibre/src/calibre/library/cli.py:215 #: /home/kovid/work/calibre/src/calibre/library/database.py:914 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:373 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:385 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1260 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1361 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2158 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2160 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2291 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:375 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:387 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1264 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1365 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2162 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2164 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2295 #: /home/kovid/work/calibre/src/calibre/library/server/mobile.py:229 -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:139 -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:142 -#: /home/kovid/work/calibre/src/calibre/library/server/xml.py:78 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:140 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:143 +#: /home/kovid/work/calibre/src/calibre/library/server/xml.py:79 #: /home/kovid/work/calibre/src/calibre/utils/localization.py:118 #: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:46 #: /home/kovid/work/calibre/src/calibre/utils/podofo/__init__.py:64 @@ -682,9 +682,9 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:888 #: /home/kovid/work/calibre/src/calibre/devices/usbms/device.py:918 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:264 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:187 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:200 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2022 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:189 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:202 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2026 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:150 msgid "News" msgstr "" @@ -692,8 +692,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2554 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:21 #: /home/kovid/work/calibre/src/calibre/library/catalog.py:560 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:1985 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2003 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:1989 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2007 msgid "Catalog" msgstr "" @@ -896,7 +896,7 @@ msgid "Adding books to device metadata listing..." msgstr "" #: /home/kovid/work/calibre/src/calibre/devices/kobo/driver.py:445 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:268 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:272 msgid "Not Implemented" msgstr "" @@ -1573,46 +1573,24 @@ msgstr "" msgid "When using an SVG cover, this option will cause the cover to scale to cover the available screen area, but still preserve its aspect ratio (ratio of width to height). That means there may be white borders at the sides or top and bottom of the image, but the image will never be distorted. Without this option the image may be slightly distorted, but there will be no borders." msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:170 +#: /home/kovid/work/calibre/src/calibre/ebooks/epub/output.py:173 #: /home/kovid/work/calibre/src/calibre/ebooks/snb/output.py:203 msgid "Start" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/fb2ml.py:151 -#: /home/kovid/work/calibre/src/calibre/ebooks/rb/rbml.py:102 -#: /home/kovid/work/calibre/src/calibre/ebooks/txt/txtml.py:78 -msgid "Table of Contents:" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:32 msgid "Do not insert a Table of Contents at the beginning of the book." msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/fb2/output.py:21 -#: /home/kovid/work/calibre/src/calibre/ebooks/pdb/output.py:32 -#: /home/kovid/work/calibre/src/calibre/ebooks/pml/output.py:37 -#: /home/kovid/work/calibre/src/calibre/ebooks/rb/output.py:21 -#: /home/kovid/work/calibre/src/calibre/ebooks/txt/output.py:36 -msgid "Add Table of Contents to beginning of the book." -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/output.py:24 -msgid "Try to turn chapters into individual sections. WARNING: This option is experimental. It can cause conversion to fail. It can also produce unexpected output." -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/output.py:30 -msgid "Try to turn chapters into individual sections using the internal structure of the ebook. This works well for EPUB books that have been internally split by chapter." -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/output.py:35 msgid "Wrap all h1 tags with fb2 title elements." msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/output.py:38 +#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/output.py:24 msgid "Wrap all h2 tags with fb2 title elements." msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/output.py:41 +#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/output.py:27 msgid "Wrap all h3 tags with fb2 title elements." msgstr "" @@ -1895,6 +1873,38 @@ msgstr "" msgid "Comic" msgstr "" +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/amazonfr.py:26 +msgid "Downloads metadata from amazon.fr" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/amazonfr.py:43 +msgid "Downloads metadata from amazon.com in spanish" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/amazonfr.py:60 +msgid "Downloads metadata from amazon.com in english" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/amazonfr.py:77 +msgid "Downloads metadata from amazon.de" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/amazonfr.py:94 +msgid "Downloads metadata from amazon.com" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/amazonfr.py:474 +msgid "" +" %prog [options]\n" +"\n" +" Fetch book metadata from Amazon. You must specify one of title, author,\n" +" ISBN, publisher or keywords. Will fetch a maximum of 10 matches,\n" +" so you should make your query as specific as possible.\n" +" You can chose the language for metadata retrieval:\n" +" All & english & french & german & spanish\n" +" " +msgstr "" + #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/archive.py:41 msgid "Extract common e-book formats from archives (zip/rar) files. Also try to autodetect if they are actually cbz/cbr files." msgstr "" @@ -1904,13 +1914,13 @@ msgid "TEMPLATE ERROR" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:533 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:59 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:60 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:492 msgid "No" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:533 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:59 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:60 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:492 msgid "Yes" msgstr "" @@ -1920,26 +1930,26 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:106 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:107 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:75 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:58 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:65 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:373 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:927 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:59 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:66 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:376 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:930 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:304 #: /home/kovid/work/calibre/src/calibre/library/server/opds.py:570 msgid "Title" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:608 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:59 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:67 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:378 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:928 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:60 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:68 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:381 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:931 msgid "Author(s)" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:609 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:61 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:72 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:62 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:73 msgid "Publisher" msgstr "" @@ -1949,36 +1959,36 @@ msgid "Producer" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:611 -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:39 -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:210 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:40 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:211 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:189 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info_ui.py:79 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:325 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1135 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:328 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1137 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:188 msgid "Comments" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:613 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:166 -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:29 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:50 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:73 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:313 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1131 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:30 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:60 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:74 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:316 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1133 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:161 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:655 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:650 msgid "Tags" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:615 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:164 -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:28 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:50 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:74 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:330 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1140 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:29 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:60 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:75 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:333 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1142 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:109 msgid "Series" msgstr "" @@ -1988,14 +1998,14 @@ msgid "Language" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:618 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1123 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1125 msgid "Timestamp" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:620 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:163 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:63 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:70 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:64 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:71 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:259 msgid "Published" msgstr "" @@ -2087,7 +2097,7 @@ msgid "No cover found" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/covers.py:28 -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:44 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:45 msgid "Cover download" msgstr "" @@ -2175,6 +2185,81 @@ msgstr "" msgid "Downloads series/tags/rating information from librarything.com" msgstr "" +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:25 +msgid "Downloads metadata from Fictionwise" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:90 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:108 +msgid "Query: %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:100 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:285 +msgid "Fictionwise timed out. Try again later." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:101 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:286 +msgid "Fictionwise encountered an error." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:219 +msgid "" +"SUMMARY:\n" +" %s" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:316 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:333 +msgid "Failed to get all details for an entry" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:354 +msgid "" +" %prog [options]\n" +"\n" +" Fetch book metadata from Fictionwise. You must specify one of title, author,\n" +" or keywords. No ISBN specification possible. Will fetch a maximum of 20 matches,\n" +" so you should make your query as specific as possible.\n" +" " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:362 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:363 +msgid "Book title" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:363 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:364 +msgid "Book author(s)" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:364 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:365 +msgid "Book publisher" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:365 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:367 +msgid "Keywords" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:367 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:373 +msgid "Maximum number of results to fetch" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:369 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:375 +msgid "Be more verbose about errors" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/fictionwise.py:383 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:390 +msgid "No result found for this search!" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/isbndb.py:107 msgid "" "\n" @@ -2205,7 +2290,6 @@ msgid "The publisher of the book to search for." msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/library_thing.py:77 -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:336 msgid " not found." msgstr "" @@ -2217,24 +2301,70 @@ msgid "" "Fetch a cover image/social metadata for the book identified by ISBN from LibraryThing.com\n" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:25 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:26 msgid "Downloads metadata from french Nicebooks" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:41 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:42 msgid "Downloads covers from french Nicebooks" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:332 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:118 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:242 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:320 msgid "Nicebooks timed out. Try again later." msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:337 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:119 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:243 +msgid "Nicebooks encountered an error." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:323 +msgid "ISBN: %s not found." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:324 msgid "An errror occured with Nicebooks cover fetcher" msgstr "" +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:354 +msgid "" +" %prog [options]\n" +"\n" +" Fetch book metadata from Nicebooks. You must specify one of title, author,\n" +" ISBN, publisher or keywords. Will fetch a maximum of 20 matches,\n" +" so you should make your query as specific as possible.\n" +" It can also get covers if the option is activated.\n" +" " +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:366 +msgid "Book ISBN" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:369 +msgid "Covers: 1-Check/ 2-Download" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:371 +msgid "Covers files path" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:396 +msgid "No cover found!" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:398 +msgid "A cover was found for this book" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/nicebooks.py:407 +msgid "Cover saved to file " +msgstr "" + #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/opf2.py:1308 -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1401 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1404 msgid "Cover" msgstr "" @@ -2271,70 +2401,70 @@ msgstr "" msgid "This is an Amazon Topaz book. It cannot be processed." msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1402 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1405 msgid "Title Page" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1403 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1406 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/htmltoc.py:15 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:53 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:199 msgid "Table of Contents" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1404 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1407 msgid "Index" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1405 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1408 msgid "Glossary" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1406 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1409 msgid "Acknowledgements" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1407 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1410 msgid "Bibliography" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1408 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1411 msgid "Colophon" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1409 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1412 msgid "Copyright" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1410 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1413 msgid "Dedication" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1411 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1414 msgid "Epigraph" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1412 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1415 msgid "Foreword" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1413 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1416 msgid "List of Illustrations" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1414 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1417 msgid "List of Tables" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1415 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1418 msgid "Notes" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1416 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1419 msgid "Preface" msgstr "" -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1417 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1420 msgid "Main Text" msgstr "" @@ -2343,7 +2473,7 @@ msgid "%s format books are not supported" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/cover.py:98 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:214 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:218 msgid "Book %s of %s" msgstr "" @@ -2356,8 +2486,8 @@ msgid "Unknown publisher" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:165 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:71 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:653 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:72 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:648 msgid "Rating" msgstr "" @@ -2405,6 +2535,13 @@ msgstr "" msgid "Specify the character encoding of the output document. The default is cp1252. Note: This option is not honored by all formats." msgstr "" +#: /home/kovid/work/calibre/src/calibre/ebooks/pdb/output.py:32 +#: /home/kovid/work/calibre/src/calibre/ebooks/pml/output.py:37 +#: /home/kovid/work/calibre/src/calibre/ebooks/rb/output.py:21 +#: /home/kovid/work/calibre/src/calibre/ebooks/txt/output.py:36 +msgid "Add Table of Contents to beginning of the book." +msgstr "" + #: /home/kovid/work/calibre/src/calibre/ebooks/pdf/input.py:24 msgid "Do not extract images from the document" msgstr "" @@ -2621,6 +2758,11 @@ msgstr "" msgid "Do not reduce the size or bit depth of images. Images have their size and depth reduced by default to accommodate applications that can not convert images on their own such as Dropbook." msgstr "" +#: /home/kovid/work/calibre/src/calibre/ebooks/rb/rbml.py:102 +#: /home/kovid/work/calibre/src/calibre/ebooks/txt/txtml.py:78 +msgid "Table of Contents:" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/ebooks/rtf/input.py:256 msgid "" "This RTF file has a feature calibre does not support. Convert it to HTML first and then try it.\n" @@ -2792,39 +2934,44 @@ msgid "Overwrite author and title with new metadata" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:127 -msgid "Limit max simultaneous jobs to number of CPUs" +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:101 +msgid "Automatically download the cover, if available" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:129 -msgid "tag browser categories not to display" +msgid "Limit max simultaneous jobs to number of CPUs" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:131 -msgid "The layout of the user interface" +msgid "tag browser categories not to display" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:133 -msgid "Show the average rating per item indication in the tag browser" +msgid "The layout of the user interface" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:135 +msgid "Show the average rating per item indication in the tag browser" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:137 msgid "Disable UI animations" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:183 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:185 #: /home/kovid/work/calibre/src/calibre/gui2/wizard/__init__.py:509 msgid "Copied" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:217 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:219 msgid "Copy" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:217 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:219 msgid "Copy to Clipboard" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:466 +#: /home/kovid/work/calibre/src/calibre/gui2/__init__.py:468 msgid "Choose Files" msgstr "" @@ -2860,107 +3007,107 @@ msgstr "" msgid "Add from ISBN" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:85 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:86 msgid "How many empty books?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:86 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:87 msgid "How many empty books should be added?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:153 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:212 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:154 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:215 msgid "Uploading books to device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:170 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:299 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:171 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:303 msgid "Books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:171 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:172 msgid "EPUB Books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:172 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:173 msgid "LRF Books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:173 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:174 msgid "HTML Books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:174 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:175 msgid "LIT Books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:175 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:176 msgid "MOBI Books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:176 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:177 msgid "Topaz books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:177 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:178 msgid "Text books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:178 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:179 msgid "PDF Books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:179 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:180 msgid "SNB Books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:180 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:181 msgid "Comics" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:181 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:182 msgid "Archives" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:185 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:186 msgid "Supported books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:221 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:225 msgid "Merged some books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:222 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:226 msgid "Some duplicates were found and merged into the following existing books:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:231 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:235 msgid "Failed to read metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:232 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:236 msgid "Failed to read metadata from the following" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:251 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:256 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:275 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:255 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:260 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:279 msgid "Add to library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:256 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:56 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:260 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:110 #: /home/kovid/work/calibre/src/calibre/gui2/actions/tweak_epub.py:28 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:94 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:135 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:85 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:126 msgid "No book selected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:269 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:273 msgid "The following books are virtual and cannot be added to the calibre library:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:275 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/add.py:279 msgid "No book files found" msgstr "" @@ -2991,10 +3138,10 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/catalog.py:30 #: /home/kovid/work/calibre/src/calibre/gui2/actions/convert.py:87 #: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:124 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:75 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:122 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:175 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:212 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:76 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:123 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:181 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:218 #: /home/kovid/work/calibre/src/calibre/gui2/actions/save_to_disk.py:92 msgid "No books selected" msgstr "" @@ -3041,7 +3188,7 @@ msgid "Generating %s catalog..." msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/catalog.py:59 -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:230 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:251 msgid "No books found" msgstr "" @@ -3088,8 +3235,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:148 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/toolbar.py:51 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:162 -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:112 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:163 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:113 msgid "%d books" msgstr "" @@ -3154,7 +3301,7 @@ msgid "Note that the actual library folder will be renamed." msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/choose_library.py:278 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:190 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:191 msgid "Already exists" msgstr "" @@ -3285,7 +3432,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/copy_to_library.py:147 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:664 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:699 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:701 #: /home/kovid/work/calibre/src/calibre/gui2/metadata.py:190 msgid "Failed" msgstr "" @@ -3294,88 +3441,104 @@ msgstr "" msgid "Copied %d books to %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:18 -msgid "Del" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:18 -msgid "Remove books" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:24 -msgid "Remove selected books" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:26 -msgid "Remove files of a specific format from selected books.." -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:29 -msgid "Remove all formats from selected books, except..." -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:32 -msgid "Remove covers from selected books" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:35 -msgid "Remove matching books from device" +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:31 +msgid "Deleting..." msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:53 -msgid "Cannot delete" +msgid "Deleted" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:65 +msgid "Failed to delete" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:66 +msgid "Failed to delete some books, click the Show Details button for details." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:72 +msgid "Del" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:72 +msgid "Remove books" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:78 +msgid "Remove selected books" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:80 +msgid "Remove files of a specific format from selected books.." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:83 +msgid "Remove all formats from selected books, except..." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:86 +msgid "Remove covers from selected books" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:89 +msgid "Remove matching books from device" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:107 +msgid "Cannot delete" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:120 msgid "Choose formats to be deleted" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:84 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:138 msgid "Choose formats not to be deleted" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:104 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:158 msgid "Cannot delete books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:105 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:159 msgid "No device is connected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:115 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:169 msgid "Main memory" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:116 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:170 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:467 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:476 msgid "Storage Card A" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:117 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:171 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:469 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:478 msgid "Storage Card B" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:122 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:176 msgid "No books to delete" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:123 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:177 msgid "None of the selected books are on the device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:140 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:200 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:194 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:259 msgid "Deleting books from device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:173 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:227 msgid "The selected books will be permanently deleted and the files removed from your calibre library. Are you sure?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:185 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:244 msgid "The selected books will be permanently deleted from your device. Are you sure?" msgstr "" @@ -3430,98 +3593,98 @@ msgstr "" msgid "Manage the collections on this device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:23 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:24 msgid "E" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:23 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:24 msgid "Edit metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:27 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:28 msgid "Merge book records" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:28 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:29 msgid "M" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:30 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:31 msgid "Edit metadata individually" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:33 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:34 msgid "Edit metadata in bulk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:36 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:37 msgid "Download metadata and covers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:39 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:40 msgid "Download only metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:41 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:42 msgid "Download only covers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:44 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:45 msgid "Download only social metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:50 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:51 msgid "Merge into first selected book - delete others" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:53 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:54 msgid "Merge into first selected book - keep others" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:74 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:75 msgid "Cannot download metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:94 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:95 msgid "social metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:96 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:97 msgid "covers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:96 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:97 #: /home/kovid/work/calibre/src/calibre/gui2/metadata.py:224 msgid "metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:97 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:98 msgid "Downloading %s for %d book(s)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:121 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:174 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:122 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:180 msgid "Cannot edit metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:211 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:214 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:217 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:220 msgid "Cannot merge books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:215 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:221 msgid "At least two books must be selected for merging" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:220 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:226 msgid "Book formats and metadata from the selected books will be added to the first selected book (%s). ISBN will not be merged.

The second and subsequently selected books will not be deleted or changed.

Please confirm you want to proceed." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:232 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:238 msgid "Book formats and metadata from the selected books will be merged into the first selected book (%s). ISBN will not be merged.

After merger the second and subsequently selected books will be deleted.

All book formats of the first selected book will be kept and any duplicate formats in the second and subsequently selected books will be permanently deleted from your computer.

Are you sure you want to proceed?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:245 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:251 msgid "You are about to merge more than 5 books. Are you sure you want to proceed?" msgstr "" @@ -3649,7 +3812,7 @@ msgid "Click the show details button to see which ones." msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/show_book_details.py:16 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:660 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:655 msgid "Show book details" msgstr "" @@ -3728,102 +3891,102 @@ msgid "V" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:24 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:32 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:31 msgid "View" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:33 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:32 msgid "View specific format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:94 -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:174 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:85 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:165 msgid "Cannot view" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:105 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:96 #: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:77 msgid "Choose the format to view" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:116 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:107 msgid "Format unavailable" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:117 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:108 msgid "Not all the selected books were available in the %s format. You should convert them first." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:124 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:115 msgid "Multiple Books Selected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:125 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:116 msgid "You are attempting to open %d books. Opening too many books at once can be slow and have a negative effect on the responsiveness of your computer. Once started the process cannot be stopped until complete. Do you wish to continue?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:134 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:125 msgid "Cannot open folder" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:175 +#: /home/kovid/work/calibre/src/calibre/gui2/actions/view.py:166 msgid "%s has no available formats." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:54 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:68 msgid "Searching in" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:198 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:221 msgid "Adding..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:211 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:234 msgid "Searching in all sub-directories..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:224 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:245 msgid "Path error" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:225 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:246 msgid "The specified directory could not be processed." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:229 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:250 #: /home/kovid/work/calibre/src/calibre/gui2/device.py:813 msgid "No books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:294 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:315 msgid "Added" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:307 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:328 msgid "Adding failed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:308 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:329 msgid "The add books process seems to have hung. Try restarting calibre and adding the books in smaller increments, until you find the problem book." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:323 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:344 msgid "Duplicates found!" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:324 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:345 msgid "Books with the same title as the following already exist in the database. Add them anyway?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:327 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:348 msgid "Adding duplicates..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:390 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:408 msgid "Saving..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/add.py:443 +#: /home/kovid/work/calibre/src/calibre/gui2/add.py:483 msgid "Saved" msgstr "" @@ -3962,57 +4125,57 @@ msgstr "" msgid "&Multiple books per folder, assumes every ebook file is a different book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:25 -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:49 -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:58 -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:417 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:26 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:50 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:59 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:418 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:123 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:124 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:125 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:135 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:76 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:320 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1121 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:323 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1123 msgid "Path" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:26 -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:52 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:27 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:53 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:126 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:127 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:128 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/book_info.py:131 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:319 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:322 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/emailp.py:24 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:118 msgid "Formats" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:27 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:931 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1124 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:28 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:934 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1126 msgid "Collections" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:51 -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:60 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:52 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:61 msgid "Click to open" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:52 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:312 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:318 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:324 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1130 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1134 -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:47 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:53 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:315 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:321 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:327 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1132 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1136 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:48 #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:78 #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:83 #: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:293 msgid "None" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:416 +#: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:417 msgid "Double-click to open Book Details window" msgstr "" @@ -4065,7 +4228,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/debug_ui.py:54 #: /home/kovid/work/calibre/src/calibre/gui2/convert/epub_output_ui.py:53 #: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_input_ui.py:33 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:48 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:39 #: /home/kovid/work/calibre/src/calibre/gui2/convert/look_and_feel_ui.py:127 #: /home/kovid/work/calibre/src/calibre/gui2/convert/lrf_output_ui.py:120 #: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata_ui.py:171 @@ -4421,31 +4584,15 @@ msgstr "" msgid "FB2 Output" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:49 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdb_output_ui.py:42 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pmlz_output_ui.py:37 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/rb_output_ui.py:34 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output_ui.py:61 -msgid "&Inline TOC" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:50 -msgid "Sectionize Chapters (Use with care!)" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:51 -msgid "Sectionize Chapters using file structure" -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:52 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:40 msgid "Wrap h1 tags with elements" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:53 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:41 msgid "Wrap h2 tags with <title> elements" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:54 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/fb2_output_ui.py:42 msgid "Wrap h3 tags with <title> elements" msgstr "" @@ -4645,44 +4792,44 @@ msgstr "" msgid "&Monospaced font family:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:44 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:45 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:114 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:200 msgid "Metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:46 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:47 msgid "Set the metadata. The output file will contain as much of this metadata as possible." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:168 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:166 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:169 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:170 msgid "Choose cover for " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:175 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:173 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:176 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:177 msgid "Cannot read" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:176 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:174 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:177 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:178 msgid "You do not have permission to read the file: " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:184 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:191 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:182 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:185 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:192 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:186 msgid "Error reading file" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:185 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:183 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:186 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:187 msgid "<p>There was an error reading from file: <br /><b>" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:192 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:191 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:193 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:195 msgid " is not a valid picture" msgstr "" @@ -4864,6 +5011,13 @@ msgstr "" msgid "&Format:" msgstr "" +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdb_output_ui.py:42 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pmlz_output_ui.py:37 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/rb_output_ui.py:34 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/txt_output_ui.py:61 +msgid "&Inline TOC" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_input.py:12 msgid "PDF Input" msgstr "" @@ -5234,38 +5388,38 @@ msgstr "" msgid "Cover browser could not be loaded" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:59 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:84 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:108 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:145 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:164 -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:270 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:60 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:85 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:109 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:146 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:165 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:271 #: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:492 -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:111 -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:131 -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:206 -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:239 -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:243 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:112 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:132 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:208 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:241 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:245 msgid "Undefined" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:122 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:123 msgid "star(s)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:123 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:124 msgid "Unrated" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:156 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:157 msgid "Set '%s' to today" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:266 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:267 msgid " index:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:332 +#: /home/kovid/work/calibre/src/calibre/gui2/custom_column_widgets.py:333 msgid "The enumeration \"{0}\" contains an invalid value that will be set to the default" msgstr "" @@ -5467,14 +5621,14 @@ msgid "<p>Cannot upload books to device there is no more free space available " msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget.py:89 -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:356 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:359 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugboard.py:234 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:57 msgid "Invalid template" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/configwidget.py:90 -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:357 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:360 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugboard.py:235 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/save_template.py:58 msgid "The template %s is invalid:" @@ -5603,7 +5757,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/check_library.py:134 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/bookmarkmanager.py:89 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:248 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:249 msgid "Name" msgstr "" @@ -5729,8 +5883,8 @@ 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:929 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:70 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:932 #: /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:569 @@ -5739,7 +5893,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:1120 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1122 msgid "Format" msgstr "" @@ -5754,13 +5908,13 @@ msgstr "" #: #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:115 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:684 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:689 msgid "Invalid author name" msgstr "" #: #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:116 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:685 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:690 msgid "Author names cannot contain & characters." msgstr "" @@ -5789,72 +5943,80 @@ msgstr "" msgid "Recalculate all author sort values" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:60 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:61 msgid "Author Sort" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:62 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:63 msgid "ISBN" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:162 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:65 +msgid "Has Cover" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:66 +msgid "Has Summary" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:170 msgid "Finding metadata..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:176 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:184 msgid "Could not find metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:177 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:185 msgid "The metadata download seems to have stalled. Try again later." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:186 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:194 msgid "Warning" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:187 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:195 msgid "Could not fetch metadata from:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:191 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:199 msgid "No metadata found" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:192 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata.py:200 msgid "No metadata found, try adjusting the title and author and/or removing the ISBN." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:90 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:93 msgid "Fetch metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:91 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:94 msgid "<p>calibre can find metadata for your books from two locations: <b>Google Books</b> and <b>isbndb.com</b>. <p>To use isbndb.com you must sign up for a <a href=\"http://www.isbndb.com\">free account</a> and enter your access key below." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:92 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:95 msgid "&Access Key:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:93 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:96 msgid "Fetch" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:94 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:97 msgid "Matches" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:95 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:98 msgid "Select the book that most closely matches your copy from the list below" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:96 -msgid "Download &social metadata (tags/rating/etc.) for the selected book" +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:99 +msgid "Overwrite author and title with author and title of selected book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:97 -msgid "Overwrite author and title with author and title of selected book" +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/fetch_metadata_ui.py:100 +msgid "Download &social metadata (tags/rating/etc.) for the selected book" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/job_view_ui.py:42 @@ -5877,109 +6039,113 @@ msgstr "" msgid "Stop &all non device jobs" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:26 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:27 msgid "Title/Author" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:27 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:28 msgid "Standard metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:28 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:29 msgid "Custom metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:29 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:30 msgid "Search/Replace" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:33 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:34 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/progress.py:76 msgid "Working" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:186 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:187 #: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:386 msgid "Lower Case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:187 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:188 #: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:385 msgid "Upper Case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:188 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:189 #: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:388 msgid "Title Case" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:191 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:190 +msgid "Capitalize" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:193 msgid "Character match" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:192 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:194 msgid "Regular Expression" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:195 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:197 msgid "Replace field" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:196 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:198 msgid "Prepend to field" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:197 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:199 msgid "Append to field" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:208 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:210 msgid "Editing meta information for <b>%d books</b>" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:237 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:239 msgid "Immediately make all changes without closing the dialog. This operation cannot be canceled or undone" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:273 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:275 msgid "Book %d:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:288 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:290 msgid "<b>You can destroy your library using this feature.</b> Changes are permanent. There is no undo function. You are strongly encouraged to back up your library before proceeding.<p>Search and replace in text fields using character matching or regular expressions. " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:296 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:298 msgid "In character mode, the field is searched for the entered search text. The text is replaced by the specified replacement text everywhere it is found in the specified field. After replacement is finished, the text can be changed to upper-case, lower-case, or title-case. If the case-sensitive check box is checked, the search text must match exactly. If it is unchecked, the search text will match both upper- and lower-case letters" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:307 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:309 msgid "In regular expression mode, the search text is an arbitrary python-compatible regular expression. The replacement text can contain backreferences to parenthesized expressions in the pattern. The search is not anchored, and can match and replace multiple times on the same string. The modification functions (lower-case etc) are applied to the matched text, not to the field as a whole. The destination box specifies the field where the result after matching and replacement is to be assigned. You can replace the text in the field, or prepend or append the matched text. See <a href=\"http://docs.python.org/library/re.html\"> this reference</a> for more information on python's regular expressions, and in particular the 'sub' function." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:452 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:454 msgid "You must specify a destination when source is a composite field" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:544 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:552 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:647 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:546 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:554 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:649 msgid "Search/replace invalid" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:545 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:547 msgid "Authors cannot be set to the empty string. Book title %s not processed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:553 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:555 msgid "Title cannot be set to the empty string. Book title %s not processed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:648 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:650 msgid "Search pattern is invalid: %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:685 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk.py:687 msgid "" "Applying changes to %d books.\n" "Phase {0} {1}%%." @@ -6207,162 +6373,166 @@ msgstr "" msgid "&Search and replace" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:93 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:97 msgid "Last modified: %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:117 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:123 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:121 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:127 msgid "Could not read cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:118 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:122 msgid "Could not read cover from %s format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:124 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:128 msgid "The cover in the %s format is invalid" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:153 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:157 msgid "Cover size: %dx%d pixels" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:190 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:194 msgid "Not a valid picture" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:208 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:212 msgid "Specify title and author" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:209 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:213 msgid "You must specify a title and author before generating a cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:242 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:247 msgid "Downloading cover..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:254 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:259 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:265 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:270 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:258 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:263 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:269 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:274 msgid "Cannot fetch cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:255 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:266 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:271 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:259 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:270 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:275 msgid "<b>Could not fetch cover.</b><br/>" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:256 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:260 msgid "The download timed out." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:260 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:264 msgid "Could not find cover for this book. Try specifying the ISBN first." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:272 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:276 msgid "For the error message from each cover source, click Show details below." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:279 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:283 msgid "Bad cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:280 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:284 msgid "The cover is not a valid picture" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:298 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:302 msgid "Choose formats for " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:329 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:333 msgid "No permission" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:330 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:334 msgid "You do not have permission to read the following files:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:357 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:358 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:361 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:362 msgid "No format selected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:369 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:373 msgid "Could not read metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:370 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:374 msgid "Could not read metadata from %s format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:441 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:445 msgid " The green color indicates that the current author sort matches the current author" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:444 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:448 msgid " The red color indicates that the current author sort does not match the current author" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:449 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:101 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:453 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:102 +#: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:221 +#: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:384 msgid "Previous" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:452 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:460 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:456 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:464 msgid "Save changes and edit the metadata of %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:457 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:102 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:461 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:103 +#: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:211 +#: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:401 msgid "Next" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:631 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:636 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:635 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:640 msgid "This ISBN number is valid" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:639 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:643 msgid "This ISBN number is invalid" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:711 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:715 msgid "Tags changed" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:712 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:716 msgid "You have changed the tags. In order to use the tags editor, you must either discard or apply these changes" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:750 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:754 msgid "There were errors" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:751 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:755 msgid "There were errors downloading social metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:782 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:789 msgid "Cannot fetch metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:783 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:790 msgid "You must specify at least one of ISBN, Title, Authors or Publisher" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:878 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:885 msgid "Permission denied" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:879 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:886 msgid "Could not open %s. Is it being used by another program?" msgstr "" @@ -6499,7 +6669,7 @@ msgstr "" msgid "Aborting..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor.py:54 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/saved_search_editor.py:55 msgid "The current saved search will be <b>permanently deleted</b>. Are you sure?" msgstr "" @@ -6600,7 +6770,7 @@ msgid "Cannot download news as no internet connection is active" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler_ui.py:198 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:283 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:284 msgid "Recipes" msgstr "" @@ -6815,21 +6985,21 @@ msgstr "" msgid "Choose formats" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:50 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:60 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:98 msgid "Authors" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:50 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:60 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:129 msgid "Publishers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:114 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:124 msgid " (not on any book)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:166 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:176 msgid "The current tag category will be <b>permanently deleted</b>. Are you sure?" msgstr "" @@ -6881,12 +7051,12 @@ msgstr "" msgid "Select the content kind of the new category" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor.py:68 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor.py:66 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:105 msgid "Are your sure?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor.py:69 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_editor.py:67 msgid "The following tags are used by one or more books. Are you certain you want to delete them?" msgstr "" @@ -6931,12 +7101,12 @@ msgid "%s (was %s)" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:74 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:674 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:679 msgid "Item is blank" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_list_editor.py:75 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:675 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:680 msgid "An item cannot be set to nothing. Delete it instead." msgstr "" @@ -7023,82 +7193,82 @@ msgstr "" msgid "<p>Explode the ePub to display contents in a file browser window. To tweak individual files, right-click, then 'Open with...' your editor of choice. When tweaks are complete, close the file browser window <b>and the editor windows you used to edit files in the epub</b>.</p><p>Rebuild the ePub, updating your calibre library.</p>" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:132 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:133 msgid "No recipe selected" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:137 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:138 msgid "The attached file: %s is a recipe to download %s." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:138 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:139 msgid "Recipe for " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:155 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:166 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:156 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:167 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:260 msgid "Switch to Advanced mode" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:161 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:169 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:162 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:170 msgid "Switch to Basic mode" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:179 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:180 msgid "Feed must have a title" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:180 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:181 msgid "The feed must have a title" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:184 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:185 msgid "Feed must have a URL" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:185 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:186 msgid "The feed %s must have a URL" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:191 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:192 msgid "This feed has already been added to the recipe" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:232 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:241 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:291 -msgid "Invalid input" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:233 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:242 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:292 -msgid "<p>Could not create recipe. Error:<br>%s" +msgid "Invalid input" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:246 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:268 -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:295 -msgid "Replace recipe?" +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:234 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:243 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:293 +msgid "<p>Could not create recipe. Error:<br>%s" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:247 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:269 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:296 +msgid "Replace recipe?" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:248 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:270 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:297 msgid "A custom recipe named %s already exists. Do you want to replace it?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:262 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:263 msgid "Pick recipe" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:262 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:263 msgid "Pick the recipe to customize" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:282 +#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:283 msgid "Choose a recipe file" msgstr "" @@ -7431,7 +7601,7 @@ msgid "Eject this device" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/layout.py:63 -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:209 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:210 msgid "Library" msgstr "" @@ -7448,7 +7618,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:826 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:828 msgid "Card A" msgstr "" @@ -7457,7 +7627,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:828 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:830 msgid "Card B" msgstr "" @@ -7509,56 +7679,56 @@ msgstr "" msgid "Delete current saved search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:317 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:320 msgid "N" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:317 +#: /home/kovid/work/calibre/src/calibre/gui2/library/delegates.py:320 msgid "Y" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:66 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:67 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:241 msgid "On Device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:68 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:69 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:286 msgid "Size (MB)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:331 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:334 msgid "Book %s of %s." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:693 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1240 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:450 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:696 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1242 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:454 msgid "The lookup/search name is \"{0}\"" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:699 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1242 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:702 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1244 msgid "This book's UUID is \"{0}\"" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:926 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:929 msgid "In Library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:930 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:933 msgid "Size" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1140 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1142 msgid "Book <font face=\"serif\">%s</font> of %s." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1220 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1222 msgid "Marked for deletion" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1223 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1225 msgid "Double click to <b>edit</b> me<br><br>" msgstr "" @@ -7847,7 +8017,7 @@ msgid "Successfully downloaded metadata for %d out of %d books" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/metadata.py:291 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:659 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:654 msgid "Details" msgstr "" @@ -7887,17 +8057,17 @@ msgstr "" msgid "&Swap author firstname and lastname" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:32 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:33 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:145 msgid "Normal" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:32 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:33 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:146 msgid "High" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:32 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior.py:33 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/behavior_ui.py:147 msgid "Low" msgstr "" @@ -8132,7 +8302,7 @@ msgstr "" #: #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column_ui.py:145 -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column_ui.py:172 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column_ui.py:171 msgid "Create or edit custom columns" msgstr "" @@ -8221,15 +8391,14 @@ msgstr "" #: #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column_ui.py:166 msgid "" -"A comma-separated list of permitted values. You can specify\n" -"empty values by entering only the comma. For example, the list\n" -"',one,two,three' has 4 valid values, one of them empty. The first\n" -"value in the list is the default." +"A comma-separated list of permitted values. The empty value is always\n" +"included, and is the default. For example, the list 'one,two,three' has\n" +"four values, the first of them being the empty value." msgstr "" #: -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column_ui.py:171 -msgid "The first value entered will be the default value for this enumeration" +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column_ui.py:169 +msgid "The empty string is always the first value" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/preferences/device_debug.py:21 @@ -8530,43 +8699,43 @@ msgid "" "Customization: " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:155 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:156 msgid "No valid plugin path" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:156 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:157 msgid "%s is not a valid plugin path" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:159 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:160 msgid "Choose plugin" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:171 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:172 msgid "Plugin cannot be disabled" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:172 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:173 msgid "The plugin: %s cannot be disabled" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:182 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:183 msgid "Plugin not customizable" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:183 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:184 msgid "Plugin: %s does not need customization" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:193 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:194 msgid "Customize" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:236 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:237 msgid "Cannot remove builtin plugin" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:237 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:238 msgid " cannot be removed. It is a builtin plugin. Try disabling it instead." msgstr "" @@ -8864,26 +9033,26 @@ msgstr "" msgid "&Current tweaks" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:92 -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:262 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:93 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:264 #: /home/kovid/work/calibre/src/calibre/gui2/widgets.py:574 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:272 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:273 msgid "Search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:306 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:308 msgid "The selected search will be <b>permanently deleted</b>. Are you sure?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:349 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:351 msgid "Search (For Advanced Search click the button to the left)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:411 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:413 msgid "Saved Searches" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:413 +#: /home/kovid/work/calibre/src/calibre/gui2/search_box.py:415 msgid "Choose saved search or enter name for new saved search" msgstr "" @@ -8904,29 +9073,29 @@ msgstr "" msgid "({0} of all)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:58 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:59 msgid "Press a key..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:79 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:80 msgid "Already assigned" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:81 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:82 msgid "already assigned to" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:131 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:132 #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:223 msgid " or " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:133 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:134 #: /home/kovid/work/calibre/src/calibre/gui2/shortcuts_ui.py:74 msgid "&Default" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:135 +#: /home/kovid/work/calibre/src/calibre/gui2/shortcuts.py:136 msgid "Customize shortcuts for" msgstr "" @@ -8964,94 +9133,94 @@ msgstr "" msgid "&Alternate shortcut:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:215 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:217 msgid "Rename '%s'" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:219 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:221 msgid "Edit sort for '%s'" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:224 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:226 msgid "Hide category %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:227 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:229 msgid "Show category" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:236 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:240 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:238 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:242 msgid "Manage %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:243 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:245 msgid "Manage Saved Searches" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:250 -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:254 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:252 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:256 msgid "Manage User Categories" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:261 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:263 msgid "Show all categories" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:545 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:549 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:550 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:554 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:606 -#: /home/kovid/work/calibre/src/calibre/library/database2.py:294 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:611 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:296 msgid "Searches" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:689 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:694 msgid "Duplicate search name" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:690 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:695 msgid "The saved search name %s is already used." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:971 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:976 msgid "Sort by name" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:971 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:976 msgid "Sort by popularity" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:972 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:977 msgid "Sort by average rating" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:975 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:980 msgid "Set the sort order for entries in the Tag Browser" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:981 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:986 msgid "Match all" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:981 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:986 msgid "Match any" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:986 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:991 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:990 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:995 msgid "Manage &user categories" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:993 +#: /home/kovid/work/calibre/src/calibre/gui2/tag_view.py:998 msgid "Add your own categories to the Tag Browser" msgstr "" @@ -9913,50 +10082,50 @@ msgstr "" msgid "Turn on the &content server" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/caches.py:365 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:373 msgid "today" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/caches.py:368 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:376 msgid "yesterday" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/caches.py:371 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:379 msgid "thismonth" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/caches.py:374 -#: /home/kovid/work/calibre/src/calibre/library/caches.py:375 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:382 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:383 msgid "daysago" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/caches.py:554 -#: /home/kovid/work/calibre/src/calibre/library/caches.py:564 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:562 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:572 msgid "unchecked" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/caches.py:554 -#: /home/kovid/work/calibre/src/calibre/library/caches.py:564 +#: /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:184 msgid "no" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/caches.py:557 -#: /home/kovid/work/calibre/src/calibre/library/caches.py:567 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:565 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:575 msgid "checked" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/caches.py:557 -#: /home/kovid/work/calibre/src/calibre/library/caches.py:567 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:565 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:575 #: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:184 msgid "yes" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/caches.py:561 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:569 msgid "blank" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/caches.py:561 +#: /home/kovid/work/calibre/src/calibre/library/caches.py:569 msgid "empty" msgstr "" @@ -10621,35 +10790,35 @@ msgstr "" msgid "The label must contain only lower case letters, digits and underscores, and start with a letter" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:57 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:59 msgid "%sAverage rating is %3.1f" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:824 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:826 msgid "Main" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2317 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2321 msgid "<p>Migrating old database to ebook library in %s<br><center>" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2346 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2350 msgid "Copying <b>%s</b>" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2363 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2367 msgid "Compacting database" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2456 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2460 msgid "Checking SQL integrity..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2495 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2499 msgid "Checking for missing files." msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/database2.py:2523 +#: /home/kovid/work/calibre/src/calibre/library/database2.py:2527 msgid "Checked id" msgstr "" @@ -10762,7 +10931,8 @@ msgstr "" msgid "Replace whitespace with underscores." msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:335 +#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:350 +#: /home/kovid/work/calibre/src/calibre/library/save_to_disk.py:374 msgid "Requested formats not available" msgstr "" @@ -10806,65 +10976,65 @@ msgstr "" msgid "Prefix to prepend to all URLs. Useful for reverseproxying to this server from Apache/nginx/etc." msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:59 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:437 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:60 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:432 msgid "Loading, please wait" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:85 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:106 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:86 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:107 msgid "Go to" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:101 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:102 msgid "First" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:101 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:102 msgid "Last" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:104 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:105 msgid "Browsing %d books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:121 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:247 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:122 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:248 msgid "Average rating" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:122 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:123 msgid "%s: %.1f stars" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:155 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:156 msgid "%d stars" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:248 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:249 msgid "Popularity" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:267 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:268 msgid "Sort by" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:270 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:271 msgid "library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:271 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:272 msgid "home" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:332 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:548 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:333 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:543 #: /home/kovid/work/calibre/src/calibre/library/server/opds.py:569 msgid "Newest" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:333 -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:549 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:334 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:544 msgid "All books" msgstr "" @@ -10876,51 +11046,51 @@ msgstr "" msgid "Choose a category to browse by:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:457 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:452 msgid "Browsing by" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:458 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:453 msgid "Up" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:579 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:574 msgid "in" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:582 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:577 msgid "Books in" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:634 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:629 msgid "Other formats" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:641 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:636 msgid "Read %s in the %s format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:646 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:641 msgid "Get" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:661 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:656 msgid "Permalink" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:662 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:657 msgid "A permanent link to this book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:673 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:668 msgid "This book has been deleted" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:757 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:752 msgid "in search" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:759 +#: /home/kovid/work/calibre/src/calibre/library/server/browse.py:754 msgid "Matching books" msgstr "" @@ -10953,35 +11123,35 @@ msgstr "" msgid "Auto reload server when source code changes. May not work in all environments." msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:112 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:113 msgid "%d book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:131 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:132 msgid "%d items" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:149 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:150 msgid "RATING: %s<br />" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:152 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:153 msgid "TAGS: %s<br />" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:157 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:158 msgid "SERIES: %s [%s]<br />" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:248 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:249 msgid "Books in your library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:254 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:255 msgid "By " msgstr "" -#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:255 +#: /home/kovid/work/calibre/src/calibre/library/server/opds.py:256 msgid "Books sorted by " msgstr "" @@ -11062,14 +11232,26 @@ msgstr "" msgid "How and when calibre updates metadata on the device." msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter.py:33 +#: /home/kovid/work/calibre/src/calibre/utils/formatter.py:36 msgid "lookup requires either 2 or an odd number of arguments" msgstr "" -#: /home/kovid/work/calibre/src/calibre/utils/formatter.py:56 +#: /home/kovid/work/calibre/src/calibre/utils/formatter.py:59 msgid "switch requires an odd number of arguments" msgstr "" +#: /home/kovid/work/calibre/src/calibre/utils/formatter.py:116 +msgid "format: type {0} requires an integer value, got {1}" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/utils/formatter.py:122 +msgid "format: type {0} requires a decimal (float) value, got {1}" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/utils/formatter.py:124 +msgid "format: unknown format type letter {0}" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:43 msgid "Waiting..." msgstr "" @@ -11374,6 +11556,35 @@ msgstr "" msgid "Custom" msgstr "" +#: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:118 +msgid "Next section" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:121 +msgid "Main menu" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:125 +msgid "Previous section" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:214 +msgid "Section Menu" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:217 +msgid "Main Menu" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:303 +#: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:393 +msgid "Sections" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:390 +msgid "Articles" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/web/fetch/simple.py:476 msgid "" "%prog URL\n" diff --git a/src/calibre/utils/ipc/server.py b/src/calibre/utils/ipc/server.py index 380e2e074b..4d35113d80 100644 --- a/src/calibre/utils/ipc/server.py +++ b/src/calibre/utils/ipc/server.py @@ -292,12 +292,12 @@ class Server(Thread): except: pass time.sleep(0.2) - for worker in self.workers: + for worker in list(self.workers): try: worker.kill() except: pass - for worker in self.pool: + for worker in list(self.pool): try: worker.kill() except: diff --git a/src/calibre/utils/magick/draw.py b/src/calibre/utils/magick/draw.py index d3cbd58c7d..c03a8660c8 100644 --- a/src/calibre/utils/magick/draw.py +++ b/src/calibre/utils/magick/draw.py @@ -54,19 +54,23 @@ def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None, changed = True if not changed: changed = fmt != orig_fmt + + ret = None if return_data: + ret = data if changed: if hasattr(img, 'set_compression_quality') and fmt == 'jpg': img.set_compression_quality(compression_quality) - return img.export(fmt) - return data - if changed: - if hasattr(img, 'set_compression_quality') and fmt == 'jpg': - img.set_compression_quality(compression_quality) - img.save(path) + ret = img.export(fmt) else: - with lopen(path, 'wb') as f: - f.write(data) + if changed: + if hasattr(img, 'set_compression_quality') and fmt == 'jpg': + img.set_compression_quality(compression_quality) + img.save(path) + else: + with lopen(path, 'wb') as f: + f.write(data) + return ret def thumbnail(data, width=120, height=120, bgcolor='#ffffff', fmt='jpg'): img = Image() diff --git a/src/calibre/utils/magick/magick.c b/src/calibre/utils/magick/magick.c index 9dac37f2ff..fd9563529a 100644 --- a/src/calibre/utils/magick/magick.c +++ b/src/calibre/utils/magick/magick.c @@ -5,6 +5,9 @@ #include "magick_constants.h" +// Ensure that the underlying MagickWand has not been deleted +#define NULL_CHECK(x) if(self->wand == NULL) {PyErr_SetString(PyExc_ValueError, "Underlying ImageMagick Wand has been destroyed"); return x; } + // magick_set_exception {{{ PyObject* magick_set_exception(MagickWand *wand) { ExceptionType ext; @@ -54,6 +57,7 @@ magick_PixelWand_new(PyTypeObject *type, PyObject *args, PyObject *kwds) static PyObject * magick_PixelWand_color_getter(magick_PixelWand *self, void *closure) { const char *fp; + NULL_CHECK(NULL); fp = PixelGetColorAsNormalizedString(self->wand); return Py_BuildValue("s", fp); } @@ -62,6 +66,8 @@ static int magick_PixelWand_color_setter(magick_PixelWand *self, PyObject *val, void *closure) { char *fmt; + NULL_CHECK(-1); + if (val == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete PixelWand color"); return -1; @@ -80,8 +86,21 @@ magick_PixelWand_color_setter(magick_PixelWand *self, PyObject *val, void *closu // }}} +// PixelWand.destroy {{{ + +static PyObject * +magick_PixelWand_destroy(magick_PixelWand *self, PyObject *args, PyObject *kwargs) { + NULL_CHECK(NULL) + self->wand = DestroyPixelWand(self->wand); + Py_RETURN_NONE; +} +// }}} + // PixelWand attr list {{{ static PyMethodDef magick_PixelWand_methods[] = { + {"destroy", (PyCFunction)magick_PixelWand_destroy, METH_VARARGS, + "Destroy the underlying ImageMagick Wand. WARNING: After using this method, all methods on this object will raise an exception."}, + {NULL} /* Sentinel */ }; @@ -175,10 +194,21 @@ magick_DrawingWand_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)self; } +// DrawingWand.destroy {{{ + +static PyObject * +magick_DrawingWand_destroy(magick_DrawingWand *self, PyObject *args, PyObject *kwargs) { + NULL_CHECK(NULL) + self->wand = DestroyDrawingWand(self->wand); + Py_RETURN_NONE; +} +// }}} + // DrawingWand.font {{{ static PyObject * magick_DrawingWand_font_getter(magick_DrawingWand *self, void *closure) { const char *fp; + NULL_CHECK(NULL); fp = DrawGetFont(self->wand); return Py_BuildValue("s", fp); } @@ -186,6 +216,7 @@ magick_DrawingWand_font_getter(magick_DrawingWand *self, void *closure) { static int magick_DrawingWand_font_setter(magick_DrawingWand *self, PyObject *val, void *closure) { char *fmt; + NULL_CHECK(-1); if (val == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand font"); @@ -208,11 +239,13 @@ magick_DrawingWand_font_setter(magick_DrawingWand *self, PyObject *val, void *cl // DrawingWand.font_size {{{ static PyObject * magick_DrawingWand_fontsize_getter(magick_DrawingWand *self, void *closure) { + NULL_CHECK(NULL) return Py_BuildValue("d", DrawGetFontSize(self->wand)); } static int magick_DrawingWand_fontsize_setter(magick_DrawingWand *self, PyObject *val, void *closure) { + NULL_CHECK(-1) if (val == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand fontsize"); return -1; @@ -233,12 +266,14 @@ magick_DrawingWand_fontsize_setter(magick_DrawingWand *self, PyObject *val, void // DrawingWand.text_antialias {{{ static PyObject * magick_DrawingWand_textantialias_getter(magick_DrawingWand *self, void *closure) { + NULL_CHECK(NULL); if (DrawGetTextAntialias(self->wand)) Py_RETURN_TRUE; Py_RETURN_FALSE; } static int magick_DrawingWand_textantialias_setter(magick_DrawingWand *self, PyObject *val, void *closure) { + NULL_CHECK(-1); if (val == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand textantialias"); return -1; @@ -253,6 +288,7 @@ magick_DrawingWand_textantialias_setter(magick_DrawingWand *self, PyObject *val, // DrawingWand.gravity {{{ static PyObject * magick_DrawingWand_gravity_getter(magick_DrawingWand *self, void *closure) { + NULL_CHECK(NULL); return Py_BuildValue("n", DrawGetGravity(self->wand)); } @@ -260,6 +296,8 @@ static int magick_DrawingWand_gravity_setter(magick_DrawingWand *self, PyObject *val, void *closure) { int grav; + NULL_CHECK(-1); + if (val == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete DrawingWand gravity"); return -1; @@ -281,6 +319,9 @@ magick_DrawingWand_gravity_setter(magick_DrawingWand *self, PyObject *val, void // DrawingWand attr list {{{ static PyMethodDef magick_DrawingWand_methods[] = { + {"destroy", (PyCFunction)magick_DrawingWand_destroy, METH_VARARGS, + "Destroy the underlying ImageMagick Wand. WARNING: After using this method, all methods on this object will raise an exception."}, + {NULL} /* Sentinel */ }; @@ -402,6 +443,7 @@ magick_Image_load(magick_Image *self, PyObject *args, PyObject *kwargs) { Py_ssize_t dlen; MagickBooleanType res; + NULL_CHECK(NULL) if (!PyArg_ParseTuple(args, "s#", &data, &dlen)) return NULL; res = MagickReadImageBlob(self->wand, data, dlen); @@ -420,7 +462,8 @@ magick_Image_read(magick_Image *self, PyObject *args, PyObject *kwargs) { const char *data; MagickBooleanType res; - if (!PyArg_ParseTuple(args, "s", &data)) return NULL; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "s", &data)) return NULL; res = MagickReadImage(self->wand, data); @@ -441,6 +484,8 @@ magick_Image_create_canvas(magick_Image *self, PyObject *args, PyObject *kwargs) PixelWand *pw; MagickBooleanType res = MagickFalse; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "nns", &width, &height, &bgcolor)) return NULL; pw = NewPixelWand(); @@ -464,6 +509,8 @@ magick_Image_font_metrics(magick_Image *self, PyObject *args, PyObject *kwargs) DrawingWand *dw; double *metrics; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "O!s", &magick_DrawingWandType, &dw_, &text)) return NULL; dw = ((magick_DrawingWand*)dw_)->wand; if (!IsDrawingWand(dw)) { PyErr_SetString(PyExc_TypeError, "Invalid drawing wand"); return NULL; } @@ -490,6 +537,8 @@ magick_Image_annotate(magick_Image *self, PyObject *args, PyObject *kwargs) { PyObject *dw_; DrawingWand *dw; double x, y, angle; + + NULL_CHECK(NULL) if (!PyArg_ParseTuple(args, "O!ddds", &magick_DrawingWandType, &dw_, &x, &y, &angle, &text)) return NULL; dw = ((magick_DrawingWand*)dw_)->wand; @@ -510,6 +559,8 @@ magick_Image_export(magick_Image *self, PyObject *args, PyObject *kwargs) { PyObject *ans; size_t len = 0; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "s", &fmt)) return NULL; if (!MagickSetFormat(self->wand, fmt)) { @@ -533,6 +584,8 @@ magick_Image_export(magick_Image *self, PyObject *args, PyObject *kwargs) { static PyObject * magick_Image_size_getter(magick_Image *self, void *closure) { size_t width, height; + NULL_CHECK(NULL) + width = MagickGetImageWidth(self->wand); height = MagickGetImageHeight(self->wand); return Py_BuildValue("nn", width, height); @@ -545,6 +598,9 @@ magick_Image_size_setter(magick_Image *self, PyObject *val, void *closure) { double blur; MagickBooleanType res; + NULL_CHECK(-1) + + if (val == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete image size"); return -1; @@ -592,6 +648,8 @@ magick_Image_size_setter(magick_Image *self, PyObject *val, void *closure) { static PyObject * magick_Image_format_getter(magick_Image *self, void *closure) { const char *fmt; + NULL_CHECK(NULL) + fmt = MagickGetImageFormat(self->wand); return Py_BuildValue("s", fmt); } @@ -599,6 +657,8 @@ magick_Image_format_getter(magick_Image *self, void *closure) { static int magick_Image_format_setter(magick_Image *self, PyObject *val, void *closure) { char *fmt; + NULL_CHECK(-1) + if (val == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete image format"); @@ -628,6 +688,8 @@ magick_Image_distort(magick_Image *self, PyObject *args, PyObject *kwargs) { MagickBooleanType res; double *arguments = NULL; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "iOO", &method, &argv, &bestfit)) return NULL; if (!PySequence_Check(argv)) { PyErr_SetString(PyExc_TypeError, "arguments must be a sequence"); return NULL; } @@ -658,6 +720,8 @@ static PyObject * magick_Image_trim(magick_Image *self, PyObject *args, PyObject *kwargs) { double fuzz; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "d", &fuzz)) return NULL; if (!MagickTrimImage(self->wand, fuzz)) return magick_set_exception(self->wand); @@ -672,6 +736,8 @@ static PyObject * magick_Image_thumbnail(magick_Image *self, PyObject *args, PyObject *kwargs) { Py_ssize_t width, height; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "nn", &width, &height)) return NULL; if (!MagickThumbnailImage(self->wand, width, height)) return magick_set_exception(self->wand); @@ -686,6 +752,8 @@ static PyObject * magick_Image_crop(magick_Image *self, PyObject *args, PyObject *kwargs) { Py_ssize_t width, height, x, y; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "nnnn", &width, &height, &x, &y)) return NULL; if (!MagickCropImage(self->wand, width, height, x, y)) return magick_set_exception(self->wand); @@ -701,6 +769,8 @@ magick_Image_set_border_color(magick_Image *self, PyObject *args, PyObject *kwar PyObject *obj; magick_PixelWand *pw; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "O!", &magick_PixelWandType, &obj)) return NULL; pw = (magick_PixelWand*)obj; if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return NULL; } @@ -719,6 +789,8 @@ magick_Image_rotate(magick_Image *self, PyObject *args, PyObject *kwargs) { magick_PixelWand *pw; double degrees; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "O!d", &magick_PixelWandType, &obj, °rees)) return NULL; pw = (magick_PixelWand*)obj; if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return NULL; } @@ -735,6 +807,8 @@ static PyObject * magick_Image_set_page(magick_Image *self, PyObject *args, PyObject *kwargs) { Py_ssize_t width, height, x, y; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "nnnn", &width, &height, &x, &y)) return NULL; if (!MagickSetImagePage(self->wand, width, height, x, y)) return magick_set_exception(self->wand); @@ -749,6 +823,8 @@ static PyObject * magick_Image_set_compression_quality(magick_Image *self, PyObject *args, PyObject *kwargs) { Py_ssize_t quality; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "n", &quality)) return NULL; if (!MagickSetImageCompressionQuality(self->wand, quality)) return magick_set_exception(self->wand); @@ -767,6 +843,8 @@ magick_Image_has_transparent_pixels(magick_Image *self, PyObject *args, PyObject size_t r, c, width, height; double alpha; + NULL_CHECK(NULL) + height = MagickGetImageHeight(self->wand); pi = NewPixelIterator(self->wand); @@ -790,6 +868,8 @@ magick_Image_has_transparent_pixels(magick_Image *self, PyObject *args, PyObject static PyObject * magick_Image_normalize(magick_Image *self, PyObject *args, PyObject *kwargs) { + NULL_CHECK(NULL) + if (!MagickNormalizeImage(self->wand)) return magick_set_exception(self->wand); Py_RETURN_NONE; @@ -804,6 +884,8 @@ magick_Image_add_border(magick_Image *self, PyObject *args, PyObject *kwargs) { PyObject *obj; magick_PixelWand *pw; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "O!nn", &magick_PixelWandType, &obj, &dx, &dy)) return NULL; pw = (magick_PixelWand*)obj; if (!IsPixelWand(pw->wand)) { PyErr_SetString(PyExc_TypeError, "Invalid PixelWand"); return NULL; } @@ -820,6 +902,8 @@ static PyObject * magick_Image_sharpen(magick_Image *self, PyObject *args, PyObject *kwargs) { double radius, sigma; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "dd", &radius, &sigma)) return NULL; if (!MagickSharpenImage(self->wand, radius, sigma)) return magick_set_exception(self->wand); @@ -835,6 +919,9 @@ magick_Image_quantize(magick_Image *self, PyObject *args, PyObject *kwargs) { Py_ssize_t number_colors, treedepth; int colorspace; PyObject *dither, *measure_error; + + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "ninOO", &number_colors, &colorspace, &treedepth, &dither, &measure_error)) return NULL; @@ -848,6 +935,8 @@ magick_Image_quantize(magick_Image *self, PyObject *args, PyObject *kwargs) { static PyObject * magick_Image_despeckle(magick_Image *self, PyObject *args, PyObject *kwargs) { + NULL_CHECK(NULL) + if (!MagickDespeckleImage(self->wand)) return magick_set_exception(self->wand); Py_RETURN_NONE; @@ -857,6 +946,8 @@ magick_Image_despeckle(magick_Image *self, PyObject *args, PyObject *kwargs) { // Image.type {{{ static PyObject * magick_Image_type_getter(magick_Image *self, void *closure) { + NULL_CHECK(NULL) + return Py_BuildValue("n", MagickGetImageType(self->wand)); } @@ -864,6 +955,8 @@ static int magick_Image_type_setter(magick_Image *self, PyObject *val, void *closure) { int type; + NULL_CHECK(-1) + if (val == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete image type"); return -1; @@ -885,8 +978,21 @@ magick_Image_type_setter(magick_Image *self, PyObject *val, void *closure) { // }}} +// Image.destroy {{{ + +static PyObject * +magick_Image_destroy(magick_Image *self, PyObject *args, PyObject *kwargs) { + NULL_CHECK(NULL) + self->wand = DestroyMagickWand(self->wand); + Py_RETURN_NONE; +} +// }}} + // Image attr list {{{ static PyMethodDef magick_Image_methods[] = { + {"destroy", (PyCFunction)magick_Image_destroy, METH_VARARGS, + "Destroy the underlying ImageMagick Wand. WARNING: After using this method, all methods on this object will raise an exception."}, + {"load", (PyCFunction)magick_Image_load, METH_VARARGS, "Load an image from a byte buffer (string)" }, @@ -1001,6 +1107,7 @@ static PyGetSetDef magick_Image_getsetters[] = { // }}} + static PyTypeObject magick_ImageType = { // {{{ PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ @@ -1053,6 +1160,9 @@ magick_Image_compose(magick_Image *self, PyObject *args, PyObject *kwargs) magick_Image *src; MagickBooleanType res = MagickFalse; + NULL_CHECK(NULL) + + if (!PyArg_ParseTuple(args, "O!nnO", &magick_ImageType, &img, &left, &top, &op_)) return NULL; src = (magick_Image*)img; if (!IsMagickWand(src->wand)) {PyErr_SetString(PyExc_TypeError, "Not a valid ImageMagick wand"); return NULL;} @@ -1078,6 +1188,8 @@ magick_Image_copy(magick_Image *self, PyObject *args, PyObject *kwargs) PyObject *img; magick_Image *src; + NULL_CHECK(NULL) + if (!PyArg_ParseTuple(args, "O!", &magick_ImageType, &img)) return NULL; src = (magick_Image*)img; if (!IsMagickWand(src->wand)) {PyErr_SetString(PyExc_TypeError, "Not a valid ImageMagick wand"); return NULL;} @@ -1153,3 +1265,4 @@ initmagick(void) MagickWandGenesis(); } // }}} + diff --git a/src/calibre/web/feeds/__init__.py b/src/calibre/web/feeds/__init__.py index 8aef350498..478dd5015b 100644 --- a/src/calibre/web/feeds/__init__.py +++ b/src/calibre/web/feeds/__init__.py @@ -166,7 +166,7 @@ class Feed(object): self.articles.append(article) else: t = strftime(u'%a, %d %b, %Y %H:%M', article.localtime.timetuple()) - self.logger.debug('Skipping article %s (%s) from feed %s as it is too old.'% + self.logger.debug(u'Skipping article %s (%s) from feed %s as it is too old.'% (title, t, self.title)) d = item.get('date', '') article.formatted_date = d