def __init__(self, mpdclient, library, config): ''' Initialize all models. ''' self.mpdclient = mpdclient self.library = library self.config = config self.libraryMutex = mutex.mutex() self.playQueue = PlayQueueModel(mpdclient, library, config) self.playlists = PlaylistsModel(mpdclient, library) self.fileSystem = FileSystemModel(library) self.artists = ArtistsModel(library) self.albums = AlbumsModel(library) self.tracks = TracksModel(library) self.playerState = PlayerState(self.mpdclient, self.playQueue)
class ModelManager(object): ''' This class manages the data in the models. ''' def __init__(self, mpdclient, library, config): ''' Initialize all models. ''' self.mpdclient = mpdclient self.library = library self.config = config self.libraryMutex = mutex.mutex() self.playQueue = PlayQueueModel(mpdclient, library, config) self.playlists = PlaylistsModel(mpdclient, library) self.fileSystem = FileSystemModel(library) self.artists = ArtistsModel(library) self.albums = AlbumsModel(library) self.tracks = TracksModel(library) self.playerState = PlayerState(self.mpdclient, self.playQueue) ################## # Main interface # ################## def processChanges(self, changes): ''' Updates the models according to the change groups in the changes argument. ''' print 'debug: Processing changes' self.mpdclient.send('status', callback= lambda status, changes=changes: self._progressChanges(changes, status)) def _progressChanges(self, changes, status): print 'debug: retrieved status form server.' if status is None: # Status returns None when the connection is in # "command list" mode. We will get a decent # update when that finishes. return if 'database' in changes: self.reloadLibrary(force=True) if 'playlist' in changes: self.updatePlayQueue(status) elif self.playerState.playState == 'stop': self.playQueue.setPlaying(None) else: self.playQueue.setPlaying(status.get('songid')) self.playerState.update(status) if 'stored_playlist' in changes: self.reloadPlaylists() def clearForms(self): ''' Clear all models. ''' self.playerState.reset() self.playQueue._clear() self.playlists.clear() self.fileSystem.clear() self.artists.clear() self.albums.clear() self.tracks.clear() ############## # Play queue # ############## def updatePlayQueue(self, status=None): ''' Updates the play queue model. ''' if not self.config.server: return if status is None: self.mpdclient.send('status', callback=self.updatePlayQueue) return self.mpdclient.send('plchanges', (self.playQueue.version,), callback= lambda changes: self.playQueue.update(changes, status)) #################### # Stored playlists # #################### def reloadPlaylists(self): self.mpdclient.send('listplaylists', callback= self.playlists.update) ############### # MPD Library # ############### def reloadLibrary(self, force=False): ''' Reloads the library in the library models. The library is loaded from cache when it is available and force is not True. The timestamp of the cached content is checked against the server. The cache is automatically updated when necessary. ''' self.mpdclient.send('stats', callback= lambda stats: self._getLibrary(stats['db_update'], force=force)) def _getCachePath(self): ''' Returns the path of the library cache file for the current server. ''' file_name = 'db_cache - ' + self.config.server[0] cache = os.path.expanduser('~/.cache/pythagora') if not os.path.isdir(cache): os.makedirs(cache) return '/'.join((cache, file_name)) def _getLibrary(self, timestamp, force=False): ''' Retrieves the library from the appropriate source. ''' path = self._getCachePath() if os.path.exists(path) and not force: db_cache = open(path, 'rb') if db_cache.readline().strip('\n') == timestamp: mainlist = _unpickle(db_cache) thread.start_new_thread(self._reloadLibrary, (mainlist,)) else: self._downloadStart = time.time() self.mpdclient.send('listallinfo', callback= lambda mainlist: self._cacheLibrary(timestamp, mainlist)) def _cacheLibrary(self, timestamp, mainlist): ''' Updates the library cache. ''' print 'Downloading of the library took {0:.3f} seconds'.format(time.time() - self._downloadStart) path = self._getCachePath() with open(path, 'wb') as db_cache: db_cache.write('%s\n' % timestamp) pickler = pickle.Pickler(db_cache, pickle.HIGHEST_PROTOCOL) for song in mainlist: pickler.dump(song) thread.start_new_thread(self._reloadLibrary, (mainlist,)) def _reloadLibrary(self, mainlist): ''' Reloads the library and updates all library models. ''' self._parseStart = time.time() server = self.config.server try: self.libraryMutex.lock(self.library.reload, mainlist) except pickle.UnpickleableError: self.reloadLibrary(force=True) self.libraryMutex.unlock() return self.libraryMutex.unlock() print 'library parsing took {0:.3} seconds'.format(time.time() - self._parseStart) if self.config.server == server: p = time.time() t = time.time() self.artists.reload(self.library.artists()) print 'load Artist took %.3f seconds' % (time.time() - t); t = time.time() self.albums.reload(self.library.albums()) print 'load Album took %.3f seconds' % (time.time() - t); t = time.time() self.tracks.reload(self.library.songs()) print 'load Tracks took %.3f seconds' % (time.time() - t); t = time.time() self.fileSystem.reload() print 'load file system took %.3f seconds' % (time.time() - t) print 'library load took %.3f seconds' % (time.time() - p)