예제 #1
0
class SpotifyClient(object):
    def __init__(self, host):
        self.host = host

        self.direct = Direct(self)
        self.server = None

        self.sp = None
        self.reconnect_time = None
        self.reconnect_timer = None

        self.ready_event = Event()
        self.messages = []

    def start(self):
        if self.sp:
            self.sp.disconnect()
            self.sp = None

        self.sp = Spotify()

        self.ready_event = Event()
        self.messages = []

        self.sp.on('error', self.on_error)\
               .on('close', self.on_close)

        self.sp.login(self.host.username, self.host.password, self.on_login)

    def on_login(self):
        # Refresh server info
        self.host.refresh()

        # Release request hold
        self.ready_event.set()

    def on_error(self, message):
        self.messages.append((logging.ERROR, message))
        Log.Error(message)

    def on_close(self, code, reason=None):
        # Force re-authentication
        self.sp.authenticated = False

        # Reconnect
        self.connect()

    def connect(self):
        # Rate-limit re-connections
        if self.reconnect_time:
            span = time.time() - self.reconnect_time
            Log.Debug('Last reconnection attempt was %s seconds ago', span)

            # Delay next reconnection
            if span < 120:
                self.connect_delayed()
                return

        Log.Info('Attempting reconnection to Spotify...')

        self.reconnect_time = time.time()

        # Hold requests while we re-connect
        self.ready_event = Event()

        # Start connecting...
        self.sp.connect()

    def connect_delayed(self):
        self.reconnect_timer = Timer(180, self.connect)
        self.reconnect_timer.start()

        Log.Info('Reconnection will be attempted again in 180 seconds')

    @property
    def constructed(self):
        return self.sp and self.ready_event

    @property
    def ready(self):
        if not self.constructed:
            return False

        return self.ready_event.wait(10)

    def shutdown(self):
        self.sp.api.shutdown()
        self.sp = None

    #
    # Public methods
    #

    def search(self, query, query_type='all', max_results=50, offset=0):
        """ Execute a search

        :param query:          A query string.
        """
        return self.sp.search(query, query_type, max_results, offset)

    def artist_uris(self, artist):
        top_tracks = self.artist_top_tracks(artist)

        # Top Track URIs
        track_uris = []

        if top_tracks:
            track_uris = [tr.uri for tr in top_tracks.tracks if tr is not None]

        # Album URIs
        album_uris = [al.uri for al in artist.albums if al is not None]

        return track_uris, album_uris

    def artist_top_tracks(self, artist):
        for tt in artist.top_tracks:
            # TopTracks matches account region?
            if tt.country == self.sp.country:
                return tt

        # Unable to find TopTracks for account region
        return None

    #
    # Streaming
    #

    def track_url(self, track):
        if self.host.proxy_tracks and self.server:
            return self.server.get_track_url(str(track.uri),
                                             hostname=self.host.hostname)

        return function_path('play', uri=str(track.uri), ext='mp3')

    def stream_url(self, uri):
        if self.host.proxy_tracks and self.server:
            return self.server.get_track_url(str(uri),
                                             hostname=self.host.hostname)

        return self.direct.get(uri)

    def last_message(self):
        if not self.messages:
            return None, ''

        return self.messages[-1]
예제 #2
0
class SpotifyClient(object):
    def __init__(self, host):
        self.host = host

        self.direct = Direct(self)
        self.server = None

        self.sp = None
        self.reconnect_time = None
        self.reconnect_timer = None

        self.ready_event = Event()
        self.messages = []

    def start(self):
        if self.sp:
            self.sp.disconnect()
            self.sp = None

        self.sp = Spotify()

        self.ready_event = Event()
        self.messages = []

        self.sp.on('error', self.on_error)\
               .on('close', self.on_close)

        self.sp.login(self.host.username, self.host.password, self.on_login)

    def on_login(self):
        # Refresh server info
        self.host.refresh()

        # Release request hold
        self.ready_event.set()

    def on_error(self, message):
        self.messages.append((logging.ERROR, message))
        Log.Error(message)

    def on_close(self, code, reason=None):
        # Force re-authentication
        self.sp.authenticated = False

        # Reconnect
        self.connect()

    def connect(self):
        # Rate-limit re-connections
        if self.reconnect_time:
            span = time.time() - self.reconnect_time
            Log.Debug('Last reconnection attempt was %s seconds ago', span)

            # Delay next reconnection
            if span < 120:
                self.connect_delayed()
                return

        Log.Info('Attempting reconnection to Spotify...')

        self.reconnect_time = time.time()

        # Hold requests while we re-connect
        self.ready_event = Event()

        # Start connecting...
        self.sp.connect()

    def connect_delayed(self):
        self.reconnect_timer = Timer(180, self.connect)
        self.reconnect_timer.start()

        Log.Info('Reconnection will be attempted again in 180 seconds')

    @property
    def constructed(self):
        return self.sp and self.ready_event

    @property
    def ready(self):
        if not self.constructed:
            return False

        return self.ready_event.wait(10)

    def shutdown(self):
        self.sp.api.shutdown()
        self.sp = None

    #
    # Public methods
    #

    def search(self, query, query_type='all', max_results=50, offset=0):
        """ Execute a search

        :param query:          A query string.
        """
        return self.sp.search(query, query_type, max_results, offset)

    def artist_uris(self, artist):
        top_tracks = self.artist_top_tracks(artist)

        # Top Track URIs
        track_uris = []

        if top_tracks:
            track_uris = [tr.uri for tr in top_tracks.tracks if tr is not None]

        # Album URIs
        album_uris = [al.uri for al in artist.albums if al is not None]

        return track_uris, album_uris

    def artist_top_tracks(self, artist):
        for tt in artist.top_tracks:
            # TopTracks matches account region?
            if tt.country == self.sp.country:
                return tt

        # Unable to find TopTracks for account region
        return None

    #
    # Streaming
    #

    def track_url(self, track):
        if self.host.proxy_tracks and self.server:
            return self.server.get_track_url(str(track.uri), hostname=self.host.hostname)

        return function_path('play', uri=str(track.uri), ext='mp3')

    def stream_url(self, uri):
        if self.host.proxy_tracks and self.server:
            return self.server.get_track_url(str(uri), hostname=self.host.hostname)

        return self.direct.get(uri)

    def last_message(self):
        if not self.messages:
            return None, ''

        return self.messages[-1]