mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge branch 'master' of https://github.com/cbhaley/calibre
This commit is contained in:
commit
2d406eb2a1
@ -355,8 +355,6 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self.debug_start_time = time.time()
|
self.debug_start_time = time.time()
|
||||||
self.debug_time = time.time()
|
self.debug_time = time.time()
|
||||||
|
|
||||||
# This must be protected by a lock because it is called from three threads
|
|
||||||
@synchronous('sync_lock')
|
|
||||||
def _debug(self, *args):
|
def _debug(self, *args):
|
||||||
# manual synchronization so we don't lose the calling method name
|
# manual synchronization so we don't lose the calling method name
|
||||||
import inspect
|
import inspect
|
||||||
@ -694,8 +692,8 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def _metadata_in_cache(self, uuid, ext_or_lpath, lastmod):
|
def _metadata_in_cache(self, uuid, ext_or_lpath, lastmod):
|
||||||
|
from calibre.utils.date import now, parse_date
|
||||||
try:
|
try:
|
||||||
from calibre.utils.date import parse_date, now
|
|
||||||
key = self._make_metadata_cache_key(uuid, ext_or_lpath)
|
key = self._make_metadata_cache_key(uuid, ext_or_lpath)
|
||||||
if isinstance(lastmod, unicode):
|
if isinstance(lastmod, unicode):
|
||||||
if lastmod == 'None':
|
if lastmod == 'None':
|
||||||
@ -795,8 +793,8 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
def _write_metadata_cache(self):
|
def _write_metadata_cache(self):
|
||||||
self._debug()
|
|
||||||
from calibre.utils.date import now
|
from calibre.utils.date import now
|
||||||
|
self._debug()
|
||||||
from calibre.utils.config import to_json
|
from calibre.utils.config import to_json
|
||||||
cache_file_name = os.path.join(cache_dir(),
|
cache_file_name = os.path.join(cache_dir(),
|
||||||
'wireless_device_' + self.device_uuid +
|
'wireless_device_' + self.device_uuid +
|
||||||
@ -990,7 +988,8 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
'currentLibraryUUID': library_uuid,
|
'currentLibraryUUID': library_uuid,
|
||||||
'pubdateFormat': tweaks['gui_pubdate_display_format'],
|
'pubdateFormat': tweaks['gui_pubdate_display_format'],
|
||||||
'timestampFormat': tweaks['gui_timestamp_display_format'],
|
'timestampFormat': tweaks['gui_timestamp_display_format'],
|
||||||
'lastModifiedFormat': tweaks['gui_last_modified_display_format']})
|
'lastModifiedFormat': tweaks['gui_last_modified_display_format'],
|
||||||
|
'calibre_version': numeric_version})
|
||||||
if opcode != 'OK':
|
if opcode != 'OK':
|
||||||
# Something wrong with the return. Close the socket
|
# Something wrong with the return. Close the socket
|
||||||
# and continue.
|
# and continue.
|
||||||
@ -1089,7 +1088,7 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self.is_read_sync_col = result.get('isReadSyncCol', None)
|
self.is_read_sync_col = result.get('isReadSyncCol', None)
|
||||||
self._debug('Device is_read sync col', self.is_read_sync_col)
|
self._debug('Device is_read sync col', self.is_read_sync_col)
|
||||||
|
|
||||||
self.is_read_date_sync_col = result.get('isReadDateSyncCol', False)
|
self.is_read_date_sync_col = result.get('isReadDateSyncCol', None)
|
||||||
self._debug('Device is_read_date sync col', self.is_read_date_sync_col)
|
self._debug('Device is_read_date sync col', self.is_read_date_sync_col)
|
||||||
|
|
||||||
if password:
|
if password:
|
||||||
@ -1209,7 +1208,8 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
{'canStream':True,
|
{'canStream':True,
|
||||||
'canScan':True,
|
'canScan':True,
|
||||||
'willUseCachedMetadata': self.client_can_use_metadata_cache,
|
'willUseCachedMetadata': self.client_can_use_metadata_cache,
|
||||||
'supportsSync': True})
|
'supportsSync': (self.is_read_sync_col or
|
||||||
|
self.is_read_date_sync_col)})
|
||||||
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']
|
||||||
@ -1257,7 +1257,7 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
book = self.json_codec.raw_to_book(result, SDBook, self.PREFIX)
|
book = self.json_codec.raw_to_book(result, SDBook, self.PREFIX)
|
||||||
book.set('_is_read_', result.get('_is_read_', None))
|
book.set('_is_read_', result.get('_is_read_', None))
|
||||||
book.set('_is_read_changed_', result.get('_is_read_changed_', None))
|
book.set('_is_read_changed_', result.get('_is_read_changed_', None))
|
||||||
book.set('_last_read_date_', r.get('_last_read_date_', None))
|
book.set('_last_read_date_', result.get('_last_read_date_', None))
|
||||||
bl.add_book(book, replace_metadata=True)
|
bl.add_book(book, replace_metadata=True)
|
||||||
if '_new_book_' in result:
|
if '_new_book_' in result:
|
||||||
book.set('_new_book_', True)
|
book.set('_new_book_', True)
|
||||||
@ -1309,7 +1309,8 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self._call_client('SEND_BOOKLISTS', {'count': count,
|
self._call_client('SEND_BOOKLISTS', {'count': count,
|
||||||
'collections': coldict,
|
'collections': coldict,
|
||||||
'willStreamMetadata': True,
|
'willStreamMetadata': True,
|
||||||
'supportsSync': True},
|
'supportsSync': (self.is_read_sync_col or
|
||||||
|
self.is_read_date_sync_col)},
|
||||||
wait_for_response=False)
|
wait_for_response=False)
|
||||||
|
|
||||||
if count:
|
if count:
|
||||||
@ -1318,7 +1319,9 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self._set_known_metadata(book)
|
self._set_known_metadata(book)
|
||||||
opcode, result = self._call_client(
|
opcode, result = self._call_client(
|
||||||
'SEND_BOOK_METADATA',
|
'SEND_BOOK_METADATA',
|
||||||
{'index': i, 'count': count, 'data': book, 'supportsSync': True},
|
{'index': i, 'count': count, 'data': book,
|
||||||
|
'supportsSync': (self.is_read_sync_col or
|
||||||
|
self.is_read_date_sync_col)},
|
||||||
print_debug_info=False,
|
print_debug_info=False,
|
||||||
wait_for_response=False)
|
wait_for_response=False)
|
||||||
|
|
||||||
@ -1466,86 +1469,123 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
|
|
||||||
@synchronous('sync_lock')
|
@synchronous('sync_lock')
|
||||||
def synchronize_with_db(self, db, id_, book):
|
def synchronize_with_db(self, db, id_, book):
|
||||||
|
from calibre.utils.date import parse_date, UNDEFINED_DATE
|
||||||
def show_message(message):
|
def show_message(message):
|
||||||
self._call_client("DISPLAY_MESSAGE",
|
self._call_client("DISPLAY_MESSAGE",
|
||||||
{'messageKind': self.MESSAGE_SHOW_TOAST,
|
{'messageKind': self.MESSAGE_SHOW_TOAST,
|
||||||
'message': message})
|
'message': message})
|
||||||
|
|
||||||
if not (self.is_read_sync_col or self.is_read_date_sync_col):
|
if self.have_bad_sync_columns or not (self.is_read_sync_col or
|
||||||
# Not syncing
|
self.is_read_date_sync_col):
|
||||||
|
# Not syncing or sync columns are invalid
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Check the validity of the columns once per connection. We do it
|
||||||
|
# here because we have access to the db to get field_metadata
|
||||||
if not self.have_checked_sync_columns:
|
if not self.have_checked_sync_columns:
|
||||||
# Check the validity of the columns once per connection. We do it
|
|
||||||
# here because we have access to the db to get field_metadata
|
|
||||||
fm = db.field_metadata.custom_field_metadata()
|
fm = db.field_metadata.custom_field_metadata()
|
||||||
if self.is_read_sync_col:
|
if self.is_read_sync_col:
|
||||||
if self.is_read_sync_col not in fm:
|
if self.is_read_sync_col not in fm:
|
||||||
self._debug('is_read_sync_col not in field_metadata')
|
self._debug('is_read_sync_col not in field_metadata')
|
||||||
show_message(_("The read sync column %s is "
|
show_message(_("The read sync column %s is "
|
||||||
"not in calibre's library")%self.is_read_sync_col)
|
"not in calibre's library")%self.is_read_sync_col)
|
||||||
|
self.have_bad_sync_columns = True
|
||||||
elif fm[self.is_read_sync_col]['datatype'] != 'bool':
|
elif fm[self.is_read_sync_col]['datatype'] != 'bool':
|
||||||
self._debug('is_read_sync_col not bool type')
|
self._debug('is_read_sync_col not bool type')
|
||||||
show_message(_("The read sync column %s is "
|
show_message(_("The read sync column %s is "
|
||||||
"not a Yes/No column")%self.is_read_sync_col)
|
"not a Yes/No column")%self.is_read_sync_col)
|
||||||
|
self.have_bad_sync_columns = True
|
||||||
|
|
||||||
if self.is_read_date_sync_col:
|
if self.is_read_date_sync_col:
|
||||||
if self.is_read_date_sync_col not in fm:
|
if self.is_read_date_sync_col not in fm:
|
||||||
self._debug('is_read_date_sync_col not in field_metadata')
|
self._debug('is_read_date_sync_col not in field_metadata')
|
||||||
show_message(_("The read date sync column %s is "
|
show_message(_("The read date sync column %s is "
|
||||||
"not in calibre's library")%self.is_read_date_sync_col)
|
"not in calibre's library")%self.is_read_date_sync_col)
|
||||||
|
self.have_bad_sync_columns = True
|
||||||
elif fm[self.is_read_date_sync_col]['datatype'] != 'datetime':
|
elif fm[self.is_read_date_sync_col]['datatype'] != 'datetime':
|
||||||
self._debug('is_read_date_sync_col not date type')
|
self._debug('is_read_date_sync_col not date type')
|
||||||
show_message(_("The read date sync column %s is "
|
show_message(_("The read date sync column %s is "
|
||||||
"not a Date column")%self.is_read_date_sync_col)
|
"not a Date column")%self.is_read_date_sync_col)
|
||||||
|
self.have_bad_sync_columns = True
|
||||||
|
|
||||||
self.have_checked_sync_columns = True
|
self.have_checked_sync_columns = True
|
||||||
|
if self.have_bad_sync_columns:
|
||||||
|
return None
|
||||||
|
|
||||||
is_changed = book.get('_is_read_changed_', None);
|
is_changed = book.get('_is_read_changed_', None);
|
||||||
is_read = book.get('_is_read_', None)
|
is_read = book.get('_is_read_', None)
|
||||||
|
# This returns UNDEFINED_DATE if the value is None
|
||||||
|
is_read_date = parse_date(book.get('_last_read_date_', None));
|
||||||
|
value_to_return = None
|
||||||
|
|
||||||
if is_changed == 2 and is_read is None:
|
if is_changed == 2:
|
||||||
# This is a special case where the user just set the sync column. In
|
# This is a special case where the user just set the sync column. In
|
||||||
# this case the device value wins if it is not None by falling
|
# this case the device value wins if it is not None by falling
|
||||||
# through to the normal sync situation below, otherwise the calibre
|
# through to the normal sync situation below, otherwise the calibre
|
||||||
# value wins.
|
# value wins. The orig_* values are set to None to force the normal
|
||||||
calibre_val = db.new_api.field_for(self.is_read_sync_col,
|
# sync code to actually sync because the values are different
|
||||||
id_, default_value=None)
|
orig_is_read_date = UNDEFINED_DATE
|
||||||
if calibre_val is not None:
|
orig_is_read = None
|
||||||
# This will force the metadata for the book to be sent . Note
|
if is_read is None:
|
||||||
# that because the devices last_read date is one-way sync, this
|
calibre_val = db.new_api.field_for(self.is_read_sync_col,
|
||||||
# could leave an empty date in the device.
|
id_, default_value=None)
|
||||||
book.set('_force_send_metadata_', True)
|
if calibre_val is not None:
|
||||||
self._debug('special update book', book.get('title', 'huh?'),
|
# This forces the metadata for the book to be sent to the
|
||||||
'to', calibre_val)
|
# device even if the mod dates haven't changed.
|
||||||
return set(id_)
|
book.set('_force_send_metadata_', True)
|
||||||
# Both values are None. Do nothing
|
self._debug('special update is_read', book.get('title', 'huh?'),
|
||||||
return None
|
'to', calibre_val)
|
||||||
|
value_to_return = set()
|
||||||
|
|
||||||
orig_is_read = book.get(self.is_read_sync_col, None)
|
if is_read_date == UNDEFINED_DATE:
|
||||||
if is_read != orig_is_read:
|
calibre_val = db.new_api.field_for(self.is_read_date_sync_col,
|
||||||
# The value in the device's is_read checkbox is not the same as the
|
id_, default_value=None)
|
||||||
# last one that came to the device from calibre during the last
|
if calibre_val != UNDEFINED_DATE:
|
||||||
# connect, meaning that the user changed it. Write the one from the
|
book.set('_force_send_metadata_', True)
|
||||||
# checkbox to calibre's db.
|
self._debug('special update is_read_date', book.get('title', 'huh?'),
|
||||||
changed_books = set()
|
'to', calibre_val)
|
||||||
is_read_date = book.get('_last_read_date_', None);
|
value_to_return = set()
|
||||||
self._debug('standard update book', book.get('title', 'huh?'), 'to',
|
# Fall through to the normal sync. At this point either the is_read*
|
||||||
is_read, is_read_date)
|
# values are different from the orig_is_read* which will cause a
|
||||||
if self.is_read_sync_col:
|
# sync below, or they are both None which will cause the code below
|
||||||
try:
|
# to do nothing. If either of the calibre data fields were set, the
|
||||||
|
# method will return set(), which will force updated metadata to be
|
||||||
|
# given back to the device, effectively forcing the sync of the
|
||||||
|
# calibre values back to the device.
|
||||||
|
else:
|
||||||
|
orig_is_read = book.get(self.is_read_sync_col, None)
|
||||||
|
orig_is_read_date = book.get(self.is_read_date_sync_col, None)
|
||||||
|
|
||||||
|
changed_books = set()
|
||||||
|
try:
|
||||||
|
if is_read != orig_is_read:
|
||||||
|
# The value in the device's is_read checkbox is not the same as the
|
||||||
|
# last one that came to the device from calibre during the last
|
||||||
|
# connect, meaning that the user changed it. Write the one from the
|
||||||
|
# device to calibre's db.
|
||||||
|
self._debug('standard update book is_read', book.get('title', 'huh?'),
|
||||||
|
'to', is_read)
|
||||||
|
if self.is_read_sync_col:
|
||||||
changed_books = db.new_api.set_field(self.is_read_sync_col,
|
changed_books = db.new_api.set_field(self.is_read_sync_col,
|
||||||
{id_: is_read})
|
{id_: is_read})
|
||||||
except:
|
except:
|
||||||
self._debug('setting read sync col tossed exception',
|
self._debug('exception syncing is_read col', self.is_read_sync_col)
|
||||||
self.is_read_sync_col)
|
traceback.print_exc()
|
||||||
if self.is_read_date_sync_col:
|
|
||||||
try:
|
try:
|
||||||
|
if is_read_date != orig_is_read_date:
|
||||||
|
self._debug('standard update book is_read_date', book.get('title', 'huh?'),
|
||||||
|
'to', is_read_date)
|
||||||
|
if self.is_read_date_sync_col:
|
||||||
changed_books |= db.new_api.set_field(self.is_read_date_sync_col,
|
changed_books |= db.new_api.set_field(self.is_read_date_sync_col,
|
||||||
{id_: is_read_date})
|
{id_: is_read_date})
|
||||||
except:
|
except:
|
||||||
self._debug('setting read date sync col tossed exception',
|
self._debug('Exception while syncing is_read_date', self.is_read_date_sync_col)
|
||||||
self.is_read_date_sync_col)
|
traceback.print_exc()
|
||||||
|
|
||||||
|
if changed_books:
|
||||||
|
# One of the two values was synced, giving a list of changed books.
|
||||||
|
# Return that.
|
||||||
return changed_books
|
return changed_books
|
||||||
|
|
||||||
# The user might have changed the value in calibre. If so, that value
|
# The user might have changed the value in calibre. If so, that value
|
||||||
@ -1553,7 +1593,7 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
# updated value has already been synced and so will also be sent, the
|
# updated value has already been synced and so will also be sent, the
|
||||||
# device should put the calibre value into its checkbox (or whatever it
|
# device should put the calibre value into its checkbox (or whatever it
|
||||||
# uses)
|
# uses)
|
||||||
return None
|
return value_to_return
|
||||||
|
|
||||||
@synchronous('sync_lock')
|
@synchronous('sync_lock')
|
||||||
def startup(self):
|
def startup(self):
|
||||||
@ -1581,6 +1621,7 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self.is_read_sync_col = None
|
self.is_read_sync_col = None
|
||||||
self.is_read_date_sync_col = None
|
self.is_read_date_sync_col = None
|
||||||
self.have_checked_sync_columns = False
|
self.have_checked_sync_columns = False
|
||||||
|
self.have_bad_sync_columns = False
|
||||||
|
|
||||||
message = None
|
message = None
|
||||||
compression_quality_ok = True
|
compression_quality_ok = True
|
||||||
|
Loading…
x
Reference in New Issue
Block a user