예제 #1
0
def getSong(spotifyAccount: spotipy.Spotify):
    results = spotifyAccount.current_user_playing_track()
    item = results['item']
    albumData = item['album']
    artist = albumData['artists'][0]['name']
    albumName = albumData['name']
    songName = item['name']
    genius = lyricsgenius.Genius(client_genius_secret)
    return Song(artist, albumName, songName, genius, results['progress_ms'],
                item['duration_ms'])
예제 #2
0
class Client:
    def __init__(self, api_id: str, api_secret: str, redirect_uri: str,
                 username: str, update_time: int) -> None:
        self.client_id = api_id
        self.client_secret = api_secret
        self.redirect_uri = redirect_uri
        self.username = username
        self.update_time = update_time
        self._client: Spotify = None

    def init(self):
        auth_manager = SpotifyOAuth(client_id=self.client_id,
                                    client_secret=self.client_secret,
                                    redirect_uri=self.redirect_uri,
                                    scope="user-read-currently-playing",
                                    username=self.username)
        self._client = Spotify(auth_manager=auth_manager)
        return self._client

    def get_current_track(self):
        track = self._client.current_user_playing_track()
        if not track:
            return Track()
        song = track['item']
        if not song:
            return Track()
        return Track(song['id'], song['name'], song['artists'][0]['name'],
                     song['album']['images'][0]['url'], track['is_playing'])

    def wait_for_new_track(self, last_track_id):
        track = self.get_current_track()
        while track.playing and track.id == last_track_id:
            time.sleep(self.update_time)
            track = self.get_current_track()

    def wait_for_track_play(self):
        track = self.get_current_track()
        while not track.playing:
            time.sleep(self.update_time)
            track = self.get_current_track()
예제 #3
0
class _ThingSpotifyImpl(_ThingSpotifyDummy):
    def __init__(self, api_base_url, tok):
        super().__init__(api_base_url)
        self._sp = Spotify(auth=tok)
        self.unmuted_vol_pct = 0
        self.volume_up_pct_delta = 10

        self.status_cache_seconds = 10
        self.last_status = None
        self.last_status_t = 0

    def playpause(self):
        if self._is_active():
            self._sp.pause_playback()
        else:
            self._sp.start_playback()

    def stop(self):
        self._sp.pause_playback()

    def play_next_in_queue(self):
        self._sp.next_track()

    def play_prev_in_queue(self):
        # First 'prev' just moves playtime back to 0
        self._sp.previous_track()
        self._sp.previous_track()

    def set_playtime(self, t):
        if not self._is_active():
            return

        self._sp.seek_track(int(t) * 1000)

    def volume_up(self):
        if not self._is_active():
            return

        vol = self._get_volume_pct() + self.volume_up_pct_delta
        if vol > 100:
            vol = 100
        self.set_volume_pct(vol)

    def volume_down(self):
        if not self._is_active():
            return

        vol = self._get_volume_pct() - self.volume_up_pct_delta
        if vol < 0:
            vol = 0
        self.set_volume_pct(vol)

    def set_volume_pct(self, pct):
        if not self._is_active():
            return
        self._sp.volume(int(pct))

    def toggle_mute(self):
        if not self._is_active():
            return
        vol = self._get_volume_pct()
        if vol == 0:
            self.set_volume_pct(self.unmuted_vol_pct)
        else:
            self.unmuted_vol_pct = vol
            self.set_volume_pct(0)

    def play_in_device(self, dev_name):
        devs = self._sp.devices()['devices']
        for dev in devs:
            if dev['name'] == dev_name:
                self._sp.transfer_playback(dev['id'])
                if self.json_status(nocache=True)['player_state'] != 'Playing':
                    self.playpause()
                return

        raise KeyError("Spotify knows no device called {}".format(dev_name))

    def _get_volume_pct(self):
        l = [
            x for x in self._sp.devices()['devices'] if x['is_active'] == True
        ]
        if len(l) == 0:
            return 0
        return l[0]['volume_percent']

    def _is_active(self):
        track = self._sp.current_user_playing_track()
        return (track is not None) and track['is_playing']

    def json_status(self, nocache=False):
        global LAST_ACTIVE_DEVICE
        if nocache == False and self.last_status is not None:
            if time.time() - self.last_status_t < self.status_cache_seconds:
                logger.debug("Return Spotify status from cache")
                return self.last_status

        self.last_status_t = time.time()

        devices = self._sp.devices()['devices']

        active_dev = None
        if len(devices) > 0:
            act_devs = [x for x in devices if x['is_active'] == True]
            if len(act_devs) > 0:
                active_dev = act_devs[0]

        if active_dev is not None:
            LAST_ACTIVE_DEVICE = active_dev['name']

        vol = active_dev['volume_percent'] if active_dev is not None else 0

        track = self._sp.current_user_playing_track()
        is_active = (track is not None) and track['is_playing']

        self.last_status = {
            'name': self.get_id(),
            'uri': None,
            'active_device':
            active_dev['name'] if active_dev is not None else None,
            'last_active_device': LAST_ACTIVE_DEVICE,
            'available_devices': [x['name'] for x in devices],
            'app': None,
            'volume_pct': vol,
            'volume_muted': (vol == 0),
            'player_state': 'Playing' if is_active else 'Idle',
            'media': None,
        }

        if track is None or track['item'] is None:
            return self.last_status

        # Get all cover images sorted by image size
        imgs = []
        try:
            imgs = [(img['height'] * img['width'], img['url'])
                    for img in track['item']['album']['images']]
            imgs.sort()
        except:
            pass

        # Pick an image that's at least 300*300 (or the biggest, if all are smaller)
        selected_img = None
        for img in imgs:
            area, selected_img = img
            if area >= 90000:
                break

        self.last_status['media'] = {
            'icon': selected_img,
            'title': track['item']['name'],
            'duration': track['item']['duration_ms'] / 1000,
            'current_time': track['progress_ms'] / 1000,
            'spotify_metadata': {
                'artist':
                ', '.join(
                    [x['name'] for x in track['item']['album']['artists']]),
                'album_link':
                track['item']['album']['external_urls']['spotify'],
                'album_name':
                track['item']['album']['name'],
                'track_count':
                track['item']['album']['total_tracks'],
                'current_track':
                track['item']['track_number'],
            }
        }

        return self.last_status
예제 #4
0
def get_playing_track(sp: Spotify) -> Dict[str, Any]:
    """Get user's currently playing track"""
    return sp.current_user_playing_track()
예제 #5
0
sp_oauth = SpotifyOAuth(cache_path=environ['SPOTIPY_CACHE_PATH'], scope=scope)

try:
    tokens = sp_oauth.get_access_token(code=authorization_code, as_dict=True)
except Exception as e:
    tokens = sp_oauth.refresh_access_token(
        sp_oauth.get_cached_token()['refresh_token'])

expires_at = tokens['expires_at']
artists_names = []
artists_urls = []

if expires_at > int(datetime.now().strftime('%s')):
    sp = Spotify(auth_manager=sp_oauth)
    last_updated = datetime.now(tz=utc).strftime('%Y-%m-%d %H:%M:%S %Z')
    currently_playing = sp.current_user_playing_track()
    if currently_playing:
        song_name = currently_playing['item']['name']
        song_url = currently_playing['item']['external_urls']['spotify']
        album_name = currently_playing['item']['album']['external_urls'][
            'spotify']
        album_image_url = currently_playing['item']['album']['images'][0][
            'url']
        artists = currently_playing['item']['artists']
        if len(artists) > 1:
            for artist in artists:
                artists_names.append(artist['name'])
                artists_urls.append(artist['external_urls']['spotify'])
        else:
            artists_names.append(artists[0]['name'])
            artists_urls.append(artists[0]['external_urls']['spotify'])
예제 #6
0
    def update_job(self):
        def update_color_caller():
            self.set_color((0, 0, 0))
            self.set_color_palette([])

        token = util.prompt_for_user_token(
            Config.SPOTIFY_USERNAME,
            "user-read-playback-state",
            client_id=Config.SPOTIFY_CLIENT_ID,
            client_secret=Config.SPOTIFY_CLIENT_SECRET,
            redirect_uri=Config.SPOTIFY_REDIRECT_URI,
        )

        sp = Spotify(auth=token)

        current_track = sp.current_user_playing_track()

        if (current_track is None or not current_track["is_playing"]
                or current_track["item"] is None):
            job = self.scheduler.get_job("color_updater")

            if job is not None:
                job.remove()

            if job is not None or self.current_track is not None:
                self.set_color((0, 0, 0))
                self.set_color_palette([])
                self.set_is_playing(False)
                self.set_current_track_title("")

            return

        track_id = current_track["item"]["id"]

        if self.current_track is None:
            self.set_is_playing(True)

        if self.current_track != track_id:
            self.current_track = track_id

            cover_urls = current_track["item"]["album"]["images"]
            cover_url = cover_urls[0]["url"]

            response = requests.get(cover_url)
            response.raise_for_status()
            image = Image.open(BytesIO(response.content))

            self.set_color(self.color_finder.get_most_prominent_color(image))
            self.set_color_palette(self.get_color_palette(image))
            self.set_current_track_title(current_track["item"]["name"])

        # One cannot use this as this is not correct
        # now = datetime.fromtimestamp(current_track['timestamp'] / 1000)

        now = datetime.now()

        start_of_track = now - timedelta(
            milliseconds=current_track["progress_ms"])
        next_change = start_of_track + timedelta(
            milliseconds=current_track["item"]["duration_ms"])

        self.scheduler.add_job(
            update_color_caller,
            "date",
            (),
            id="color_updater",
            run_date=next_change,
            replace_existing=True,
        )