From 5bce3d10d3c53ab5952c31799bb7eb6fe974eeab Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 16 Jan 2010 21:15:23 -0700 Subject: [PATCH 1/3] New recipe for Joop by kwetal --- resources/images/news/joop.png | Bin 0 -> 395 bytes resources/images/news/nrcnext.png | Bin 0 -> 1723 bytes resources/quick_start.epub | Bin 0 -> 14164 bytes resources/recipes/fokkeensukke.recipe | 83 +++++++++++--------- resources/recipes/joop.recipe | 91 ++++++++++++++++++++++ resources/recipes/ncrnext.recipe | 106 ++++++++++++++------------ 6 files changed, 195 insertions(+), 85 deletions(-) create mode 100644 resources/images/news/joop.png create mode 100644 resources/images/news/nrcnext.png create mode 100644 resources/quick_start.epub create mode 100644 resources/recipes/joop.recipe diff --git a/resources/images/news/joop.png b/resources/images/news/joop.png new file mode 100644 index 0000000000000000000000000000000000000000..0ea5e422e10e371a28e69249c24919b06d651df3 GIT binary patch literal 395 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg4Mgd_Bv84~+iU3XF_H=O!u{gbT zvSraB2Ladk{tJ&hBpL0R4zf=4;wqJN>O0iwlW=N^Q!$s5@P-V@i+mcw4GUT{>ntw+ zT~_~JDlqgZ34=Xs%!6+OQw`j6dz3Z@r#uG*dyTVqSa4oVeW+ zwuWuixopuVdg0%1hy7yQx?N76ZNjtPuH1I9$*@hM%j2?0gNmoeBMHHSrLi){cji9y zpSqS|!!@P{yYhCc+Ud5|GaoY8!(XuO0KeSqgxz=Vv0KRS9Tz#3%r&>~vfP4I%Q@?= zWiz-fz8Kmtr+(S4b%KIDhI@E_-B^|MbFT_V(>F1**}RWGO5FcEqyF4_Gjk@Fmb-Pw l3oKH;87{v4_MXoR@d>ATEz_C04gf=n!PC{xWt~$(698N$oH_si literal 0 HcmV?d00001 diff --git a/resources/images/news/nrcnext.png b/resources/images/news/nrcnext.png new file mode 100644 index 0000000000000000000000000000000000000000..13497559257329a06ee962335bc9e47de7668062 GIT binary patch literal 1723 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 literal 0 HcmV?d00001 diff --git a/resources/recipes/fokkeensukke.recipe b/resources/recipes/fokkeensukke.recipe index 3ddbe1cfe5..76a4aa39b9 100644 --- a/resources/recipes/fokkeensukke.recipe +++ b/resources/recipes/fokkeensukke.recipe @@ -1,23 +1,29 @@ -#!/usr/bin/python from calibre.web.feeds.news import BasicNewsRecipe -from calibre.ebooks.BeautifulSoup import Tag +from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag class FokkeEnSukkeRecipe(BasicNewsRecipe) : __license__ = 'GPL v3' __author__ = 'kwetal' language = 'nl' - description = u'Popular Dutch daily cartoon Fokke en Sukke' + country = 'NL' + version = 2 title = u'Fokke en Sukke' - no_stylesheets = True - # For reasons unknown to me the extra css is, on the cartoon pages, inserted in the and not in the . My reader (Sony PRS-600) has a serious issue - # with that: it treats it as content and displays it as is. Setting this property to empty solves this for me. - template_css = '' - INDEX = u'http://foksuk.nl' + publisher = u'Reid, Geleijnse & Van Tol' + category = u'News, Cartoons' + description = u'Popular Dutch daily cartoon Fokke en Sukke' - # This cover is not as nice as it could be, needs some work - #cover_url = 'http://foksuk.nl/content/wysiwyg/simpleimages/image350.gif' + conversion_options = {'comments': description, 'language': language, 'publisher': publisher} + + no_stylesheets = True + extra_css = ''' + body{font-family: verdana, arial, helvetica, geneva, sans-serif ; margin: 0em; padding: 0em;} + div.title {text-align: center; margin-bottom: 1em;} + ''' + + INDEX = u'http://foksuk.nl' + cover_url = 'http://foksuk.nl/content/wysiwyg/simpleimages/image350.gif' keep_only_tags = [dict(name='div', attrs={'class' : 'cartoon'})] @@ -31,15 +37,14 @@ class FokkeEnSukkeRecipe(BasicNewsRecipe) : links = index.findAll('a') maxIndex = len(links) - 1 articles = [] - for i in range(len(links)) : - # The first link does not interest us, as it points to no cartoon. A begin_at parameter in the range() function would be nice. - if i == 0 : - continue - - # There can be more than one cartoon for a given day (currently either one or two). If there's only one, there is just a link with the dayname. - # If there are two, there are three links in sequence: dayname 1 2. In that case we're interested in the last two. + for i in range(1, len(links)) : + # There can be more than one cartoon for a given day (currently either one or two). + # If there's only one, there is just a link with the dayname. + # If there are two, there are three links in sequence: dayname 1 2. + # In that case we're interested in the last two. if links[i].renderContents() in dayNames : - # If the link is not in daynames, we processed it already, but if it is, let's see if the next one has '1' as content + # If the link is not in daynames, we processed it already, but if it is, let's see + # if the next one has '1' as content if (i + 1 <= maxIndex) and (links[i + 1].renderContents() == '1') : # Got you! Add it to the list article = {'title' : links[i].renderContents() + ' 1', 'date' : u'', 'url' : self.INDEX + links[i + 1]['href'], 'description' : ''} @@ -59,29 +64,31 @@ class FokkeEnSukkeRecipe(BasicNewsRecipe) : return [[week, articles]] def preprocess_html(self, soup) : - # This method is called for every page, be it cartoon or TOC. We need to process each in their own way cartoon = soup.find('div', attrs={'class' : 'cartoon'}) - if cartoon : - # It is a cartoon. Extract the title. - title = '' - img = soup.find('img', attrs = {'alt' : True}) - if img : - title = img['alt'] - # Using the 'extra_css' displays it in the and not in the . See comment at the top of this class. Setting the style this way solves that. - tag = Tag(soup, 'div', [('style', 'text-align: center; margin-bottom: 8px')]) - tag.insert(0, title) - cartoon.insert(0, tag) + title = '' + img = soup.find('img', attrs = {'alt' : True}) + if img : + title = img['alt'] - # I have not quite worked out why, but we have to throw out this part of the page. It contains the very same index we processed earlier, - # and Calibre does not like that too much. As far as I can tell it goes into recursion and the result is an empty eBook. - select = cartoon.find('div', attrs={'class' : 'selectcartoon'}) - if select : - select.extract() + tag = Tag(soup, 'div', [('class', 'title')]) + tag.insert(0, title) + cartoon.insert(0, tag) - return cartoon - else : - # It is a TOC. Just return the whole lot. - return soup + # We only want the cartoon, so throw out the index + select = cartoon.find('div', attrs={'class' : 'selectcartoon'}) + if select : + select.extract() + + freshSoup = self.getFreshSoup(soup) + freshSoup.body.append(cartoon) + + return freshSoup + + def getFreshSoup(self, oldSoup): + freshSoup = BeautifulSoup('') + if oldSoup.head.title: + freshSoup.head.title.append(self.tag_to_string(oldSoup.head.title)) + return freshSoup diff --git a/resources/recipes/joop.recipe b/resources/recipes/joop.recipe new file mode 100644 index 0000000000..a913328b9b --- /dev/null +++ b/resources/recipes/joop.recipe @@ -0,0 +1,91 @@ +from calibre.web.feeds.news import BasicNewsRecipe +from calibre.ebooks.BeautifulSoup import Tag +import re + +class JoopRecipe(BasicNewsRecipe): + __license__ = 'GPL v3' + __author__ = 'kwetal' + language = 'nl' + country = 'NL' + version = 1 + + title = u'Joop' + publisher = u'Vara' + category = u'News, Politics, Discussion' + description = u'Political blog from the Netherlands' + + oldest_article = 7 + max_articles_per_feed = 100 + use_embedded_content = False + + no_stylesheets = True + remove_javascript = True + + keep_only_tags = [] + keep_only_tags.append(dict(name = 'div', attrs = {'class': 'author_head clearfix photo'})) + keep_only_tags.append(dict(name = 'h2', attrs = {'class': 'columnhead smallline'})) + keep_only_tags.append(dict(name = 'div', attrs = {'class': re.compile('article.*')})) + + extra_css = ''' + body {font-family: verdana, arial, helvetica, geneva, sans-serif;} + img {margin-right: 0.4em;} + h3 {font-size: medium; font-style: italic; font-weight: normal;} + h2 {font-size: xx-large; font-weight: bold} + sub {color: #666666; font-size: x-small; font-weight: normal;} + div.joop_byline {font-size: large} + div.joop_byline_job {font-size: small; color: #696969;} + div.joop_date {font-size: x-small; font-style: italic; margin-top: 0.6em} + ''' + + INDEX = 'http://www.joop.nl' + + conversion_options = {'comments': description, 'tags': category, 'language': language, + 'publisher': publisher} + + def parse_index(self): + sections = ['Politiek', 'Wereld', 'Economie', 'Groen', 'Media', 'Leven', 'Show', 'Opinies'] + soup = self.index_to_soup(self.INDEX) + answer = [] + + div = soup.find('div', attrs = {'id': 'footer'}) + for section in sections: + articles = [] + h2 = div.find(lambda tag: tag.name == 'h2' and tag.renderContents() == section) + if h2: + ul = h2.findNextSibling('ul', 'linklist') + if ul: + for li in ul.findAll('li'): + title = self.tag_to_string(li.a) + url = self.INDEX + li.a['href'] + articles.append({'title': title, 'date': None, 'url': url, 'description': ''}) + + answer.append((section, articles)) + + return answer + + def preprocess_html(self, soup): + div = soup.find('div', 'author_head clearfix photo') + if div: + h2 = soup.find('h2') + if h2: + h2.name = 'div' + h2['class'] = 'joop_byline' + span = h2.find('span') + if span: + span.name = 'div' + span['class'] = 'joop_byline_job' + div.replaceWith(h2) + + h2 = soup.find('h2', attrs = {'class': 'columnhead smallline'}) + if h2: + txt = None + span = h2.find('span', 'info') + if span: + txt = span.find(text = True) + div = Tag(soup, 'div', attrs = [('class', 'joop_date')]) + div.append(txt) + h2.replaceWith(div) + + return soup + + diff --git a/resources/recipes/ncrnext.recipe b/resources/recipes/ncrnext.recipe index d8a51e62c8..e03da301fa 100644 --- a/resources/recipes/ncrnext.recipe +++ b/resources/recipes/ncrnext.recipe @@ -1,29 +1,38 @@ from calibre.web.feeds.news import BasicNewsRecipe -from calibre.ebooks.BeautifulSoup import BeautifulSoup +from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag class NrcNextRecipe(BasicNewsRecipe): - __license__ = 'GPL v3' + __license__ = 'GPL v3' __author__ = 'kwetal' - version = 1 language = 'nl' + country = 'NL' + version = 2 + + title = u'nrcnext' + publisher = u'NRC Media' + category = u'News, Opinion, the Netherlands' description = u'Dutch newsblog from the Dutch daily newspaper nrcnext.' - title = u'nrcnext' + + conversion_options = {'comments': description, 'language': language, 'publisher': publisher} no_stylesheets = True - template_css = '' + remove_javascript = True - # I want to do some special processing on the articles. I could not solve it with the 'extra_css' property . So we do it the hard way. keep_only_tags = [dict(name='div', attrs={'id' : 'main'})] - # If that's overkill for you comment out the previous line and uncomment the next. Then get rid of the preprocess_html() method. - #keep_only_tags = [dict(name='div', attrs={'class' : 'post'}), dict(name='div', attrs={'class' : 'vlag'}) ] - remove_tags = [dict(name = 'div', attrs = {'class' : 'meta'}), - dict(name = 'div', attrs = {'class' : 'datumlabel'}), - dict(name = 'ul', attrs = {'class' : 'cats single'}), - dict(name = 'ul', attrs = {'class' : 'cats onderwerpen'}), - dict(name = 'ul', attrs = {'class' : 'cats rubrieken'})] + remove_tags = [] + remove_tags.append(dict(name = 'div', attrs = {'class' : 'meta'})) + remove_tags.append(dict(name = 'div', attrs = {'class' : 'datumlabel'})) + remove_tags.append(dict(name = 'ul', attrs = {'class' : 'cats single'})) + remove_tags.append(dict(name = 'ul', attrs = {'class' : 'cats onderwerpen'})) + remove_tags.append(dict(name = 'ul', attrs = {'class' : 'cats rubrieken'})) - use_embedded_content = False + extra_css = ''' + body {font-family: verdana, arial, helvetica, geneva, sans-serif; text-align: left;} + p.wp-caption-text {font-size: x-small; color: #666666;} + h2.sub_title {font-size: medium; color: #696969;} + h2.vlag {font-size: small; font-weight: bold;} + ''' def parse_index(self) : # Use the wesbite as an index. Their RSS feeds can be out of date. @@ -44,10 +53,11 @@ class NrcNextRecipe(BasicNewsRecipe): # Find the links to the actual articles and rember the location they're pointing to and the title a = post.find('a', attrs={'rel' : 'bookmark'}) href = a['href'] - title = a.renderContents() + title = self.tag_to_string(a) if index == 'columnisten' : - # In this feed/page articles can be written by more than one author. It is nice to see their names in the titles. + # In this feed/page articles can be written by more than one author. + # It is nice to see their names in the titles. flag = post.find('h2', attrs = {'class' : 'vlag'}) author = flag.contents[0].renderContents() completeTitle = u''.join([author, u': ', title]) @@ -71,44 +81,46 @@ class NrcNextRecipe(BasicNewsRecipe): return answer def preprocess_html(self, soup) : - # This method is called for every page, be it cartoon or TOC. We need to process each in their own way - if soup.find('div', attrs = {'id' : 'main', 'class' : 'single'}) : - # It's an article, find the interesting part + if soup.find('div', attrs = {'id' : 'main', 'class' : 'single'}): tag = soup.find('div', attrs = {'class' : 'post'}) - if tag : - # And replace any links with their text, so they don't show up underlined on my reader. - for link in tag.findAll('a') : - link.replaceWith(link.renderContents()) + if tag: + h2 = tag.find('h2', 'vlag') + if h2: + new_h2 = Tag(soup, 'h2', attrs = [('class', 'vlag')]) + new_h2.append(self.tag_to_string(h2)) + h2.replaceWith(new_h2) + else: + h2 = tag.find('h2') + if h2: + new_h2 = Tag(soup, 'h2', attrs = [('class', 'sub_title')]) + new_h2.append(self.tag_to_string(h2)) + h2.replaceWith(new_h2) - # Slows down my Sony reader; feel free to comment out - for movie in tag.findAll('span', attrs = {'class' : 'vvqbox vvqvimeo'}) : + h1 = tag.find('h1') + if h1: + new_h1 = Tag(soup, 'h1') + new_h1.append(self.tag_to_string(h1)) + h1.replaceWith(new_h1) + + # Slows down my reader. + for movie in tag.findAll('span', attrs = {'class' : 'vvqbox vvqvimeo'}): movie.extract() - for movie in tag.findAll('span', attrs = {'class' : 'vvqbox vvqyoutube'}) : + for movie in tag.findAll('span', attrs = {'class' : 'vvqbox vvqyoutube'}): movie.extract() + for iframe in tag.findAll('iframe') : + iframe.extract() - homeMadeSoup = BeautifulSoup('') - body = homeMadeSoup.find('body') - body.append(tag) + fresh_soup = self.getFreshSoup(soup) + fresh_soup.body.append(tag) - return homeMadeSoup - else : + return fresh_soup + else: # This should never happen and other famous last words... return soup - else : - # It's a TOC, return the whole lot. - return soup - - def postproces_html(self, soup) : - # Should not happen, but it does. Slows down my Sony eReader - for img in soup.findAll('img') : - if img['src'].startswith('http://') : - img.extract() - - # Happens for some movies which we are not able to view anyway - for iframe in soup.findAll('iframe') : - if iframe['src'].startswith('http://') : - iframe.extract() - - + def getFreshSoup(self, oldSoup): + freshSoup = BeautifulSoup('') + if oldSoup.head.title: + freshSoup.head.title.append(self.tag_to_string(oldSoup.head.title)) + return freshSoup From ee561de271784f0b9ec103e87f8c7730a2749d99 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 16 Jan 2010 21:17:47 -0700 Subject: [PATCH 2/3] New recipe for Le Devoir by Lorenzo Vigentini --- resources/recipes/ledevoir.recipe | 80 +++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 resources/recipes/ledevoir.recipe diff --git a/resources/recipes/ledevoir.recipe b/resources/recipes/ledevoir.recipe new file mode 100644 index 0000000000..4612beea2e --- /dev/null +++ b/resources/recipes/ledevoir.recipe @@ -0,0 +1,80 @@ +#!/usr/bin/env python +__license__ = 'GPL v3' +__author__ = 'Lorenzo Vigentini' +__copyright__ = '2009, Lorenzo Vigentini ' +__version__ = 'v1.01' +__date__ = '14, January 2010' +__description__ = 'Canadian Paper ' + +''' +http://www.ledevoir.com/ +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class ledevoir(BasicNewsRecipe): + author = 'Lorenzo Vigentini' + description = 'Canadian Paper' + + cover_url = 'http://www.ledevoir.com/images/ul/graphiques/logo_devoir.gif' + title = u'Le Devoir' + publisher = 'leDevoir.com' + category = 'News, finance, economy, politics' + + language = 'fr' + encoding = 'utf-8' + timefmt = '[%a, %d %b, %Y]' + + oldest_article = 1 + max_articles_per_feed = 50 + use_embedded_content = False + recursion = 10 + + remove_javascript = True + no_stylesheets = True + + keep_only_tags = [ + dict(name='div', attrs={'id':'article'}), + dict(name='ul', attrs={'id':'ariane'}) + ] + + remove_tags = [ + dict(name='div', attrs={'id':'dialog'}), + dict(name='div', attrs={'class':['interesse_actions','reactions']}), + dict(name='ul', attrs={'class':'mots_cles'}), + dict(name='a', attrs={'class':'haut'}), + dict(name='h5', attrs={'class':'interesse_actions'}) + ] + + feeds = [ + (u'A la une', 'http://www.ledevoir.com/rss/manchettes.xml'), + (u'Edition complete', 'http://feeds2.feedburner.com/fluxdudevoir'), + (u'Opinions', 'http://www.ledevoir.com/rss/opinions.xml'), + (u'Chroniques', 'http://www.ledevoir.com/rss/chroniques.xml'), + (u'Politique', 'http://www.ledevoir.com/rss/section/politique.xml?id=51'), + (u'International', 'http://www.ledevoir.com/rss/section/international.xml?id=76'), + (u'Culture', 'http://www.ledevoir.com/rss/section/culture.xml?id=48'), + (u'Environnement', 'http://www.ledevoir.com/rss/section/environnement.xml?id=78'), + (u'Societe', 'http://www.ledevoir.com/rss/section/societe.xml?id=52'), + (u'Economie', 'http://www.ledevoir.com/rss/section/economie.xml?id=49'), + (u'Sports', 'http://www.ledevoir.com/rss/section/sports.xml?id=85'), + (u'Loisirs', 'http://www.ledevoir.com/rss/section/loisirs.xml?id=50') + ] + + extra_css = ''' + h1 {color:#1C1E7C;font-family:Times,Georgia,serif;font-size:1.85em;font-size-adjust:none;font-stretch:normal;font-style:normal;font-variant:normal;font-weight:bold;line-height:1.2em;margin:0 0 5px;} + h2 {color:#333333;font-family:Times,Georgia,serif;font-size:1.5em;font-size-adjust:none;font-stretch:normal;font-style:normal;font-variant:normal;font-weight:normal;line-height:1.2em;margin:0 0 5px;} + h3 {color:#4D4D4D;font-family:Arial,Helvetica,sans-serif; font-size:15px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:14px;} + h4 {color:#333333; font-family:Arial,Helvetica,sans-serif;font-size:13px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:14px; } + h5 {color:#333333; font-family:Arial,Helvetica,sans-serif; font-size:11px; font-size-adjust:none; font-stretch:normal; font-style:normal; font-variant:normal; font-weight:bold; line-height:14px; text-transform:uppercase;} + .specs {line-height:1em;margin:1px 0;} + .specs span.auteur {font:0.85em/1.1em Arial, Verdana, sans-serif;color:#787878;} + .specs span.auteur a, + .specs span.auteur span {text-transform:uppercase;color:#787878;} + .specs .date {font:0.85em/1.1em Arial, Verdana, sans-serif;color:#787878;} + ul#ariane {list-style-type:none;margin:0;padding:5px 0 8px 0;font:0.85em/1.2em Arial, Verdana, sans-serif;color:#2E2E2E;border-bottom:10px solid #fff;} + ul#ariane li {display:inline;} + ul#ariane a {color:#2E2E2E;text-decoration:underline;} + .credit {color:#787878;font-size:0.71em;line-height:1.1em;font-weight:bold;} + .texte {font-size:1.15em;line-height:1.4em;margin-bottom:17px;} + ''' From e12253ff151c83d749cd17f98bdca10ad6fa4410 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 16 Jan 2010 21:24:58 -0700 Subject: [PATCH 3/3] Add quick start guide on first run --- src/calibre/gui2/__init__.py | 3 ++- src/calibre/gui2/ui.py | 17 +++++++++++++++-- src/calibre/utils/config.py | 28 +++++++++++++++++++++++----- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index db4bb5c754..34f9f57161 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -10,11 +10,12 @@ from PyQt4.QtGui import QFileDialog, QMessageBox, QPixmap, QFileIconProvider, \ ORG_NAME = 'KovidsBrain' APP_UID = 'libprs500' from calibre import islinux, iswindows, isosx -from calibre.utils.config import Config, ConfigProxy, dynamic +from calibre.utils.config import Config, ConfigProxy, dynamic, JSONConfig from calibre.utils.localization import set_qt_translator from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats from calibre.ebooks.metadata import MetaInformation +gprefs = JSONConfig('gui') NONE = QVariant() #: Null value to return from the data function of item models diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index f85a19da24..6cbae7f7b0 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -31,7 +31,7 @@ from calibre.utils.ipc.server import Server from calibre.gui2 import warning_dialog, choose_files, error_dialog, \ question_dialog,\ pixmap_to_data, choose_dir, \ - Dispatcher, \ + Dispatcher, gprefs, \ available_height, \ max_available_height, config, info_dialog, \ available_width, GetMetadata @@ -518,7 +518,21 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.connect(self.library_view.model(), SIGNAL('count_changed(int)'), self.tags_view.recount) self.connect(self.search, SIGNAL('cleared()'), self.tags_view.clear) + if not gprefs.get('quick_start_guide_added', False): + from calibre.ebooks.metadata import MetaInformation + mi = MetaInformation(_('Calibre Quick Start Guide'), ['John Schember']) + mi.author_sort = 'Schember, John' + mi.comments = "A guide to get you up an running with calibre" + mi.publisher = 'calibre' + self.library_view.model().add_books([P('quick_start.epub')], ['epub'], + [mi]) + gprefs['quick_start_guide_added'] = True + self.library_view.model().books_added(1) + if hasattr(self, 'db_images'): + self.db_images.reset() + self.library_view.model().count_changed() + ########################### Cover Flow ################################ self.cover_flow = None if CoverFlow is not None: @@ -1008,7 +1022,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): return self._add_books(books, to_device) - def _add_books(self, paths, to_device, on_card=None): if on_card is None: on_card = 'carda' if self.stack.currentIndex() == 2 else 'cardb' if self.stack.currentIndex() == 3 else None diff --git a/src/calibre/utils/config.py b/src/calibre/utils/config.py index 697cfbe388..a0e5632cb7 100644 --- a/src/calibre/utils/config.py +++ b/src/calibre/utils/config.py @@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en' ''' Manage application-wide preferences. ''' -import os, re, cPickle, textwrap, traceback, plistlib +import os, re, cPickle, textwrap, traceback, plistlib, json from copy import deepcopy from functools import partial from optparse import OptionParser as _OptionParser @@ -564,23 +564,31 @@ class XMLConfig(dict): data types. ''' + EXTENSION = '.plist' + def __init__(self, rel_path_to_cf_file): dict.__init__(self) self.file_path = os.path.join(config_dir, *(rel_path_to_cf_file.split('/'))) self.file_path = os.path.abspath(self.file_path) - if not self.file_path.endswith('.plist'): - self.file_path += '.plist' + if not self.file_path.endswith(self.EXTENSION): + self.file_path += self.EXTENSION self.refresh() + def raw_to_object(self, raw): + return plistlib.readPlistFromString(raw) + + def to_raw(self): + return plistlib.writePlistToString(self) + def refresh(self): d = {} if os.path.exists(self.file_path): with ExclusiveFile(self.file_path) as f: raw = f.read() try: - d = plistlib.readPlistFromString(raw) if raw.strip() else {} + d = self.raw_to_object(raw) if raw.strip() else {} except SystemError: pass except: @@ -618,11 +626,21 @@ class XMLConfig(dict): if not os.path.exists(dpath): os.makedirs(dpath, mode=CONFIG_DIR_MODE) with ExclusiveFile(self.file_path) as f: - raw = plistlib.writePlistToString(self) + raw = self.to_raw() f.seek(0) f.truncate() f.write(raw) +class JSONConfig(XMLConfig): + + EXTENSION = '.json' + + def raw_to_object(self, raw): + return json.loads(raw.decode('utf-8')) + + def to_raw(self): + return json.dumps(self, indent=2) + def _prefs(): c = Config('global', 'calibre wide preferences')