This commit is contained in:
Kovid Goyal 2012-09-13 23:53:10 +05:30
commit 4addd5b985

View File

@ -22,6 +22,7 @@ from calibre.devices.interface import DevicePlugin
from calibre.devices.usbms.books import Book, CollectionsBookList from calibre.devices.usbms.books import Book, CollectionsBookList
from calibre.devices.usbms.deviceconfig import DeviceConfig from calibre.devices.usbms.deviceconfig import DeviceConfig
from calibre.devices.usbms.driver import USBMS from calibre.devices.usbms.driver import USBMS
from calibre.devices.utils import build_template_regexp
from calibre.ebooks import BOOK_EXTENSIONS from calibre.ebooks import BOOK_EXTENSIONS
from calibre.ebooks.metadata import title_sort from calibre.ebooks.metadata import title_sort
from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.book.base import Metadata
@ -522,7 +523,7 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
def _set_known_metadata(self, book, remove=False): def _set_known_metadata(self, book, remove=False):
lpath = book.lpath lpath = book.lpath
if remove: if remove:
self.known_metadata[lpath] = None self.known_metadata.pop(lpath, None)
else: else:
self.known_metadata[lpath] = book.deepcopy() self.known_metadata[lpath] = book.deepcopy()
@ -560,6 +561,16 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
self.broadcast_socket.close() self.broadcast_socket.close()
self.broadcast_socket = None self.broadcast_socket = None
def _read_file_metadata(self, temp_file_name):
from calibre.ebooks.metadata.meta import get_metadata
from calibre.customize.ui import quick_metadata
ext = temp_file_name.rpartition('.')[-1].lower()
with open(temp_file_name, 'rb') as stream:
with quick_metadata:
return get_metadata(stream, stream_type=ext,
force_read_metadata=True,
pattern=build_template_regexp(self.save_template()))
# The public interface methods. # The public interface methods.
@synchronous('sync_lock') @synchronous('sync_lock')
@ -801,11 +812,13 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
self._debug(oncard) self._debug(oncard)
if oncard is not None: if oncard is not None:
return CollectionsBookList(None, None, None) return CollectionsBookList(None, None, None)
opcode, result = self._call_client('GET_BOOK_COUNT', {'canStream':True}) opcode, result = self._call_client('GET_BOOK_COUNT', {'canStream':True,
'canScan':True})
bl = CollectionsBookList(None, self.PREFIX, self.settings) bl = CollectionsBookList(None, self.PREFIX, self.settings)
if opcode == 'OK': if opcode == 'OK':
count = result['count'] count = result['count']
will_stream = 'willStream' in result will_stream = 'willStream' in result
will_scan = 'willScan' in result
for i in range(0, count): for i in range(0, count):
if (i % 100) == 0: if (i % 100) == 0:
self._debug('getting book metadata. Done', i, 'of', count) self._debug('getting book metadata. Done', i, 'of', count)
@ -818,10 +831,28 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
if '_series_sort_' in result: if '_series_sort_' in result:
del result['_series_sort_'] del result['_series_sort_']
book = self.json_codec.raw_to_book(result, SDBook, self.PREFIX) book = self.json_codec.raw_to_book(result, SDBook, self.PREFIX)
self._set_known_metadata(book)
bl.add_book(book, replace_metadata=True) bl.add_book(book, replace_metadata=True)
if '_new_book_' in result:
book.set('_new_book_', True)
else:
self._set_known_metadata(book)
else: else:
raise ControlError(desc='book metadata not returned') raise ControlError(desc='book metadata not returned')
if will_scan:
total = 0
for book in bl:
if book.get('_new_book_', None):
total += 1
count = 0
for book in bl:
if book.get('_new_book_', None):
paths = [book.lpath]
self._set_known_metadata(book, remove=True)
self.prepare_addable_books(paths, this_book=count, total_books=total)
book.smart_update(self._read_file_metadata(paths[0]))
del book._new_book_
count += 1
self._debug('finished getting book metadata') self._debug('finished getting book metadata')
return bl return bl
@ -951,33 +982,41 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
@synchronous('sync_lock') @synchronous('sync_lock')
def get_file(self, path, outfile, end_session=True): def get_file(self, path, outfile, end_session=True, this_book=None, total_books=None):
self._debug(path) self._debug(path)
eof = False eof = False
position = 0 position = 0
while not eof: while not eof:
opcode, result = self._call_client('GET_BOOK_FILE_SEGMENT', opcode, result = self._call_client('GET_BOOK_FILE_SEGMENT',
{'lpath' : path, 'position': position}, {'lpath' : path, 'position': position,
'thisBook': this_book, 'totalBooks': total_books,
'canStream':True},
print_debug_info=False) print_debug_info=False)
if opcode == 'OK': if opcode == 'OK':
if not result['eof']: client_will_stream = 'willStream' in result
data = b64decode(result['data']) while not eof:
if len(data) != result['next_position'] - position: if not result['eof']:
self._debug('position mismatch', result['next_position'], position) data = b64decode(result['data'])
position = result['next_position'] if len(data) != result['next_position'] - position:
outfile.write(data) self._debug('position mismatch', result['next_position'], position)
else: position = result['next_position']
eof = True outfile.write(data)
opcode, result = self._receive_from_client(print_debug_info=True)
else:
eof = True
if not client_will_stream:
break
else: else:
raise ControlError(desc='request for book data failed') raise ControlError(desc='request for book data failed')
@synchronous('sync_lock') @synchronous('sync_lock')
def prepare_addable_books(self, paths): def prepare_addable_books(self, paths, this_book=None, total_books=None):
for idx, path in enumerate(paths): for idx, path in enumerate(paths):
(ign, ext) = os.path.splitext(path) (ign, ext) = os.path.splitext(path)
tf = PersistentTemporaryFile(suffix=ext) with PersistentTemporaryFile(suffix=ext) as tf:
self.get_file(path, tf) self.get_file(path, tf, this_book=this_book, total_books=total_books)
paths[idx] = tf.name paths[idx] = tf.name
tf.name = path
return paths return paths
@synchronous('sync_lock') @synchronous('sync_lock')