Beispiel #1
0
 def do_list(self, line):
     container = self._session.playlistcontainer()
     
     if not container.is_loaded():
         checker = BulkConditionChecker()
         #Wait until the container is loaded
         checker.add_condition(container.is_loaded)
         callbacks = JukeboxPlaylistContainerCallbacks(checker)
         container.add_callbacks(callbacks)
         checker.complete_wait()
         
         for item in container.playlists():
             item.set_in_ram(self._session, True)
     
     if not line:
         #Print all playlists
         print "%d playlists:" % container.num_playlists()
         
         for k, item in enumerate(container.playlists()):
             if item.is_loaded():
                 print "playlist #%d: %s" % (k, item.name()) 
             else:
                 print "playlist #%d: loading..." % k
     else:
         pos = int(line)
         pl = container.playlist(pos)
         print "playlist #%d, %d tracks:" % (pos, pl.num_tracks())
         
         for index,item in enumerate(pl.tracks()):
             if item.is_loaded():
                 print "track #%d: %s" % (index, item.name())
                 #print item.album().cover()
             else:
                 print "track #%d: loading..." % index
Beispiel #2
0
 def _load_toplist(self, type, region, user):
     checker = BulkConditionChecker()
     callbacks = ToplistbrowseLoadCallbacks(checker)
     toplistbrowse_obj = toplistbrowse.Toplistbrowse(
         self._session, type, region, user, callbacks
     )
     checker.add_condition(toplistbrowse_obj.is_loaded)
     checker.complete_wait(10)
     
     return toplistbrowse_obj
Beispiel #3
0
    def __init__(self, session, container, playlist_manager):
        self.__session = session
        self.__container = container
        self.__playlist_manager = playlist_manager
        self.__playlists = []
        self.__checker = BulkConditionChecker()
        self.__loading_lock = threading.RLock()
        self.__list_lock = threading.RLock()
        self.__is_loaded = False

        #Load the rest in the background
        self._start_load()
Beispiel #4
0
 def _load_search(self, query):
     checker = BulkConditionChecker()
     callbacks = SearchLoadCallbacks(checker)
     search_obj = search.Search(
         self._session, query,
         track_count=100, album_count=100, artist_count=100,
         callbacks=callbacks
     )
     checker.add_condition(search_obj.is_loaded)
     checker.complete_wait(10)
     
     return search_obj
Beispiel #5
0
    def __init__(self, session, artist):
        self.__checker = BulkConditionChecker()
        self.__session = session
        self.__artist = artist
        self.__album_data = {}
        cb = ArtistCallbacks(self)
        self.__artistbrowse = artistbrowse.Artistbrowse(
            session, artist, BrowseType.NoTracks, cb)
        self.__is_loaded = False

        #Avoid locking this thread and continue in another one
        self.continue_in_background()
Beispiel #6
0
    def load_album_info(self, index, album):
        #Directly discard unavailable albums
        if not album.is_available():
            self.__album_data[index] = {
                'available_tracks': 0,
                'type': self._get_album_type(album),
            }

        #Otherwise load it's data
        else:
            #A checker for a single condition? Overkill!
            checker = BulkConditionChecker()
            cb = AlbumCallbacks(checker)
            album_info = albumbrowse.Albumbrowse(self.__session, album, cb)

            #Now wait until it's loaded
            self._wait_for_album_info(album_info, checker)

            #Populate it's data
            self.__album_data[index] = {
                'available_tracks': self._num_available_tracks(album_info),
                'type': self._get_album_type(album),
            }

            #Tell that we've done
            self.__checker.check_conditions()
Beispiel #7
0
 def _load_artist(self, id):
     full_id = "spotify:artist:%s" % id
     checker = BulkConditionChecker()
     
     #Get the artist object
     link_obj = link.create_from_string(full_id)
     artist_obj = link_obj.as_artist()
     
     #Now initialize the artistbrowse load stuff
     callbacks = ArtistbrowseLoadCallbacks(checker)
     artistbrowse_obj = artistbrowse.Artistbrowse(
         self._session, artist_obj, callbacks
     )
     checker.add_condition(artistbrowse_obj.is_loaded)
     checker.complete_wait(10)
     
     return artist_obj, artistbrowse_obj
Beispiel #8
0
    def __init__(self, session, playlist, playlist_manager):
        #Initialize all instance vars
        self.__playlist = playlist
        self.__playlist_manager = playlist_manager
        self.__checker = BulkConditionChecker()
        self.__is_loaded = False
        self.__has_errors = False
        self.__thumbnails = []

        #Add the callbacks we are interested in
        playlist.add_callbacks(PlaylistCallbacks(self))

        #Fire playlist loading if neccesary
        if not playlist.is_in_ram(session):
            playlist.set_in_ram(session, True)

        #Finish the rest in the background
        self.load_in_background()
Beispiel #9
0
 def _load_album(self, id):
     import time
     full_id = "spotify:album:%s" % id
     checker = BulkConditionChecker()
     
     #All the album loading stuff
     link_obj = link.create_from_string(full_id)
     album_obj = link_obj.as_album()
     
     #Now the albumbrowse object
     callbacks = AlbumbrowseLoadCallbacks(checker)
     albumbrowse_obj = albumbrowse.Albumbrowse(
         self._session, album_obj, callbacks
     )
     checker.add_condition(albumbrowse_obj.is_loaded)
     checker.complete_wait(10)
     
     return album_obj, albumbrowse_obj
Beispiel #10
0
    def get_album_info(self, index):
        album = self.__artistbrowse.album(index)
        checker = BulkConditionChecker()
        cb = AlbumCallbacks(checker)
        album_info = albumbrowse.Albumbrowse(self.__session, album, cb)

        #Wait until it's loaded
        self._wait_for_album_info(album_info, checker)

        return album_info
def load_track(sess_obj, track_obj):
    
    #FIXME: Doing all these things is just overkill!
    if not track_obj.is_loaded():
    
        #Set callbacks for loading the track
        checker = BulkConditionChecker()
        checker.add_condition(track_obj.is_loaded)
        callbacks = TrackLoadCallback(checker)
        sess_obj.add_callbacks(callbacks)
        
        try:
            #Wait until it's done (should be enough)
            checker.complete_wait(10)
        
        finally:
            #Remove that callback, or will be around forever
            sess_obj.remove_callbacks(callbacks)
    
    return track_obj
Beispiel #12
0
 def __init__(self, session, container, playlist_manager):
     self.__session = session
     self.__container = container
     self.__playlist_manager = playlist_manager
     self.__playlists = []
     self.__checker = BulkConditionChecker()
     self.__loading_lock = threading.RLock()
     self.__list_lock = threading.RLock()
     self.__is_loaded = False
     
     #Load the rest in the background
     self._start_load()
Beispiel #13
0
 def do_list(self, line):
     container = self._session.playlistcontainer()
     
     if not container.is_loaded():
         checker = BulkConditionChecker()
         #Wait until the container is loaded
         checker.add_condition(container.is_loaded)
         callbacks = JukeboxPlaylistContainerCallbacks(checker)
         container.add_callbacks(callbacks)
         checker.complete_wait()
         
         for item in container.playlists():
             item.set_in_ram(self._session, True)
     
     if not line:
         #Print all playlists
         print "%d playlists:" % container.num_playlists()
         
         for k, item in enumerate(container.playlists()):
             if item.is_loaded():
                 print "playlist #%d: %s" % (k, item.name()) 
             else:
                 print "playlist #%d: loading..." % k
     else:
         pos = int(line)
         pl = container.playlist(pos)
         print "playlist #%d, %d tracks:" % (pos, pl.num_tracks())
         
         for index,item in enumerate(pl.tracks()):
             if item.is_loaded():
                 print "track #%d: %s" % (index, item.name())
                 #print item.album().cover()
             else:
                 print "track #%d: loading..." % index
Beispiel #14
0
 def __init__(self, session, artist):
     self.__checker = BulkConditionChecker()
     self.__session = session
     self.__artist = artist
     self.__album_data = {}
     cb = ArtistCallbacks(self)
     self.__artistbrowse = artistbrowse.Artistbrowse(
         session, artist, BrowseType.NoTracks, cb
     )
     self.__is_loaded = False
     
     #Avoid locking this thread and continue in another one
     self.continue_in_background()
Beispiel #15
0
    def _load_toplist(self, type, region, user):
        checker = BulkConditionChecker()
        callbacks = ToplistbrowseLoadCallbacks(checker)
        toplistbrowse_obj = toplistbrowse.Toplistbrowse(
            self._session, type, region, user, callbacks)
        checker.add_condition(toplistbrowse_obj.is_loaded)
        checker.complete_wait(10)

        return toplistbrowse_obj
Beispiel #16
0
 def _load_radio(self, from_year, to_year, genres):
     checker = BulkConditionChecker()
     callbacks = SearchLoadCallbacks(checker)
     radio_obj = radio.RadioSearch(
         self._session, from_year, to_year, genres, callbacks
     )
     checker.add_condition(radio_obj.is_loaded)
     checker.complete_wait(10)
     
     return radio_obj
Beispiel #17
0
 def _load_search(self, query):
     checker = BulkConditionChecker()
     callbacks = SearchLoadCallbacks(checker)
     search_obj = search.Search(
         self._session, query,
         track_count=100, album_count=100, artist_count=100,
         callbacks=callbacks
     )
     checker.add_condition(search_obj.is_loaded)
     checker.complete_wait(10)
     
     return search_obj
Beispiel #18
0
 def __init__(self, session, playlist, playlist_manager):
     #Initialize all instance vars
     self.__playlist = playlist
     self.__playlist_manager = playlist_manager
     self.__checker = BulkConditionChecker()
     self.__is_loaded = False
     self.__has_errors = False
     self.__thumbnails = []
     
     #Add the callbacks we are interested in
     playlist.add_callbacks(PlaylistCallbacks(self))
     
     #Fire playlist loading if neccesary
     if not playlist.is_in_ram(session):
         playlist.set_in_ram(session, True)
     
     #Finish the rest in the background
     self.load_in_background()
Beispiel #19
0
    def _load_artist(self, id):
        full_id = "spotify:artist:%s" % id
        checker = BulkConditionChecker()

        #Get the artist object
        link_obj = link.create_from_string(full_id)
        artist_obj = link_obj.as_artist()

        #Now initialize the artistbrowse load stuff
        callbacks = ArtistbrowseLoadCallbacks(checker)
        artistbrowse_obj = artistbrowse.Artistbrowse(self._session, artist_obj,
                                                     callbacks)
        checker.add_condition(artistbrowse_obj.is_loaded)
        checker.complete_wait(10)

        return artist_obj, artistbrowse_obj
Beispiel #20
0
    def _load_album(self, id):
        import time
        full_id = "spotify:album:%s" % id
        checker = BulkConditionChecker()

        #All the album loading stuff
        link_obj = link.create_from_string(full_id)
        album_obj = link_obj.as_album()

        #Now the albumbrowse object
        callbacks = AlbumbrowseLoadCallbacks(checker)
        albumbrowse_obj = albumbrowse.Albumbrowse(self._session, album_obj,
                                                  callbacks)
        checker.add_condition(albumbrowse_obj.is_loaded)
        checker.complete_wait(10)

        return album_obj, albumbrowse_obj
Beispiel #21
0
class ContainerLoader:
    __session = None
    __container = None
    __playlist_manager = None
    __playlists = None
    __checker = None
    __loading_lock = None
    __list_lock = None
    __is_loaded = None

    def __init__(self, session, container, playlist_manager):
        self.__session = session
        self.__container = container
        self.__playlist_manager = playlist_manager
        self.__playlists = []
        self.__checker = BulkConditionChecker()
        self.__loading_lock = threading.RLock()
        self.__list_lock = threading.RLock()
        self.__is_loaded = False

        #Load the rest in the background
        self._start_load()

    def _fill_spaces(self, position):
        try:
            self.__list_lock.acquire()

            if position >= len(self.__playlists):
                for idx in range(len(self.__playlists), position + 1):
                    self.__playlists.append(None)

        finally:
            self.__list_lock.release()

    def is_playlist(self, position):
        playlist_type = self.__container.playlist_type(position)
        return playlist_type == playlist.PlaylistType.Playlist

    def add_playlist(self, playlist, position):
        try:
            self.__list_lock.acquire()

            #Ensure that it gets added in the correct position
            self._fill_spaces(position - 1)

            #Instantiate a loader if it's a real playlist
            if self.is_playlist(position):
                item = ContainerPlaylistLoader(self.__session, playlist,
                                               self.__playlist_manager, self)

            #Ignore if it's not a real playlist
            else:
                item = None

            #Insert the generated item
            self.__playlists.insert(position, item)

        finally:
            self.__list_lock.release()

    def remove_playlist(self, position):
        try:
            self.__list_lock.acquire()
            del self.__playlists[position]

        finally:
            self.__list_lock.release()

    def move_playlist(self, position, new_position):
        try:
            self.__list_lock.acquire()
            self.__playlists.insert(new_position, self.__playlists[position])

            #Calculate new position
            if position > new_position:
                position += 1

            del self.__playlists[position]

        finally:
            self.__list_lock.release()

    def _add_missing_playlists(self):
        #Ensure that the container and loader length is the same
        self._fill_spaces(self.__container.num_playlists() - 1)

        #Iterate over the container to add the missing ones
        for pos, item in enumerate(self.__container.playlists()):
            if self.is_playlist(pos) and self.__playlists[pos] is None:
                self.add_playlist(item, pos)

    def _check_playlist(self, playlist):
        def is_playlist_loaded():
            #If it has errors, say yes.
            if playlist.has_errors():
                return True

            #And if it was loaded, say yes
            if playlist.is_loaded():
                return True

        self.__checker.add_condition(is_playlist_loaded)

    def _load_container(self):
        #Wait for the container to be fully loaded
        self.__checker.add_condition(self.__container.is_loaded)
        self.__checker.complete_wait()

        #Fill the container with unseen playlists
        self._add_missing_playlists()

        #Add a load check for each playlist
        for item in self.__playlists:
            if item is not None and not item.is_loaded():
                self._check_playlist(item)

        #Wait until all conditions become true
        self.__checker.complete_wait(self.__container.num_playlists() * 5)

        #Set the status of the loader
        self.__is_loaded = True

        #Check and print errors for not loaded playlists
        for idx, item in enumerate(self.__playlists):
            if item is not None and item.has_errors():
                xbmc.log('Playlist #%s failed loading.' % idx, xbmc.LOGERROR)

        #Finally tell the gui we are done
        xbmc.executebuiltin("Action(Noop)")

    @run_in_thread
    def _start_update(self):
        """
        Try gaining a lock.
        If we can't get one, another update is running, so do nothing.
        """
        if self.__loading_lock.acquire(False):
            try:
                self._load_container()

            finally:
                self.__loading_lock.release()

    @run_in_thread
    def _start_load(self):
        self.__loading_lock.acquire()

        try:
            """
            Register container callbacks so they start loading after
            this point. Too bad if they reach before.
            """
            self.__container.add_callbacks(ContainerCallbacks(self))

            #And take care of the rest
            self._load_container()

        finally:
            self.__loading_lock.release()

    def update(self):
        self.__checker.check_conditions()
        self._start_update()

    def is_loaded(self):
        return self.__is_loaded

    def playlist(self, index):
        return self.__playlists[index]

    def num_playlists(self):
        return len(self.__playlists)

    def playlists(self):
        return CallbackIterator(self.num_playlists, self.playlist)

    def get_container(self):
        return self.__container

    def __del__(self):
        print "ContainerLoader __del__"
Beispiel #22
0
class ArtistAlbumLoader:
    __checker = None
    __session = None
    __artist = None
    __album_data = None
    __artistbrowse = None
    __is_loaded = None
    __sorted_albums = None

    def __init__(self, session, artist):
        self.__checker = BulkConditionChecker()
        self.__session = session
        self.__artist = artist
        self.__album_data = {}
        cb = ArtistCallbacks(self)
        self.__artistbrowse = artistbrowse.Artistbrowse(
            session, artist, BrowseType.NoTracks, cb)
        self.__is_loaded = False

        #Avoid locking this thread and continue in another one
        self.continue_in_background()

    def check(self):
        self.__checker.check_conditions()

    def _wait_for_album_info(self, album_info, checker):
        def info_is_loaded():
            return album_info.is_loaded()

        if not info_is_loaded():
            checker.add_condition(info_is_loaded)
            checker.complete_wait(10)  #Should be enough for an album

    def _num_available_tracks(self, album_info):
        count = 0

        #Return true if it has at least one playable track
        for track in album_info.tracks():
            track_status = track.get_availability(self.__session)
            if track_status == TrackAvailability.Available:
                count += 1

        return count

    def _is_same_artist(self, artist1, artist2):
        album1_str = link.create_from_artist(artist1).as_string()
        album2_str = link.create_from_artist(artist2).as_string()

        return album1_str == album2_str

    def _get_album_type(self, album):
        if album.type() == SpotifyAlbumType.Single:
            return AlbumType.Single

        elif album.type() == SpotifyAlbumType.Compilation:
            return AlbumType.Compilation

        if not self._is_same_artist(self.__artist, album.artist()):
            return AlbumType.AppearsIn

        else:
            return AlbumType.Album

    def get_album_info(self, index):
        album = self.__artistbrowse.album(index)
        checker = BulkConditionChecker()
        cb = AlbumCallbacks(checker)
        album_info = albumbrowse.Albumbrowse(self.__session, album, cb)

        #Wait until it's loaded
        self._wait_for_album_info(album_info, checker)

        return album_info

    @run_in_thread(threads_per_class=5)
    def load_album_info(self, index, album):
        #Directly discard unavailable albums
        if not album.is_available():
            self.__album_data[index] = {
                'available_tracks': 0,
                'type': self._get_album_type(album),
            }

        #Otherwise load it's data
        else:
            #A checker for a single condition? Overkill!
            checker = BulkConditionChecker()
            cb = AlbumCallbacks(checker)
            album_info = albumbrowse.Albumbrowse(self.__session, album, cb)

            #Now wait until it's loaded
            self._wait_for_album_info(album_info, checker)

            #Populate it's data
            self.__album_data[index] = {
                'available_tracks': self._num_available_tracks(album_info),
                'type': self._get_album_type(album),
            }

            #Tell that we've done
            self.__checker.check_conditions()

    def _wait_for_album_list(self):
        if not self.__artistbrowse.is_loaded():
            self.__checker.add_condition(self.__artistbrowse.is_loaded)
            self.__checker.complete_wait(60)  #Should be enough?

    def _add_album_processed_check(self, index):
        def album_is_processed():
            return index in self.__album_data

        if not album_is_processed():
            self.__checker.add_condition(album_is_processed)

    @run_in_thread(threads_per_class=1)
    def continue_in_background(self):
        #Wait until the album list got loaded
        self._wait_for_album_list()

        #Now load albumbrowse data from each one
        for index, album in enumerate(self.__artistbrowse.albums()):
            #Add a condition for the next wait
            self._add_album_processed_check(index)

            #Start loading the info in the background
            self.load_album_info(index, album)

        #Now wait until all info gets loaded
        self.__checker.complete_wait(60)

        #Final steps...
        self.__is_loaded = True
        xbmc.executebuiltin("Action(Noop)")

    def is_loaded(self):
        return self.__is_loaded

    def get_album_available_tracks(self, index):
        return self.__album_data[index]['available_tracks']

    def get_album_type(self, index):
        return self.__album_data[index]['type']

    def get_album(self, index):
        return self.__artistbrowse.album(index)

    def get_non_similar_albums(self):
        name_dict = {}

        for index, album in self.get_albums():
            name = album.name()
            available_tracks = self.get_album_available_tracks(index)

            #If that name is new to us just store it
            if name not in name_dict:
                name_dict[name] = (index, available_tracks)

            #If the album has more playable tracks than the stored one
            elif available_tracks > name_dict[name][1]:
                name_dict[name] = (index, available_tracks)

        #Now return the list if indexes
        return [item[0] for item in name_dict.itervalues()]

    def get_albums(self):
        def sort_func(album_index):
            #Sort by album type and then by year (desc)
            return (self.get_album_type(album_index),
                    -self.__artistbrowse.album(album_index).year())

        #Do nothing if is loading
        if self.is_loaded():
            #Build the sorted album list if needed
            if self.__sorted_albums is None:
                album_indexes = self.__album_data.keys()
                sorted_indexes = sorted(album_indexes, key=sort_func)
                ab = self.__artistbrowse
                self.__sorted_albums = [(index, ab.album(index))
                                        for index in sorted_indexes]
                print self.__sorted_albums

            return self.__sorted_albums
Beispiel #23
0
class ContainerLoader:
    __session = None
    __container = None
    __playlist_manager = None
    __playlists = None
    __checker = None
    __loading_lock = None
    __list_lock = None
    __is_loaded = None
    
    
    def __init__(self, session, container, playlist_manager):
        self.__session = session
        self.__container = container
        self.__playlist_manager = playlist_manager
        self.__playlists = []
        self.__checker = BulkConditionChecker()
        self.__loading_lock = threading.RLock()
        self.__list_lock = threading.RLock()
        self.__is_loaded = False
        
        #Load the rest in the background
        self._start_load()
    
    
    def _fill_spaces(self, position):
        try:
            self.__list_lock.acquire()
            
            if position >= len(self.__playlists):
                for idx in range(len(self.__playlists), position + 1):
                    self.__playlists.append(None)
        
        finally:
            self.__list_lock.release()
    
    
    def is_playlist(self, position):
        playlist_type = self.__container.playlist_type(position)
        return playlist_type == playlist.PlaylistType.Playlist
    
    
    def add_playlist(self, playlist, position):
        try:
            self.__list_lock.acquire()
            
            #Ensure that it gets added in the correct position
            self._fill_spaces(position - 1)
            
            #Instantiate a loader if it's a real playlist
            if self.is_playlist(position):
                item = ContainerPlaylistLoader(
                    self.__session, playlist, self.__playlist_manager, self 
                )
            
            #Ignore if it's not a real playlist
            else:
                item = None
            
            #Insert the generated item
            self.__playlists.insert(position, item)
                
        
        finally:
            self.__list_lock.release()
    
    
    def remove_playlist(self, position):
        try:
            self.__list_lock.acquire()
            del self.__playlists[position]
        
        finally:
            self.__list_lock.release()
    
    
    def move_playlist(self, position, new_position):
        try:
            self.__list_lock.acquire()
            self.__playlists.insert(new_position, self.__playlists[position])
            
            #Calculate new position
            if position > new_position:
                position += 1
            
            del self.__playlists[position]
        
        finally:
            self.__list_lock.release()
    
    
    def _add_missing_playlists(self):
        #Ensure that the container and loader length is the same
        self._fill_spaces(self.__container.num_playlists() - 1)
        
        #Iterate over the container to add the missing ones
        for pos, item in enumerate(self.__container.playlists()):
            if self.is_playlist(pos) and self.__playlists[pos] is None:
                self.add_playlist(item, pos)
    
    
    def _check_playlist(self, playlist):
        def is_playlist_loaded():
            #If it has errors, say yes.
            if playlist.has_errors():
                return True
            
            #And if it was loaded, say yes
            if playlist.is_loaded():
                return True
        
        self.__checker.add_condition(is_playlist_loaded)
    
    
    def _load_container(self):
        #Wait for the container to be fully loaded
        self.__checker.add_condition(self.__container.is_loaded)
        self.__checker.complete_wait()
        
        #Fill the container with unseen playlists
        self._add_missing_playlists()
        
        #Add a load check for each playlist
        for item in self.__playlists:
            if item is not None and not item.is_loaded():
                self._check_playlist(item)
        
        #Wait until all conditions become true
        self.__checker.complete_wait(self.__container.num_playlists() * 5)
        
        #Set the status of the loader
        self.__is_loaded = True
        
        #Check and print errors for not loaded playlists
        for idx, item in enumerate(self.__playlists):
            if item is not None and item.has_errors():
                xbmc.log('Playlist #%s failed loading.' % idx, xbmc.LOGERROR)
        
        #Finally tell the gui we are done
        xbmc.executebuiltin("Action(Noop)")
    
    
    @run_in_thread
    def _start_update(self):
        """
        Try gaining a lock.
        If we can't get one, another update is running, so do nothing.
        """
        if self.__loading_lock.acquire(False):
            try:
                self._load_container()
            
            finally:
                self.__loading_lock.release()
    
    
    @run_in_thread
    def _start_load(self):
        self.__loading_lock.acquire()
        
        try:
            """
            Register container callbacks so they start loading after
            this point. Too bad if they reach before.
            """
            self.__container.add_callbacks(ContainerCallbacks(self))
            
            #And take care of the rest
            self._load_container()
        
        finally:
            self.__loading_lock.release()
    
    
    def update(self):
        self.__checker.check_conditions()
        self._start_update()
    
    
    def is_loaded(self):
        return self.__is_loaded
    
    
    def playlist(self, index):
        return self.__playlists[index]
    
    
    def num_playlists(self):
        return len(self.__playlists)
    
    
    def playlists(self):
        return CallbackIterator(self.num_playlists, self.playlist)
    
    
    def get_container(self):
        return self.__container
    
    
    def __del__(self):
        print "ContainerLoader __del__"
Beispiel #24
0
class BasePlaylistLoader:
    __playlist = None
    __playlist_manager = None
    __checker = None
    
    #Playlist attributes
    __name = None
    __num_tracks = None
    __thumbnails = None
    __is_collaborative = None
    __is_loaded = None
    __has_errors = None
    __has_changes = None
    
    
    def __init__(self, session, playlist, playlist_manager):
        #Initialize all instance vars
        self.__playlist = playlist
        self.__playlist_manager = playlist_manager
        self.__checker = BulkConditionChecker()
        self.__is_loaded = False
        self.__has_errors = False
        self.__thumbnails = []
        
        #Add the callbacks we are interested in
        playlist.add_callbacks(PlaylistCallbacks(self))
        
        #Fire playlist loading if neccesary
        if not playlist.is_in_ram(session):
            playlist.set_in_ram(session, True)
        
        #Finish the rest in the background
        self.load_in_background()
    
    
    @run_in_thread(threads_per_class=10, single_instance=True)
    def load_in_background(self):
        try:
            #Reset change flag
            self._set_changes(False)
            
            #And call the method that does the actual loading task
            self._start_loading()
            
            #Clear previous error flags (if any)
            if self.has_errors():
                self._set_error(False)
        
        except:
            #Mark this playlist
            self._set_error(True)
        
        finally:
            #If changes or errors were detected
            if self.has_changes() or self.has_errors():
                self.end_loading()
    
    
    def get_playlist(self):
        return self.__playlist
    
    
    def _set_thumbnails(self, thumbnails):
        self.__thumbnails = thumbnails
    
    
    def get_thumbnails(self):
        return self.__thumbnails
    
    
    def _set_name(self, name):
        self.__name = name
    
    
    def get_name(self):
        return self.__name
    
    
    def get_num_tracks(self):
        return self.__num_tracks
    
    
    def get_tracks(self):
        return self.__playlist.tracks()
    
    
    def get_track(self, index):
        track_list = self.get_tracks()
        return track_list[index]
    
    
    def get_is_collaborative(self):
        return self.__is_collaborative
    
    
    def _track_is_ready(self, track, test_album=True, test_artists=True):
        def album_is_loaded():
            album = track.album()
            return album is not None and album.is_loaded()
        
        def artists_are_loaded():
            for item in track.artists():
                if item is None or not item.is_loaded():
                    return False
            return True
        
        #If track has an error stop further processing
        if track.error() not in [ErrorType.Ok, ErrorType.IsLoading]:
            return True
        
        #Always test for the track data
        if not track.is_loaded():
            return False
        
        #If album data was requested
        elif test_album and not album_is_loaded():
            return False
        
        #If artist data was requested
        elif test_artists and not artists_are_loaded():
            return False
        
        #Otherwise everything was ok
        else:
            return True
    
    
    def _wait_for_playlist(self):
        if not self.__playlist.is_loaded():
            self.__checker.add_condition(self.__playlist.is_loaded)
            self.__checker.complete_wait(10)
    
    
    def _wait_for_track_metadata(self, track):
        def test_is_loaded():
            return self._track_is_ready(
                track, test_album=True, test_artists=False
            )
        
        if not test_is_loaded():
            self.__checker.add_condition(test_is_loaded)
            self.__checker.complete_wait(10)
    
    
    def _load_thumbnails(self):
        pm = self.__playlist_manager
        
        #If playlist has an image
        playlist_image = self.__playlist.get_image()
        if playlist_image is not None:
            thumbnails = [pm.get_image_url(playlist_image)]
        
        #Otherwise get them from the album covers
        else:
            thumbnails = []
            for item in self.__playlist.tracks():
                #Wait until this track is fully loaded
                self._wait_for_track_metadata(item)
                
                #Check if item was loaded without errors
                if item.is_loaded() and item.error() == 0:
                    #Append the cover if it's new
                    image_id = item.album().cover()
                    image_url = pm.get_image_url(image_id)
                    if image_url not in thumbnails:
                        thumbnails.append(image_url)
                    
                    #If we reached to the desired thumbnail count...
                    if len(thumbnails) == 4:
                        break
        
        #If the thumnbail count is still zero...
        if len(thumbnails) == 0:
            self.__thumbnails = ['common/pl-default.png']
            return True
        
        #If the stored thumbnail data changed...
        if self.__thumbnails != thumbnails:
            self.__thumbnails = thumbnails
            return True
    
    
    def _load_name(self):
        if self.__name != self.__playlist.name():
            self.__name = self.__playlist.name()
            return True
        else:
            return False
    
    
    def _load_num_tracks(self):
        if self.__num_tracks != self.__playlist.num_tracks():
            self.__num_tracks = self.__playlist.num_tracks()
            return True
        else:
            return False
    
    
    def _load_is_collaborative(self):
        if self.__is_collaborative != self.__playlist.is_collaborative():
            self.__is_collaborative = self.__playlist.is_collaborative()
            return True
        else:
            return False
    
    
    def _load_attributes(self):
        #Now check for changes
        has_changes = False
        
        if self._load_name():
            has_changes = True
        
        if self._load_num_tracks():
            has_changes = True
        
        if self._load_is_collaborative():
            has_changes = True
        
        #If we detected something different
        return has_changes
    
    
    def _add_condition(self, condition):
        self.__checker.add_condition(condition)
   
   
    def _wait_for_conditions(self, timeout):
        self.__checker.complete_wait(timeout)
    
    
    def check(self):
        self.__checker.check_conditions()
    
    
    def _set_loaded(self, status):
        self.__is_loaded = status 
    
    
    def is_loaded(self):
        return self.__is_loaded
    
    
    def _set_error(self, status):
        self.__has_errors = status
        
    
    def has_errors(self):
        return self.__has_errors
    
    
    def _set_changes(self, status):
        self.__has_changes = status
    
    
    def has_changes(self):
        return self.__has_changes
    
    
    def _start_loading(self):
        raise NotImplementedError()
    
    
    def end_loading(self):
        pass
    
    
    def __del__(self):
        print "PlaylistLoader __del__"
Beispiel #25
0
class ArtistAlbumLoader:
    __checker = None
    __session = None
    __artist = None
    __album_data = None
    __artistbrowse = None
    __is_loaded = None
    __sorted_albums = None
    
    
    def __init__(self, session, artist):
        self.__checker = BulkConditionChecker()
        self.__session = session
        self.__artist = artist
        self.__album_data = {}
        cb = ArtistCallbacks(self)
        self.__artistbrowse = artistbrowse.Artistbrowse(
            session, artist, BrowseType.NoTracks, cb
        )
        self.__is_loaded = False
        
        #Avoid locking this thread and continue in another one
        self.continue_in_background()
    
    
    def check(self):
        self.__checker.check_conditions()
    
    
    def _wait_for_album_info(self, album_info, checker):
        def info_is_loaded():
            return album_info.is_loaded()
        
        if not info_is_loaded():
            checker.add_condition(info_is_loaded)
            checker.complete_wait(10) #Should be enough for an album
    
    
    def _num_available_tracks(self, album_info):
        count = 0
        
        #Return true if it has at least one playable track
        for track in album_info.tracks():
            track_status = track.get_availability(self.__session)
            if track_status == TrackAvailability.Available:
                count += 1
        
        return count
    
    
    def _is_same_artist(self, artist1, artist2):
        album1_str = link.create_from_artist(artist1).as_string()
        album2_str = link.create_from_artist(artist2).as_string()
        
        return album1_str == album2_str
    
    
    def _get_album_type(self, album):
        if album.type() == SpotifyAlbumType.Single:
            return AlbumType.Single
        
        elif album.type() == SpotifyAlbumType.Compilation:
            return AlbumType.Compilation
        
        if not self._is_same_artist(self.__artist, album.artist()):
            return AlbumType.AppearsIn
        
        else:
            return AlbumType.Album
    
    
    @run_in_thread(threads_per_class=5)
    def load_album_info(self, index, album):
        #Directly discard unavailable albums
        if not album.is_available():
            self.__album_data[index] = {
                'available_tracks': 0,
                'type': self._get_album_type(album),
            }
        
        #Otherwise load it's data
        else:
            #A checker for a single condition? Overkill!
            checker = BulkConditionChecker()
            cb = AlbumCallbacks(checker)
            album_info = albumbrowse.Albumbrowse(self.__session, album, cb)
            
            #Now wait until it's loaded
            self._wait_for_album_info(album_info, checker)
            
            #Populate it's data
            self.__album_data[index] = {
                'available_tracks': self._num_available_tracks(album_info),
                'type': self._get_album_type(album),
            }
            
            #Tell that we've done
            self.__checker.check_conditions()
        
        
    def _wait_for_album_list(self):
        if not self.__artistbrowse.is_loaded():
            self.__checker.add_condition(self.__artistbrowse.is_loaded)
            self.__checker.complete_wait(60) #Should be enough?
    
    
    def _add_album_processed_check(self, index):
        def album_is_processed():
            return index in self.__album_data
        
        if not album_is_processed():
            self.__checker.add_condition(album_is_processed)
    
    
    @run_in_thread(threads_per_class=1)
    def continue_in_background(self):
        #Wait until the album list got loaded
        self._wait_for_album_list()
        
        #Now load albumbrowse data from each one
        for index, album in enumerate(self.__artistbrowse.albums()):
            #Add a condition for the next wait
            self._add_album_processed_check(index)
            
            #Start loading the info in the background
            self.load_album_info(index, album)
        
        #Now wait until all info gets loaded
        self.__checker.complete_wait(60)
        
        #Final steps...
        self.__is_loaded = True
        xbmc.executebuiltin("Action(Noop)")
    
    
    def is_loaded(self):
        return self.__is_loaded
    
    
    def get_album_available_tracks(self, index):
        return self.__album_data[index]['available_tracks']
    
    
    def get_album_type(self, index):
        return self.__album_data[index]['type']
    
    
    def get_album(self, index):
        return self.__artistbrowse.album(index)
    
    
    def get_non_similar_albums(self):
        name_dict = {}
        
        for index, album in self.get_albums():
            name = album.name()
            available_tracks = self.get_album_available_tracks(index)
            
            #If that name is new to us just store it
            if name not in name_dict:
                name_dict[name] = (index, available_tracks)
            
            #If the album has more playable tracks than the stored one 
            elif available_tracks > name_dict[name][1]:
                name_dict[name] = (index, available_tracks)
        
        #Now return the list if indexes
        return [item[0] for item in name_dict.itervalues()]
    
    
    def get_albums(self):
        def sort_func(album_index):
            #Sort by album type and then by year (desc)
            return (
                self.get_album_type(album_index),
                -self.__artistbrowse.album(album_index).year()
            )
        
        #Do nothing if is loading
        if self.is_loaded():
            #Build the sorted album list if needed
            if self.__sorted_albums is None:
                album_indexes = self.__album_data.keys()
                sorted_indexes = sorted(album_indexes, key=sort_func)
                ab = self.__artistbrowse
                self.__sorted_albums = [
                    (index, ab.album(index)) for index in sorted_indexes
                ]
                print self.__sorted_albums
            
            return self.__sorted_albums
Beispiel #26
0
class BasePlaylistLoader:
    __playlist = None
    __playlist_manager = None
    __checker = None

    #Playlist attributes
    __name = None
    __num_tracks = None
    __thumbnails = None
    __is_collaborative = None
    __is_loaded = None
    __has_errors = None
    __has_changes = None

    def __init__(self, session, playlist, playlist_manager):
        #Initialize all instance vars
        self.__playlist = playlist
        self.__playlist_manager = playlist_manager
        self.__checker = BulkConditionChecker()
        self.__is_loaded = False
        self.__has_errors = False
        self.__thumbnails = []

        #Add the callbacks we are interested in
        playlist.add_callbacks(PlaylistCallbacks(self))

        #Fire playlist loading if neccesary
        if not playlist.is_in_ram(session):
            playlist.set_in_ram(session, True)

        #Finish the rest in the background
        self.load_in_background()

    @run_in_thread(threads_per_class=10, single_instance=True)
    def load_in_background(self):
        try:
            #Reset change flag
            self._set_changes(False)

            #And call the method that does the actual loading task
            self._start_loading()

            #Clear previous error flags (if any)
            if self.has_errors():
                self._set_error(False)

        except:
            #Mark this playlist
            self._set_error(True)

        finally:
            #If changes or errors were detected
            if self.has_changes() or self.has_errors():
                self.end_loading()

    def get_playlist(self):
        return self.__playlist

    def _set_thumbnails(self, thumbnails):
        self.__thumbnails = thumbnails

    def get_thumbnails(self):
        return self.__thumbnails

    def _set_name(self, name):
        self.__name = name

    def get_name(self):
        return self.__name

    def get_num_tracks(self):
        return self.__num_tracks

    def get_tracks(self):
        return self.__playlist.tracks()

    def get_track(self, index):
        track_list = self.get_tracks()
        return track_list[index]

    def get_is_collaborative(self):
        return self.__is_collaborative

    def _track_is_ready(self, track, test_album=True, test_artists=True):
        def album_is_loaded():
            album = track.album()
            return album is not None and album.is_loaded()

        def artists_are_loaded():
            for item in track.artists():
                if item is None or not item.is_loaded():
                    return False
            return True

        #If track has an error stop further processing
        if track.error() not in [ErrorType.Ok, ErrorType.IsLoading]:
            return True

        #Always test for the track data
        if not track.is_loaded():
            return False

        #If album data was requested
        elif test_album and not album_is_loaded():
            return False

        #If artist data was requested
        elif test_artists and not artists_are_loaded():
            return False

        #Otherwise everything was ok
        else:
            return True

    def _wait_for_playlist(self):
        if not self.__playlist.is_loaded():
            self.__checker.add_condition(self.__playlist.is_loaded)
            self.__checker.complete_wait(10)

    def _wait_for_track_metadata(self, track):
        def test_is_loaded():
            return self._track_is_ready(track,
                                        test_album=True,
                                        test_artists=False)

        if not test_is_loaded():
            self.__checker.add_condition(test_is_loaded)
            self.__checker.complete_wait(10)

    def _load_thumbnails(self):
        pm = self.__playlist_manager

        #If playlist has an image
        playlist_image = self.__playlist.get_image()
        if playlist_image is not None:
            thumbnails = [pm.get_image_url(playlist_image)]

        #Otherwise get them from the album covers
        else:
            thumbnails = []
            for item in self.__playlist.tracks():
                #Wait until this track is fully loaded
                self._wait_for_track_metadata(item)

                #Check if item was loaded without errors
                if item.is_loaded() and item.error() == 0:
                    #Append the cover if it's new
                    image_id = item.album().cover()
                    image_url = pm.get_image_url(image_id)
                    if image_url not in thumbnails:
                        thumbnails.append(image_url)

                    #If we reached to the desired thumbnail count...
                    if len(thumbnails) == 4:
                        break

        #If the thumnbail count is still zero...
        if len(thumbnails) == 0:
            self.__thumbnails = ['common/pl-default.png']
            return True

        #If the stored thumbnail data changed...
        if self.__thumbnails != thumbnails:
            self.__thumbnails = thumbnails
            return True

    def _load_name(self):
        if self.__name != self.__playlist.name():
            self.__name = self.__playlist.name()
            return True
        else:
            return False

    def _load_num_tracks(self):
        if self.__num_tracks != self.__playlist.num_tracks():
            self.__num_tracks = self.__playlist.num_tracks()
            return True
        else:
            return False

    def _load_is_collaborative(self):
        if self.__is_collaborative != self.__playlist.is_collaborative():
            self.__is_collaborative = self.__playlist.is_collaborative()
            return True
        else:
            return False

    def _load_attributes(self):
        #Now check for changes
        has_changes = False

        if self._load_name():
            has_changes = True

        if self._load_num_tracks():
            has_changes = True

        if self._load_is_collaborative():
            has_changes = True

        #If we detected something different
        return has_changes

    def _add_condition(self, condition):
        self.__checker.add_condition(condition)

    def _wait_for_conditions(self, timeout):
        self.__checker.complete_wait(timeout)

    def check(self):
        self.__checker.check_conditions()

    def _set_loaded(self, status):
        self.__is_loaded = status

    def is_loaded(self):
        return self.__is_loaded

    def _set_error(self, status):
        self.__has_errors = status

    def has_errors(self):
        return self.__has_errors

    def _set_changes(self, status):
        self.__has_changes = status

    def has_changes(self):
        return self.__has_changes

    def _start_loading(self):
        raise NotImplementedError()

    def end_loading(self):
        pass

    def __del__(self):
        print "PlaylistLoader __del__"