diff --git a/format_docs/pdb/mbp.txt b/format_docs/pdb/mbp.txt index 61e1d2d9ee..13959a6381 100644 --- a/format_docs/pdb/mbp.txt +++ b/format_docs/pdb/mbp.txt @@ -118,7 +118,7 @@ EBVS <0x 00 00 00 00> <0x 00 00 00 10> ...(rest of size of DATA block) -<0x FD EA = PAD? ()> +<0x FD EA = PAD? (ýê)> DATA <0x 4 bytes = size of > @@ -155,7 +155,7 @@ EBVS <0x 00 00 00 00> <0x 00 00 00 10> ...(rest of size of DATA block) -<0x FD EA = PAD? ()> +<0x FD EA = PAD? (ýê)> [fi MARK || BOOKMARK] //------------------------------- [if CORRECTION] @@ -174,7 +174,7 @@ EBVS <0x 00 00 00 00> <0x 00 00 00 10> ...(rest of size of DATA block) -<0x FD EA = PAD? ()> +<0x FD EA = PAD? (ýê)> DATA <0x 4 bytes = size of > @@ -246,7 +246,7 @@ EBVS <0x 00 00 00 00> <0x 00 00 00 10> ...(size of DATA block - 30) -<0x FD EA = PAD? ()> +<0x FD EA = PAD? (ýê)> [fi DRAWING] //------------------------------- [next {NOTE,MARK,CORRECTION,DRAWING}] @@ -308,7 +308,7 @@ EBVS ...4 ...4 ...4 -<0x FD EA = PAD? ()> +<0x FD EA = PAD? (ýê)> //-------------------------------------------------------------------- // CATEGORY (if any) @@ -411,4 +411,4 @@ BKMK // END OF FILE // by idleloop@yahoo.com, v0.2.e, 12/2009 -// http://www.angelfire.com/ego2/idleloop \ No newline at end of file +// http://www.angelfire.com/ego2/idleloop diff --git a/recipes/archeowiesci.recipe b/recipes/archeowiesci.recipe new file mode 100644 index 0000000000..3c93d3644f --- /dev/null +++ b/recipes/archeowiesci.recipe @@ -0,0 +1,21 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class Archeowiesci(BasicNewsRecipe): + title = u'Archeowiesci' + __author__ = 'fenuks' + category = 'archeology' + language = 'pl' + cover_url='http://archeowiesci.pl/wp-content/uploads/2011/05/Archeowiesci2-115x115.jpg' + oldest_article = 7 + max_articles_per_feed = 100 + auto_cleanup = True + remove_tags=[dict(name='span', attrs={'class':['post-ratings', 'post-ratings-loading']})] + feeds = [(u'Archeowieści', u'http://archeowiesci.pl/feed/')] + + def parse_feeds (self): + feeds = BasicNewsRecipe.parse_feeds(self) + for feed in feeds: + for article in feed.articles[:]: + if 'subskrypcja' in article.title: + feed.articles.remove(article) + return feeds diff --git a/recipes/cgm_pl.recipe b/recipes/cgm_pl.recipe index eba856ac3a..485cf45245 100644 --- a/recipes/cgm_pl.recipe +++ b/recipes/cgm_pl.recipe @@ -9,9 +9,10 @@ class CGM(BasicNewsRecipe): category = 'music' language = 'pl' use_embedded_content = False + remove_empty_feeds= True max_articles_per_feed = 100 no_stylesheers=True - extra_css = 'div {color:black;} strong {color:black;} span {color:black;} p {color:black;}' + extra_css = 'div {color:black;} strong {color:black;} span {color:black;} p {color:black;} h2 {color:black;}' remove_tags_before=dict(id='mainContent') remove_tags_after=dict(name='div', attrs={'class':'fbContainer'}) remove_tags=[dict(name='div', attrs={'class':'fbContainer'}), @@ -22,10 +23,12 @@ class CGM(BasicNewsRecipe): def preprocess_html(self, soup): - ad=soup.findAll('img') + for item in soup.findAll(style=True): + del item['style'] + ad=soup.findAll('a') for r in ad: - if '/_vault/_article_photos/5841.jpg' in r['src'] or '_vault/_article_photos/5807.jpg' in r['src'] or 'article_photos/5841.jpg' in r['src'] or 'article_photos/5825.jpg' in r['src'] or '_article_photos/5920.jpg' in r['src'] or '_article_photos/5919.jpg' in r['src'] or '_article_photos/5918.jpg' in r['src'] or '_article_photos/5914.jpg' in r['src'] or '_article_photos/5911.jpg' in r['src'] or '_article_photos/5923.jpg' in r['src'] or '_article_photos/5921.jpg' in r['src']: - ad[ad.index(r)].extract() + if 'http://www.hustla.pl' in r['href']: + r.extract() gallery=soup.find('div', attrs={'class':'galleryFlash'}) if gallery: img=gallery.find('embed') diff --git a/recipes/dark_horizons.recipe b/recipes/dark_horizons.recipe new file mode 100644 index 0000000000..a6929136c3 --- /dev/null +++ b/recipes/dark_horizons.recipe @@ -0,0 +1,15 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class AdvancedUserRecipe1317580312(BasicNewsRecipe): + title = u'Dark Horizons' + language = 'en' + __author__ = 'Jaded' + description ='News, images, video clips and reviews of current and upcoming blockbuster films. ' + category = 'movies, tv, news' + oldest_article = 7 + max_articles_per_feed = 100 + cover_url = 'http://a4.sphotos.ak.fbcdn.net/hphotos-ak-ash2/164168_148419801879765_148410081880737_225532_464073_n.jpg' + masthead_url = 'http://www.darkhorizons.com/graphics/2/logo_print.png' + auto_cleanup = True + + feeds = [(u'News', u'http://www.darkhorizons.com/feeds/news.atom'), (u'Features', u'http://www.darkhorizons.com/feeds/features.atom'), (u'Reviews', u'http://www.darkhorizons.com/feeds/reviews.atom')] diff --git a/recipes/descopera.recipe b/recipes/descopera.recipe index 71560c1e0e..adbb518404 100644 --- a/recipes/descopera.recipe +++ b/recipes/descopera.recipe @@ -22,6 +22,10 @@ class Descopera(BasicNewsRecipe): category = 'Ziare,Reviste,Descopera' encoding = 'utf-8' cover_url = 'http://www.descopera.ro/images/header_images/logo.gif' + use_embedded_content = False + + no_stylesheets = True + auto_cleanup = True conversion_options = { 'comments' : description @@ -30,28 +34,6 @@ class Descopera(BasicNewsRecipe): ,'publisher' : publisher } - - keep_only_tags = [ - dict(name='h1', attrs={'style':'font-family: Arial,Helvetica,sans-serif; font-size: 18px; color: rgb(51, 51, 51); font-weight: bold; margin: 10px 0pt; clear: both; float: left;width: 610px;'}) - ,dict(name='div', attrs={'style':'margin-right: 15px; margin-bottom: 15px; float: left;'}) - , dict(name='p', attrs={'id':'itemDescription'}) - ,dict(name='div', attrs={'id':'itemBody'}) - ] - - remove_tags = [ - dict(name='div', attrs={'class':['tools']}) - , dict(name='div', attrs={'class':['share']}) - , dict(name='div', attrs={'class':['category']}) - , dict(name='div', attrs={'id':['comments']}) - ] - - remove_tags_after = [ - dict(name='div', attrs={'id':'comments'}) - ] - feeds = [ (u'Feeds', u'http://www.descopera.ro/rss') ] - - def preprocess_html(self, soup): - return self.adeify_images(soup) diff --git a/recipes/eioba.recipe b/recipes/eioba.recipe new file mode 100644 index 0000000000..14256c5811 --- /dev/null +++ b/recipes/eioba.recipe @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +from calibre.web.feeds.news import BasicNewsRecipe + +class eioba(BasicNewsRecipe): + title = u'eioba' + __author__ = 'fenuks' + cover_url = 'http://www.eioba.org/lay/logo_pl_v3.png' + language = 'pl' + oldest_article = 7 + remove_empty_feeds= True + max_articles_per_feed = 100 + extra_css = '#ctl0_body_Topic {font-weight: bold; font-size:30px;}' + keep_only_tags=[dict(id=['ctl0_body_Topic', 'articleContent'])] + feeds = [(u'Wszyskie kategorie', u'http://feeds.eioba.pl/eioba-pl-top'), + (u'Technologia', u'http://www.eioba.pl/feed/categories/1.xml'), + (u'Nauka', u'http://www.eioba.pl/feed/categories/12.xml'), + (u'Finanse', u'http://www.eioba.pl/feed/categories/7.xml'), + (u'Życie', u'http://www.eioba.pl/feed/categories/5.xml'), + (u'Zainteresowania', u'http://www.eioba.pl/feed/categories/420.xml'), + (u'Społeczeństwo', u'http://www.eioba.pl/feed/categories/8.xml'), + (u'Rozrywka', u'http://www.eioba.pl/feed/categories/10.xml'), + (u'Rożne', u'http://www.eioba.pl/feed/categories/9.xml') + ] diff --git a/recipes/focus_pl.recipe b/recipes/focus_pl.recipe new file mode 100644 index 0000000000..d63af135bc --- /dev/null +++ b/recipes/focus_pl.recipe @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +from calibre.web.feeds.news import BasicNewsRecipe + +class Focus_pl(BasicNewsRecipe): + title = u'Focus.pl' + oldest_article = 15 + max_articles_per_feed = 100 + __author__ = 'fenuks' + language = 'pl' + description ='polish scientific monthly magazine' + category='magazine' + cover_url='' + remove_empty_feeds= True + no_stylesheets=True + remove_tags_before=dict(name='div', attrs={'class':'h2 h2f'}) + remove_tags_after=dict(name='div', attrs={'class':'clear'}) + feeds = [(u'Wszystkie kategorie', u'http://focus.pl.feedsportal.com/c/32992/f/532692/index.rss'), + (u'Nauka', u'http://focus.pl.feedsportal.com/c/32992/f/532693/index.rss'), + (u'Historia', u'http://focus.pl.feedsportal.com/c/32992/f/532694/index.rss'), + (u'Cywilizacja', u'http://focus.pl.feedsportal.com/c/32992/f/532695/index.rss'), + (u'Sport', u'http://focus.pl.feedsportal.com/c/32992/f/532696/index.rss'), + (u'Technika', u'http://focus.pl.feedsportal.com/c/32992/f/532697/index.rss'), + (u'Przyroda', u'http://focus.pl.feedsportal.com/c/32992/f/532698/index.rss'), + (u'Technologie', u'http://focus.pl.feedsportal.com/c/32992/f/532699/index.rss'), + (u'Warto wiedzieć', u'http://focus.pl.feedsportal.com/c/32992/f/532700/index.rss'), + + + +] + + def skip_ad_pages(self, soup): + tag=soup.find(name='a') + if tag: + new_soup=self.index_to_soup(tag['href']+ 'do-druku/1/', raw=True) + return new_soup + + def append_page(self, appendtag): + tag=appendtag.find(name='div', attrs={'class':'arrows'}) + if tag: + nexturl='http://www.focus.pl/'+tag.a['href'] + for rem in appendtag.findAll(name='div', attrs={'class':'klik-nav'}): + rem.extract() + while nexturl: + soup2=self.index_to_soup(nexturl) + nexturl=None + pagetext=soup2.find(name='div', attrs={'class':'txt'}) + tag=pagetext.find(name='div', attrs={'class':'arrows'}) + for r in tag.findAll(name='a'): + if u'Następne' in r.string: + nexturl='http://www.focus.pl/'+r['href'] + for rem in pagetext.findAll(name='div', attrs={'class':'klik-nav'}): + rem.extract() + pos = len(appendtag.contents) + appendtag.insert(pos, pagetext) + + def get_cover_url(self): + soup=self.index_to_soup('http://www.focus.pl/magazyn/') + tag=soup.find(name='div', attrs={'class':'clr fl'}) + if tag: + self.cover_url='http://www.focus.pl/' + tag.a['href'] + return getattr(self, 'cover_url', self.cover_url) + + + def preprocess_html(self, soup): + self.append_page(soup.body) + return soup diff --git a/recipes/gazeta_wyborcza.recipe b/recipes/gazeta_wyborcza.recipe new file mode 100644 index 0000000000..0959ff80a3 --- /dev/null +++ b/recipes/gazeta_wyborcza.recipe @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +from calibre.web.feeds.news import BasicNewsRecipe + +class Gazeta_Wyborcza(BasicNewsRecipe): + title = u'Gazeta Wyborcza' + __author__ = 'fenuks' + cover_url = 'http://bi.gazeta.pl/im/5/10285/z10285445AA.jpg' + language = 'pl' + description ='news from gazeta.pl' + category='newspaper' + INDEX='http://wyborcza.pl' + remove_empty_feeds= True + oldest_article = 3 + max_articles_per_feed = 100 + remove_javascript=True + no_stylesheets=True + remove_tags_before=dict(id='k0') + remove_tags_after=dict(id='banP4') + remove_tags=[dict(name='div', attrs={'class':'rel_box'}), dict(attrs={'class':['date', 'zdjP', 'zdjM', 'pollCont', 'rel_video', 'brand', 'txt_upl']}), dict(name='div', attrs={'id':'footer'})] + feeds = [(u'Kraj', u'http://rss.feedsportal.com/c/32739/f/530266/index.rss'), (u'\u015awiat', u'http://rss.feedsportal.com/c/32739/f/530270/index.rss'), + (u'Wyborcza.biz', u'http://wyborcza.biz/pub/rss/wyborcza_biz_wiadomosci.htm'), + (u'Komentarze', u'http://rss.feedsportal.com/c/32739/f/530312/index.rss'), + (u'Kultura', u'http://rss.gazeta.pl/pub/rss/gazetawyborcza_kultura.xml'), + (u'Nauka', u'http://rss.feedsportal.com/c/32739/f/530269/index.rss'), (u'Opinie', u'http://rss.gazeta.pl/pub/rss/opinie.xml'), (u'Gazeta \u015awi\u0105teczna', u'http://rss.feedsportal.com/c/32739/f/530431/index.rss'), (u'Du\u017cy Format', u'http://rss.feedsportal.com/c/32739/f/530265/index.rss'), (u'Witamy w Polsce', u'http://rss.feedsportal.com/c/32739/f/530476/index.rss'), (u'M\u0119ska Muzyka', u'http://rss.feedsportal.com/c/32739/f/530337/index.rss'), (u'Lata Lec\u0105', u'http://rss.feedsportal.com/c/32739/f/530326/index.rss'), (u'Solidarni z Tybetem', u'http://rss.feedsportal.com/c/32739/f/530461/index.rss'), (u'W pon. - \u017bakowski', u'http://rss.feedsportal.com/c/32739/f/530491/index.rss'), (u'We wt. - Kolenda-Zalewska', u'http://rss.feedsportal.com/c/32739/f/530310/index.rss'), (u'\u015aroda w \u015brod\u0119', u'http://rss.feedsportal.com/c/32739/f/530428/index.rss'), (u'W pi\u0105tek - Olejnik', u'http://rss.feedsportal.com/c/32739/f/530364/index.rss'), (u'Nekrologi', u'http://rss.feedsportal.com/c/32739/f/530358/index.rss') + ] + + def skip_ad_pages(self, soup): + tag=soup.find(name='a', attrs={'class':'btn'}) + if tag: + new_soup=self.index_to_soup(tag['href'], raw=True) + return new_soup + + + def append_page(self, soup, appendtag): + loop=False + tag = soup.find('div', attrs={'id':'Str'}) + if appendtag.find('div', attrs={'id':'Str'}): + nexturl=tag.findAll('a') + appendtag.find('div', attrs={'id':'Str'}).extract() + loop=True + if appendtag.find(id='source'): + appendtag.find(id='source').extract() + while loop: + loop=False + for link in nexturl: + if u'następne' in link.string: + url= self.INDEX + link['href'] + soup2 = self.index_to_soup(url) + pagetext = soup2.find(id='artykul') + pos = len(appendtag.contents) + appendtag.insert(pos, pagetext) + tag = soup2.find('div', attrs={'id':'Str'}) + nexturl=tag.findAll('a') + loop=True + + def gallery_article(self, appendtag): + tag=appendtag.find(id='container_gal') + if tag: + nexturl=appendtag.find(id='gal_btn_next').a['href'] + appendtag.find(id='gal_navi').extract() + while nexturl: + soup2=self.index_to_soup(nexturl) + pagetext=soup2.find(id='container_gal') + nexturl=pagetext.find(id='gal_btn_next') + if nexturl: + nexturl=nexturl.a['href'] + pos = len(appendtag.contents) + appendtag.insert(pos, pagetext) + rem=appendtag.find(id='gal_navi') + if rem: + rem.extract() + + def preprocess_html(self, soup): + self.append_page(soup, soup.body) + if soup.find(id='container_gal'): + self.gallery_article(soup.body) + return soup + + def print_version(self, url): + if 'http://wyborcza.biz/biznes/' not in url: + return url + else: + return url.replace('http://wyborcza.biz/biznes/1', 'http://wyborcza.biz/biznes/2029020') diff --git a/recipes/gram_pl.recipe b/recipes/gram_pl.recipe index 091c0bb1dc..c8655dc9cd 100644 --- a/recipes/gram_pl.recipe +++ b/recipes/gram_pl.recipe @@ -9,8 +9,17 @@ class Gram_pl(BasicNewsRecipe): oldest_article = 8 max_articles_per_feed = 100 no_stylesheets= True + extra_css = 'h2 {font-style: italic; font-size:20px;}' 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')] + + def parse_feeds (self): + feeds = BasicNewsRecipe.parse_feeds(self) + for feed in feeds: + for article in feed.articles[:]: + if 'REKLAMA SKLEP' in article.title.upper() or u'ARTYKUŁ:' in article.title.upper(): + feed.articles.remove(article) + return feeds diff --git a/recipes/icons/archeowiesci.png b/recipes/icons/archeowiesci.png new file mode 100644 index 0000000000..7cf0ee1ff6 Binary files /dev/null and b/recipes/icons/archeowiesci.png differ diff --git a/recipes/icons/dark_horizons.png b/recipes/icons/dark_horizons.png new file mode 100644 index 0000000000..59b9a0654b Binary files /dev/null and b/recipes/icons/dark_horizons.png differ diff --git a/recipes/icons/eioba.png b/recipes/icons/eioba.png new file mode 100644 index 0000000000..9004d28d25 Binary files /dev/null and b/recipes/icons/eioba.png differ diff --git a/recipes/icons/focus_pl.png b/recipes/icons/focus_pl.png new file mode 100644 index 0000000000..4dfd72200c Binary files /dev/null and b/recipes/icons/focus_pl.png differ diff --git a/recipes/icons/gazeta_wyborcza.png b/recipes/icons/gazeta_wyborcza.png new file mode 100644 index 0000000000..9e480cc41d Binary files /dev/null and b/recipes/icons/gazeta_wyborcza.png differ diff --git a/recipes/icons/konflikty_zbrojne.png b/recipes/icons/konflikty_zbrojne.png new file mode 100644 index 0000000000..e8dcceba7c Binary files /dev/null and b/recipes/icons/konflikty_zbrojne.png differ diff --git a/recipes/konflikty_zbrojne.recipe b/recipes/konflikty_zbrojne.recipe new file mode 100644 index 0000000000..7921e98f48 --- /dev/null +++ b/recipes/konflikty_zbrojne.recipe @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +from calibre.web.feeds.news import BasicNewsRecipe + +class Konflikty(BasicNewsRecipe): + title = u'Konflikty Zbrojne' + __author__ = 'fenuks' + cover_url = 'http://www.konflikty.pl/images/tapety_logo.jpg' + language = 'pl' + description ='military news' + category='military, history' + oldest_article = 7 + max_articles_per_feed = 100 + auto_cleanup = True + + feeds = [(u'Aktualności', u'http://www.konflikty.pl/rss_aktualnosci_10.xml'), (u'Artyku\u0142y', u'http://www.konflikty.pl/rss_artykuly_10.xml'), (u'Relacje', u'http://www.konflikty.pl/rss_relacje_10.xml'), (u'Recenzje', u'http://www.konflikty.pl/rss_recenzje_10.xml')] diff --git a/recipes/naczytniki.recipe b/recipes/naczytniki.recipe new file mode 100644 index 0000000000..374c6dd0cb --- /dev/null +++ b/recipes/naczytniki.recipe @@ -0,0 +1,15 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class naczytniki(BasicNewsRecipe): + title = u'naczytniki.pl' + __author__ = 'fenuks' + cover_url = 'http://naczytniki.pl/wp-content/uploads/2010/08/logo_nc28.png' + language = 'pl' + description ='everything about e-readers' + category='readers' + oldest_article = 7 + max_articles_per_feed = 100 + 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')] diff --git a/recipes/nowa_fantastyka.recipe b/recipes/nowa_fantastyka.recipe new file mode 100644 index 0000000000..d8015105f8 --- /dev/null +++ b/recipes/nowa_fantastyka.recipe @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +from calibre.web.feeds.news import BasicNewsRecipe + +class Nowa_Fantastyka(BasicNewsRecipe): + title = u'Nowa Fantastyka' + oldest_article = 7 + __author__ = 'fenuks' + language = 'pl' + description ='site for fantasy readers' + category='fantasy' + max_articles_per_feed = 100 + INDEX='http://www.fantastyka.pl/' + remove_tags_before=dict(attrs={'class':'belka1-tlo-md'}) + #remove_tags_after=dict(name='span', attrs={'class':'naglowek-oceny'}) + remove_tags_after=dict(name='td', attrs={'class':'belka1-bot'}) + remove_tags=[dict(attrs={'class':'avatar2'})] + feeds = [] + + def find_articles(self, url): + articles = [] + soup=self.index_to_soup(url) + tag=soup.find(attrs={'class':'belka1-tlo-m'}) + art=tag.findAll(name='a', attrs={'class':'a-box'}) + for i in art: + title=i.string + url=self.INDEX+i['href'] + #date=soup.find(id='footer').ul.li.string[41:-1] + articles.append({'title' : title, + 'url' : url, + 'date' : '', + 'description' : '' + }) + return articles + + def parse_index(self): + feeds = [] + feeds.append((u"Opowiadania", self.find_articles('http://www.fantastyka.pl/3.html'))) + feeds.append((u"Publicystyka", self.find_articles('http://www.fantastyka.pl/6.html'))) + feeds.append((u"Hype Park", self.find_articles('http://www.fantastyka.pl/9.html'))) + + return feeds + + def get_cover_url(self): + soup = self.index_to_soup('http://www.fantastyka.pl/1.html') + cover=soup.find(name='img', attrs={'class':'okladka'}) + self.cover_url=self.INDEX+ cover['src'] + return getattr(self, 'cover_url', self.cover_url) diff --git a/recipes/tablety_pl.recipe b/recipes/tablety_pl.recipe index 08212fbc66..af317d1b09 100644 --- a/recipes/tablety_pl.recipe +++ b/recipes/tablety_pl.recipe @@ -9,4 +9,6 @@ class Tablety_pl(BasicNewsRecipe): language = 'pl' oldest_article = 8 max_articles_per_feed = 100 + keep_only_tags=[dict(name='header', attrs={'class':'entry-header'}), dict(name='div', attrs={'class':'entry-content clearfix'})] + remove_tags=[dict(name='div', attrs={'class':'snap_nopreview sharing robots-nocontent'}), dict(name='span', attrs={'class':'dsq-postid'})] feeds = [(u'Najnowsze posty', u'http://www.tablety.pl/feed/')] diff --git a/session.vim b/session.vim index b85e21ce8c..b2617c6334 100644 --- a/session.vim +++ b/session.vim @@ -22,7 +22,7 @@ vipy.session.initialize(project_name='calibre', src_dir=src_dir, def recipe_title_callback(raw): return eval(raw.decode('utf-8')).replace(' ', '_') -vipy.session.add_content_browser('.r', ',r', 'Recipe', +vipy.session.add_content_browser('r', 'Recipe', vipy.session.glob_based_iterator(os.path.join(project_dir, 'recipes', '*.recipe')), vipy.session.regexp_based_matcher(r'title\s*=\s*(?P.+)', 'title', recipe_title_callback)) EOFPY diff --git a/src/calibre/devices/kobo/driver.py b/src/calibre/devices/kobo/driver.py index 393b96442b..cdb9e0c4c9 100644 --- a/src/calibre/devices/kobo/driver.py +++ b/src/calibre/devices/kobo/driver.py @@ -8,7 +8,6 @@ __docformat__ = 'restructuredtext en' import os import sqlite3 as sqlite from contextlib import closing - from calibre.devices.usbms.books import BookList from calibre.devices.kobo.books import Book from calibre.devices.kobo.books import ImageWrapper @@ -16,6 +15,7 @@ from calibre.devices.mime import mime_type_ext from calibre.devices.usbms.driver import USBMS, debug_print from calibre import prints from calibre.devices.usbms.books import CollectionsBookList +from calibre.utils.magick.draw import save_cover_data_to class KOBO(USBMS): @@ -53,11 +53,23 @@ class KOBO(USBMS): _('The Kobo supports several collections including ')+\ 'Read, Closed, Im_Reading. ' +\ _('Create tags for automatic management'), - ] + _('Upload covers for books (newer readers)') + + ':::'+_('Normally, the KOBO readers get the cover image from the' + ' ebook file itself. With this option, calibre will send a ' + 'separate cover image to the reader, useful if you ' + 'have modified the cover.'), + _('Upload Black and White Covers') + ] - EXTRA_CUSTOMIZATION_DEFAULT = [', '.join(['tags'])] + EXTRA_CUSTOMIZATION_DEFAULT = [ + ', '.join(['tags']), + True, + True + ] - OPT_COLLECTIONS = 0 + OPT_COLLECTIONS = 0 + OPT_UPLOAD_COVERS = 1 + OPT_UPLOAD_GRAYSCALE_COVERS = 2 def initialize(self): USBMS.initialize(self) @@ -593,7 +605,7 @@ class KOBO(USBMS): raise else: connection.commit() - debug_print(' Commit: Reset ReadStatus list') + # debug_print(' Commit: Reset ReadStatus list') cursor.close() @@ -616,7 +628,7 @@ class KOBO(USBMS): raise else: connection.commit() - debug_print(' Commit: Setting ReadStatus List') + # debug_print(' Commit: Setting ReadStatus List') cursor.close() def reset_favouritesindex(self, connection, oncard): @@ -635,7 +647,7 @@ class KOBO(USBMS): raise else: connection.commit() - debug_print(' Commit: Reset FavouritesIndex list') + # debug_print(' Commit: Reset FavouritesIndex list') def set_favouritesindex(self, connection, ContentID): cursor = connection.cursor() @@ -650,7 +662,7 @@ class KOBO(USBMS): raise else: connection.commit() - debug_print(' Commit: Set FavouritesIndex') + # debug_print(' Commit: Set FavouritesIndex') def update_device_database_collections(self, booklists, collections_attributes, oncard): # Only process categories in this list @@ -702,9 +714,9 @@ class KOBO(USBMS): # Process any collections that exist for category, books in collections.items(): if category in supportedcategories: - debug_print("Category: ", category, " id = ", readstatuslist.get(category)) + # debug_print("Category: ", category, " id = ", readstatuslist.get(category)) for book in books: - debug_print(' Title:', book.title, 'category: ', category) + # debug_print(' Title:', book.title, 'category: ', category) if category not in book.device_collections: book.device_collections.append(category) @@ -763,3 +775,93 @@ class KOBO(USBMS): collections_attributes = [] self.update_device_database_collections(booklist, collections_attributes, oncard) + def upload_cover(self, path, filename, metadata, filepath): + ''' + Upload book cover to the device. Default implementation does nothing. + + :param path: The full path to the directory where the associated book is located. + :param filename: The name of the book file without the extension. + :param metadata: metadata belonging to the book. Use metadata.thumbnail + for cover + :param filepath: The full path to the ebook file + + ''' + + opts = self.settings() + if not opts.extra_customization[self.OPT_UPLOAD_COVERS]: + # Building thumbnails disabled + debug_print('KOBO: not uploading cover') + return + + if not opts.extra_customization[self.OPT_UPLOAD_GRAYSCALE_COVERS]: + uploadgrayscale = False + else: + uploadgrayscale = True + + debug_print('KOBO: uploading cover') + try: + self._upload_cover(path, filename, metadata, filepath, uploadgrayscale) + except: + debug_print('FAILED to upload cover', filepath) + + def _upload_cover(self, path, filename, metadata, filepath, uploadgrayscale): + if metadata.cover: + cover = self.normalize_path(metadata.cover.replace('/', os.sep)) + + if os.path.exists(cover): + # Get ContentID for Selected Book + extension = os.path.splitext(filepath)[1] + ContentType = self.get_content_type_from_extension(extension) if extension != '' else self.get_content_type_from_path(filepath) + ContentID = self.contentid_from_path(filepath, ContentType) + + with closing(sqlite.connect(self.normalize_path(self._main_prefix + + '.kobo/KoboReader.sqlite'))) as connection: + + # return bytestrings if the content cannot the decoded as unicode + connection.text_factory = lambda x: unicode(x, "utf-8", "ignore") + + cursor = connection.cursor() + t = (ContentID,) + cursor.execute('select ImageId from Content where BookID is Null and ContentID = ?', t) + result = cursor.fetchone() + if result is None: + debug_print("No rows exist in the database - cannot upload") + return + else: + ImageID = result[0] +# debug_print("ImageId: ", result[0]) + + cursor.close() + + if ImageID != None: + path_prefix = '.kobo/images/' + path = self._main_prefix + path_prefix + ImageID + + file_endings = {' - iPhoneThumbnail.parsed':(103,150), + ' - bbMediumGridList.parsed':(93,135), + ' - NickelBookCover.parsed':(500,725), + ' - N3_LIBRARY_FULL.parsed':(355,530), + ' - N3_LIBRARY_GRID.parsed':(149,233), + ' - N3_LIBRARY_LIST.parsed':(60,90), + ' - N3_SOCIAL_CURRENTREAD.parsed':(120,186)} + + for ending, resize in file_endings.items(): + fpath = path + ending + fpath = self.normalize_path(fpath.replace('/', os.sep)) + + if os.path.exists(fpath): + with open(cover, 'rb') as f: + data = f.read() + + # Return the data resized and in Grayscale if + # required + data = save_cover_data_to(data, 'dummy.jpg', + grayscale=uploadgrayscale, + resize_to=resize, return_data=True) + + with open(fpath, 'wb') as f: + f.write(data) + + else: + debug_print("ImageID could not be retreived from the database") + diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 7d4a39fe4e..6676bc30e1 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -100,7 +100,7 @@ gprefs.defaults['default_author_link'] = 'http://en.wikipedia.org/w/index.php?se gprefs.defaults['preserve_date_on_ctl'] = True gprefs.defaults['cb_fullscreen'] = False gprefs.defaults['worker_max_time'] = 0 - +gprefs.defaults['show_files_after_save'] = True # }}} NONE = QVariant() #: Null value to return from the data function of item models diff --git a/src/calibre/gui2/actions/catalog.py b/src/calibre/gui2/actions/catalog.py index 9b95f5e8d0..5287d0d9b3 100644 --- a/src/calibre/gui2/actions/catalog.py +++ b/src/calibre/gui2/actions/catalog.py @@ -18,11 +18,15 @@ class GenerateCatalogAction(InterfaceAction): name = 'Generate Catalog' action_spec = (_('Create catalog'), 'catalog.png', 'Catalog builder', ()) - dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device']) + dont_add_to = frozenset(['context-menu-device']) def genesis(self): self.qaction.triggered.connect(self.generate_catalog) + def location_selected(self, loc): + enabled = loc == 'library' + self.qaction.setEnabled(enabled) + def generate_catalog(self): rows = self.gui.library_view.selectionModel().selectedRows() if not rows or len(rows) < 2: diff --git a/src/calibre/gui2/actions/choose_library.py b/src/calibre/gui2/actions/choose_library.py index 657d150dbb..01430f14f0 100644 --- a/src/calibre/gui2/actions/choose_library.py +++ b/src/calibre/gui2/actions/choose_library.py @@ -138,7 +138,7 @@ class ChooseLibraryAction(InterfaceAction): name = 'Choose Library' action_spec = (_('Choose Library'), 'lt.png', _('Choose calibre library to work with'), None) - dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device']) + dont_add_to = frozenset(['context-menu-device']) action_add_menu = True action_menu_clone_qaction = _('Switch/create library...') diff --git a/src/calibre/gui2/actions/convert.py b/src/calibre/gui2/actions/convert.py index 0dbbdaf1f3..fc1d166685 100644 --- a/src/calibre/gui2/actions/convert.py +++ b/src/calibre/gui2/actions/convert.py @@ -20,7 +20,7 @@ class ConvertAction(InterfaceAction): name = 'Convert Books' action_spec = (_('Convert books'), 'convert.png', None, _('C')) - dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device']) + dont_add_to = frozenset(['context-menu-device']) action_type = 'current' action_add_menu = True diff --git a/src/calibre/gui2/actions/copy_to_library.py b/src/calibre/gui2/actions/copy_to_library.py index fdcce87342..383b3e54d8 100644 --- a/src/calibre/gui2/actions/copy_to_library.py +++ b/src/calibre/gui2/actions/copy_to_library.py @@ -127,7 +127,7 @@ class CopyToLibraryAction(InterfaceAction): action_spec = (_('Copy to library'), 'lt.png', _('Copy selected books to the specified library'), None) popup_type = QToolButton.InstantPopup - dont_add_to = frozenset(['toolbar-device', 'context-menu-device']) + dont_add_to = frozenset(['context-menu-device']) action_type = 'current' action_add_menu = True diff --git a/src/calibre/gui2/actions/device.py b/src/calibre/gui2/actions/device.py index 483b398943..4d96669972 100644 --- a/src/calibre/gui2/actions/device.py +++ b/src/calibre/gui2/actions/device.py @@ -24,7 +24,7 @@ class ShareConnMenu(QMenu): # {{{ config_email = pyqtSignal() toggle_server = pyqtSignal() - dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device']) + dont_add_to = frozenset(['context-menu-device']) def __init__(self, parent=None): QMenu.__init__(self, parent) diff --git a/src/calibre/gui2/actions/next_match.py b/src/calibre/gui2/actions/next_match.py index 8e076655a9..c604dc635c 100644 --- a/src/calibre/gui2/actions/next_match.py +++ b/src/calibre/gui2/actions/next_match.py @@ -11,7 +11,7 @@ class NextMatchAction(InterfaceAction): name = 'Move to next highlighted book' action_spec = (_('Move to next match'), 'arrow-down.png', _('Move to next highlighted match'), [_('N'), _('F3')]) - dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device']) + dont_add_to = frozenset(['context-menu-device']) action_type = 'current' def genesis(self): diff --git a/src/calibre/gui2/actions/open.py b/src/calibre/gui2/actions/open.py index a66f68eee5..fc78df5f33 100644 --- a/src/calibre/gui2/actions/open.py +++ b/src/calibre/gui2/actions/open.py @@ -13,7 +13,7 @@ class OpenFolderAction(InterfaceAction): name = 'Open Folder' action_spec = (_('Open containing folder'), 'document_open.png', None, _('O')) - dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device']) + dont_add_to = frozenset(['context-menu-device']) action_type = 'current' def genesis(self): diff --git a/src/calibre/gui2/actions/random.py b/src/calibre/gui2/actions/random.py index f30b1e0464..03d1dedd82 100644 --- a/src/calibre/gui2/actions/random.py +++ b/src/calibre/gui2/actions/random.py @@ -16,11 +16,15 @@ class PickRandomAction(InterfaceAction): name = 'Pick Random Book' action_spec = (_('Pick a random book'), 'random.png', 'Select a random book from your calibre library', ()) - dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device']) + dont_add_to = frozenset(['context-menu-device']) def genesis(self): self.qaction.triggered.connect(self.pick_random) + def location_selected(self, loc): + enabled = loc == 'library' + self.qaction.setEnabled(enabled) + def pick_random(self): pick = random.randint(0, self.gui.library_view.model().rowCount(None)) self.gui.library_view.set_current_row(pick) diff --git a/src/calibre/gui2/actions/save_to_disk.py b/src/calibre/gui2/actions/save_to_disk.py index 73f4367abc..b2bb8fb547 100644 --- a/src/calibre/gui2/actions/save_to_disk.py +++ b/src/calibre/gui2/actions/save_to_disk.py @@ -11,8 +11,8 @@ from functools import partial from PyQt4.Qt import QMenu, pyqtSignal from calibre.utils.config import prefs -from calibre.gui2 import error_dialog, Dispatcher, \ - choose_dir, warning_dialog, open_local_file +from calibre.gui2 import (error_dialog, Dispatcher, gprefs, + choose_dir, warning_dialog, open_local_file) from calibre.gui2.actions import InterfaceAction from calibre.ebooks import BOOK_EXTENSIONS @@ -141,7 +141,8 @@ class SaveToDiskAction(InterfaceAction): _('Could not save some books') + ', ' + _('Click the show details button to see which ones.'), u'\n\n'.join(failures), show=True) - open_local_file(path) + if gprefs['show_files_after_save']: + open_local_file(path) def books_saved(self, job): if job.failed: diff --git a/src/calibre/gui2/actions/show_book_details.py b/src/calibre/gui2/actions/show_book_details.py index 1c28a08a79..2ab1e19edd 100644 --- a/src/calibre/gui2/actions/show_book_details.py +++ b/src/calibre/gui2/actions/show_book_details.py @@ -15,7 +15,7 @@ class ShowBookDetailsAction(InterfaceAction): name = 'Show Book Details' action_spec = (_('Show book details'), 'dialog_information.png', None, _('I')) - dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device']) + dont_add_to = frozenset(['context-menu-device']) action_type = 'current' def genesis(self): diff --git a/src/calibre/gui2/actions/show_quickview.py b/src/calibre/gui2/actions/show_quickview.py index 4f7bbc0473..b07b05af66 100644 --- a/src/calibre/gui2/actions/show_quickview.py +++ b/src/calibre/gui2/actions/show_quickview.py @@ -14,7 +14,7 @@ class ShowQuickviewAction(InterfaceAction): name = 'Show quickview' action_spec = (_('Show quickview'), 'search.png', None, _('Q')) - dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device']) + dont_add_to = frozenset(['context-menu-device']) action_type = 'current' current_instance = None diff --git a/src/calibre/gui2/actions/tweak_epub.py b/src/calibre/gui2/actions/tweak_epub.py index d3924e7cd3..d5ee346d31 100755 --- a/src/calibre/gui2/actions/tweak_epub.py +++ b/src/calibre/gui2/actions/tweak_epub.py @@ -17,7 +17,7 @@ class TweakEpubAction(InterfaceAction): action_spec = (_('Tweak ePub'), 'trim.png', _('Make small changes to ePub format books'), _('T')) - dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device']) + dont_add_to = frozenset(['context-menu-device']) action_type = 'current' def genesis(self): diff --git a/src/calibre/gui2/dialogs/check_library.py b/src/calibre/gui2/dialogs/check_library.py index d87ad7041f..1705839bb4 100644 --- a/src/calibre/gui2/dialogs/check_library.py +++ b/src/calibre/gui2/dialogs/check_library.py @@ -310,7 +310,7 @@ class CheckLibraryDialog(QDialog): tl = Item() tl.setText(0, h) - if fixable: + if fixable and list: tl.setText(1, _('(fixable)')) tl.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable) tl.setCheckState(1, False) diff --git a/src/calibre/gui2/preferences/saving.py b/src/calibre/gui2/preferences/saving.py index e4b6a33917..bd5fcbb078 100644 --- a/src/calibre/gui2/preferences/saving.py +++ b/src/calibre/gui2/preferences/saving.py @@ -12,6 +12,7 @@ from calibre.gui2.preferences import ConfigWidgetBase, test_widget, \ from calibre.gui2.preferences.saving_ui import Ui_Form from calibre.utils.config import ConfigProxy from calibre.library.save_to_disk import config +from calibre.gui2 import gprefs class ConfigWidget(ConfigWidgetBase, Ui_Form): @@ -24,6 +25,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): for x in ('asciiize', 'update_metadata', 'save_cover', 'write_opf', 'replace_whitespace', 'to_lowercase', 'formats', 'timefmt'): r(x, self.proxy) + r('show_files_after_save', gprefs) self.save_template.changed_signal.connect(self.changed_signal.emit) diff --git a/src/calibre/gui2/preferences/saving.ui b/src/calibre/gui2/preferences/saving.ui index e4f5aaeb47..14619b7964 100644 --- a/src/calibre/gui2/preferences/saving.ui +++ b/src/calibre/gui2/preferences/saving.ui @@ -95,6 +95,13 @@ </property> </widget> </item> + <item row="4" column="0" colspan="2"> + <widget class="QCheckBox" name="opt_show_files_after_save"> + <property name="text"> + <string>&Show files in file browser after saving to disk</string> + </property> + </widget> + </item> </layout> </widget> <customwidgets> diff --git a/src/calibre/gui2/preferences/toolbar.py b/src/calibre/gui2/preferences/toolbar.py index 1f62336de7..7a2cfdcff4 100644 --- a/src/calibre/gui2/preferences/toolbar.py +++ b/src/calibre/gui2/preferences/toolbar.py @@ -231,6 +231,8 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): def genesis(self, gui): self.models = {} + self.what.addItem(_('Click to choose toolbar or menu to customize'), + 'blank') for key, text in self.LOCATIONS: self.what.addItem(text, key) all_model = AllModel(key, gui) @@ -247,8 +249,14 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): def what_changed(self, idx): key = unicode(self.what.itemData(idx).toString()) - self.all_actions.setModel(self.models[key][0]) - self.current_actions.setModel(self.models[key][1]) + if key == 'blank': + self.actions_widget.setVisible(False) + self.spacer_widget.setVisible(True) + else: + self.actions_widget.setVisible(True) + self.spacer_widget.setVisible(False) + self.all_actions.setModel(self.models[key][0]) + self.current_actions.setModel(self.models[key][1]) def add_action(self, *args): x = self.all_actions.selectionModel().selectedIndexes() diff --git a/src/calibre/gui2/preferences/toolbar.ui b/src/calibre/gui2/preferences/toolbar.ui index a364d067c3..c8ff4977eb 100644 --- a/src/calibre/gui2/preferences/toolbar.ui +++ b/src/calibre/gui2/preferences/toolbar.ui @@ -13,16 +13,19 @@ <property name="windowTitle"> <string>Form</string> </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0" colspan="5"> - <widget class="QComboBox" name="what"> - <property name="font"> - <font> - <pointsize>20</pointsize> - <weight>75</weight> - <bold>true</bold> - </font> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string><p>The toolbar in calibre is different depending on whether a device is connected or not. Choose <b>which toolbar</b> you would like to customize:</string> </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="what"> <property name="toolTip"> <string>Choose the toolbar to customize</string> </property> @@ -34,132 +37,59 @@ </property> </widget> </item> - <item row="2" column="0" colspan="2"> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>A&vailable actions</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QWidget" name="actions_widget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="margin"> + <number>0</number> + </property> <item> - <widget class="QListView" name="all_actions"> - <property name="selectionMode"> - <enum>QAbstractItemView::MultiSelection</enum> - </property> - <property name="iconSize"> - <size> - <width>32</width> - <height>32</height> - </size> - </property> - <property name="spacing"> - <number>10</number> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item row="2" column="2"> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <item> - <widget class="QToolButton" name="add_action_button"> - <property name="toolTip"> - <string>Add selected actions to toolbar</string> - </property> - <property name="text"> - <string>...</string> - </property> - <property name="icon"> - <iconset resource="../../../../resources/images.qrc"> - <normaloff>:/images/forward.png</normaloff>:/images/forward.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QToolButton" name="remove_action_button"> - <property name="toolTip"> - <string>Remove selected actions from toolbar</string> - </property> - <property name="text"> - <string>...</string> - </property> - <property name="icon"> - <iconset resource="../../../../resources/images.qrc"> - <normaloff>:/images/back.png</normaloff>:/images/back.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>24</width> - <height>24</height> - </size> - </property> - </widget> - </item> - </layout> - </item> - <item row="2" column="3" colspan="2"> - <widget class="QGroupBox" name="groupBox_2"> - <property name="title"> - <string>&Current actions</string> - </property> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QListView" name="current_actions"> - <property name="selectionMode"> - <enum>QAbstractItemView::MultiSelection</enum> - </property> - <property name="iconSize"> - <size> - <width>32</width> - <height>32</height> - </size> - </property> - <property name="spacing"> - <number>10</number> - </property> - <property name="wordWrap"> - <bool>true</bool> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>A&vailable actions</string> </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QListView" name="all_actions"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>100</verstretch> + </sizepolicy> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::MultiSelection</enum> + </property> + <property name="iconSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="spacing"> + <number>10</number> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> </widget> </item> <item> - <layout class="QVBoxLayout" name="verticalLayout_4"> + <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <widget class="QToolButton" name="action_up_button"> + <widget class="QToolButton" name="add_action_button"> <property name="toolTip"> - <string>Move selected action up</string> + <string>Add selected actions to toolbar</string> </property> <property name="text"> <string>...</string> </property> <property name="icon"> <iconset resource="../../../../resources/images.qrc"> - <normaloff>:/images/arrow-up.png</normaloff>:/images/arrow-up.png</iconset> + <normaloff>:/images/forward.png</normaloff>:/images/forward.png</iconset> </property> <property name="iconSize"> <size> @@ -170,10 +100,13 @@ </widget> </item> <item> - <spacer name="verticalSpacer_2"> + <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> @@ -183,16 +116,16 @@ </spacer> </item> <item> - <widget class="QToolButton" name="action_down_button"> + <widget class="QToolButton" name="remove_action_button"> <property name="toolTip"> - <string>Move selected action down</string> + <string>Remove selected actions from toolbar</string> </property> <property name="text"> <string>...</string> </property> <property name="icon"> <iconset resource="../../../../resources/images.qrc"> - <normaloff>:/images/arrow-down.png</normaloff>:/images/arrow-down.png</iconset> + <normaloff>:/images/back.png</normaloff>:/images/back.png</iconset> </property> <property name="iconSize"> <size> @@ -200,24 +133,124 @@ <height>24</height> </size> </property> - <property name="shortcut"> - <string>Ctrl+S</string> - </property> </widget> </item> </layout> </item> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>&Current actions</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QListView" name="current_actions"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>100</verstretch> + </sizepolicy> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::MultiSelection</enum> + </property> + <property name="iconSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="spacing"> + <number>10</number> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QToolButton" name="action_up_button"> + <property name="toolTip"> + <string>Move selected action up</string> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="icon"> + <iconset resource="../../../../resources/images.qrc"> + <normaloff>:/images/arrow-up.png</normaloff>:/images/arrow-up.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QToolButton" name="action_down_button"> + <property name="toolTip"> + <string>Move selected action down</string> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="icon"> + <iconset resource="../../../../resources/images.qrc"> + <normaloff>:/images/arrow-down.png</normaloff>:/images/arrow-down.png</iconset> + </property> + <property name="iconSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + <property name="shortcut"> + <string>Ctrl+S</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> </layout> </widget> </item> - <item row="1" column="0" colspan="5"> - <widget class="QLabel" name="label"> - <property name="text"> - <string><p>The toolbar in calibre is different depending on whether a device is connected or not. To customize the toolbar when a device is connected as well as customizing right click menus, <b>click the dropdown above</b> and select which toolbar/menu you want to customize.</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> + <item> + <widget class="QWidget" name="spacer_widget" native="true"> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>224</height> + </size> + </property> + </spacer> + </item> + </layout> </widget> </item> </layout> diff --git a/src/calibre/gui2/store/stores/libri_de_plugin.py b/src/calibre/gui2/store/stores/libri_de_plugin.py index 912ae668e8..a83353523e 100644 --- a/src/calibre/gui2/store/stores/libri_de_plugin.py +++ b/src/calibre/gui2/store/stores/libri_de_plugin.py @@ -24,7 +24,7 @@ class LibreDEStore(BasicStoreConfig, StorePlugin): def open(self, parent=None, detail_item=None, external=False): url = 'http://ad.zanox.com/ppc/?18817073C15644254T' - url_details = ('http://ad.zanox.com/ppc/?18848208C1197627693T&ULP=[[' + url_details = ('http://ad.zanox.com/ppc/?18817073C15644254T&ULP=[[' 'http://www.libri.de/shop/action/productDetails?artiId={0}]]') if external or self.config.get('open_external', False): diff --git a/src/calibre/library/server/base.py b/src/calibre/library/server/base.py index 69322512a0..d065ddc926 100644 --- a/src/calibre/library/server/base.py +++ b/src/calibre/library/server/base.py @@ -112,8 +112,12 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache, self.opts = opts self.embedded = embedded self.state_callback = None - self.max_cover_width, self.max_cover_height = \ + try: + self.max_cover_width, self.max_cover_height = \ map(int, self.opts.max_cover.split('x')) + except: + self.max_cover_width = 1200 + self.max_cover_height = 1600 path = P('content_server') self.build_time = fromtimestamp(os.stat(path).st_mtime) self.default_cover = open(P('content_server/default_cover.jpg'), 'rb').read() diff --git a/src/calibre/utils/magick/draw.py b/src/calibre/utils/magick/draw.py index 1e854b0f56..e4163743d9 100644 --- a/src/calibre/utils/magick/draw.py +++ b/src/calibre/utils/magick/draw.py @@ -47,7 +47,8 @@ def normalize_format_name(fmt): return fmt def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None, - return_data=False, compression_quality=90, minify_to=None): + return_data=False, compression_quality=90, minify_to=None, + grayscale=False): ''' Saves image in data to path, in the format specified by the path extension. Removes any transparency. If there is no transparency and no @@ -60,7 +61,8 @@ def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None, compression (lossless). :param bgcolor: The color for transparent pixels. Must be specified in hex. :param resize_to: A tuple (width, height) or None for no resizing - :param minify_to: A tuple (width, height) to specify target size. The image + :param minify_to: A tuple (width, height) to specify maximum target size. + :param grayscale: If True, the image is grayscaled will be resized to fit into this target size. If None the value from the tweak is used. @@ -71,6 +73,10 @@ def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None, fmt = os.path.splitext(path)[1] fmt = normalize_format_name(fmt[1:]) + if grayscale: + img.type = "GrayscaleType" + changed = True + if resize_to is not None: img.size = (resize_to[0], resize_to[1]) changed = True