GwR revisions apple driver 0.5

This commit is contained in:
GRiker 2010-06-10 09:03:23 -06:00
parent e78d1dafc1
commit 7a67294ae7

View File

@ -114,6 +114,7 @@ class ITUNES(DevicePlugin):
# Properties # Properties
cached_books = {} cached_books = {}
cache_dir = os.path.join(config_dir, 'caches', 'itunes') cache_dir = os.path.join(config_dir, 'caches', 'itunes')
description_prefix = "added by calibre"
ejected = False ejected = False
iTunes= None iTunes= None
iTunes_media = None iTunes_media = None
@ -620,6 +621,7 @@ class ITUNES(DevicePlugin):
if DEBUG: if DEBUG:
self.log.info("ITUNES.remove_books_from_metadata()") self.log.info("ITUNES.remove_books_from_metadata()")
for path in paths: for path in paths:
self._dump_cached_book(self.cached_books[path])
if self.cached_books[path]['lib_book']: if self.cached_books[path]['lib_book']:
# Remove from the booklist # Remove from the booklist
for i,book in enumerate(booklists[0]): for i,book in enumerate(booklists[0]):
@ -881,6 +883,7 @@ class ITUNES(DevicePlugin):
'author': metadata[i].author[0], 'author': metadata[i].author[0],
'lib_book': lb_added, 'lib_book': lb_added,
'dev_book': db_added } 'dev_book': db_added }
self._dump_cached_books(header="after upload_books()")
# Report progress # Report progress
if self.report_progress is not None: if self.report_progress is not None:
@ -928,7 +931,7 @@ class ITUNES(DevicePlugin):
def _add_device_book(self,fpath, metadata): def _add_device_book(self,fpath, metadata):
''' '''
''' '''
self.log.info("ITUNES._add_device_book()") self.log.info(" ITUNES._add_device_book()")
if isosx: if isosx:
if 'iPod' in self.sources: if 'iPod' in self.sources:
connected_device = self.sources['iPod'] connected_device = self.sources['iPod']
@ -961,7 +964,7 @@ class ITUNES(DevicePlugin):
break break
else: else:
if DEBUG: if DEBUG:
self.log.info(" no Books playlist found") self.log.info(" no Books playlist found")
# Add the passed book to the Device|Books playlist # Add the passed book to the Device|Books playlist
if pl: if pl:
@ -976,7 +979,7 @@ class ITUNES(DevicePlugin):
op_status = pl.AddFiles(fa) op_status = pl.AddFiles(fa)
if DEBUG: if DEBUG:
sys.stdout.write(" uploading '%s' to device ..." % metadata.title) sys.stdout.write(" uploading '%s' to device ..." % metadata.title)
sys.stdout.flush() sys.stdout.flush()
while op_status.InProgress: while op_status.InProgress:
@ -991,7 +994,7 @@ class ITUNES(DevicePlugin):
# This doesn't seem to work with device, just Library # This doesn't seem to work with device, just Library
if False: if False:
if DEBUG: if DEBUG:
sys.stdout.write(" waiting for handle to added '%s' ..." % metadata.title) sys.stdout.write(" waiting for handle to added '%s' ..." % metadata.title)
sys.stdout.flush() sys.stdout.flush()
while op_status.Tracks is None: while op_status.Tracks is None:
time.sleep(0.5) time.sleep(0.5)
@ -1015,11 +1018,11 @@ class ITUNES(DevicePlugin):
def _add_library_book(self,file, metadata): def _add_library_book(self,file, metadata):
''' '''
assumes pythoncom wrapper windows assumes pythoncom wrapper
''' '''
self.log.info("ITUNES._add_library_book()") self.log.info(" ITUNES._add_library_book()")
if isosx: if isosx:
print "to be implemented" added = self.iTunes.add(appscript.mactypes.File(file))
elif iswindows: elif iswindows:
lib = self.iTunes.LibraryPlaylist lib = self.iTunes.LibraryPlaylist
@ -1028,12 +1031,12 @@ class ITUNES(DevicePlugin):
fa = FileArray(file_s) fa = FileArray(file_s)
op_status = lib.AddFiles(fa) op_status = lib.AddFiles(fa)
if DEBUG: if DEBUG:
self.log.info(" file added to Library|Books") self.log.info(" file added to Library|Books")
self.log.info(" iTunes adding '%s'" % file) self.log.info(" iTunes adding '%s'" % file)
if DEBUG: if DEBUG:
sys.stdout.write(" iTunes copying '%s' ..." % metadata.title) sys.stdout.write(" iTunes copying '%s' ..." % metadata.title)
sys.stdout.flush() sys.stdout.flush()
while op_status.InProgress: while op_status.InProgress:
@ -1047,7 +1050,7 @@ class ITUNES(DevicePlugin):
if True: if True:
if DEBUG: if DEBUG:
sys.stdout.write(" waiting for handle to added '%s' ..." % metadata.title) sys.stdout.write(" waiting for handle to added '%s' ..." % metadata.title)
sys.stdout.flush() sys.stdout.flush()
while op_status.Tracks is None: while op_status.Tracks is None:
time.sleep(0.5) time.sleep(0.5)
@ -1062,13 +1065,13 @@ class ITUNES(DevicePlugin):
added = self._find_library_book( added = self._find_library_book(
{'title': metadata.title, {'title': metadata.title,
'author': metadata.author[0]}) 'author': metadata.author[0]})
return added return added
def _add_new_copy(self, fpath, metadata): def _add_new_copy(self, fpath, metadata):
''' '''
''' '''
if DEBUG: if DEBUG:
self.log.info("ITUNES._add_new_copy()") self.log.info(" ITUNES._add_new_copy()")
db_added = None db_added = None
lb_added = None lb_added = None
@ -1076,15 +1079,15 @@ class ITUNES(DevicePlugin):
if self.manual_sync_mode: if self.manual_sync_mode:
db_added = self._add_device_book(fpath, metadata) db_added = self._add_device_book(fpath, metadata)
if DEBUG: if DEBUG:
self.log.info(" file uploaded to Device|Books") self.log.info(" file uploaded to Device|Books")
if not getattr(fpath, 'deleted_after_upload', False): if not getattr(fpath, 'deleted_after_upload', False):
lb_added = self._add_library_book(fpath, metadata) lb_added = self._add_library_book(fpath, metadata)
if DEBUG: if DEBUG:
self.log.info(" file added to Library|Books for iTunes:iBooks tracking") self.log.info(" file added to Library|Books for iTunes:iBooks tracking")
else: else:
lb_added = self._add_library_book(fpath, metadata) lb_added = self._add_library_book(fpath, metadata)
if DEBUG: if DEBUG:
self.log.info(" file added to Library|Books for pending sync") self.log.info(" file added to Library|Books for pending sync")
return db_added, lb_added return db_added, lb_added
@ -1092,20 +1095,42 @@ class ITUNES(DevicePlugin):
''' '''
assumes pythoncom wrapper for db_added assumes pythoncom wrapper for db_added
''' '''
self.log.info("ITUNES._cover_to_thumb()") self.log.info(" ITUNES._cover_to_thumb()")
thumb = None thumb = None
if metadata.cover: if metadata.cover:
if lb_added: if isosx:
if lb_added.Artwork.Count: cover_data = open(metadata.cover,'rb')
lb_added.Artwork.Item(1).SetArtworkFromFile(metadata.cover) if lb_added:
else: lb_added.artworks[1].data_.set(cover_data.read())
lb_added.AddArtworkFromFile(metadata.cover)
if db_added: if db_added:
if db_added.Artwork.Count: # The following command generates an error, but the artwork does in fact
db_added.Artwork.Item(1).SetArtworkFromFile(metadata.cover) # get sent to the device. Seems like a bug in Apple's automation interface
else: try:
db_added.AddArtworkFromFile(metadata.cover) db_added.artworks[1].data_.set(cover_data.read())
except:
if DEBUG:
self.log.warning(" iTunes automation interface generated an error"
" when adding artwork to '%s'" % metadata.title)
#import traceback
#traceback.print_exc()
#from calibre import ipython
#ipython(user_ns=locals())
pass
elif iswindows:
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: try:
# Resize for thumb # Resize for thumb
@ -1119,7 +1144,7 @@ class ITUNES(DevicePlugin):
# Refresh the thumbnail cache # Refresh the thumbnail cache
if DEBUG: if DEBUG:
self.log.info( " refreshing cached thumb for '%s'" % metadata.title) self.log.info( " refreshing cached thumb for '%s'" % metadata.title)
archive_path = os.path.join(self.cache_dir, "thumbs.zip") archive_path = os.path.join(self.cache_dir, "thumbs.zip")
zfw = zipfile.ZipFile(archive_path, mode='a') zfw = zipfile.ZipFile(archive_path, mode='a')
thumb_path = path.rpartition('.')[0] + '.jpg' thumb_path = path.rpartition('.')[0] + '.jpg'
@ -1127,7 +1152,7 @@ class ITUNES(DevicePlugin):
zfw.close() zfw.close()
except: except:
self.problem_titles.append("'%s' by %s" % (metadata.title, metadata.author[0])) 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)) self.log.error(" error converting '%s' to thumb for '%s'" % (metadata.cover,metadata.title))
return thumb return thumb
@ -1135,7 +1160,7 @@ class ITUNES(DevicePlugin):
''' '''
''' '''
if DEBUG: if DEBUG:
self.log.info("ITUNES._create_new_book()") self.log.info(" ITUNES._create_new_book()")
this_book = Book(metadata.title, metadata.author[0]) this_book = Book(metadata.title, metadata.author[0])
@ -1183,7 +1208,7 @@ class ITUNES(DevicePlugin):
''' '''
if DEBUG: if DEBUG:
self.log.info("ITUNES._discover_manual_sync_mode()") self.log.info(" ITUNES._discover_manual_sync_mode()")
if isosx: if isosx:
connected_device = self.sources['iPod'] connected_device = self.sources['iPod']
dev_books = None dev_books = None
@ -1193,18 +1218,18 @@ class ITUNES(DevicePlugin):
dev_books = pl.file_tracks() dev_books = pl.file_tracks()
break break
else: else:
self.log.error(" book_playlist not found") self.log.error(" book_playlist not found")
if len(dev_books): if len(dev_books):
first_book = dev_books[0] first_book = dev_books[0]
#if DEBUG: #if DEBUG:
#self.log.info(" determing manual mode by modifying '%s' by %s" % (first_book.name(), first_book.artist())) #self.log.info(" determing manual mode by modifying '%s' by %s" % (first_book.name(), first_book.artist()))
try: try:
first_book.bpm.set(0) first_book.bpm.set(0)
self.manual_sync_mode = True self.manual_sync_mode = True
except: except:
self.manual_sync_mode = False self.manual_sync_mode = False
self.log.info(" iTunes.manual_sync_mode: %s" % self.manual_sync_mode) self.log.info(" iTunes.manual_sync_mode: %s" % self.manual_sync_mode)
elif iswindows: elif iswindows:
if wait: if wait:
@ -1228,7 +1253,7 @@ class ITUNES(DevicePlugin):
self.manual_sync_mode = True self.manual_sync_mode = True
except: except:
self.manual_sync_mode = False self.manual_sync_mode = False
self.log.info(" iTunes.manual_sync_mode: %s" % self.manual_sync_mode) self.log.info(" iTunes.manual_sync_mode: %s" % self.manual_sync_mode)
def _dump_booklist(self, booklist, header=None): def _dump_booklist(self, booklist, header=None):
''' '''
@ -1246,6 +1271,31 @@ class ITUNES(DevicePlugin):
self.log.info("%-40.40s %-30.30s" % self.log.info("%-40.40s %-30.30s" %
(book.title, book.author)) (book.title, book.author))
def _dump_cached_book(self, cached_book, header=None):
'''
'''
if header:
msg = '%s' % header
self.log.info(msg)
self.log.info( "%s" % ('-' * len(msg)))
if isosx:
self.log.info("%-40.40s %-30.30s %-10.10s %-10.10s" %
('title',
'author',
'lib_book',
'dev_book'))
self.log.info("%-40.40s %-30.30s %-10.10s %-10.10s" %
(cached_book['title'],
cached_book['author'],
str(cached_book['lib_book'])[-9:],
str(cached_book['dev_book'])[-9:]))
elif iswindows:
self.log.info("%-40.40s %-30.30s" %
(cached_book['title'],
cached_book['author']))
self.log.info()
def _dump_cached_books(self, header=None): def _dump_cached_books(self, header=None):
''' '''
''' '''
@ -1254,6 +1304,11 @@ class ITUNES(DevicePlugin):
self.log.info(msg) self.log.info(msg)
self.log.info( "%s" % ('-' * len(msg))) self.log.info( "%s" % ('-' * len(msg)))
if isosx: if isosx:
self.log.info("%-40.40s %-30.30s %-10.10s %-10.10s" %
('title',
'author',
'lib_book',
'dev_book'))
for cb in self.cached_books.keys(): for cb in self.cached_books.keys():
self.log.info("%-40.40s %-30.30s %-10.10s %-10.10s" % self.log.info("%-40.40s %-30.30s %-10.10s %-10.10s" %
(self.cached_books[cb]['title'], (self.cached_books[cb]['title'],
@ -1318,8 +1373,8 @@ class ITUNES(DevicePlugin):
''' '''
if iswindows: if iswindows:
if DEBUG: if DEBUG:
self.log.info("ITUNES._find_device_book()") self.log.info(" ITUNES._find_device_book()")
self.log.info(" looking for '%s' by %s" % (cached_book['title'], cached_book['author'])) self.log.info(" looking for '%s' by %s" % (cached_book['title'], cached_book['author']))
dev_books = self._get_device_books_playlist() dev_books = self._get_device_books_playlist()
attempts = 9 attempts = 9
@ -1328,17 +1383,17 @@ class ITUNES(DevicePlugin):
hits = dev_books.Search(cached_book['author'],self.SearchField.index('Artists')) hits = dev_books.Search(cached_book['author'],self.SearchField.index('Artists'))
if hits: if hits:
for hit in hits: for hit in hits:
self.log.info(" evaluating '%s' by %s" % (hit.Name, hit.Artist)) self.log.info(" evaluating '%s' by %s" % (hit.Name, hit.Artist))
if hit.Name == cached_book['title']: if hit.Name == cached_book['title']:
self.log.info(" matched '%s' by %s" % (hit.Name, hit.Artist)) self.log.info(" matched '%s' by %s" % (hit.Name, hit.Artist))
return hit return hit
attempts -= 1 attempts -= 1
time.sleep(0.5) time.sleep(0.5)
if DEBUG: if DEBUG:
self.log.warning(" attempt #%d" % (10 - attempts)) self.log.warning(" attempt #%d" % (10 - attempts))
if DEBUG: if DEBUG:
self.log.error(" search for '%s' yielded no hits" % cached_book['title']) self.log.error(" search for '%s' yielded no hits" % cached_book['title'])
return None return None
def _find_library_book(self, cached_book): def _find_library_book(self, cached_book):
@ -1347,18 +1402,18 @@ class ITUNES(DevicePlugin):
''' '''
if iswindows: if iswindows:
if DEBUG: if DEBUG:
self.log.info("ITUNES._find_library_book()") self.log.info(" ITUNES._find_library_book()")
self.log.info(" looking for '%s' by %s" % (cached_book['title'], cached_book['author'])) self.log.info(" looking for '%s' by %s" % (cached_book['title'], cached_book['author']))
for source in self.iTunes.sources: for source in self.iTunes.sources:
if source.Kind == self.Sources.index('Library'): if source.Kind == self.Sources.index('Library'):
lib = source lib = source
if DEBUG: if DEBUG:
self.log.info(" Library source: '%s' kind: %s" % (lib.Name, self.Sources[lib.Kind])) self.log.info(" Library source: '%s' kind: %s" % (lib.Name, self.Sources[lib.Kind]))
break break
else: else:
if DEBUG: if DEBUG:
self.log.info(" Library source not found") self.log.info(" Library source not found")
if lib is not None: if lib is not None:
lib_books = None lib_books = None
@ -1366,12 +1421,12 @@ class ITUNES(DevicePlugin):
if pl.Kind == self.PlaylistKind.index('User') and \ if pl.Kind == self.PlaylistKind.index('User') and \
pl.SpecialKind == self.PlaylistSpecialKind.index('Books'): pl.SpecialKind == self.PlaylistSpecialKind.index('Books'):
if DEBUG: if DEBUG:
self.log.info(" Books playlist: '%s'" % (pl.Name)) self.log.info(" Books playlist: '%s'" % (pl.Name))
lib_books = pl lib_books = pl
break break
else: else:
if DEBUG: if DEBUG:
self.log.error(" no Books playlist found") self.log.error(" no Books playlist found")
attempts = 9 attempts = 9
while attempts: while attempts:
@ -1379,17 +1434,17 @@ class ITUNES(DevicePlugin):
hits = lib_books.Search(cached_book['author'],self.SearchField.index('Artists')) hits = lib_books.Search(cached_book['author'],self.SearchField.index('Artists'))
if hits: if hits:
for hit in hits: for hit in hits:
self.log.info(" evaluating '%s' by %s" % (hit.Name, hit.Artist)) self.log.info(" evaluating '%s' by %s" % (hit.Name, hit.Artist))
if hit.Name == cached_book['title']: if hit.Name == cached_book['title']:
self.log.info(" matched '%s' by %s" % (hit.Name, hit.Artist)) self.log.info(" matched '%s' by %s" % (hit.Name, hit.Artist))
return hit return hit
attempts -= 1 attempts -= 1
time.sleep(0.5) time.sleep(0.5)
if DEBUG: if DEBUG:
self.log.warning(" attempt #%d" % (10 - attempts)) self.log.warning(" attempt #%d" % (10 - attempts))
if DEBUG: if DEBUG:
self.log.error(" search for '%s' yielded no hits" % cached_book['title']) self.log.error(" search for '%s' yielded no hits" % cached_book['title'])
return None return None
def _generate_thumbnail(self, book_path, book): def _generate_thumbnail(self, book_path, book):
@ -1411,6 +1466,7 @@ class ITUNES(DevicePlugin):
else: else:
return thumb_data return thumb_data
self.log.info(" ITUNES._generate_thumbnail()")
if isosx: if isosx:
try: try:
# Resize the cover # Resize the cover
@ -1424,21 +1480,19 @@ class ITUNES(DevicePlugin):
# Cache the tagged thumb # Cache the tagged thumb
if DEBUG: if DEBUG:
self.log.info("ITUNES._generate_thumbnail(): generated thumb for '%s', caching" % book.name()) self.log.info(" generated thumb for '%s', caching" % book.name())
zfw.writestr(thumb_path, thumb.getvalue()) zfw.writestr(thumb_path, thumb.getvalue())
zfw.close() zfw.close()
return thumb.getvalue() return thumb.getvalue()
except: except:
self.log.error("ITUNES._generate_thumbnail(): error generating thumb for '%s'" % book.name()) self.log.error(" error generating thumb for '%s'" % book.name())
return None return None
elif iswindows: elif iswindows:
if DEBUG:
self.log.info("ITUNES._generate_thumbnail()")
if not book.Artwork.Count: if not book.Artwork.Count:
if DEBUG: if DEBUG:
self.log.info(" no artwork available") self.log.info(" no artwork available")
return None return None
# Save the cover from iTunes # Save the cover from iTunes
@ -1455,12 +1509,12 @@ class ITUNES(DevicePlugin):
# Cache the tagged thumb # Cache the tagged thumb
if DEBUG: if DEBUG:
self.log.info(" generated thumb for '%s', caching" % book.Name) self.log.info(" generated thumb for '%s', caching" % book.Name)
zfw.writestr(thumb_path, thumb.getvalue()) zfw.writestr(thumb_path, thumb.getvalue())
zfw.close() zfw.close()
return thumb.getvalue() return thumb.getvalue()
except: except:
self.log.error(" error generating thumb for '%s'" % book.Name) self.log.error(" error generating thumb for '%s'" % book.Name)
return None return None
def _get_device_book_size(self, file, compressed_size): def _get_device_book_size(self, file, compressed_size):
@ -1473,9 +1527,9 @@ class ITUNES(DevicePlugin):
for file in myZipList: for file in myZipList:
exploded_file_size += file.file_size exploded_file_size += file.file_size
if DEBUG: if DEBUG:
self.log.info("ITUNES._get_device_book_size()") self.log.info(" ITUNES._get_device_book_size()")
self.log.info(" %d items in archive" % len(myZipList)) self.log.info(" %d items in archive" % len(myZipList))
self.log.info(" compressed: %d exploded: %d" % (compressed_size, exploded_file_size)) self.log.info(" compressed: %d exploded: %d" % (compressed_size, exploded_file_size))
return exploded_file_size return exploded_file_size
def _get_device_books(self): def _get_device_books(self):
@ -1483,7 +1537,7 @@ class ITUNES(DevicePlugin):
Assumes pythoncom wrapper for Windows Assumes pythoncom wrapper for Windows
''' '''
if DEBUG: if DEBUG:
self.log.info("\nITUNES._get_device_books()") self.log.info("\n ITUNES._get_device_books()")
device_books = [] device_books = []
if isosx: if isosx:
@ -1493,20 +1547,20 @@ class ITUNES(DevicePlugin):
for pl in device.playlists(): for pl in device.playlists():
if pl.special_kind() == appscript.k.Books: if pl.special_kind() == appscript.k.Books:
if DEBUG: if DEBUG:
self.log.info(" Book playlist: '%s'" % (pl.name())) self.log.info(" Book playlist: '%s'" % (pl.name()))
books = pl.file_tracks() books = pl.file_tracks()
break break
else: else:
self.log.error(" book_playlist not found") self.log.error(" book_playlist not found")
for book in books: for book in books:
# This may need additional entries for international iTunes users # This may need additional entries for international iTunes users
if book.kind() in ['MPEG audio file']: if book.kind() in ['MPEG audio file']:
if DEBUG: if DEBUG:
self.log.info(" ignoring '%s' of type '%s'" % (book.name(), book.kind())) self.log.info(" ignoring '%s' of type '%s'" % (book.name(), book.kind()))
else: else:
if DEBUG: if DEBUG:
self.log.info(" adding %-30.30s [%s]" % (book.name(), book.kind())) self.log.info(" adding %-30.30s [%s]" % (book.name(), book.kind()))
device_books.append(book) device_books.append(book)
elif iswindows: elif iswindows:
@ -1521,21 +1575,21 @@ class ITUNES(DevicePlugin):
if pl.Kind == self.PlaylistKind.index('User') and \ if pl.Kind == self.PlaylistKind.index('User') and \
pl.SpecialKind == self.PlaylistSpecialKind.index('Books'): pl.SpecialKind == self.PlaylistSpecialKind.index('Books'):
if DEBUG: if DEBUG:
self.log.info(" Books playlist: '%s'" % (pl.Name)) self.log.info(" Books playlist: '%s'" % (pl.Name))
dev_books = pl.Tracks dev_books = pl.Tracks
break break
else: else:
if DEBUG: if DEBUG:
self.log.info(" no Books playlist found") self.log.info(" no Books playlist found")
for book in dev_books: for book in dev_books:
# This may need additional entries for international iTunes users # This may need additional entries for international iTunes users
if book.KindAsString in ['MPEG audio file']: if book.KindAsString in ['MPEG audio file']:
if DEBUG: if DEBUG:
self.log.info(" ignoring '%s' of type '%s'" % (book.Name, book.KindAsString)) self.log.info(" ignoring '%s' of type '%s'" % (book.Name, book.KindAsString))
else: else:
if DEBUG: if DEBUG:
self.log.info(" adding %-30.30s [%s]" % (book.Name, book.KindAsString)) self.log.info(" adding %-30.30s [%s]" % (book.Name, book.KindAsString))
device_books.append(book) device_books.append(book)
finally: finally:
@ -1547,6 +1601,8 @@ class ITUNES(DevicePlugin):
''' '''
assumes pythoncom wrapper assumes pythoncom wrapper
''' '''
if DEBUG:
self.log.info(" ITUNES._get_device_books_playlist()")
if iswindows: if iswindows:
if 'iPod' in self.sources: if 'iPod' in self.sources:
pl = None pl = None
@ -1560,7 +1616,7 @@ class ITUNES(DevicePlugin):
break break
else: else:
if DEBUG: if DEBUG:
self.log.error(" no iPad|Books playlist found") self.log.error(" no iPad|Books playlist found")
return pl return pl
def _get_fpath(self,file): def _get_fpath(self,file):
@ -1570,7 +1626,7 @@ class ITUNES(DevicePlugin):
calibre exits. calibre exits.
''' '''
if DEBUG: if DEBUG:
self.log.info("ITUNES._get_fpath()") self.log.info(" ITUNES._get_fpath()")
fpath = file fpath = file
if not getattr(fpath, 'deleted_after_upload', False): if not getattr(fpath, 'deleted_after_upload', False):
@ -1580,7 +1636,7 @@ class ITUNES(DevicePlugin):
fpath = file.name fpath = file.name
else: else:
if DEBUG: if DEBUG:
self.log.info(" file will be deleted after upload") self.log.info(" file will be deleted after upload")
return fpath return fpath
def _get_library_books(self): def _get_library_books(self):
@ -1588,7 +1644,7 @@ class ITUNES(DevicePlugin):
Populate a dict of paths from iTunes Library|Books Populate a dict of paths from iTunes Library|Books
''' '''
if DEBUG: if DEBUG:
self.log.info("\nITUNES._get_library_books()") self.log.info("\n ITUNES._get_library_books()")
library_books = {} library_books = {}
lib = None lib = None
@ -1598,11 +1654,11 @@ class ITUNES(DevicePlugin):
if source.kind() == appscript.k.library: if source.kind() == appscript.k.library:
lib = source lib = source
if DEBUG: if DEBUG:
self.log.info(" Library source: '%s'" % (lib.name())) self.log.info(" Library source: '%s'" % (lib.name()))
break break
else: else:
if DEBUG: if DEBUG:
self.log.error(' Library source not found') self.log.error(' Library source not found')
if lib is not None: if lib is not None:
lib_books = None lib_books = None
@ -1610,29 +1666,37 @@ class ITUNES(DevicePlugin):
for pl in lib.playlists(): for pl in lib.playlists():
if pl.special_kind() == appscript.k.Books: if pl.special_kind() == appscript.k.Books:
if DEBUG: if DEBUG:
self.log.info(" Books playlist: '%s'" % (pl.name())) self.log.info(" Books playlist: '%s'" % (pl.name()))
break break
else: else:
if DEBUG: if DEBUG:
self.log.info(" no Library|Books playlist found") self.log.info(" no Library|Books playlist found")
lib_books = pl.file_tracks() lib_books = pl.file_tracks()
for book in lib_books: for book in lib_books:
# This may need additional entries for international iTunes users # This may need additional entries for international iTunes users
if book.kind() in ['MPEG audio file']: if book.kind() in ['MPEG audio file']:
if DEBUG: if DEBUG:
self.log.info(" ignoring '%s' of type '%s'" % (book.name(), book.kind())) self.log.info(" ignoring '%s' of type '%s'" % (book.name(), book.kind()))
else: else:
if DEBUG: # Remove calibre orphans
self.log.info(" adding %-30.30s [%s]" % (book.name(), book.kind())) if str(book.description()).startswith(self.description_prefix):
if book.location() == appscript.k.missing_value:
if DEBUG:
self.log.info(" deleting calibre orphan '%s' from Library|Books" % book.name())
book.delete()
continue
path = self.path_template % (book.name(), book.artist()) path = self.path_template % (book.name(), book.artist())
library_books[path] = book library_books[path] = book
if DEBUG:
self.log.info(" adding %-30.30s [%s]" % (book.name(), book.kind()))
else: else:
if DEBUG: if DEBUG:
self.log.info('No Library playlists') self.log.info(' no Library playlists')
else: else:
if DEBUG: if DEBUG:
self.log.info(' no Library found') self.log.info(' no Library found')
elif iswindows: elif iswindows:
lib = None lib = None
@ -1671,10 +1735,18 @@ class ITUNES(DevicePlugin):
if DEBUG: if DEBUG:
self.log.info(" ignoring %-30.30s of type '%s'" % (book.Name, book.KindAsString)) self.log.info(" ignoring %-30.30s of type '%s'" % (book.Name, book.KindAsString))
else: else:
if DEBUG: # Remove calibre orphans
self.log.info(" adding %-30.30s [%s]" % (book.Name, book.KindAsString)) if book.Description.startswith(self.description_prefix):
if not book.Location:
if DEBUG:
self.log.info(" deleting calibre orphan '%s' from Library|Books" % book.Name)
book.Delete()
continue
path = self.path_template % (book.Name, book.Artist) path = self.path_template % (book.Name, book.Artist)
library_books[path] = book library_books[path] = book
if DEBUG:
self.log.info(" adding %-30.30s [%s]" % (book.Name, book.KindAsString))
except: except:
if DEBUG: if DEBUG:
self.log.info(" no books in library") self.log.info(" no books in library")
@ -1730,7 +1802,7 @@ class ITUNES(DevicePlugin):
''' '''
''' '''
if DEBUG: if DEBUG:
self.log.info("ITUNES:_launch_iTunes():\n Instantiating iTunes") self.log.info(" ITUNES:_launch_iTunes():\n Instantiating iTunes")
if isosx: if isosx:
''' '''
@ -1756,13 +1828,13 @@ class ITUNES(DevicePlugin):
if os.path.exists(media_dir): if os.path.exists(media_dir):
self.iTunes_media = media_dir self.iTunes_media = media_dir
else: else:
self.log.error(" could not confirm valid iTunes.media_dir from %s" % 'com.apple.itunes') self.log.error(" could not confirm valid iTunes.media_dir from %s" % 'com.apple.itunes')
if DEBUG: if DEBUG:
self.log.info(" [%s - %s (%s), driver version %d.%d.%d]" % self.log.info(" [%s - %s (%s), driver version %d.%d.%d]" %
(self.iTunes.name(), self.iTunes.version(), initial_status, (self.iTunes.name(), self.iTunes.version(), initial_status,
self.version[0],self.version[1],self.version[2])) self.version[0],self.version[1],self.version[2]))
self.log.info(" iTunes_media: %s" % self.iTunes_media) self.log.info(" iTunes_media: %s" % self.iTunes_media)
if iswindows: if iswindows:
''' '''
Launch iTunes if not already running Launch iTunes if not already running
@ -1783,21 +1855,21 @@ class ITUNES(DevicePlugin):
if os.path.exists(media_dir): if os.path.exists(media_dir):
self.iTunes_media = media_dir self.iTunes_media = media_dir
else: else:
self.log.error(" could not extract valid iTunes.media_dir from %s" % self.iTunes.LibraryXMLPath) self.log.error(" could not extract valid iTunes.media_dir from %s" % self.iTunes.LibraryXMLPath)
self.log.error(" %s" % string.parent.prettify()) self.log.error(" %s" % string.parent.prettify())
self.log.error(" '%s' not found" % media_dir) self.log.error(" '%s' not found" % media_dir)
if DEBUG: if DEBUG:
self.log.info( " [%s - %s (%s), driver version %d.%d.%d]" % self.log.info(" [%s - %s (%s), driver version %d.%d.%d]" %
(self.iTunes.Windows[0].name, self.iTunes.Version, initial_status, (self.iTunes.Windows[0].name, self.iTunes.Version, initial_status,
self.version[0],self.version[1],self.version[2])) self.version[0],self.version[1],self.version[2]))
self.log.info(" iTunes_media: %s" % self.iTunes_media) self.log.info(" iTunes_media: %s" % self.iTunes_media)
def _remove_existing_copies(self,path,file,metadata): def _remove_existing_copies(self,path,file,metadata):
''' '''
''' '''
if DEBUG: if DEBUG:
self.log.info("ITUNES._remove_existing_copies()") self.log.info(" ITUNES._remove_existing_copies()")
if self.manual_sync_mode: if self.manual_sync_mode:
# Delete existing from Device|Books, add to self.update_list # Delete existing from Device|Books, add to self.update_list
@ -1806,14 +1878,14 @@ class ITUNES(DevicePlugin):
self.update_list.append(self.cached_books[path]) self.update_list.append(self.cached_books[path])
self._remove_from_device(self.cached_books[path]) self._remove_from_device(self.cached_books[path])
if DEBUG: if DEBUG:
self.log.info( " deleting device book '%s'" % (path)) self.log.info( " deleting device book '%s'" % (path))
if not getattr(file, 'deleted_after_upload', False): if not getattr(file, 'deleted_after_upload', False):
self._remove_from_iTunes(self.cached_books[path]) self._remove_from_iTunes(self.cached_books[path])
if DEBUG: if DEBUG:
self.log.info(" deleting library book '%s'" % path) self.log.info(" deleting library book '%s'" % path)
else: else:
if DEBUG: if DEBUG:
self.log.info(" '%s' not in cached_books" % metadata.title) self.log.info(" '%s' not in cached_books" % metadata.title)
else: else:
# Delete existing from Library|Books, add to self.update_list # Delete existing from Library|Books, add to self.update_list
# for deletion from booklist[0] during add_books_to_metadata # for deletion from booklist[0] during add_books_to_metadata
@ -1821,21 +1893,20 @@ class ITUNES(DevicePlugin):
self.update_list.append(self.cached_books[path]) self.update_list.append(self.cached_books[path])
self._remove_from_iTunes(self.cached_books[path]) self._remove_from_iTunes(self.cached_books[path])
if DEBUG: if DEBUG:
self.log.info( " deleting library book '%s'" % path) self.log.info( " deleting library book '%s'" % path)
else: else:
if DEBUG: if DEBUG:
self.log.info(" '%s' not in cached_books" % metadata.title) self.log.info(" '%s' not in cached_books" % metadata.title)
def _remove_from_device(self, cached_book): def _remove_from_device(self, cached_book):
''' '''
Windows assumes pythoncom wrapper Windows assumes pythoncom wrapper
''' '''
self.log.info("ITUNES._remove_from_device()") self.log.info(" ITUNES._remove_from_device()")
if isosx: if isosx:
if DEBUG: if DEBUG:
self.log.info(" deleting %s" % cached_book['dev_book']) self.log.info(" deleting %s" % cached_book['dev_book'])
result = cached_book['dev_book'].delete() result = cached_book['dev_book'].delete()
print "result: %s" % result
elif iswindows: elif iswindows:
dev_pl = self._get_device_books_playlist() dev_pl = self._get_device_books_playlist()
@ -1843,10 +1914,10 @@ class ITUNES(DevicePlugin):
if hits: if hits:
for hit in hits: for hit in hits:
if DEBUG: if DEBUG:
self.log.info(" evaluating '%s' by %s" % (hit.Name, hit.Artist)) self.log.info(" evaluating '%s' by %s" % (hit.Name, hit.Artist))
if hit.Name == cached_book['title']: if hit.Name == cached_book['title']:
if DEBUG: if DEBUG:
self.log.info(" deleting '%s' by %s" % (hit.Name, hit.Artist)) self.log.info(" deleting '%s' by %s" % (hit.Name, hit.Artist))
results = hit.Delete() results = hit.Delete()
break break
@ -1856,34 +1927,36 @@ class ITUNES(DevicePlugin):
We only want to delete stored copies if the file is stored in iTunes We only want to delete stored copies if the file is stored in iTunes
We don't want to delete files stored outside of iTunes We don't want to delete files stored outside of iTunes
''' '''
if DEBUG:
self.log.info(" ITUNES._remove_from_iTunes():")
if isosx: if isosx:
storage_path = os.path.split(cached_book['lib_book'].location().path) storage_path = os.path.split(cached_book['lib_book'].location().path)
if cached_book['lib_book'].location().path.startswith(self.iTunes_media): if cached_book['lib_book'].location().path.startswith(self.iTunes_media):
title_storage_path = storage_path[0] title_storage_path = storage_path[0]
if DEBUG: if DEBUG:
self.log.info("ITUNES._remove_from_iTunes():") self.log.info(" removing title_storage_path: %s" % title_storage_path)
self.log.info(" removing title_storage_path: %s" % title_storage_path)
try: try:
shutil.rmtree(title_storage_path) shutil.rmtree(title_storage_path)
except: except:
self.log.info(" '%s' not empty" % title_storage_path) self.log.info(" '%s' not empty" % title_storage_path)
# Clean up title/author directories # Clean up title/author directories
author_storage_path = os.path.split(title_storage_path)[0] author_storage_path = os.path.split(title_storage_path)[0]
self.log.info(" author_storage_path: %s" % author_storage_path) self.log.info(" author_storage_path: %s" % author_storage_path)
author_files = os.listdir(author_storage_path) author_files = os.listdir(author_storage_path)
if '.DS_Store' in author_files: if '.DS_Store' in author_files:
author_files.pop(author_files.index('.DS_Store')) author_files.pop(author_files.index('.DS_Store'))
if not author_files: if not author_files:
shutil.rmtree(author_storage_path) shutil.rmtree(author_storage_path)
if DEBUG: if DEBUG:
self.log.info(" removing empty author_storage_path") self.log.info(" removing empty author_storage_path")
else: else:
if DEBUG: if DEBUG:
self.log.info(" author_storage_path not empty (%d objects):" % len(author_files)) self.log.info(" author_storage_path not empty (%d objects):" % len(author_files))
self.log.info(" %s" % '\n'.join(author_files)) self.log.info(" %s" % '\n'.join(author_files))
else: else:
self.log.info(" '%s' stored external to iTunes, no files deleted" % cached_book['title']) self.log.info(" '%s' stored external to iTunes, no files deleted" % cached_book['title'])
self.iTunes.delete(cached_book['lib_book']) self.iTunes.delete(cached_book['lib_book'])
@ -1892,42 +1965,40 @@ class ITUNES(DevicePlugin):
Assume we're wrapped in a pythoncom Assume we're wrapped in a pythoncom
Windows stores the book under a common author directory, so we just delete the .epub Windows stores the book under a common author directory, so we just delete the .epub
''' '''
if DEBUG:
self.log.info("ITUNES._remove_from_iTunes():\n '%s'" % cached_book['title'])
book = self._find_library_book(cached_book) book = self._find_library_book(cached_book)
if book: if book:
path = book.Location path = book.Location
storage_path = os.path.split(book.Location) storage_path = os.path.split(book.Location)
if book.Location.startswith(self.iTunes_media): if book.Location.startswith(self.iTunes_media):
if DEBUG: if DEBUG:
self.log.info("ITUNES._remove_from_iTunes():") self.log.info(" removing '%s' at %s" %
self.log.info(" removing '%s' at %s" %
(cached_book['title'], path)) (cached_book['title'], path))
try: try:
os.remove(path) os.remove(path)
except: except:
self.log.warning(" could not find '%s' in iTunes storage" % path) self.log.warning(" could not find '%s' in iTunes storage" % path)
try: try:
os.rmdir(storage_path[0]) os.rmdir(storage_path[0])
self.log.info(" removed folder '%s'" % storage_path[0]) self.log.info(" removed folder '%s'" % storage_path[0])
except: except:
self.log.info(" folder '%s' not found or not empty" % storage_path[0]) self.log.info(" folder '%s' not found or not empty" % storage_path[0])
# Delete from iTunes database # Delete from iTunes database
else: else:
self.log.info(" '%s' stored external to iTunes, no files deleted" % cached_book['title']) self.log.info(" '%s' stored external to iTunes, no files deleted" % cached_book['title'])
book.Delete() book.Delete()
else: else:
self.log.warning(" could not find '%s' in iTunes database" % cached_book['title']) self.log.warning(" could not find '%s' in iTunes database" % cached_book['title'])
def _update_device(self, msg='', wait=True): def _update_device(self, msg='', wait=True):
''' '''
Trigger a sync, wait for completion Trigger a sync, wait for completion
''' '''
if DEBUG: if DEBUG:
self.log.info("ITUNES:_update_device():\n %s" % msg) self.log.info(" ITUNES:_update_device():\n %s" % msg)
if isosx: if isosx:
self.iTunes.update() self.iTunes.update()
@ -1935,7 +2006,7 @@ class ITUNES(DevicePlugin):
if wait: if wait:
# This works if iTunes has books not yet synced to iPad. # This works if iTunes has books not yet synced to iPad.
if DEBUG: if DEBUG:
sys.stdout.write(" waiting for iPad sync to complete ...") sys.stdout.write(" waiting for iPad sync to complete ...")
sys.stdout.flush() sys.stdout.flush()
while len(self._get_device_books()) != (len(self._get_library_books()) + len(self._get_purchased_book_ids())): while len(self._get_device_books()) != (len(self._get_library_books()) + len(self._get_purchased_book_ids())):
if DEBUG: if DEBUG:
@ -1950,7 +2021,7 @@ class ITUNES(DevicePlugin):
self.iTunes.UpdateIPod() self.iTunes.UpdateIPod()
if wait: if wait:
if DEBUG: if DEBUG:
sys.stdout.write(" waiting for iPad sync to complete ...") sys.stdout.write(" waiting for iPad sync to complete ...")
sys.stdout.flush() sys.stdout.flush()
while True: while True:
db_count = len(self._get_device_books()) db_count = len(self._get_device_books())
@ -1973,7 +2044,7 @@ class ITUNES(DevicePlugin):
''' '''
''' '''
if DEBUG: if DEBUG:
self.log.info("ITUNES._update_iTunes_metadata()") self.log.info(" ITUNES._update_iTunes_metadata()")
strip_tags = re.compile(r'<[^<]*?/?>') strip_tags = re.compile(r'<[^<]*?/?>')
@ -1995,13 +2066,13 @@ class ITUNES(DevicePlugin):
pass pass
if lb_added: if lb_added:
lb_added.description.set("added by calibre %s" % strftime('%Y-%m-%d %H:%M:%S')) lb_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
lb_added.enabled.set(True) lb_added.enabled.set(True)
lb_added.sort_artist.set(metadata.author_sort.title()) lb_added.sort_artist.set(metadata.author_sort.title())
lb_added.sort_name.set(this_book.title_sorter) lb_added.sort_name.set(this_book.title_sorter)
if db_added: if db_added:
db_added.description.set("added by calibre %s" % strftime('%Y-%m-%d %H:%M:%S')) db_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
db_added.enabled.set(True) db_added.enabled.set(True)
db_added.sort_artist.set(metadata.author_sort.title()) db_added.sort_artist.set(metadata.author_sort.title())
db_added.sort_name.set(this_book.title_sorter) db_added.sort_name.set(this_book.title_sorter)
@ -2036,14 +2107,13 @@ class ITUNES(DevicePlugin):
pass pass
if lb_added: if lb_added:
lb_added.Description = ("added by calibre %s" % strftime('%Y-%m-%d %H:%M:%S')) lb_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
lb_added.Enabled = True lb_added.Enabled = True
lb_added.SortArtist = (metadata.author_sort.title()) lb_added.SortArtist = (metadata.author_sort.title())
lb_added.SortName = (this_book.title_sorter) lb_added.SortName = (this_book.title_sorter)
if db_added: if db_added:
db_added.Description = ("added by calibre %s" % strftime('%Y-%m-%d %H:%M:%S')) db_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
db_added.Enabled = True
db_added.SortArtist = (metadata.author_sort.title()) db_added.SortArtist = (metadata.author_sort.title())
db_added.SortName = (this_book.title_sorter) db_added.SortName = (this_book.title_sorter)