diff --git a/recipes/android_com_pl.recipe b/recipes/android_com_pl.recipe index a44d5e560a..c7a4a97d3c 100644 --- a/recipes/android_com_pl.recipe +++ b/recipes/android_com_pl.recipe @@ -6,6 +6,7 @@ class Android_com_pl(BasicNewsRecipe): description = 'Android.com.pl - biggest polish Android site' category = 'Android, mobile' language = 'pl' + use_embedded_content=True cover_url =u'http://upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Android_robot.svg/220px-Android_robot.svg.png' oldest_article = 8 max_articles_per_feed = 100 diff --git a/recipes/b92.recipe b/recipes/b92.recipe index 7181419682..c4520b37fc 100644 --- a/recipes/b92.recipe +++ b/recipes/b92.recipe @@ -1,6 +1,6 @@ __license__ = 'GPL v3' -__copyright__ = '2008-2011, Darko Miletic ' +__copyright__ = '2008-2012, Darko Miletic ' ''' b92.net ''' @@ -20,13 +20,13 @@ class B92(BasicNewsRecipe): encoding = 'cp1250' language = 'sr' publication_type = 'newsportal' - masthead_url = 'http://www.b92.net/images/fp/logo.gif' + masthead_url = 'http://b92s.net/v4/img/new-logo.png' extra_css = """ - @font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)} @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: Arial,Helvetica,sans1,sans-serif} - .articledescription{font-family: serif1, serif} .article-info2,.article-info1{text-transform: uppercase; font-size: small} + img{display: block} + .sms{font-weight: bold} """ conversion_options = { @@ -37,11 +37,17 @@ class B92(BasicNewsRecipe): , 'linearize_tables' : True } - preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] + preprocess_regexps = [ + (re.compile(u'\u0110'), lambda match: u'\u00D0'), + (re.compile(r'', re.DOTALL|re.IGNORECASE), lambda match: 'something') + ] keep_only_tags = [dict(attrs={'class':['article-info1','article-text']})] - remove_attributes = ['width','height','align','hspace','vspace','border'] - remove_tags = [dict(name=['embed','link','base','meta'])] + remove_attributes = ['width','height','align','hspace','vspace','border','lang','xmlns:fb'] + remove_tags = [ + dict(name=['embed','link','base','meta','iframe']) + ,dict(attrs={'id':'social'}) + ] feeds = [ (u'Vesti' , u'http://www.b92.net/info/rss/vesti.xml' ) diff --git a/recipes/cgm_pl.recipe b/recipes/cgm_pl.recipe index 673a9f940b..4ab4402c3a 100644 --- a/recipes/cgm_pl.recipe +++ b/recipes/cgm_pl.recipe @@ -1,4 +1,5 @@ from calibre.web.feeds.news import BasicNewsRecipe +from calibre.ebooks.BeautifulSoup import BeautifulSoup class CGM(BasicNewsRecipe): title = u'CGM' @@ -17,9 +18,9 @@ class CGM(BasicNewsRecipe): remove_tags_before=dict(id='mainContent') remove_tags_after=dict(name='div', attrs={'class':'fbContainer'}) remove_tags=[dict(name='div', attrs={'class':'fbContainer'}), - dict(name='p', attrs={'class':['tagCloud', 'galleryAuthor']}), - dict(id=['movieShare', 'container'])] - feeds = [(u'Informacje', u'http://www.cgm.pl/rss.xml'), (u'Polecamy', u'http://www.cgm.pl/rss,4,news.xml'), + dict(name='p', attrs={'class':['tagCloud', 'galleryAuthor']}), + dict(id=['movieShare', 'container'])] + feeds = [(u'Informacje', u'http://www.cgm.pl/rss.xml'), (u'Polecamy', u'http://www.cgm.pl/rss,4,news.xml'), (u'Recenzje', u'http://www.cgm.pl/rss,1,news.xml')] @@ -33,10 +34,12 @@ class CGM(BasicNewsRecipe): img='http://www.cgm.pl'+img[img.find('url(')+4:img.find(')')] gallery.contents[1].name='img' gallery.contents[1]['src']=img + pos = len(gallery.contents) + gallery.insert(pos, BeautifulSoup('
')) for item in soup.findAll(style=True): del item['style'] ad=soup.findAll('a') for r in ad: - if 'www.hustla.pl' in r['href'] or 'www.ebilet.pl' in r['href']: + if 'www.hustla.pl' in r['href'] or 'www.ebilet.pl' in r['href']: r.extract() - return soup \ No newline at end of file + return soup diff --git a/recipes/elektroda_pl.recipe b/recipes/elektroda_pl.recipe index c2123cb8cf..55858020ad 100644 --- a/recipes/elektroda_pl.recipe +++ b/recipes/elektroda_pl.recipe @@ -1,4 +1,5 @@ from calibre.web.feeds.news import BasicNewsRecipe +from calibre.ebooks.BeautifulSoup import BeautifulSoup class Elektroda(BasicNewsRecipe): title = u'Elektroda' @@ -13,3 +14,18 @@ class Elektroda(BasicNewsRecipe): remove_tags_after=dict(name='td', attrs={'class':'spaceRow'}) remove_tags=[dict(name='a', attrs={'href':'#top'})] feeds = [(u'Elektroda', u'http://www.elektroda.pl/rtvforum/rss.php')] + + + def preprocess_html(self, soup): + tag=soup.find('span', attrs={'class':'postbody'}) + if tag: + pos = len(tag.contents) + tag.insert(pos, BeautifulSoup('
')) + return soup + + def parse_feeds (self): + feeds = BasicNewsRecipe.parse_feeds(self) + for feed in feeds: + for article in feed.articles[:]: + article.title=article.title[article.title.find("::")+3:] + return feeds diff --git a/recipes/film_web.recipe b/recipes/film_web.recipe index 0671deec6c..877d4472bc 100644 --- a/recipes/film_web.recipe +++ b/recipes/film_web.recipe @@ -13,7 +13,7 @@ class Filmweb_pl(BasicNewsRecipe): remove_empty_feeds=True extra_css = '.hdrBig {font-size:22px;} ul {list-style-type:none; padding: 0; margin: 0;}' remove_tags= [dict(name='div', attrs={'class':['recommendOthers']}), dict(name='ul', attrs={'class':'fontSizeSet'})] - keep_only_tags= [dict(name='h1', attrs={'class':'hdrBig'}), dict(name='div', attrs={'class':['newsInfo', 'reviewContent fontSizeCont description']})] + keep_only_tags= [dict(name='h1', attrs={'class':['hdrBig', 'hdrEntity']}), dict(name='div', attrs={'class':['newsInfo', 'newsInfoSmall', 'reviewContent description']})] feeds = [(u'Wszystkie newsy', u'http://www.filmweb.pl/feed/news/latest'), (u'News / Filmy w produkcji', 'http://www.filmweb.pl/feed/news/category/filminproduction'), (u'News / Festiwale, nagrody i przeglądy', u'http://www.filmweb.pl/feed/news/category/festival'), diff --git a/recipes/gram_pl.recipe b/recipes/gram_pl.recipe index c8655dc9cd..07927796c0 100644 --- a/recipes/gram_pl.recipe +++ b/recipes/gram_pl.recipe @@ -9,12 +9,12 @@ class Gram_pl(BasicNewsRecipe): oldest_article = 8 max_articles_per_feed = 100 no_stylesheets= True - extra_css = 'h2 {font-style: italic; font-size:20px;}' + extra_css = 'h2 {font-style: italic; font-size:20px;} .picbox div {float: left;}' cover_url=u'http://www.gram.pl/www/01/img/grampl_zima.png' remove_tags= [dict(name='p', attrs={'class':['extraText', 'must-log-in']}), dict(attrs={'class':['el', 'headline', 'post-info']}), dict(name='div', attrs={'class':['twojaOcena', 'comment-body', 'comment-author vcard', 'comment-meta commentmetadata', 'tw_button']}), dict(id=['igit_rpwt_css', 'comments', 'reply-title', 'igit_title'])] keep_only_tags= [dict(name='div', attrs={'class':['main', 'arkh-postmetadataheader', 'arkh-postcontent', 'post', 'content', 'news_header', 'news_subheader', 'news_text']}), dict(attrs={'class':['contentheading', 'contentpaneopen']})] - feeds = [(u'gram.pl - informacje', u'http://www.gram.pl/feed_news.asp'), - (u'gram.pl - publikacje', u'http://www.gram.pl/feed_news.asp?type=articles')] + feeds = [(u'Informacje', u'http://www.gram.pl/feed_news.asp'), + (u'Publikacje', u'http://www.gram.pl/feed_news.asp?type=articles')] def parse_feeds (self): feeds = BasicNewsRecipe.parse_feeds(self) @@ -23,3 +23,33 @@ class Gram_pl(BasicNewsRecipe): if 'REKLAMA SKLEP' in article.title.upper() or u'ARTYKUŁ:' in article.title.upper(): feed.articles.remove(article) return feeds + + def append_page(self, soup, appendtag): + nexturl = appendtag.find('a', attrs={'class':'cpn'}) + while nexturl: + soup2 = self.index_to_soup('http://www.gram.pl'+ nexturl['href']) + r=appendtag.find(id='pgbox') + if r: + r.extract() + pagetext = soup2.find(attrs={'class':'main'}) + r=pagetext.find('h1') + if r: + r.extract() + r=pagetext.find('h2') + if r: + r.extract() + for r in pagetext.findAll('script'): + r.extract() + pos = len(appendtag.contents) + appendtag.insert(pos, pagetext) + nexturl = appendtag.find('a', attrs={'class':'cpn'}) + r=appendtag.find(id='pgbox') + if r: + r.extract() + + def preprocess_html(self, soup): + self.append_page(soup, soup.body) + tag=soup.findAll(name='div', attrs={'class':'picbox'}) + for t in tag: + t['style']='float: left;' + return soup \ No newline at end of file diff --git a/recipes/icons/b92.png b/recipes/icons/b92.png index 864c2e4e8e..bd02fd88ae 100644 Binary files a/recipes/icons/b92.png and b/recipes/icons/b92.png differ diff --git a/recipes/naczytniki.recipe b/recipes/naczytniki.recipe index 2ae6bc391e..3d1a8b6095 100644 --- a/recipes/naczytniki.recipe +++ b/recipes/naczytniki.recipe @@ -7,12 +7,12 @@ class naczytniki(BasicNewsRecipe): cover_url = 'http://naczytniki.pl/wp-content/uploads/2010/08/logo_nc28.png' language = 'pl' description ='everything about e-readers' - category='readers' + category='e-readers' no_stylesheets=True + use_embedded_content=False oldest_article = 7 max_articles_per_feed = 100 preprocess_regexps = [(re.compile(ur'


Zobacz także:

.*?', re.DOTALL), lambda match: '') ] - remove_tags_after= dict(name='div', attrs={'class':'sociable'}) keep_only_tags=[dict(name='div', attrs={'class':'post'})] remove_tags=[dict(name='span', attrs={'class':'comments'}), dict(name='div', attrs={'class':'sociable'})] - feeds = [(u'Wpisy', u'http://naczytniki.pl/?feed=rss2')] + feeds = [(u'Wpisy', u'http://naczytniki.pl/?feed=rss2')] \ No newline at end of file diff --git a/recipes/overclock_pl.recipe b/recipes/overclock_pl.recipe index d7f4c8093d..953dee67eb 100644 --- a/recipes/overclock_pl.recipe +++ b/recipes/overclock_pl.recipe @@ -17,21 +17,8 @@ class Overclock_pl(BasicNewsRecipe): remove_tags=[dict(name='span', attrs={'class':'info'}), dict(attrs={'class':'shareit'})] feeds = [(u'Aktualno\u015bci', u'http://www.overclock.pl/rss.news.xml'), (u'Testy i recenzje', u'http://www.overclock.pl/rss.articles.xml')] - - def append_page(self, soup, appendtag): - tag=soup.find(id='navigation') - if tag: - nexturl=tag.findAll('option') - tag.extract() - for nextpage in nexturl[2:]: - soup2 = self.index_to_soup(nextpage['value']) - pagetext = soup2.find(id='content') - pos = len(appendtag.contents) - appendtag.insert(pos, pagetext) - rem=appendtag.find(attrs={'alt':'Pierwsza'}) - if rem: - rem.parent.extract() - - def preprocess_html(self, soup): - self.append_page(soup, soup.body) - return soup \ No newline at end of file + def print_version(self, url): + if 'articles/show' in url: + return url.replace('show', 'showall') + else: + return url \ No newline at end of file diff --git a/recipes/palmtop_pl.recipe b/recipes/palmtop_pl.recipe index ace772e7e7..87da5d0d1c 100644 --- a/recipes/palmtop_pl.recipe +++ b/recipes/palmtop_pl.recipe @@ -10,5 +10,7 @@ class palmtop_pl(BasicNewsRecipe): oldest_article = 7 max_articles_per_feed = 100 no_stylesheets = True - + use_embedded_content=True + #remove_tags_before=dict(name='h2') + #remove_tags_after=dict(attrs={'class':'entry clearfix'}) feeds = [(u'Newsy', u'http://palmtop.pl/feed/atom/')] diff --git a/recipes/pc_arena.recipe b/recipes/pc_arena.recipe index faefeb25c0..952db30c3e 100644 --- a/recipes/pc_arena.recipe +++ b/recipes/pc_arena.recipe @@ -1,31 +1,25 @@ from calibre.web.feeds.news import BasicNewsRecipe class PC_Arena(BasicNewsRecipe): title = u'PCArena' - oldest_article = 18300 + oldest_article = 7 max_articles_per_feed = 100 __author__ = 'fenuks' description = u'Najnowsze informacje z branży IT - testy, recenzje, aktualności, rankingi, wywiady. Twoje źródło informacji o sprzęcie komputerowym.' category = 'IT' language = 'pl' - masthead_url='http://pcarena.pl/public/design/frontend/images/logo.gif' - cover_url= 'http://pcarena.pl/public/design/frontend/images/logo.gif' + masthead_url='http://pcarena.pl/pcarena/img/logo.png' + cover_url= 'http://pcarena.pl/pcarena/img/logo.png' no_stylesheets = True - keep_only_tags=[dict(attrs={'class':['artHeader', 'art']})] - remove_tags=[dict(attrs={'class':'pages'})] - feeds = [(u'Newsy', u'http://pcarena.pl/misc/rss/news'), (u'Artyku\u0142y', u'http://pcarena.pl/misc/rss/articles')] + remove_empty_feeds=True + #keep_only_tags=[dict(attrs={'class':['artHeader', 'art']})] + #remove_tags=[dict(attrs={'class':'pages'})] + feeds = [(u'Aktualności', u'http://pcarena.pl/aktualnosci/feeds.rss'), (u'Testy', u'http://pcarena.pl/testy/feeds.rss'), (u'Software', u'http://pcarena.pl/oprogramowanie/feeds.rss'), (u'Poradniki', u'http://pcarena.pl/poradniki/feeds.rss'), (u'Mobile', u'http://pcarena.pl/mobile/feeds.rss')] + + def print_version(self, url): + return url.replace('show', 'print') - def append_page(self, soup, appendtag): - tag=soup.find(name='div', attrs={'class':'pagNum'}) - if tag: - nexturl=tag.findAll('a') - tag.extract() - for nextpage in nexturl[1:]: - nextpage= 'http://pcarena.pl' + nextpage['href'] - soup2 = self.index_to_soup(nextpage) - pagetext = soup2.find(attrs={'class':'artBody'}) - pos = len(appendtag.contents) - appendtag.insert(pos, pagetext) - - def preprocess_html(self, soup): - self.append_page(soup, soup.body) - return soup \ No newline at end of file + def image_url_processor(self, baseurl, url): + if 'http' not in url: + return 'http://pcarena.pl' + url + else: + return url \ No newline at end of file diff --git a/recipes/pc_centre_pl.recipe b/recipes/pc_centre_pl.recipe index 68a17888ce..f4eccd70a0 100644 --- a/recipes/pc_centre_pl.recipe +++ b/recipes/pc_centre_pl.recipe @@ -10,32 +10,11 @@ class PC_Centre(BasicNewsRecipe): masthead_url= 'http://pccentre.pl/views/images/logo.gif' cover_url= 'http://pccentre.pl/views/images/logo.gif' no_stylesheets = True - keep_only_tags= [dict(id='content')] - remove_tags=[dict(attrs={'class':['ikony r', 'list_of_content', 'dot accordion']}), dict(id='comments')] - feeds = [(u'Publikacje', u'http://pccentre.pl/backend.php?mode=a'), (u'Aktualno\u015bci', u'http://pccentre.pl/backend.php'), (u'Sprz\u0119t komputerowy', u'http://pccentre.pl/backend.php?mode=n§ion=2'), (u'Oprogramowanie', u'http://pccentre.pl/backend.php?mode=n§ion=3'), (u'Gry komputerowe i konsole', u'http://pccentre.pl/backend.php?mode=n§ion=4'), (u'Internet', u'http://pccentre.pl/backend.php?mode=n§ion=7'), (u'Bezpiecze\u0144stwo', u'http://pccentre.pl/backend.php?mode=n§ion=5'), (u'Multimedia', u'http://pccentre.pl/backend.php?mode=n§ion=6'), (u'Biznes', u'http://pccentre.pl/backend.php?mode=n§ion=9')] + remove_empty_feeds = True + #keep_only_tags= [dict(id='content')] + #remove_tags=[dict(attrs={'class':['ikony r', 'list_of_content', 'dot accordion']}), dict(id='comments')] + remove_tags=[dict(attrs={'class':'logo_print'})] + feeds = [(u'Aktualno\u015bci', u'http://pccentre.pl/backend.php'), (u'Publikacje', u'http://pccentre.pl/backend.php?mode=a'), (u'Sprz\u0119t komputerowy', u'http://pccentre.pl/backend.php?mode=n§ion=2'), (u'Oprogramowanie', u'http://pccentre.pl/backend.php?mode=n§ion=3'), (u'Gry komputerowe i konsole', u'http://pccentre.pl/backend.php?mode=n§ion=4'), (u'Internet', u'http://pccentre.pl/backend.php?mode=n§ion=7'), (u'Bezpiecze\u0144stwo', u'http://pccentre.pl/backend.php?mode=n§ion=5'), (u'Multimedia', u'http://pccentre.pl/backend.php?mode=n§ion=6'), (u'Biznes', u'http://pccentre.pl/backend.php?mode=n§ion=9')] - - def append_page(self, soup, appendtag): - tag=soup.find(name='div', attrs={'class':'pages'}) - if tag: - nexturl=tag.findAll('a') - tag.extract() - for nextpage in nexturl[:-1]: - nextpage= 'http://pccentre.pl' + nextpage['href'] - soup2 = self.index_to_soup(nextpage) - pagetext = soup2.find(id='content') - rem=pagetext.findAll(attrs={'class':['subtitle', 'content_info', 'list_of_content', 'pages', 'social2', 'pcc_acc', 'pcc_acc_na']}) - for r in rem: - r.extract() - rem=pagetext.findAll(id='comments') - for r in rem: - r.extract() - rem=pagetext.findAll('h1') - for r in rem: - r.extract() - pos = len(appendtag.contents) - appendtag.insert(pos, pagetext) - - def preprocess_html(self, soup): - self.append_page(soup, soup.body) - return soup \ No newline at end of file + def print_version(self, url): + return url.replace('show', 'print') \ No newline at end of file diff --git a/recipes/tablety_pl.recipe b/recipes/tablety_pl.recipe index f4c1efa9b8..1c3f46f967 100644 --- a/recipes/tablety_pl.recipe +++ b/recipes/tablety_pl.recipe @@ -8,10 +8,11 @@ class Tablety_pl(BasicNewsRecipe): cover_url = 'http://www.tablety.pl/wp-content/themes/kolektyw/img/logo.png' category = 'IT' language = 'pl' + use_embedded_content=True oldest_article = 8 max_articles_per_feed = 100 preprocess_regexps = [(re.compile(ur'

Przeczytaj także.*?

', re.DOTALL), lambda match: ''), (re.compile(ur'

Przeczytaj koniecznie.*?

', re.DOTALL), lambda match: '')] - remove_tags_before=dict(name="h1", attrs={'class':'entry-title'}) - remove_tags_after=dict(name="div", attrs={'class':'snap_nopreview sharing robots-nocontent'}) - remove_tags=[dict(name='div', attrs={'class':'snap_nopreview sharing robots-nocontent'})] + #remove_tags_before=dict(name="h1", attrs={'class':'entry-title'}) + #remove_tags_after=dict(name="footer", attrs={'class':'entry-footer clearfix'}) + #remove_tags=[dict(name='footer', attrs={'class':'entry-footer clearfix'}), dict(name='div', attrs={'class':'entry-comment-counter'})] feeds = [(u'Najnowsze posty', u'http://www.tablety.pl/feed/')] diff --git a/recipes/wnp.recipe b/recipes/wnp.recipe index e53e4cc66b..ee87112437 100644 --- a/recipes/wnp.recipe +++ b/recipes/wnp.recipe @@ -1,5 +1,5 @@ from calibre.web.feeds.news import BasicNewsRecipe - +import re class AdvancedUserRecipe1312886443(BasicNewsRecipe): title = u'WNP' @@ -8,10 +8,11 @@ class AdvancedUserRecipe1312886443(BasicNewsRecipe): description = u'Wirtualny Nowy Przemysł' category = 'economy' language = 'pl' + preprocess_regexps = [(re.compile(ur'Czytaj też:.*?', re.DOTALL), lambda match: ''), (re.compile(ur'Czytaj więcej:.*?', re.DOTALL), lambda match: '')] oldest_article = 8 max_articles_per_feed = 100 no_stylesheets= True - keep_only_tags = dict(name='div', attrs={'id':'contentText'}) + remove_tags=[dict(attrs={'class':'printF'})] feeds = [(u'Wiadomości gospodarcze', u'http://www.wnp.pl/rss/serwis_rss.xml'), (u'Serwis Energetyka - Gaz', u'http://www.wnp.pl/rss/serwis_rss_1.xml'), (u'Serwis Nafta - Chemia', u'http://www.wnp.pl/rss/serwis_rss_2.xml'), @@ -19,3 +20,7 @@ class AdvancedUserRecipe1312886443(BasicNewsRecipe): (u'Serwis Górnictwo', u'http://www.wnp.pl/rss/serwis_rss_4.xml'), (u'Serwis Logistyka', u'http://www.wnp.pl/rss/serwis_rss_5.xml'), (u'Serwis IT', u'http://www.wnp.pl/rss/serwis_rss_6.xml')] + + + def print_version(self, url): + return 'http://wnp.pl/drukuj/' +url[url.find(',')+1:] \ No newline at end of file diff --git a/resources/fonts/liberation/LiberationMono-Bold.ttf b/resources/fonts/liberation/LiberationMono-Bold.ttf index 42941e57b1..11b3f56fb4 100644 Binary files a/resources/fonts/liberation/LiberationMono-Bold.ttf and b/resources/fonts/liberation/LiberationMono-Bold.ttf differ diff --git a/resources/fonts/liberation/LiberationMono-BoldItalic.ttf b/resources/fonts/liberation/LiberationMono-BoldItalic.ttf index 4682e4de1f..3e81a59651 100644 Binary files a/resources/fonts/liberation/LiberationMono-BoldItalic.ttf and b/resources/fonts/liberation/LiberationMono-BoldItalic.ttf differ diff --git a/resources/fonts/liberation/LiberationMono-Italic.ttf b/resources/fonts/liberation/LiberationMono-Italic.ttf index e19f08cfb7..8ee00830e4 100644 Binary files a/resources/fonts/liberation/LiberationMono-Italic.ttf and b/resources/fonts/liberation/LiberationMono-Italic.ttf differ diff --git a/resources/fonts/liberation/LiberationMono-Regular.ttf b/resources/fonts/liberation/LiberationMono-Regular.ttf index dea96958a1..47da91c66e 100644 Binary files a/resources/fonts/liberation/LiberationMono-Regular.ttf and b/resources/fonts/liberation/LiberationMono-Regular.ttf differ diff --git a/resources/fonts/liberation/LiberationSans-Bold.ttf b/resources/fonts/liberation/LiberationSans-Bold.ttf index b29a5640e4..ee978ce029 100644 Binary files a/resources/fonts/liberation/LiberationSans-Bold.ttf and b/resources/fonts/liberation/LiberationSans-Bold.ttf differ diff --git a/resources/fonts/liberation/LiberationSans-BoldItalic.ttf b/resources/fonts/liberation/LiberationSans-BoldItalic.ttf index 0b0bf94a57..10002b8763 100644 Binary files a/resources/fonts/liberation/LiberationSans-BoldItalic.ttf and b/resources/fonts/liberation/LiberationSans-BoldItalic.ttf differ diff --git a/resources/fonts/liberation/LiberationSans-Italic.ttf b/resources/fonts/liberation/LiberationSans-Italic.ttf index 4a430cdddd..1d287ee9f6 100644 Binary files a/resources/fonts/liberation/LiberationSans-Italic.ttf and b/resources/fonts/liberation/LiberationSans-Italic.ttf differ diff --git a/resources/fonts/liberation/LiberationSans-Regular.ttf b/resources/fonts/liberation/LiberationSans-Regular.ttf index 2de10634e0..d31cf3174b 100644 Binary files a/resources/fonts/liberation/LiberationSans-Regular.ttf and b/resources/fonts/liberation/LiberationSans-Regular.ttf differ diff --git a/resources/fonts/liberation/LiberationSerif-Bold.ttf b/resources/fonts/liberation/LiberationSerif-Bold.ttf index 892746e128..fa525f13e5 100644 Binary files a/resources/fonts/liberation/LiberationSerif-Bold.ttf and b/resources/fonts/liberation/LiberationSerif-Bold.ttf differ diff --git a/resources/fonts/liberation/LiberationSerif-BoldItalic.ttf b/resources/fonts/liberation/LiberationSerif-BoldItalic.ttf index ad754700fd..84a9cb4f78 100644 Binary files a/resources/fonts/liberation/LiberationSerif-BoldItalic.ttf and b/resources/fonts/liberation/LiberationSerif-BoldItalic.ttf differ diff --git a/resources/fonts/liberation/LiberationSerif-Italic.ttf b/resources/fonts/liberation/LiberationSerif-Italic.ttf index e81544aab2..1e7d7fc773 100644 Binary files a/resources/fonts/liberation/LiberationSerif-Italic.ttf and b/resources/fonts/liberation/LiberationSerif-Italic.ttf differ diff --git a/resources/fonts/liberation/LiberationSerif-Regular.ttf b/resources/fonts/liberation/LiberationSerif-Regular.ttf index 155675f711..d934d218b1 100644 Binary files a/resources/fonts/liberation/LiberationSerif-Regular.ttf and b/resources/fonts/liberation/LiberationSerif-Regular.ttf differ diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 55742b3ee3..3e91bc2ef3 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -1538,6 +1538,7 @@ class StoreWaterstonesUKStore(StoreBase): headquarters = 'UK' formats = ['EPUB', 'PDF'] + affiliate = True class StoreWeightlessBooksStore(StoreBase): name = 'Weightless Books' @@ -1557,15 +1558,6 @@ class StoreWHSmithUKStore(StoreBase): headquarters = 'UK' formats = ['EPUB', 'PDF'] -class StoreWizardsTowerBooksStore(StoreBase): - name = 'Wizards Tower Books' - description = u'A science fiction and fantasy publisher. Concentrates mainly on making out-of-print works available once more as e-books, and helping other small presses exploit the e-book market. Also publishes a small number of limited-print-run anthologies with a view to encouraging diversity in the science fiction and fantasy field.' - actual_plugin = 'calibre.gui2.store.stores.wizards_tower_books_plugin:WizardsTowerBooksStore' - - drm_free_only = True - headquarters = 'UK' - formats = ['EPUB', 'MOBI'] - class StoreWoblinkStore(StoreBase): name = 'Woblink' author = u'Tomasz Długosz' @@ -1573,7 +1565,7 @@ class StoreWoblinkStore(StoreBase): actual_plugin = 'calibre.gui2.store.stores.woblink_plugin:WoblinkStore' headquarters = 'PL' - formats = ['EPUB', 'PDF', 'WOBLINK'] + formats = ['EPUB', 'MOBI', 'PDF', 'WOBLINK'] class XinXiiStore(StoreBase): name = 'XinXii' @@ -1636,7 +1628,6 @@ plugins += [ StoreWaterstonesUKStore, StoreWeightlessBooksStore, StoreWHSmithUKStore, - StoreWizardsTowerBooksStore, StoreWoblinkStore, XinXiiStore, StoreZixoStore diff --git a/src/calibre/gui2/actions/copy_to_library.py b/src/calibre/gui2/actions/copy_to_library.py index dd25b83d50..abc10c2d76 100644 --- a/src/calibre/gui2/actions/copy_to_library.py +++ b/src/calibre/gui2/actions/copy_to_library.py @@ -13,7 +13,8 @@ from contextlib import closing from PyQt4.Qt import QToolButton from calibre.gui2.actions import InterfaceAction -from calibre.gui2 import error_dialog, Dispatcher, warning_dialog, gprefs +from calibre.gui2 import (error_dialog, Dispatcher, warning_dialog, gprefs, + info_dialog) from calibre.gui2.dialogs.progress import ProgressDialog from calibre.utils.config import prefs, tweaks from calibre.utils.date import now @@ -30,6 +31,7 @@ class Worker(Thread): # {{{ self.progress = progress self.done = done self.delete_after = delete_after + self.auto_merged_ids = {} def run(self): try: @@ -79,6 +81,8 @@ class Worker(Thread): # {{{ if prefs['add_formats_to_existing']: identical_book_list = newdb.find_identical_books(mi) if identical_book_list: # books with same author and nearly same title exist in newdb + self.auto_merged_ids[x] = _('%s by %s')%(mi.title, + mi.format_field('authors')[1]) automerged = True seen_fmts = set() for identical_book in identical_book_list: @@ -196,6 +200,15 @@ class CopyToLibraryAction(InterfaceAction): self.gui.status_bar.show_message( _('Copied %(num)d books to %(loc)s') % dict(num=len(ids), loc=loc), 2000) + if self.worker.auto_merged_ids: + books = '\n'.join(self.worker.auto_merged_ids.itervalues()) + info_dialog(self.gui, _('Auto merged'), + _('Some books were automatically merged into existing ' + 'records in the target library. Click Show ' + 'details to see which ones. This behavior is ' + 'controlled by the Auto merge option in ' + 'Preferences->Adding books.'), det_msg=books, + show=True) if delete_after and self.worker.processed: v = self.gui.library_view ci = v.currentIndex() diff --git a/src/calibre/gui2/store/declined.txt b/src/calibre/gui2/store/declined.txt index bd2aa296bd..b109d30d50 100644 --- a/src/calibre/gui2/store/declined.txt +++ b/src/calibre/gui2/store/declined.txt @@ -5,4 +5,3 @@ or asked not to be included in the store integration. * Indigo (http://www.chapters.indigo.ca/). * Libraria Rizzoli (http://libreriarizzoli.corriere.it/). * EPubBuy DE: reason: too much traffic for too little sales -* Empik (http://empik.com.pl). diff --git a/src/calibre/gui2/store/stores/amazon_de_plugin.py b/src/calibre/gui2/store/stores/amazon_de_plugin.py index ea92839268..c42c7392a1 100644 --- a/src/calibre/gui2/store/stores/amazon_de_plugin.py +++ b/src/calibre/gui2/store/stores/amazon_de_plugin.py @@ -41,7 +41,9 @@ class AmazonDEKindleStore(StorePlugin): counter = max_results with closing(br.open(url, timeout=timeout)) as f: - doc = html.fromstring(f.read().decode('latin-1', 'replace')) + # doc = html.fromstring(f.read().decode('latin-1', 'replace')) + # Apparently amazon Europe is responding in UTF-8 now + doc = html.fromstring(f.read()) data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]' format_xpath = './/span[@class="format"]/text()' @@ -65,8 +67,8 @@ class AmazonDEKindleStore(StorePlugin): cover_url = ''.join(data.xpath(cover_xpath)) - title = ''.join(data.xpath('.//div[@class="title"]/a/text()')) - price = ''.join(data.xpath('.//div[@class="newPrice"]/span/text()')) + title = ''.join(data.xpath('.//a[@class="title"]/text()')) + price = ''.join(data.xpath('.//span[@class="price"]/text()')) author = ''.join(data.xpath('.//div[@class="title"]/span[@class="ptBrand"]/text()')) if author.startswith('von '): diff --git a/src/calibre/gui2/store/stores/amazon_es_plugin.py b/src/calibre/gui2/store/stores/amazon_es_plugin.py index d89c051d87..97abab61ed 100644 --- a/src/calibre/gui2/store/stores/amazon_es_plugin.py +++ b/src/calibre/gui2/store/stores/amazon_es_plugin.py @@ -37,7 +37,9 @@ class AmazonESKindleStore(StorePlugin): counter = max_results with closing(br.open(url, timeout=timeout)) as f: - doc = html.fromstring(f.read().decode('latin-1', 'replace')) + # doc = html.fromstring(f.read().decode('latin-1', 'replace')) + # Apparently amazon Europe is responding in UTF-8 now + doc = html.fromstring(f.read()) data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]' format_xpath = './/span[@class="format"]/text()' @@ -61,8 +63,8 @@ class AmazonESKindleStore(StorePlugin): cover_url = ''.join(data.xpath(cover_xpath)) - title = ''.join(data.xpath('.//div[@class="title"]/a/text()')) - price = ''.join(data.xpath('.//div[@class="newPrice"]/span/text()')) + title = ''.join(data.xpath('.//a[@class="title"]/text()')) + price = ''.join(data.xpath('.//span[@class="price"]/text()')) author = unicode(''.join(data.xpath('.//div[@class="title"]/span[@class="ptBrand"]/text()'))) if author.startswith('de '): author = author[3:] diff --git a/src/calibre/gui2/store/stores/amazon_fr_plugin.py b/src/calibre/gui2/store/stores/amazon_fr_plugin.py index ea4c80e50d..b98ba06117 100644 --- a/src/calibre/gui2/store/stores/amazon_fr_plugin.py +++ b/src/calibre/gui2/store/stores/amazon_fr_plugin.py @@ -39,7 +39,7 @@ class AmazonFRKindleStore(StorePlugin): counter = max_results with closing(br.open(url, timeout=timeout)) as f: # doc = html.fromstring(f.read().decode('latin-1', 'replace')) - # Apparently amazon.fr is responding in UTF-8 now + # Apparently amazon Europe is responding in UTF-8 now doc = html.fromstring(f.read()) data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]' @@ -64,8 +64,8 @@ class AmazonFRKindleStore(StorePlugin): cover_url = ''.join(data.xpath(cover_xpath)) - title = ''.join(data.xpath('.//div[@class="title"]/a/text()')) - price = ''.join(data.xpath('.//div[@class="newPrice"]/span/text()')) + title = ''.join(data.xpath('.//a[@class="title"]/text()')) + price = ''.join(data.xpath('.//span[@class="price"]/text()')) author = unicode(''.join(data.xpath('.//div[@class="title"]/span[@class="ptBrand"]/text()'))) if author.startswith('de '): author = author[3:] diff --git a/src/calibre/gui2/store/stores/amazon_it_plugin.py b/src/calibre/gui2/store/stores/amazon_it_plugin.py index c62273deeb..23cde51555 100644 --- a/src/calibre/gui2/store/stores/amazon_it_plugin.py +++ b/src/calibre/gui2/store/stores/amazon_it_plugin.py @@ -37,7 +37,9 @@ class AmazonITKindleStore(StorePlugin): counter = max_results with closing(br.open(url, timeout=timeout)) as f: - doc = html.fromstring(f.read().decode('latin-1', 'replace')) + # doc = html.fromstring(f.read().decode('latin-1', 'replace')) + # Apparently amazon Europe is responding in UTF-8 now + doc = html.fromstring(f.read()) data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]' format_xpath = './/span[@class="format"]/text()' @@ -61,8 +63,8 @@ class AmazonITKindleStore(StorePlugin): cover_url = ''.join(data.xpath(cover_xpath)) - title = ''.join(data.xpath('.//div[@class="title"]/a/text()')) - price = ''.join(data.xpath('.//div[@class="newPrice"]/span/text()')) + title = ''.join(data.xpath('.//a[@class="title"]/text()')) + price = ''.join(data.xpath('.//span[@class="price"]/text()')) author = unicode(''.join(data.xpath('.//div[@class="title"]/span[@class="ptBrand"]/text()'))) if author.startswith('di '): author = author[3:] diff --git a/src/calibre/gui2/store/stores/amazon_uk_plugin.py b/src/calibre/gui2/store/stores/amazon_uk_plugin.py index ef15951d50..0d063a4a6e 100644 --- a/src/calibre/gui2/store/stores/amazon_uk_plugin.py +++ b/src/calibre/gui2/store/stores/amazon_uk_plugin.py @@ -38,7 +38,8 @@ class AmazonUKKindleStore(StorePlugin): counter = max_results with closing(br.open(url, timeout=timeout)) as f: - doc = html.fromstring(f.read().decode('latin-1', 'replace')) + # Apparently amazon Europe is responding in UTF-8 now + doc = html.fromstring(f.read()) data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]' format_xpath = './/span[@class="format"]/text()' @@ -62,8 +63,8 @@ class AmazonUKKindleStore(StorePlugin): cover_url = ''.join(data.xpath(cover_xpath)) - title = ''.join(data.xpath('.//div[@class="title"]/a/text()')) - price = ''.join(data.xpath('.//div[@class="newPrice"]/span/text()')) + title = ''.join(data.xpath('.//a[@class="title"]/text()')) + price = ''.join(data.xpath('.//span[@class="price"]/text()')) author = ''.join(data.xpath('.//div[@class="title"]/span[@class="ptBrand"]/text()')) if author.startswith('by '): diff --git a/src/calibre/gui2/store/stores/bn_plugin.py b/src/calibre/gui2/store/stores/bn_plugin.py index aa30ffe677..ab3d39264f 100644 --- a/src/calibre/gui2/store/stores/bn_plugin.py +++ b/src/calibre/gui2/store/stores/bn_plugin.py @@ -62,7 +62,7 @@ class BNStore(BasicStoreConfig, StorePlugin): title = ''.join(data.xpath('.//p[@class="title"]//span[@class="name"]/text()')) author = ', '.join(data.xpath('.//ul[@class="contributors"]//li[position()>1]//a/text()')) - price = ''.join(data.xpath('.//table[@class="displayed-formats"]//a[@class="subtle"]/text()')) + price = ''.join(data.xpath('.//table[@class="displayed-formats"]//a[contains(@class, "bn-price")]/text()')) counter -= 1 diff --git a/src/calibre/gui2/store/stores/diesel_ebooks_plugin.py b/src/calibre/gui2/store/stores/diesel_ebooks_plugin.py index a6876f8840..1d410e2c38 100644 --- a/src/calibre/gui2/store/stores/diesel_ebooks_plugin.py +++ b/src/calibre/gui2/store/stores/diesel_ebooks_plugin.py @@ -7,7 +7,7 @@ __copyright__ = '2011, John Schember ' __docformat__ = 'restructuredtext en' import random -import urllib2 +import urllib from contextlib import closing from lxml import html @@ -22,7 +22,7 @@ from calibre.gui2.store.search_result import SearchResult from calibre.gui2.store.web_store_dialog import WebStoreDialog class DieselEbooksStore(BasicStoreConfig, StorePlugin): - + def open(self, parent=None, detail_item=None, external=False): url = 'http://www.diesel-ebooks.com/' @@ -33,7 +33,7 @@ class DieselEbooksStore(BasicStoreConfig, StorePlugin): detail_url = None if detail_item: - detail_url = url + detail_item + aff_id + detail_url = detail_item + aff_id url = url + aff_id if external or self.config.get('open_external', False): @@ -45,54 +45,46 @@ class DieselEbooksStore(BasicStoreConfig, StorePlugin): d.exec_() def search(self, query, max_results=10, timeout=60): - url = 'http://www.diesel-ebooks.com/index.php?page=seek&id[m]=&id[c]=scope%253Dinventory&id[q]=' + urllib2.quote(query) - + url = 'http://www.diesel-ebooks.com/index.php?page=seek&id[m]=&id[c]=scope%253Dinventory&id[q]=' + urllib.quote_plus(query) + br = browser() - + counter = max_results with closing(br.open(url, timeout=timeout)) as f: doc = html.fromstring(f.read()) - for data in doc.xpath('//div[@class="item clearfix"]'): - data = html.fromstring(html.tostring(data)) + for data in doc.xpath('//div[contains(@class, "item")]'): if counter <= 0: break id = ''.join(data.xpath('div[@class="cover"]/a/@href')) if not id or '/item/' not in id: continue - a, b, id = id.partition('/item/') cover_url = ''.join(data.xpath('div[@class="cover"]//img/@src')) - title = ''.join(data.xpath('.//div[@class="content"]//h2/text()')) - author = ''.join(data.xpath('//div[@class="content"]//div[@class="author"]/a/text()')) + title = ''.join(data.xpath('.//div[@class="content"]//h2/a/text()')) + author = ''.join(data.xpath('.//div[@class="content"]/span//a/text()')) price = '' - price_elem = data.xpath('//td[@class="price"]/text()') + price_elem = data.xpath('.//div[@class="price_fat"]//h1/text()') if price_elem: price = price_elem[0] - formats = ', '.join(data.xpath('.//td[@class="format"]/text()')) + formats = ', '.join(data.xpath('.//div[@class="book-info"]//text()')).strip() + a, b, formats = formats.partition('Format:') + drm = SearchResult.DRM_LOCKED + if 'drm free' not in formats.lower(): + drm = SearchResult.DRM_UNLOCKED + counter -= 1 - + s = SearchResult() s.cover_url = cover_url s.title = title.strip() s.author = author.strip() s.price = price.strip() - s.detail_item = '/item/' + id.strip() + s.detail_item = id.strip() s.formats = formats - - yield s + s.drm = drm - def get_details(self, search_result, timeout): - url = 'http://www.diesel-ebooks.com/item/' - - br = browser() - with closing(br.open(url + search_result.detail_item, timeout=timeout)) as nf: - idata = html.fromstring(nf.read()) - if idata.xpath('boolean(//table[@class="format-info"]//tr[contains(th, "DRM") and contains(td, "No")])'): - search_result.drm = SearchResult.DRM_UNLOCKED - else: - search_result.drm = SearchResult.DRM_LOCKED - return True + yield s diff --git a/src/calibre/gui2/store/stores/foyles_uk_plugin.py b/src/calibre/gui2/store/stores/foyles_uk_plugin.py index 0e5ccfad01..c7c236d200 100644 --- a/src/calibre/gui2/store/stores/foyles_uk_plugin.py +++ b/src/calibre/gui2/store/stores/foyles_uk_plugin.py @@ -60,10 +60,6 @@ class FoylesUKStore(BasicStoreConfig, StorePlugin): continue cover_url = ''.join(data.xpath('.//a[@class="Jacket"]/img/@src')) - if cover_url: - cover_url = 'http://www.foyles.co.uk' + cover_url - #print(cover_url) - title = ''.join(data.xpath('.//a[@class="Title"]/text()')) author = ', '.join(data.xpath('.//span[@class="Author"]/text()')) price = ''.join(data.xpath('./ul/li[@class="Strong"]/text()')) diff --git a/src/calibre/gui2/store/stores/kobo_plugin.py b/src/calibre/gui2/store/stores/kobo_plugin.py index 9ec0e4b786..249d59ec5c 100644 --- a/src/calibre/gui2/store/stores/kobo_plugin.py +++ b/src/calibre/gui2/store/stores/kobo_plugin.py @@ -68,7 +68,7 @@ class KoboStore(BasicStoreConfig, StorePlugin): cover_url = ''.join(data.xpath('.//div[@class="SearchImageContainer"]//img[1]/@src')) title = ''.join(data.xpath('.//div[@class="SCItemHeader"]/h1/a[1]/text()')) - author = ''.join(data.xpath('.//div[@class="SCItemSummary"]/span/a[1]/text()')) + author = ', '.join(data.xpath('.//div[@class="SCItemSummary"]//span//a/text()')) drm = data.xpath('boolean(.//span[@class="SCAvailibilityFormatsText" and contains(text(), "DRM")])') counter -= 1 diff --git a/src/calibre/gui2/store/stores/waterstones_uk_plugin.py b/src/calibre/gui2/store/stores/waterstones_uk_plugin.py index a5065128ba..df17372d0a 100644 --- a/src/calibre/gui2/store/stores/waterstones_uk_plugin.py +++ b/src/calibre/gui2/store/stores/waterstones_uk_plugin.py @@ -57,7 +57,7 @@ class WaterstonesUKStore(BasicStoreConfig, StorePlugin): cover_url = ''.join(data.xpath('.//div[@class="image"]/a/img/@src')) title = ''.join(data.xpath('./div/div/h2/a/text()')) author = ', '.join(data.xpath('.//p[@class="byAuthor"]/a/text()')) - price = ''.join(data.xpath('.//p[@class="price"]/span[@class="priceStandard"]/text()')) + price = ''.join(data.xpath('.//p[@class="price"]/span[@class="priceRed2"]/text()')) drm = data.xpath('boolean(.//td[@headers="productFormat" and contains(., "DRM")])') pdf = data.xpath('boolean(.//td[@headers="productFormat" and contains(., "PDF")])') epub = data.xpath('boolean(.//td[@headers="productFormat" and contains(., "EPUB")])') diff --git a/src/calibre/gui2/store/stores/wizards_tower_books_plugin.py b/src/calibre/gui2/store/stores/wizards_tower_books_plugin.py deleted file mode 100644 index 90966fc06a..0000000000 --- a/src/calibre/gui2/store/stores/wizards_tower_books_plugin.py +++ /dev/null @@ -1,118 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import (unicode_literals, division, absolute_import, print_function) - -__license__ = 'GPL 3' -__copyright__ = '2011, John Schember ' -__docformat__ = 'restructuredtext en' - -import urllib -from contextlib import closing - -from lxml import html - -from PyQt4.Qt import QUrl - -from calibre import browser, url_slash_cleaner -from calibre.gui2 import open_url -from calibre.gui2.store import StorePlugin -from calibre.gui2.store.basic_config import BasicStoreConfig -from calibre.gui2.store.search_result import SearchResult -from calibre.gui2.store.web_store_dialog import WebStoreDialog - -class WizardsTowerBooksStore(BasicStoreConfig, StorePlugin): - - url = 'http://www.wizardstowerbooks.com/' - - def open(self, parent=None, detail_item=None, external=False): - if detail_item: - detail_item = self.url + detail_item - - if external or self.config.get('open_external', False): - open_url(QUrl(url_slash_cleaner(detail_item))) - else: - d = WebStoreDialog(self.gui, self.url, parent, detail_item) - d.setWindowTitle(self.name) - d.set_tags(self.config.get('tags', '')) - d.exec_() - - def search(self, query, max_results=10, timeout=60): - url = 'http://www.wizardstowerbooks.com/search.html?for=' + urllib.quote(query) - - br = browser() - - counter = max_results - with closing(br.open(url, timeout=timeout)) as f: - doc = html.fromstring(f.read()) - if 'search.html' in f.geturl(): - for data in doc.xpath('//table[@class="gridp"]//td'): - if counter <= 0: - break - - id = ''.join(data.xpath('.//span[@class="prti"]/a/@href')) - id = id.strip() - if not id: - continue - - cover_url = ''.join(data.xpath('.//div[@class="prim"]/a/img/@src')) - cover_url = url_slash_cleaner(self.url + cover_url.strip()) - - price = ''.join(data.xpath('.//font[@class="selling_price"]//text()')) - price = price.strip() - if not price: - continue - - title = ''.join(data.xpath('.//span[@class="prti"]/a/b/text()')) - author = ''.join(data.xpath('.//p[@class="last"]/text()')) - a, b, author = author.partition(' by ') - - counter -= 1 - - s = SearchResult() - s.cover_url = cover_url - s.title = title.strip() - s.author = author.strip() - s.price = price.strip() - s.detail_item = id.strip() - s.drm = SearchResult.DRM_UNLOCKED - - yield s - # Exact match brought us to the books detail page. - else: - s = SearchResult() - - cover_url = ''.join(doc.xpath('//div[@id="image"]/a/img[@title="Zoom"]/@src')).strip() - s.cover_url = url_slash_cleaner(self.url + cover_url.strip()) - - s.title = ''.join(doc.xpath('//form[@name="details"]/h1/text()')).strip() - - authors = doc.xpath('//p[contains(., "Author:")]//text()') - author_index = None - for i, a in enumerate(authors): - if 'author' in a.lower(): - author_index = i + 1 - break - if author_index is not None and len(authors) > author_index: - a = authors[author_index] - a = a.replace(u'\xa0', '') - s.author = a.strip() - - s.price = ''.join(doc.xpath('//span[@id="price_selling"]//text()')).strip() - s.detail_item = f.geturl().replace(self.url, '').strip() - s.formats = ', '.join(doc.xpath('//select[@id="N1_"]//option//text()')) - s.drm = SearchResult.DRM_UNLOCKED - - yield s - - def get_details(self, search_result, timeout): - if search_result.formats: - return False - - br = browser() - with closing(br.open(url_slash_cleaner(self.url + search_result.detail_item), timeout=timeout)) as nf: - idata = html.fromstring(nf.read()) - - formats = ', '.join(idata.xpath('//select[@id="N1_"]//option//text()')) - search_result.formats = formats.upper() - - return True diff --git a/src/calibre/gui2/store/stores/woblink_plugin.py b/src/calibre/gui2/store/stores/woblink_plugin.py index 9992c80eb9..e9696b39a6 100644 --- a/src/calibre/gui2/store/stores/woblink_plugin.py +++ b/src/calibre/gui2/store/stores/woblink_plugin.py @@ -3,7 +3,7 @@ from __future__ import (unicode_literals, division, absolute_import, print_function) __license__ = 'GPL 3' -__copyright__ = '2011, Tomasz Długosz ' +__copyright__ = '2011-2012, Tomasz Długosz ' __docformat__ = 'restructuredtext en' import re @@ -41,6 +41,11 @@ class WoblinkStore(BasicStoreConfig, StorePlugin): def search(self, query, max_results=10, timeout=60): url = 'http://woblink.com/publication?query=' + urllib.quote_plus(query.encode('utf-8')) + if max_results > 10: + if max_results > 20: + url += '&limit=' + str(30) + else: + url += '&limit=' + str(20) br = browser() @@ -58,15 +63,16 @@ class WoblinkStore(BasicStoreConfig, StorePlugin): cover_url = ''.join(data.xpath('.//td[@class="w10 va-t"]/a[1]/img/@src')) title = ''.join(data.xpath('.//h2[@class="title"]/a[1]/text()')) author = ', '.join(data.xpath('.//p[@class="author"]/a/text()')) - price = ''.join(data.xpath('.//div[@class="prices"]/p[1]/span/text()')) - price = re.sub('PLN', ' zł', price) + price = ''.join(data.xpath('.//div[@class="prices"]/span[1]/span/text()')) price = re.sub('\.', ',', price) - formats = ', '.join(data.xpath('.//p[3]/img/@src')) - formats = formats[8:-4].upper() - if formats == 'EPUB': - formats = 'WOBLINK' + formats = [ form[8:-4].split('_')[0] for form in data.xpath('.//p[3]/img/@src')] + if 'epub' in formats: + formats.remove('epub') + formats.append('WOBLINK') if 'E Ink' in data.xpath('.//div[@class="prices"]/img/@title'): - formats += ', EPUB' + formats.insert(0, 'EPUB') + if 'pdf' in formats: + formats[formats.index('pdf')] = 'PDF' counter -= 1 @@ -74,9 +80,9 @@ class WoblinkStore(BasicStoreConfig, StorePlugin): s.cover_url = 'http://woblink.com' + cover_url s.title = title.strip() s.author = author.strip() - s.price = price + s.price = price + ' zł' s.detail_item = id.strip() - s.drm = SearchResult.DRM_LOCKED - s.formats = formats + s.drm = SearchResult.DRM_UNKNOWN if 'MOBI' in formats else SearchResult.DRM_LOCKED + s.formats = ', '.join(formats) yield s diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index 7999458004..3dee673150 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -8,7 +8,7 @@ import os, math, re, glob, sys, zipfile from base64 import b64encode from functools import partial -from PyQt4.Qt import (QSize, QSizePolicy, QUrl, SIGNAL, Qt, QTimer, +from PyQt4.Qt import (QSize, QSizePolicy, QUrl, SIGNAL, Qt, QPainter, QPalette, QBrush, QFontDatabase, QDialog, QColor, QPoint, QImage, QRegion, QVariant, QIcon, QFont, pyqtSignature, QAction, QByteArray, QMenu, @@ -184,12 +184,10 @@ class Document(QWebPage): # {{{ self.misc_config() self.after_load() - def __init__(self, shortcuts, parent=None, resize_callback=lambda: None, - debug_javascript=False): + def __init__(self, shortcuts, parent=None, debug_javascript=False): QWebPage.__init__(self, parent) self.setObjectName("py_bridge") self.debug_javascript = debug_javascript - self.resize_callback = resize_callback self.current_language = None self.loaded_javascript = False self.js_loader = JavaScriptLoader( @@ -259,12 +257,6 @@ class Document(QWebPage): # {{{ if self.loaded_javascript: return self.loaded_javascript = True - self.javascript( - ''' - window.onresize = function(event) { - window.py_bridge.window_resized(); - } - ''') self.loaded_lang = self.js_loader(self.mainFrame().evaluateJavaScript, self.current_language, self.hyphenate_default_lang) @@ -310,10 +302,6 @@ class Document(QWebPage): # {{{ def debug(self, msg): prints(msg) - @pyqtSignature('') - def window_resized(self): - self.resize_callback() - def reference_mode(self, enable): self.javascript(('enter' if enable else 'leave')+'_reference_mode()') @@ -444,7 +432,7 @@ class Document(QWebPage): # {{{ def scroll_fraction(self): def fget(self): try: - return float(self.ypos)/(self.height-self.window_height) + return abs(float(self.ypos)/(self.height-self.window_height)) except ZeroDivisionError: return 0. def fset(self, val): @@ -516,7 +504,6 @@ class DocumentView(QWebView): # {{{ self.initial_pos = 0.0 self.to_bottom = False self.document = Document(self.shortcuts, parent=self, - resize_callback=self.viewport_resized, debug_javascript=debug_javascript) self.setPage(self.document) self.manager = None @@ -1035,13 +1022,9 @@ class DocumentView(QWebView): # {{{ return handled def resizeEvent(self, event): - ret = QWebView.resizeEvent(self, event) - QTimer.singleShot(10, self.initialize_scrollbar) - return ret - - def viewport_resized(self): if self.manager is not None: - self.manager.viewport_resized(self.scroll_fraction) + self.manager.viewport_resize_started(event) + return QWebView.resizeEvent(self, event) def event(self, ev): if ev.type() == ev.Gesture: diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index c1cb89aeb6..413916fb81 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -224,6 +224,10 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.toc.setVisible(False) self.action_quit = QAction(self) self.addAction(self.action_quit) + self.view_resized_timer = QTimer(self) + self.view_resized_timer.timeout.connect(self.viewport_resize_finished) + self.view_resized_timer.setSingleShot(True) + self.resize_in_progress = False qs = [Qt.CTRL+Qt.Key_Q] if isosx: qs += [Qt.CTRL+Qt.Key_W] @@ -311,6 +315,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer): border-radius: 20px; } ''') + self.window_mode_changed = None self.toggle_toolbar_action = QAction(_('Show/hide controls'), self) self.toggle_toolbar_action.triggered.connect(self.toggle_toolbars) self.addAction(self.toggle_toolbar_action) @@ -441,6 +446,8 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.showFullScreen() def showFullScreen(self): + self.view.document.page_position.save() + self.window_mode_changed = 'fullscreen' self.tool_bar.setVisible(False) self.tool_bar2.setVisible(False) self._original_frame_margins = ( @@ -450,7 +457,6 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.centralwidget.layout().setContentsMargins(0, 0, 0, 0) super(EbookViewer, self).showFullScreen() - QTimer.singleShot(10, self.show_full_screen_label) def show_full_screen_label(self): f = self.full_screen_label @@ -469,6 +475,8 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.view.document.switch_to_fullscreen_mode() def showNormal(self): + self.view.document.page_position.save() + self.window_mode_changed = 'normal' self.esc_full_screen_action.setEnabled(False) self.tool_bar.setVisible(True) self.tool_bar2.setVisible(True) @@ -478,7 +486,16 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.centralwidget.layout().setContentsMargins(om[0]) self.frame.layout().setContentsMargins(om[1]) super(EbookViewer, self).showNormal() - self.view.document.switch_to_window_mode() + + def handle_window_mode_toggle(self): + if self.window_mode_changed: + fs = self.window_mode_changed == 'fullscreen' + self.window_mode_changed = None + if fs: + self.show_full_screen_label() + else: + self.view.document.switch_to_window_mode() + self.view.document.page_position.restore() def goto(self, ref): if ref: @@ -507,6 +524,10 @@ class EbookViewer(MainWindow, Ui_EbookViewer): def toc_clicked(self, index): item = self.toc_model.itemFromIndex(index) if item.abspath is not None: + if not os.path.exists(item.abspath): + return error_dialog(self, _('No such location'), + _('The location pointed to by this item' + ' does not exist.'), show=True) url = QUrl.fromLocalFile(item.abspath) if item.fragment: url.setFragment(item.fragment) @@ -674,16 +695,28 @@ class EbookViewer(MainWindow, Ui_EbookViewer): self.open_progress_indicator(_('Laying out %s')%self.current_title) self.view.load_path(path, pos=pos) - def viewport_resized(self, frac): - new_page = self.pos.value() - if self.current_page is not None: - try: - frac = float(new_page-self.current_page.start_page)/(self.current_page.pages-1) - except ZeroDivisionError: - frac = 0 - self.view.scroll_to(frac, notify=False) + def viewport_resize_started(self, event): + if not self.resize_in_progress: + # First resize, so save the current page position + self.resize_in_progress = True + if not self.window_mode_changed: + # The special handling for window mode changed will already + # have saved page position, so only save it if this is not a + # mode change + self.view.document.page_position.save() + + if self.resize_in_progress: + self.view_resized_timer.start(75) + + def viewport_resize_finished(self): + # There hasn't been a resize event for some time + # restore the current page position. + self.resize_in_progress = False + if self.window_mode_changed: + # This resize is part of a window mode change, special case it + self.handle_window_mode_toggle() else: - self.set_page_number(frac) + self.view.document.page_position.restore() def close_progress_indicator(self): self.pi.stop() diff --git a/src/calibre/gui2/viewer/position.py b/src/calibre/gui2/viewer/position.py index 53b0a8f11c..5eb44ec687 100644 --- a/src/calibre/gui2/viewer/position.py +++ b/src/calibre/gui2/viewer/position.py @@ -57,12 +57,20 @@ class PagePosition(object): return ans def __enter__(self): - self._cpos = self.current_pos + self.save() def __exit__(self, *args): + self.restore() + + def save(self): + self._cpos = self.current_pos + + def restore(self): + if self._cpos is None: return if isinstance(self._cpos, (int, float)): self.document.scroll_fraction = self._cpos else: self.scroll_to_cfi(self._cpos) self._cpos = None + diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py index 6e7421c7f0..191ac53f94 100644 --- a/src/calibre/library/caches.py +++ b/src/calibre/library/caches.py @@ -953,7 +953,7 @@ class ResultCache(SearchQueryParser): # {{{ self.series_col, self.series_sort_col) self._data[id].append(db.book_on_device_string(id)) self._data[id].append(self.marked_ids_dict.get(id, None)) - self._data[id].append(None) + self._data[id].append(None) # Series sort column self._map[0:0] = ids self._map_filtered[0:0] = ids @@ -983,8 +983,8 @@ class ResultCache(SearchQueryParser): # {{{ for item in self._data: if item is not None: item.append(db.book_on_device_string(item[0])) - item.append(None) - item.append(None) + # Temp mark and series_sort columns + item.extend((None, None)) marked_col = self.FIELD_MAP['marked'] for id_,val in self.marked_ids_dict.iteritems():