From 74243ac0b9277f5468bcdb58e54b397862da76e1 Mon Sep 17 00:00:00 2001 From: ldolse Date: Mon, 10 Jan 2011 17:07:40 +0800 Subject: [PATCH 01/14] preprocess tweaks --- src/calibre/ebooks/conversion/preprocess.py | 2 +- src/calibre/ebooks/conversion/utils.py | 4 ++-- src/calibre/ebooks/txt/processor.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/calibre/ebooks/conversion/preprocess.py b/src/calibre/ebooks/conversion/preprocess.py index 08a46cb8d9..f994888f19 100644 --- a/src/calibre/ebooks/conversion/preprocess.py +++ b/src/calibre/ebooks/conversion/preprocess.py @@ -360,7 +360,7 @@ class HTMLPreProcessor(object): (re.compile(r'((?<=)\s*file:////?[A-Z].*
|file:////?[A-Z].*
(?=\s*
))', re.IGNORECASE), lambda match: ''), # Center separator lines - (re.compile(u'
\s*(?P([*#•✦]+\s*)+)\s*
'), lambda match: '

\n

' + match.group(1) + '

'), + (re.compile(u'
\s*(?P([*#•✦=]+\s*)+)\s*
'), lambda match: '

\n

' + match.group(1) + '

'), # Remove page links (re.compile(r'', re.IGNORECASE), lambda match: ''), diff --git a/src/calibre/ebooks/conversion/utils.py b/src/calibre/ebooks/conversion/utils.py index 52d1bcc619..9177b5e53b 100644 --- a/src/calibre/ebooks/conversion/utils.py +++ b/src/calibre/ebooks/conversion/utils.py @@ -155,9 +155,9 @@ class PreProcessor(object): chapter_types = [ [r"[^'\"]?(Introduction|Synopsis|Acknowledgements|Chapter|Kapitel|Epilogue|Volume\s|Prologue|Book\s|Part\s|Dedication|Preface)\s*([\d\w-]+\:?\'?\s*){0,5}", True, "Searching for common Chapter Headings"], + [r"([A-Z]\s+){3,}\s*([\d\w-]+\s*){0,3}\s*", True, "Searching for letter spaced headings"], # Spaced Lettering [r"]*>\s*(]*>)?\s*(?!([*#•]+\s*)+)(\s*(?=[\d.\w#\-*\s]+<)([\d.\w#-*]+\s*){1,5}\s*)(?!\.)()?\s*", True, "Searching for emphasized lines"], # Emphasized lines [r"[^'\"]?(\d+(\.|:)|CHAPTER)\s*([\dA-Z\-\'\"#,]+\s*){0,7}\s*", True, "Searching for numeric chapter headings"], # Numeric Chapters - [r"([A-Z]\s+){3,}\s*([\d\w-]+\s*){0,3}\s*", True, "Searching for letter spaced headings"], # Spaced Lettering [r"[^'\"]?(\d+\.?\s+([\d\w-]+\:?\'?-?\s?){0,5})\s*", True, "Searching for numeric chapters with titles"], # Numeric Titles [r"[^'\"]?(\d+|CHAPTER)\s*([\dA-Z\-\'\"\?!#,]+\s*){0,7}\s*", True, "Searching for simple numeric chapter headings"], # Numeric Chapters, no dot or colon [r"\s*[^'\"]?([A-Z#]+(\s|-){0,3}){1,5}\s*", False, "Searching for chapters with Uppercase Characters" ] # Uppercase Chapters @@ -357,6 +357,6 @@ class PreProcessor(object): html = blankreg.sub('\n'+r'\g'+u'\u00a0'+r'\g', html) # Center separator lines - html = re.sub(u'<(?Pp|div)[^>]*>\s*(<(?Pfont|span|[ibu])[^>]*>)?\s*(<(?Pfont|span|[ibu])[^>]*>)?\s*(<(?Pfont|span|[ibu])[^>]*>)?\s*(?P([*#•]+\s*)+)\s*()?\s*()?\s*()?\s*', '

' + '\g' + '

', html) + html = re.sub(u'<(?Pp|div)[^>]*>\s*(<(?Pfont|span|[ibu])[^>]*>)?\s*(<(?Pfont|span|[ibu])[^>]*>)?\s*(<(?Pfont|span|[ibu])[^>]*>)?\s*(?P([*#•=✦]+\s*)+)\s*()?\s*()?\s*()?\s*', '

' + '\g' + '

', html) return html diff --git a/src/calibre/ebooks/txt/processor.py b/src/calibre/ebooks/txt/processor.py index 6a1a106681..ef9920185f 100644 --- a/src/calibre/ebooks/txt/processor.py +++ b/src/calibre/ebooks/txt/processor.py @@ -147,7 +147,7 @@ def detect_paragraph_type(txt): if .15 <= print_percent <= .75: return 'print' elif .15 <= block_percent <= .75: - return 'block' + return 'block' # Assume unformatted text with hardbreaks if nothing else matches return 'unformatted' From 9832b7118b592679541ab357de02e426e1f48a19 Mon Sep 17 00:00:00 2001 From: ldolse Date: Tue, 11 Jan 2011 11:27:25 +0800 Subject: [PATCH 02/14] chapter detection tweaks --- src/calibre/ebooks/conversion/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calibre/ebooks/conversion/utils.py b/src/calibre/ebooks/conversion/utils.py index 9177b5e53b..cfa57a28c3 100644 --- a/src/calibre/ebooks/conversion/utils.py +++ b/src/calibre/ebooks/conversion/utils.py @@ -151,11 +151,11 @@ class PreProcessor(object): n_lookahead_open = "\s+(?!" n_lookahead_close = ")" - default_title = r"(<[ibu][^>]*>)?\s{0,3}([\w\'\"-]+\s{0,3}){1,5}?(]*>)?(?=<)" + default_title = r"(<[ibu][^>]*>)?\s{0,3}([\w\:\'\"-]+\s{0,3}){1,5}?(]*>)?(?=<)" chapter_types = [ [r"[^'\"]?(Introduction|Synopsis|Acknowledgements|Chapter|Kapitel|Epilogue|Volume\s|Prologue|Book\s|Part\s|Dedication|Preface)\s*([\d\w-]+\:?\'?\s*){0,5}", True, "Searching for common Chapter Headings"], - [r"([A-Z]\s+){3,}\s*([\d\w-]+\s*){0,3}\s*", True, "Searching for letter spaced headings"], # Spaced Lettering + [r"([A-Z-]\s+){3,}\s*([\d\w-]+\s*){0,3}\s*", True, "Searching for letter spaced headings"], # Spaced Lettering [r"]*>\s*(]*>)?\s*(?!([*#•]+\s*)+)(\s*(?=[\d.\w#\-*\s]+<)([\d.\w#-*]+\s*){1,5}\s*)(?!\.)()?\s*", True, "Searching for emphasized lines"], # Emphasized lines [r"[^'\"]?(\d+(\.|:)|CHAPTER)\s*([\dA-Z\-\'\"#,]+\s*){0,7}\s*", True, "Searching for numeric chapter headings"], # Numeric Chapters [r"[^'\"]?(\d+\.?\s+([\d\w-]+\:?\'?-?\s?){0,5})\s*", True, "Searching for numeric chapters with titles"], # Numeric Titles From f965037fb44184957d9bc20dc3efb1ce1adee6a9 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 17 Jan 2011 12:22:30 -0700 Subject: [PATCH 03/14] MOBI Output: Fix bug that could cause a link pointing to the start of a section to go to a point later in the section is the section contained an empty id attribute --- src/calibre/ebooks/mobi/writer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/ebooks/mobi/writer.py b/src/calibre/ebooks/mobi/writer.py index cd6674c2e2..ed102ecc80 100644 --- a/src/calibre/ebooks/mobi/writer.py +++ b/src/calibre/ebooks/mobi/writer.py @@ -251,7 +251,7 @@ class Serializer(object): tag = prefixname(elem.tag, nsrmap) # Previous layers take care of @name id = elem.attrib.pop('id', None) - if id is not None: + if id: href = '#'.join((item.href, id)) offset = self.anchor_offset or buffer.tell() self.id_offsets[urlnormalize(href)] = offset From aa28b379517028b5e7951c8aa94f2226a99c918d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 17 Jan 2011 13:03:34 -0700 Subject: [PATCH 04/14] Fix #8424 (Dilbert retrieval fails) --- resources/recipes/dilbert.recipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/recipes/dilbert.recipe b/resources/recipes/dilbert.recipe index 2c3268da2f..56aa4af8c9 100644 --- a/resources/recipes/dilbert.recipe +++ b/resources/recipes/dilbert.recipe @@ -28,7 +28,7 @@ class DilbertBig(BasicNewsRecipe): ,'publisher' : publisher } - feeds = [(u'Dilbert', u'http://feeds.dilbert.com/DilbertDailyStrip' )] + feeds = [(u'Dilbert', u'http://feed.dilbert.com/dilbert/daily_strip' )] def get_article_url(self, article): return article.get('feedburner_origlink', None) From 84d1dd94d23db7b53f47051ecb3cfd5c47965f0b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 17 Jan 2011 13:10:10 -0700 Subject: [PATCH 05/14] Make postprocess_html in the NY Times recipes more robust --- resources/recipes/nytimes.recipe | 204 +++++++++++++------------ resources/recipes/nytimes_sub.recipe | 214 +++++++++++++++------------ 2 files changed, 229 insertions(+), 189 deletions(-) diff --git a/resources/recipes/nytimes.recipe b/resources/recipes/nytimes.recipe index 6f80f4f85f..7e313e5727 100644 --- a/resources/recipes/nytimes.recipe +++ b/resources/recipes/nytimes.recipe @@ -586,105 +586,125 @@ class NYTimes(BasicNewsRecipe): return self.strip_anchors(soup) def postprocess_html(self,soup, True): + try: + if self.one_picture_per_article: + # Remove all images after first + largeImg = soup.find(True, {'class':'articleSpanImage'}) + inlineImgs = soup.findAll(True, {'class':'inlineImage module'}) + if largeImg: + for inlineImg in inlineImgs: + inlineImg.extract() + else: + if inlineImgs: + firstImg = inlineImgs[0] + for inlineImg in inlineImgs[1:]: + inlineImg.extract() + # Move firstImg before article body + cgFirst = soup.find(True, {'class':re.compile('columnGroup *first')}) + if cgFirst: + # Strip all sibling NavigableStrings: noise + navstrings = cgFirst.findAll(text=True, recursive=False) + [ns.extract() for ns in navstrings] + headline_found = False + tag = cgFirst.find(True) + insertLoc = 0 + while True: + insertLoc += 1 + if hasattr(tag,'class') and tag['class'] == 'articleHeadline': + headline_found = True + break + tag = tag.nextSibling + if not tag: + headline_found = False + break + if headline_found: + cgFirst.insert(insertLoc,firstImg) + else: + self.log(">>> No class:'columnGroup first' found <<<") + except: + self.log("ERROR: One picture per article in postprocess_html") - if self.one_picture_per_article: - # Remove all images after first - largeImg = soup.find(True, {'class':'articleSpanImage'}) - inlineImgs = soup.findAll(True, {'class':'inlineImage module'}) - if largeImg: - for inlineImg in inlineImgs: - inlineImg.extract() - else: - if inlineImgs: - firstImg = inlineImgs[0] - for inlineImg in inlineImgs[1:]: - inlineImg.extract() - # Move firstImg before article body - cgFirst = soup.find(True, {'class':re.compile('columnGroup *first')}) - if cgFirst: - # Strip all sibling NavigableStrings: noise - navstrings = cgFirst.findAll(text=True, recursive=False) - [ns.extract() for ns in navstrings] - headline_found = False - tag = cgFirst.find(True) - insertLoc = 0 - while True: - insertLoc += 1 - if hasattr(tag,'class') and tag['class'] == 'articleHeadline': - headline_found = True - break - tag = tag.nextSibling - if not tag: - headline_found = False - break - if headline_found: - cgFirst.insert(insertLoc,firstImg) - else: - self.log(">>> No class:'columnGroup first' found <<<") + try: + # Change captions to italic + for caption in soup.findAll(True, {'class':'caption'}) : + if caption and len(caption) > 0: + cTag = Tag(soup, "p", [("class", "caption")]) + c = self.fixChars(self.tag_to_string(caption,use_alt=False)).strip() + mp_off = c.find("More Photos") + if mp_off >= 0: + c = c[:mp_off] + cTag.insert(0, c) + caption.replaceWith(cTag) + except: + self.log("ERROR: Problem in change captions to italic") - # Change captions to italic - for caption in soup.findAll(True, {'class':'caption'}) : - if caption and caption.contents[0]: - cTag = Tag(soup, "p", [("class", "caption")]) - c = self.fixChars(self.tag_to_string(caption,use_alt=False)).strip() - mp_off = c.find("More Photos") - if mp_off >= 0: - c = c[:mp_off] - cTag.insert(0, c) - caption.replaceWith(cTag) + try: + # Change to

+ h1 = soup.find('h1') + if h1: + headline = h1.find("nyt_headline") + if headline: + tag = Tag(soup, "h2") + tag['class'] = "headline" + tag.insert(0, self.fixChars(headline.contents[0])) + h1.replaceWith(tag) + else: + # Blog entry - replace headline, remove
tags + headline = soup.find('title') + if headline: + tag = Tag(soup, "h2") + tag['class'] = "headline" + tag.insert(0, self.fixChars(headline.contents[0])) + soup.insert(0, tag) + hrs = soup.findAll('hr') + for hr in hrs: + hr.extract() + except: + self.log("ERROR: Problem in Change to

") - # Change to

- h1 = soup.find('h1') - if h1: - headline = h1.find("nyt_headline") - if headline: - tag = Tag(soup, "h2") - tag['class'] = "headline" - tag.insert(0, self.fixChars(headline.contents[0])) - h1.replaceWith(tag) - else: - # Blog entry - replace headline, remove
tags - headline = soup.find('title') - if headline: - tag = Tag(soup, "h2") - tag['class'] = "headline" - tag.insert(0, self.fixChars(headline.contents[0])) - soup.insert(0, tag) - hrs = soup.findAll('hr') - for hr in hrs: - hr.extract() + try: + # Change

to

- used in editorial blogs + masthead = soup.find("h1") + if masthead: + # Nuke the href + if masthead.a: + del(masthead.a['href']) + tag = Tag(soup, "h3") + tag.insert(0, self.fixChars(masthead.contents[0])) + masthead.replaceWith(tag) + except: + self.log("ERROR: Problem in Change

to

- used in editorial blogs") - # Change

to

- used in editorial blogs - masthead = soup.find("h1") - if masthead: - # Nuke the href - if masthead.a: - del(masthead.a['href']) - tag = Tag(soup, "h3") - tag.insert(0, self.fixChars(masthead.contents[0])) - masthead.replaceWith(tag) + try: + # Change to + for subhead in soup.findAll(True, {'class':'bold'}) : + if subhead.contents: + bTag = Tag(soup, "b") + bTag.insert(0, subhead.contents[0]) + subhead.replaceWith(bTag) + except: + self.log("ERROR: Problem in Change

to

- used in editorial blogs") - # Change to - for subhead in soup.findAll(True, {'class':'bold'}) : - if subhead.contents: - bTag = Tag(soup, "b") - bTag.insert(0, subhead.contents[0]) - subhead.replaceWith(bTag) + try: + divTag = soup.find('div',attrs={'id':'articleBody'}) + if divTag: + divTag['class'] = divTag['id'] + except: + self.log("ERROR: Problem in soup.find(div,attrs={id:articleBody})") - divTag = soup.find('div',attrs={'id':'articleBody'}) - if divTag: - divTag['class'] = divTag['id'] + try: + # Add class="authorId" to
so we can format with CSS + divTag = soup.find('div',attrs={'id':'authorId'}) + if divTag and divTag.contents[0]: + tag = Tag(soup, "p") + tag['class'] = "authorId" + tag.insert(0, self.fixChars(self.tag_to_string(divTag.contents[0], + use_alt=False))) + divTag.replaceWith(tag) + except: + self.log("ERROR: Problem in Add class=authorId to
so we can format with CSS") - # Add class="authorId" to
so we can format with CSS - divTag = soup.find('div',attrs={'id':'authorId'}) - if divTag and divTag.contents[0]: - tag = Tag(soup, "p") - tag['class'] = "authorId" - tag.insert(0, self.fixChars(self.tag_to_string(divTag.contents[0], - use_alt=False))) - divTag.replaceWith(tag) - - return soup + return soup def populate_article_metadata(self, article, soup, first): shortparagraph = "" diff --git a/resources/recipes/nytimes_sub.recipe b/resources/recipes/nytimes_sub.recipe index 8ac7c735f7..8f92852237 100644 --- a/resources/recipes/nytimes_sub.recipe +++ b/resources/recipes/nytimes_sub.recipe @@ -586,105 +586,125 @@ class NYTimes(BasicNewsRecipe): return self.strip_anchors(soup) def postprocess_html(self,soup, True): + try: + if self.one_picture_per_article: + # Remove all images after first + largeImg = soup.find(True, {'class':'articleSpanImage'}) + inlineImgs = soup.findAll(True, {'class':'inlineImage module'}) + if largeImg: + for inlineImg in inlineImgs: + inlineImg.extract() + else: + if inlineImgs: + firstImg = inlineImgs[0] + for inlineImg in inlineImgs[1:]: + inlineImg.extract() + # Move firstImg before article body + cgFirst = soup.find(True, {'class':re.compile('columnGroup *first')}) + if cgFirst: + # Strip all sibling NavigableStrings: noise + navstrings = cgFirst.findAll(text=True, recursive=False) + [ns.extract() for ns in navstrings] + headline_found = False + tag = cgFirst.find(True) + insertLoc = 0 + while True: + insertLoc += 1 + if hasattr(tag,'class') and tag['class'] == 'articleHeadline': + headline_found = True + break + tag = tag.nextSibling + if not tag: + headline_found = False + break + if headline_found: + cgFirst.insert(insertLoc,firstImg) + else: + self.log(">>> No class:'columnGroup first' found <<<") + except: + self.log("ERROR: One picture per article in postprocess_html") + + try: + # Change captions to italic + for caption in soup.findAll(True, {'class':'caption'}) : + if caption and len(caption) > 0: + cTag = Tag(soup, "p", [("class", "caption")]) + c = self.fixChars(self.tag_to_string(caption,use_alt=False)).strip() + mp_off = c.find("More Photos") + if mp_off >= 0: + c = c[:mp_off] + cTag.insert(0, c) + caption.replaceWith(cTag) + except: + self.log("ERROR: Problem in change captions to italic") + + try: + # Change to

+ h1 = soup.find('h1') + if h1: + headline = h1.find("nyt_headline") + if headline: + tag = Tag(soup, "h2") + tag['class'] = "headline" + tag.insert(0, self.fixChars(headline.contents[0])) + h1.replaceWith(tag) + else: + # Blog entry - replace headline, remove
tags + headline = soup.find('title') + if headline: + tag = Tag(soup, "h2") + tag['class'] = "headline" + tag.insert(0, self.fixChars(headline.contents[0])) + soup.insert(0, tag) + hrs = soup.findAll('hr') + for hr in hrs: + hr.extract() + except: + self.log("ERROR: Problem in Change to

") - if self.one_picture_per_article: - # Remove all images after first - largeImg = soup.find(True, {'class':'articleSpanImage'}) - inlineImgs = soup.findAll(True, {'class':'inlineImage module'}) - if largeImg: - for inlineImg in inlineImgs: - inlineImg.extract() - else: - if inlineImgs: - firstImg = inlineImgs[0] - for inlineImg in inlineImgs[1:]: - inlineImg.extract() - # Move firstImg before article body - cgFirst = soup.find(True, {'class':re.compile('columnGroup *first')}) - if cgFirst: - # Strip all sibling NavigableStrings: noise - navstrings = cgFirst.findAll(text=True, recursive=False) - [ns.extract() for ns in navstrings] - headline_found = False - tag = cgFirst.find(True) - insertLoc = 0 - while True: - insertLoc += 1 - if hasattr(tag,'class') and tag['class'] == 'articleHeadline': - headline_found = True - break - tag = tag.nextSibling - if not tag: - headline_found = False - break - if headline_found: - cgFirst.insert(insertLoc,firstImg) - else: - self.log(">>> No class:'columnGroup first' found <<<") + try: + # Change

to

- used in editorial blogs + masthead = soup.find("h1") + if masthead: + # Nuke the href + if masthead.a: + del(masthead.a['href']) + tag = Tag(soup, "h3") + tag.insert(0, self.fixChars(masthead.contents[0])) + masthead.replaceWith(tag) + except: + self.log("ERROR: Problem in Change

to

- used in editorial blogs") - # Change captions to italic - for caption in soup.findAll(True, {'class':'caption'}) : - if caption and caption.contents[0]: - cTag = Tag(soup, "p", [("class", "caption")]) - c = self.fixChars(self.tag_to_string(caption,use_alt=False)).strip() - mp_off = c.find("More Photos") - if mp_off >= 0: - c = c[:mp_off] - cTag.insert(0, c) - caption.replaceWith(cTag) - - # Change to

- h1 = soup.find('h1') - if h1: - headline = h1.find("nyt_headline") - if headline: - tag = Tag(soup, "h2") - tag['class'] = "headline" - tag.insert(0, self.fixChars(headline.contents[0])) - h1.replaceWith(tag) - else: - # Blog entry - replace headline, remove
tags - headline = soup.find('title') - if headline: - tag = Tag(soup, "h2") - tag['class'] = "headline" - tag.insert(0, self.fixChars(headline.contents[0])) - soup.insert(0, tag) - hrs = soup.findAll('hr') - for hr in hrs: - hr.extract() - - # Change

to

- used in editorial blogs - masthead = soup.find("h1") - if masthead: - # Nuke the href - if masthead.a: - del(masthead.a['href']) - tag = Tag(soup, "h3") - tag.insert(0, self.fixChars(masthead.contents[0])) - masthead.replaceWith(tag) - - # Change to - for subhead in soup.findAll(True, {'class':'bold'}) : - if subhead.contents: - bTag = Tag(soup, "b") - bTag.insert(0, subhead.contents[0]) - subhead.replaceWith(bTag) - - divTag = soup.find('div',attrs={'id':'articleBody'}) - if divTag: - divTag['class'] = divTag['id'] - - # Add class="authorId" to
so we can format with CSS - divTag = soup.find('div',attrs={'id':'authorId'}) - if divTag and divTag.contents[0]: - tag = Tag(soup, "p") - tag['class'] = "authorId" - tag.insert(0, self.fixChars(self.tag_to_string(divTag.contents[0], - use_alt=False))) - divTag.replaceWith(tag) - - return soup + try: + # Change to + for subhead in soup.findAll(True, {'class':'bold'}) : + if subhead.contents: + bTag = Tag(soup, "b") + bTag.insert(0, subhead.contents[0]) + subhead.replaceWith(bTag) + except: + self.log("ERROR: Problem in Change

to

- used in editorial blogs") + + try: + divTag = soup.find('div',attrs={'id':'articleBody'}) + if divTag: + divTag['class'] = divTag['id'] + except: + self.log("ERROR: Problem in soup.find(div,attrs={id:articleBody})") + + try: + # Add class="authorId" to
so we can format with CSS + divTag = soup.find('div',attrs={'id':'authorId'}) + if divTag and divTag.contents[0]: + tag = Tag(soup, "p") + tag['class'] = "authorId" + tag.insert(0, self.fixChars(self.tag_to_string(divTag.contents[0], + use_alt=False))) + divTag.replaceWith(tag) + except: + self.log("ERROR: Problem in Add class=authorId to
so we can format with CSS") + + return soup def populate_article_metadata(self, article, soup, first): shortparagraph = "" try: From 927c389e91ffe47880ed1b0949b421d449f7ad4b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 17 Jan 2011 13:20:12 -0700 Subject: [PATCH 06/14] Fix #8436 (Add tag when using Add ISBN Dialog) --- src/calibre/gui2/actions/add.py | 9 ++-- src/calibre/gui2/dialogs/add_from_isbn.py | 7 +++ src/calibre/gui2/dialogs/add_from_isbn.ui | 52 +++++++++++++++++++---- 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/calibre/gui2/actions/add.py b/src/calibre/gui2/actions/add.py index 9917c542ae..6fa53d6290 100644 --- a/src/calibre/gui2/actions/add.py +++ b/src/calibre/gui2/actions/add.py @@ -91,13 +91,14 @@ class AddAction(InterfaceAction): self.gui.library_view.model().db.import_book(MetaInformation(None), []) self.gui.library_view.model().books_added(num) - def add_isbns(self, books): + def add_isbns(self, books, add_tags=[]): from calibre.ebooks.metadata import MetaInformation ids = set([]) + db = self.gui.library_view.model().db + for x in books: mi = MetaInformation(None) mi.isbn = x['isbn'] - db = self.gui.library_view.model().db if x['path'] is not None: ids.add(db.import_book(mi, [x['path']])) else: @@ -109,6 +110,8 @@ class AddAction(InterfaceAction): self.gui.iactions['Edit Metadata'].do_download_metadata(ids) finally: config['overwrite_author_title_metadata'] = orig + if add_tags and ids: + db.bulk_modify_tags(ids, add=add_tags) def files_dropped(self, paths): @@ -166,7 +169,7 @@ class AddAction(InterfaceAction): from calibre.gui2.dialogs.add_from_isbn import AddFromISBN d = AddFromISBN(self.gui) if d.exec_() == d.Accepted: - self.add_isbns(d.books) + self.add_isbns(d.books, add_tags=d.set_tags) def add_books(self, *args): ''' diff --git a/src/calibre/gui2/dialogs/add_from_isbn.py b/src/calibre/gui2/dialogs/add_from_isbn.py index f93cddecd5..433b70291c 100644 --- a/src/calibre/gui2/dialogs/add_from_isbn.py +++ b/src/calibre/gui2/dialogs/add_from_isbn.py @@ -12,6 +12,7 @@ from PyQt4.Qt import QDialog, QApplication from calibre.gui2.dialogs.add_from_isbn_ui import Ui_Dialog from calibre.ebooks.metadata import check_isbn from calibre.constants import iswindows +from calibre.gui2 import gprefs class AddFromISBN(QDialog, Ui_Dialog): @@ -25,7 +26,9 @@ class AddFromISBN(QDialog, Ui_Dialog): self.isbns = [] self.books = [] + self.set_tags = [] self.paste_button.clicked.connect(self.paste) + self.add_tags.setText(', '.join(gprefs.get('add from ISBN tags', []))) def paste(self, *args): app = QApplication.instance() @@ -37,6 +40,10 @@ class AddFromISBN(QDialog, Ui_Dialog): self.isbn_box.setPlainText(new) def accept(self, *args): + tags = unicode(self.add_tags.text()).strip().split(',') + tags = list(filter(None, [x.strip() for x in tags])) + gprefs['add from ISBN tags'] = tags + self.set_tags = tags for line in unicode(self.isbn_box.toPlainText()).strip().splitlines(): line = line.strip() if not line: diff --git a/src/calibre/gui2/dialogs/add_from_isbn.ui b/src/calibre/gui2/dialogs/add_from_isbn.ui index e37c4ed769..f598e6f1d8 100644 --- a/src/calibre/gui2/dialogs/add_from_isbn.ui +++ b/src/calibre/gui2/dialogs/add_from_isbn.ui @@ -18,8 +18,19 @@ :/images/add_book.png:/images/add_book.png - - + + + + + + + + + &Paste from clipboard + + + + @@ -34,6 +45,36 @@ + + + + + + &Tags to set on created book entries: + + + add_tags + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + @@ -44,13 +85,6 @@ - - - - &Paste from clipboard - - - From e82dd54242eb86382f55a2840338acea526b4fb1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 17 Jan 2011 17:42:40 -0700 Subject: [PATCH 07/14] Fix #8409 (bulk edit date) --- src/calibre/gui2/dialogs/metadata_bulk.py | 24 ++++- src/calibre/gui2/dialogs/metadata_bulk.ui | 117 +++++++++++++++------- 2 files changed, 100 insertions(+), 41 deletions(-) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index 2b3a319663..6e6b553dba 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -49,7 +49,6 @@ def get_cover_data(path): # {{{ return cdata, area # }}} - class MyBlockingBusy(QDialog): # {{{ do_one_signal = pyqtSignal() @@ -134,7 +133,7 @@ class MyBlockingBusy(QDialog): # {{{ do_autonumber, do_remove_format, remove_format, do_swap_ta, \ do_remove_conv, do_auto_author, series, do_series_restart, \ series_start_value, do_title_case, cover_action, clear_series, \ - pubdate = self.args + pubdate, adddate = self.args # first loop: do author and title. These will commit at the end of each @@ -214,6 +213,9 @@ class MyBlockingBusy(QDialog): # {{{ if pubdate is not None: self.db.set_pubdate(id, pubdate, notify=False, commit=False) + if adddate is not None: + self.db.set_timestamp(id, adddate, notify=False, commit=False) + if do_series: if do_series_restart: if self.series_start_value is None: @@ -300,6 +302,10 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): self.pubdate.setSpecialValueText(_('Undefined')) self.clear_pubdate_button.clicked.connect(self.clear_pubdate) self.pubdate.dateChanged.connect(self.do_apply_pubdate) + self.adddate.setMinimumDate(UNDEFINED_QDATE) + self.adddate.setSpecialValueText(_('Undefined')) + self.clear_adddate_button.clicked.connect(self.clear_adddate) + self.adddate.dateChanged.connect(self.do_apply_adddate) if len(self.db.custom_field_keys(include_composites=False)) == 0: self.central_widget.removeTab(1) @@ -322,6 +328,12 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): def clear_pubdate(self, *args): self.pubdate.setDate(UNDEFINED_QDATE) + def do_apply_adddate(self, *args): + self.apply_adddate.setChecked(True) + + def clear_adddate(self, *args): + self.adddate.setDate(UNDEFINED_QDATE) + def button_clicked(self, which): if which == self.button_box.button(QDialogButtonBox.Apply): self.do_again = True @@ -726,7 +738,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): name = name.strip().replace('|', ',') self.authors.addItem(name) self.authors.setEditText('') - + self.authors.set_separator('&') self.authors.set_space_before_sep(True) self.authors.update_items_cache(self.db.all_author_names()) @@ -805,9 +817,11 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): do_remove_conv = self.remove_conversion_settings.isChecked() do_auto_author = self.auto_author_sort.isChecked() do_title_case = self.change_title_to_title_case.isChecked() - pubdate = None + pubdate = adddate = None if self.apply_pubdate.isChecked(): pubdate = qt_to_dt(self.pubdate.date()) + if self.apply_adddate.isChecked(): + adddate = qt_to_dt(self.adddate.date()) cover_action = None if self.cover_remove.isChecked(): @@ -821,7 +835,7 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): do_autonumber, do_remove_format, remove_format, do_swap_ta, do_remove_conv, do_auto_author, series, do_series_restart, series_start_value, do_title_case, cover_action, clear_series, - pubdate) + pubdate, adddate) bb = MyBlockingBusy(_('Applying changes to %d books.\nPhase {0} {1}%%.') %len(self.ids), args, self.db, self.ids, diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index 8db74b343d..f8ae926be6 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -347,6 +347,51 @@ from the value in the box + + + + &Date: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + adddate + + + + + + + + + d MMM yyyy + + + true + + + + + + + ... + + + + :/images/trash.png:/images/trash.png + + + + + + + + + &Apply date + + + @@ -395,6 +440,42 @@ from the value in the box + + + + Remove &format: + + + remove_format + + + + + + + + 120 + 16777215 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 15 + + + + @@ -478,42 +559,6 @@ Future conversion of these books will use the default settings. - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 15 - - - - - - - - Remove &format: - - - remove_format - - - - - - - - 120 - 16777215 - - - - From 5376137156d4dc1e86aeddc8c1238f16fc46754b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 17 Jan 2011 18:01:05 -0700 Subject: [PATCH 08/14] ... --- src/calibre/gui2/ui.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 9eb202d761..6c6e41e0a5 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -485,7 +485,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ if 'calibre.ebooks.DRMError' in job.details: if not minz: from calibre.gui2.dialogs.drm_error import DRMErrorMessage - d = DRMErrorMessage(self, job.description.split(':')[-1]) + d = DRMErrorMessage(self, _('Cannot convert') + ' ' + + job.description.split(':')[-1].partition('(')[-1][:-1]) d.setModal(False) d.show() self._modeless_dialogs.append(d) From 8f38a56699d727e6338aaf3b228cb1a438b9fe76 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 17 Jan 2011 18:01:35 -0700 Subject: [PATCH 09/14] Use html editor widget for comments in convert dialog as well --- src/calibre/gui2/comments_editor.py | 5 ++ src/calibre/gui2/convert/metadata.py | 6 +- src/calibre/gui2/convert/metadata.ui | 85 ++++++++++------------------ 3 files changed, 40 insertions(+), 56 deletions(-) diff --git a/src/calibre/gui2/comments_editor.py b/src/calibre/gui2/comments_editor.py index 013d13f9e7..04bc5284ed 100644 --- a/src/calibre/gui2/comments_editor.py +++ b/src/calibre/gui2/comments_editor.py @@ -593,6 +593,11 @@ class Editor(QWidget): # {{{ def code_dirtied(self, *args): self.source_dirty = True + def hide_toolbars(self): + self.toolbar1.setVisible(False) + self.toolbar2.setVisible(False) + self.toolbar3.setVisible(False) + # }}} if __name__ == '__main__': diff --git a/src/calibre/gui2/convert/metadata.py b/src/calibre/gui2/convert/metadata.py index 5f39202e26..23cac74cf8 100644 --- a/src/calibre/gui2/convert/metadata.py +++ b/src/calibre/gui2/convert/metadata.py @@ -18,6 +18,7 @@ from calibre.ebooks.metadata.opf2 import metadata_to_opf from calibre.ptempfile import PersistentTemporaryFile from calibre.gui2.convert import Widget from calibre.utils.icu import sort_key +from calibre.library.comments import comments_to_html def create_opf_file(db, book_id): mi = db.get_metadata(book_id, index_is_id=True) @@ -57,6 +58,7 @@ class MetadataWidget(Widget, Ui_Form): self.initialize_metadata_options() self.initialize_options(get_option, get_help, db, book_id) self.connect(self.cover_button, SIGNAL("clicked()"), self.select_cover) + self.comment.hide_toolbars() def deduce_author_sort(self, *args): au = unicode(self.author.currentText()) @@ -79,7 +81,7 @@ class MetadataWidget(Widget, Ui_Form): self.author_sort.setText(mi.author_sort if mi.author_sort else '') self.tags.setText(', '.join(mi.tags if mi.tags else [])) self.tags.update_items_cache(self.db.all_tags()) - self.comment.setPlainText(mi.comments if mi.comments else '') + self.comment.html = comments_to_html(mi.comments) if mi.comments else '' if mi.series: self.series.setCurrentIndex(self.series.findText(mi.series)) if mi.series_index is not None: @@ -154,7 +156,7 @@ class MetadataWidget(Widget, Ui_Form): author_sort = unicode(self.author_sort.text()).strip() if author_sort: mi.author_sort = author_sort - comments = unicode(self.comment.toPlainText()).strip() + comments = self.comment.html if comments: mi.comments = comments mi.series_index = float(self.series_index.value()) diff --git a/src/calibre/gui2/convert/metadata.ui b/src/calibre/gui2/convert/metadata.ui index 8db4cfa2a1..61c27594c4 100644 --- a/src/calibre/gui2/convert/metadata.ui +++ b/src/calibre/gui2/convert/metadata.ui @@ -20,30 +20,6 @@ Book Cover - - - - - - - 0 - 0 - - - - - - - - - - Use cover from &source file - - - true - - - @@ -95,6 +71,30 @@ + + + + Use cover from &source file + + + true + + + + + + + + + + 0 + 0 + + + + + + opt_prefer_metadata_cover @@ -264,35 +264,7 @@ - - - - 0 - 0 - - - - - 16777215 - 200 - - - - Comments - - - - - - - 16777215 - 180 - - - - - - + @@ -325,6 +297,12 @@
calibre/gui2/widgets.h
1 + + Editor + QWidget +
calibre/gui2/comments_editor.h
+ 1 +
title @@ -334,7 +312,6 @@ tags series series_index - comment cover_path cover_button opt_prefer_metadata_cover From 798c361bcdca8634c7a1ab79704e63294a08a73b Mon Sep 17 00:00:00 2001 From: John Schember Date: Mon, 17 Jan 2011 20:38:51 -0500 Subject: [PATCH 10/14] TXT Input: Add textile option to options. --- src/calibre/ebooks/txt/input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/ebooks/txt/input.py b/src/calibre/ebooks/txt/input.py index 0b0bd6d570..cca9a74250 100644 --- a/src/calibre/ebooks/txt/input.py +++ b/src/calibre/ebooks/txt/input.py @@ -34,7 +34,7 @@ class TXTInput(InputFormatPlugin): 'starts a paragraph.' '* unformatted: Most lines have hard line breaks, few/no blank lines or indents.')), OptionRecommendation(name='formatting_type', recommended_value='auto', - choices=['auto', 'none', 'heuristic', 'markdown'], + choices=['auto', 'none', 'heuristic', 'textile', 'markdown'], help=_('Formatting used within the document.' '* auto: Automatically decide which formatting processor to use.\n' '* none: Do not process the document formatting. Everything is a ' From 39bffe09836da0a47fba0efd235d4664120241f8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 17 Jan 2011 20:43:27 -0700 Subject: [PATCH 11/14] Updated Ars Technica --- resources/recipes/ars_technica.recipe | 51 +++++++++++++++++++++------ 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/resources/recipes/ars_technica.recipe b/resources/recipes/ars_technica.recipe index 3997ee4645..3a955d5e15 100644 --- a/resources/recipes/ars_technica.recipe +++ b/resources/recipes/ars_technica.recipe @@ -1,6 +1,5 @@ - __license__ = 'GPL v3' -__copyright__ = '2008-2010, Darko Miletic ' +__copyright__ = '2008-2011, Darko Miletic ' ''' arstechnica.com ''' @@ -9,19 +8,26 @@ import re from calibre.web.feeds.news import BasicNewsRecipe from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag -class ArsTechnica2(BasicNewsRecipe): +class ArsTechnica(BasicNewsRecipe): title = u'Ars Technica' language = 'en' - __author__ = 'Darko Miletic and Sujata Raman' + __author__ = 'Darko Miletic, Sujata Raman, Alexis Rohou' description = 'The art of technology' publisher = 'Ars Technica' category = 'news, IT, technology' - oldest_article = 2 + oldest_article = 5 max_articles_per_feed = 100 no_stylesheets = True encoding = 'utf-8' use_embedded_content = False - extra_css = ' body {font-family: Arial,Helvetica,sans-serif} .title{text-align: left} .byline{font-weight: bold; line-height: 1em; font-size: 0.625em; text-decoration: none} ' + extra_css = ''' + body {font-family: Arial,Helvetica,sans-serif} + .title{text-align: left} + .byline{font-weight: bold; line-height: 1em; font-size: 0.625em; text-decoration: none} + .news-item-figure-caption-text{font-size:small; font-style:italic} + .news-item-figure-caption-byline{font-size:small; font-style:italic; font-weight:bold} + ''' + ignoreEtcArticles = True # Etc feed items can be ignored, as they're not real stories conversion_options = { 'comments' : description @@ -31,10 +37,10 @@ class ArsTechnica2(BasicNewsRecipe): } - preprocess_regexps = [ - (re.compile(r'
.*?', re.DOTALL|re.IGNORECASE),lambda match: '') - ] + #preprocess_regexps = [ + # (re.compile(r'
.*?', re.DOTALL|re.IGNORECASE),lambda match: '') + # ] keep_only_tags = [dict(name='div', attrs={'id':['story','etc-story']})] @@ -42,7 +48,7 @@ class ArsTechnica2(BasicNewsRecipe): dict(name=['object','link','embed']) ,dict(name='div', attrs={'class':'read-more-link'}) ] - remove_attributes=['width','height'] + #remove_attributes=['width','height'] feeds = [ (u'Infinite Loop (Apple content)' , u'http://feeds.arstechnica.com/arstechnica/apple/' ) @@ -56,6 +62,7 @@ class ArsTechnica2(BasicNewsRecipe): ,(u'Law & Disorder (Tech policy content)' , u'http://feeds.arstechnica.com/arstechnica/tech-policy/') ] + # This deals with multi-page stories def append_page(self, soup, appendtag, position): pager = soup.find('div',attrs={'class':'pager'}) if pager: @@ -81,6 +88,7 @@ class ArsTechnica2(BasicNewsRecipe): def preprocess_html(self, soup): + # Adds line breaks near the byline (not sure why this is needed) ftag = soup.find('div', attrs={'class':'byline'}) if ftag: brtag = Tag(soup,'br') @@ -88,12 +96,33 @@ class ArsTechnica2(BasicNewsRecipe): ftag.insert(4,brtag) ftag.insert(5,brtag2) + # Remove style items for item in soup.findAll(style=True): del item['style'] + # Remove id + for item in soup.findAll(id=True): + del item['id'] + + # For some reason, links to authors don't have the domainname + a_author = soup.find('a',{'href':re.compile("^/author")}) + if a_author: + a_author['href'] = 'http://arstechnica.com'+a_author['href'] + + # within div class news-item-figure, we need to grab images + + # Deal with multi-page stories self.append_page(soup, soup.body, 3) return soup def get_article_url(self, article): + # If the article title starts with Etc:, don't return it + if self.ignoreEtcArticles: + article_title = article.get('title',None) + if re.match('Etc: ',article_title) is not None: + return None + + # The actual article is in a guid tag return article.get('guid', None).rpartition('?')[0] + From de60086a688c87116a593154c49398a72f25a2d0 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 17 Jan 2011 21:08:07 -0700 Subject: [PATCH 12/14] Updated Seattle Times --- resources/recipes/seattle_times.recipe | 57 +++++++++++++++++++++----- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/resources/recipes/seattle_times.recipe b/resources/recipes/seattle_times.recipe index 7fcea9cae5..cd7f96fc8b 100644 --- a/resources/recipes/seattle_times.recipe +++ b/resources/recipes/seattle_times.recipe @@ -21,16 +21,53 @@ class SeattleTimes(BasicNewsRecipe): encoding = 'cp1252' language = 'en' - - html2lrf_options = [ - '--comment' , description - , '--category' , category - , '--publisher', publisher - ] - - html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"' - - feeds = [(u'Articles', u'http://seattletimes.nwsource.com/rss/seattletimes.xml')] + feeds = [ + (u'Top Stories', + u'http://seattletimes.nwsource.com/rss/home.xml'), + #(u'Articles', u'http://seattletimes.nwsource.com/rss/seattletimes.xml') + (u'Business & Technology', + u'http://seattletimes.nwsource.com/rss/businesstechnology.xml'), + (u'Personal Technology', + u'http://seattletimes.nwsource.com/rss/personaltechnology.xml'), + (u'Entertainment & the Arts', + u'http://seattletimes.nwsource.com/rss/artsentertainment.xml'), + (u'Health', + u'http://seattletimes.nwsource.com/rss/health.xml'), + (u'Living', + u'http://seattletimes.nwsource.com/rss/living.xml'), + (u'Local News', + u'http://seattletimes.nwsource.com/rss/localnews.xml'), + (u'Nation & World', + u'http://seattletimes.nwsource.com/rss/nationworld.xml'), + (u'Opinion', + u'http://seattletimes.nwsource.com/rss/opinion.xml'), + (u'Politics', + u'http://seattletimes.nwsource.com/rss/politics.xml'), + (u'Sports', + u'http://seattletimes.nwsource.com/rss/sports.xml'), + (u'Nicole Brodeur', + u'http://seattletimes.nwsource.com/rss/nicolebrodeur.xml'), + (u'Danny Westneat', + u'http://seattletimes.nwsource.com/rss/dannywestneat.xml'), + (u'Jerry Large', + u'http://seattletimes.nwsource.com/rss/jerrylarge.xml'), + (u'Ron Judd', + u'http://seattletimes.nwsource.com/rss/ronjudd.xml'), + (u'Education', + u'http://seattletimes.nwsource.com/rss/education.xml'), + (u'Letters to the Editor', + u'http://seattletimes.nwsource.com/rss/northwestvoices.xml'), + (u'Travel', + u'http://seattletimes.nwsource.com/rss/travel.xml'), + (u'Outdoors', + u'http://seattletimes.nwsource.com/rss/outdoors.xml'), + (u'Steve Kelley', + u'http://seattletimes.nwsource.com/rss/stevekelley.xml'), + (u'Jerry Brewer', + u'http://seattletimes.nwsource.com/rss/jerrybrewer.xml'), + (u'Most Read Articles', + u'http://seattletimes.nwsource.com/rss/mostreadarticles.xml'), + ] remove_tags = [ dict(name=['object','link','script']) From 1768d5cdab9520d0295c7c01f574e441f01cd4f4 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 17 Jan 2011 21:23:16 -0700 Subject: [PATCH 13/14] ... --- src/calibre/devices/eb600/driver.py | 2 +- src/calibre/devices/misc.py | 4 ++-- src/calibre/gui2/wizard/__init__.py | 15 +++++++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/calibre/devices/eb600/driver.py b/src/calibre/devices/eb600/driver.py index 3201229699..95f6dc6ab0 100644 --- a/src/calibre/devices/eb600/driver.py +++ b/src/calibre/devices/eb600/driver.py @@ -178,7 +178,7 @@ class INVESBOOK(EB600): class BOOQ(EB600): name = 'Booq Device Interface' - gui_name = 'Booq' + gui_name = 'bq Reader' FORMATS = ['epub', 'mobi', 'prc', 'fb2', 'pdf', 'doc', 'rtf', 'txt', 'html'] diff --git a/src/calibre/devices/misc.py b/src/calibre/devices/misc.py index ecd12ac61d..aaf948f25e 100644 --- a/src/calibre/devices/misc.py +++ b/src/calibre/devices/misc.py @@ -33,8 +33,8 @@ class PALMPRE(USBMS): class AVANT(USBMS): name = 'Booq Avant Device Interface' - gui_name = 'Avant' - description = _('Communicate with the Booq Avant') + gui_name = 'bq Avant' + description = _('Communicate with the Bq Avant') author = 'Kovid Goyal' supported_platforms = ['windows', 'osx', 'linux'] diff --git a/src/calibre/gui2/wizard/__init__.py b/src/calibre/gui2/wizard/__init__.py index 4e5e79bbdf..8144dcabf3 100644 --- a/src/calibre/gui2/wizard/__init__.py +++ b/src/calibre/gui2/wizard/__init__.py @@ -111,7 +111,7 @@ class Kobo(Device): id = 'kobo' class Booq(Device): - name = 'Booq Reader' + name = 'bq Classic' manufacturer = 'Booq' output_profile = 'sony' output_format = 'EPUB' @@ -125,7 +125,18 @@ class TheBook(Device): id = 'thebook' class Avant(Booq): - name = 'Booq Avant' + name = 'bq Avant' + +class AvantXL(Booq): + name = 'bq Avant XL' + output_profile = 'ipad' + +class BooqPocketPlus(Booq): + name = 'bq Pocket Plus' + output_profile = 'sony300' + +class BooqCervantes(Booq): + name = 'bq Cervantes' class Sony300(Sony505): From dccbc65fc98e3227ebb5e03f90bdeb7e5ca1ade2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 17 Jan 2011 21:50:00 -0700 Subject: [PATCH 14/14] ... --- src/calibre/gui2/preferences/plugins.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/calibre/gui2/preferences/plugins.py b/src/calibre/gui2/preferences/plugins.py index c53c634ab4..b00a485566 100644 --- a/src/calibre/gui2/preferences/plugins.py +++ b/src/calibre/gui2/preferences/plugins.py @@ -196,6 +196,12 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): def modify_plugin(self, op=''): index = self.plugin_view.currentIndex() if index.isValid(): + if not index.parent().isValid(): + name = unicode(index.data().toString()) + return error_dialog(self, _('Error'), '

'+ + _('Select an actual plugin under %s to customize')%name, + show=True, show_copy_button=False) + plugin = self._plugin_model.index_to_plugin(index) if op == 'toggle': if not plugin.can_be_disabled: