From b8bc876d078dabb2b583577b82cf3b5637aed66b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 29 Jan 2010 06:54:20 -0700 Subject: [PATCH 01/11] Fix #4721 (Bulk import stops because of utf-8 errors) --- src/calibre/gui2/add.py | 6 +++++- src/calibre/gui2/ui.py | 2 ++ src/calibre/startup.py | 1 + src/calibre/web/feeds/news.py | 3 +-- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/add.py b/src/calibre/gui2/add.py index 5419596334..ace2ac5c7e 100644 --- a/src/calibre/gui2/add.py +++ b/src/calibre/gui2/add.py @@ -12,7 +12,7 @@ from calibre.gui2.dialogs.progress import ProgressDialog from calibre.gui2 import question_dialog, error_dialog, info_dialog from calibre.ebooks.metadata.opf2 import OPF from calibre.ebooks.metadata import MetaInformation -from calibre.constants import preferred_encoding +from calibre.constants import preferred_encoding, filesystem_encoding class DuplicatesAdder(QThread): @@ -46,6 +46,8 @@ class RecursiveFind(QThread): def run(self): root = os.path.abspath(self.path) self.books = [] + if isinstance(root, unicode): + root = root.encode(filesystem_encoding) try: for dirpath in os.walk(root): if self.canceled: @@ -55,6 +57,8 @@ class RecursiveFind(QThread): self.books += list(self.db.find_books_in_directory(dirpath[0], self.single_book_per_directory)) except Exception, err: + import traceback + traceback.print_exc() try: msg = unicode(err) except: diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 714b2c3a27..28efdc93ff 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -1048,6 +1048,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): if self._adder.critical: det_msg = [] for name, log in self._adder.critical.items(): + if isinstance(name, str): + name = name.decode(filesystem_encoding, 'replace') det_msg.append(name+'\n'+log) warning_dialog(self, _('Failed to read metadata'), _('Failed to read metadata from the following')+':', diff --git a/src/calibre/startup.py b/src/calibre/startup.py index 3a761cca10..3e33757f92 100644 --- a/src/calibre/startup.py +++ b/src/calibre/startup.py @@ -84,6 +84,7 @@ if not _run_once: return res os.path.abspath = my_abspath + _join = os.path.join def my_join(a, *p): encoding=sys.getfilesystemencoding() diff --git a/src/calibre/web/feeds/news.py b/src/calibre/web/feeds/news.py index 65f6135b8e..5b8a4fc215 100644 --- a/src/calibre/web/feeds/news.py +++ b/src/calibre/web/feeds/news.py @@ -558,8 +558,6 @@ class BasicNewsRecipe(Recipe): '--max-recursions', str(self.recursions), '--delay', str(self.delay), ] - if self.encoding is not None: - web2disk_cmdline.extend(['--encoding', self.encoding]) if self.verbose: web2disk_cmdline.append('--verbose') @@ -578,6 +576,7 @@ class BasicNewsRecipe(Recipe): 'preprocess_html', 'remove_tags_after', 'remove_tags_before'): setattr(self.web2disk_options, extra, getattr(self, extra)) self.web2disk_options.postprocess_html = self._postprocess_html + self.web2disk_options.encoding = self.encoding if self.delay > 0: self.simultaneous_downloads = 1 From caac66510280309c596fa08350cfd5ebb85eb2b3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 29 Jan 2010 07:18:32 -0700 Subject: [PATCH 02/11] New recipe for Michelle Malkin by Walt Anthony --- resources/images/news/michellemalkin_icon.png | Bin 0 -> 419 bytes resources/recipes/michellemalkin.recipe | 49 ++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 resources/images/news/michellemalkin_icon.png create mode 100644 resources/recipes/michellemalkin.recipe diff --git a/resources/images/news/michellemalkin_icon.png b/resources/images/news/michellemalkin_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..76842ec64232ba2dd68a115f182e8b68ccf792fd GIT binary patch literal 419 zcmV;U0bKrxP)y-UMT6va={%>D<)4;<9WYb*W(iVjY8Q8z(R5JWc-aj-f# zh=>S+g9SmMA5rMgL0ZIib;(jxx=03*Iuz1Gq%Gt+STt$AiofN-yYJj{@8NMoMED1q zra{+r2mr9hakdA$9(@%>fvT!tjDc?#cnJYOmSt3{RWQZ?;IDxnhGC#sEI<$fh(sd4 z_d+LQH|llV7aq_f_F{Nw&{`xPYBiOTX^Bct&yID$(Xz!y#B?T$(|8iIGt<~wUq*np#xpg)W?Mg>I{OK+^7e|-V;-vubJ*Tk zv5CzB^9caL*QbW_i+(IFmC!d3bWhs_{_v;^06G?%-2nixnD1xw Date: Fri, 29 Jan 2010 08:06:26 -0700 Subject: [PATCH 03/11] Basic support for associating file types on OS X --- setup/installer/osx/app/main.py | 5 ++++- src/calibre/gui2/__init__.py | 13 ++++++++++++- src/calibre/gui2/main.py | 5 ++++- src/calibre/gui2/ui.py | 4 ++-- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/setup/installer/osx/app/main.py b/setup/installer/osx/app/main.py index 85533717b4..2a10d09998 100644 --- a/setup/installer/osx/app/main.py +++ b/setup/installer/osx/app/main.py @@ -355,6 +355,7 @@ class Py2App(object): @flush def create_plist(self): + from calibre.ebooks import BOOK_EXTENSIONS env = dict(**ENV) env['CALIBRE_LAUNCHED_FROM_BUNDLE']='1'; @@ -367,10 +368,11 @@ class Py2App(object): CFBundlePackageType='APPL', CFBundleSignature='????', CFBundleExecutable='calibre', + CFBundleTypeExtensions=list(BOOK_EXTENSIONS), LSMinimumSystemVersion='10.4.2', LSRequiresNativeExecution=True, NSAppleScriptEnabled=False, - NSHumanReadableCopyright='Copyright 2008, Kovid Goyal', + NSHumanReadableCopyright='Copyright 2010, Kovid Goyal', CFBundleGetInfoString=('calibre, an E-book management ' 'application. Visit http://calibre-ebook.com for details.'), CFBundleIconFile='library.icns', @@ -594,6 +596,7 @@ class Py2App(object): if x == 'Info.plist': plist = plistlib.readPlist(join(self.contents_dir, x)) plist['LSUIElement'] = '1' + plist.pop('CFBundleTypeExtensions') plistlib.writePlist(plist, join(cc_dir, x)) else: os.symlink(join('../..', x), diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 34f9f57161..7181c16329 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -3,7 +3,8 @@ __copyright__ = '2008, Kovid Goyal ' """ The GUI """ import os from PyQt4.QtCore import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, QSize, \ - QByteArray, QTranslator, QCoreApplication, QThread + QByteArray, QTranslator, QCoreApplication, QThread, \ + QEvent from PyQt4.QtGui import QFileDialog, QMessageBox, QPixmap, QFileIconProvider, \ QIcon, QTableView, QApplication, QDialog, QPushButton @@ -524,6 +525,7 @@ class Application(QApplication): def __init__(self, args): qargs = [i.encode('utf-8') if isinstance(i, unicode) else i for i in args] QApplication.__init__(self, qargs) + self.file_event_hook = None global gui_thread, qt_app gui_thread = QThread.currentThread() self._translator = None @@ -549,6 +551,15 @@ class Application(QApplication): if set_qt_translator(self._translator): self.installTranslator(self._translator) + def event(self, e): + if callable(self.file_event_hook) and e.type() == QEvent.FileOpen: + path = unicode(e.file()) + if os.access(path, os.R_OK): + self.file_event_hook(path) + return True + else: + return QApplication.event(self, e) + _store_app = None def is_ok_to_use_qt(): diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index cf62508751..fef0853a23 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -2,6 +2,7 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal ' import sys, os, time, socket, traceback +from functools import partial from PyQt4.Qt import QCoreApplication, QIcon, QMessageBox @@ -52,10 +53,12 @@ def run_gui(opts, args, actions, listener, app): wizard().exec_() dynamic.set('welcome_wizard_was_run', True) main = Main(listener, opts, actions) + add_filesystem_book = partial(main.add_filesystem_book, allow_device=False) sys.excepthook = main.unhandled_exception if len(args) > 1: args[1] = os.path.abspath(args[1]) - main.add_filesystem_book(args[1]) + add_filesystem_book(args[1]) + app.file_event_hook = add_filesystem_book ret = app.exec_() if getattr(main, 'run_wizard_b4_shutdown', False): from calibre.gui2.wizard import wizard diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 28efdc93ff..7f3ca297fd 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -987,10 +987,10 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.cover_cache.refresh([cid]) self.library_view.model().current_changed(current_idx, current_idx) - def add_filesystem_book(self, path): + def add_filesystem_book(self, path, allow_device=True): if os.access(path, os.R_OK): books = [os.path.abspath(path)] - to_device = self.stack.currentIndex() != 0 + to_device = allow_device and self.stack.currentIndex() != 0 self._add_books(books, to_device) if to_device: self.status_bar.showMessage(\ From b3bcd13f3a4b497979ca6de706d6ab8003a9ffc0 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 29 Jan 2010 08:58:51 -0700 Subject: [PATCH 04/11] OS X: Allow adding of books to calibre via drag and drop on the calibre dock icon --- icons/book.icns | Bin 0 -> 11285 bytes setup/installer/osx/app/main.py | 13 +++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 icons/book.icns diff --git a/icons/book.icns b/icons/book.icns new file mode 100644 index 0000000000000000000000000000000000000000..ee305dc9ddc3f40a512d1364d88719a6855d62eb GIT binary patch literal 11285 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 literal 0 HcmV?d00001 diff --git a/setup/installer/osx/app/main.py b/setup/installer/osx/app/main.py index 2a10d09998..a473281e61 100644 --- a/setup/installer/osx/app/main.py +++ b/setup/installer/osx/app/main.py @@ -266,6 +266,7 @@ class Py2App(object): def get_local_dependencies(self, path_to_lib): for x in self.get_dependencies(path_to_lib): for y in (SW+'/lib/', '/usr/local/lib/', SW+'/qt/lib/', + '/opt/local/lib/', '/Library/Frameworks/Python.framework/', SW+'/freetype/lib/'): if x.startswith(y): if y == '/Library/Frameworks/Python.framework/': @@ -338,8 +339,8 @@ class Py2App(object): c = join(self.build_dir, 'Contents') for x in ('Frameworks', 'MacOS', 'Resources'): os.makedirs(join(c, x)) - x = 'library.icns' - shutil.copyfile(join('icons', x), join(self.resources_dir, x)) + for x in ('library.icns', 'book.icns'): + shutil.copyfile(join('icons', x), join(self.resources_dir, x)) @flush def add_calibre_plugins(self): @@ -358,6 +359,10 @@ class Py2App(object): from calibre.ebooks import BOOK_EXTENSIONS env = dict(**ENV) env['CALIBRE_LAUNCHED_FROM_BUNDLE']='1'; + docs = [{'CFBundleTypeName':'E-book', + 'CFBundleTypeExtensions':list(BOOK_EXTENSIONS), + 'CFBundleTypeRole':'Viewer', + }] pl = dict( CFBundleDevelopmentRegion='English', @@ -368,7 +373,7 @@ class Py2App(object): CFBundlePackageType='APPL', CFBundleSignature='????', CFBundleExecutable='calibre', - CFBundleTypeExtensions=list(BOOK_EXTENSIONS), + CFBundleDocumentTypes=docs, LSMinimumSystemVersion='10.4.2', LSRequiresNativeExecution=True, NSAppleScriptEnabled=False, @@ -596,7 +601,7 @@ class Py2App(object): if x == 'Info.plist': plist = plistlib.readPlist(join(self.contents_dir, x)) plist['LSUIElement'] = '1' - plist.pop('CFBundleTypeExtensions') + plist.pop('CFBundleDocumentTypes') plistlib.writePlist(plist, join(cc_dir, x)) else: os.symlink(join('../..', x), From 800981cb5857ab1098b77ccd05bff9bd40e3fb68 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 29 Jan 2010 09:54:44 -0700 Subject: [PATCH 05/11] New recipe for Open Left by XanthanGum --- resources/recipes/open_left.recipe | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 resources/recipes/open_left.recipe diff --git a/resources/recipes/open_left.recipe b/resources/recipes/open_left.recipe new file mode 100644 index 0000000000..148bb07f13 --- /dev/null +++ b/resources/recipes/open_left.recipe @@ -0,0 +1,22 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class OpenLeft(BasicNewsRecipe): + # Information about the recipe + + title = 'Open Left' + description = 'Progressive American commentary on current events' + category = 'news, commentary' + language = 'en' + __author__ = 'Xanthan Gum' + + # Fetch no article older than seven days + + oldest_article = 7 + + # Fetch no more than 100 articles + + max_articles_per_feed = 100 + + # Fetch the articles from the RSS feed + + feeds = [(u'Articles', u'http://www.openleft.com/rss/rss2.xml')] From 0b04ea9ffd9a96575059603f74057ba7e768f09d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 29 Jan 2010 10:54:44 -0700 Subject: [PATCH 06/11] Fix #4693 (Bulk edit metadata - can not set rating to 0 stars) --- src/calibre/gui2/dialogs/metadata_bulk.py | 6 +----- src/calibre/gui2/dialogs/metadata_bulk.ui | 9 +++++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index d76d8136db..46342c8a88 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -20,10 +20,8 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): self.db = db self.ids = [ db.id(r) for r in rows] self.write_series = False - self.write_rating = False self.changed = False QObject.connect(self.button_box, SIGNAL("accepted()"), self.sync) - QObject.connect(self.rating, SIGNAL('valueChanged(int)'), self.rating_changed) self.tags.update_tags_cache(self.db.all_tags()) self.remove_tags.update_tags_cache(self.db.all_tags()) @@ -99,7 +97,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): aus = unicode(self.author_sort.text()) if aus and self.author_sort.isEnabled(): self.db.set_author_sort(id, aus, notify=False) - if self.write_rating: + if self.rating.value() != -1: self.db.set_rating(id, 2*self.rating.value(), notify=False) pub = unicode(self.publisher.text()) if pub: @@ -134,5 +132,3 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): def series_changed(self): self.write_series = True - def rating_changed(self): - self.write_rating = True diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index 0fdb36b717..1a38568b60 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -96,12 +96,21 @@ QAbstractSpinBox::PlusMinus + + No change + stars + + -1 + 5 + + -1 + From 37c90afed4f9aa2774f6ff573b92f7e9cfa3c11d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 29 Jan 2010 10:58:04 -0700 Subject: [PATCH 07/11] ... --- src/calibre/gui2/viewer/documentview.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index 6b95a4dcaa..9b911754c8 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -514,7 +514,7 @@ class DocumentView(QWebView): mt = guess_type(path)[0] html = open(path, 'rb').read().decode(path.encoding, 'replace') html = EntityDeclarationProcessor(html).processed_html - has_svg = re.search(r'<[:a-z]*svg', html) is not None + has_svg = re.search(r'<[:a-zA-Z]*svg', html) is not None if 'xhtml' in mt: html = self.self_closing_pat.sub(self.self_closing_sub, html) From 79bb3ba0053df10d79c527812b42cf6b454bba2c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 29 Jan 2010 11:22:30 -0700 Subject: [PATCH 08/11] Fix #4683 (If comics.txt is UTF-8 with a byte order mark, the first comic is skipped) --- src/calibre/ebooks/comic/input.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/calibre/ebooks/comic/input.py b/src/calibre/ebooks/comic/input.py index 122f61e45a..6fba918888 100755 --- a/src/calibre/ebooks/comic/input.py +++ b/src/calibre/ebooks/comic/input.py @@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en' Based on ideas from comiclrf created by FangornUK. ''' -import os, shutil, traceback, textwrap, time +import os, shutil, traceback, textwrap, time, codecs from ctypes import byref from Queue import Empty @@ -338,8 +338,9 @@ class ComicInput(InputFormatPlugin): if not os.path.exists('comics.txt'): raise ValueError('%s is not a valid comic collection' %stream.name) - for line in open('comics.txt', - 'rb').read().decode('utf-8').splitlines(): + raw = open('comics.txt', 'rb').read().decode('utf-8') + raw.lstrip(unicode(codecs.BOM_UTF8, "utf8" )) + for line in raw.splitlines(): line = line.strip() if not line: continue From d2b721e678b8dc8927ba5d58bb724f378c0a9eea Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 29 Jan 2010 12:58:07 -0700 Subject: [PATCH 09/11] EPUB Output: Remove tags that point to the internet for their images as this causes the ever delicate ADE to crash. Fixes #4692 (epub file from NY Times (subscription) site crashes Sony PRS-700) --- src/calibre/ebooks/epub/output.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/ebooks/epub/output.py b/src/calibre/ebooks/epub/output.py index 8e9c9efea9..6e381d5237 100644 --- a/src/calibre/ebooks/epub/output.py +++ b/src/calibre/ebooks/epub/output.py @@ -269,7 +269,7 @@ class EPUBOutput(OutputFormatPlugin): bad = [] for x in XPath('//h:img')(body): src = x.get('src', '').strip() - if src in ('', '#'): + if src in ('', '#') or src.startswith('http:'): bad.append(x) for img in bad: img.getparent().remove(img) From 2a51e38d221739c84b7ca707623964c1cb55c92b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 29 Jan 2010 13:07:22 -0700 Subject: [PATCH 10/11] MOBI Input: Ignore width and height percentage measures for tags. Fixes #4726 (using calibre 0.6.36, chapter head graphics take all page in viewer) --- src/calibre/ebooks/mobi/reader.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py index 4f894ce088..4aac84e599 100644 --- a/src/calibre/ebooks/mobi/reader.py +++ b/src/calibre/ebooks/mobi/reader.py @@ -573,6 +573,8 @@ class MobiReader(object): attrib[attr] = "%dpx"%int(nval) except: del attrib[attr] + elif val.lower().endswith('%'): + del attrib[attr] elif tag.tag == 'pre': if not tag.text: tag.tag = 'div' From 5fb1d6ab82ad774f2a4d4400856493266e7cfef2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 29 Jan 2010 13:09:47 -0700 Subject: [PATCH 11/11] Fix #4727 (AttributeError: 'MetaInformation' object has no attribute 'thumnbail') --- src/calibre/devices/prs500/books.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/devices/prs500/books.py b/src/calibre/devices/prs500/books.py index 07f9310e87..91fcb3255f 100644 --- a/src/calibre/devices/prs500/books.py +++ b/src/calibre/devices/prs500/books.py @@ -274,7 +274,7 @@ class BookList(_BookList): node.setAttribute(attr, attrs[attr]) try: w, h, data = mi.thumbnail - except TypeError: + except: w, h, data = None, None, None if data: