diff --git a/resources/recipes/nytimes.recipe b/resources/recipes/nytimes.recipe index eba717027e..ec546569e5 100644 --- a/resources/recipes/nytimes.recipe +++ b/resources/recipes/nytimes.recipe @@ -16,7 +16,7 @@ class NYTimes(BasicNewsRecipe): title = 'New York Times Top Stories' __author__ = 'GRiker' - language = _('English') + language = 'en' description = 'Top Stories from the New York Times' # List of sections typically included in Top Stories. Use a keyword from the diff --git a/src/calibre/devices/apple/driver.py b/src/calibre/devices/apple/driver.py index 6a240c7040..13be5952a9 100644 --- a/src/calibre/devices/apple/driver.py +++ b/src/calibre/devices/apple/driver.py @@ -14,7 +14,6 @@ from calibre.devices.interface import DevicePlugin from calibre.ebooks.BeautifulSoup import BeautifulSoup from calibre.ebooks.metadata import MetaInformation from calibre.library.server.utils import strftime -from calibre.ptempfile import PersistentTemporaryFile from calibre.utils.config import Config, config_dir from calibre.utils.date import parse_date from calibre.utils.logging import Log @@ -775,10 +774,12 @@ class ITUNES(DevicePlugin): self._remove_from_iTunes(self.cached_books[path]) # Add to iTunes Library|Books - if isinstance(file,PersistentTemporaryFile): - added = self.iTunes.add(appscript.mactypes.File(file._name)) - else: - added = self.iTunes.add(appscript.mactypes.File(file)) + fpath = file + if getattr(file, 'orig_file_path', None) is not None: + fpath = file.orig_file_path + elif getattr(file, 'name', None) is not None: + fpath = file.name + added = self.iTunes.add(appscript.mactypes.File(fpath)) thumb = None if metadata[i].cover: @@ -815,7 +816,7 @@ class ITUNES(DevicePlugin): this_book.device_collections = [] this_book.library_id = added this_book.path = path - this_book.size = self._get_device_book_size(file, added.size()) + this_book.size = self._get_device_book_size(fpath, added.size()) this_book.thumbnail = thumb this_book.iTunes_id = added @@ -922,12 +923,15 @@ class ITUNES(DevicePlugin): self.log.info(" '%s' not in cached_books" % metadata[i].title) # Add to iTunes Library|Books - if isinstance(file,PersistentTemporaryFile): - op_status = lib_books.AddFile(file._name) - self.log.info("ITUNES.upload_books():\n iTunes adding '%s'" % file._name) - else: - op_status = lib_books.AddFile(file) - self.log.info(" iTunes adding '%s'" % file) + fpath = file + if getattr(file, 'orig_file_path', None) is not None: + fpath = file.orig_file_path + elif getattr(file, 'name', None) is not None: + fpath = file.name + + op_status = lib_books.AddFile(fpath) + self.log.info("ITUNES.upload_books():\n iTunes adding '%s'" + % fpath) if DEBUG: sys.stdout.write(" iTunes copying '%s' ..." % metadata[i].title) @@ -1464,7 +1468,7 @@ class ITUNES(DevicePlugin): # Read the current storage path for iTunes media cmd = "defaults read com.apple.itunes NSNavLastRootDirectory" proc = subprocess.Popen( cmd, shell=True, cwd=os.curdir, stdout=subprocess.PIPE) - retcode = proc.wait() + proc.wait() media_dir = os.path.abspath(proc.communicate()[0].strip()) if os.path.exists(media_dir): self.iTunes_media = media_dir diff --git a/src/calibre/devices/interface.py b/src/calibre/devices/interface.py index 35617d8097..2d82bf4563 100644 --- a/src/calibre/devices/interface.py +++ b/src/calibre/devices/interface.py @@ -287,7 +287,9 @@ class DevicePlugin(Plugin): This method should raise a L{FreeSpaceError} if there is not enough free space on the device. The text of the FreeSpaceError must contain the word "card" if C{on_card} is not None otherwise it must contain the word "memory". - :files: A list of paths and/or file-like objects. + :files: A list of paths and/or file-like objects. If they are paths and + the paths point to temporary files, they may have an additional + attribute, original_file_path pointing to the originals. :names: A list of file names that the books should have once uploaded to the device. len(names) == len(files) :return: A list of 3-element tuples. The list is meant to be passed diff --git a/src/calibre/devices/usbms/books.py b/src/calibre/devices/usbms/books.py index ce33aebc0b..d065d0f47a 100644 --- a/src/calibre/devices/usbms/books.py +++ b/src/calibre/devices/usbms/books.py @@ -108,7 +108,7 @@ class BookList(_BookList): def add_book(self, book, replace_metadata): try: b = self.index(book) - except ValueError, IndexError: + except (ValueError, IndexError): b = None if b is None: self.append(book) diff --git a/src/calibre/devices/usbms/device.py b/src/calibre/devices/usbms/device.py index cb95374ed5..2f01b8dd41 100644 --- a/src/calibre/devices/usbms/device.py +++ b/src/calibre/devices/usbms/device.py @@ -765,12 +765,8 @@ class Device(DeviceConfig, DevicePlugin): path = existing[0] def get_size(obj): - if hasattr(obj, 'seek'): - obj.seek(0, os.SEEK_END) - size = obj.tell() - obj.seek(0) - return size - return os.path.getsize(obj) + path = getattr(obj, 'name', obj) + return os.path.getsize(path) sizes = [get_size(f) for f in files] size = sum(sizes) diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index fd102f6dbd..378c585efb 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -1,6 +1,8 @@ from __future__ import with_statement __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal ' + +# Imports {{{ import os, traceback, Queue, time, socket, cStringIO, re from threading import Thread, RLock from itertools import repeat @@ -27,7 +29,9 @@ from calibre.utils.smtp import compose_mail, sendmail, extract_email_address, \ config as email_config from calibre.devices.folder_device.driver import FOLDER_DEVICE -class DeviceJob(BaseJob): +# }}} + +class DeviceJob(BaseJob): # {{{ def __init__(self, func, done, job_manager, args=[], kwargs={}, description=''): @@ -78,8 +82,9 @@ class DeviceJob(BaseJob): def log_file(self): return cStringIO.StringIO(self._details.encode('utf-8')) + # }}} -class DeviceManager(Thread): +class DeviceManager(Thread): # {{{ def __init__(self, connected_slot, job_manager, open_feedback_slot, sleep_time=2): ''' @@ -338,8 +343,9 @@ class DeviceManager(Thread): return self.create_job(self._view_book, done, args=[path, target], description=_('View book on device')) + # }}} -class DeviceAction(QAction): +class DeviceAction(QAction): # {{{ a_s = pyqtSignal(object) @@ -356,9 +362,9 @@ class DeviceAction(QAction): def __repr__(self): return self.__class__.__name__ + ':%s:%s:%s'%(self.dest, self.delete, self.specific) + # }}} - -class DeviceMenu(QMenu): +class DeviceMenu(QMenu): # {{{ fetch_annotations = pyqtSignal() connect_to_folder = pyqtSignal() @@ -532,8 +538,9 @@ class DeviceMenu(QMenu): annot_enable = enable and getattr(device, 'SUPPORTS_ANNOTATIONS', False) self.annotation_action.setEnabled(annot_enable) + # }}} -class Emailer(Thread): +class Emailer(Thread): # {{{ def __init__(self, timeout=60): Thread.__init__(self) @@ -590,6 +597,7 @@ class Emailer(Thread): results.append([jobname, e, traceback.format_exc()]) callback(results) + # }}} class DeviceGUI(object): @@ -637,7 +645,7 @@ class DeviceGUI(object): if not ids or len(ids) == 0: return files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(ids, - fmts, paths=True, set_metadata=True, + fmts, set_metadata=True, specific_format=specific_format, exclude_auto=do_auto_convert) if do_auto_convert: @@ -647,7 +655,6 @@ class DeviceGUI(object): _auto_ids = [] full_metadata = self.library_view.model().metadata_for(ids) - files = [getattr(f, 'name', None) for f in files] bad, remove_ids, jobnames = [], [], [] texts, subjects, attachments, attachment_names = [], [], [], [] @@ -760,7 +767,7 @@ class DeviceGUI(object): for account, fmts in accounts: files, auto = self.library_view.model().\ get_preferred_formats_from_ids([id], fmts) - files = [f.name for f in files if f is not None] + files = [f for f in files if f is not None] if not files: continue attachment = files[0] @@ -824,7 +831,7 @@ class DeviceGUI(object): prefix = prefix.decode(preferred_encoding, 'replace') prefix = ascii_filename(prefix) names.append('%s_%d%s'%(prefix, id, - os.path.splitext(f.name)[1])) + os.path.splitext(f)[1])) if mi.cover and os.access(mi.cover, os.R_OK): mi.thumbnail = self.cover_to_thumbnail(open(mi.cover, 'rb').read()) @@ -837,7 +844,7 @@ class DeviceGUI(object): on_card = space.get(sorted(space.keys(), reverse=True)[0], None) self.upload_books(files, names, metadata, on_card=on_card, - memory=[[f.name for f in files], remove]) + memory=[files, remove]) self.status_bar.showMessage(_('Sending catalogs to device.'), 5000) @@ -884,7 +891,7 @@ class DeviceGUI(object): prefix = prefix.decode(preferred_encoding, 'replace') prefix = ascii_filename(prefix) names.append('%s_%d%s'%(prefix, id, - os.path.splitext(f.name)[1])) + os.path.splitext(f)[1])) if mi.cover and os.access(mi.cover, os.R_OK): mi.thumbnail = self.cover_to_thumbnail(open(mi.cover, 'rb').read()) @@ -898,7 +905,7 @@ class DeviceGUI(object): on_card = space.get(sorted(space.keys(), reverse=True)[0], None) self.upload_books(files, names, metadata, on_card=on_card, - memory=[[f.name for f in files], remove]) + memory=[files, remove]) self.status_bar.showMessage(_('Sending news to device.'), 5000) @@ -914,7 +921,7 @@ class DeviceGUI(object): _files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(ids, settings.format_map, - paths=True, set_metadata=True, + set_metadata=True, specific_format=specific_format, exclude_auto=do_auto_convert) if do_auto_convert: @@ -930,9 +937,8 @@ class DeviceGUI(object): mi.thumbnail = self.cover_to_thumbnail(open(mi.cover, 'rb').read()) imetadata = iter(metadata) - files = [getattr(f, 'name', None) for f in _files] bad, good, gf, names, remove_ids = [], [], [], [], [] - for f in files: + for f in _files: mi = imetadata.next() id = ids.next() if f is None: diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 5bccfd7c0d..abd80aaa8f 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -21,7 +21,8 @@ from calibre.utils.date import dt_factory, qt_to_dt, isoformat from calibre.ebooks.metadata.meta import set_metadata as _set_metadata from calibre.utils.search_query_parser import SearchQueryParser from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH -from calibre import strftime +from calibre import strftime, isbytestring +from calibre.constants import filesystem_encoding from calibre.gui2.library import DEFAULT_SORT def human_readable(size, precision=1): @@ -33,6 +34,13 @@ TIME_FMT = '%d %b %Y' ALIGNMENT_MAP = {'left': Qt.AlignLeft, 'right': Qt.AlignRight, 'center': Qt.AlignHCenter} +class FormatPath(unicode): + + def __new__(cls, path, orig_file_path): + ans = unicode.__new__(cls, path) + ans.orig_file_path = orig_file_path + return ans + class BooksModel(QAbstractTableModel): # {{{ about_to_be_sorted = pyqtSignal(object, name='aboutToBeSorted') @@ -379,7 +387,7 @@ class BooksModel(QAbstractTableModel): # {{{ else: return metadata - def get_preferred_formats_from_ids(self, ids, formats, paths=False, + def get_preferred_formats_from_ids(self, ids, formats, set_metadata=False, specific_format=None, exclude_auto=False, mode='r+b'): ans = [] @@ -404,12 +412,20 @@ class BooksModel(QAbstractTableModel): # {{{ as_file=True)) as src: shutil.copyfileobj(src, pt) pt.flush() + if getattr(src, 'name', None): + pt.orig_file_path = os.path.abspath(src.name) pt.seek(0) if set_metadata: _set_metadata(pt, self.db.get_metadata(id, get_cover=True, index_is_id=True), format) - pt.close() if paths else pt.seek(0) - ans.append(pt) + pt.close() + def to_uni(x): + if isbytestring(x): + x = x.decode(filesystem_encoding) + return x + name, op = map(to_uni, map(os.path.abspath, (pt.name, + pt.orig_file_path))) + ans.append(FormatPath(name, op)) else: need_auto.append(id) if not exclude_auto: diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index 95b83b407c..056838750f 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -186,7 +186,7 @@ class TagsView(QTreeView): # {{{ def is_visible(self, idx): item = idx.internalPointer() - if item.type == TagTreeItem.TAG: + if getattr(item, 'type', None) == TagTreeItem.TAG: idx = idx.parent() return self.isExpanded(idx)