This commit is contained in:
GRiker 2010-06-09 17:06:53 -06:00
parent 6a3f7e533b
commit 8b5833db16
2 changed files with 313 additions and 171 deletions

View File

@ -476,14 +476,14 @@ class ITUNES(DevicePlugin):
if isosx:
self._remove_from_iTunes(self.cached_books[path])
if self.manual_sync_mode:
self._remove_device_book(self.cached_books[path])
self._remove_from_device(self.cached_books[path])
elif iswindows:
try:
pythoncom.CoInitialize()
self.iTunes = win32com.client.Dispatch("iTunes.Application")
self._remove_from_iTunes(self.cached_books[path])
if self.manual_sync_mode:
self._remove_device_book(self.cached_books[path])
self._remove_from_device(self.cached_books[path])
finally:
pythoncom.CoUninitialize()
@ -766,7 +766,7 @@ class ITUNES(DevicePlugin):
self.log.info( " deleting existing '%s'" % (path))
self._remove_from_iTunes(self.cached_books[path])
if self.manual_sync_mode:
dev_book_added = self._remove_device_book(self.cached_books[path])
dev_book_added = self._remove_from_device(self.cached_books[path])
'''
Old code testing for PTO
@ -881,162 +881,144 @@ class ITUNES(DevicePlugin):
lib = self.iTunes.LibraryPlaylist
for (i,file) in enumerate(files):
# Delete existing from Library|Books, add to self.update_list
# for deletion from booklist[0] during add_books_to_metadata
path = self.path_template % (metadata[i].title, metadata[i].author[0])
if self.manual_sync_mode:
# Delete existing from Device|Books, add to self.update_list
# for deletion from booklist[0] during add_books_to_metadata
if path in self.cached_books:
self.update_list.append(self.cached_books[path])
self._remove_from_device(self.cached_books[path])
if DEBUG:
self.log.info( " deleting device book '%s'" % (path))
if not getattr(fpath, 'deleted_after_upload', False):
self._remove_from_iTunes(self.cached_books[path])
if DEBUG:
self.log.info(" deleting library book '%s'" % path)
else:
if DEBUG:
self.log.info(" '%s' not in cached_books" % metadata[i].title)
else:
# Delete existing from Library|Books, add to self.update_list
# for deletion from booklist[0] during add_books_to_metadata
if path in self.cached_books:
self.update_list.append(self.cached_books[path])
self._remove_from_iTunes(self.cached_books[path])
if DEBUG:
self.log.info("ITUNES.upload_books():")
self.log.info( " deleting existing '%s'" % (path))
self._remove_from_iTunes(self.cached_books[path])
if self.manual_sync_mode:
dev_book_added = self._remove_device_book(self.cached_books[path])
self.log.info( " deleting library book '%s'" % path)
else:
if DEBUG:
self.log.info(" '%s' not in cached_books" % metadata[i].title)
# Add to iTunes Library|Books
# If the database copy will be deleted after upload, we have to
# use file (the PersistentTemporaryFile), which will be around until
# calibre exits.
fpath = file
lb_added = None
db_added = None
if not getattr(fpath, 'deleted_after_upload', False):
if getattr(file, 'orig_file_path', None) is not None:
fpath = file.orig_file_path
elif getattr(file, 'name', None) is not None:
fpath = file.name
# If this file is to be deleted after xfer to device, don't add it to the
# iTunes database, as the file path will be invalid when calibre exits.
# Only possible in manual_sync_mode
if getattr(file, 'deleted_after_upload', False) and self.manual_sync_mode:
if DEBUG:
self.log.info(" PTF not added to Library|Books")
else:
# Add fpath to Library|Books
file_s = ctypes.c_char_p(fpath)
FileArray = ctypes.c_char_p * 1
fa = FileArray(file_s)
op_status = lib.AddFiles(fa)
if DEBUG:
self.log.info(" file added to Library|Books")
self.log.info(" file will be deleted after upload")
self.log.info("ITUNES.upload_books():\n iTunes adding '%s'"
% fpath)
if DEBUG:
sys.stdout.write(" iTunes copying '%s' ..." % metadata[i].title)
sys.stdout.flush()
while op_status.InProgress:
time.sleep(0.5)
if DEBUG:
sys.stdout.write('.')
sys.stdout.flush()
if DEBUG:
sys.stdout.write("\n")
sys.stdout.flush()
if True:
if DEBUG:
sys.stdout.write(" waiting for handle to added '%s' ..." % metadata[i].title)
sys.stdout.flush()
while op_status.Tracks is None:
time.sleep(0.5)
if DEBUG:
sys.stdout.write('.')
sys.stdout.flush()
if DEBUG:
print
added = op_status.Tracks[0]
else:
# This approach simply scans Library|Books for the book we just added
added = self._find_library_book(
{'title': metadata[i].title,
'author': metadata[i].author[0]})
dev_book_added = None
if self.manual_sync_mode:
added = dev_book_added = self._add_device_book(fpath)
if added:
thumb = None
# Use cover data as artwork
if metadata[i].cover:
if added.Artwork.Count:
added.Artwork.Item(1).SetArtworkFromFile(metadata[i].cover)
else:
added.AddArtworkFromFile(metadata[i].cover)
try:
# Resize for thumb
width = metadata[i].thumbnail[0]
height = metadata[i].thumbnail[1]
im = PILImage.open(metadata[i].cover)
im = im.resize((width, height), PILImage.ANTIALIAS)
of = cStringIO.StringIO()
im.convert('RGB').save(of, 'JPEG')
thumb = of.getvalue()
# Refresh the thumbnail cache
db_added = self._add_device_book(fpath, metadata[i])
if DEBUG:
self.log.info( " refreshing cached thumb for '%s'" % metadata[i].title)
archive_path = os.path.join(self.cache_dir, "thumbs.zip")
zfw = zipfile.ZipFile(archive_path, mode='a')
thumb_path = path.rpartition('.')[0] + '.jpg'
zfw.writestr(thumb_path, thumb)
zfw.close()
except:
self.problem_titles.append("'%s' by %s" % (metadata[i].title, metadata[i].author[0]))
self.log.error("ITUNES.upload_books():\n error converting '%s' to thumb for '%s'" % (metadata[i].cover,metadata[i].title))
self.log.info(" file uploaded to Device|Books")
if not getattr(fpath, 'deleted_after_upload', False):
lb_added = self._add_library_book(fpath, metadata[i])
if DEBUG:
self.log.info(" file added to Library|Books for iTunes:iBooks tracking")
else:
lb_added = self._add_library_book(fpath, metadata[i])
if DEBUG:
self.log.info(" file added to Library|Books for pending sync")
# Use calibre cover data as artwork if available
thumb = self._cover_to_thumb(path, metadata[i], lb_added, db_added)
# Create a new Book
this_book = Book(metadata[i].title, metadata[i].author[0])
if lb_added:
try:
this_book.datetime = parse_date(str(added.DateAdded)).timetuple()
this_book.datetime = parse_date(str(lb_added.DateAdded)).timetuple()
except:
pass
elif db_added:
try:
this_book.datetime = parse_date(str(db_added.DateAdded)).timetuple()
except:
pass
this_book.db_id = None
this_book.device_collections = []
this_book.library_id = added
this_book.library_id = lb_added
this_book.path = path
this_book.size = added.Size # Updated later from actual storage size
if lb_added:
this_book.size = self._get_device_book_size(fpath, lb_added.Size)
else:
this_book.size = self._get_device_book_size(fpath, db_added.Size)
this_book.thumbnail = thumb
this_book.iTunes_id = added
if lb_added:
this_book.iTunes_id = lb_added
new_booklist.append(this_book)
# Flesh out the iTunes metadata
if metadata[i].comments:
added.Comment = (strip_tags.sub('',metadata[i].comments))
added.Description = ("added by calibre %s" % strftime('%Y-%m-%d %H:%M:%S'))
added.Enabled = True
if lb_added:
lb_added.Comment = (strip_tags.sub('',metadata[i].comments))
if db_added:
db_added.Comment = (strip_tags.sub('',metadata[i].comments))
if metadata[i].rating:
added.AlbumRating = (metadata[i].rating*10)
added.SortArtist = (metadata[i].author_sort.title())
added.SortName = (this_book.title_sorter)
if lb_added:
lb_added.AlbumRating = (metadata[i].rating*10)
# iBooks currently doesn't allow setting rating ... ?
try:
if db_added:
db_added.AlbumRating = (metadata[i].rating*10)
except:
pass
if lb_added:
lb_added.Description = ("added by calibre %s" % strftime('%Y-%m-%d %H:%M:%S'))
lb_added.Enabled = True
lb_added.SortArtist = (metadata[i].author_sort.title())
lb_added.SortName = (this_book.title_sorter)
if db_added:
db_added.Description = ("added by calibre %s" % strftime('%Y-%m-%d %H:%M:%S'))
db_added.Enabled = True
db_added.SortArtist = (metadata[i].author_sort.title())
db_added.SortName = (this_book.title_sorter)
# Set genre from metadata
# iTunes grabs the first dc:subject from the opf metadata,
# But we can manually override with first tag starting with alpha
for tag in metadata[i].tags:
if self._is_alpha(tag[0]):
added.Category = (tag)
if lb_added:
lb_added.Category = (tag)
if db_added:
db_added.Category = (tag)
break
# Add new_book to self.cached_paths
self.cached_books[this_book.path] = {
'title': metadata[i].title,
'author': metadata[i].author[0],
'lib_book': added,
'dev_book': dev_book_added
'lib_book': lb_added,
'dev_book': db_added
}
# Report progress
if self.report_progress is not None:
self.report_progress(i+1/file_count, _('%d of %d') % (i+1, file_count))
else:
self.log.error("ITUNES.upload_books():\n could not find added book in iTunes")
finally:
pythoncom.CoUninitialize()
@ -1051,7 +1033,7 @@ class ITUNES(DevicePlugin):
return (new_booklist, [], [])
# Private methods
def _add_device_book(self,fpath):
def _add_device_book(self,fpath, metadata):
'''
'''
self.log.info("ITUNES._add_device_book()")
@ -1091,14 +1073,148 @@ class ITUNES(DevicePlugin):
# Add the passed book to the Device|Books playlist
if pl:
'''
added = pl.AddFile(fpath)
if DEBUG:
self.log.info(" adding '%s' to device" % fpath)
'''
file_s = ctypes.c_char_p(fpath)
FileArray = ctypes.c_char_p * 1
fa = FileArray(file_s)
op_status = pl.AddFiles(fa)
if DEBUG:
sys.stdout.write(" uploading '%s' to device ..." % metadata.title)
sys.stdout.flush()
while op_status.InProgress:
time.sleep(0.5)
if DEBUG:
sys.stdout.write('.')
sys.stdout.flush()
if DEBUG:
sys.stdout.write("\n")
sys.stdout.flush()
# This doesn't seem to work with device, just Library
if False:
if DEBUG:
sys.stdout.write(" waiting for handle to added '%s' ..." % metadata.title)
sys.stdout.flush()
while op_status.Tracks is None:
time.sleep(0.5)
if DEBUG:
sys.stdout.write('.')
sys.stdout.flush()
if DEBUG:
print
added = op_status.Tracks[0]
else:
# This approach simply scans Library|Books for the book we just added
added = self._find_device_book(
{'title': metadata.title,
'author': metadata.author[0]})
return added
finally:
pythoncom.CoUninitialize()
return added
def _add_library_book(self,file, metadata):
'''
assumes pythoncom wrapper
'''
self.log.info("ITUNES._add_library_book()")
if isosx:
print "to be implemented"
elif iswindows:
lib = self.iTunes.LibraryPlaylist
file_s = ctypes.c_char_p(file)
FileArray = ctypes.c_char_p * 1
fa = FileArray(file_s)
op_status = lib.AddFiles(fa)
if DEBUG:
self.log.info(" file added to Library|Books")
self.log.info(" iTunes adding '%s'" % file)
if DEBUG:
sys.stdout.write(" iTunes copying '%s' ..." % metadata.title)
sys.stdout.flush()
while op_status.InProgress:
time.sleep(0.5)
if DEBUG:
sys.stdout.write('.')
sys.stdout.flush()
if DEBUG:
sys.stdout.write("\n")
sys.stdout.flush()
if True:
if DEBUG:
sys.stdout.write(" waiting for handle to added '%s' ..." % metadata.title)
sys.stdout.flush()
while op_status.Tracks is None:
time.sleep(0.5)
if DEBUG:
sys.stdout.write('.')
sys.stdout.flush()
if DEBUG:
print
added = op_status.Tracks[0]
else:
# This approach simply scans Library|Books for the book we just added
added = self._find_library_book(
{'title': metadata.title,
'author': metadata.author[0]})
return added
def _cover_to_thumb(self, path, metadata, lb_added, db_added):
'''
assumes pythoncom wrapper for db_added
'''
self.log.info("ITUNES._cover_to_thumb()")
thumb = None
if metadata.cover:
if lb_added:
if lb_added.Artwork.Count:
lb_added.Artwork.Item(1).SetArtworkFromFile(metadata.cover)
else:
lb_added.AddArtworkFromFile(metadata.cover)
if db_added:
if db_added.Artwork.Count:
db_added.Artwork.Item(1).SetArtworkFromFile(metadata.cover)
else:
db_added.AddArtworkFromFile(metadata.cover)
try:
# Resize for thumb
width = metadata.thumbnail[0]
height = metadata.thumbnail[1]
im = PILImage.open(metadata.cover)
im = im.resize((width, height), PILImage.ANTIALIAS)
of = cStringIO.StringIO()
im.convert('RGB').save(of, 'JPEG')
thumb = of.getvalue()
# Refresh the thumbnail cache
if DEBUG:
self.log.info( " refreshing cached thumb for '%s'" % metadata.title)
archive_path = os.path.join(self.cache_dir, "thumbs.zip")
zfw = zipfile.ZipFile(archive_path, mode='a')
thumb_path = path.rpartition('.')[0] + '.jpg'
zfw.writestr(thumb_path, thumb)
zfw.close()
except:
self.problem_titles.append("'%s' by %s" % (metadata.title, metadata.author[0]))
self.log.error(" error converting '%s' to thumb for '%s'" % (metadata.cover,metadata.title))
return thumb
def _discover_manual_sync_mode(self, wait=0):
'''
Assumes pythoncom for windows
@ -1235,6 +1351,35 @@ class ITUNES(DevicePlugin):
ub['author']))
self.log.info()
def _find_device_book(self, cached_book):
'''
Windows-only method to get a handle to device book in the current pythoncom session
'''
if iswindows:
if DEBUG:
self.log.info("ITUNES._find_device_book()")
self.log.info(" looking for '%s' by %s" % (cached_book['title'], cached_book['author']))
dev_books = self._get_device_books_playlist()
attempts = 9
while attempts:
# Find book whose Artist field = cached_book['author']
hits = dev_books.Search(cached_book['author'],self.SearchField.index('Artists'))
if hits:
for hit in hits:
self.log.info(" evaluating '%s' by %s" % (hit.Name, hit.Artist))
if hit.Name == cached_book['title']:
self.log.info(" matched '%s' by %s" % (hit.Name, hit.Artist))
return hit
attempts -= 1
time.sleep(0.5)
if DEBUG:
self.log.warning(" attempt #%d" % (10 - attempts))
if DEBUG:
self.log.error(" search for '%s' yielded no hits" % cached_book['title'])
return None
def _find_library_book(self, cached_book):
'''
Windows-only method to get a handle to a library book in the current pythoncom session
@ -1437,15 +1582,13 @@ class ITUNES(DevicePlugin):
return device_books
def _get_device_playlist(self):
def _get_device_books_playlist(self):
'''
assumes pythoncom wrapper
'''
if iswindows:
if 'iPod' in self.sources:
pl = None
try:
pythoncom.CoInitialize()
connected_device = self.sources['iPod']
device = self.iTunes.sources.ItemByName(connected_device)
@ -1457,8 +1600,6 @@ class ITUNES(DevicePlugin):
else:
if DEBUG:
self.log.error(" no iPad|Books playlist found")
finally:
pythoncom.CoUninitialize()
return pl
def _get_library_books(self):
@ -1671,11 +1812,11 @@ class ITUNES(DevicePlugin):
self.version[0],self.version[1],self.version[2]))
self.log.info(" iTunes_media: %s" % self.iTunes_media)
def _remove_device_book(self, cached_book):
def _remove_from_device(self, cached_book):
'''
Windows assumes pythoncom wrapper
'''
self.log.info("ITUNES._remove_device_book()")
self.log.info("ITUNES._remove_from_device()")
if isosx:
if DEBUG:
self.log.info(" deleting %s" % cached_book['dev_book'])
@ -1683,7 +1824,7 @@ class ITUNES(DevicePlugin):
print "result: %s" % result
elif iswindows:
dev_pl = self._get_device_playlist()
dev_pl = self._get_device_books_playlist()
hits = dev_pl.Search(cached_book['author'],self.SearchField.index('Artists'))
if hits:
for hit in hits:

View File

@ -67,7 +67,8 @@ if pictureflow is not None:
return ans
def reset(self):
self.dataChanged.emit()
#self.dataChanged.emit()
pass
def image(self, index):
return self.model.cover(index)