Put sony driver back the way it was. Next, will put in code that will use tz variable, if it exists.

This commit is contained in:
Charles Haley 2010-08-24 11:00:20 +01:00
parent f5f41107fd
commit 95429a33c6

View File

@ -5,7 +5,7 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os, time, datetime import os, time
from base64 import b64decode from base64 import b64decode
from uuid import uuid4 from uuid import uuid4
from lxml import etree from lxml import etree
@ -17,7 +17,6 @@ from calibre.constants import DEBUG, preferred_encoding
from calibre.ebooks.chardet import xml_to_unicode from calibre.ebooks.chardet import xml_to_unicode
from calibre.ebooks.metadata import authors_to_string, title_sort, \ from calibre.ebooks.metadata import authors_to_string, title_sort, \
authors_to_sort_string authors_to_sort_string
from calibre.utils.date import fromtimestamp, utc_tz
# Utility functions {{{ # Utility functions {{{
EMPTY_CARD_CACHE = '''\ EMPTY_CARD_CACHE = '''\
@ -354,18 +353,20 @@ class XMLCache(object):
debug_print('Updating XML Cache:', i) debug_print('Updating XML Cache:', i)
root = self.record_roots[i] root = self.record_roots[i]
lpath_map = self.build_lpath_map(root) lpath_map = self.build_lpath_map(root)
tz_offset = None gtz_count = ltz_count = 0
for book in booklist: for book in booklist:
path = os.path.join(self.prefixes[i], *(book.lpath.split('/'))) path = os.path.join(self.prefixes[i], *(book.lpath.split('/')))
record = lpath_map.get(book.lpath, None) record = lpath_map.get(book.lpath, None)
if record is None: if record is None:
record = self.create_text_record(root, i, book.lpath) record = self.create_text_record(root, i, book.lpath)
tz_offset = self.update_text_record(record, book, path, i, tz_offset) (gtz_count, ltz_count) = self.update_text_record(record, book,
path, i, gtz_count, ltz_count)
# Ensure the collections in the XML database are recorded for # Ensure the collections in the XML database are recorded for
# this book # this book
if book.device_collections is None: if book.device_collections is None:
book.device_collections = [] book.device_collections = []
book.device_collections = playlist_map.get(book.lpath, []) book.device_collections = playlist_map.get(book.lpath, [])
debug_print('Timezone votes: %d GMT, %d LTZ'%(gtz_count, ltz_count))
self.update_playlists(i, root, booklist, collections_attributes) self.update_playlists(i, root, booklist, collections_attributes)
# Update the device collections because update playlist could have added # Update the device collections because update playlist could have added
# some new ones. # some new ones.
@ -463,49 +464,43 @@ class XMLCache(object):
root.append(ans) root.append(ans)
return ans return ans
def update_text_record(self, record, book, path, bl_index, tz_offset): def update_text_record(self, record, book, path, bl_index, gtz_count, ltz_count):
''' '''
Update the Sony database from the book. This is done if the timestamp in Update the Sony database from the book. This is done if the timestamp in
the db differs from the timestamp on the file. the db differs from the timestamp on the file.
''' '''
# It seems that a Sony device can sometimes know what timezone it is in,
# and apparently converts the dates to GMT when it writes them to the
# db. Unfortunately, we can't tell when it does this, so we use a
# horrible heuristic. First, set dates only for new books, trying to
# avoid upsetting the sony. Use the timezone determined through the
# voting described next. Second, voting: if a book is not new, compare
# its Sony DB date against localtime and gmtime. Count the matches. When
# we must set a date, use the one with the most matches. Use localtime
# if the case of a tie, and hope it is right.
timestamp = os.path.getmtime(path)
rec_date = record.get('date', None)
def clean(x): def clean(x):
if isbytestring(x): if isbytestring(x):
x = x.decode(preferred_encoding, 'replace') x = x.decode(preferred_encoding, 'replace')
x.replace(u'\0', '') x.replace(u'\0', '')
return x return x
# It seems that a Sony device can sometimes know what timezone it is in,
# and apparently converts the dates to GMT when it writes them to the
# db. The Sony assumes that the mtime is localtime, applies its TZ
# factor, then stores the resulting date string in its DB. We compensate
# for this by reversing the computation. We first convert the string in
# the DB to datetime, forcing it to UTC (offset 0:00:00). We next
# convert the mtime to a datetime assuming that it is UTC. The
# difference between these datetimes is the timezone factor that the
# Sony used.
timestamp = os.path.getmtime(path)
if not getattr(book, '_new_book', False): # book is not new if not getattr(book, '_new_book', False): # book is not new
rec_date = record.get('date', None) if strftime(timestamp, zone=time.gmtime) == rec_date:
if tz_offset is None and record.get('tz', None) == '0': gtz_count += 1
# All existing books should have the same offset, so simply use elif strftime(timestamp, zone=time.localtime) == rec_date:
# the first one we see. However, some (perhaps all) Sony DBs ltz_count += 1
# have an attribute called TZ, and it is not clear what this else: # book is new. Set the time using the current votes
# attribute means. Because it is set to "0" by the reader for if ltz_count >= gtz_count:
# books added by Calibre, to avoid confusion we will use the tz = time.localtime
# offset for the first book with that value. debug_print("Using localtime TZ for new book", book.lpath)
tt = strptime(rec_date) else:
dt = datetime.datetime(tt.tm_year, tt.tm_mon, tt.tm_mday, tt.tm_hour, tz = time.gmtime
tt.tm_min, tt.tm_sec, tzinfo=utc_tz) debug_print("Using GMT TZ for new book", book.lpath)
tz_offset = dt - fromtimestamp(timestamp) date = strftime(timestamp, zone=tz)
debug_print('Timezone offset:', tz_offset)
else: # book is new. Set the time using the current offset
if tz_offset is None:
# No existing books! Assume a zero offset
tz_offset = datetime.timedelta()
debug_print('Timezone offset: using default of ', tz_offset)
date = strftime(fromtimestamp(timestamp) - tz_offset)
record.set('date', clean(date)) record.set('date', clean(date))
record.set('size', clean(str(os.stat(path).st_size))) record.set('size', clean(str(os.stat(path).st_size)))
@ -537,7 +532,7 @@ class XMLCache(object):
if 'id' not in record.attrib: if 'id' not in record.attrib:
num = self.max_id(record.getroottree().getroot()) num = self.max_id(record.getroottree().getroot())
record.set('id', str(num+1)) record.set('id', str(num+1))
return tz_offset return (gtz_count, ltz_count)
# }}} # }}}
# Writing the XML files {{{ # Writing the XML files {{{