From 0373f8bf70c0836ffaf56b3a8427778a01eff76d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C5=82ugosz?= Date: Wed, 3 Apr 2013 22:26:53 +0200 Subject: [PATCH 01/31] add garfield to .bzrignore --- .bzrignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.bzrignore b/.bzrignore index 6b6450f1f9..8711782023 100644 --- a/.bzrignore +++ b/.bzrignore @@ -40,6 +40,7 @@ recipes/.gitignore recipes/README.md recipes/icon_checker.py recipes/readme_updater.py +recipes/garfield.recipe recipes/katalog_egazeciarz.recipe recipes/tv_axnscifi.recipe recipes/tv_comedycentral.recipe @@ -63,6 +64,7 @@ recipes/tv_tvppolonia.recipe recipes/tv_tvpuls.recipe recipes/tv_viasathistory.recipe recipes/icons/katalog_egazeciarz.png +recipes/icons/garfield.png recipes/icons/tv_axnscifi.png recipes/icons/tv_comedycentral.png recipes/icons/tv_discoveryscience.png From 673f8aa9ad3343a08a0cde43bda0bef0d777f35f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C5=82ugosz?= Date: Wed, 3 Apr 2013 22:28:39 +0200 Subject: [PATCH 02/31] recipe for sportowefakty --- recipes/icons/sportowefakty.png | Bin 0 -> 511 bytes recipes/sportowefakty.recipe | 69 ++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 recipes/icons/sportowefakty.png create mode 100644 recipes/sportowefakty.recipe diff --git a/recipes/icons/sportowefakty.png b/recipes/icons/sportowefakty.png new file mode 100644 index 0000000000000000000000000000000000000000..0128c34f2648a9591066134d0c9bdd44776f251b GIT binary patch literal 511 zcmVF(E zR5}=OFeXExEp!m#qz-Q4l)QV-k#is3BuBDcgE#;bffE3+z0YIgUfd3P8TXAHLpw$3(;j z-#&Bs-ZlGfx;4#zV|;s@(_3lwANuSZ^mlD6zr^~LRa~9Aj9WjKASit*q5Z3kPPc3y^93gIV={R+RG}OI?%4^Hi|0TaUvYhI5rWZUd0QhBNf9BNn}|S6 zPS8cT|M7{nT)VJj85xb6k86l>v4AFxNJr2{iY?z+4pLKKt1PCx-jiXpj^|HkdC`VES2BO44$R&D?Q002ovPDHLkV1jEI B-O&I5 literal 0 HcmV?d00001 diff --git a/recipes/sportowefakty.recipe b/recipes/sportowefakty.recipe new file mode 100644 index 0000000000..909bbbb0f2 --- /dev/null +++ b/recipes/sportowefakty.recipe @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +__license__ = 'GPL v3' + +from calibre.web.feeds.news import BasicNewsRecipe +from calibre.utils.magick import Image + +class sportowefakty(BasicNewsRecipe): + title = u'SportoweFakty' + __author__ = 'Artur Stachecki , Tomasz Długosz ' + language = 'pl' + description = u'Najważniejsze informacje sportowe z kraju i ze świata, relacje, komentarze, wywiady, zdjęcia!' + oldest_article = 1 + masthead_url='http://www.sportowefakty.pl/images/logo.png' + max_articles_per_feed = 100 + simultaneous_downloads = 5 + use_embedded_content=False + remove_javascript=True + no_stylesheets=True + ignore_duplicate_articles = {'title', 'url'} + + keep_only_tags = [dict(attrs = {'class' : 'box-article'})] + remove_tags =[] + remove_tags.append(dict(attrs = {'class' : re.compile(r'^newsStream')})) + remove_tags.append(dict(attrs = {'target' : '_blank'})) + + feeds = [ + (u'Piłka Nożna', u'http://www.sportowefakty.pl/pilka-nozna/index.rss'), + (u'Koszykówka', u'http://www.sportowefakty.pl/koszykowka/index.rss'), + (u'Żużel', u'http://www.sportowefakty.pl/zuzel/index.rss'), + (u'Siatkówka', u'http://www.sportowefakty.pl/siatkowka/index.rss'), + (u'Zimowe', u'http://www.sportowefakty.pl/zimowe/index.rss'), + (u'Hokej', u'http://www.sportowefakty.pl/hokej/index.rss'), + (u'Moto', u'http://www.sportowefakty.pl/moto/index.rss'), + (u'Tenis', u'http://www.sportowefakty.pl/tenis/index.rss') + ] + + def get_article_url(self, article): + link = article.get('link', None) + if 'utm_source' in link: + return link.split('?utm')[0] + else: + return link + + def print_version(self, url): + print_url = url + '/drukuj' + return print_url + + def preprocess_html(self, soup): + head = soup.find('h1') + if 'Fotorelacja' in self.tag_to_string(head): + return None + else: + for alink in soup.findAll('a'): + if alink.string is not None: + tstr = alink.string + alink.replaceWith(tstr) + return soup + + def postprocess_html(self, soup, first): + for tag in soup.findAll(lambda tag: tag.name.lower()=='img' and tag.has_key('src')): + iurl = tag['src'] + img = Image() + img.open(iurl) + if img < 0: + raise RuntimeError('Out of memory') + img.type = "GrayscaleType" + img.save(iurl) + return soup From 59e81ea0777761ec2a81d3f74f9a7915d12cf9bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C5=82ugosz?= Date: Thu, 4 Apr 2013 21:13:33 +0200 Subject: [PATCH 03/31] remove DF as it is paywalled --- recipes/wyborcza_duzy_format.recipe | 144 ---------------------------- 1 file changed, 144 deletions(-) delete mode 100644 recipes/wyborcza_duzy_format.recipe diff --git a/recipes/wyborcza_duzy_format.recipe b/recipes/wyborcza_duzy_format.recipe deleted file mode 100644 index 30b0cfe418..0000000000 --- a/recipes/wyborcza_duzy_format.recipe +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/env python - -from calibre.web.feeds.recipes import BasicNewsRecipe - -class GazetaWyborczaDuzyForma(BasicNewsRecipe): - cover_url = 'http://bi.gazeta.pl/im/8/5415/m5415058.gif' - title = u"Gazeta Wyborcza Duzy Format" - __author__ = 'ravcio - rlelusz[at]gmail.com' - description = u"Articles from Gazeta's website" - language = 'pl' - max_articles_per_feed = 50 #you can increade it event up to maybe 600, should still work - recursions = 0 - encoding = 'iso-8859-2' - no_stylesheets = True - remove_javascript = True - use_embedded_content = False - - - keep_only_tags = [ - dict(name='div', attrs={'id':['k1']}) - ] - - remove_tags = [ - dict(name='div', attrs={'class':['zdjM', 'rel_video', 'zdjP', 'rel_box', 'index mod_zi_dolStrony']}) - ,dict(name='div', attrs={'id':['source', 'banP4', 'article_toolbar', 'rel', 'inContext_disabled']}) - ,dict(name='ul', attrs={'id':['articleToolbar']}) - ,dict(name='img', attrs={'class':['brand']}) - ,dict(name='h5', attrs={'class':['author']}) - ,dict(name='h6', attrs={'class':['date']}) - ,dict(name='p', attrs={'class':['txt_upl']}) - ] - - remove_tags_after = [ - dict(name='div', attrs={'id':['Str']}) #nawigator numerow linii - ] - - def load_article_links(self, url, count): - print '--- load_article_links', url, count - - #page with link to articles - soup = self.index_to_soup(url) - - #table with articles - list = soup.find('div', attrs={'class':'GWdalt'}) - - #single articles (link, title, ...) - links = list.findAll('div', attrs={'class':['GWdaltE']}) - - if len(links) < count: - #load links to more articles... - - #remove new link - pages_nav = list.find('div', attrs={'class':'pages'}) - next = pages_nav.find('a', attrs={'class':'next'}) - if next: - print 'next=', next['href'] - url = 'http://wyborcza.pl' + next['href'] - #e.g. url = 'http://wyborcza.pl/0,75480.html?str=2' - - older_links = self.load_article_links(url, count - len(links)) - links.extend(older_links) - - return links - - - #produce list of articles to download - def parse_index(self): - print '--- parse_index' - - max_articles = 8000 - links = self.load_article_links('http://wyborcza.pl/0,75480.html', max_articles) - - ans = [] - key = None - articles = {} - - key = 'Uncategorized' - articles[key] = [] - - for div_art in links: - div_date = div_art.find('div', attrs={'class':'kL'}) - div = div_art.find('div', attrs={'class':'kR'}) - - a = div.find('a', href=True) - - url = a['href'] - title = a.string - description = '' - pubdate = div_date.string.rstrip().lstrip() - summary = div.find('span', attrs={'class':'lead'}) - - desc = summary.find('a', href=True) - if desc: - desc.extract() - - description = self.tag_to_string(summary, use_alt=False) - description = description.rstrip().lstrip() - - feed = key if key is not None else 'Duzy Format' - - if not articles.has_key(feed): - articles[feed] = [] - - if description != '': # skip just pictures atricle - articles[feed].append( - dict(title=title, url=url, date=pubdate, - description=description, - content='')) - - ans = [(key, articles[key])] - return ans - - def append_page(self, soup, appendtag, position): - pager = soup.find('div',attrs={'id':'Str'}) - if pager: - #seek for 'a' element with nast value (if not found exit) - list = pager.findAll('a') - - for elem in list: - if 'nast' in elem.string: - nexturl = elem['href'] - - soup2 = self.index_to_soup('http://warszawa.gazeta.pl' + nexturl) - - texttag = soup2.find('div', attrs={'id':'artykul'}) - - newpos = len(texttag.contents) - self.append_page(soup2,texttag,newpos) - texttag.extract() - appendtag.insert(position,texttag) - - def preprocess_html(self, soup): - self.append_page(soup, soup.body, 3) - - # finally remove some tags - pager = soup.find('div',attrs={'id':'Str'}) - if pager: - pager.extract() - - pager = soup.find('div',attrs={'class':'tylko_int'}) - if pager: - pager.extract() - - return soup From 517448c1b1a72be102e1f59c9b185f51892bfa09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C5=82ugosz?= Date: Thu, 4 Apr 2013 21:15:23 +0200 Subject: [PATCH 04/31] add wysokie obcasy --- recipes/icons/wysokie_obcasy.png | Bin 0 -> 205 bytes recipes/wysokie_obcasy.recipe | 58 +++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 recipes/icons/wysokie_obcasy.png create mode 100644 recipes/wysokie_obcasy.recipe diff --git a/recipes/icons/wysokie_obcasy.png b/recipes/icons/wysokie_obcasy.png new file mode 100644 index 0000000000000000000000000000000000000000..3ab94b3c66467a977b7409e32c9cc2b9d8bb8990 GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFP2=EDU{r~^}MF#T=3>H^K+%GX$ zTwpN1ZIp1C!SoWN)sO2Bem{S686<0VMa2DSdgrUQg=>CKoB`C!SQ6wH%;50sMjDXg z?djqe!Z9;BL4oa$DH~I@!sE${7A#m`GvVWMfm1)8ti7@&Q2xXW>5$+@Nt`JgST(ui zb~2FVdQ&MBb@0ChW1 AL;wH) literal 0 HcmV?d00001 diff --git a/recipes/wysokie_obcasy.recipe b/recipes/wysokie_obcasy.recipe new file mode 100644 index 0000000000..40c8cf60a9 --- /dev/null +++ b/recipes/wysokie_obcasy.recipe @@ -0,0 +1,58 @@ +#!/usr/bin/env python +__license__ = 'GPL v3' +import re + +from calibre.web.feeds.news import BasicNewsRecipe + +class WysokieObcasyRecipe(BasicNewsRecipe): + __author__ = u'Artur Stachecki ' + language = 'pl' + version = 1 + + title = u'Wysokie Obcasy' + publisher = 'Agora SA' + description = u'Serwis sobotniego dodatku do Gazety Wyborczej' + category='magazine' + language = 'pl' + publication_type = 'magazine' + cover_url='' + remove_empty_feeds= True + no_stylesheets=True + oldest_article = 7 + max_articles_per_feed = 100000 + recursions = 0 + + no_stylesheets = True + remove_javascript = True + simultaneous_downloads = 5 + + keep_only_tags =[] + keep_only_tags.append(dict(name = 'div', attrs = {'id' : 'article'})) + + remove_tags =[] + remove_tags.append(dict(name = 'img')) + remove_tags.append(dict(name = 'p', attrs = {'class' : 'info'})) + + extra_css = ''' + body {font-family: verdana, arial, helvetica, geneva, sans-serif ;} + h1{text-align: left;} + ''' + + feeds = [ + ('Wszystkie Artykuly', 'feed://www.wysokieobcasy.pl/pub/rss/wysokieobcasy.xml'), + ] + + def print_version(self,url): + baseURL='http://www.wysokieobcasy.pl/wysokie-obcasy' + segments = url.split(',') + subPath= '/2029020,' + articleURL1 = segments[1] + articleURL2 = segments[2] + printVerString=articleURL1 + ',' + articleURL2 + s= baseURL + subPath + printVerString + '.html' + return s + + def get_cover_url(self): + soup = self.index_to_soup('http://www.wysokieobcasy.pl/wysokie-obcasy/0,0.html') + self.cover_url = soup.find(attrs={'class':'holder_cr'}).find('img')['src'] + return getattr(self, 'cover_url', self.cover_url) \ No newline at end of file From 2b78b82be70100e8d3b6e84d04b1ee24ddd09c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C5=82ugosz?= Date: Thu, 4 Apr 2013 21:18:31 +0200 Subject: [PATCH 05/31] change title of gazeta_pl flavors --- recipes/gazeta_pl_krakow.recipe | 2 +- recipes/gazeta_pl_szczecin.recipe | 2 +- recipes/gazeta_pl_warszawa.recipe | 2 +- recipes/gazeta_wyborcza.recipe | 2 +- recipes/icons/gazeta_pl_krakow.png | Bin 802 -> 294 bytes recipes/icons/gazeta_pl_szczecin.png | Bin 802 -> 294 bytes recipes/icons/gazeta_pl_warszawa.png | Bin 802 -> 294 bytes recipes/icons/gazeta_wyborcza.png | Bin 802 -> 294 bytes 8 files changed, 4 insertions(+), 4 deletions(-) diff --git a/recipes/gazeta_pl_krakow.recipe b/recipes/gazeta_pl_krakow.recipe index 59b3b00933..0f7633e4b2 100644 --- a/recipes/gazeta_pl_krakow.recipe +++ b/recipes/gazeta_pl_krakow.recipe @@ -10,7 +10,7 @@ krakow.gazeta.pl from calibre.web.feeds.news import BasicNewsRecipe class gw_krakow(BasicNewsRecipe): - title = u'Gazeta.pl Kraków' + title = u'Gazeta Wyborcza Kraków' __author__ = 'teepel based on GW from fenuks' language = 'pl' description =u'Wiadomości z Krakowa na portalu Gazeta.pl.' diff --git a/recipes/gazeta_pl_szczecin.recipe b/recipes/gazeta_pl_szczecin.recipe index af229c5721..501b25dfe5 100644 --- a/recipes/gazeta_pl_szczecin.recipe +++ b/recipes/gazeta_pl_szczecin.recipe @@ -5,7 +5,7 @@ import string from calibre.web.feeds.news import BasicNewsRecipe class GazetaPlSzczecin(BasicNewsRecipe): - title = u'Gazeta.pl Szczecin' + title = u'Gazeta Wyborcza Szczecin' description = u'Wiadomości ze Szczecina na portalu Gazeta.pl.' __author__ = u'Michał Szkutnik' __license__ = u'GPL v3' diff --git a/recipes/gazeta_pl_warszawa.recipe b/recipes/gazeta_pl_warszawa.recipe index 9e10a0610c..6a37a96885 100644 --- a/recipes/gazeta_pl_warszawa.recipe +++ b/recipes/gazeta_pl_warszawa.recipe @@ -10,7 +10,7 @@ warszawa.gazeta.pl from calibre.web.feeds.news import BasicNewsRecipe class gw_wawa(BasicNewsRecipe): - title = u'Gazeta.pl Warszawa' + title = u'Gazeta Wyborcza Warszawa' __author__ = 'teepel based on GW from fenuks' language = 'pl' description ='Wiadomości z Warszawy na portalu Gazeta.pl.' diff --git a/recipes/gazeta_wyborcza.recipe b/recipes/gazeta_wyborcza.recipe index c415edc9d0..310077cdec 100644 --- a/recipes/gazeta_wyborcza.recipe +++ b/recipes/gazeta_wyborcza.recipe @@ -3,7 +3,7 @@ from calibre.web.feeds.news import BasicNewsRecipe from calibre.ebooks.BeautifulSoup import Comment class Gazeta_Wyborcza(BasicNewsRecipe): - title = u'Gazeta.pl' + title = u'Gazeta Wyborcza' __author__ = 'fenuks, Artur Stachecki' language = 'pl' description = 'Wiadomości z Polski i ze świata. Serwisy tematyczne i lokalne w 20 miastach.' diff --git a/recipes/icons/gazeta_pl_krakow.png b/recipes/icons/gazeta_pl_krakow.png index 119afbba3a21235994b651d96e0ea8cc5fd35658..49d76d2ddc6f4549c7211bb82f5176d1d8413c5b 100644 GIT binary patch literal 294 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;OS+@4BLl<6e(pbstUx|vage(c z!@6@aFM%9|WRD45bDP46hOx7_4S6Fo+k-*%fF5lwb?+ z32_C|R|OO``h28;EXI-`zhDN3XE)M-9L@rd$YLPv0mg18v+aNkK2I0N5RU7~6aF7` z;9_E!{avu|+_&36QyElCTq8?Mnsfm?=g|>l_ zm4QL?RMuxG8glbfGSe!78VoFT4UBXR%|i^0txQd=jLo$T41pR-ew-5nYGCkm^>bP0 Hl+XkKPAf?O delta 791 zcmV+y1L*vw0-^?x7=H)`0000V^Z#K000QYrL_t(Ijct-oXk1kk#((d=m-%O!41_Ey zZLOvabum!sLaBm^pi~zkinLTv!G$0g5kzrcy6M72w_4mPrAAaz+N7m5X*y0&)6Arr zHkl@-$@I@KO(yf+yYJq6Tug>o@GQ@FIN#y-9Zy8W&Q>86;C~P706^k|=$m0=t%<$9 zNbd7@@%KFjfId5kom(U*?4j$q{V08|NOa~r%`Z-3rmnY#ez=GWo48Qpw5E0Z6adNO zHIk_rT)n}@u~Wpumr!9xc7OFgrcycDfE0wgh95wGF)dHc%d_1C7KyyumqCe=jHx{^KEuL7E}5IUgh!N|;gw z^VcHTkKQJDY7lc}hGb$22?F$wzmj_CX>wn_hrPK>e1B#Xsjp*i)yNJVM#UrJIOQSf zfY!WHwz`Uq5;})UGsKpw zc$pMVCx~(2`=AYGdLBWrVccer{rCv3R);8|`?Gfd$Q(U{)Eb1BN<>#@$R2qGZ(EMc z(L;DB!hiEcf?bc2`|z#J6grSRZ;Rpm2k5a9!M@!Dg@G-&+91sqUT-(}YBPl}Ms)IU zjDODIt+z0xS!8WvOGpKHJ&%B|+Mar>B*|0-TV5bLbeLfOAo`ba%-lSPA{i~=5A3A- zt4~3M=<8wZ!ZNDAkIV45bDP46hOx7_4S6Fo+k-*%fF5lwb?+ z32_C|R|OO``h28;EXI-`zhDN3XE)M-9L@rd$YLPv0mg18v+aNkK2I0N5RU7~6aF7` z;9_E!{avu|+_&36QyElCTq8?Mnsfm?=g|>l_ zm4QL?RMuxG8glbfGSe!78VoFT4UBXR%|i^0txQd=jLo$T41pR-ew-5nYGCkm^>bP0 Hl+XkKPAf?O delta 791 zcmV+y1L*vw0-^?x7=H)`0000V^Z#K000QYrL_t(Ijct-oXk1kk#((d=m-%O!41_Ey zZLOvabum!sLaBm^pi~zkinLTv!G$0g5kzrcy6M72w_4mPrAAaz+N7m5X*y0&)6Arr zHkl@-$@I@KO(yf+yYJq6Tug>o@GQ@FIN#y-9Zy8W&Q>86;C~P706^k|=$m0=t%<$9 zNbd7@@%KFjfId5kom(U*?4j$q{V08|NOa~r%`Z-3rmnY#ez=GWo48Qpw5E0Z6adNO zHIk_rT)n}@u~Wpumr!9xc7OFgrcycDfE0wgh95wGF)dHc%d_1C7KyyumqCe=jHx{^KEuL7E}5IUgh!N|;gw z^VcHTkKQJDY7lc}hGb$22?F$wzmj_CX>wn_hrPK>e1B#Xsjp*i)yNJVM#UrJIOQSf zfY!WHwz`Uq5;})UGsKpw zc$pMVCx~(2`=AYGdLBWrVccer{rCv3R);8|`?Gfd$Q(U{)Eb1BN<>#@$R2qGZ(EMc z(L;DB!hiEcf?bc2`|z#J6grSRZ;Rpm2k5a9!M@!Dg@G-&+91sqUT-(}YBPl}Ms)IU zjDODIt+z0xS!8WvOGpKHJ&%B|+Mar>B*|0-TV5bLbeLfOAo`ba%-lSPA{i~=5A3A- zt4~3M=<8wZ!ZNDAkIV45bDP46hOx7_4S6Fo+k-*%fF5lwb?+ z32_C|R|OO``h28;EXI-`zhDN3XE)M-9L@rd$YLPv0mg18v+aNkK2I0N5RU7~6aF7` z;9_E!{avu|+_&36QyElCTq8?Mnsfm?=g|>l_ zm4QL?RMuxG8glbfGSe!78VoFT4UBXR%|i^0txQd=jLo$T41pR-ew-5nYGCkm^>bP0 Hl+XkKPAf?O delta 791 zcmV+y1L*vw0-^?x7=H)`0000V^Z#K000QYrL_t(Ijct-oXk1kk#((d=m-%O!41_Ey zZLOvabum!sLaBm^pi~zkinLTv!G$0g5kzrcy6M72w_4mPrAAaz+N7m5X*y0&)6Arr zHkl@-$@I@KO(yf+yYJq6Tug>o@GQ@FIN#y-9Zy8W&Q>86;C~P706^k|=$m0=t%<$9 zNbd7@@%KFjfId5kom(U*?4j$q{V08|NOa~r%`Z-3rmnY#ez=GWo48Qpw5E0Z6adNO zHIk_rT)n}@u~Wpumr!9xc7OFgrcycDfE0wgh95wGF)dHc%d_1C7KyyumqCe=jHx{^KEuL7E}5IUgh!N|;gw z^VcHTkKQJDY7lc}hGb$22?F$wzmj_CX>wn_hrPK>e1B#Xsjp*i)yNJVM#UrJIOQSf zfY!WHwz`Uq5;})UGsKpw zc$pMVCx~(2`=AYGdLBWrVccer{rCv3R);8|`?Gfd$Q(U{)Eb1BN<>#@$R2qGZ(EMc z(L;DB!hiEcf?bc2`|z#J6grSRZ;Rpm2k5a9!M@!Dg@G-&+91sqUT-(}YBPl}Ms)IU zjDODIt+z0xS!8WvOGpKHJ&%B|+Mar>B*|0-TV5bLbeLfOAo`ba%-lSPA{i~=5A3A- zt4~3M=<8wZ!ZNDAkIV45bDP46hOx7_4S6Fo+k-*%fF5lwb?+ z32_C|R|OO``h28;EXI-`zhDN3XE)M-9L@rd$YLPv0mg18v+aNkK2I0N5RU7~6aF7` z;9_E!{avu|+_&36QyElCTq8?Mnsfm?=g|>l_ zm4QL?RMuxG8glbfGSe!78VoFT4UBXR%|i^0txQd=jLo$T41pR-ew-5nYGCkm^>bP0 Hl+XkKPAf?O delta 791 zcmV+y1L*vw0-^?x7=H)`0000V^Z#K000QYrL_t(Ijct-oXk1kk#((d=m-%O!41_Ey zZLOvabum!sLaBm^pi~zkinLTv!G$0g5kzrcy6M72w_4mPrAAaz+N7m5X*y0&)6Arr zHkl@-$@I@KO(yf+yYJq6Tug>o@GQ@FIN#y-9Zy8W&Q>86;C~P706^k|=$m0=t%<$9 zNbd7@@%KFjfId5kom(U*?4j$q{V08|NOa~r%`Z-3rmnY#ez=GWo48Qpw5E0Z6adNO zHIk_rT)n}@u~Wpumr!9xc7OFgrcycDfE0wgh95wGF)dHc%d_1C7KyyumqCe=jHx{^KEuL7E}5IUgh!N|;gw z^VcHTkKQJDY7lc}hGb$22?F$wzmj_CX>wn_hrPK>e1B#Xsjp*i)yNJVM#UrJIOQSf zfY!WHwz`Uq5;})UGsKpw zc$pMVCx~(2`=AYGdLBWrVccer{rCv3R);8|`?Gfd$Q(U{)Eb1BN<>#@$R2qGZ(EMc z(L;DB!hiEcf?bc2`|z#J6grSRZ;Rpm2k5a9!M@!Dg@G-&+91sqUT-(}YBPl}Ms)IU zjDODIt+z0xS!8WvOGpKHJ&%B|+Mar>B*|0-TV5bLbeLfOAo`ba%-lSPA{i~=5A3A- zt4~3M=<8wZ!ZNDAkIV Date: Thu, 4 Apr 2013 21:19:33 +0200 Subject: [PATCH 06/31] minor fix for esensja rss --- recipes/esensja_(rss).recipe | 6 ------ 1 file changed, 6 deletions(-) diff --git a/recipes/esensja_(rss).recipe b/recipes/esensja_(rss).recipe index af23ea58a9..0afa2b0d07 100644 --- a/recipes/esensja_(rss).recipe +++ b/recipes/esensja_(rss).recipe @@ -12,12 +12,6 @@ class EsensjaRSS(BasicNewsRecipe): language = 'pl' encoding = 'utf-8' INDEX = 'http://www.esensja.pl' - extra_css = '''.t-title {font-size: x-large; font-weight: bold; text-align: left} - .t-author {font-size: x-small; text-align: left} - .t-title2 {font-size: x-small; font-style: italic; text-align: left} - .text {font-size: small; text-align: left} - .annot-ref {font-style: italic; text-align: left} - ''' cover_url = '' masthead_url = 'http://esensja.pl/img/wrss.gif' use_embedded_content = False From 702658aad09e31999210237b7aa2ae05b19d1950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C5=82ugosz?= Date: Thu, 4 Apr 2013 21:20:33 +0200 Subject: [PATCH 07/31] recipe for forbes.pl --- recipes/forbes_pl.recipe | 54 ++++++++++++++++++++++++++++++++++++ recipes/icons/forbes_pl.png | Bin 0 -> 1179 bytes 2 files changed, 54 insertions(+) create mode 100644 recipes/forbes_pl.recipe create mode 100644 recipes/icons/forbes_pl.png diff --git a/recipes/forbes_pl.recipe b/recipes/forbes_pl.recipe new file mode 100644 index 0000000000..ec65ecf279 --- /dev/null +++ b/recipes/forbes_pl.recipe @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +__license__ = 'GPL v3' + +from calibre.web.feeds.news import BasicNewsRecipe +import datetime +import re +from calibre.ebooks.BeautifulSoup import Comment + +class forbes_pl(BasicNewsRecipe): + title = u'Forbes.pl' + __author__ = 'Artur Stachecki ' + language = 'pl' + description = u'Biznes, finanse, gospodarka, strategie, wiadomości gospodarcze, analizy finasowe i strategiczne.' + oldest_article = 1 + index = 'http://www.forbes.pl' + cover_url = 'http://www.forbes.pl/resources/front/images/logo.png' + max_articles_per_feed = 100 + extra_css = '.Block-Photo {float:left; max-width: 300px; margin-right: 5px;}' + preprocess_regexps = [(re.compile(ur'

()?(Czytaj|Zobacz) (też|także):.*?

', re.DOTALL), lambda match: ''), (re.compile(ur'Zobacz:.*?', re.DOTALL), lambda match: '')] + remove_javascript = True + no_stylesheets = True + now = datetime.datetime.now() + yesterday = now - datetime.timedelta(hours=24) + yesterday = yesterday.strftime("%d.%m.%Y %H:%M:%S") + pages_count = 4 + keep_only_tags = [dict(attrs={'class':['Block-Node Content-Article ', 'Block-Node Content-Article piano-closed']})] + remove_tags = [dict(attrs={'class':['Keywords Styled', 'twitter-share-button', 'Block-List-Related Block-List']})] + + feeds = [(u'Wszystkie', 'http://www.forbes.pl/rss')] + + '''def preprocess_html(self, soup): + self.append_page(soup, soup.body) + return soup + + + def append_page(self, soup, appendtag): + cleanup = False + nexturl = appendtag.find('a', attrs={'class':'next'}) + if nexturl: + cleanup = True + while nexturl: + soup2 = self.index_to_soup(self.index + nexturl['href']) + nexturl = soup2.find('a', attrs={'class':'next'}) + pagetext = soup2.findAll(id='article-body-wrapper') + if not pagetext: + pagetext = soup2.findAll(attrs={'class':'Article-Entry Styled'}) + for comment in pagetext.findAll(text=lambda text:isinstance(text, Comment)): + comment.extract() + pos = len(appendtag.contents) + appendtag.insert(pos, pagetext) + if cleanup: + for r in appendtag.findAll(attrs={'class':'paginator'}): + r.extract()''' \ No newline at end of file diff --git a/recipes/icons/forbes_pl.png b/recipes/icons/forbes_pl.png new file mode 100644 index 0000000000000000000000000000000000000000..feaa47487a5f0bf88df6de03eb3db4552191f7f5 GIT binary patch literal 1179 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgf<4skwt!$UoVdl?v5q&;06Lo5Ut z1z6tyW?a91!~dT@KLAyd3jQ;kIdheP1*AD5;sI3mcOcD($E5#2IZmiN2axVzU_q$< z&9Gxf0E4@`1zhOcw|5L|Y-|kw{`~{ed|+`###$ha(8dH;&A`gw;jxop!Gb+-AuB68 z23A&A26lF5hQ`JUsQ7xgJcxlX3M%~I0YZqAlNBf$0L0%J8X6ul7#pv_(1K76H2@o> zuP?yx{{26OoSdydX;>IQR3do+Q|tHdpg{e_(BJRHASro`;o(CKAm0Z?Azl|8K75*i zgX2Fi9QYU*8Ser$nga136a(jj9aKR_4g0-1M!7}fb8c?=gQDg6V9g8?TeD7As2@&^!m0x@0#{xa0nSu(`M zIROn-K+1pI#5t^cX`UOaK@LpbP?XDhPo5 uIswc=B|uI`cRoZ9%jwfsfs#F_>Pg`FK8an=XpprEq{Y+K&t;ucLK6U@R)7@% literal 0 HcmV?d00001 From da3c080baa9c867ce24abfbec477a6ed93aa103a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20D=C5=82ugosz?= Date: Thu, 4 Apr 2013 21:21:42 +0200 Subject: [PATCH 08/31] icon for slashdot --- recipes/icons/slashdot.png | Bin 0 -> 250 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 recipes/icons/slashdot.png diff --git a/recipes/icons/slashdot.png b/recipes/icons/slashdot.png new file mode 100644 index 0000000000000000000000000000000000000000..5e7487244b9e56abdbddc3bbd7ee2d8c951f7032 GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!aez;VE07jRN-;@F5%KcjiHlM3 z@>#NPPsyYyK2 Date: Fri, 5 Apr 2013 08:08:46 +0530 Subject: [PATCH 09/31] ... --- recipes/hbr.recipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipes/hbr.recipe b/recipes/hbr.recipe index fa89a10f29..a418ba96d4 100644 --- a/recipes/hbr.recipe +++ b/recipes/hbr.recipe @@ -20,7 +20,7 @@ class HBR(BasicNewsRecipe): 'articleToolbarTopRD', 'pageRightSubColumn', 'pageRightColumn', 'todayOnHBRListWidget', 'mostWidget', 'keepUpWithHBR', 'mailingListTout', 'partnerCenter', 'pageFooter', - 'superNavHeadContainer', 'hbrDisqus', + 'superNavHeadContainer', 'hbrDisqus', 'article-toolbox', 'articleToolbarTop', 'articleToolbarBottom', 'articleToolbarRD']), dict(name='iframe')] extra_css = ''' From cb97563d7daabe30171e8a8ef0427ff6321fc2f2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 5 Apr 2013 08:20:43 +0530 Subject: [PATCH 10/31] Diario de Noticias by Jose Pinto --- recipes/diario_de_noticias.recipe | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 recipes/diario_de_noticias.recipe diff --git a/recipes/diario_de_noticias.recipe b/recipes/diario_de_noticias.recipe new file mode 100644 index 0000000000..4ba7c6f7e5 --- /dev/null +++ b/recipes/diario_de_noticias.recipe @@ -0,0 +1,23 @@ +# vim:fileencoding=UTF-8 + +from __future__ import unicode_literals +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1365070687(BasicNewsRecipe): + title ='Diário de Notícias' + oldest_article = 7 + language = 'pt' + __author__ = 'Jose Pinto' + max_articles_per_feed = 100 + keep_only_tags = [dict(name='div', attrs={'id':'cln-esqmid'}) ] + remove_tags = [ dict(name='table', attrs={'class':'TabFerramentasInf'}) ] + + feeds = [(u'Portugal', u'http://feeds.dn.pt/DN-Portugal'), + (u'Globo', u'http://feeds.dn.pt/DN-Globo'), + (u'Economia', u'http://feeds.dn.pt/DN-Economia'), + (u'Ci\xeancia', u'http://feeds.dn.pt/DN-Ciencia'), + (u'Artes', u'http://feeds.dn.pt/DN-Artes'), + (u'TV & Media', u'http://feeds.dn.pt/DN-Media'), + (u'Opini\xe3o', u'http://feeds.dn.pt/DN-Opiniao'), + (u'Pessoas', u'http://feeds.dn.pt/DN-Pessoas') + ] From c680f51d520f26045deb26718abcae5160483078 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 5 Apr 2013 08:26:52 +0530 Subject: [PATCH 11/31] ... --- src/calibre/utils/mreplace.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/calibre/utils/mreplace.py b/src/calibre/utils/mreplace.py index 70591d6ca7..2586c83967 100644 --- a/src/calibre/utils/mreplace.py +++ b/src/calibre/utils/mreplace.py @@ -17,8 +17,7 @@ class MReplace(UserDict): def compile_regex(self): if len(self.data) > 0: - keys = sorted(self.data.keys(), key=len) - keys.reverse() + keys = sorted(self.data.keys(), key=len, reverse=True) tmp = "(%s)" % "|".join(map(re.escape, keys)) if self.re != tmp: self.re = tmp From 12b5fbf81f3a2792672338feaff6676f7b231b2d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 5 Apr 2013 08:28:54 +0530 Subject: [PATCH 12/31] XSL cleanups --- resources/templates/rtf.xsl | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/resources/templates/rtf.xsl b/resources/templates/rtf.xsl index 61474701dc..ee247296c6 100644 --- a/resources/templates/rtf.xsl +++ b/resources/templates/rtf.xsl @@ -357,7 +357,7 @@ - + @@ -390,7 +390,6 @@ - @@ -415,13 +414,11 @@ - - page-break-after:always - +
- +
@@ -445,7 +442,7 @@ - + @@ -472,9 +469,7 @@ - - - + From 9f3271714ccc37511e30659e39bdaac72688b747 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 5 Apr 2013 08:38:35 +0530 Subject: [PATCH 13/31] version 0.9.26 --- Changelog.yaml | 52 ++++++++++++++++++++++++++++++++++++++++ src/calibre/constants.py | 2 +- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/Changelog.yaml b/Changelog.yaml index f27843ad1f..8fb8965e8d 100644 --- a/Changelog.yaml +++ b/Changelog.yaml @@ -20,6 +20,58 @@ # new recipes: # - title: +- version: 0.9.26 + date: 2013-04-05 + + new features: + - title: "PDF Output: Allow using templates to create arbitrary headers and footers. Look under PDF Output in the conversion dialog for this feature." + + - title: "ToC Editor: Allow generating the ToC directly from individual files inside the ebook. Useful for EPUBs that have individual chapters in single files." + tickets: [1163520] + + - title: "ToC Editor: Add buttons to indent/unindent the current entry" + + - title: "ToC Editor: Right-click menu to perform various useful actions on entries in the ToC" + + - title: "Column icons: Allow use of wide images as column icons" + + - title: "Add USB ids for the Palm Pre2 and Samsung Galaxy phone to the device drivers" + tickets: [1162293,1163115] + + bug fixes: + - title: "PDF Output: Fix generating page numbers causing links to not work." + tickets: [1162573] + + - title: "Wrong filename output in error message when 'Guide reference not found'" + tickets: [1163659] + + - title: "Get Books: Update Amazon, Barnes & Noble, Waterstones and Gutenberg store plugins for website change" + + - title: "PDF Output: Fix 1 pixel wide left and top margins on the cover page for some PDF conversions due to incorrect rounding." + tickets: [1162054] + + - title: "ToC Editor: Fix drag and drop of multiple items resulting in the dropped items being in random order sometimes." + tickets: [1161999] + + improved recipes: + - Financial Times UK + - Sing Tao Daily + - Apple Daily + - A List Apart + - Business Week + - Harpers printed edition + - Harvard Business Review + + new recipes: + - title: AM730 + author: Eddie Lau + + - title: Arret sur images + author: Francois D + + - title: Diario de Noticias + author: Jose Pinto + - version: 0.9.25 date: 2013-03-29 diff --git a/src/calibre/constants.py b/src/calibre/constants.py index 724aa4d96c..bb85221558 100644 --- a/src/calibre/constants.py +++ b/src/calibre/constants.py @@ -4,7 +4,7 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __docformat__ = 'restructuredtext en' __appname__ = u'calibre' -numeric_version = (0, 9, 25) +numeric_version = (0, 9, 26) __version__ = u'.'.join(map(unicode, numeric_version)) __author__ = u"Kovid Goyal " From 053c84b57fc447262411f36ab96531691b9c4848 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 5 Apr 2013 09:22:08 +0530 Subject: [PATCH 14/31] IGN:Tag release --- src/calibre/translations/calibre.pot | 613 ++++++++++++++++----------- 1 file changed, 363 insertions(+), 250 deletions(-) diff --git a/src/calibre/translations/calibre.pot b/src/calibre/translations/calibre.pot index f21970ce7e..3e56497f17 100644 --- a/src/calibre/translations/calibre.pot +++ b/src/calibre/translations/calibre.pot @@ -4,9 +4,9 @@ # msgid "" msgstr "" -"Project-Id-Version: calibre 0.9.25\n" -"POT-Creation-Date: 2013-03-29 10:03+IST\n" -"PO-Revision-Date: 2013-03-29 10:03+IST\n" +"Project-Id-Version: calibre 0.9.26\n" +"POT-Creation-Date: 2013-04-05 08:39+IST\n" +"PO-Revision-Date: 2013-04-05 08:39+IST\n" "Last-Translator: Automatically generated\n" "Language-Team: LANGUAGE\n" "MIME-Version: 1.0\n" @@ -97,9 +97,9 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/rtf.py:101 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/snb.py:16 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/base.py:50 -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/base.py:347 -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/covers.py:79 -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/covers.py:81 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/base.py:350 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/covers.py:84 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/covers.py:86 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/douban.py:79 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google.py:81 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/identify.py:259 @@ -108,7 +108,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/identify.py:468 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/ozon.py:59 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/ozon.py:130 -#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/worker.py:26 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/worker.py:27 #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/txt.py:18 #: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader/headers.py:28 #: /home/kovid/work/calibre/src/calibre/ebooks/mobi/reader/headers.py:98 @@ -158,18 +158,18 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/scheduler.py:381 #: /home/kovid/work/calibre/src/calibre/gui2/email.py:193 #: /home/kovid/work/calibre/src/calibre/gui2/email.py:208 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:475 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1178 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1394 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1397 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1400 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1488 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:482 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1185 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1401 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1404 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1407 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1495 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:85 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:250 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:261 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:426 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:178 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:182 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:177 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:181 #: /home/kovid/work/calibre/src/calibre/gui2/store/search/models.py:202 #: /home/kovid/work/calibre/src/calibre/gui2/store/stores/google_books_plugin.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:209 @@ -317,330 +317,330 @@ msgstr "" msgid "Set metadata from %s files" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:770 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:771 msgid "Add books to calibre or the connected device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:775 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:776 msgid "Fetch annotations from a connected Kindle (experimental)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:780 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:781 msgid "Generate a catalog of the books in your calibre library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:785 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:786 msgid "Convert books to various ebook formats" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:790 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:791 msgid "Fine tune your ebooks" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:795 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:796 #: /home/kovid/work/calibre/src/calibre/gui2/actions/toc_edit.py:63 msgid "Edit the Table of Contents in your books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:800 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:801 msgid "Delete books from your calibre library or connected device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:805 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:806 msgid "Edit the metadata of books in your calibre library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:810 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:811 msgid "Read books in your calibre library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:815 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:816 msgid "Download news from the internet in ebook form" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:820 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:821 msgid "Show a list of related books quickly" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:825 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:826 msgid "Export books from your calibre library to the hard disk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:830 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:831 msgid "Show book details in a separate popup" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:835 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:836 #: /home/kovid/work/calibre/src/calibre/gui2/actions/restart.py:14 msgid "Restart calibre" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:840 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:841 msgid "Open the folder that contains the book files in your calibre library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:846 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:847 msgid "Send books to the connected device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:851 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:852 msgid "Send books via email or the web also connect to iTunes or folders on your computer as if they are devices" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:857 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:858 #: /home/kovid/work/calibre/src/calibre/gui2/actions/help.py:16 msgid "Browse the calibre User Manual" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:862 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:863 msgid "Customize calibre" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:867 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:868 msgid "Easily find books similar to the currently selected one" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:872 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:873 msgid "Switch between different calibre libraries and perform maintenance on them" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:878 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:879 msgid "Copy books from the devce to your calibre library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:883 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:884 msgid "Edit the collections in which books are placed on your device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:888 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:889 msgid "Copy a book from one calibre library to another" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:893 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:894 msgid "Make small tweaks to epub or htmlz files in your calibre library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:898 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:899 msgid "Find the next or previous match when searching in your calibre library in highlight mode" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:904 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:905 msgid "Choose a random book from your calibre library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:911 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:912 msgid "Search for books from different book sellers" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:927 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:928 msgid "Get new calibre plugins or update your existing ones" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:946 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:947 msgid "Look and Feel" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:948 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:960 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:971 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:982 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:994 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:949 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:961 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:972 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:983 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:995 msgid "Interface" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:952 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:953 msgid "Adjust the look and feel of the calibre interface to suit your tastes" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:958 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:959 msgid "Behavior" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:964 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:965 msgid "Change the way calibre behaves" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:969 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:970 #: /home/kovid/work/calibre/src/calibre/gui2/library/views.py:276 msgid "Add your own columns" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:975 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:976 msgid "Add/remove your own columns to the calibre book list" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:980 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:981 msgid "Toolbar" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:986 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:987 msgid "Customize the toolbars and context menus, changing which actions are available in each" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:992 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:993 msgid "Searching" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:998 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:999 msgid "Customize the way searching for books works in calibre" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1003 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1004 msgid "Input Options" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1005 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1016 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1027 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1006 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1017 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1028 msgid "Conversion" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1009 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1010 msgid "Set conversion options specific to each input format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1014 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1015 msgid "Common Options" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1020 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1021 msgid "Set conversion options common to all formats" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1025 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1026 msgid "Output Options" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1031 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1032 msgid "Set conversion options specific to each output format" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1036 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1037 msgid "Adding books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1038 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1050 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1062 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1074 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1039 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1051 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1063 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1075 msgid "Import/Export" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1042 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1043 msgid "Control how calibre reads metadata from files when adding books" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1048 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1049 msgid "Saving books to disk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1054 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1055 msgid "Control how calibre exports files from its database to disk when using Save to disk" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1060 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1061 msgid "Sending books to devices" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1066 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1067 msgid "Control how calibre transfers files to your ebook reader" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1072 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1073 msgid "Metadata plugboards" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1078 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1079 msgid "Change metadata fields before saving/sending" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1083 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1084 msgid "Template Functions" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1085 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1145 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1157 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1168 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1179 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1086 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1146 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1158 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1169 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1180 msgid "Advanced" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1089 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1090 msgid "Create your own template functions" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1094 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1095 msgid "Sharing books by email" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1096 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1108 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1121 -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1132 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1097 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1109 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1122 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1133 msgid "Sharing" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1100 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1101 msgid "Setup sharing of books via email. Can be used for automatic sending of downloaded news to your devices" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1106 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1107 msgid "Sharing over the net" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1112 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1113 msgid "Setup the calibre Content Server which will give you access to your calibre library from anywhere, on any device, over the internet" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1119 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1120 msgid "Metadata download" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1125 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1126 msgid "Control how calibre downloads ebook metadata from the net" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1130 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1131 #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:400 msgid "Ignored devices" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1136 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1137 msgid "Control which devices calibre will ignore when they are connected to the computer." msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1143 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1144 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/plugins.py:296 msgid "Plugins" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1149 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1150 msgid "Add/remove/customize various bits of calibre functionality" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1155 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1156 msgid "Tweaks" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1161 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1162 msgid "Fine tune how calibre behaves in various contexts" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1166 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1167 msgid "Keyboard" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1172 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1173 msgid "Customize the keyboard shortcuts used by calibre" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1177 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1178 #: /home/kovid/work/calibre/src/calibre/gui2/keyboard.py:110 msgid "Miscellaneous" msgstr "" -#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1183 +#: /home/kovid/work/calibre/src/calibre/customize/builtins.py:1184 msgid "Miscellaneous advanced configuration" msgstr "" @@ -937,7 +937,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/db/fields.py:484 #: /home/kovid/work/calibre/src/calibre/db/fields.py:499 #: /home/kovid/work/calibre/src/calibre/devices/apple/driver.py:2826 -#: /home/kovid/work/calibre/src/calibre/devices/nook/driver.py:106 +#: /home/kovid/work/calibre/src/calibre/devices/nook/driver.py:107 #: /home/kovid/work/calibre/src/calibre/devices/prs505/sony_cache.py:448 #: /home/kovid/work/calibre/src/calibre/devices/prs505/sony_cache.py:471 #: /home/kovid/work/calibre/src/calibre/devices/prst1/driver.py:773 @@ -1880,7 +1880,7 @@ msgstr "" msgid "Communicate with the Nook eBook reader." msgstr "" -#: /home/kovid/work/calibre/src/calibre/devices/nook/driver.py:85 +#: /home/kovid/work/calibre/src/calibre/devices/nook/driver.py:86 msgid "Communicate with the Nook Color, TSR and Tablet eBook readers." msgstr "" @@ -2295,7 +2295,7 @@ msgid "There is insufficient free space on the storage card" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:210 -#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/render/from_html.py:255 +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/render/from_html.py:274 #, python-format msgid "Rendered %s" msgstr "" @@ -2767,11 +2767,17 @@ msgid "Add page numbers to the bottom of every page in the generated PDF file. I msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/pdf_output.py:107 -msgid "An HTML template used to generate footers on every page. The string _PAGENUM_ will be replaced by the current page number." +#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/pdf_output.py:110 +#, python-format +msgid "An HTML template used to generate %s on every page. The strings _PAGENUM_, _TITLE_, _AUTHOR_ and _SECTION_ will be replaced by their current values." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/pdf_output.py:108 +msgid "footers" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/pdf_output.py:111 -msgid "An HTML template used to generate headers on every page. The string _PAGENUM_ will be replaced by the current page number." +msgid "headers" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/conversion/plugins/pml_output.py:22 @@ -3515,9 +3521,9 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:76 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/quickview.py:85 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:222 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:115 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1183 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:150 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:122 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1190 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:149 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:162 #: /home/kovid/work/calibre/src/calibre/gui2/store/search/models.py:39 #: /home/kovid/work/calibre/src/calibre/gui2/store/stores/mobileread/models.py:23 @@ -3528,14 +3534,14 @@ msgid "Title" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:770 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:117 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1184 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:124 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1191 #: /home/kovid/work/calibre/src/calibre/gui2/store/stores/mobileread/models.py:23 msgid "Author(s)" msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:771 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:122 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:129 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:159 msgid "Publisher" msgstr "" @@ -3571,7 +3577,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:637 #: /home/kovid/work/calibre/src/calibre/gui2/catalog/catalog_epub_mobi.py:1132 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:60 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:123 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:130 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:70 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:161 #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:981 @@ -3586,7 +3592,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/quickview.py:89 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/tag_categories.py:60 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/template_dialog.py:224 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:124 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:131 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:70 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:163 #: /home/kovid/work/calibre/src/calibre/library/catalogs/epub_mobi_builder.py:306 @@ -3598,7 +3604,7 @@ msgstr[0] "" msgstr[1] "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:778 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:126 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:133 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:164 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:127 msgid "Languages" @@ -3610,8 +3616,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/book/base.py:782 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:183 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:120 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:150 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:127 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:149 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:305 msgid "Published" msgstr "" @@ -3783,6 +3789,49 @@ msgstr "" msgid "Downloads metadata and covers from Google Books" msgstr "" +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:18 +msgid "Downloads covers from a Google Image search. Useful to find larger/alternate covers." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:20 +msgid "Configure the Google Image Search plugin" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:22 +msgid "Maximum number of covers to get" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:23 +msgid "The maximum number of covers to process from the google search result" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:24 +msgid "Cover size" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:25 +msgid "Search for covers larger than the specified size" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:27 +msgid "Any size" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:28 +#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:146 +msgid "Large" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:29 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:30 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:31 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:32 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:33 +#: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/google_images.py:34 +#, python-format +msgid "Larger than %s" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/ebooks/metadata/sources/isbndb.py:24 msgid "Downloads metadata from isbndb.com" msgstr "" @@ -3859,9 +3908,9 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/mobi/writer8/toc.py:15 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/base.py:1286 -#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/toc.py:344 +#: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/toc.py:373 #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/htmltoc.py:15 -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:351 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:356 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:221 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/toc.py:219 msgid "Table of Contents" @@ -4115,8 +4164,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/polish/toc.py:199 #: /home/kovid/work/calibre/src/calibre/gui2/toc/location.py:234 -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:524 -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:539 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:669 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:684 msgid "(Untitled)" msgstr "" @@ -4132,7 +4181,7 @@ msgid "HTML TOC generation options." msgstr "" #: /home/kovid/work/calibre/src/calibre/ebooks/oeb/transforms/jacket.py:185 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:121 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:128 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:71 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/metadata_sources.py:160 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:176 @@ -4176,6 +4225,10 @@ msgstr "" msgid "Could not find pdftohtml, check it is in your PATH" msgstr "" +#: /home/kovid/work/calibre/src/calibre/ebooks/pdf/render/from_html.py:310 +msgid "Untitled" +msgstr "" + #: /home/kovid/work/calibre/src/calibre/ebooks/rb/rbml.py:102 #: /home/kovid/work/calibre/src/calibre/ebooks/txt/txtml.py:97 msgid "Table of Contents:" @@ -4632,7 +4685,7 @@ msgid "Select destination for %(title)s.%(fmt)s" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/catalog.py:101 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:986 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:993 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:108 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:280 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:345 @@ -5139,11 +5192,13 @@ msgid "Some of the selected books are on the attached device. Where do yo msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/delete.py:350 -msgid "The selected books will be permanently deleted and the files removed from your calibre library. Are you sure?" +#, python-format +msgid "The %d selected book(s) 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:385 -msgid "The selected books will be permanently deleted from your device. Are you sure?" +#, python-format +msgid "The %d selected book(s) will be permanently deleted from your device. Are you sure?" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/device.py:33 @@ -5305,8 +5360,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:129 #: /home/kovid/work/calibre/src/calibre/gui2/dnd.py:84 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:534 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:846 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:533 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:882 msgid "Download failed" msgstr "" @@ -5338,7 +5393,7 @@ msgid "Download complete" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/actions/edit_metadata.py:151 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:908 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:945 msgid "Download log" msgstr "" @@ -6391,7 +6446,7 @@ msgid "Book %(sidx)s of %(series)s" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/book_details.py:233 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1187 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1194 msgid "Collections" msgstr "" @@ -6502,7 +6557,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/page_setup_ui.py:124 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdb_output_ui.py:47 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_input_ui.py:43 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:117 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:139 #: /home/kovid/work/calibre/src/calibre/gui2/convert/pmlz_output_ui.py:46 #: /home/kovid/work/calibre/src/calibre/gui2/convert/rb_output_ui.py:33 #: /home/kovid/work/calibre/src/calibre/gui2/convert/search_and_replace_ui.py:145 @@ -7887,56 +7942,60 @@ msgstr "" msgid "PDF Output" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:118 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:140 msgid "Note: The paper size settings below only take effect if you enable the \"Override\" checkbox below. Otherwise the size from the output profile will be used." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:119 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:141 msgid "&Override paper size set in output profile" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:120 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:142 msgid "&Paper Size:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:121 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:143 msgid "&Custom size:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:122 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:144 msgid "&Unit:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:123 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:145 msgid "Preserve &aspect ratio of cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:124 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:146 +msgid "Add page &numbers to the bottom of every page" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:147 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:392 msgid "Se&rif family:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:125 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:148 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:393 msgid "&Sans family:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:126 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:149 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:394 msgid "&Monospace family:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:127 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:150 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:399 msgid "S&tandard font:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:128 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:151 msgid "Default font si&ze:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:129 -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:131 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:152 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:154 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel_ui.py:280 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:396 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:398 @@ -7948,13 +8007,25 @@ msgstr "" msgid " px" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:130 +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:153 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/config_ui.py:397 msgid "Monospace &font size:" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:132 -msgid "Add page &numbers to the bottom of every page" +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:155 +msgid "Page headers and footers" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:156 +msgid "You can insert headers and footers into every page of the produced PDF file by using header and footer templates. For examples, see the documentation." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:157 +msgid "&Header template:" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/convert/pdf_output_ui.py:158 +msgid "&Footer template:" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/convert/pml_output.py:14 @@ -8989,7 +9060,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/device_drivers/mtp_config.py:421 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/message_box.py:141 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:901 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:938 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/tweaks.py:344 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:227 msgid "Copy to clipboard" @@ -9498,8 +9569,8 @@ msgid "Location" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/delete_matching_from_device.py:77 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:119 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1185 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:126 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1192 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:35 #: /home/kovid/work/calibre/src/calibre/gui2/preferences/create_custom_column.py:76 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:365 @@ -9616,7 +9687,7 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/edit_authors_dialog.py:122 #: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main.py:160 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:543 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:542 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:753 msgid "No matches found" msgstr "" @@ -9795,8 +9866,8 @@ msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/message_box.py:196 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/message_box.py:251 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:966 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:1075 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:1003 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:1112 #: /home/kovid/work/calibre/src/calibre/gui2/proceed.py:48 msgid "View log" msgstr "" @@ -12211,62 +12282,62 @@ msgstr "" msgid "Y" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:116 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:123 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:285 msgid "On Device" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:118 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:125 msgid "Size (MB)" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:125 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:132 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:275 msgid "Modified" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:893 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1530 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:900 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1537 #: /home/kovid/work/calibre/src/calibre/gui2/tag_browser/model.py:337 msgid "The lookup/search name is \"{0}\"" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:899 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1532 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:906 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1539 msgid "This book's UUID is \"{0}\"" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:987 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:994 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:109 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/basic_widgets.py:281 #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:479 msgid "Could not change the on disk location of this book. Is it open in another program?" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:991 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:997 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:998 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1004 msgid "Failed to set data" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:992 -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:998 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:999 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1005 msgid "Could not set data, click Show Details to see why." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1182 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1189 msgid "In Library" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1186 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1193 #: /home/kovid/work/calibre/src/calibre/library/field_metadata.py:355 msgid "Size" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1512 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1519 msgid "Marked for deletion" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1515 +#: /home/kovid/work/calibre/src/calibre/gui2/library/models.py:1522 msgid "Double click to edit me

" msgstr "" @@ -12369,7 +12440,7 @@ msgid "Previous Page" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/lrf_renderer/main_ui.py:133 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:963 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:1000 #: /home/kovid/work/calibre/src/calibre/gui2/store/web_store_dialog_ui.py:62 #: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:215 msgid "Back" @@ -12838,7 +12909,7 @@ msgid "Edit Metadata" msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/metadata/single.py:63 -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:956 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:993 #: /home/kovid/work/calibre/src/calibre/library/server/browse.py:108 #: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:219 #: /home/kovid/work/calibre/src/calibre/web/feeds/templates.py:410 @@ -12974,15 +13045,15 @@ msgstr "" msgid "Basic metadata" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:150 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:149 msgid "Has cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:150 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:149 msgid "Has summary" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:207 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:206 msgid "" "The has cover indication is not fully\n" "reliable. Sometimes results marked as not\n" @@ -12990,62 +13061,62 @@ msgid "" "cover stage, and vice versa." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:301 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:300 msgid "See at" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:462 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:461 msgid "calibre is downloading metadata from: " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:484 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:483 msgid "Please wait" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:516 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:515 msgid "Query: " msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:535 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:534 msgid "Failed to download metadata. Click Show Details to see details" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:544 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:543 msgid "Failed to find any books that match your search. Try making the search less specific. For example, use only the author's last name and a single distinctive word from the title.

To see the full log, click Show Details." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:652 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:651 msgid "Current cover" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:655 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:654 msgid "Searching..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:816 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:852 #, python-format msgid "Downloading covers for %s, please wait..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:847 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:883 msgid "Failed to download any covers, click \"Show details\" for details." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:853 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:889 #, python-format msgid "Could not find any covers for %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:855 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:891 #, python-format -msgid "Found %(num)d covers of %(title)s. Pick the one you like best." +msgid "Found %(num)d possible covers for %(title)s. When the download completes, the covers will be sorted by size." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:944 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:981 msgid "Downloading metadata..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:1059 +#: /home/kovid/work/calibre/src/calibre/gui2/metadata/single_download.py:1096 msgid "Downloading cover..." msgstr "" @@ -14106,10 +14177,6 @@ msgstr "" msgid "Small" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:146 -msgid "Large" -msgstr "" - #: /home/kovid/work/calibre/src/calibre/gui2/preferences/look_feel.py:146 msgid "Medium" msgstr "" @@ -16256,187 +16323,233 @@ msgstr "" msgid "The XPath expression %s is not valid." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:146 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:147 msgid "You can edit existing entries in the Table of Contents by clicking them in the panel to the left." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:148 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:149 msgid "Entries with a green tick next to them point to a location that has been verified to exist. Entries with a red dot are broken and may need to be fixed." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:156 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:157 msgid "Create a &new entry" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:161 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:162 msgid "Generate ToC from &major headings" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:164 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:165 msgid "Generate a Table of Contents from the major headings in the book. This will work if the book identifies its headings using HTML heading tags. Uses the

,

and

tags." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:168 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:169 msgid "Generate ToC from &all headings" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:171 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:172 msgid "Generate a Table of Contents from all the headings in the book. This will work if the book identifies its headings using HTML heading tags. Uses the tags." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:176 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:177 msgid "Generate ToC from &links" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:179 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:180 msgid "Generate a Table of Contents from all the links in the book. Links that point to destinations that do not exist in the book are ignored. Also multiple links with the same destination or the same text are ignored." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:186 -msgid "Generate ToC from &XPath" +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:187 +msgid "Generate ToC from &files" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:189 -msgid "Generate a Table of Contents from arbitrary XPath expressions." -msgstr "" - -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:193 -msgid "Flatten the ToC" +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:190 +msgid "Generate a Table of Contents from individual files in the book. Each entry in the ToC will point to the start of the file, the text of the entry will be the \"first line\" of text from the file." msgstr "" #: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:196 +msgid "Generate ToC from &XPath" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:199 +msgid "Generate a Table of Contents from arbitrary XPath expressions." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:203 +msgid "&Flatten the ToC" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:206 msgid "Flatten the Table of Contents, putting all entries at the top level" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:202 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:212 msgid "WARNING: calibre only supports the creation of linear ToCs in AZW3 files. In a linear ToC every entry must point to a location after the previous entry. If you create a non-linear ToC it will be automatically re-arranged inside the AZW3 file." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:218 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:228 msgid "You can move this entry around the Table of Contents by drag and drop or using the up and down buttons to the left" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:239 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:249 msgid "Change the &location this entry points to" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:243 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:253 msgid "&Remove this entry" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:253 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:263 msgid "New entry &inside this entry" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:256 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:266 msgid "New entry &above this entry" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:259 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:269 msgid "New entry &below this entry" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:263 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:273 msgid "&Flatten this entry" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:265 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:275 msgid "All children of this entry are brought to the same level as this entry." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:276 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:286 msgid "&Return to welcome screen" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:278 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:288 msgid "Go back to the top level view" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:328 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:338 msgid "This entry points to an existing destination" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:331 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:341 msgid "The location this entry points to does not exist" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:369 -msgid "Move current entry up" +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:519 +#, python-format +msgid "Move \"%s\" up" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:375 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:521 +#, python-format +msgid "Move \"%s\" down" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:522 +msgid "Remove all selected items" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:524 +#, python-format +msgid "Unindent \"%s\"" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:526 +#, python-format +msgid "Indent \"%s\"" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:527 +msgid "Change all selected items to title case" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:545 +msgid "Move current entry up [Ctrl+Up]" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:552 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:566 +msgid "Unindent the current entry [Ctrl+Left]" +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:559 msgid "Remove all selected entries" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:381 -msgid "Move current entry down" +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:573 +msgid "Move current entry down [Ctrl+Down]" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:383 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:575 msgid "&Expand all" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:387 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:579 msgid "&Collapse all" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:390 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:582 msgid "Double click on an entry to change the text" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:515 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:660 msgid "Title: {0} Dest: {1}{2}" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:546 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:691 #, python-format msgid "" "The location this entry point to does not exist:\n" "%s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:636 -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:643 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:781 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:788 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:795 msgid "No items found" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:637 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:782 msgid "No items were found that could be added to the Table of Contents." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:644 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:789 msgid "No links were found that could be added to the Table of Contents." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:661 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:796 +msgid "No files were found that could be added to the Table of Contents." +msgstr "" + +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:814 #, python-format msgid "Edit the ToC in %s" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:677 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:830 #, python-format msgid "Loading %s, please wait..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:712 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:865 #, python-format msgid "Writing %s, please wait..." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:720 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:873 msgid "Failed to write book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:721 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:874 #, python-format msgid "Could not write %s. Click \"Show details\" for more information." msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:758 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:911 msgid "Failed to load book" msgstr "" -#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:759 +#: /home/kovid/work/calibre/src/calibre/gui2/toc/main.py:912 #, python-format msgid "Could not load %s. Click \"Show details\" for more information." msgstr "" @@ -20386,7 +20499,7 @@ msgid "Splitting multiple author names" msgstr "" #: /home/kovid/work/calibre/resources/default_tweaks.py:78 -msgid "By default, calibre splits a string containing multiple author names on\nampersands and the words \"and\" and \"with\". You can customize the splitting\nby changing the regular expression below. Strings are split on whatever the\nspecified regular expression matches.\nDefault: r'(?i),?\\s+(and|with)\\s+'" +msgid "By default, calibre splits a string containing multiple author names on\nampersands and the words \"and\" and \"with\". You can customize the splitting\nby changing the regular expression below. Strings are split on whatever the\nspecified regular expression matches, in addition to ampersands.\nDefault: r'(?i),?\\s+(and|with)\\s+'" msgstr "" #: /home/kovid/work/calibre/resources/default_tweaks.py:85 From 9a1d1c4fee860bd88f0080eb51a391c668e0f565 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 5 Apr 2013 15:50:44 +0530 Subject: [PATCH 15/31] The Galaxy's Edge by Krittika Goyal --- recipes/galaxys_edge.recipe | 108 ++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 recipes/galaxys_edge.recipe diff --git a/recipes/galaxys_edge.recipe b/recipes/galaxys_edge.recipe new file mode 100644 index 0000000000..e6e1dd7475 --- /dev/null +++ b/recipes/galaxys_edge.recipe @@ -0,0 +1,108 @@ +from __future__ import with_statement +__license__ = 'GPL 3' +__copyright__ = '2009, Kovid Goyal ' + +from calibre.web.feeds.news import BasicNewsRecipe + +class GalaxyEdge(BasicNewsRecipe): + title = u'The Galaxy\'s Edge' + language = 'en' + + oldest_article = 7 + __author__ = 'Krittika Goyal' + no_stylesheets = True + + auto_cleanup = True + + #keep_only_tags = [dict(id='content')] + #remove_tags = [dict(attrs={'class':['article-links', 'breadcr']}), + #dict(id=['email-section', 'right-column', 'printfooter', 'topover', + #'slidebox', 'th_footer'])] + + extra_css = '.photo-caption { font-size: smaller }' + + def parse_index(self): + soup = self.index_to_soup('http://www.galaxysedge.com/') + main = soup.find('table', attrs={'width':'911'}) + toc = main.find('td', attrs={'width':'225'}) + + + + current_section = None + current_articles = [] + feeds = [] + c = 0 + for x in toc.findAll(['p']): + c = c+1 + if c == 5: + if current_articles and current_section: + feeds.append((current_section, current_articles)) + edwo = x.find('a') + current_section = self.tag_to_string(edwo) + current_articles = [] + self.log('\tFound section:', current_section) + title = self.tag_to_string(edwo) + url = edwo.get('href', True) + url = 'http://www.galaxysedge.com/'+url + print(title) + print(c) + if not url or not title: + continue + self.log('\t\tFound article:', title) + self.log('\t\t\t', url) + current_articles.append({'title': title, 'url':url, + 'description':'', 'date':''}) + elif c>5: + current_section = self.tag_to_string(x.find('b')) + current_articles = [] + self.log('\tFound section:', current_section) + for y in x.findAll('a'): + title = self.tag_to_string(y) + url = y.get('href', True) + url = 'http://www.galaxysedge.com/'+url + print(title) + if not url or not title: + continue + self.log('\t\tFound article:', title) + self.log('\t\t\t', url) + current_articles.append({'title': title, 'url':url, + 'description':'', 'date':''}) + if current_articles and current_section: + feeds.append((current_section, current_articles)) + + return feeds + + + + + #def preprocess_raw_html(self, raw, url): + #return raw.replace('

', '

').replace('

', '

') + + #def postprocess_html(self, soup, first_fetch): + #for t in soup.findAll(['table', 'tr', 'td','center']): + #t.name = 'div' + #return soup + + #def parse_index(self): + #today = time.strftime('%Y-%m-%d') + #soup = self.index_to_soup( + #'http://www.thehindu.com/todays-paper/tp-index/?date=' + today) + #div = soup.find(id='left-column') + #feeds = [] + #current_section = None + #current_articles = [] + #for x in div.findAll(['h3', 'div']): + #if current_section and x.get('class', '') == 'tpaper': + #a = x.find('a', href=True) + #if a is not None: + #current_articles.append({'url':a['href']+'?css=print', + #'title':self.tag_to_string(a), 'date': '', + #'description':''}) + #if x.name == 'h3': + #if current_section and current_articles: + #feeds.append((current_section, current_articles)) + #current_section = self.tag_to_string(x) + #current_articles = [] + #return feeds + + From fa47afe5a6035b0ee98e327ad663b8a533dd459b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 5 Apr 2013 22:56:22 +0530 Subject: [PATCH 16/31] Update Victoria Times --- recipes/vic_times.recipe | 111 ++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 43 deletions(-) diff --git a/recipes/vic_times.recipe b/recipes/vic_times.recipe index 48fb9038aa..8aaa6d05b3 100644 --- a/recipes/vic_times.recipe +++ b/recipes/vic_times.recipe @@ -6,17 +6,62 @@ __license__ = 'GPL v3' www.canada.com ''' import re -from calibre.web.feeds.recipes import BasicNewsRecipe +from calibre.web.feeds.news import BasicNewsRecipe + from calibre.ebooks.BeautifulSoup import Tag, BeautifulStoneSoup class TimesColonist(BasicNewsRecipe): + # Customization -- remove sections you don't want. + # If your e-reader is an e-ink Kindle and your output profile is + # set properly this recipe will not include images because the + # resulting file is too large. If you have one of these and want + # images you can set kindle_omit_images = False + # and remove sections (typically the e-ink Kindles will + # work with about a dozen of these, but your mileage may vary). + + kindle_omit_images = True + + section_list = [ + ('','Web Front Page'), + ('news/','News Headlines'), + ('news/b-c/','BC News'), + ('news/national/','National News'), + ('news/world/','World News'), + ('opinion/','Opinion'), + ('opinion/letters/','Letters'), + ('business/','Business'), + ('business/money/','Money'), + ('business/technology/','Technology'), + ('business/working/','Working'), + ('sports/','Sports'), + ('sports/hockey/','Hockey'), + ('sports/football/','Football'), + ('sports/basketball/','Basketball'), + ('sports/golf/','Golf'), + ('entertainment/','entertainment'), + ('entertainment/go/','Go!'), + ('entertainment/music/','Music'), + ('entertainment/books/','Books'), + ('entertainment/Movies/','Movies'), + ('entertainment/television/','Television'), + ('life/','Life'), + ('life/health/','Health'), + ('life/travel/','Travel'), + ('life/driving/','Driving'), + ('life/homes/','Homes'), + ('life/food-drink/','Food & Drink') + ] + title = u'Victoria Times Colonist' url_prefix = 'http://www.timescolonist.com' description = u'News from Victoria, BC' fp_tag = 'CAN_TC' + masthead_url = 'http://www.timescolonist.com/gmg/img/global/logoTimesColonist.png' + + url_list = [] language = 'en_CA' __author__ = 'Nick Redding' @@ -29,15 +74,21 @@ class TimesColonist(BasicNewsRecipe): .caption { font-size: xx-small; font-style: italic; font-weight: normal; } ''' keep_only_tags = [dict(name='div', attrs={'class':re.compile('main.content')})] - remove_tags = [{'class':'comments'}, - {'id':'photocredit'}, - dict(name='div', attrs={'class':re.compile('top.controls')}), - dict(name='div', attrs={'class':re.compile('social')}), - dict(name='div', attrs={'class':re.compile('tools')}), - dict(name='div', attrs={'class':re.compile('bottom.tools')}), - dict(name='div', attrs={'class':re.compile('window')}), - dict(name='div', attrs={'class':re.compile('related.news.element')})] + def __init__(self, options, log, progress_reporter): + self.remove_tags = [{'class':'comments'}, + {'id':'photocredit'}, + dict(name='div', attrs={'class':re.compile('top.controls')}), + dict(name='div', attrs={'class':re.compile('^comments')}), + dict(name='div', attrs={'class':re.compile('social')}), + dict(name='div', attrs={'class':re.compile('tools')}), + dict(name='div', attrs={'class':re.compile('bottom.tools')}), + dict(name='div', attrs={'class':re.compile('window')}), + dict(name='div', attrs={'class':re.compile('related.news.element')})] + print("PROFILE NAME = "+options.output_profile.short_name) + if self.kindle_omit_images and options.output_profile.short_name in ['kindle', 'kindle_dx', 'kindle_pw']: + self.remove_tags.append(dict(name='div', attrs={'class':re.compile('image-container')})) + BasicNewsRecipe.__init__(self, options, log, progress_reporter) def get_cover_url(self): from datetime import timedelta, date @@ -122,7 +173,6 @@ class TimesColonist(BasicNewsRecipe): def preprocess_html(self,soup): byline = soup.find('p',attrs={'class':re.compile('ancillary')}) if byline is not None: - byline.find('a') authstr = self.tag_to_string(byline,False) authstr = re.sub('/ *Times Colonist','/',authstr, flags=re.IGNORECASE) authstr = re.sub('BY */','',authstr, flags=re.IGNORECASE) @@ -149,9 +199,10 @@ class TimesColonist(BasicNewsRecipe): atag = htag.a if atag is not None: url = atag['href'] - #print("Checking "+url) - if atag['href'].startswith('/'): - url = self.url_prefix+atag['href'] + url = url.strip() + # print("Checking >>"+url+'<<\n\r') + if url.startswith('/'): + url = self.url_prefix+url if url in self.url_list: return self.url_list.append(url) @@ -171,10 +222,10 @@ class TimesColonist(BasicNewsRecipe): if dtag is not None: description = self.tag_to_string(dtag,False) article_list.append(dict(title=title,url=url,date='',description=description,author='',content='')) - #print(sectitle+title+": description = "+description+" URL="+url) + print(sectitle+title+": description = "+description+" URL="+url+'\n\r') def add_section_index(self,ans,securl,sectitle): - print("Add section url="+self.url_prefix+'/'+securl) + print("Add section url="+self.url_prefix+'/'+securl+'\n\r') try: soup = self.index_to_soup(self.url_prefix+'/'+securl) except: @@ -193,33 +244,7 @@ class TimesColonist(BasicNewsRecipe): def parse_index(self): ans = [] - ans = self.add_section_index(ans,'','Web Front Page') - ans = self.add_section_index(ans,'news/','News Headlines') - ans = self.add_section_index(ans,'news/b-c/','BC News') - ans = self.add_section_index(ans,'news/national/','Natioanl News') - ans = self.add_section_index(ans,'news/world/','World News') - ans = self.add_section_index(ans,'opinion/','Opinion') - ans = self.add_section_index(ans,'opinion/letters/','Letters') - ans = self.add_section_index(ans,'business/','Business') - ans = self.add_section_index(ans,'business/money/','Money') - ans = self.add_section_index(ans,'business/technology/','Technology') - ans = self.add_section_index(ans,'business/working/','Working') - ans = self.add_section_index(ans,'sports/','Sports') - ans = self.add_section_index(ans,'sports/hockey/','Hockey') - ans = self.add_section_index(ans,'sports/football/','Football') - ans = self.add_section_index(ans,'sports/basketball/','Basketball') - ans = self.add_section_index(ans,'sports/golf/','Golf') - ans = self.add_section_index(ans,'entertainment/','entertainment') - ans = self.add_section_index(ans,'entertainment/go/','Go!') - ans = self.add_section_index(ans,'entertainment/music/','Music') - ans = self.add_section_index(ans,'entertainment/books/','Books') - ans = self.add_section_index(ans,'entertainment/Movies/','movies') - ans = self.add_section_index(ans,'entertainment/television/','Television') - ans = self.add_section_index(ans,'life/','Life') - ans = self.add_section_index(ans,'life/health/','Health') - ans = self.add_section_index(ans,'life/travel/','Travel') - ans = self.add_section_index(ans,'life/driving/','Driving') - ans = self.add_section_index(ans,'life/homes/','Homes') - ans = self.add_section_index(ans,'life/food-drink/','Food & Drink') + for (url,title) in self.section_list: + ans = self.add_section_index(ans,url,title) return ans From a68eaa53da1f8d06981aa4b4dbfa03fe68165b84 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 6 Apr 2013 08:29:26 +0530 Subject: [PATCH 17/31] Update Business Week Magazine --- recipes/bwmagazine2.recipe | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/recipes/bwmagazine2.recipe b/recipes/bwmagazine2.recipe index 608c046d07..d02efc2861 100644 --- a/recipes/bwmagazine2.recipe +++ b/recipes/bwmagazine2.recipe @@ -1,3 +1,4 @@ +import re from calibre.web.feeds.recipes import BasicNewsRecipe from collections import OrderedDict @@ -39,7 +40,7 @@ class BusinessWeekMagazine(BasicNewsRecipe): title=self.tag_to_string(div.a).strip() url=div.a['href'] soup0 = self.index_to_soup(url) - urlprint=soup0.find('li', attrs={'class':'print tracked'}).a['href'] + urlprint=soup0.find('a', attrs={'href':re.compile('.*printer.*')})['href'] articles.append({'title':title, 'url':urlprint, 'description':'', 'date':''}) @@ -56,7 +57,7 @@ class BusinessWeekMagazine(BasicNewsRecipe): title=self.tag_to_string(div.a).strip() url=div.a['href'] soup0 = self.index_to_soup(url) - urlprint=soup0.find('li', attrs={'class':'print tracked'}).a['href'] + urlprint=soup0.find('a', attrs={'href':re.compile('.*printer.*')})['href'] articles.append({'title':title, 'url':urlprint, 'description':desc, 'date':''}) if articles: From b2b473a05ee49807ed66c9a423b99890339a8afc Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 6 Apr 2013 08:42:32 +0530 Subject: [PATCH 18/31] Update Financial Times UK --- recipes/financial_times_uk.recipe | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/recipes/financial_times_uk.recipe b/recipes/financial_times_uk.recipe index eae77f4f4d..8105a9777f 100644 --- a/recipes/financial_times_uk.recipe +++ b/recipes/financial_times_uk.recipe @@ -110,10 +110,12 @@ class FinancialTimes(BasicNewsRecipe): soup = self.index_to_soup(self.INDEX) #dates= self.tag_to_string(soup.find('div', attrs={'class':'btm-links'}).find('div')) #self.timefmt = ' [%s]'%dates + section_title = 'Untitled' for column in soup.findAll('div', attrs = {'class':'feedBoxes clearfix'}): for section in column. findAll('div', attrs = {'class':'feedBox'}): - section_title=self.tag_to_string(section.find('h4')) + sectiontitle=self.tag_to_string(section.find('h4')) + if '...' not in sectiontitle: section_title=sectiontitle for article in section.ul.findAll('li'): articles = [] title=self.tag_to_string(article.a) From 279013573a3936c3cf7be4b1a0297dc44718421e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 6 Apr 2013 08:51:00 +0530 Subject: [PATCH 19/31] ... --- src/calibre/library/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/library/cli.py b/src/calibre/library/cli.py index 58175f215b..2fdec62ff0 100644 --- a/src/calibre/library/cli.py +++ b/src/calibre/library/cli.py @@ -54,7 +54,7 @@ def get_parser(usage): def get_db(dbpath, options): global do_notify if options.library_path is not None: - dbpath = options.library_path + dbpath = os.path.expanduser(options.library_path) if dbpath is None: raise ValueError('No saved library path, either run the GUI or use the' ' --with-library option') From f491ff67cc3b9f9a9ae73844939990efc0f5c23c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 6 Apr 2013 09:58:43 +0530 Subject: [PATCH 20/31] Enable the Google Images cover download plugin --- src/calibre/customize/builtins.py | 4 ++-- src/calibre/ebooks/metadata/sources/covers.py | 11 ++++++----- src/calibre/ebooks/metadata/sources/google_images.py | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 474617c911..a1cc0b5c64 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -757,9 +757,9 @@ from calibre.ebooks.metadata.sources.isbndb import ISBNDB from calibre.ebooks.metadata.sources.overdrive import OverDrive from calibre.ebooks.metadata.sources.douban import Douban from calibre.ebooks.metadata.sources.ozon import Ozon -# from calibre.ebooks.metadata.sources.google_images import GoogleImages +from calibre.ebooks.metadata.sources.google_images import GoogleImages -plugins += [GoogleBooks, Amazon, Edelweiss, OpenLibrary, ISBNDB, OverDrive, Douban, Ozon] +plugins += [GoogleBooks, GoogleImages, Amazon, Edelweiss, OpenLibrary, ISBNDB, OverDrive, Douban, Ozon] # }}} diff --git a/src/calibre/ebooks/metadata/sources/covers.py b/src/calibre/ebooks/metadata/sources/covers.py index 0fe963e3f7..2df716253b 100644 --- a/src/calibre/ebooks/metadata/sources/covers.py +++ b/src/calibre/ebooks/metadata/sources/covers.py @@ -18,12 +18,13 @@ from calibre.utils.magick.draw import Image, save_cover_data_to class Worker(Thread): - def __init__(self, plugin, abort, title, authors, identifiers, timeout, rq): + def __init__(self, plugin, abort, title, authors, identifiers, timeout, rq, get_best_cover=False): Thread.__init__(self) self.daemon = True self.plugin = plugin self.abort = abort + self.get_best_cover = get_best_cover self.buf = BytesIO() self.log = create_log(self.buf) self.title, self.authors, self.identifiers = (title, authors, @@ -37,7 +38,7 @@ class Worker(Thread): try: if self.plugin.can_get_multiple_covers: self.plugin.download_cover(self.log, self.rq, self.abort, - title=self.title, authors=self.authors, get_best_cover=True, + title=self.title, authors=self.authors, get_best_cover=self.get_best_cover, identifiers=self.identifiers, timeout=self.timeout) else: self.plugin.download_cover(self.log, self.rq, self.abort, @@ -72,7 +73,7 @@ def process_result(log, result): return (plugin, width, height, fmt, data) def run_download(log, results, abort, - title=None, authors=None, identifiers={}, timeout=30): + title=None, authors=None, identifiers={}, timeout=30, get_best_cover=False): ''' Run the cover download, putting results into the queue :param:`results`. @@ -89,7 +90,7 @@ def run_download(log, results, abort, plugins = [p for p in metadata_plugins(['cover']) if p.is_configured()] rq = Queue() - workers = [Worker(p, abort, title, authors, identifiers, timeout, rq) for p + workers = [Worker(p, abort, title, authors, identifiers, timeout, rq, get_best_cover=get_best_cover) for p in plugins] for w in workers: w.start() @@ -163,7 +164,7 @@ def download_cover(log, abort = Event() run_download(log, rq, abort, title=title, authors=authors, - identifiers=identifiers, timeout=timeout) + identifiers=identifiers, timeout=timeout, get_best_cover=True) results = [] diff --git a/src/calibre/ebooks/metadata/sources/google_images.py b/src/calibre/ebooks/metadata/sources/google_images.py index c755fea192..36fe2750ee 100644 --- a/src/calibre/ebooks/metadata/sources/google_images.py +++ b/src/calibre/ebooks/metadata/sources/google_images.py @@ -51,6 +51,7 @@ class GoogleImages(Source): urls = urls[:self.prefs['max_covers']] if get_best_cover: urls = urls[:1] + log('Downloading %d covers'%len(urls)) workers = [Thread(target=self.download_image, args=(url, timeout, log, result_queue)) for url in urls] for w in workers: w.daemon = True From e7cfdba57cf60debbec6c5f8ab75ac042ea63fa8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 6 Apr 2013 11:56:57 +0530 Subject: [PATCH 21/31] Refactor the multiple cover download code in to the base class so it can be reused --- src/calibre/ebooks/metadata/sources/base.py | 34 +++++++++++++++++++ .../ebooks/metadata/sources/google_images.py | 31 +---------------- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/calibre/ebooks/metadata/sources/base.py b/src/calibre/ebooks/metadata/sources/base.py index 41812af8eb..58d5f4aff3 100644 --- a/src/calibre/ebooks/metadata/sources/base.py +++ b/src/calibre/ebooks/metadata/sources/base.py @@ -429,6 +429,40 @@ class Source(Plugin): mi.tags = list(map(fixcase, mi.tags)) mi.isbn = check_isbn(mi.isbn) + def download_multiple_covers(self, title, authors, urls, get_best_cover, timeout, result_queue, abort, log, prefs_name='max_covers'): + if not urls: + log('No images found for, title: %r and authors: %r'%(title, authors)) + return + from threading import Thread + import time + if prefs_name: + urls = urls[:self.prefs[prefs_name]] + if get_best_cover: + urls = urls[:1] + log('Downloading %d covers'%len(urls)) + workers = [Thread(target=self.download_image, args=(u, timeout, log, result_queue)) for u in urls] + for w in workers: + w.daemon = True + w.start() + alive = True + start_time = time.time() + while alive and not abort.is_set() and time.time() - start_time < timeout: + alive = False + for w in workers: + if w.is_alive(): + alive = True + break + abort.wait(0.1) + + def download_image(self, url, timeout, log, result_queue): + try: + ans = self.browser.open_novisit(url, timeout=timeout).read() + result_queue.put((self, ans)) + log('Downloaded cover from: %s'%url) + except Exception: + self.log.exception('Failed to download cover from: %r'%url) + + # }}} # Metadata API {{{ diff --git a/src/calibre/ebooks/metadata/sources/google_images.py b/src/calibre/ebooks/metadata/sources/google_images.py index 36fe2750ee..0563417bac 100644 --- a/src/calibre/ebooks/metadata/sources/google_images.py +++ b/src/calibre/ebooks/metadata/sources/google_images.py @@ -39,40 +39,11 @@ class GoogleImages(Source): title=None, authors=None, identifiers={}, timeout=30, get_best_cover=False): if not title: return - from threading import Thread - import time timeout = max(60, timeout) # Needs at least a minute title = ' '.join(self.get_title_tokens(title)) author = ' '.join(self.get_author_tokens(authors)) urls = self.get_image_urls(title, author, log, abort, timeout) - if not urls: - log('No images found in Google for, title: %r and authors: %r'%(title, author)) - return - urls = urls[:self.prefs['max_covers']] - if get_best_cover: - urls = urls[:1] - log('Downloading %d covers'%len(urls)) - workers = [Thread(target=self.download_image, args=(url, timeout, log, result_queue)) for url in urls] - for w in workers: - w.daemon = True - w.start() - alive = True - start_time = time.time() - while alive and not abort.is_set() and time.time() - start_time < timeout: - alive = False - for w in workers: - if w.is_alive(): - alive = True - break - abort.wait(0.1) - - def download_image(self, url, timeout, log, result_queue): - try: - ans = self.browser.open_novisit(url, timeout=timeout).read() - result_queue.put((self, ans)) - log('Downloaded cover from: %s'%url) - except Exception: - self.log.exception('Failed to download cover from: %r'%url) + self.download_multiple_covers(title, authors, urls, get_best_cover, timeout, result_queue, abort, log) def get_image_urls(self, title, author, log, abort, timeout): from calibre.utils.ipc.simple_worker import fork_job, WorkerError From 20d970c3627a92593eb41a92ac72530647ea43b6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 6 Apr 2013 12:05:54 +0530 Subject: [PATCH 22/31] Metadata download: Add plugin to download book covers from bigbooksearch.com --- src/calibre/customize/builtins.py | 3 +- src/calibre/customize/ui.py | 2 +- src/calibre/ebooks/metadata/sources/base.py | 2 +- .../metadata/sources/big_book_search.py | 58 +++++++++++++++++++ 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 src/calibre/ebooks/metadata/sources/big_book_search.py diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index a1cc0b5c64..bb23eae91a 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -758,8 +758,9 @@ from calibre.ebooks.metadata.sources.overdrive import OverDrive from calibre.ebooks.metadata.sources.douban import Douban from calibre.ebooks.metadata.sources.ozon import Ozon from calibre.ebooks.metadata.sources.google_images import GoogleImages +from calibre.ebooks.metadata.sources.big_book_search import BigBookSearch -plugins += [GoogleBooks, GoogleImages, Amazon, Edelweiss, OpenLibrary, ISBNDB, OverDrive, Douban, Ozon] +plugins += [GoogleBooks, GoogleImages, Amazon, Edelweiss, OpenLibrary, ISBNDB, OverDrive, Douban, Ozon, BigBookSearch] # }}} diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index 06fd2784e4..f6f4df4a78 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -91,7 +91,7 @@ def restore_plugin_state_to_default(plugin_or_name): config['enabled_plugins'] = ep default_disabled_plugins = set([ - 'Overdrive', 'Douban Books', 'OZON.ru', 'Edelweiss', 'Google Images', + 'Overdrive', 'Douban Books', 'OZON.ru', 'Edelweiss', 'Google Images', 'Big Book Search', ]) def is_disabled(plugin): diff --git a/src/calibre/ebooks/metadata/sources/base.py b/src/calibre/ebooks/metadata/sources/base.py index 58d5f4aff3..13069eb86f 100644 --- a/src/calibre/ebooks/metadata/sources/base.py +++ b/src/calibre/ebooks/metadata/sources/base.py @@ -31,7 +31,7 @@ msprefs.defaults['find_first_edition_date'] = False # Google covers are often poor quality (scans/errors) but they have high # resolution, so they trump covers from better sources. So make sure they # are only used if no other covers are found. -msprefs.defaults['cover_priorities'] = {'Google':2, 'Google Images':2} +msprefs.defaults['cover_priorities'] = {'Google':2, 'Google Images':2, 'Big Book Search':2} def create_log(ostream=None): from calibre.utils.logging import ThreadSafeLog, FileStream diff --git a/src/calibre/ebooks/metadata/sources/big_book_search.py b/src/calibre/ebooks/metadata/sources/big_book_search.py new file mode 100644 index 0000000000..789ef1c1aa --- /dev/null +++ b/src/calibre/ebooks/metadata/sources/big_book_search.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8 +from __future__ import (unicode_literals, division, absolute_import, + print_function) + +__license__ = 'GPL v3' +__copyright__ = '2013, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +from calibre.ebooks.metadata.sources.base import Source, Option + +def get_urls(br, tokens): + from urllib import quote_plus + from mechanize import Request + from lxml import html + escaped = [quote_plus(x.encode('utf-8')) for x in tokens if x and x.strip()] + q = b'+'.join(escaped) + url = 'http://bigbooksearch.com/books/'+q + br.open(url).read() + req = Request('http://bigbooksearch.com/query.php?SearchIndex=books&Keywords=%s&ItemPage=1'%q) + req.add_header('X-Requested-With', 'XMLHttpRequest') + req.add_header('Referer', url) + raw = br.open(req).read() + root = html.fromstring(raw.decode('utf-8')) + urls = [i.get('src') for i in root.xpath('//img[@src]')] + return urls + +class BigBookSearch(Source): + + name = 'Big Book Search' + description = _('Downloads multiple book covers from Amazon. Useful to find alternate covers.') + capabilities = frozenset(['cover']) + config_help_message = _('Configure the Big Book Search plugin') + can_get_multiple_covers = True + options = (Option('max_covers', 'number', 5, _('Maximum number of covers to get'), + _('The maximum number of covers to process from the search result')), + ) + supports_gzip_transfer_encoding = True + + def download_cover(self, log, result_queue, abort, + title=None, authors=None, identifiers={}, timeout=30, get_best_cover=False): + if not title: + return + br = self.browser + tokens = tuple(self.get_title_tokens(title)) + tuple(self.get_author_tokens(authors)) + urls = get_urls(br, tokens) + self.download_multiple_covers(title, authors, urls, get_best_cover, timeout, result_queue, abort, log) + +def test(): + from calibre import browser + import pprint + br = browser() + urls = get_urls(br, ['consider', 'phlebas', 'banks']) + pprint.pprint(urls) + +if __name__ == '__main__': + test() + From d76bf663efe911a8f9f5ee99309e1dded51890c0 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 6 Apr 2013 18:38:12 +0530 Subject: [PATCH 23/31] Fix #1021270 (Private bug) --- src/calibre/ebooks/rtf2xml/border_parse.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/calibre/ebooks/rtf2xml/border_parse.py b/src/calibre/ebooks/rtf2xml/border_parse.py index 910d877135..f6cb2ee507 100755 --- a/src/calibre/ebooks/rtf2xml/border_parse.py +++ b/src/calibre/ebooks/rtf2xml/border_parse.py @@ -180,5 +180,6 @@ class BorderParse: elif 'single' in border_style_list: new_border_dict[att] = 'single' else: - new_border_dict[att] = border_style_list[0] + if border_style_list: + new_border_dict[att] = border_style_list[0] return new_border_dict From 604068944757447774362f8304c6bfcc6843a6b3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 7 Apr 2013 00:33:09 +0530 Subject: [PATCH 24/31] ... --- src/calibre/ebooks/metadata/sources/edelweiss.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/calibre/ebooks/metadata/sources/edelweiss.py b/src/calibre/ebooks/metadata/sources/edelweiss.py index 53ae6c6ee3..27fd296503 100644 --- a/src/calibre/ebooks/metadata/sources/edelweiss.py +++ b/src/calibre/ebooks/metadata/sources/edelweiss.py @@ -106,6 +106,8 @@ class Worker(Thread): # {{{ parts = pub.partition(':')[0::2] pub = parts[1] or parts[0] try: + if ', Ship Date:' in pub: + pub = pub.partition(', Ship Date:')[0] q = parse_only_date(pub, assume_utc=True) if q.year != UNDEFINED_DATE: mi.pubdate = q From acb10eea1ed62c93d4efca2203fb14123c3767df Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 7 Apr 2013 09:11:05 +0530 Subject: [PATCH 25/31] Update New Yorker --- recipes/new_yorker.recipe | 322 ++++++++++++++++++++++++++++++-------- 1 file changed, 261 insertions(+), 61 deletions(-) diff --git a/recipes/new_yorker.recipe b/recipes/new_yorker.recipe index 2730b45d6d..93a231792c 100644 --- a/recipes/new_yorker.recipe +++ b/recipes/new_yorker.recipe @@ -1,64 +1,44 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- __license__ = 'GPL v3' -__copyright__ = '2008-2013, Darko Miletic ' -''' -newyorker.com -''' +''' +www.canada.com +''' +import re from calibre.web.feeds.news import BasicNewsRecipe +from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup + class NewYorker(BasicNewsRecipe): - title = 'The New Yorker' - __author__ = 'Darko Miletic' - description = 'The best of US journalism' - oldest_article = 15 - language = 'en' - max_articles_per_feed = 100 - no_stylesheets = True - use_embedded_content = False - publisher = 'Conde Nast Publications' - category = 'news, politics, USA' - encoding = 'cp1252' - publication_type = 'magazine' - masthead_url = 'http://www.newyorker.com/css/i/hed/logo.gif' - extra_css = """ - body {font-family: "Times New Roman",Times,serif} - .articleauthor{color: #9F9F9F; - font-family: Arial, sans-serif; - font-size: small; - text-transform: uppercase} - .rubric,.dd,h6#credit{color: #CD0021; - font-family: Arial, sans-serif; - font-size: small; - text-transform: uppercase} - .descender:first-letter{display: inline; font-size: xx-large; font-weight: bold} - .dd,h6#credit{color: gray} - .c{display: block} - .caption,h2#articleintro{font-style: italic} - .caption{font-size: small} - """ - conversion_options = { - 'comment' : description - , 'tags' : category - , 'publisher' : publisher - , 'language' : language - } - keep_only_tags = [dict(name='div', attrs={'id':'pagebody'})] - remove_tags = [ - dict(name=['meta','iframe','base','link','embed','object']) - ,dict(attrs={'class':['utils','socialUtils','articleRailLinks','icons','social-utils-top','entry-keywords','entry-categories','utilsPrintEmail'] }) - ,dict(attrs={'id':['show-header','show-footer'] }) - ] - remove_tags_after = dict(attrs={'class':'entry-content'}) - remove_attributes = ['lang'] - feeds = [(u'The New Yorker', u'http://www.newyorker.com/services/mrss/feeds/everything.xml')] + title = u'New Yorker Magazine' + newyorker_prefix = 'http://m.newyorker.com' + description = u'Content from the New Yorker website' + fp_tag = 'CAN_TC' - def print_version(self, url): - return url + '?printable=true¤tPage=all' + masthead_url = 'http://www.newyorker.com/images/elements/print/newyorker_printlogo.gif' - def image_url_processor(self, baseurl, url): - return url.strip() + compress_news_images = True + compress_news_images_auto_size = 8 + scale_news_images_to_device = False + scale_news_images = (768, 1024) + + url_list = [] + language = 'en' + __author__ = 'Nick Redding' + no_stylesheets = True + timefmt = ' [%b %d]' + encoding = 'utf-8' + extra_css = ''' + .byline { font-size:xx-small; font-weight: bold;} + h3 { margin-bottom: 6px; } + .caption { font-size: xx-small; font-style: italic; font-weight: normal; } + ''' + keep_only_tags = [dict(name='div', attrs={'id':re.compile('pagebody')})] + + remove_tags = [{'class':'socialUtils'},{'class':'entry-keywords'}] def get_cover_url(self): cover_url = "http://www.newyorker.com/images/covers/1925/1925_02_21_p233.jpg" @@ -68,13 +48,233 @@ class NewYorker(BasicNewsRecipe): cover_url = 'http://www.newyorker.com' + cover_item.div.img['src'].strip() return cover_url - def preprocess_html(self, soup): - for item in soup.findAll(style=True): - del item['style'] - auth = soup.find(attrs={'id':'articleauthor'}) - if auth: - alink = auth.find('a') - if alink and alink.string is not None: - txt = alink.string - alink.replaceWith(txt) + def fixChars(self,string): + # Replace lsquo (\x91) + fixed = re.sub("\x91","‘",string) + # Replace rsquo (\x92) + fixed = re.sub("\x92","’",fixed) + # Replace ldquo (\x93) + fixed = re.sub("\x93","“",fixed) + # Replace rdquo (\x94) + fixed = re.sub("\x94","”",fixed) + # Replace ndash (\x96) + fixed = re.sub("\x96","–",fixed) + # Replace mdash (\x97) + fixed = re.sub("\x97","—",fixed) + fixed = re.sub("’","’",fixed) + return fixed + + def massageNCXText(self, description): + # Kindle TOC descriptions won't render certain characters + if description: + massaged = unicode(BeautifulStoneSoup(description, convertEntities=BeautifulStoneSoup.HTML_ENTITIES)) + # Replace '&' with '&' + massaged = re.sub("&","&", massaged) + return self.fixChars(massaged) + else: + return description + + def populate_article_metadata(self, article, soup, first): + if first: + picdiv = soup.find('body').find('img') + if picdiv is not None: + self.add_toc_thumbnail(article,re.sub(r'links\\link\d+\\','',picdiv['src'])) + xtitle = article.text_summary.strip() + if len(xtitle) == 0: + desc = soup.find('meta',attrs={'property':'og:description'}) + if desc is not None: + article.summary = article.text_summary = desc['content'] + shortparagraph = "" +## try: + if len(article.text_summary.strip()) == 0: + articlebodies = soup.findAll('div',attrs={'class':'entry-content'}) + if articlebodies: + for articlebody in articlebodies: + if articlebody: + paras = articlebody.findAll('p') + for p in paras: + refparagraph = self.massageNCXText(self.tag_to_string(p,use_alt=False)).strip() + #account for blank paragraphs and short paragraphs by appending them to longer ones + if len(refparagraph) > 0: + if len(refparagraph) > 70: #approximately one line of text + newpara = shortparagraph + refparagraph + article.summary = article.text_summary = newpara.strip() + return + else: + shortparagraph = refparagraph + " " + if shortparagraph.strip().find(" ") == -1 and not shortparagraph.strip().endswith(":"): + shortparagraph = shortparagraph + "- " + else: + article.summary = article.text_summary = self.massageNCXText(article.text_summary) +## except: +## self.log("Error creating article descriptions") +## return + + + def strip_anchors(self,soup): + paras = soup.findAll(True) + for para in paras: + aTags = para.findAll('a') + for a in aTags: + if a.img is None: + a.replaceWith(a.renderContents().decode('cp1252','replace')) return soup + + def preprocess_html(self,soup): + dateline = soup.find('div','published') + byline = soup.find('div','byline') + title = soup.find('h1','entry-title') + if title is None: + return self.strip_anchors(soup) + if byline is None: + title.append(dateline) + return self.strip_anchors(soup) + byline.append(dateline) + return self.strip_anchors(soup) + + def load_global_nav(self,soup): + seclist = [] + ul = soup.find('ul',attrs={'id':re.compile('global-nav-menu')}) + if ul is not None: + for li in ul.findAll('li'): + if li.a is not None: + securl = li.a['href'] + if securl != '/' and securl != '/magazine' and securl.startswith('/'): + seclist.append((self.tag_to_string(li.a),self.newyorker_prefix+securl)) + return seclist + + def exclude_url(self,url): + if url in self.url_list: + return True + if not url.endswith('html'): + return True + if 'goings-on-about-town-app' in url: + return True + if 'something-to-be-thankful-for' in url: + return True + if '/shouts/' in url: + return True + if 'out-loud' in url: + return True + if '/rss/' in url: + return True + if '/video-' in url: + return True + self.url_list.append(url) + return False + + + def load_index_page(self,soup): + article_list = [] + for div in soup.findAll('div',attrs={'class':re.compile('^rotator')}): + h2 = div.h2 + if h2 is not None: + a = h2.a + if a is not None: + url = a['href'] + if not self.exclude_url(url): + if url.startswith('/'): + url = self.newyorker_prefix+url + byline = h2.span + if byline is not None: + author = self.tag_to_string(byline) + if author.startswith('by '): + author.replace('by ','') + byline.extract() + else: + author = '' + if h2.br is not None: + h2.br.replaceWith(' ') + title = self.tag_to_string(h2) + desc = div.find(attrs={'class':['rotator-ad-body','feature-blurb-text']}) + if desc is not None: + description = self.tag_to_string(desc) + else: + description = '' + article_list.append(dict(title=title,url=url,date='',description=description,author=author,content='')) + ul = div.find('ul','feature-blurb-links') + if ul is not None: + for li in ul.findAll('li'): + a = li.a + if a is not None: + url = a['href'] + if not self.exclude_url(url): + if url.startswith('/'): + url = self.newyorker_prefix+url + if a.br is not None: + a.br.replaceWith(' ') + title = '>>'+self.tag_to_string(a) + article_list.append(dict(title=title,url=url,date='',description='',author='',content='')) + for h3 in soup.findAll('h3','header'): + a = h3.a + if a is not None: + url = a['href'] + if not self.exclude_url(url): + if url.startswith('/'): + url = self.newyorker_prefix+url + byline = h3.span + if byline is not None: + author = self.tag_to_string(byline) + if author.startswith('by '): + author = author.replace('by ','') + byline.extract() + else: + author = '' + if h3.br is not None: + h3.br.replaceWith(' ') + title = self.tag_to_string(h3).strip() + article_list.append(dict(title=title,url=url,date='',description='',author=author,content='')) + return article_list + + def load_global_section(self,securl): + article_list = [] + try: + soup = self.index_to_soup(securl) + except: + return article_list + if '/blogs/' not in securl: + return self.load_index_page(soup) + for div in soup.findAll('div',attrs={'id':re.compile('^entry')}): + h3 = div.h3 + if h3 is not None: + a = h3.a + if a is not None: + url = a['href'] + if not self.exclude_url(url): + if url.startswith('/'): + url = self.newyorker_prefix+url + if h3.br is not None: + h3.br.replaceWith(' ') + title = self.tag_to_string(h3) + article_list.append(dict(title=title,url=url,date='',description='',author='',content='')) + return article_list + + def filter_ans(self, ans) : + total_article_count = 0 + idx = 0 + idx_max = len(ans)-1 + while idx <= idx_max: + if True: #self.verbose + self.log("Section %s: %d articles" % (ans[idx][0], len(ans[idx][1])) ) + for article in ans[idx][1]: + total_article_count += 1 + if True: #self.verbose + self.log("\t%-40.40s... \t%-60.60s..." % (article['title'].encode('cp1252','replace'), + article['url'].replace('http://m.newyorker.com','').encode('cp1252','replace'))) + idx = idx+1 + self.log( "Queued %d articles" % total_article_count ) + return ans + + + def parse_index(self): + ans = [] + try: + soup = self.index_to_soup(self.newyorker_prefix) + except: + return ans + seclist = self.load_global_nav(soup) + ans.append(('Front Page',self.load_index_page(soup))) + for (sectitle,securl) in seclist: + ans.append((sectitle,self.load_global_section(securl))) + return self.filter_ans(ans) + From 6d1fba3a0d94de46d06d4f483b74afc447b8b25d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 7 Apr 2013 09:19:06 +0530 Subject: [PATCH 26/31] Universe Today by seird --- recipes/universe_today.recipe | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 recipes/universe_today.recipe diff --git a/recipes/universe_today.recipe b/recipes/universe_today.recipe new file mode 100644 index 0000000000..65aefc231f --- /dev/null +++ b/recipes/universe_today.recipe @@ -0,0 +1,17 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class UniverseToday(BasicNewsRecipe): + title = u'Universe Today' + language = 'en' + description = u'Space and astronomy news.' + __author__ = 'seird' + publisher = u'universetoday.com' + category = 'science, astronomy, news, rss' + oldest_article = 7 + max_articles_per_feed = 40 + auto_cleanup = True + no_stylesheets = True + use_embedded_content = False + remove_empty_feeds = True + + feeds = [(u'Universe Today', u'http://feeds.feedburner.com/universetoday/pYdq')] From 9c3591a4679865104cc98b25c25567875ef41da5 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 7 Apr 2013 11:11:32 +0530 Subject: [PATCH 27/31] When extracting zip files do not allow maliciously created zip files to overwrite other files on the system --- src/calibre/utils/localunzip.py | 8 +++++++- src/calibre/utils/zipfile.py | 11 +++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/calibre/utils/localunzip.py b/src/calibre/utils/localunzip.py index 4fd3006076..289b9d46c0 100644 --- a/src/calibre/utils/localunzip.py +++ b/src/calibre/utils/localunzip.py @@ -174,7 +174,13 @@ def _extractall(f, path=None, file_info=None): has_data_descriptors = header.flags & (1 << 3) seekval = header.compressed_size + (16 if has_data_descriptors else 0) found = True - parts = header.filename.split('/') + # Sanitize path changing absolute to relative paths and removing .. and + # . + fname = header.filename.replace(os.sep, '/') + fname = os.path.splitdrive(fname)[1] + parts = [x for x in fname.split('/') if x not in {'', os.path.pardir, os.path.curdir}] + if not parts: + continue if header.uncompressed_size == 0: # Directory f.seek(f.tell()+seekval) diff --git a/src/calibre/utils/zipfile.py b/src/calibre/utils/zipfile.py index 95e556418c..566823b639 100644 --- a/src/calibre/utils/zipfile.py +++ b/src/calibre/utils/zipfile.py @@ -1099,10 +1099,13 @@ class ZipFile: base_target = targetpath # Added by Kovid - # don't include leading "/" from file name if present - fname = member.filename - if fname.startswith('/'): - fname = fname[1:] + # Sanitize path, changing absolute paths to relative paths + # and removing .. and . (changed by Kovid) + fname = member.filename.replace(os.sep, '/') + fname = os.path.splitdrive(fname)[1] + fname = '/'.join(x for x in fname.split('/') if x not in {'', os.path.curdir, os.path.pardir}) + if not fname: + raise BadZipfile('The member %r has an invalid name'%member.filename) targetpath = os.path.normpath(os.path.join(base_target, fname)) From f539b863dd0f086920d4ab08ebb21662367a4d3c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 7 Apr 2013 11:54:19 +0530 Subject: [PATCH 28/31] Amazon metadata download: When downloading from amazon.co.jp handle the 'Black curtain redirect' for adult titles. Fixes #1165628 (Amazon.co.jp : Cover and info fail collecting) --- src/calibre/ebooks/metadata/sources/amazon.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/calibre/ebooks/metadata/sources/amazon.py b/src/calibre/ebooks/metadata/sources/amazon.py index 3fefe2d886..fe39c3cd16 100644 --- a/src/calibre/ebooks/metadata/sources/amazon.py +++ b/src/calibre/ebooks/metadata/sources/amazon.py @@ -132,7 +132,7 @@ class Worker(Thread): # Get details {{{ text()="Détails sur le produit" or \ text()="Detalles del producto" or \ text()="Detalhes do produto" or \ - text()="登録情報"]/../div[@class="content"] + starts-with(text(), "登録情報")]/../div[@class="content"] ''' # Editor: is for Spanish self.publisher_xpath = ''' @@ -235,6 +235,12 @@ class Worker(Thread): # Get details {{{ msg = 'Failed to parse amazon details page: %r'%self.url self.log.exception(msg) return + if self.domain == 'jp': + for a in root.xpath('//a[@href]'): + if 'black-curtain-redirect.html' in a.get('href'): + self.url = 'http://amazon.co.jp'+a.get('href') + self.log('Black curtain redirect found, following') + return self.get_details() errmsg = root.xpath('//*[@id="errorMessage"]') if errmsg: @@ -252,8 +258,8 @@ class Worker(Thread): # Get details {{{ self.log.exception('Error parsing asin for url: %r'%self.url) asin = None if self.testing: - import tempfile - with tempfile.NamedTemporaryFile(prefix=asin + '_', + import tempfile, uuid + with tempfile.NamedTemporaryFile(prefix=(asin or str(uuid.uuid4()))+ '_', suffix='.html', delete=False) as f: f.write(raw) print ('Downloaded html for', asin, 'saved in', f.name) @@ -499,7 +505,7 @@ class Worker(Thread): # Get details {{{ def parse_language(self, pd): for x in reversed(pd.xpath(self.language_xpath)): if x.tail: - raw = x.tail.strip() + raw = x.tail.strip().partition(',')[0].strip() ans = self.lang_map.get(raw, None) if ans: return ans @@ -1004,6 +1010,11 @@ if __name__ == '__main__': # tests {{{ ] # }}} jp_tests = [ # {{{ + ( # Adult filtering test + {'identifiers':{'isbn':'4799500066'}}, + [title_test(u'Bitch Trap'),] + ), + ( # isbn -> title, authors {'identifiers':{'isbn': '9784101302720' }}, [title_test(u'精霊の守り人', From 78924144aaf27969436b8f088f90ff0822307aee Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 7 Apr 2013 13:24:21 +0530 Subject: [PATCH 29/31] Economia by Manish Bhattarai --- recipes/economia.recipe | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 recipes/economia.recipe diff --git a/recipes/economia.recipe b/recipes/economia.recipe new file mode 100644 index 0000000000..249125b76f --- /dev/null +++ b/recipes/economia.recipe @@ -0,0 +1,17 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1314326622(BasicNewsRecipe): + title = u'Economia' + __author__ = 'Manish Bhattarai' + description = 'Economia - Intelligence & Insight for ICAEW Members' + language = 'en_GB' + oldest_article = 7 + max_articles_per_feed = 25 + masthead_url = 'http://economia.icaew.com/~/media/Images/Design%20Images/Economia_Red_website.ashx' + cover_url = 'http://economia.icaew.com/~/media/Images/Design%20Images/Economia_Red_website.ashx' + no_stylesheets = True + remove_empty_feeds = True + remove_tags_before = dict(id='content') + remove_tags_after = dict(id='stars-wrapper') + remove_tags = [dict(attrs={'class':['floatR', 'sharethis', 'rating clearfix']})] + feeds = [(u'News', u'http://feedity.com/icaew-com/VlNTVFRa.rss'),(u'Business', u'http://feedity.com/icaew-com/VlNTVFtS.rss'),(u'People', u'http://feedity.com/icaew-com/VlNTVFtX.rss'),(u'Opinion', u'http://feedity.com/icaew-com/VlNTVFtW.rss'),(u'Finance', u'http://feedity.com/icaew-com/VlNTVFtV.rss')] From 6bd12a445002c5ea6c65ccccd236e50698ae2b9c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 7 Apr 2013 16:39:01 +0530 Subject: [PATCH 30/31] Update The Onion --- recipes/theonion.recipe | 46 +++++++++-------------------------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/recipes/theonion.recipe b/recipes/theonion.recipe index b0eacbb5e0..d177e0978d 100644 --- a/recipes/theonion.recipe +++ b/recipes/theonion.recipe @@ -36,47 +36,21 @@ class TheOnion(BasicNewsRecipe): , 'publisher': publisher , 'language' : language } - - keep_only_tags = [ - dict(name='h2', attrs={'class':['section_title','title']}) - ,dict(attrs={'class':['main_image','meta','article_photo_lead','article_body']}) - ,dict(attrs={'id':['entries']}) - ] - remove_attributes=['lang','rel'] - remove_tags_after = dict(attrs={'class':['article_body','feature_content']}) + keep_only_tags = [dict(name='article', attrs={'class':'full-article'})] remove_tags = [ - dict(name=['object','link','iframe','base','meta']) - ,dict(name='div', attrs={'class':['toolbar_side','graphical_feature','toolbar_bottom']}) - ,dict(name='div', attrs={'id':['recent_slider','sidebar','pagination','related_media']}) - ] - + dict(name=['nav', 'aside', 'section', 'meta']), + {'attrs':{'class':lambda x: x and ('share-tools' in x or 'ad-zone' in x)}}, + ] feeds = [ (u'Daily' , u'http://feeds.theonion.com/theonion/daily' ) ,(u'Sports' , u'http://feeds.theonion.com/theonion/sports' ) ] - def get_article_url(self, article): - artl = BasicNewsRecipe.get_article_url(self, article) - if artl.startswith('http://www.theonion.com/audio/'): - artl = None - return artl - - def preprocess_html(self, soup): - for item in soup.findAll(style=True): - del item['style'] - for item in soup.findAll('a'): - limg = item.find('img') - if item.string is not None: - str = item.string - item.replaceWith(str) - else: - if limg: - item.name = 'div' - item.attrs = [] - if not limg.has_key('alt'): - limg['alt'] = 'image' - else: - str = self.tag_to_string(item) - item.replaceWith(str) + def preprocess_html(self, soup, *args): + for img in soup.findAll('img', attrs={'data-src':True}): + if img['data-src']: + img['src'] = img['data-src'] return soup + + From f082a072e974ad99fd35e43b4ca7db5edd817e8f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 7 Apr 2013 16:45:29 +0530 Subject: [PATCH 31/31] Fix #1165686 (On the Edit TOC display, both indent and unindent show "unindent" when hovering) --- src/calibre/gui2/toc/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/toc/main.py b/src/calibre/gui2/toc/main.py index 7cb4f9b462..90d9a8f4a8 100644 --- a/src/calibre/gui2/toc/main.py +++ b/src/calibre/gui2/toc/main.py @@ -559,11 +559,11 @@ class TOCView(QWidget): # {{{ b.setToolTip(_('Remove all selected entries')) b.clicked.connect(self.del_items) - self.left_button = b = QToolButton(self) + self.right_button = b = QToolButton(self) b.setIcon(QIcon(I('forward.png'))) b.setIconSize(QSize(ICON_SIZE, ICON_SIZE)) l.addWidget(b, 4, 3) - b.setToolTip(_('Unindent the current entry [Ctrl+Left]')) + b.setToolTip(_('Indent the current entry [Ctrl+Right]')) b.clicked.connect(self.tocw.move_right) self.down_button = b = QToolButton(self)