mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
Merge branch 'master' of https://github.com/cbhaley/calibre
This commit is contained in:
commit
2e99bf845e
@ -7,7 +7,7 @@ Created on 29 Jun 2012
|
|||||||
|
|
||||||
@author: charles
|
@author: charles
|
||||||
'''
|
'''
|
||||||
import socket, select, json, os, traceback, time, sys, random
|
import socket, select, json, os, traceback, time, sys, random, cPickle
|
||||||
import posixpath
|
import posixpath
|
||||||
import hashlib, threading
|
import hashlib, threading
|
||||||
import Queue
|
import Queue
|
||||||
@ -34,7 +34,8 @@ from calibre.library import current_library_name
|
|||||||
from calibre.library.server import server_config as content_server_config
|
from calibre.library.server import server_config as content_server_config
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.utils.ipc import eintr_retry_call
|
from calibre.utils.ipc import eintr_retry_call
|
||||||
from calibre.utils.config_base import tweaks
|
from calibre.utils.config_base import config_dir, tweaks
|
||||||
|
from calibre.utils.date import parse_date
|
||||||
from calibre.utils.filenames import ascii_filename as sanitize, shorten_components_to
|
from calibre.utils.filenames import ascii_filename as sanitize, shorten_components_to
|
||||||
from calibre.utils.mdns import (publish as publish_zeroconf, unpublish as
|
from calibre.utils.mdns import (publish as publish_zeroconf, unpublish as
|
||||||
unpublish_zeroconf, get_all_ips)
|
unpublish_zeroconf, get_all_ips)
|
||||||
@ -108,7 +109,7 @@ class ConnectionListener(Thread):
|
|||||||
try:
|
try:
|
||||||
packet = self.driver.broadcast_socket.recvfrom(100)
|
packet = self.driver.broadcast_socket.recvfrom(100)
|
||||||
remote = packet[1]
|
remote = packet[1]
|
||||||
content_server_port = b'';
|
content_server_port = b''
|
||||||
try :
|
try :
|
||||||
content_server_port = \
|
content_server_port = \
|
||||||
str(content_server_config().parse().port)
|
str(content_server_config().parse().port)
|
||||||
@ -330,7 +331,6 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
OPT_OVERWRITE_BOOKS_UUID = 12
|
OPT_OVERWRITE_BOOKS_UUID = 12
|
||||||
OPT_COMPRESSION_QUALITY = 13
|
OPT_COMPRESSION_QUALITY = 13
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
self.sync_lock = threading.RLock()
|
self.sync_lock = threading.RLock()
|
||||||
self.noop_counter = 0
|
self.noop_counter = 0
|
||||||
@ -457,7 +457,8 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
else:
|
else:
|
||||||
for c in tag.split('/'):
|
for c in tag.split('/'):
|
||||||
c = sanitize(c)
|
c = sanitize(c)
|
||||||
if not c: continue
|
if not c:
|
||||||
|
continue
|
||||||
extra_components.append(c)
|
extra_components.append(c)
|
||||||
extra_components.append(name)
|
extra_components.append(name)
|
||||||
|
|
||||||
@ -680,6 +681,18 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _metadata_in_cache(self, uuid, ext, lastmod):
|
||||||
|
key = uuid+ext
|
||||||
|
if isinstance(lastmod, unicode):
|
||||||
|
lastmod = parse_date(lastmod)
|
||||||
|
# if key in self.known_uuids:
|
||||||
|
# self._debug(key, lastmod, self.known_uuids[key].last_modified)
|
||||||
|
# else:
|
||||||
|
# self._debug(key, 'not in known uuids')
|
||||||
|
if key in self.known_uuids and self.known_uuids[key].last_modified == lastmod:
|
||||||
|
return self.known_uuids[key].deepcopy()
|
||||||
|
return None
|
||||||
|
|
||||||
def _metadata_already_on_device(self, book):
|
def _metadata_already_on_device(self, book):
|
||||||
v = self.known_metadata.get(book.lpath, None)
|
v = self.known_metadata.get(book.lpath, None)
|
||||||
if v is not None:
|
if v is not None:
|
||||||
@ -701,6 +714,32 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _read_metadata_cache(self):
|
||||||
|
cache_file_name = os.path.join(config_dir,
|
||||||
|
'device_drivers_' + self.__class__.__name__ +
|
||||||
|
'_metadata_cache.pickle')
|
||||||
|
if os.path.exists(cache_file_name):
|
||||||
|
with open(cache_file_name, mode='rb') as fd:
|
||||||
|
json_metadata = cPickle.load(fd)
|
||||||
|
for uuid,json_book in json_metadata.iteritems():
|
||||||
|
book = self.json_codec.raw_to_book(json_book, SDBook, self.PREFIX)
|
||||||
|
self.known_uuids[uuid] = book
|
||||||
|
lpath = book.get('lpath')
|
||||||
|
if lpath in self.known_metadata:
|
||||||
|
self.known_uuids.pop(uuid, None)
|
||||||
|
else:
|
||||||
|
self.known_metadata[lpath] = book
|
||||||
|
|
||||||
|
def _write_metadata_cache(self):
|
||||||
|
cache_file_name = os.path.join(config_dir,
|
||||||
|
'device_drivers_' + self.__class__.__name__ +
|
||||||
|
'_metadata_cache.pickle')
|
||||||
|
json_metadata = {}
|
||||||
|
for uuid,book in self.known_uuids.iteritems():
|
||||||
|
json_metadata[uuid] = self.json_codec.encode_book_metadata(book)
|
||||||
|
with open(cache_file_name, mode='wb') as fd:
|
||||||
|
cPickle.dump(json_metadata, fd, -1)
|
||||||
|
|
||||||
def _set_known_metadata(self, book, remove=False):
|
def _set_known_metadata(self, book, remove=False):
|
||||||
lpath = book.lpath
|
lpath = book.lpath
|
||||||
ext = os.path.splitext(lpath)[1]
|
ext = os.path.splitext(lpath)[1]
|
||||||
@ -721,6 +760,7 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
self.device_socket = None
|
self.device_socket = None
|
||||||
|
self._write_metadata_cache()
|
||||||
self.is_connected = False
|
self.is_connected = False
|
||||||
|
|
||||||
def _attach_to_port(self, sock, port):
|
def _attach_to_port(self, sock, port):
|
||||||
@ -868,6 +908,8 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self._debug('Device can receive book binary', self.client_can_stream_metadata)
|
self._debug('Device can receive book binary', self.client_can_stream_metadata)
|
||||||
self.client_can_delete_multiple = result.get('canDeleteMultipleBooks', False)
|
self.client_can_delete_multiple = result.get('canDeleteMultipleBooks', False)
|
||||||
self._debug('Device can delete multiple books', self.client_can_delete_multiple)
|
self._debug('Device can delete multiple books', self.client_can_delete_multiple)
|
||||||
|
self.client_can_use_metadata_cache = result.get('canUseCachedMetadata', False)
|
||||||
|
self._debug('Device can use cached metadata', self.client_can_use_metadata_cache)
|
||||||
|
|
||||||
self.client_device_kind = result.get('deviceKind', '')
|
self.client_device_kind = result.get('deviceKind', '')
|
||||||
self._debug('Client device kind', self.client_device_kind)
|
self._debug('Client device kind', self.client_device_kind)
|
||||||
@ -875,6 +917,9 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self.client_device_name = result.get('deviceName', self.client_device_kind)
|
self.client_device_name = result.get('deviceName', self.client_device_kind)
|
||||||
self._debug('Client device name', self.client_device_name)
|
self._debug('Client device name', self.client_device_name)
|
||||||
|
|
||||||
|
self.client_app_name = result.get('appName', "")
|
||||||
|
self._debug('Client app name', self.client_app_name)
|
||||||
|
|
||||||
self.max_book_packet_len = result.get('maxBookContentPacketLen',
|
self.max_book_packet_len = result.get('maxBookContentPacketLen',
|
||||||
self.BASE_PACKET_LEN)
|
self.BASE_PACKET_LEN)
|
||||||
self._debug('max_book_packet_len', self.max_book_packet_len)
|
self._debug('max_book_packet_len', self.max_book_packet_len)
|
||||||
@ -888,7 +933,6 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self.client_wants_uuid_file_names = result.get('useUuidFileNames', False)
|
self.client_wants_uuid_file_names = result.get('useUuidFileNames', False)
|
||||||
self._debug('Device wants UUID file names', self.client_wants_uuid_file_names)
|
self._debug('Device wants UUID file names', self.client_wants_uuid_file_names)
|
||||||
|
|
||||||
|
|
||||||
config = self._configProxy()
|
config = self._configProxy()
|
||||||
config['format_map'] = exts
|
config['format_map'] = exts
|
||||||
self._debug('selected formats', config['format_map'])
|
self._debug('selected formats', config['format_map'])
|
||||||
@ -933,8 +977,6 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.known_metadata = {}
|
|
||||||
self.known_uuids = {}
|
|
||||||
return True
|
return True
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
self._close_device_socket()
|
self._close_device_socket()
|
||||||
@ -1019,13 +1061,41 @@ 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',
|
||||||
'canScan':True})
|
{'canStream':True,
|
||||||
|
'canScan':True,
|
||||||
|
'willUseCachedMetadata': self.client_can_use_metadata_cache})
|
||||||
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
|
will_scan = 'willScan' in result
|
||||||
|
will_use_cache = self.client_can_use_metadata_cache
|
||||||
|
|
||||||
|
if will_use_cache:
|
||||||
|
books_on_device = {}
|
||||||
|
self._debug('caching. count=', count)
|
||||||
|
for i in range(0, count):
|
||||||
|
opcode, result = self._receive_from_client(print_debug_info=False)
|
||||||
|
books_on_device[result.get('uuid')] = result
|
||||||
|
|
||||||
|
books_to_send = []
|
||||||
|
for u,v in books_on_device.iteritems():
|
||||||
|
book = self._metadata_in_cache(u, v['extension'], v['last_modified'])
|
||||||
|
if book:
|
||||||
|
bl.add_book(book, replace_metadata=True)
|
||||||
|
else:
|
||||||
|
books_to_send.append(v['priKey'])
|
||||||
|
|
||||||
|
count = len(books_to_send)
|
||||||
|
self._debug('caching. Need count from device', count)
|
||||||
|
|
||||||
|
self._call_client('NOOP', {'count': count},
|
||||||
|
print_debug_info=False, wait_for_response=False)
|
||||||
|
for priKey in books_to_send:
|
||||||
|
self._call_client('NOOP', {'priKey':priKey},
|
||||||
|
print_debug_info=False, wait_for_response=False)
|
||||||
|
|
||||||
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)
|
||||||
@ -1209,7 +1279,6 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self.report_progress(1.0, _('Removing books from device metadata listing...'))
|
self.report_progress(1.0, _('Removing books from device metadata listing...'))
|
||||||
self._debug('finished removing metadata for %d books' % (len(paths)))
|
self._debug('finished removing metadata for %d books' % (len(paths)))
|
||||||
|
|
||||||
|
|
||||||
@synchronous('sync_lock')
|
@synchronous('sync_lock')
|
||||||
def get_file(self, path, outfile, end_session=True, this_book=None, total_books=None):
|
def get_file(self, path, outfile, end_session=True, this_book=None, total_books=None):
|
||||||
if self.settings().extra_customization[self.OPT_EXTRA_DEBUG]:
|
if self.settings().extra_customization[self.OPT_EXTRA_DEBUG]:
|
||||||
@ -1397,6 +1466,8 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self.connection_queue = Queue.Queue(1)
|
self.connection_queue = Queue.Queue(1)
|
||||||
self.connection_listener = ConnectionListener(self)
|
self.connection_listener = ConnectionListener(self)
|
||||||
self.connection_listener.start()
|
self.connection_listener.start()
|
||||||
|
|
||||||
|
self._read_metadata_cache()
|
||||||
return message
|
return message
|
||||||
|
|
||||||
@synchronous('sync_lock')
|
@synchronous('sync_lock')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user