GwR revisions

This commit is contained in:
GRiker 2010-06-04 11:48:24 -06:00
parent 0086263f52
commit 375393997b
2 changed files with 165 additions and 113 deletions

View File

@ -44,6 +44,12 @@ if iswindows:
] ]
class ITUNES(DevicePlugin): class ITUNES(DevicePlugin):
'''
try:
pythoncom.CoInitialize()
finally:
pythoncom.CoUninitialize()
'''
name = 'Apple device interface' name = 'Apple device interface'
gui_name = 'Apple device' gui_name = 'Apple device'
@ -69,6 +75,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')
ejected = False
iTunes= None iTunes= None
log = Log() log = Log()
path_template = 'iTunes/%s - %s.epub' path_template = 'iTunes/%s - %s.epub'
@ -264,31 +271,49 @@ class ITUNES(DevicePlugin):
if self.iTunes: if self.iTunes:
# Check for connected book-capable device # Check for connected book-capable device
try: self.sources = self._get_sources()
''' if 'iPod' in self.sources:
names = [s.name() for s in self.iTunes.sources()] #if DEBUG:
kinds = [str(s.kind()).rpartition('.')[2] for s in self.iTunes.sources()] #sys.stdout.write('.')
self.sources = sources = dict(zip(kinds,names)) #sys.stdout.flush()
''' return True
self.sources = self._get_sources() else:
if 'iPod' in self.sources: if DEBUG:
# if DEBUG: sys.stdout.write('-')
# sys.stdout.write('.') sys.stdout.flush()
# sys.stdout.flush()
return True
else:
if DEBUG:
self.log.info("ITUNES.can_handle(): device ejected")
return False
except:
# iTunes connection failed, probably not running anymore
self.log.error("ITUNES.can_handle(): lost connection to iTunes")
return False return False
else: else:
# can_handle() is called once before open(), so need to return True # Called at entry
# to keep things going # We need to know if iTunes sees the iPad
# It may have been ejected
if DEBUG: if DEBUG:
self.log.info("ITUNES:can_handle(): iTunes not yet instantiated") self.log.info("ITUNES.can_handle()")
self._launch_iTunes()
self.sources = self._get_sources()
if (not 'iPod' in self.sources) or (self.sources['iPod'] == ''):
attempts = 9
while attempts:
# If iTunes was just launched, device may not be detected yet
self.sources = self._get_sources()
if (not 'iPod' in self.sources) or (self.sources['iPod'] == ''):
attempts -= 1
time.sleep(0.5)
if DEBUG:
self.log.warning(" waiting for identified iPad, attempt #%d" % (10 - attempts))
else:
if DEBUG:
self.log.info(' found connected iPad in iTunes')
break
else:
# iTunes running, but not connected iPad
if DEBUG:
self.log.info(' self.ejected = True')
self.ejected = True
return False
else:
self.log.info(' found connected iPad in sources')
return True return True
def can_handle_windows(self, device_id, debug=False): def can_handle_windows(self, device_id, debug=False):
@ -302,35 +327,74 @@ class ITUNES(DevicePlugin):
:param device_info: On windows a device ID string. On Unix a tuple of :param device_info: On windows a device ID string. On Unix a tuple of
``(vendor_id, product_id, bcd)``. ``(vendor_id, product_id, bcd)``.
iPad implementation notes:
It is necessary to use this method to check for the presence of a connected
iPad, as we have to return True if we can handle device interaction, or False if not.
''' '''
if self.iTunes: if self.iTunes:
# Check for connected book-capable device # We've previously run, so the user probably ejected the device
try: try:
''' pythoncom.CoInitialize()
names = [s.name() for s in self.iTunes.sources()]
kinds = [str(s.kind()).rpartition('.')[2] for s in self.iTunes.sources()]
self.sources = sources = dict(zip(kinds,names))
'''
self.sources = self._get_sources() self.sources = self._get_sources()
if 'iPod' in self.sources: if 'iPod' in self.sources:
if DEBUG: if DEBUG:
sys.stdout.write('.') sys.stdout.write('.')
sys.stdout.flush() sys.stdout.flush()
if DEBUG:
self.log.info('ITUNES.can_handle_windows:\n confirming connected iPad')
self.ejected = False
return True return True
else: else:
if DEBUG: if DEBUG:
self.log.info("ITUNES.can_handle(): device ejected") self.log.info("ITUNES.can_handle_windows():\n device ejected")
self.ejected = True
return False return False
except: except:
# iTunes connection failed, probably not running anymore # iTunes connection failed, probably not running anymore
self.log.error("ITUNES.can_handle(): lost connection to iTunes")
self.log.error("ITUNES.can_handle_windows():\n lost connection to iTunes")
return False return False
finally:
pythoncom.CoUninitialize()
else: else:
# can_handle_windows() is called once before open(), so need to return True # This is called at entry
# to keep things going # We need to know if iTunes sees the iPad
# It may have been ejected
if DEBUG: if DEBUG:
self.log.info("ITUNES:can_handle(): iTunes not yet instantiated") self.log.info("ITUNES:can_handle_windows():\n Launching iTunes")
try:
pythoncom.CoInitialize()
self._launch_iTunes()
self.sources = self._get_sources()
if (not 'iPod' in self.sources) or (self.sources['iPod'] == ''):
attempts = 9
while attempts:
# If iTunes was just launched, device may not be detected yet
self.sources = self._get_sources()
if (not 'iPod' in self.sources) or (self.sources['iPod'] == ''):
attempts -= 1
time.sleep(0.5)
if DEBUG:
self.log.warning(" waiting for identified iPad, attempt #%d" % (10 - attempts))
else:
if DEBUG:
self.log.info(' found connected iPad in iTunes')
break
else:
# iTunes running, but not connected iPad
if DEBUG:
self.log.info(' self.ejected = True')
self.ejected = True
return False
else:
self.log.info(' found connected iPad in sources')
finally:
pythoncom.CoUninitialize()
return True return True
def card_prefix(self, end_session=True): def card_prefix(self, end_session=True):
@ -343,8 +407,6 @@ class ITUNES(DevicePlugin):
('place', None) ('place', None)
(None, None) (None, None)
''' '''
# if DEBUG:
# self.log.info("ITUNES:card_prefix()")
return (None,None) return (None,None)
def delete_books(self, paths, end_session=True): def delete_books(self, paths, end_session=True):
@ -423,13 +485,19 @@ class ITUNES(DevicePlugin):
elif iswindows: elif iswindows:
if 'iPod' in self.sources: if 'iPod' in self.sources:
try:
pythoncom.CoInitialize() while True:
self.iTunes = win32com.client.Dispatch("iTunes.Application") try:
connected_device = self.sources['iPod'] try:
free_space = self.iTunes.sources.ItemByName(connected_device).FreeSpace pythoncom.CoInitialize()
finally: self.iTunes = win32com.client.Dispatch("iTunes.Application")
pythoncom.CoUninitialize() connected_device = self.sources['iPod']
free_space = self.iTunes.sources.ItemByName(connected_device).FreeSpace
finally:
pythoncom.CoUninitialize()
break
except:
self.log.error(' waiting for free_space() call to go through')
return (free_space,-1,-1) return (free_space,-1,-1)
@ -462,62 +530,11 @@ class ITUNES(DevicePlugin):
mounted. The base class within USBMS device.py has a implementation of mounted. The base class within USBMS device.py has a implementation of
this function that should serve as a good example for USB Mass storage this function that should serve as a good example for USB Mass storage
devices. devices.
Note that most of the initialization is necessarily performed in can_handle(), as
we need to talk to iTunes to discover if there's a connected iPod
''' '''
if isosx:
# Launch iTunes if not already running
if DEBUG:
self.log.info("ITUNES:open(): Instantiating iTunes")
# Instantiate iTunes
running_apps = appscript.app('System Events')
if not 'iTunes' in running_apps.processes.name():
if DEBUG:
self.log.info( "ITUNES:open(): Launching iTunes" )
self.iTunes = iTunes= appscript.app('iTunes', hide=True)
iTunes.run()
initial_status = 'launched'
else:
self.iTunes = appscript.app('iTunes')
initial_status = 'already running'
if DEBUG:
self.log.info( " %s - %s (%s), driver version %s" %
(self.iTunes.name(), self.iTunes.version(), initial_status, repr(self.version)))
# Init the iTunes source list
'''
names = [s.name() for s in self.iTunes.sources()]
kinds = [str(s.kind()).rpartition('.')[2] for s in self.iTunes.sources()]
self.sources = dict(zip(kinds,names))
'''
self.sources = self._get_sources()
elif iswindows:
# Launch iTunes if not already running
if DEBUG:
self.log.info("ITUNES:open(): Instantiating iTunes")
# Instantiate iTunes
try:
pythoncom.CoInitialize()
self.iTunes = win32com.client.Dispatch("iTunes.Application")
if not DEBUG:
self.iTunes.Windows[0].Minimized = True
initial_status = 'launched'
if DEBUG:
self.log.info( " %s - %s (%s), driver version %d.%d.%d" %
(self.iTunes.Windows[0].name, self.iTunes.Version, initial_status,
self.version[0],self.version[1],self.version[2]))
# Init the iTunes source list
self.sources = self._get_sources()
finally:
pythoncom.CoUninitialize()
# Confirm/create thumbs archive # Confirm/create thumbs archive
archive_path = os.path.join(self.cache_dir, "thumbs.zip") archive_path = os.path.join(self.cache_dir, "thumbs.zip")
@ -586,8 +603,6 @@ class ITUNES(DevicePlugin):
If it is called with -1 that means that the If it is called with -1 that means that the
task does not have any progress information task does not have any progress information
''' '''
# if DEBUG:
# self.log.info("ITUNES:set_progress_reporter()")
self.report_progress = report_progress self.report_progress = report_progress
def settings(self): def settings(self):
@ -595,8 +610,6 @@ class ITUNES(DevicePlugin):
Should return an opts object. The opts object should have one attribute Should return an opts object. The opts object should have one attribute
`format_map` which is an ordered list of formats for the device. `format_map` which is an ordered list of formats for the device.
''' '''
# if DEBUG:
# self.log.info("ITUNES.settings()")
klass = self if isinstance(self, type) else self.__class__ klass = self if isinstance(self, type) else self.__class__
c = Config('device_drivers_%s' % klass.__name__, _('settings for device drivers')) c = Config('device_drivers_%s' % klass.__name__, _('settings for device drivers'))
c.add_opt('format_map', default=self.FORMATS, c.add_opt('format_map', default=self.FORMATS,
@ -627,16 +640,9 @@ class ITUNES(DevicePlugin):
size_on_device = self._get_device_book_size(updated_book['title'], size_on_device = self._get_device_book_size(updated_book['title'],
updated_book['author'][0]) updated_book['author'][0])
if size_on_device: if size_on_device:
if DEBUG:
self._dump_booklist(booklists[0], 'sync_booklists()')
self.log.info(" looking for '%s' by %s" %
(updated_book['title'], updated_book['author']))
for book in booklists[0]: for book in booklists[0]:
if book.title == updated_book['title'] and \ if book.title == updated_book['title'] and \
book.author == updated_book['author']: book.author == updated_book['author']:
if DEBUG:
self.log.info(" found '%s' by %s" % (book.title, book.author[0]))
book.size = size_on_device
break break
else: else:
self.log.error("ITUNES:sync_booklists(): could not update book size for '%s'" % updated_book['title']) self.log.error("ITUNES:sync_booklists(): could not update book size for '%s'" % updated_book['title'])
@ -1224,6 +1230,10 @@ class ITUNES(DevicePlugin):
dev_playlists = [pl.Name for pl in dev.Playlists] dev_playlists = [pl.Name for pl in dev.Playlists]
if 'Books' in dev_playlists: if 'Books' in dev_playlists:
return self.iTunes.sources.ItemByName(connected_device).Playlists.ItemByName('Books').Tracks return self.iTunes.sources.ItemByName(connected_device).Playlists.ItemByName('Books').Tracks
else:
return []
if DEBUG:
self.log.warning('ITUNES._get_device_book(): No iPod device connected')
return [] return []
def _get_library_books(self): def _get_library_books(self):
@ -1285,6 +1295,7 @@ class ITUNES(DevicePlugin):
kinds = [str(s.kind()).rpartition('.')[2] for s in self.iTunes.sources()] kinds = [str(s.kind()).rpartition('.')[2] for s in self.iTunes.sources()]
return dict(zip(kinds,names)) return dict(zip(kinds,names))
elif iswindows: elif iswindows:
# Assumes a pythoncom wrapper
it_sources = ['Unknown','Library','iPod','AudioCD','MP3CD','Device','RadioTuner','SharedLibrary'] it_sources = ['Unknown','Library','iPod','AudioCD','MP3CD','Device','RadioTuner','SharedLibrary']
names = [s.name for s in self.iTunes.sources] names = [s.name for s in self.iTunes.sources]
kinds = [it_sources[s.kind] for s in self.iTunes.sources] kinds = [it_sources[s.kind] for s in self.iTunes.sources]
@ -1298,6 +1309,49 @@ class ITUNES(DevicePlugin):
else: else:
return True return True
def _launch_iTunes(self):
'''
'''
if DEBUG:
self.log.info("ITUNES:_launch_iTunes():\n Instantiating iTunes")
if isosx:
'''
Launch iTunes if not already running
'''
# Instantiate iTunes
running_apps = appscript.app('System Events')
if not 'iTunes' in running_apps.processes.name():
if DEBUG:
self.log.info( "ITUNES:open(): Launching iTunes" )
self.iTunes = iTunes= appscript.app('iTunes', hide=True)
iTunes.run()
initial_status = 'launched'
else:
self.iTunes = appscript.app('iTunes')
initial_status = 'already running'
if DEBUG:
self.log.info( " [%s - %s (%s), driver version %d.%d.%d]" %
(self.iTunes.name(), self.iTunes.version(), initial_status,
self.version[0],self.version[1],self.version[2]))
if iswindows:
'''
Launch iTunes if not already running
Assumes pythoncom wrapper
'''
# Instantiate iTunes
self.iTunes = win32com.client.Dispatch("iTunes.Application")
if not DEBUG:
self.iTunes.Windows[0].Minimized = True
initial_status = 'launched'
if DEBUG:
self.log.info( " [%s - %s (%s), driver version %d.%d.%d]" %
(self.iTunes.Windows[0].name, self.iTunes.Version, initial_status,
self.version[0],self.version[1],self.version[2]))
def _remove_from_iTunes(self, cached_book): def _remove_from_iTunes(self, cached_book):
''' '''
iTunes does not delete books from storage when removing from database iTunes does not delete books from storage when removing from database
@ -1393,8 +1447,8 @@ class ITUNES(DevicePlugin):
pb_count = len(self._get_purchased_book_ids()) pb_count = len(self._get_purchased_book_ids())
if db_count != lb_count + pb_count: if db_count != lb_count + pb_count:
if DEBUG: if DEBUG:
sys.stdout.write(' %d != %d + %d\n' % (db_count,lb_count,pb_count)) #sys.stdout.write(' %d != %d + %d\n' % (db_count,lb_count,pb_count))
#sys.stdout.write('.') sys.stdout.write('.')
sys.stdout.flush() sys.stdout.flush()
time.sleep(2) time.sleep(2)
else: else:

View File

@ -185,15 +185,13 @@ class TouchscreenIndexTemplate(Template):
for i, feed in enumerate(feeds): for i, feed in enumerate(feeds):
if feed: if feed:
tr = TR() tr = TR()
tr.append(TD( CLASS('toc_item','calibre_rescale_120'), A(feed.title.strip(), href='feed_%d/index.html'%i))) tr.append(TD( CLASS('calibre_rescale_120'), A(feed.title, href='feed_%d/index.html'%i)))
tr.append(TD( '%s' % len(feed.articles), style="text-align:right")) tr.append(TD( '%s' % len(feed.articles), style="text-align:right"))
toc.append(tr) toc.append(tr)
div = DIV( div = DIV(
masthead_p, masthead_p,
PT(date, style='text-align:center'), PT(date, style='text-align:center'),
toc, toc)
CLASS('calibre_rescale_100'))
self.root = HTML(head, BODY(div)) self.root = HTML(head, BODY(div))
class FeedTemplate(Template): class FeedTemplate(Template):