Exemple #1
0
 def filesystem_cache(self):
     if self._filesystem_cache is None:
         debug('Loading filesystem metadata...')
         st = time.time()
         from calibre.devices.mtp.filesystem_cache import FilesystemCache
         ts = self.total_space()
         all_storage = []
         items = []
         for storage_id, capacity in zip([self._main_id, self._carda_id,
             self._cardb_id], ts):
             if storage_id is None: continue
             name = _('Unknown')
             for s in self.dev.data['storage']:
                 if s['id'] == storage_id:
                     name = s['name']
                     break
             storage = {'id':storage_id, 'size':capacity, 'name':name,
                     'is_folder':True, 'can_delete':False, 'is_system':True}
             self._currently_getting_sid = unicode(storage_id)
             id_map = self.dev.get_filesystem(storage_id,
                     self._filesystem_callback)
             for x in id_map.itervalues(): x['storage_id'] = storage_id
             all_storage.append(storage)
             items.append(id_map.itervalues())
         self._filesystem_cache = FilesystemCache(all_storage, chain(*items))
         debug('Filesystem metadata loaded in %g seconds (%d objects)'%(
             time.time()-st, len(self._filesystem_cache)))
     return self._filesystem_cache
Exemple #2
0
 def filesystem_cache(self):
     if self._filesystem_cache is None:
         st = time.time()
         debug('Loading filesystem metadata...')
         from calibre.devices.mtp.filesystem_cache import FilesystemCache
         with self.lock:
             storage, all_items, all_errs = [], [], []
             for sid, capacity in zip([self._main_id, self._carda_id,
                 self._cardb_id], self.total_space()):
                 if sid is None: continue
                 name = _('Unknown')
                 for x in self.dev.storage_info:
                     if x['id'] == sid:
                         name = x['name']
                         break
                 storage.append({'id':sid, 'size':capacity,
                     'is_folder':True, 'name':name, 'can_delete':False,
                     'is_system':True})
                 items, errs = self.dev.get_filesystem(sid,
                         self._filesystem_callback)
                 all_items.extend(items), all_errs.extend(errs)
             if not all_items and all_errs:
                 raise DeviceError(
                         'Failed to read filesystem from %s with errors: %s'
                         %(self.current_friendly_name,
                             self.format_errorstack(all_errs)))
             if all_errs:
                 prints('There were some errors while getting the '
                         ' filesystem from %s: %s'%(
                             self.current_friendly_name,
                             self.format_errorstack(all_errs)))
             self._filesystem_cache = FilesystemCache(storage, all_items)
         debug('Filesystem metadata loaded in %g seconds (%d objects)'%(
             time.time()-st, len(self._filesystem_cache)))
     return self._filesystem_cache
Exemple #3
0
 def sync_booklists(self, booklists, end_session=True):
     debug('sync_booklists() called')
     for bl in booklists:
         if getattr(bl, 'storage_id', None) is None:
             continue
         storage = self.filesystem_cache.storage(bl.storage_id)
         if storage is None:
             continue
         self.write_metadata_cache(storage, bl)
     debug('sync_booklists() ended')
Exemple #4
0
 def osx_is_device_mtp(self, d, debug=None):
     if not d.serial:
         ans = False
     else:
         try:
             ans = self.usbobserver.is_mtp_device(d.vendor_id, d.product_id, d.bcd, d.serial)
         except Exception:
             if debug is not None:
                 import traceback
                 traceback.print_stack()
             return False
     if debug is not None and ans:
         debug('Device {0} claims to be an MTP device in the IOKit registry'.format(d))
     return bool(ans)
Exemple #5
0
 def _filesystem_callback(self, fs_map, entry, level):
     name = entry.get('name', '')
     self.filesystem_callback(_('Found object: %s')%name)
     fs_map[entry.get('id', null)] = entry
     path = [name]
     pid = entry.get('parent_id', 0)
     while pid != 0 and pid in fs_map:
         parent = fs_map[pid]
         path.append(parent.get('name', ''))
         pid = parent.get('parent_id', 0)
         if fs_map.get(pid, None) is parent:
             break  # An object is its own parent
     path = tuple(reversed(path))
     ok = not self.is_folder_ignored(self._currently_getting_sid, path)
     if not ok:
         debug('Ignored object: %s' % '/'.join(path))
     return ok
Exemple #6
0
    def upload_books(self, files, names, on_card=None, end_session=True,
                     metadata=None):
        debug('upload_books() called')
        from calibre.devices.utils import sanity_check
        sanity_check(on_card, files, self.card_prefix(), self.free_space())
        prefix = self.prefix_for_location(on_card)
        sid = {'carda':self._carda_id, 'cardb':self._cardb_id}.get(on_card,
                self._main_id)
        bl_idx = {'carda':1, 'cardb':2}.get(on_card, 0)
        storage = self.filesystem_cache.storage(sid)

        ans = []
        self.report_progress(0, _('Transferring books to device...'))
        i, total = 0, len(files)

        routing = {fmt:dest for fmt,dest in self.get_pref('rules')}

        for infile, fname, mi in izip(files, names, metadata):
            path = self.create_upload_path(prefix, mi, fname, routing)
            if path and self.is_folder_ignored(storage, path):
                raise MTPInvalidSendPathError('/'.join(path))
            parent = self.ensure_parent(storage, path)
            if hasattr(infile, 'read'):
                pos = infile.tell()
                infile.seek(0, 2)
                sz = infile.tell()
                infile.seek(pos)
                stream = infile
                close = False
            else:
                sz = os.path.getsize(infile)
                stream = lopen(infile, 'rb')
                close = True
            try:
                mtp_file = self.put_file(parent, path[-1], stream, sz)
            finally:
                if close:
                    stream.close()
            ans.append((mtp_file, bl_idx))
            i += 1
            self.report_progress(i/total, _('Transferred %s to device')%mi.title)

        self.report_progress(1, _('Transfer to device finished...'))
        debug('upload_books() ended')
        return ans
Exemple #7
0
    def add_books_to_metadata(self, mtp_files, metadata, booklists):
        debug('add_books_to_metadata() called')
        from calibre.devices.mtp.books import Book

        i, total = 0, len(mtp_files)
        self.report_progress(0, _('Adding books to device metadata listing...'))
        for x, mi in izip(mtp_files, metadata):
            mtp_file, bl_idx = x
            bl = booklists[bl_idx]
            book = Book(mtp_file.storage_id, '/'.join(mtp_file.mtp_relpath),
                    other=mi)
            book = bl.add_book(book, replace_metadata=True)
            if book is not None:
                book.size = mtp_file.size
                book.datetime = mtp_file.last_modified.timetuple()
                book.path = mtp_file.mtp_id_path
            i += 1
            self.report_progress(i/total, _('Added %s')%mi.title)

        self.report_progress(1, _('Adding complete'))
        debug('add_books_to_metadata() ended')
Exemple #8
0
    def add_books_to_metadata(self, mtp_files, metadata, booklists):
        debug('add_books_to_metadata() called')
        from calibre.devices.mtp.books import Book

        i, total = 0, len(mtp_files)
        self.report_progress(0, _('Adding books to device metadata listing...'))
        for x, mi in zip(mtp_files, metadata):
            mtp_file, bl_idx = x
            bl = booklists[bl_idx]
            book = Book(mtp_file.storage_id, '/'.join(mtp_file.mtp_relpath),
                    other=mi)
            book = bl.add_book(book, replace_metadata=True)
            if book is not None:
                book.size = mtp_file.size
                book.datetime = mtp_file.last_modified.timetuple()
                book.path = mtp_file.mtp_id_path
            i += 1
            self.report_progress(i/total, _('Added %s')%mi.title)

        self.report_progress(1, _('Adding complete'))
        debug('add_books_to_metadata() ended')
Exemple #9
0
 def filesystem_cache(self):
     if self._filesystem_cache is None:
         debug('Loading filesystem metadata...')
         st = time.time()
         from calibre.devices.mtp.filesystem_cache import FilesystemCache
         ts = self.total_space()
         all_storage = []
         items = []
         for storage_id, capacity in zip(
             [self._main_id, self._carda_id, self._cardb_id], ts):
             if storage_id is None:
                 continue
             name = _('Unknown')
             for s in self.dev.data['storage']:
                 if s['id'] == storage_id:
                     name = s['name']
                     break
             storage = {
                 'id': storage_id,
                 'size': capacity,
                 'name': name,
                 'is_folder': True,
                 'can_delete': False,
                 'is_system': True
             }
             self._currently_getting_sid = unicode_type(storage_id)
             id_map = self.dev.get_filesystem(
                 storage_id, partial(self._filesystem_callback, {}))
             for x in itervalues(id_map):
                 x['storage_id'] = storage_id
             all_storage.append(storage)
             items.append(itervalues(id_map))
         self._filesystem_cache = FilesystemCache(all_storage,
                                                  chain(*items))
         debug('Filesystem metadata loaded in %g seconds (%d objects)' %
               (time.time() - st, len(self._filesystem_cache)))
     return self._filesystem_cache
Exemple #10
0
 def filesystem_cache(self):
     if self._filesystem_cache is None:
         st = time.time()
         debug('Loading filesystem metadata...')
         from calibre.devices.mtp.filesystem_cache import FilesystemCache
         with self.lock:
             storage, all_items, all_errs = [], [], []
             for sid, capacity in zip([self._main_id, self._carda_id,
                 self._cardb_id], self.total_space()):
                 if sid is None:
                     continue
                 name = _('Unknown')
                 for x in self.dev.storage_info:
                     if x['id'] == sid:
                         name = x['name']
                         break
                 storage.append({'id':sid, 'size':capacity,
                     'is_folder':True, 'name':name, 'can_delete':False,
                     'is_system':True})
                 self._currently_getting_sid = unicode_type(sid)
                 items, errs = self.dev.get_filesystem(sid,
                         partial(self._filesystem_callback, {}))
                 all_items.extend(items), all_errs.extend(errs)
             if not all_items and all_errs:
                 raise DeviceError(
                         'Failed to read filesystem from %s with errors: %s'
                         %(self.current_friendly_name,
                             self.format_errorstack(all_errs)))
             if all_errs:
                 prints('There were some errors while getting the '
                         ' filesystem from %s: %s'%(
                             self.current_friendly_name,
                             self.format_errorstack(all_errs)))
             self._filesystem_cache = FilesystemCache(storage, all_items)
         debug('Filesystem metadata loaded in %g seconds (%d objects)'%(
             time.time()-st, len(self._filesystem_cache)))
     return self._filesystem_cache
Exemple #11
0
    def books(self, oncard=None, end_session=True):
        from calibre.devices.mtp.books import JSONCodec
        from calibre.devices.mtp.books import BookList, Book
        self.report_progress(0, _('Listing files, this can take a while'))
        self.get_driveinfo()  # Ensure driveinfo is loaded
        sid = {'carda':self._carda_id, 'cardb':self._cardb_id}.get(oncard,
                self._main_id)
        if sid is None:
            return BookList(None)

        bl = BookList(sid)
        # If True then there is a mismatch between the ebooks on the device and
        # the metadata cache
        need_sync = False
        all_books = list(self.filesystem_cache.iterebooks(sid))
        steps = len(all_books) + 2
        count = 0

        self.report_progress(0, _('Reading e-book metadata'))
        # Read the cache if it exists
        storage = self.filesystem_cache.storage(sid)
        cache = storage.find_path(self.calibre_file_paths['metadata'].split('/'))
        if cache is not None:
            json_codec = JSONCodec()
            try:
                stream = self.get_mtp_file(cache)
                json_codec.decode_from_file(stream, bl, Book, sid)
            except:
                need_sync = True

        relpath_cache = {b.mtp_relpath:i for i, b in enumerate(bl)}

        for mtp_file in all_books:
            count += 1
            relpath = mtp_file.mtp_relpath
            idx = relpath_cache.get(relpath, None)
            if idx is not None:
                cached_metadata = bl[idx]
                del relpath_cache[relpath]
                if cached_metadata.size == mtp_file.size:
                    cached_metadata.datetime = mtp_file.last_modified.timetuple()
                    cached_metadata.path = mtp_file.mtp_id_path
                    debug('Using cached metadata for',
                            '/'.join(mtp_file.full_path))
                    continue  # No need to update metadata
                book = cached_metadata
            else:
                book = Book(sid, '/'.join(relpath))
                bl.append(book)

            need_sync = True
            self.report_progress(count/steps, _('Reading metadata from %s')%
                    ('/'.join(relpath)))
            try:
                book.smart_update(self.read_file_metadata(mtp_file))
                debug('Read metadata for', '/'.join(mtp_file.full_path))
            except:
                prints('Failed to read metadata from',
                        '/'.join(mtp_file.full_path))
                traceback.print_exc()
            book.size = mtp_file.size
            book.datetime = mtp_file.last_modified.timetuple()
            book.path = mtp_file.mtp_id_path

        # Remove books in the cache that no longer exist
        for idx in sorted(relpath_cache.itervalues(), reverse=True):
            del bl[idx]
            need_sync = True

        if need_sync:
            self.report_progress(count/steps, _('Updating metadata cache on device'))
            self.write_metadata_cache(storage, bl)
        self.report_progress(1, _('Finished reading metadata from device'))
        return bl