Exemple #1
0
def shuffle(mode, verbose=0, quiet=False, _create_request=False):
    """Turn shuffle on or off."""
    request = {
        'endpoint': ('me/player/shuffle?state={}'.format('true' if mode ==
                                                         'on' else 'false')),
        'method':
        'PUT',
        'handle_errs': {
            404: NoPlaybackError
        },
    }
    if _create_request:
        return request

    Spotify.request(**request)
    if quiet:
        return

    if verbose == 0:
        click.echo('Shuffle turned {}.'.format(mode))
    else:
        from cli.commands.status import status
        status.callback(verbose=verbose,
                        _override={'is_shuffle': mode == 'on'})

    return
Exemple #2
0
def toggle(verbose=0, quiet=False, raw=False):
    """Resume any paused playback, or pause it if already running."""

    res = Spotify.request('me/player', method='GET')
    if not res:
        raise NoPlaybackError

    if res['is_playing']:
        Spotify.request('me/player/pause',
                        method='PUT',
                        ignore_errs=[403],
                        handle_errs={404: NoPlaybackError})
        if not quiet:
            from cli.commands.status import status
            status.callback(verbose=verbose, _override={'is_playing': False})
    else:
        Spotify.request('me/player/play',
                        method='PUT',
                        ignore_errs=[403],
                        handle_errs={404: NoPlaybackError})

        if not quiet:
            from cli.commands.status import status
            status.callback(verbose=verbose, _override={'is_playing': True})

    return
Exemple #3
0
def repeat(mode, verbose=0, quiet=False, _create_request=False):
    """Turn repeat on (all/track) or off."""
    state_map = {'all': 'context', 'track': 'track', 'off': 'off'}
    request = {
        'endpoint': 'me/player/repeat?state={}'.format(state_map[mode]),
        'method': 'PUT',
        'handle_errs': {
            404: NoPlaybackError
        },
    }
    if _create_request:
        return request

    Spotify.request(**request)
    if quiet:
        return

    if verbose == 0:
        if mode == 'off':
            click.echo('Repeat turned off.')
        elif mode == 'track':
            click.echo('Repeat set to current track.')
        elif mode == 'all':
            click.echo('Repeat set to all tracks.')
    else:
        from cli.commands.status import status
        status.callback(verbose=verbose,
                        _override={'is_repeat': mode in ['all', 'track']})

    return
Exemple #4
0
def previous(verbose=0, quiet=False):
    """Play the previous song in the queue."""
    Spotify.request('me/player/previous', method='POST')
    if not quiet:
        from cli.commands.status import status
        status.callback(verbose=verbose)

    return
Exemple #5
0
def _next(verbose=0, quiet=False):
    """Play the next track in the queue."""
    Spotify.request('me/player/next',
                    method='POST',
                    handle_errs={404: NoPlaybackError})
    if not quiet:
        from cli.commands.status import status
        status.callback(verbose=verbose)

    return
Exemple #6
0
def pause(verbose=0, quiet=False):
    """Pause playback."""
    Spotify.request(
        'me/player/pause', method='PUT',
        ignore_errs=[403],
        handle_errs={404: NoPlaybackError}
    )

    if not quiet:
        from cli.commands.status import status
        status.callback(verbose=verbose, _override={'is_playing': False})

    return
Exemple #7
0
def browse(browse_type, verbose=0, quiet=False):
    """Open the current track, album, artist, or playlist in the browser.

    Specify one of the above options to change what to browse (default: track).
    """
    import webbrowser
    from cli.commands.status import status
    playback_data = status.callback(_return_parsed=True)
    music = playback_data['music']

    # parse command and playback context
    if browse_type in ['track', 'album', 'artist']:
        url = music[browse_type]['url']
        name = music[browse_type]['name']
        if browse_type != 'artist':
            name = '"{}" by {}'.format(name, music['artist']['name'])

    elif browse_type == 'playlist':
        # playlist and radio are both type 'playlist'
        if music['context']['type'] != 'playlist':
            click.echo('Error: Current session is not a playlist.', err=True)
            return

        url = music['context']['url']
        id_str = music['context']['id']
        name = Spotify.request('playlists/' + id_str)['name']

    if not quiet:
        click.echo('{} - {}\n' '{}'.format(browse_type.title(), name, url))

    webbrowser.open(url)
    return
Exemple #8
0
def play(verbose=0, quiet=False):
    """Resume playback."""
    try:
        Spotify.request('me/player/play', method='PUT')
    except SpotifyAPIError as e:
        if e.status == 403:
            pass
        else:
            raise e

    if not quiet:
        from cli.commands.status import status
        status.callback(verbose=verbose, override={'is_playing': True})


    return
Exemple #9
0
def volume(to, up, down):
    """Control the active device's volume level."""
    num_options = (bool(up) + bool(down) + bool(to))
    if num_options != 1:
        raise InvalidVolumeInput

    if to:
        new_volume = to
    else:
        from cli.commands.status import status
        raw_status = status.callback(raw=True, verbose=-1)
        current_volume = raw_status['device']['volume_percent']
        new_volume = current_volume + up - down
        if new_volume > 100:
            new_volume = 100
        elif new_volume < 0:
            new_volume = 0

    try:
        Spotify.request(
            'me/player/volume?volume_percent={}'.format(new_volume),
            method='PUT')
    except SpotifyAPIError as e:
        if e.status == 403:
            raise DeviceOperationRestricted
        else:
            raise e

    click.echo('Volume set to {}%'.format(new_volume))
    return
Exemple #10
0
def volume(mode, amount):
    """Control the active device's volume level (0-100).

    Example: spotify volume to 50
    """
    if mode == 'to':
        new_volume = amount
    else:
        from cli.commands.status import status
        device = status.callback(raw=True, verbose=-1).get('device')
        current_volume = device['volume_percent']

        if mode == 'up':
            increment = amount
        elif mode == 'down':
            increment = -amount

        new_volume = current_volume + increment
        if new_volume > 100:
            new_volume = 100
        elif new_volume < 0:
            new_volume = 0

    Spotify.request('me/player/volume?volume_percent={}'.format(new_volume),
                    method='PUT',
                    handle_errs={403: DeviceOperationRestricted})
    click.echo('Volume set to {}%'.format(new_volume))
    return
Exemple #11
0
def queue(keyword, queue_type='track', yes=False, quiet=False):
    """Add a track or album to your queue.

    Example: Use 'spotify queue .' to add the current track.
    """
    keyword = ' '.join(keyword)
    if keyword == '.':
        from cli.commands.status import status
        playback_data = status.callback(_return_parsed=True)
        item = playback_data['music']['track']
    else:
        import urllib.parse as ul
        pager = Spotify.Pager(
            'search',
            params={
                'q': ul.quote_plus(keyword),
                'type': queue_type,
            },
            content_callback=lambda c: c[queue_type + 's'],
        )
        if len(pager.content['items']) == 0:
            click.echo('No results found for "{}"'.format(keywords), err=True)
            return

        item = pager.content['items'][0]

    # parse command and playback context
    display_str = '{} - {}{}'.format(
        cut_string(item['name'], 50),
        cut_string(', '.join(parse_artists(item['artists'])['names']), 30),
        '' if queue_type == 'track' else ' ({} tracks)'.format(
            item['total_tracks']),
    )

    # handle confirmation & request
    if not yes:
        click.confirm(display_str +
                      '\nAdd this {} to the queue?'.format(queue_type),
                      default=True,
                      abort=True)

    if queue_type == 'track':
        uris = [item['uri']]
    else:
        album = Spotify.request('albums/' + item['id'])
        uris = [track['uri'] for track in album['tracks']['items']]

    requests = [{
        'endpoint': 'me/player/queue?uri=' + uri,
        'method': 'POST',
    } for uri in uris]
    Spotify.multirequest(requests, delay_between=0.25)

    # print output
    if not quiet:
        click.echo(queue_type.capitalize() + ' added to queue' +
                   ('.' if not yes else ':\n' + display_str))

    return
Exemple #12
0
def save(keyword, save_type, yes, quiet=False):
    """Save a track, album, artist, or playlist.

    Example: Use 'spotify save .' to save the current track.
    """
    keyword = ' '.join(keyword)
    if keyword == '.':
        from cli.commands.status import status
        playback_data = status.callback(_return_parsed=True)
        music = playback_data['music']
    else:
        import urllib.parse as ul
        pager = Spotify.Pager(
            'search',
            params={
                'q': ul.quote_plus(keyword),
                'type': save_type,
            },
            content_callback=lambda c: c[save_type + 's'],
        )
        if len(pager.content['items']) == 0:
            click.echo('No results found for "{}"'.format(keywords), err=True)
            return

        music = pager.content['items'][0]

    # parse command and playback context
    if keyword == '.' and save_type != 'playlist':
        music = music[save_type]

    if save_type in ['track', 'album']:
        id_str = music['id']
        name = cut_string(music['name'], 50)

    elif save_type == 'artist':
        id_str = music['id']
        name = music['name']

    elif save_type == 'playlist':
        # playlist and radio are both type 'playlist'
        if keyword == '.':
            if music['context']['type'] != 'playlist':
                click.echo('Error: Current session is not a playlist.',
                           err=True)
                return

            id_str = music['context']['id']
            name = Spotify.request('playlists/' + id_str)['name']
        else:
            id_str = music['id']
            name = music['name']

    # format endpoint
    data = None
    if save_type in ['track', 'album']:
        endpoint = 'me/{}s?ids={}'.format(save_type, id_str)
        message = 'Saved {} - {} to library.'.format(save_type, name)

    elif save_type == 'artist':
        endpoint = 'me/following?type=artist&ids={}'.format(id_str)
        message = 'Following {} - {}.'.format(save_type, name)

    elif save_type == 'playlist':
        endpoint = 'playlists/{}/followers'.format(id_str)
        message = 'Following {} - {}.'.format(save_type, name)
        data = {'public': True}

    if not yes:
        click.confirm(name +
                      '\nSave this {} to your library?'.format(save_type),
                      default=True,
                      abort=True)

    Spotify.request(endpoint,
                    method='PUT',
                    data=data,
                    handle_errs={
                        403: (AuthScopeError, {
                            'required_scope_key': 'user-modify'
                        })
                    })
    click.echo(message)
    return
Exemple #13
0
def seek(forward, reverse, position):
    """Seek to time (default unit: seconds) in the current track.

    \b
    Examples:
    spotify seek -f 50        # increment playback position by 50s
    spotify seek -r 1m10s     # decrement playback position by 1m10s
    spotify seek 50%          # set playback position to half the track duration
    spotify seek 2m           # set playback position to 2 minutes into the track
    """
    tokens = [s for s in re.split('(%|ms|m|s)', position) if len(s) > 0]
    relative_factor = 0
    if reverse:
        relative_factor = -1
    if forward:
        relative_factor = 1
    if len(tokens) > 0:
        from cli.commands.status import status
        status_data = status.callback(raw=True, verbose=-1)
        progress_ms = status_data.get('progress_ms')
        duration_ms = status_data.get('item').get('duration_ms')

        expect_unit = False
        new_position_ms = 0

        for t in tokens:
            if not expect_unit:
                try:
                    value = float(t)
                    expect_unit = True
                except:
                    raise InvalidInput(
                        ' Expected number but can\'t convert {} to number.'.
                        format(t))
            else:
                if t == "ms":
                    new_position_ms += int(value)
                elif t == "s":
                    new_position_ms += int(value * 1000)
                elif t == "m":
                    new_position_ms += int(value * 60000)
                elif t == "%":
                    new_position_ms += int((value / 100.0) * duration_ms)
                else:
                    raise InvalidInput(
                        ' Expected unit (m, s, ms or %) but got {}.'.format(t))
                expect_unit = False
                value = None
        if value is not None:
            new_position_ms += int(value * 1000)

        if relative_factor != 0:
            new_position_ms = progress_ms + relative_factor * new_position_ms

        new_position_ms = min(max(0, new_position_ms), duration_ms)

        Spotify.request(
            'me/player/seek?position_ms={}'.format(new_position_ms),
            method='PUT',
            handle_errs={404: NoPlaybackError})

        position_str = ""
        if new_position_ms >= 60000:
            position_str += "{}m".format(new_position_ms // 60000)
        position_str += "{}s".format((new_position_ms // 1000) % 60)
        click.echo('Position set to {}.'.format(position_str))
    return