mirror of
https://github.com/spotipy-dev/spotipy.git
synced 2026-06-19 09:13:53 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
9b8c90dbe1
23
.github/workflows/pythonapp.yml
vendored
Normal file
23
.github/workflows/pythonapp.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: Python application
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Set up Python 3.7
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.7
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
- name: Lint with flake8
|
||||
run: |
|
||||
pip install flake8
|
||||
flake8 . --count --show-source --statistics
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -52,6 +52,5 @@ coverage.xml
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
|
||||
.*
|
||||
archive
|
||||
archive
|
||||
29
.travis.yml
29
.travis.yml
@ -1,29 +0,0 @@
|
||||
language: python
|
||||
|
||||
python:
|
||||
- 2.7
|
||||
- 3.6
|
||||
- 3.5
|
||||
- 3.4
|
||||
- pypy
|
||||
|
||||
install:
|
||||
- pip install coveralls
|
||||
|
||||
script:
|
||||
- python setup.py install
|
||||
- coverage run --include=*spotipy* tests/tests.py
|
||||
- for file in examples/*.py; do python $file; done
|
||||
|
||||
after_success:
|
||||
- coverage report
|
||||
- coveralls
|
||||
- pip install pep8 pyflakes
|
||||
- pep8 *.py tests/*.py
|
||||
- pyflakes *.py tests/*.py
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- python: 3.6
|
||||
- python: 3.5
|
||||
- python: 3.4
|
||||
126
CHANGELOG.md
Normal file
126
CHANGELOG.md
Normal file
@ -0,0 +1,126 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Allow session keepalive
|
||||
- Bump requests to 2.20.0
|
||||
|
||||
## [2.6.1] - 2020-01-13
|
||||
|
||||
### Fixed
|
||||
- Fixed inconsistent behaviour with some API methods when
|
||||
a full HTTP URL is passed.
|
||||
- Fixed invalid calls to logging warn method
|
||||
|
||||
### Removed
|
||||
- `mock` no longer needed for install. Only used in `tox`.
|
||||
|
||||
## [2.6.0] - 2020-01-12
|
||||
|
||||
### Added
|
||||
- Support for `playlist` to get a playlist without specifying a user
|
||||
- Support for `current_user_saved_albums_delete`
|
||||
- Support for `current_user_saved_albums_contains`
|
||||
- Support for `user_unfollow_artists`
|
||||
- Support for `user_unfollow_users`
|
||||
- Lint with flake8 using Github action
|
||||
|
||||
### Changed
|
||||
- Fix typos in doc
|
||||
- Start following [SemVer](https://semver.org) properly
|
||||
|
||||
## [2.5.0] - 2020-01-11
|
||||
Added follow and player endpoints
|
||||
|
||||
## [2.4.4] - 2017-01-04
|
||||
Python 3 fix
|
||||
|
||||
## [2.4.3] - 2017-01-02
|
||||
Fixed proxy issue in standard auth flow
|
||||
|
||||
## [2.4.2] - 2017-01-02
|
||||
Support getting audio features for a single track
|
||||
|
||||
## [2.4.1] - 2017-01-02
|
||||
Incorporated proxy support
|
||||
|
||||
## [2.4.0] - 2016-12-31
|
||||
Incorporated a number of PRs
|
||||
|
||||
## [2.3.8] - 2016-03-31
|
||||
Added recs, audio features, user top lists
|
||||
|
||||
## [2.3.7] - 2015-08-10
|
||||
Added current_user_followed_artists
|
||||
|
||||
## [2.3.6] - 2015-06-03
|
||||
Support for offset/limit with album_tracks API
|
||||
|
||||
## [2.3.5] - 2015-04-28
|
||||
Fixed bug in auto retry logic
|
||||
|
||||
## [2.3.3] - 2015-04-01
|
||||
Aadded client credential flow
|
||||
|
||||
## [2.3.2] - 2015-03-31
|
||||
Added auto retry logic
|
||||
|
||||
## [2.3.0] - 2015-01-05
|
||||
Added session support added by akx.
|
||||
|
||||
## [2.2.0] - 2014-11-15
|
||||
Added support for user_playlist_tracks
|
||||
|
||||
## [2.1.0] - 2014-10-25
|
||||
Added support for new_releases and featured_playlists
|
||||
|
||||
## [2.0.2] - 2014-08-25
|
||||
Moved to spotipy at pypi
|
||||
|
||||
## [1.2.0] - 2014-08-22
|
||||
Upgraded APIs and docs to make it be a real library
|
||||
|
||||
## [1.310.0] - 2014-08-20
|
||||
Added playlist replace and remove methods. Added auth tests. Improved API docs
|
||||
|
||||
## [1.301.0] - 2014-08-19
|
||||
Upgraded version number to take precedence over previously botched release (sigh)
|
||||
|
||||
## [1.50.0] - 2014-08-14
|
||||
Refactored util out of examples and into the main package
|
||||
|
||||
## [1.49.0] - 2014-07-23
|
||||
Support for "Your Music" tracks (add, delete, get), with examples
|
||||
|
||||
## [1.45.0] - 2014-07-07
|
||||
Support for related artists endpoint. Don't use cache auth codes when scope changes
|
||||
|
||||
## [1.44.0] - 2014-07-03
|
||||
Added show tracks.py example
|
||||
|
||||
## [1.43.0] - 2014-06-27
|
||||
Fixed JSON handling issue
|
||||
|
||||
## [1.42.0] - 2014-06-19
|
||||
Removed dependency on simplejson
|
||||
|
||||
## [1.40.0] - 2014-06-12
|
||||
Initial public release.
|
||||
|
||||
## [1.4.2] - 2014-06-21
|
||||
Added support for retrieving starred playlists
|
||||
|
||||
## [1.1.0] - 2014-06-17
|
||||
Updates to match released API
|
||||
|
||||
## [1.1.0] - 2014-05-18
|
||||
Repackaged for saner imports
|
||||
|
||||
## [1.0.0] - 2017-04-05
|
||||
Initial release
|
||||
16
CHANGES.txt
16
CHANGES.txt
@ -1,16 +0,0 @@
|
||||
v1.40, June 12, 2014 -- Initial public release.
|
||||
v1.42, June 19, 2014 -- Removed dependency on simplejson
|
||||
v1.43, June 27, 2014 -- Fixed JSON handling issue
|
||||
v1.44, July 3, 2014 -- Added show_tracks.py exampole
|
||||
v1.45, July 7, 2014 -- Support for related artists endpoint. Don't use
|
||||
cache auth codes when scope changes
|
||||
v1.50, August 14, 2014 -- Refactored util out of examples and into the main
|
||||
package
|
||||
v2.301, August 19, 2014 -- Upgraded version number to take precedence over
|
||||
previously botched release (sigh)
|
||||
v2.310, August 20, 2014 -- Added playlist replace and remove methods. Added auth
|
||||
tests. Improved API docs
|
||||
v2.310, January 5, 2015 -- Added session support
|
||||
v2.3.1, March 28, 2015 -- Auto retry support
|
||||
v2.3.5, April 28, 2015 -- Fixed bug in auto retry support
|
||||
v2.3.6, June 3, 2015 -- Support for offset/limit with album_tracks API
|
||||
43
README.md
43
README.md
@ -1,8 +1,9 @@
|
||||
# Spotipy - a Python client for The Spotify Web API
|
||||
# Spotipy
|
||||
|
||||
## Description
|
||||
##### A light weight Python library for the Spotify Web API
|
||||
|
||||
[](https://spotipy.readthedocs.io/en/latest/?badge=latest)
|
||||
|
||||
Spotipy is a thin client library for the Spotify Web API.
|
||||
|
||||
## Documentation
|
||||
|
||||
@ -43,7 +44,7 @@ sp = spotipy.Spotify()
|
||||
|
||||
results = sp.search(q='weezer', limit=20)
|
||||
for i, t in enumerate(results['tracks']['items']):
|
||||
print ' ', i, t['name']
|
||||
print(' ', i, t['name'])
|
||||
```
|
||||
|
||||
A full set of examples can be found in the [online documentation](http://spotipy.readthedocs.org/) and in the [Spotipy examples directory](https://github.com/plamere/spotipy/tree/master/examples).
|
||||
@ -51,36 +52,4 @@ A full set of examples can be found in the [online documentation](http://spotipy
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
If you have suggestions, bugs or other issues specific to this library, file them [here](https://github.com/plamere/spotipy/issues). Or just send me a pull request.
|
||||
|
||||
## Version
|
||||
|
||||
- 1.0 - 04/05/2014 - Initial release
|
||||
- 1.1 - 05/18/2014 - Repackaged for saner imports
|
||||
- 1.4.1 - 06/17/2014 - Updates to match released API
|
||||
- 1.4.2 - 06/21/2014 - Added support for retrieving starred playlists
|
||||
- v1.40, June 12, 2014 -- Initial public release.
|
||||
- v1.42, June 19, 2014 -- Removed dependency on simplejson
|
||||
- v1.43, June 27, 2014 -- Fixed JSON handling issue
|
||||
- v1.44, July 3, 2014 -- Added show tracks.py example
|
||||
- v1.45, July 7, 2014 -- Support for related artists endpoint. Don't use cache auth codes when scope changes
|
||||
- v1.49, July 23, 2014 -- Support for "Your Music" tracks (add, delete, get), with examples
|
||||
- v1.50, August 14, 2014 -- Refactored util out of examples and into the main package
|
||||
- v1.301, August 19, 2014 -- Upgraded version number to take precedence over previously botched release (sigh)
|
||||
- v1.310, August 20, 2014 -- Added playlist replace and remove methods. Added auth tests. Improved API docs
|
||||
- v2.0 - August 22, 2014 -- Upgraded APIs and docs to make it be a real library
|
||||
- v2.0.2 - August 25, 2014 -- Moved to spotipy at pypi
|
||||
- v2.1.0 - October 25, 2014 -- Added support for new_releases and featured_playlists
|
||||
- v2.2.0 - November 15, 2014 -- Added support for user_playlist_tracks
|
||||
- v2.3.0 - January 5, 2015 -- Added session support added by akx.
|
||||
- v2.3.2 - March 31, 2015 -- Added auto retry logic
|
||||
- v2.3.3 - April 1, 2015 -- added client credential flow
|
||||
- v2.3.5 - April 28, 2015 -- Fixed bug in auto retry logic
|
||||
- v2.3.6 - June 3, 2015 -- Support for offset/limit with album_tracks API
|
||||
- v2.3.7 - August 10, 2015 -- Added current_user_followed_artists
|
||||
- v2.3.8 - March 30, 2016 -- Added recs, audio features, user top lists
|
||||
- v2.4.0 - December 31, 2016 -- Incorporated a number of PRs
|
||||
- v2.4.1 - January 2, 2017 -- Incorporated proxy support
|
||||
- v2.4.2 - January 2, 2017 -- support getting audio features for a single track
|
||||
- v2.4.3 - January 2, 2017 -- fixed proxy issue in standard auth flow
|
||||
- v2.4.4 - January 4, 2017 -- python 3 fix
|
||||
If you have suggestions, bugs or other issues specific to this library, file them [here](https://github.com/plamere/spotipy/issues). Or just send me a pull request.
|
||||
19
deploy
19
deploy
@ -1,19 +0,0 @@
|
||||
#
|
||||
# sudo python setup.py develop --uninstall
|
||||
# sudo python setup.py install
|
||||
|
||||
# How do deploy
|
||||
# - run tests
|
||||
# - push to github
|
||||
# - Adjust version number in setup.py
|
||||
# - Update README.md with updated version info
|
||||
# - leave development mode
|
||||
# sudo python setup.py develop --uninstall
|
||||
# sudo python setup.py install
|
||||
# - upload dist
|
||||
# sudo python setup.py sdist upload
|
||||
# docs should automatically be updated. verify them at
|
||||
# http://spotipy.readthedocs.org/en/latest/
|
||||
|
||||
sudo python setup.py sdist upload
|
||||
|
||||
120
docs/index.rst
120
docs/index.rst
@ -5,7 +5,7 @@ Welcome to Spotipy!
|
||||
===================================
|
||||
*Spotipy* is a lightweight Python library for the `Spotify Web API
|
||||
<https://developer.spotify.com/web-api/>`_. With *Spotipy*
|
||||
you get full access to all of the music data provided by the Spotify platform.
|
||||
you get full access to all of the music data provided by the Spotify platform.
|
||||
|
||||
Here's a quick example of using *Spotipy* to list the names of all the albums
|
||||
released by the artist 'Birdy'::
|
||||
@ -27,6 +27,7 @@ released by the artist 'Birdy'::
|
||||
Here's another example showing how to get 30 second samples and cover art
|
||||
for the top 10 tracks for Led Zeppelin::
|
||||
|
||||
from __future__ import print_function
|
||||
import spotipy
|
||||
|
||||
lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp'
|
||||
@ -35,14 +36,15 @@ for the top 10 tracks for Led Zeppelin::
|
||||
results = spotify.artist_top_tracks(lz_uri)
|
||||
|
||||
for track in results['tracks'][:10]:
|
||||
print 'track : ' + track['name']
|
||||
print 'audio : ' + track['preview_url']
|
||||
print 'cover art: ' + track['album']['images'][0]['url']
|
||||
print
|
||||
print('track : ' + track['name'])
|
||||
print('audio : ' + track['preview_url'])
|
||||
print('cover art: ' + track['album']['images'][0]['url'])
|
||||
print()
|
||||
|
||||
Finally, here's an example that will get the URL for an artist image given the
|
||||
artist's name::
|
||||
|
||||
from __future__ import print_function
|
||||
import spotipy
|
||||
import sys
|
||||
|
||||
@ -57,7 +59,7 @@ artist's name::
|
||||
items = results['artists']['items']
|
||||
if len(items) > 0:
|
||||
artist = items[0]
|
||||
print artist['name'], artist['images'][0]['url']
|
||||
print(artist['name'], artist['images'][0]['url'])
|
||||
|
||||
|
||||
Features
|
||||
@ -87,10 +89,11 @@ Non-Authorized requests
|
||||
For methods that do not require authorization, simply create a Spotify object
|
||||
and start making method calls like so::
|
||||
|
||||
from __future__ import print_function
|
||||
import spotipy
|
||||
spotify = spotipy.Spotify()
|
||||
results = spotify.search(q='artist:' + name, type='artist')
|
||||
print results
|
||||
print(results)
|
||||
|
||||
Authorized requests
|
||||
=======================
|
||||
@ -99,21 +102,23 @@ generate an authorization token that indicates that the user has granted
|
||||
permission for your application to perform the given task. You will need to
|
||||
register your app to get the credentials necessary to make authorized calls.
|
||||
|
||||
Even if your script does not have an accessible URL you need to specify one
|
||||
when registering your application where the spotify authentication API will
|
||||
redirect to after successful login. The URL doesn't need to work or be
|
||||
accessible, you can specify "http://localhost/", after successful login you
|
||||
just need to copy the "http://localhost/?code=..." URL from your browser
|
||||
and paste it to the console where your script is running.
|
||||
Even if your script does not have an accessible URL you will need to specify one
|
||||
when registering your application which the Spotify authentication server will
|
||||
redirect to after successful login. The URL doesn't need to be publicly
|
||||
accessible, so you can specify "http://localhost/", and after succesfully
|
||||
authenticating your app, you can simply copy the
|
||||
"http://localhost/?code=..." URL from your browser and paste it to the
|
||||
console where your script is running.
|
||||
|
||||
Register your app at
|
||||
Register your app at
|
||||
`My Applications
|
||||
<https://developer.spotify.com/my-applications/#!/applications>`_.
|
||||
<https://developer.spotify.com/my-applications/#!/applications>`_ and register the
|
||||
redirect URI mentioned in the above paragragh.
|
||||
|
||||
|
||||
*spotipy* supports two authorization flows:
|
||||
|
||||
- The **Authorization Code flow** This method is suitable for long-running applications
|
||||
- The **Authorization Code flow** This method is suitable for long-running applications
|
||||
which the user logs into once. It provides an access token that can be refreshed.
|
||||
|
||||
- The **Client Credentials flow** The method makes it possible
|
||||
@ -127,25 +132,26 @@ To support the **Authorization Code Flow** *Spotipy* provides a
|
||||
utility method ``util.prompt_for_user_token`` that will attempt to authorize the
|
||||
user. You can pass your app credentials directly into the method as arguments::
|
||||
|
||||
util.prompt_for_user_token(username,scope,client_id='your-app-redirect-url',client_secret='your-app-redirect-url',redirect_uri='your-app-redirect-url')
|
||||
util.prompt_for_user_token(username,scope,client_id='your-spotify-client-id',client_secret='your-spotify-client-secret',redirect_uri='your-app-redirect-url')
|
||||
|
||||
or if you are reluctant to immortalize your app credentials in your source code,
|
||||
or if you are reluctant to immortalize your app credentials in your source code,
|
||||
you can set environment variables like so::
|
||||
|
||||
export SPOTIPY_CLIENT_ID='your-spotify-client-id'
|
||||
export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret'
|
||||
export SPOTIPY_REDIRECT_URI='your-app-redirect-url'
|
||||
|
||||
Call ``util.prompt_for_user_token`` method with the username and the
|
||||
Call ``util.prompt_for_user_token`` method with the username and the
|
||||
desired scope (see `Using
|
||||
Scopes <https://developer.spotify.com/web-api/using-scopes/>`_ for information
|
||||
about scopes) and credentials. This will coordinate the user authorization via
|
||||
your web browser and ask for the SPOTIPY_REDIRECT_URI you were redirected to
|
||||
your web browser and callback to the SPOTIPY_REDIRECT_URI you were redirected to
|
||||
with the authorization token appended. The credentials are cached locally and
|
||||
are used to automatically re-authorized expired tokens.
|
||||
|
||||
Here's an example of getting user authorization to read a user's saved tracks::
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import spotipy
|
||||
import spotipy.util as util
|
||||
@ -155,7 +161,7 @@ Here's an example of getting user authorization to read a user's saved tracks::
|
||||
if len(sys.argv) > 1:
|
||||
username = sys.argv[1]
|
||||
else:
|
||||
print "Usage: %s username" % (sys.argv[0],)
|
||||
print("Usage: %s username" % (sys.argv[0],))
|
||||
sys.exit()
|
||||
|
||||
token = util.prompt_for_user_token(username, scope)
|
||||
@ -165,9 +171,9 @@ Here's an example of getting user authorization to read a user's saved tracks::
|
||||
results = sp.current_user_saved_tracks()
|
||||
for item in results['items']:
|
||||
track = item['track']
|
||||
print track['name'] + ' - ' + track['artists'][0]['name']
|
||||
print(track['name'] + ' - ' + track['artists'][0]['name'])
|
||||
else:
|
||||
print "Can't get token for", username
|
||||
print("Can't get token for", username)
|
||||
|
||||
Client Credentials Flow
|
||||
=======================
|
||||
@ -191,8 +197,8 @@ class SpotifyClientCredentials that can be used to authenticate requests like so
|
||||
playlists = None
|
||||
|
||||
Client credentials flow is appropriate for requests that do not require access to a
|
||||
user's private data. Even if you are only making calls that do not require
|
||||
authorization, using this flow yields the benefit of a higher rate limit
|
||||
user's private data. Even if you are only making calls that do not require
|
||||
authorization, using this flow yields the benefit of a higher rate limit
|
||||
|
||||
IDs URIs and URLs
|
||||
=======================
|
||||
@ -217,6 +223,7 @@ Here are a few more examples of using *Spotipy*.
|
||||
|
||||
Add tracks to a playlist::
|
||||
|
||||
from __future__ import print_function
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
@ -228,7 +235,7 @@ Add tracks to a playlist::
|
||||
playlist_id = sys.argv[2]
|
||||
track_ids = sys.argv[3:]
|
||||
else:
|
||||
print "Usage: %s username playlist_id track_id ..." % (sys.argv[0],)
|
||||
print("Usage: %s username playlist_id track_id ..." % (sys.argv[0],))
|
||||
sys.exit()
|
||||
|
||||
scope = 'playlist-modify-public'
|
||||
@ -238,15 +245,16 @@ Add tracks to a playlist::
|
||||
sp = spotipy.Spotify(auth=token)
|
||||
sp.trace = False
|
||||
results = sp.user_playlist_add_tracks(username, playlist_id, track_ids)
|
||||
print results
|
||||
print(results)
|
||||
else:
|
||||
print "Can't get token for", username
|
||||
print("Can't get token for", username)
|
||||
|
||||
|
||||
Shows the contents of every playlist owned by a user::
|
||||
|
||||
# shows a user's playlists (need to be authenticated via oauth)
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import spotipy
|
||||
import spotipy.util as util
|
||||
@ -254,16 +262,16 @@ Shows the contents of every playlist owned by a user::
|
||||
def show_tracks(tracks):
|
||||
for i, item in enumerate(tracks['items']):
|
||||
track = item['track']
|
||||
print " %d %32.32s %s" % (i, track['artists'][0]['name'],
|
||||
track['name'])
|
||||
print(" %d %32.32s %s" % (i, track['artists'][0]['name'],
|
||||
track['name']))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 1:
|
||||
username = sys.argv[1]
|
||||
else:
|
||||
print "Whoops, need your username!"
|
||||
print "usage: python user_playlists.py [username]"
|
||||
print("Whoops, need your username!")
|
||||
print("usage: python user_playlists.py [username]")
|
||||
sys.exit()
|
||||
|
||||
token = util.prompt_for_user_token(username)
|
||||
@ -273,10 +281,10 @@ Shows the contents of every playlist owned by a user::
|
||||
playlists = sp.user_playlists(username)
|
||||
for playlist in playlists['items']:
|
||||
if playlist['owner']['id'] == username:
|
||||
print
|
||||
print playlist['name']
|
||||
print ' total tracks', playlist['tracks']['total']
|
||||
results = sp.user_playlist(username, playlist['id'],
|
||||
print()
|
||||
print(playlist['name'])
|
||||
print (' total tracks', playlist['tracks']['total'])
|
||||
results = sp.user_playlist(username, playlist['id'],
|
||||
fields="tracks,next")
|
||||
tracks = results['tracks']
|
||||
show_tracks(tracks)
|
||||
@ -284,7 +292,7 @@ Shows the contents of every playlist owned by a user::
|
||||
tracks = sp.next(tracks)
|
||||
show_tracks(tracks)
|
||||
else:
|
||||
print "Can't get token for", username
|
||||
print("Can't get token for", username)
|
||||
|
||||
|
||||
More Examples
|
||||
@ -292,7 +300,7 @@ More Examples
|
||||
There are many more examples of how to use *Spotipy* in the `Examples
|
||||
Directory <https://github.com/plamere/spotipy/tree/master/examples>`_ on Github
|
||||
|
||||
API Reference
|
||||
API Reference
|
||||
==============
|
||||
|
||||
:mod:`client` Module
|
||||
@ -330,7 +338,7 @@ You can ask questions about Spotipy on Stack Overflow. Don’t forget to add t
|
||||
|
||||
http://stackoverflow.com/questions/ask
|
||||
|
||||
If you think you've found a bug, let us know at
|
||||
If you think you've found a bug, let us know at
|
||||
`Spotify Issues <https://github.com/plamere/spotipy/issues>`_
|
||||
|
||||
|
||||
@ -338,28 +346,30 @@ Contribute
|
||||
==========
|
||||
Spotipy authored by Paul Lamere (plamere) with contributions by:
|
||||
|
||||
- Daniel Beaudry // danbeaudry
|
||||
- Faruk Emre Sahin // fsahin
|
||||
- George // rogueleaderr
|
||||
- Henry Greville // sethaurus
|
||||
- Hugo // hugovk
|
||||
- José Manuel Pérez // JMPerez
|
||||
- Lucas Nunno // lnunno
|
||||
- Lynn Root // econchick
|
||||
- Matt Dennewitz // mattdennewitz
|
||||
- Matthew Duck // mattduck
|
||||
- Michael Thelin // thelinmichael
|
||||
- Ryan Choi // ryankicks
|
||||
- Simon Metson // drsm79
|
||||
- Daniel Beaudry // danbeaudry
|
||||
- Faruk Emre Sahin // fsahin
|
||||
- George // rogueleaderr
|
||||
- Henry Greville // sethaurus
|
||||
- Hugo // hugovk
|
||||
- José Manuel Pérez // JMPerez
|
||||
- Lucas Nunno // lnunno
|
||||
- Lynn Root // econchick
|
||||
- Matt Dennewitz // mattdennewitz
|
||||
- Matthew Duck // mattduck
|
||||
- Michael Thelin // thelinmichael
|
||||
- Ryan Choi // ryankicks
|
||||
- Simon Metson // drsm79
|
||||
- Steve Winton // swinton
|
||||
- Tim Balzer // timbalzer
|
||||
- corycorycory // corycorycory
|
||||
- Tim Balzer // timbalzer
|
||||
- corycorycory // corycorycory
|
||||
- Nathan Coleman // nathancoleman
|
||||
- Michael Birtwell // mbirtwell
|
||||
- Harrison Hayes // Harrison97
|
||||
- Stephane Bruckert // stephanebruckert
|
||||
|
||||
License
|
||||
=======
|
||||
https://github.com/plamere/spotipy/blob/master/LICENSE.txt
|
||||
https://github.com/plamere/spotipy/blob/master/LICENSE.md
|
||||
|
||||
|
||||
Indices and tables
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
|
||||
# Adds tracks to a playlist
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
import spotipy
|
||||
|
||||
@ -5,6 +5,7 @@ import spotipy
|
||||
''' shows the albums and tracks for a given artist.
|
||||
'''
|
||||
|
||||
|
||||
def get_artist(name):
|
||||
results = sp.search(q='artist:' + name, type='artist')
|
||||
items = results['artists']['items']
|
||||
@ -13,6 +14,7 @@ def get_artist(name):
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def show_artist_albums(artist):
|
||||
albums = []
|
||||
results = sp.artist_albums(artist['id'], album_type='album')
|
||||
@ -20,14 +22,15 @@ def show_artist_albums(artist):
|
||||
while results['next']:
|
||||
results = sp.next(results)
|
||||
albums.extend(results['items'])
|
||||
seen = set() # to avoid dups
|
||||
albums.sort(key=lambda album:album['name'].lower())
|
||||
seen = set() # to avoid dups
|
||||
albums.sort(key=lambda album: album['name'].lower())
|
||||
for album in albums:
|
||||
name = album['name']
|
||||
if name not in seen:
|
||||
print((' ' + name))
|
||||
seen.add(name)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
|
||||
@ -5,6 +5,7 @@ import spotipy
|
||||
''' shows the albums and tracks for a given artist.
|
||||
'''
|
||||
|
||||
|
||||
def get_artist(name):
|
||||
results = sp.search(q='artist:' + name, type='artist')
|
||||
items = results['artists']['items']
|
||||
@ -13,6 +14,7 @@ def get_artist(name):
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def show_album_tracks(album):
|
||||
tracks = []
|
||||
results = sp.album_tracks(album['id'])
|
||||
@ -25,6 +27,7 @@ def show_album_tracks(album):
|
||||
print()
|
||||
print(track)
|
||||
|
||||
|
||||
def show_artist_albums(id):
|
||||
albums = []
|
||||
results = sp.artist_albums(artist['id'], album_type='album')
|
||||
@ -36,17 +39,19 @@ def show_artist_albums(id):
|
||||
unique = set() # skip duplicate albums
|
||||
for album in albums:
|
||||
name = album['name'].lower()
|
||||
if not name in unique:
|
||||
if name not in unique:
|
||||
print(name)
|
||||
unique.add(name)
|
||||
show_album_tracks(album)
|
||||
|
||||
|
||||
def show_artist(artist):
|
||||
print('====', artist['name'], '====')
|
||||
print('Popularity: ', artist['popularity'])
|
||||
if len(artist['genres']) > 0:
|
||||
print('Genres: ', ','.join(artist['genres']))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
|
||||
@ -7,7 +7,8 @@ import spotipy
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
sp.trace=False
|
||||
sp.trace = False
|
||||
|
||||
|
||||
def get_artist(name):
|
||||
results = sp.search(q='artist:' + name, type='artist')
|
||||
@ -17,11 +18,12 @@ def get_artist(name):
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def show_recommendations_for_artist(artist):
|
||||
albums = []
|
||||
results = sp.recommendations(seed_artists = [artist['id']])
|
||||
results = sp.recommendations(seed_artists=[artist['id']])
|
||||
for track in results['tracks']:
|
||||
print track['name'], '-', track['artists'][0]['name']
|
||||
print(track['name'], '-', track['artists'][0]['name'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
@ -32,4 +34,4 @@ if __name__ == '__main__':
|
||||
if artist:
|
||||
show_recommendations_for_artist(artist)
|
||||
else:
|
||||
print "Can't find that artist", name
|
||||
print("Can't find that artist", name)
|
||||
|
||||
@ -20,4 +20,4 @@ start = time.time()
|
||||
analysis = sp.audio_analysis(tid)
|
||||
delta = time.time() - start
|
||||
print(json.dumps(analysis, indent=4))
|
||||
print ("analysis retrieved in %.2f seconds" % (delta,))
|
||||
print("analysis retrieved in %.2f seconds" % (delta,))
|
||||
|
||||
@ -11,7 +11,7 @@ import sys
|
||||
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
sp.trace=False
|
||||
sp.trace = False
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
artist_name = ' '.join(sys.argv[1:])
|
||||
@ -33,4 +33,4 @@ for feature in features:
|
||||
analysis = sp._get(feature['analysis_url'])
|
||||
print(json.dumps(analysis, indent=4))
|
||||
print()
|
||||
print ("features retrieved in %.2f seconds" % (delta,))
|
||||
print("features retrieved in %.2f seconds" % (delta,))
|
||||
|
||||
@ -12,7 +12,7 @@ import sys
|
||||
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
sp.trace=True
|
||||
sp.trace = True
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
tids = sys.argv[1:]
|
||||
@ -22,4 +22,4 @@ if len(sys.argv) > 1:
|
||||
features = sp.audio_features(tids)
|
||||
delta = time.time() - start
|
||||
print(json.dumps(features, indent=4))
|
||||
print ("features retrieved in %.2f seconds" % (delta,))
|
||||
print("features retrieved in %.2f seconds" % (delta,))
|
||||
|
||||
@ -24,8 +24,8 @@ if len(sys.argv) > 3:
|
||||
description = sys.argv[6]
|
||||
|
||||
else:
|
||||
print ("Usage: %s username playlist_id name [public collaborative "
|
||||
"description]" % (sys.argv[0]))
|
||||
print("Usage: %s username playlist_id name [public collaborative "
|
||||
"description]" % (sys.argv[0]))
|
||||
sys.exit()
|
||||
|
||||
scope = 'playlist-modify-public playlist-modify-private'
|
||||
@ -37,6 +37,6 @@ if token:
|
||||
results = sp.user_playlist_change_details(
|
||||
username, playlist_id, name=name, public=public,
|
||||
collaborative=collaborative, description=description)
|
||||
print results
|
||||
print(results)
|
||||
else:
|
||||
print "Can't get token for", username
|
||||
print("Can't get token for"), username
|
||||
|
||||
@ -10,7 +10,7 @@ if len(sys.argv) > 2:
|
||||
username = sys.argv[1]
|
||||
tids = sys.argv[2:]
|
||||
else:
|
||||
print("Usage: %s username track-id ..." % (sys.argv[0],))
|
||||
print("Usage: %s username track-id ..." % (sys.argv[0],))
|
||||
sys.exit()
|
||||
|
||||
token = util.prompt_for_user_token(username, scope)
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import spotipy
|
||||
import spotipy.util as util
|
||||
@ -14,16 +12,19 @@ if len(sys.argv) > 2:
|
||||
playlist_name = sys.argv[2]
|
||||
playlist_description = sys.argv[3]
|
||||
else:
|
||||
print("Usage: %s username playlist-name playlist-description" % (sys.argv[0],))
|
||||
print(
|
||||
"Usage: %s username playlist-name playlist-description" %
|
||||
(sys.argv[0],))
|
||||
sys.exit()
|
||||
|
||||
token = util.prompt_for_user_token(username)
|
||||
scope = "playlist-modify-public"
|
||||
token = util.prompt_for_user_token(username, scope)
|
||||
|
||||
if token:
|
||||
sp = spotipy.Spotify(auth=token)
|
||||
sp.trace = False
|
||||
playlists = sp.user_playlist_create(username, playlist_name,
|
||||
playlist_description)
|
||||
description=playlist_description)
|
||||
pprint.pprint(playlists)
|
||||
else:
|
||||
print("Can't get token for", username)
|
||||
|
||||
@ -2,22 +2,18 @@
|
||||
|
||||
from __future__ import print_function # (at top of module)
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import json
|
||||
import spotipy
|
||||
import time
|
||||
import sys
|
||||
|
||||
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
sp.trace=True
|
||||
sp.trace = True
|
||||
try:
|
||||
print ('bad call 0')
|
||||
print('bad call 0')
|
||||
bad_artist_call = sp.artist('spotify:artist:12341234')
|
||||
except spotipy.client.SpotifyException:
|
||||
print ('bad call 0 exception' )
|
||||
print('bad call 0 exception')
|
||||
|
||||
print ('bad call 1')
|
||||
print('bad call 1')
|
||||
bad_artist_call = sp.artist('spotify:artist:12341234')
|
||||
print ('bad artist', bad_artist_call)
|
||||
|
||||
print('bad artist', bad_artist_call)
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
# Shows the top artists for a user
|
||||
# Shows a user's playlists
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
import spotipy
|
||||
import spotipy.util as util
|
||||
import simplejson as json
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
username = sys.argv[1]
|
||||
@ -21,6 +19,6 @@ if token:
|
||||
sp.trace = False
|
||||
results = sp.current_user_playlists(limit=50)
|
||||
for i, item in enumerate(results['items']):
|
||||
print("%d %s" %(i, item['name']))
|
||||
print("%d %s" % (i, item['name']))
|
||||
else:
|
||||
print("Can't get token for", username)
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
# Shows the top artists for a user
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
import spotipy
|
||||
import spotipy.util as util
|
||||
import simplejson as json
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
username = sys.argv[1]
|
||||
@ -21,10 +19,10 @@ if token:
|
||||
sp.trace = False
|
||||
ranges = ['short_term', 'medium_term', 'long_term']
|
||||
for range in ranges:
|
||||
print "range:", range
|
||||
print("range:", range)
|
||||
results = sp.current_user_top_artists(time_range=range, limit=50)
|
||||
for i, item in enumerate(results['items']):
|
||||
print i, item['name']
|
||||
print
|
||||
print(i, item['name'])
|
||||
print()
|
||||
else:
|
||||
print("Can't get token for", username)
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
# Adds tracks to a playlist
|
||||
# Shows the top tracks for a user
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
|
||||
import spotipy
|
||||
import spotipy.util as util
|
||||
import simplejson as json
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
username = sys.argv[1]
|
||||
@ -21,11 +19,11 @@ if token:
|
||||
sp.trace = False
|
||||
ranges = ['short_term', 'medium_term', 'long_term']
|
||||
for range in ranges:
|
||||
print "range:", range
|
||||
print("range:", range)
|
||||
results = sp.current_user_top_tracks(time_range=range, limit=50)
|
||||
for i, item in enumerate(results['items']):
|
||||
print i, item['name'], '//', item['artists'][0]['name']
|
||||
print
|
||||
|
||||
print(i, item['name'], '//', item['artists'][0]['name'])
|
||||
print()
|
||||
|
||||
else:
|
||||
print("Can't get token for", username)
|
||||
|
||||
@ -10,4 +10,4 @@ username = uri.split(':')[2]
|
||||
playlist_id = uri.split(':')[4]
|
||||
|
||||
results = sp.user_playlist(username, playlist_id)
|
||||
print json.dumps(results, indent=4)
|
||||
print(json.dumps(results, indent=4))
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
|
||||
# Adds tracks to a playlist
|
||||
# removes tracks from a playlist
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
@ -11,12 +10,14 @@ if len(sys.argv) > 3:
|
||||
username = sys.argv[1]
|
||||
playlist_id = sys.argv[2]
|
||||
track_ids_and_positions = sys.argv[3:]
|
||||
track_ids = [ ]
|
||||
track_ids = []
|
||||
for t_pos in sys.argv[3:]:
|
||||
tid, pos = t_pos.split(',')
|
||||
track_ids.append( { "uri" : tid, "positions": [ int(pos)] } )
|
||||
track_ids.append({"uri": tid, "positions": [int(pos)]})
|
||||
else:
|
||||
print("Usage: %s username playlist_id track_id,pos track_id,pos ..." % (sys.argv[0],))
|
||||
print(
|
||||
"Usage: %s username playlist_id track_id,pos track_id,pos ..." %
|
||||
(sys.argv[0],))
|
||||
sys.exit()
|
||||
|
||||
scope = 'playlist-modify-public'
|
||||
@ -25,7 +26,8 @@ token = util.prompt_for_user_token(username, scope)
|
||||
if token:
|
||||
sp = spotipy.Spotify(auth=token)
|
||||
sp.trace = False
|
||||
results = sp.user_playlist_remove_specific_occurrences_of_tracks(username, playlist_id, track_ids)
|
||||
results = sp.user_playlist_remove_specific_occurrences_of_tracks(
|
||||
username, playlist_id, track_ids)
|
||||
pprint.pprint(results)
|
||||
else:
|
||||
print("Can't get token for", username)
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
|
||||
# Adds tracks to a playlist
|
||||
# removes tracks to a playlist
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
@ -21,7 +20,8 @@ token = util.prompt_for_user_token(username, scope)
|
||||
if token:
|
||||
sp = spotipy.Spotify(auth=token)
|
||||
sp.trace = False
|
||||
results = sp.user_playlist_remove_all_occurrences_of_tracks(username, playlist_id, track_ids)
|
||||
results = sp.user_playlist_remove_all_occurrences_of_tracks(
|
||||
username, playlist_id, track_ids)
|
||||
pprint.pprint(results)
|
||||
else:
|
||||
print("Can't get token for", username)
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
# Replaces all tracks in a playlist
|
||||
|
||||
import pprint
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import spotipy
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import sys
|
||||
import pprint
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import spotipy
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import sys
|
||||
import pprint
|
||||
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import spotipy
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import sys
|
||||
import pprint
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
urn = sys.argv[1]
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
import spotipy
|
||||
import sys
|
||||
import pprint
|
||||
import spotipy.util as util
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
import spotipy
|
||||
import sys
|
||||
import pprint
|
||||
import spotipy.util as util
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
@ -22,7 +21,7 @@ if token:
|
||||
while response:
|
||||
albums = response['albums']
|
||||
for i, item in enumerate(albums['items']):
|
||||
print(albums['offset'] + i,item['name'])
|
||||
print(albums['offset'] + i, item['name'])
|
||||
|
||||
if albums['next']:
|
||||
response = sp.next(albums)
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import spotipy
|
||||
import sys
|
||||
import pprint
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
artist_name = sys.argv[1]
|
||||
@ -22,6 +21,5 @@ try:
|
||||
print('Related artists for', name)
|
||||
for artist in related['artists']:
|
||||
print(' ', artist['name'])
|
||||
except:
|
||||
except BaseException:
|
||||
print("usage show_related.py [artist-name]")
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import spotipy
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import sys
|
||||
import pprint
|
||||
|
||||
|
||||
@ -21,6 +21,3 @@ if __name__ == '__main__':
|
||||
results = sp.tracks(tids[start: start + max_tracks_per_call])
|
||||
for track in results['tracks']:
|
||||
print(track['name'] + ' - ' + track['artists'][0]['name'])
|
||||
|
||||
|
||||
|
||||
|
||||
@ -16,4 +16,3 @@ sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
sp.trace = True
|
||||
user = sp.user(username)
|
||||
pprint.pprint(user)
|
||||
|
||||
|
||||
@ -1,18 +1,16 @@
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import spotipy
|
||||
|
||||
|
||||
birdy_uri = 'spotify:artist:2WX2uTcsvV5OnS0inACecP'
|
||||
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
|
||||
results = spotify.artist_albums(birdy_uri, album_type='album')
|
||||
results = sp.artist_albums(birdy_uri, album_type='album')
|
||||
albums = results['items']
|
||||
while results['next']:
|
||||
results = spotify.next(results)
|
||||
results = sp.next(results)
|
||||
albums.extend(results['items'])
|
||||
|
||||
for album in albums:
|
||||
print((album['name']))
|
||||
|
||||
|
||||
@ -2,13 +2,12 @@
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import spotipy
|
||||
|
||||
|
||||
lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp'
|
||||
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
|
||||
results = spotify.artist_top_tracks(lz_uri)
|
||||
results = sp.artist_top_tracks(lz_uri)
|
||||
|
||||
for track in results['tracks'][:10]:
|
||||
print('track : ' + track['name'])
|
||||
|
||||
@ -1,18 +1,16 @@
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import spotipy
|
||||
import sys
|
||||
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
name = ' '.join(sys.argv[1:])
|
||||
else:
|
||||
name = 'Radiohead'
|
||||
|
||||
results = spotify.search(q='artist:' + name, type='artist')
|
||||
results = sp.search(q='artist:' + name, type='artist')
|
||||
items = results['artists']['items']
|
||||
if len(items) > 0:
|
||||
artist = items[0]
|
||||
print(artist['name'], artist['images'][0]['url'])
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import spotipy
|
||||
import random
|
||||
import simplejson as json
|
||||
|
||||
'''
|
||||
generates a list of songs where the first word in each subsequent song
|
||||
@ -18,14 +17,15 @@ skiplist = set(['dm', 'remix'])
|
||||
max_offset = 500
|
||||
seen = set()
|
||||
|
||||
|
||||
def find_songs_that_start_with_word(word):
|
||||
max_titles = 20
|
||||
max_offset = 200
|
||||
offset = 0
|
||||
|
||||
out = []
|
||||
while offset < max_offset and len(out) < max_titles:
|
||||
results = sp.search(q=word, type = 'track', limit=50, offset = offset)
|
||||
while offset < max_offset and len(out) < max_titles:
|
||||
results = sp.search(q=word, type='track', limit=50, offset=offset)
|
||||
if len(results['tracks']['items']) == 0:
|
||||
break
|
||||
|
||||
@ -41,27 +41,29 @@ def find_songs_that_start_with_word(word):
|
||||
if '/' in name:
|
||||
continue
|
||||
words = name.split()
|
||||
if len(words) > 1 and words[0] == word and words[-1] not in skiplist:
|
||||
#print " ", name, len(out)
|
||||
if len(words) > 1 and words[0] == word \
|
||||
and words[-1] not in skiplist:
|
||||
# print " ", name, len(out)
|
||||
out.append(item)
|
||||
offset += 50
|
||||
#print "found", len(out), "matches"
|
||||
# print "found", len(out), "matches"
|
||||
return out
|
||||
|
||||
|
||||
def make_chain(word):
|
||||
which = 1
|
||||
while True:
|
||||
songs = find_songs_that_start_with_word(word)
|
||||
if len(songs) > 0:
|
||||
song = random.choice(songs)
|
||||
print which, song['name'] + " by " + song['artists'][0]['name']
|
||||
print(which, song['name'] + " by " + song['artists'][0]['name'])
|
||||
which += 1
|
||||
word = song['name'].lower().split()[-1]
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
title = ' '.join(sys.argv[1:])
|
||||
make_chain(sys.argv[1].lower())
|
||||
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
# shows a user's playlists (need to be authenticated via oauth)
|
||||
|
||||
import pprint
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import spotipy
|
||||
|
||||
|
||||
@ -4,10 +4,13 @@ import sys
|
||||
import spotipy
|
||||
import spotipy.util as util
|
||||
|
||||
|
||||
def show_tracks(results):
|
||||
for i, item in enumerate(results['items']):
|
||||
track = item['track']
|
||||
print(" %d %32.32s %s" % (i, track['artists'][0]['name'], track['name']))
|
||||
print(
|
||||
" %d %32.32s %s" %
|
||||
(i, track['artists'][0]['name'], track['name']))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
@ -28,7 +31,8 @@ if __name__ == '__main__':
|
||||
print()
|
||||
print(playlist['name'])
|
||||
print(' total tracks', playlist['tracks']['total'])
|
||||
results = sp.user_playlist(username, playlist['id'], fields="tracks,next")
|
||||
results = sp.user_playlist(
|
||||
username, playlist['id'], fields="tracks,next")
|
||||
tracks = results['tracks']
|
||||
show_tracks(tracks)
|
||||
while tracks['next']:
|
||||
@ -36,4 +40,3 @@ if __name__ == '__main__':
|
||||
show_tracks(tracks)
|
||||
else:
|
||||
print("Can't get token for", username)
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Gets all the public playlists for the given
|
||||
# user. Uses Client Credentials flow
|
||||
#
|
||||
#
|
||||
|
||||
import sys
|
||||
import spotipy
|
||||
@ -18,7 +18,13 @@ playlists = sp.user_playlists(user)
|
||||
|
||||
while playlists:
|
||||
for i, playlist in enumerate(playlists['items']):
|
||||
print("%4d %s %s" % (i + 1 + playlists['offset'], playlist['uri'], playlist['name']))
|
||||
print(
|
||||
"%4d %s %s" %
|
||||
(i +
|
||||
1 +
|
||||
playlists['offset'],
|
||||
playlist['uri'],
|
||||
playlist['name']))
|
||||
if playlists['next']:
|
||||
playlists = sp.next(playlists)
|
||||
else:
|
||||
|
||||
28
examples/user_saved_albums_delete.py
Normal file
28
examples/user_saved_albums_delete.py
Normal file
@ -0,0 +1,28 @@
|
||||
"""
|
||||
Deletes user saved album
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import spotipy
|
||||
import spotipy.util as util
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
username = sys.argv[1]
|
||||
else:
|
||||
print("Usage: %s username" % (sys.argv[0],))
|
||||
sys.exit()
|
||||
|
||||
scope = 'user-library-modify'
|
||||
token = util.prompt_for_user_token(username, scope)
|
||||
|
||||
if token:
|
||||
sp = spotipy.Spotify(auth=token)
|
||||
sp.trace = False
|
||||
uris = input("input a list of album URIs, URLs or IDs: ")
|
||||
uris = list(map(str, uris.split()))
|
||||
deleted = sp.current_user_saved_albums_delete(uris)
|
||||
print("Deletion successful.")
|
||||
|
||||
else:
|
||||
print("Can't get token for", username)
|
||||
@ -5,7 +5,6 @@ import spotipy
|
||||
import spotipy.util as util
|
||||
|
||||
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
username = sys.argv[1]
|
||||
else:
|
||||
@ -23,7 +22,7 @@ if token:
|
||||
while tracks:
|
||||
for item in tracks['items']:
|
||||
track = item['track']
|
||||
print(which, track['name' ], ' --', track['artists'][0]['name'])
|
||||
print(which, track['name'], ' --', track['artists'][0]['name'])
|
||||
which += 1
|
||||
tracks = sp.next(tracks)
|
||||
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
Spotipy Authorization Page
|
||||
===========================
|
||||
|
||||
If you are here, you are probably running a Spotipy test app that has been asked to authenticate the user.
|
||||
Now you just need to cut/paste the URL into the terminal at the prompt asking:
|
||||
|
||||
Enter the URL you were redirected to:
|
||||
|
||||
|
||||
And you should be good to go
|
||||
@ -1,2 +1,3 @@
|
||||
requests==2.3.0
|
||||
mock==2.0.0
|
||||
requests==2.20.0
|
||||
six==1.10.0
|
||||
11
setup.py
11
setup.py
@ -1,15 +1,18 @@
|
||||
from setuptools import setup
|
||||
|
||||
desc = """### A light weight Python library for the Spotify Web API"""
|
||||
|
||||
setup(
|
||||
name='spotipy',
|
||||
version='2.4.4',
|
||||
description='simple client for the Spotify Web API',
|
||||
version='2.6.1',
|
||||
long_description=desc,
|
||||
long_description_content_type='text/markdown',
|
||||
author="@plamere",
|
||||
author_email="paul@echonest.com",
|
||||
url='http://spotipy.readthedocs.org/',
|
||||
install_requires=[
|
||||
'requests>=2.3.0',
|
||||
'requests>=2.20.0',
|
||||
'six>=1.10.0',
|
||||
],
|
||||
license='LICENSE.txt',
|
||||
license='LICENSE.md',
|
||||
packages=['spotipy'])
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
VERSION='2.0.1'
|
||||
from .client import Spotify, SpotifyException
|
||||
from .client import * # noqa
|
||||
from .oauth2 import * # noqa
|
||||
from .util import * # noqa
|
||||
|
||||
@ -1,17 +1,21 @@
|
||||
# coding: utf-8
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
""" A simple and thin Python library for the Spotify Web API """
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import requests
|
||||
|
||||
__all__ = [
|
||||
'Spotify',
|
||||
'SpotifyException'
|
||||
]
|
||||
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
|
||||
import requests
|
||||
import six
|
||||
|
||||
""" A simple and thin Python library for the Spotify Web API
|
||||
"""
|
||||
|
||||
|
||||
class SpotifyException(Exception):
|
||||
def __init__(self, http_status, code, msg, headers=None):
|
||||
@ -53,9 +57,10 @@ class Spotify(object):
|
||||
max_get_retries = 10
|
||||
|
||||
def __init__(self, auth=None, requests_session=True,
|
||||
client_credentials_manager=None, proxies=None, requests_timeout=None):
|
||||
client_credentials_manager=None, proxies=None,
|
||||
requests_timeout=None):
|
||||
"""
|
||||
Create a Spotify API object.
|
||||
Creates a Spotify API client.
|
||||
|
||||
:param auth: An authorization token (optional)
|
||||
:param requests_session:
|
||||
@ -68,7 +73,8 @@ class Spotify(object):
|
||||
:param proxies:
|
||||
Definition of proxies (optional)
|
||||
:param requests_timeout:
|
||||
Tell Requests to stop waiting for a response after a given number of seconds
|
||||
Tell Requests to stop waiting for a response after a given
|
||||
number of seconds
|
||||
"""
|
||||
self.prefix = 'https://api.spotify.com/v1/'
|
||||
self._auth = auth
|
||||
@ -107,36 +113,39 @@ class Spotify(object):
|
||||
|
||||
if self.trace_out:
|
||||
print(url)
|
||||
r = self._session.request(method, url, headers=headers, proxies=self.proxies, **args)
|
||||
|
||||
with self._session.request(method, url, headers=headers,
|
||||
proxies=self.proxies, **args) as r:
|
||||
|
||||
if self.trace: # pragma: no cover
|
||||
print()
|
||||
print('Request headers:', headers)
|
||||
print('Response headers:', r.headers)
|
||||
print('HTTP status', r.status_code)
|
||||
print(method, r.url)
|
||||
if payload:
|
||||
print("Data", json.dumps(payload))
|
||||
|
||||
try:
|
||||
r.raise_for_status()
|
||||
except BaseException:
|
||||
try:
|
||||
msg = r.json()['error']['message']
|
||||
except BaseException:
|
||||
msg = 'error'
|
||||
raise SpotifyException(r.status_code,
|
||||
-1, '%s:\n %s' % (r.url, msg),
|
||||
headers=r.headers)
|
||||
|
||||
try:
|
||||
results = r.json()
|
||||
except BaseException:
|
||||
results = None
|
||||
|
||||
if self.trace: # pragma: no cover
|
||||
print('Response:', results)
|
||||
print()
|
||||
print ('headers', headers)
|
||||
print ('http status', r.status_code)
|
||||
print(method, r.url)
|
||||
if payload:
|
||||
print("DATA", json.dumps(payload))
|
||||
|
||||
try:
|
||||
r.raise_for_status()
|
||||
except:
|
||||
if r.text and len(r.text) > 0 and r.text != 'null':
|
||||
raise SpotifyException(r.status_code,
|
||||
-1, '%s:\n %s' % (r.url, r.json()['error']['message']),
|
||||
headers=r.headers)
|
||||
else:
|
||||
raise SpotifyException(r.status_code,
|
||||
-1, '%s:\n %s' % (r.url, 'error'), headers=r.headers)
|
||||
finally:
|
||||
r.connection.close()
|
||||
if r.text and len(r.text) > 0 and r.text != 'null':
|
||||
results = r.json()
|
||||
if self.trace: # pragma: no cover
|
||||
print('RESP', results)
|
||||
print()
|
||||
return results
|
||||
else:
|
||||
return None
|
||||
return results
|
||||
|
||||
def _get(self, url, args=None, payload=None, **kwargs):
|
||||
if args:
|
||||
@ -154,21 +163,22 @@ class Spotify(object):
|
||||
if retries < 0:
|
||||
raise
|
||||
else:
|
||||
sleep_seconds = int(e.headers.get('Retry-After', delay))
|
||||
print ('retrying ...' + str(sleep_seconds) + 'secs')
|
||||
sleep_seconds = int(
|
||||
e.headers.get('Retry-After', delay))
|
||||
print('retrying ...' + str(sleep_seconds) + 'secs')
|
||||
time.sleep(sleep_seconds + 1)
|
||||
delay += 1
|
||||
else:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise
|
||||
print ('exception', str(e))
|
||||
print('exception', str(e))
|
||||
# some other exception. Requests have
|
||||
# been know to throw a BadStatusLine exception
|
||||
retries -= 1
|
||||
if retries >= 0:
|
||||
sleep_seconds = int(e.headers.get('Retry-After', delay))
|
||||
print ('retrying ...' + str(delay) + 'secs')
|
||||
print('retrying ...' + str(delay) + 'secs')
|
||||
time.sleep(sleep_seconds + 1)
|
||||
delay += 1
|
||||
else:
|
||||
@ -227,7 +237,7 @@ class Spotify(object):
|
||||
trid = self._get_id('track', track_id)
|
||||
return self._get('tracks/' + trid)
|
||||
|
||||
def tracks(self, tracks, market = None):
|
||||
def tracks(self, tracks, market=None):
|
||||
""" returns a list of tracks given a list of track IDs, URIs, or URLs
|
||||
|
||||
Parameters:
|
||||
@ -236,7 +246,7 @@ class Spotify(object):
|
||||
"""
|
||||
|
||||
tlist = [self._get_id('track', t) for t in tracks]
|
||||
return self._get('tracks/?ids=' + ','.join(tlist), market = market)
|
||||
return self._get('tracks/?ids=' + ','.join(tlist), market=market)
|
||||
|
||||
def artist(self, artist_id):
|
||||
""" returns a single artist given the artist's ID, URI or URL
|
||||
@ -339,9 +349,11 @@ class Spotify(object):
|
||||
- offset - the index of the first item to return
|
||||
- type - the type of item to return. One of 'artist', 'album',
|
||||
'track' or 'playlist'
|
||||
- market - An ISO 3166-1 alpha-2 country code or the string from_token.
|
||||
- market - An ISO 3166-1 alpha-2 country code or the string
|
||||
from_token.
|
||||
"""
|
||||
return self._get('search', q=q, limit=limit, offset=offset, type=type, market=market)
|
||||
return self._get('search', q=q, limit=limit,
|
||||
offset=offset, type=type, market=market)
|
||||
|
||||
def user(self, user):
|
||||
""" Gets basic profile information about a Spotify User
|
||||
@ -382,6 +394,18 @@ class Spotify(object):
|
||||
plid = self._get_id('playlist', playlist_id)
|
||||
return self._get("users/%s/playlists/%s" % (user, plid), fields=fields)
|
||||
|
||||
def playlist(self, playlist_id, fields=None, market=None):
|
||||
""" Gets playlist by id
|
||||
|
||||
Parameters:
|
||||
- playlist - the id of the playlist
|
||||
- fields - which fields to return
|
||||
- market - An ISO 3166-1 alpha-2 country code or the string
|
||||
from_token.
|
||||
"""
|
||||
plid = self._get_id('playlist', playlist_id)
|
||||
return self._get("playlists/%s" % (plid), fields=fields)
|
||||
|
||||
def user_playlist_tracks(self, user, playlist_id=None, fields=None,
|
||||
limit=100, offset=0, market=None):
|
||||
""" Get full details of the tracks of a playlist owned by a user.
|
||||
@ -399,7 +423,6 @@ class Spotify(object):
|
||||
limit=limit, offset=offset, fields=fields,
|
||||
market=market)
|
||||
|
||||
|
||||
def user_playlist_create(self, user, name, public=True, description=''):
|
||||
""" Creates a playlist for a user
|
||||
|
||||
@ -411,7 +434,6 @@ class Spotify(object):
|
||||
"""
|
||||
data = {'name': name, 'public': public, 'description': description}
|
||||
|
||||
|
||||
return self._post("users/%s/playlists" % (user,), payload=data)
|
||||
|
||||
def user_playlist_change_details(
|
||||
@ -447,7 +469,8 @@ class Spotify(object):
|
||||
- user - the id of the user
|
||||
- name - the name of the playlist
|
||||
"""
|
||||
return self._delete("users/%s/playlists/%s/followers" % (user, playlist_id))
|
||||
return self._delete("users/%s/playlists/%s/followers" %
|
||||
(user, playlist_id))
|
||||
|
||||
def user_playlist_add_tracks(self, user, playlist_id, tracks,
|
||||
position=None):
|
||||
@ -487,8 +510,10 @@ class Spotify(object):
|
||||
- user - the id of the user
|
||||
- playlist_id - the id of the playlist
|
||||
- range_start - the position of the first track to be reordered
|
||||
- range_length - optional the number of tracks to be reordered (default: 1)
|
||||
- insert_before - the position where the tracks should be inserted
|
||||
- range_length - optional the number of tracks to be reordered
|
||||
(default: 1)
|
||||
- insert_before - the position where the tracks should be
|
||||
inserted
|
||||
- snapshot_id - optional playlist's snapshot ID
|
||||
"""
|
||||
plid = self._get_id('playlist', playlist_id)
|
||||
@ -507,7 +532,7 @@ class Spotify(object):
|
||||
Parameters:
|
||||
- user - the id of the user
|
||||
- playlist_id - the id of the playlist
|
||||
- tracks - the list of track ids to add to the playlist
|
||||
- tracks - the list of track ids to remove from the playlist
|
||||
- snapshot_id - optional id of the playlist snapshot
|
||||
|
||||
"""
|
||||
@ -527,9 +552,11 @@ class Spotify(object):
|
||||
Parameters:
|
||||
- user - the id of the user
|
||||
- playlist_id - the id of the playlist
|
||||
- tracks - an array of objects containing Spotify URIs of the tracks to remove with their current positions in the playlist. For example:
|
||||
[ { "uri":"4iV5W9uYEdYUVa79Axb7Rh", "positions":[2] },
|
||||
{ "uri":"1301WleyT98MSxVHPZCA6M", "positions":[7] } ]
|
||||
- tracks - an array of objects containing Spotify URIs of the
|
||||
tracks to remove with their current positions in the
|
||||
playlist. For example:
|
||||
[ { "uri":"4iV5W9uYEdYUVa79Axb7Rh", "positions":[2] },
|
||||
{ "uri":"1301WleyT98MSxVHPZCA6M", "positions":[7] } ]
|
||||
- snapshot_id - optional id of the playlist snapshot
|
||||
"""
|
||||
|
||||
@ -555,19 +582,26 @@ class Spotify(object):
|
||||
- playlist_id - the id of the playlist
|
||||
|
||||
"""
|
||||
return self._put("users/{}/playlists/{}/followers".format(playlist_owner_id, playlist_id))
|
||||
return self._put(
|
||||
"users/{}/playlists/{}/followers".format(playlist_owner_id,
|
||||
playlist_id))
|
||||
|
||||
def user_playlist_is_following(self, playlist_owner_id, playlist_id, user_ids):
|
||||
def user_playlist_is_following(
|
||||
self, playlist_owner_id, playlist_id, user_ids):
|
||||
"""
|
||||
Check to see if the given users are following the given playlist
|
||||
|
||||
Parameters:
|
||||
- playlist_owner_id - the user id of the playlist owner
|
||||
- playlist_id - the id of the playlist
|
||||
- user_ids - the ids of the users that you want to check to see if they follow the playlist. Maximum: 5 ids.
|
||||
- user_ids - the ids of the users that you want to check to see
|
||||
if they follow the playlist. Maximum: 5 ids.
|
||||
|
||||
"""
|
||||
return self._get("users/{}/playlists/{}/followers/contains?ids={}".format(playlist_owner_id, playlist_id, ','.join(user_ids)))
|
||||
endpoint = "users/{}/playlists/{}/followers/contains?ids={}"
|
||||
return self._get(endpoint.format(playlist_owner_id,
|
||||
playlist_id,
|
||||
','.join(user_ids)))
|
||||
|
||||
def me(self):
|
||||
""" Get detailed profile information about the current user.
|
||||
@ -586,17 +620,6 @@ class Spotify(object):
|
||||
'''
|
||||
return self._get('me/player/currently-playing')
|
||||
|
||||
def current_user_saved_albums(self, limit=20, offset=0):
|
||||
""" Gets a list of the albums saved in the current authorized user's
|
||||
"Your Music" library
|
||||
|
||||
Parameters:
|
||||
- limit - the number of albums to return
|
||||
- offset - the index of the first album to return
|
||||
|
||||
"""
|
||||
return self._get('me/albums', limit=limit, offset=offset)
|
||||
|
||||
def current_user_saved_tracks(self, limit=20, offset=0):
|
||||
""" Gets a list of the tracks saved in the current authorized user's
|
||||
"Your Music" library
|
||||
@ -612,8 +635,9 @@ class Spotify(object):
|
||||
""" Gets a list of the artists followed by the current authorized user
|
||||
|
||||
Parameters:
|
||||
- limit - the number of tracks to return
|
||||
- after - ghe last artist ID retrieved from the previous request
|
||||
- limit - the number of artists to return
|
||||
- after - the last artist ID retrieved from the previous
|
||||
request
|
||||
|
||||
"""
|
||||
return self._get('me/following', type='artist', limit=limit,
|
||||
@ -686,9 +710,30 @@ class Spotify(object):
|
||||
|
||||
Parameters:
|
||||
- limit - the number of entities to return
|
||||
'''
|
||||
'''
|
||||
return self._get('me/player/recently-played', limit=limit)
|
||||
|
||||
def current_user_saved_albums(self, limit=20, offset=0):
|
||||
""" Gets a list of the albums saved in the current authorized user's
|
||||
"Your Music" library
|
||||
|
||||
Parameters:
|
||||
- limit - the number of albums to return
|
||||
- offset - the index of the first album to return
|
||||
|
||||
"""
|
||||
return self._get('me/albums', limit=limit, offset=offset)
|
||||
|
||||
def current_user_saved_albums_contains(self, albums=[]):
|
||||
""" Check if one or more albums is already saved in
|
||||
the current Spotify user’s “Your Music” library.
|
||||
|
||||
Parameters:
|
||||
- albums - a list of album URIs, URLs or IDs
|
||||
"""
|
||||
alist = [self._get_id('album', a) for a in albums]
|
||||
return self._get('me/albums/contains?ids=' + ','.join(alist))
|
||||
|
||||
def current_user_saved_albums_add(self, albums=[]):
|
||||
""" Add one or more albums to the current user's
|
||||
"Your Music" library.
|
||||
@ -696,8 +741,17 @@ class Spotify(object):
|
||||
- albums - a list of album URIs, URLs or IDs
|
||||
"""
|
||||
alist = [self._get_id('album', a) for a in albums]
|
||||
r = self._put('me/albums?ids=' + ','.join(alist))
|
||||
return r
|
||||
return self._put('me/albums?ids=' + ','.join(alist))
|
||||
|
||||
def current_user_saved_albums_delete(self, albums=[]):
|
||||
""" Remove one or more albums from the current user's
|
||||
"Your Music" library.
|
||||
|
||||
Parameters:
|
||||
- albums - a list of album URIs, URLs or IDs
|
||||
"""
|
||||
alist = [self._get_id('album', a) for a in albums]
|
||||
return self._delete('me/albums/?ids=' + ','.join(alist))
|
||||
|
||||
def user_follow_artists(self, ids=[]):
|
||||
''' Follow one or more artists
|
||||
@ -713,6 +767,20 @@ class Spotify(object):
|
||||
'''
|
||||
return self._put('me/following?type=user&ids=' + ','.join(ids))
|
||||
|
||||
def user_unfollow_artists(self, ids=[]):
|
||||
''' Unfollow one or more artists
|
||||
Parameters:
|
||||
- ids - a list of artist IDs
|
||||
'''
|
||||
return self._delete('me/following?type=artist&ids=' + ','.join(ids))
|
||||
|
||||
def user_unfollow_users(self, ids=[]):
|
||||
''' Unfollow one or more users
|
||||
Parameters:
|
||||
- ids - a list of user IDs
|
||||
'''
|
||||
return self._delete('me/following?type=user&ids=' + ','.join(ids))
|
||||
|
||||
def featured_playlists(self, locale=None, country=None, timestamp=None,
|
||||
limit=20, offset=0):
|
||||
""" Get a list of Spotify featured playlists
|
||||
@ -801,20 +869,21 @@ class Spotify(object):
|
||||
Parameters:
|
||||
- seed_artists - a list of artist IDs, URIs or URLs
|
||||
|
||||
- seed_tracks - a list of artist IDs, URIs or URLs
|
||||
- seed_tracks - a list of track IDs, URIs or URLs
|
||||
|
||||
- seed_genres - a list of genre names. Available genres for
|
||||
recommendations can be found by calling recommendation_genre_seeds
|
||||
recommendations can be found by calling
|
||||
recommendation_genre_seeds
|
||||
|
||||
- country - An ISO 3166-1 alpha-2 country code. If provided, all
|
||||
results will be playable in this country.
|
||||
- country - An ISO 3166-1 alpha-2 country code. If provided,
|
||||
all results will be playable in this country.
|
||||
|
||||
- limit - The maximum number of items to return. Default: 20.
|
||||
Minimum: 1. Maximum: 100
|
||||
Minimum: 1. Maximum: 100
|
||||
|
||||
- min/max/target_<attribute> - For the tuneable track attributes listed
|
||||
in the documentation, these values provide filters and targeting on
|
||||
results.
|
||||
- min/max/target_<attribute> - For the tuneable track
|
||||
attributes listed in the documentation, these values
|
||||
provide filters and targeting on results.
|
||||
"""
|
||||
params = dict(limit=limit)
|
||||
if seed_artists:
|
||||
@ -869,36 +938,28 @@ class Spotify(object):
|
||||
else:
|
||||
return results
|
||||
|
||||
def audio_analysis(self, id):
|
||||
""" Get audio analysis for a track based upon its Spotify ID
|
||||
Parameters:
|
||||
- id - a track URIs, URLs or IDs
|
||||
"""
|
||||
id = self._get_id('track', id)
|
||||
return self._get('audio-analysis/'+id)
|
||||
|
||||
def devices(self):
|
||||
''' Get a list of user's available devices.
|
||||
'''
|
||||
return self._get("me/player/devices")
|
||||
|
||||
def current_playback(self, market = None):
|
||||
def current_playback(self, market=None):
|
||||
''' Get information about user's current playback.
|
||||
|
||||
Parameters:
|
||||
- market - an ISO 3166-1 alpha-2 country code.
|
||||
'''
|
||||
return self._get("me/player", market = market)
|
||||
return self._get("me/player", market=market)
|
||||
|
||||
def currently_playing(self, market = None):
|
||||
def currently_playing(self, market=None):
|
||||
''' Get user's currently playing track.
|
||||
|
||||
Parameters:
|
||||
- market - an ISO 3166-1 alpha-2 country code.
|
||||
'''
|
||||
return self._get("me/player/currently-playing", market = market)
|
||||
return self._get("me/player/currently-playing", market=market)
|
||||
|
||||
def transfer_playback(self, device_id, force_play = True):
|
||||
def transfer_playback(self, device_id, force_play=True):
|
||||
''' Transfer playback to another device.
|
||||
Note that the API accepts a list of device ids, but only
|
||||
actually supports one.
|
||||
@ -914,7 +975,8 @@ class Spotify(object):
|
||||
}
|
||||
return self._put("me/player", payload=data)
|
||||
|
||||
def start_playback(self, device_id = None, context_uri = None, uris = None, offset = None):
|
||||
def start_playback(self, device_id=None,
|
||||
context_uri=None, uris=None, offset=None):
|
||||
''' Start or resume user's playback.
|
||||
|
||||
Provide a `context_uri` to start playback or a album,
|
||||
@ -945,9 +1007,10 @@ class Spotify(object):
|
||||
data['uris'] = uris
|
||||
if offset is not None:
|
||||
data['offset'] = offset
|
||||
return self._put(self._append_device_id("me/player/play", device_id), payload=data)
|
||||
return self._put(self._append_device_id(
|
||||
"me/player/play", device_id), payload=data)
|
||||
|
||||
def pause_playback(self, device_id = None):
|
||||
def pause_playback(self, device_id=None):
|
||||
''' Pause user's playback.
|
||||
|
||||
Parameters:
|
||||
@ -955,7 +1018,7 @@ class Spotify(object):
|
||||
'''
|
||||
return self._put(self._append_device_id("me/player/pause", device_id))
|
||||
|
||||
def next_track(self, device_id = None):
|
||||
def next_track(self, device_id=None):
|
||||
''' Skip user's playback to next track.
|
||||
|
||||
Parameters:
|
||||
@ -963,15 +1026,16 @@ class Spotify(object):
|
||||
'''
|
||||
return self._post(self._append_device_id("me/player/next", device_id))
|
||||
|
||||
def previous_track(self, device_id = None):
|
||||
def previous_track(self, device_id=None):
|
||||
''' Skip user's playback to previous track.
|
||||
|
||||
Parameters:
|
||||
- device_id - device target for playback
|
||||
'''
|
||||
return self._post(self._append_device_id("me/player/previous", device_id))
|
||||
return self._post(self._append_device_id(
|
||||
"me/player/previous", device_id))
|
||||
|
||||
def seek_track(self, position_ms, device_id = None):
|
||||
def seek_track(self, position_ms, device_id=None):
|
||||
''' Seek to position in current track.
|
||||
|
||||
Parameters:
|
||||
@ -981,9 +1045,10 @@ class Spotify(object):
|
||||
if not isinstance(position_ms, int):
|
||||
self._warn('position_ms must be an integer')
|
||||
return
|
||||
return self._put(self._append_device_id("me/player/seek?position_ms=%s" % position_ms, device_id))
|
||||
return self._put(self._append_device_id(
|
||||
"me/player/seek?position_ms=%s" % position_ms, device_id))
|
||||
|
||||
def repeat(self, state, device_id = None):
|
||||
def repeat(self, state, device_id=None):
|
||||
''' Set repeat mode for playback.
|
||||
|
||||
Parameters:
|
||||
@ -993,9 +1058,12 @@ class Spotify(object):
|
||||
if state not in ['track', 'context', 'off']:
|
||||
self._warn('invalid state')
|
||||
return
|
||||
self._put(self._append_device_id("me/player/repeat?state=%s" % state, device_id))
|
||||
self._put(
|
||||
self._append_device_id(
|
||||
"me/player/repeat?state=%s" %
|
||||
state, device_id))
|
||||
|
||||
def volume(self, volume_percent, device_id = None):
|
||||
def volume(self, volume_percent, device_id=None):
|
||||
''' Set playback volume.
|
||||
|
||||
Parameters:
|
||||
@ -1008,9 +1076,12 @@ class Spotify(object):
|
||||
if volume_percent < 0 or volume_percent > 100:
|
||||
self._warn('volume must be between 0 and 100, inclusive')
|
||||
return
|
||||
self._put(self._append_device_id("me/player/volume?volume_percent=%s" % volume_percent, device_id))
|
||||
self._put(
|
||||
self._append_device_id(
|
||||
"me/player/volume?volume_percent=%s" %
|
||||
volume_percent, device_id))
|
||||
|
||||
def shuffle(self, state, device_id = None):
|
||||
def shuffle(self, state, device_id=None):
|
||||
''' Toggle playback shuffling.
|
||||
|
||||
Parameters:
|
||||
@ -1021,7 +1092,10 @@ class Spotify(object):
|
||||
self._warn('state must be a boolean')
|
||||
return
|
||||
state = str(state).lower()
|
||||
self._put(self._append_device_id("me/player/shuffle?state=%s" % state, device_id))
|
||||
self._put(
|
||||
self._append_device_id(
|
||||
"me/player/shuffle?state=%s" %
|
||||
state, device_id))
|
||||
|
||||
def _append_device_id(self, path, device_id):
|
||||
''' Append device ID to API path.
|
||||
@ -1040,16 +1114,16 @@ class Spotify(object):
|
||||
fields = id.split(':')
|
||||
if len(fields) >= 3:
|
||||
if type != fields[-2]:
|
||||
self._warn('expected id of type %s but found type %s %s',
|
||||
type, fields[-2], id)
|
||||
self._warn('expected id of type %s but found type %s %s' %
|
||||
(type, fields[-2], id))
|
||||
return fields[-1]
|
||||
fields = id.split('/')
|
||||
if len(fields) >= 3:
|
||||
itype = fields[-2]
|
||||
if type != itype:
|
||||
self._warn('expected id of type %s but found type %s %s',
|
||||
type, itype, id)
|
||||
return fields[-1]
|
||||
self._warn('expected id of type %s but found type %s %s' %
|
||||
(type, itype, id))
|
||||
return fields[-1].split('?')[0]
|
||||
return id
|
||||
|
||||
def _get_uri(self, type, id):
|
||||
|
||||
@ -1,11 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
__all__ = [
|
||||
'is_token_expired',
|
||||
'SpotifyClientCredentials',
|
||||
'SpotifyOAuth',
|
||||
'SpotifyOauthError'
|
||||
]
|
||||
|
||||
import base64
|
||||
import requests
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
import requests
|
||||
|
||||
# Workaround to support both python 2 & 3
|
||||
import six
|
||||
@ -17,7 +27,11 @@ class SpotifyOauthError(Exception):
|
||||
|
||||
|
||||
def _make_authorization_headers(client_id, client_secret):
|
||||
auth_header = base64.b64encode(six.text_type(client_id + ':' + client_secret).encode('ascii'))
|
||||
auth_header = base64.b64encode(
|
||||
six.text_type(
|
||||
client_id +
|
||||
':' +
|
||||
client_secret).encode('ascii'))
|
||||
return {'Authorization': 'Basic %s' % auth_header.decode('ascii')}
|
||||
|
||||
|
||||
@ -31,7 +45,7 @@ class SpotifyClientCredentials(object):
|
||||
|
||||
def __init__(self, client_id=None, client_secret=None, proxies=None):
|
||||
"""
|
||||
You can either provid a client_id and client_secret to the
|
||||
You can either provide a client_id and client_secret to the
|
||||
constructor or set SPOTIPY_CLIENT_ID and SPOTIPY_CLIENT_SECRET
|
||||
environment variables
|
||||
"""
|
||||
@ -67,12 +81,14 @@ class SpotifyClientCredentials(object):
|
||||
|
||||
def _request_access_token(self):
|
||||
"""Gets client credentials access token """
|
||||
payload = { 'grant_type': 'client_credentials'}
|
||||
payload = {'grant_type': 'client_credentials'}
|
||||
|
||||
headers = _make_authorization_headers(self.client_id, self.client_secret)
|
||||
headers = _make_authorization_headers(
|
||||
self.client_id, self.client_secret)
|
||||
|
||||
response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
|
||||
headers=headers, verify=True, proxies=self.proxies)
|
||||
headers=headers, verify=True,
|
||||
proxies=self.proxies)
|
||||
if response.status_code != 200:
|
||||
raise SpotifyOauthError(response.reason)
|
||||
token_info = response.json()
|
||||
@ -99,7 +115,7 @@ class SpotifyOAuth(object):
|
||||
OAUTH_TOKEN_URL = 'https://accounts.spotify.com/api/token'
|
||||
|
||||
def __init__(self, client_id, client_secret, redirect_uri,
|
||||
state=None, scope=None, cache_path=None, proxies=None):
|
||||
state=None, scope=None, cache_path=None, proxies=None):
|
||||
'''
|
||||
Creates a SpotifyOAuth object
|
||||
|
||||
@ -115,9 +131,9 @@ class SpotifyOAuth(object):
|
||||
self.client_id = client_id
|
||||
self.client_secret = client_secret
|
||||
self.redirect_uri = redirect_uri
|
||||
self.state=state
|
||||
self.state = state
|
||||
self.cache_path = cache_path
|
||||
self.scope=self._normalize_scope(scope)
|
||||
self.scope = self._normalize_scope(scope)
|
||||
self.proxies = proxies
|
||||
|
||||
def get_cached_token(self):
|
||||
@ -132,11 +148,13 @@ class SpotifyOAuth(object):
|
||||
token_info = json.loads(token_info_string)
|
||||
|
||||
# if scopes don't match, then bail
|
||||
if 'scope' not in token_info or not self._is_scope_subset(self.scope, token_info['scope']):
|
||||
if 'scope' not in token_info or not self._is_scope_subset(
|
||||
self.scope, token_info['scope']):
|
||||
return None
|
||||
|
||||
if self.is_token_expired(token_info):
|
||||
token_info = self.refresh_access_token(token_info['refresh_token'])
|
||||
token_info = self.refresh_access_token(
|
||||
token_info['refresh_token'])
|
||||
|
||||
except IOError:
|
||||
pass
|
||||
@ -154,7 +172,8 @@ class SpotifyOAuth(object):
|
||||
|
||||
def _is_scope_subset(self, needle_scope, haystack_scope):
|
||||
needle_scope = set(needle_scope.split()) if needle_scope else set()
|
||||
haystack_scope = set(haystack_scope.split()) if haystack_scope else set()
|
||||
haystack_scope = set(
|
||||
haystack_scope.split()) if haystack_scope else set()
|
||||
return needle_scope <= haystack_scope
|
||||
|
||||
def is_token_expired(self, token_info):
|
||||
@ -212,7 +231,8 @@ class SpotifyOAuth(object):
|
||||
headers = self._make_authorization_headers()
|
||||
|
||||
response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
|
||||
headers=headers, verify=True, proxies=self.proxies)
|
||||
headers=headers, verify=True,
|
||||
proxies=self.proxies)
|
||||
if response.status_code != 200:
|
||||
raise SpotifyOauthError(response.reason)
|
||||
token_info = response.json()
|
||||
@ -222,30 +242,29 @@ class SpotifyOAuth(object):
|
||||
|
||||
def _normalize_scope(self, scope):
|
||||
if scope:
|
||||
scopes = scope.split()
|
||||
scopes.sort()
|
||||
scopes = sorted(scope.split())
|
||||
return ' '.join(scopes)
|
||||
else:
|
||||
return None
|
||||
|
||||
def refresh_access_token(self, refresh_token):
|
||||
payload = { 'refresh_token': refresh_token,
|
||||
payload = {'refresh_token': refresh_token,
|
||||
'grant_type': 'refresh_token'}
|
||||
|
||||
headers = self._make_authorization_headers()
|
||||
|
||||
response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
|
||||
headers=headers, proxies=self.proxies)
|
||||
headers=headers, proxies=self.proxies)
|
||||
if response.status_code != 200:
|
||||
if False: # debugging code
|
||||
print('headers', headers)
|
||||
print('request', response.url)
|
||||
self._warn("couldn't refresh token: code:%d reason:%s" \
|
||||
% (response.status_code, response.reason))
|
||||
self._warn("couldn't refresh token: code:%d reason:%s"
|
||||
% (response.status_code, response.reason))
|
||||
return None
|
||||
token_info = response.json()
|
||||
token_info = self._add_custom_values_to_token_info(token_info)
|
||||
if not 'refresh_token' in token_info:
|
||||
if 'refresh_token' not in token_info:
|
||||
token_info['refresh_token'] = refresh_token
|
||||
self._save_token_info(token_info)
|
||||
return token_info
|
||||
@ -261,4 +280,3 @@ class SpotifyOAuth(object):
|
||||
|
||||
def _warn(self, msg):
|
||||
print('warning:' + msg, file=sys.stderr)
|
||||
|
||||
|
||||
@ -1,15 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# shows a user's playlists (need to be authenticated via oauth)
|
||||
""" Shows a user's playlists (need to be authenticated via oauth) """
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
__all__ = [
|
||||
'CLIENT_CREDS_ENV_VARS',
|
||||
'prompt_for_user_token'
|
||||
]
|
||||
|
||||
import os
|
||||
|
||||
from . import oauth2
|
||||
|
||||
import spotipy
|
||||
|
||||
def prompt_for_user_token(username, scope=None, client_id = None,
|
||||
client_secret = None, redirect_uri = None, cache_path = None):
|
||||
CLIENT_CREDS_ENV_VARS = {
|
||||
'client_id': 'SPOTIPY_CLIENT_ID',
|
||||
'client_secret': 'SPOTIPY_CLIENT_SECRET',
|
||||
'client_username': 'SPOTIPY_CLIENT_USERNAME',
|
||||
'redirect_uri': 'SPOTIPY_REDIRECT_URI'
|
||||
}
|
||||
|
||||
|
||||
def prompt_for_user_token(username, scope=None, client_id=None,
|
||||
client_secret=None, redirect_uri=None,
|
||||
cache_path=None):
|
||||
''' prompts the user to login if necessary and returns
|
||||
the user token suitable for use with the spotipy.Spotify
|
||||
the user token suitable for use with the spotipy.Spotify
|
||||
constructor
|
||||
|
||||
Parameters:
|
||||
@ -41,14 +59,14 @@ def prompt_for_user_token(username, scope=None, client_id = None,
|
||||
export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret'
|
||||
export SPOTIPY_REDIRECT_URI='your-app-redirect-url'
|
||||
|
||||
Get your credentials at
|
||||
Get your credentials at
|
||||
https://developer.spotify.com/my-applications
|
||||
''')
|
||||
raise spotipy.SpotifyException(550, -1, 'no credentials set')
|
||||
|
||||
cache_path = cache_path or ".cache-" + username
|
||||
sp_oauth = oauth2.SpotifyOAuth(client_id, client_secret, redirect_uri,
|
||||
scope=scope, cache_path=cache_path)
|
||||
sp_oauth = oauth2.SpotifyOAuth(client_id, client_secret, redirect_uri,
|
||||
scope=scope, cache_path=cache_path)
|
||||
|
||||
# try to get a valid token for this user, from the cache,
|
||||
# if not in the cache, the create a new (this will send
|
||||
@ -71,7 +89,7 @@ def prompt_for_user_token(username, scope=None, client_id = None,
|
||||
import webbrowser
|
||||
webbrowser.open(auth_url)
|
||||
print("Opened %s in your browser" % auth_url)
|
||||
except:
|
||||
except BaseException:
|
||||
print("Please navigate here: %s" % auth_url)
|
||||
|
||||
print()
|
||||
@ -82,7 +100,7 @@ def prompt_for_user_token(username, scope=None, client_id = None,
|
||||
response = input("Enter the URL you were redirected to: ")
|
||||
|
||||
print()
|
||||
print()
|
||||
print()
|
||||
|
||||
code = sp_oauth.parse_response_code(response)
|
||||
token_info = sp_oauth.get_access_token(code)
|
||||
|
||||
@ -1,222 +0,0 @@
|
||||
# -*- coding: latin-1 -*-
|
||||
|
||||
import spotipy
|
||||
from spotipy import util
|
||||
import unittest
|
||||
import pprint
|
||||
import sys
|
||||
import simplejson as json
|
||||
|
||||
'''
|
||||
Since these tests require authentication they are maintained
|
||||
separately from the other tests.
|
||||
|
||||
These tests try to be benign and leave your collection and
|
||||
playlists in a relatively stable state.
|
||||
'''
|
||||
|
||||
class AuthTestSpotipy(unittest.TestCase):
|
||||
'''
|
||||
These tests require user authentication
|
||||
'''
|
||||
|
||||
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
|
||||
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||
"spotify:track:7IHOIqZUUInxjVkko181PB",
|
||||
"4VrWlk8IQxevMvERoX08iC",
|
||||
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
|
||||
|
||||
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||
"spotify:track:7IHOIqZUUInxjVkko181PB"]
|
||||
|
||||
other_tracks=["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
|
||||
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
|
||||
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
|
||||
|
||||
bad_id = 'BAD_ID'
|
||||
|
||||
def test_track_bad_id(self):
|
||||
try:
|
||||
track = spotify.track(self.bad_id)
|
||||
self.assertTrue(False)
|
||||
except spotipy.SpotifyException:
|
||||
self.assertTrue(True)
|
||||
|
||||
|
||||
def test_basic_user_profile(self):
|
||||
user = spotify.user(username)
|
||||
self.assertTrue(user['id'] == username)
|
||||
|
||||
def test_current_user(self):
|
||||
user = spotify.current_user()
|
||||
self.assertTrue(user['id'] == username)
|
||||
|
||||
def test_me(self):
|
||||
user = spotify.me()
|
||||
self.assertTrue(user['id'] == username)
|
||||
|
||||
def test_user_playlists(self):
|
||||
playlists = spotify.user_playlists(username, limit=5)
|
||||
self.assertTrue('items' in playlists)
|
||||
self.assertTrue(len(playlists['items']) == 5)
|
||||
|
||||
def test_user_playlist_tracks(self):
|
||||
playlists = spotify.user_playlists(username, limit=5)
|
||||
self.assertTrue('items' in playlists)
|
||||
for playlist in playlists['items']:
|
||||
user = playlist['owner']['id']
|
||||
pid = playlist['id']
|
||||
results = spotify.user_playlist_tracks(user, pid)
|
||||
self.assertTrue(len(results['items']) >= 0)
|
||||
|
||||
def user_playlist_tracks(self, user, playlist_id = None, fields=None,
|
||||
limit=100, offset=0):
|
||||
|
||||
# known API issue currently causes this test to fail
|
||||
# the issue is that the API doesn't currently respect the
|
||||
# limit paramter
|
||||
|
||||
self.assertTrue(len(playlists['items']) == 5)
|
||||
|
||||
def test_current_user_saved_tracks(self):
|
||||
tracks = spotify.current_user_saved_tracks()
|
||||
self.assertTrue(len(tracks['items']) > 0)
|
||||
|
||||
def test_current_user_saved_albums(self):
|
||||
albums = spotify.current_user_saved_albums()
|
||||
self.assertTrue(len(albums['items']) > 0)
|
||||
|
||||
def test_current_user_playlists(self):
|
||||
playlists = spotify.current_user_playlists(limit=10)
|
||||
self.assertTrue('items' in playlists)
|
||||
self.assertTrue(len(playlists['items']) == 10)
|
||||
|
||||
def test_user_playlist_follow(self):
|
||||
spotify.user_playlist_follow_playlist('plamere', '4erXB04MxwRAVqcUEpu30O')
|
||||
follows = spotify.user_playlist_is_following('plamere', '4erXB04MxwRAVqcUEpu30O', ['plamere'])
|
||||
|
||||
self.assertTrue(len(follows) == 1, 'proper follows length')
|
||||
self.assertTrue(follows[0], 'is following')
|
||||
spotify.user_playlist_unfollow('plamere', '4erXB04MxwRAVqcUEpu30O')
|
||||
|
||||
follows = spotify.user_playlist_is_following('plamere', '4erXB04MxwRAVqcUEpu30O', ['plamere'])
|
||||
self.assertTrue(len(follows) == 1, 'proper follows length')
|
||||
self.assertFalse(follows[0], 'is no longer following')
|
||||
|
||||
|
||||
def test_current_user_save_and_unsave_tracks(self):
|
||||
tracks = spotify.current_user_saved_tracks()
|
||||
total = tracks['total']
|
||||
|
||||
spotify.current_user_saved_tracks_add(self.four_tracks)
|
||||
|
||||
tracks = spotify.current_user_saved_tracks()
|
||||
new_total = tracks['total']
|
||||
self.assertTrue(new_total - total == len(self.four_tracks))
|
||||
|
||||
tracks = spotify.current_user_saved_tracks_delete(self.four_tracks)
|
||||
tracks = spotify.current_user_saved_tracks()
|
||||
new_total = tracks['total']
|
||||
self.assertTrue(new_total == total)
|
||||
|
||||
|
||||
def test_categories(self):
|
||||
response = spotify.categories()
|
||||
self.assertTrue(len(response['categories']) > 0)
|
||||
|
||||
def test_category_playlists(self):
|
||||
response = spotify.categories()
|
||||
for cat in response['categories']['items']:
|
||||
cat_id = cat['id']
|
||||
response = spotify.category_playlists(category_id=cat_id)
|
||||
self.assertTrue(len(response['playlists']["items"]) > 0)
|
||||
|
||||
def test_new_releases(self):
|
||||
response = spotify.new_releases()
|
||||
self.assertTrue(len(response['albums']) > 0)
|
||||
|
||||
def test_featured_releases(self):
|
||||
response = spotify.featured_playlists()
|
||||
self.assertTrue(len(response['playlists']) > 0)
|
||||
|
||||
def test_current_user_follows(self):
|
||||
response = spotify.current_user_followed_artists()
|
||||
artists = response['artists']
|
||||
self.assertTrue(len(artists['items']) > 0)
|
||||
|
||||
def test_current_user_top_tracks(self):
|
||||
response = spotify.current_user_top_tracks()
|
||||
items = response['items']
|
||||
self.assertTrue(len(items) > 0)
|
||||
|
||||
def test_current_user_top_artists(self):
|
||||
response = spotify.current_user_top_artists()
|
||||
items = response['items']
|
||||
self.assertTrue(len(items) > 0)
|
||||
|
||||
def get_or_create_spotify_playlist(self, username, playlist_name):
|
||||
playlists = spotify.user_playlists(username)
|
||||
while playlists:
|
||||
for item in playlists['items']:
|
||||
if item['name'] == playlist_name:
|
||||
return item['id']
|
||||
playlists = spotify.next(playlists)
|
||||
playlist = spotify.user_playlist_create(username, playlist_name)
|
||||
playlist_id = playlist['uri']
|
||||
return playlist_id
|
||||
|
||||
def test_user_playlist_ops(self):
|
||||
# create empty playlist
|
||||
playlist_id = self.get_or_create_spotify_playlist(username,
|
||||
'spotipy-testing-playlist-1')
|
||||
|
||||
# remove all tracks from it
|
||||
|
||||
spotify.user_playlist_replace_tracks(username, playlist_id,[])
|
||||
|
||||
playlist = spotify.user_playlist(username, playlist_id)
|
||||
self.assertTrue(playlist['tracks']['total'] == 0)
|
||||
self.assertTrue(len(playlist['tracks']['items']) == 0)
|
||||
|
||||
# add tracks to it
|
||||
|
||||
spotify.user_playlist_add_tracks(username, playlist_id, self.four_tracks)
|
||||
playlist = spotify.user_playlist(username, playlist_id)
|
||||
self.assertTrue(playlist['tracks']['total'] == 4)
|
||||
self.assertTrue(len(playlist['tracks']['items']) == 4)
|
||||
|
||||
# remove two tracks from it
|
||||
|
||||
spotify.user_playlist_remove_all_occurrences_of_tracks (username,
|
||||
playlist_id, self.two_tracks)
|
||||
|
||||
playlist = spotify.user_playlist(username, playlist_id)
|
||||
self.assertTrue(playlist['tracks']['total'] == 2)
|
||||
self.assertTrue(len(playlist['tracks']['items']) == 2)
|
||||
|
||||
# replace with 3 other tracks
|
||||
spotify.user_playlist_replace_tracks(username,
|
||||
playlist_id, self.other_tracks)
|
||||
|
||||
playlist = spotify.user_playlist(username, playlist_id)
|
||||
self.assertTrue(playlist['tracks']['total'] == 3)
|
||||
self.assertTrue(len(playlist['tracks']['items']) == 3)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 1:
|
||||
username = sys.argv[1]
|
||||
del sys.argv[1]
|
||||
|
||||
scope = 'playlist-modify-public '
|
||||
scope += 'user-library-read '
|
||||
scope += 'user-follow-read '
|
||||
scope += 'user-library-modify '
|
||||
scope += 'user-read-private '
|
||||
scope += 'user-top-read'
|
||||
|
||||
token = util.prompt_for_user_token(username, scope)
|
||||
spotify = spotipy.Spotify(auth=token)
|
||||
spotify.trace = False
|
||||
unittest.main()
|
||||
else:
|
||||
print("Usage: %s username" % (sys.argv[0],))
|
||||
@ -1,70 +0,0 @@
|
||||
# -*- coding: latin-1 -*-
|
||||
|
||||
import spotipy
|
||||
from spotipy import util
|
||||
import unittest
|
||||
import pprint
|
||||
import sys
|
||||
import simplejson as json
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
|
||||
'''
|
||||
Since these tests require authentication they are maintained
|
||||
separately from the other tests.
|
||||
|
||||
These tests try to be benign and leave your collection and
|
||||
playlists in a relatively stable state.
|
||||
'''
|
||||
|
||||
class AuthTestSpotipy(unittest.TestCase):
|
||||
'''
|
||||
These tests require user authentication
|
||||
'''
|
||||
|
||||
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
|
||||
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||
"spotify:track:7IHOIqZUUInxjVkko181PB",
|
||||
"4VrWlk8IQxevMvERoX08iC",
|
||||
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
|
||||
|
||||
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||
"spotify:track:7IHOIqZUUInxjVkko181PB"]
|
||||
|
||||
other_tracks=["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
|
||||
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
|
||||
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
|
||||
|
||||
bad_id = 'BAD_ID'
|
||||
|
||||
|
||||
def test_audio_analysis(self):
|
||||
result = spotify.audio_analysis(self.four_tracks[0])
|
||||
assert('beats' in result)
|
||||
|
||||
def test_audio_features(self):
|
||||
results = spotify.audio_features(self.four_tracks)
|
||||
self.assertTrue(len(results) == len(self.four_tracks))
|
||||
for track in results:
|
||||
assert('speechiness' in track)
|
||||
|
||||
def test_audio_features_with_bad_track(self):
|
||||
bad_tracks = []
|
||||
bad_tracks = ['spotify:track:bad']
|
||||
input = self.four_tracks + bad_tracks
|
||||
results = spotify.audio_features(input)
|
||||
self.assertTrue(len(results) == len(input))
|
||||
for track in results[:-1]:
|
||||
if track != None:
|
||||
assert('speechiness' in track)
|
||||
self.assertTrue(results[-1] == None)
|
||||
|
||||
def test_recommendations(self):
|
||||
results = spotify.recommendations(seed_tracks=self.four_tracks, min_danceability=0, max_loudness=0, target_popularity=50)
|
||||
self.assertTrue(len(results['tracks']) == 20)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
spotify.trace = False
|
||||
unittest.main()
|
||||
@ -1,27 +0,0 @@
|
||||
# -*- coding: latin-1 -*-
|
||||
|
||||
import spotipy
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
import unittest
|
||||
|
||||
'''
|
||||
Client Credentials Requests Tests
|
||||
'''
|
||||
|
||||
class ClientCredentialsTestSpotipy(unittest.TestCase):
|
||||
'''
|
||||
These tests require user authentication
|
||||
'''
|
||||
|
||||
muse_urn = 'spotify:artist:12Chz98pHFMPJEknJQMWvI'
|
||||
|
||||
def test_request_with_token(self):
|
||||
artist = spotify.artist(self.muse_urn)
|
||||
self.assertTrue(artist['name'] == 'Muse')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
spotify_cc = SpotifyClientCredentials()
|
||||
spotify = spotipy.Spotify(client_credentials_manager=spotify_cc)
|
||||
spotify.trace = False
|
||||
unittest.main()
|
||||
312
tests/test_auth.py
Normal file
312
tests/test_auth.py
Normal file
@ -0,0 +1,312 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
These tests require user authentication - provide client credentials using the
|
||||
following environment variables
|
||||
|
||||
::
|
||||
|
||||
'SPOTIPY_CLIENT_USERNAME'
|
||||
'SPOTIPY_CLIENT_ID'
|
||||
'SPOTIPY_CLIENT_SECRET'
|
||||
'SPOTIPY_REDIRECT_URI'
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from spotipy import (
|
||||
CLIENT_CREDS_ENV_VARS as CCEV,
|
||||
prompt_for_user_token,
|
||||
Spotify,
|
||||
SpotifyException,
|
||||
)
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.pardir))
|
||||
|
||||
|
||||
class AuthTestSpotipy(unittest.TestCase):
|
||||
"""
|
||||
These tests require user authentication - provide client credentials using
|
||||
the following environment variables
|
||||
|
||||
::
|
||||
|
||||
'SPOTIPY_CLIENT_USERNAME'
|
||||
'SPOTIPY_CLIENT_ID'
|
||||
'SPOTIPY_CLIENT_SECRET'
|
||||
'SPOTIPY_REDIRECT_URI'
|
||||
"""
|
||||
|
||||
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
|
||||
playlist_new_id = "spotify:playlist:7GlxpQjjxRjmbb3RP2rDqI"
|
||||
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||
"spotify:track:7IHOIqZUUInxjVkko181PB",
|
||||
"4VrWlk8IQxevMvERoX08iC",
|
||||
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
|
||||
|
||||
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||
"spotify:track:7IHOIqZUUInxjVkko181PB"]
|
||||
|
||||
other_tracks = ["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
|
||||
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
|
||||
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
|
||||
|
||||
album_ids = ["spotify:album:6kL09DaURb7rAoqqaA51KU",
|
||||
"spotify:album:6RTzC0rDbvagTSJLlY7AKl"]
|
||||
|
||||
bad_id = 'BAD_ID'
|
||||
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
|
||||
missing = list(filter(lambda var: not os.getenv(CCEV[var]), CCEV))
|
||||
|
||||
if missing:
|
||||
raise Exception(
|
||||
('Please set the client credentials for the test application'
|
||||
' using the following environment variables: {}').format(
|
||||
CCEV.values()))
|
||||
|
||||
self.username = os.getenv(CCEV['client_username'])
|
||||
|
||||
self.scope = (
|
||||
'playlist-modify-public '
|
||||
'user-library-read '
|
||||
'user-follow-read '
|
||||
'user-library-modify '
|
||||
'user-read-private '
|
||||
'user-top-read '
|
||||
'user-follow-modify'
|
||||
)
|
||||
|
||||
self.token = prompt_for_user_token(self.username, scope=self.scope)
|
||||
|
||||
self.spotify = Spotify(auth=self.token)
|
||||
|
||||
def test_track_bad_id(self):
|
||||
try:
|
||||
self.spotify.track(self.bad_id)
|
||||
self.assertTrue(False)
|
||||
except SpotifyException:
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_basic_user_profile(self):
|
||||
user = self.spotify.user(self.username)
|
||||
self.assertTrue(user['id'] == self.username.lower())
|
||||
|
||||
def test_current_user(self):
|
||||
user = self.spotify.current_user()
|
||||
self.assertTrue(user['id'] == self.username.lower())
|
||||
|
||||
def test_me(self):
|
||||
user = self.spotify.me()
|
||||
self.assertTrue(user['id'] == self.username.lower())
|
||||
|
||||
def test_user_playlists(self):
|
||||
playlists = self.spotify.user_playlists(self.username, limit=5)
|
||||
self.assertTrue('items' in playlists)
|
||||
self.assertTrue(len(playlists['items']) == 5)
|
||||
|
||||
def test_user_playlist_tracks(self):
|
||||
playlists = self.spotify.user_playlists(self.username, limit=5)
|
||||
self.assertTrue('items' in playlists)
|
||||
for playlist in playlists['items']:
|
||||
user = playlist['owner']['id']
|
||||
pid = playlist['id']
|
||||
results = self.spotify.user_playlist_tracks(user, pid)
|
||||
self.assertTrue(len(results['items']) >= 0)
|
||||
|
||||
# known API issue currently causes this test to fail
|
||||
# the issue is that the API doesn't currently respect the
|
||||
# limit parameter
|
||||
# def user_playlist_tracks(self, user, playlist_id=None, fields=None,
|
||||
# limit=100, offset=0):
|
||||
# self.assertTrue(len(playlists['items']) == 5)
|
||||
|
||||
def test_current_user_saved_albums(self):
|
||||
# List
|
||||
albums = self.spotify.current_user_saved_albums()
|
||||
self.assertTrue(len(albums['items']) == 1)
|
||||
|
||||
# Add
|
||||
self.spotify.current_user_saved_albums_add(self.album_ids)
|
||||
|
||||
# Contains
|
||||
self.assertTrue(
|
||||
self.spotify.current_user_saved_albums_contains(
|
||||
self.album_ids) == [
|
||||
True, True])
|
||||
|
||||
# Remove
|
||||
self.spotify.current_user_saved_albums_delete(self.album_ids)
|
||||
albums = self.spotify.current_user_saved_albums()
|
||||
self.assertTrue(len(albums['items']) == 1)
|
||||
|
||||
def test_current_user_playlists(self):
|
||||
playlists = self.spotify.current_user_playlists(limit=10)
|
||||
self.assertTrue('items' in playlists)
|
||||
self.assertTrue(len(playlists['items']) == 10)
|
||||
|
||||
def test_user_playlist_follow(self):
|
||||
self.spotify.user_playlist_follow_playlist(
|
||||
'plamere', '4erXB04MxwRAVqcUEpu30O')
|
||||
follows = self.spotify.user_playlist_is_following(
|
||||
'plamere', '4erXB04MxwRAVqcUEpu30O', [
|
||||
self.spotify.current_user()['id']])
|
||||
|
||||
self.assertTrue(len(follows) == 1, 'proper follows length')
|
||||
self.assertTrue(follows[0], 'is following')
|
||||
self.spotify.user_playlist_unfollow(
|
||||
'plamere', '4erXB04MxwRAVqcUEpu30O')
|
||||
|
||||
follows = self.spotify.user_playlist_is_following(
|
||||
'plamere', '4erXB04MxwRAVqcUEpu30O', [
|
||||
self.spotify.current_user()['id']])
|
||||
self.assertTrue(len(follows) == 1, 'proper follows length')
|
||||
self.assertFalse(follows[0], 'is no longer following')
|
||||
|
||||
def test_current_user_saved_tracks(self):
|
||||
tracks = self.spotify.current_user_saved_tracks()
|
||||
self.assertTrue(len(tracks['items']) > 0)
|
||||
|
||||
def test_current_user_save_and_unsave_tracks(self):
|
||||
tracks = self.spotify.current_user_saved_tracks()
|
||||
total = tracks['total']
|
||||
self.spotify.current_user_saved_tracks_add(self.four_tracks)
|
||||
|
||||
tracks = self.spotify.current_user_saved_tracks()
|
||||
new_total = tracks['total']
|
||||
self.assertTrue(new_total - total == len(self.four_tracks))
|
||||
|
||||
tracks = self.spotify.current_user_saved_tracks_delete(
|
||||
self.four_tracks)
|
||||
tracks = self.spotify.current_user_saved_tracks()
|
||||
new_total = tracks['total']
|
||||
self.assertTrue(new_total == total)
|
||||
|
||||
def test_categories(self):
|
||||
response = self.spotify.categories()
|
||||
self.assertTrue(len(response['categories']) > 0)
|
||||
|
||||
def test_category_playlists(self):
|
||||
response = self.spotify.categories()
|
||||
for cat in response['categories']['items']:
|
||||
cat_id = cat['id']
|
||||
response = self.spotify.category_playlists(category_id=cat_id)
|
||||
if len(response['playlists']["items"]) > 0:
|
||||
break
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_new_releases(self):
|
||||
response = self.spotify.new_releases()
|
||||
self.assertTrue(len(response['albums']) > 0)
|
||||
|
||||
def test_featured_releases(self):
|
||||
response = self.spotify.featured_playlists()
|
||||
self.assertTrue(len(response['playlists']) > 0)
|
||||
|
||||
def test_current_user_follows(self):
|
||||
response = self.spotify.current_user_followed_artists()
|
||||
artists = response['artists']
|
||||
self.assertTrue(len(artists['items']) > 0)
|
||||
|
||||
def test_current_user_top_tracks(self):
|
||||
response = self.spotify.current_user_top_tracks()
|
||||
items = response['items']
|
||||
self.assertTrue(len(items) > 0)
|
||||
|
||||
def test_current_user_top_artists(self):
|
||||
response = self.spotify.current_user_top_artists()
|
||||
items = response['items']
|
||||
self.assertTrue(len(items) > 0)
|
||||
|
||||
def get_or_create_spotify_playlist(self, playlist_name):
|
||||
playlists = self.spotify.user_playlists(self.username)
|
||||
while playlists:
|
||||
for item in playlists['items']:
|
||||
if item['name'] == playlist_name:
|
||||
return item['id']
|
||||
playlists = self.spotify.next(playlists)
|
||||
playlist = self.spotify.user_playlist_create(
|
||||
self.username, playlist_name)
|
||||
playlist_id = playlist['uri']
|
||||
return playlist_id
|
||||
|
||||
def test_user_playlist_ops(self):
|
||||
sp = self.spotify
|
||||
# create empty playlist
|
||||
playlist_id = self.get_or_create_spotify_playlist(
|
||||
'spotipy-testing-playlist-1')
|
||||
|
||||
# remove all tracks from it
|
||||
sp.user_playlist_replace_tracks(
|
||||
self.username, playlist_id, [])
|
||||
playlist = sp.user_playlist(self.username, playlist_id)
|
||||
self.assertTrue(playlist['tracks']['total'] == 0)
|
||||
self.assertTrue(len(playlist['tracks']['items']) == 0)
|
||||
|
||||
# add tracks to it
|
||||
sp.user_playlist_add_tracks(
|
||||
self.username, playlist_id, self.four_tracks)
|
||||
playlist = sp.user_playlist(self.username, playlist_id)
|
||||
self.assertTrue(playlist['tracks']['total'] == 4)
|
||||
self.assertTrue(len(playlist['tracks']['items']) == 4)
|
||||
|
||||
# remove two tracks from it
|
||||
|
||||
sp.user_playlist_remove_all_occurrences_of_tracks(self.username,
|
||||
playlist_id,
|
||||
self.two_tracks)
|
||||
playlist = sp.user_playlist(self.username, playlist_id)
|
||||
self.assertTrue(playlist['tracks']['total'] == 2)
|
||||
self.assertTrue(len(playlist['tracks']['items']) == 2)
|
||||
|
||||
# replace with 3 other tracks
|
||||
sp.user_playlist_replace_tracks(self.username,
|
||||
playlist_id,
|
||||
self.other_tracks)
|
||||
playlist = sp.user_playlist(self.username, playlist_id)
|
||||
self.assertTrue(playlist['tracks']['total'] == 3)
|
||||
self.assertTrue(len(playlist['tracks']['items']) == 3)
|
||||
|
||||
def test_playlist(self):
|
||||
# New playlist ID
|
||||
pl = self.spotify.playlist(self.playlist_new_id)
|
||||
self.assertTrue(pl["tracks"]["total"] > 0)
|
||||
|
||||
# Old playlist ID
|
||||
pl = self.spotify.playlist(self.playlist)
|
||||
self.assertTrue(pl["tracks"]["total"] > 0)
|
||||
|
||||
def test_user_follows_and_unfollows_artist(self):
|
||||
# Initially follows 1 artist
|
||||
res = self.spotify.current_user_followed_artists()
|
||||
self.assertTrue(res['artists']['total'] == 1)
|
||||
|
||||
# Follow 2 more artists
|
||||
artists = ["6DPYiyq5kWVQS4RGwxzPC7", "0NbfKEOTQCcwd6o7wSDOHI"]
|
||||
self.spotify.user_follow_artists(artists)
|
||||
res = self.spotify.current_user_followed_artists()
|
||||
self.assertTrue(res['artists']['total'] == 3)
|
||||
|
||||
# Unfollow these 2 artists
|
||||
self.spotify.user_unfollow_artists(artists)
|
||||
res = self.spotify.current_user_followed_artists()
|
||||
self.assertTrue(res['artists']['total'] == 1)
|
||||
|
||||
def test_user_follows_and_unfollows_user(self):
|
||||
# TODO improve after implementing `me/following/contains`
|
||||
users = ["11111204", "xlqeojt6n7on0j7coh9go8ifd"]
|
||||
|
||||
# Follow 2 more users
|
||||
self.spotify.user_follow_users(users)
|
||||
|
||||
# Unfollow these 2 users
|
||||
self.spotify.user_unfollow_users(users)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
91
tests/test_auth2.py
Normal file
91
tests/test_auth2.py
Normal file
@ -0,0 +1,91 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
These tests require user authentication - provide client credentials using the
|
||||
following environment variables
|
||||
|
||||
::
|
||||
|
||||
'SPOTIPY_CLIENT_USERNAME'
|
||||
'SPOTIPY_CLIENT_ID'
|
||||
'SPOTIPY_CLIENT_SECRET'
|
||||
'SPOTIPY_REDIRECT_URI'
|
||||
"""
|
||||
|
||||
from spotipy import (
|
||||
Spotify,
|
||||
SpotifyClientCredentials,
|
||||
)
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.pardir))
|
||||
|
||||
|
||||
class AuthTestSpotipy(unittest.TestCase):
|
||||
"""
|
||||
These tests require user authentication - provide client credentials using
|
||||
the following environment variables
|
||||
|
||||
::
|
||||
|
||||
'SPOTIPY_CLIENT_USERNAME'
|
||||
'SPOTIPY_CLIENT_ID'
|
||||
'SPOTIPY_CLIENT_SECRET'
|
||||
'SPOTIPY_REDIRECT_URI'
|
||||
"""
|
||||
|
||||
playlist = "spotify:user:plamere:playlist:2oCEWyyAPbZp9xhVSxZavx"
|
||||
four_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||
"spotify:track:7IHOIqZUUInxjVkko181PB",
|
||||
"4VrWlk8IQxevMvERoX08iC",
|
||||
"http://open.spotify.com/track/3cySlItpiPiIAzU3NyHCJf"]
|
||||
|
||||
two_tracks = ["spotify:track:6RtPijgfPKROxEzTHNRiDp",
|
||||
"spotify:track:7IHOIqZUUInxjVkko181PB"]
|
||||
|
||||
other_tracks = ["spotify:track:2wySlB6vMzCbQrRnNGOYKa",
|
||||
"spotify:track:29xKs5BAHlmlX1u4gzQAbJ",
|
||||
"spotify:track:1PB7gRWcvefzu7t3LJLUlf"]
|
||||
|
||||
bad_id = 'BAD_ID'
|
||||
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
self.spotify = Spotify(
|
||||
client_credentials_manager=SpotifyClientCredentials())
|
||||
self.spotify.trace = False
|
||||
|
||||
def test_audio_analysis(self):
|
||||
result = self.spotify.audio_analysis(self.four_tracks[0])
|
||||
assert('beats' in result)
|
||||
|
||||
def test_audio_features(self):
|
||||
results = self.spotify.audio_features(self.four_tracks)
|
||||
self.assertTrue(len(results) == len(self.four_tracks))
|
||||
for track in results:
|
||||
assert('speechiness' in track)
|
||||
|
||||
def test_audio_features_with_bad_track(self):
|
||||
bad_tracks = []
|
||||
bad_tracks = ['spotify:track:bad']
|
||||
input = self.four_tracks + bad_tracks
|
||||
results = self.spotify.audio_features(input)
|
||||
self.assertTrue(len(results) == len(input))
|
||||
for track in results[:-1]:
|
||||
if track is not None:
|
||||
assert('speechiness' in track)
|
||||
self.assertTrue(results[-1] is None)
|
||||
|
||||
def test_recommendations(self):
|
||||
results = self.spotify.recommendations(
|
||||
seed_tracks=self.four_tracks,
|
||||
min_danceability=0,
|
||||
max_loudness=0,
|
||||
target_popularity=50)
|
||||
self.assertTrue(len(results['tracks']) == 20)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
43
tests/test_client_credentials.py
Normal file
43
tests/test_client_credentials.py
Normal file
@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
""" Client Credentials Requests Tests """
|
||||
|
||||
from spotipy import (
|
||||
Spotify,
|
||||
SpotifyClientCredentials,
|
||||
)
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.pardir))
|
||||
|
||||
|
||||
class ClientCredentialsTestSpotipy(unittest.TestCase):
|
||||
"""
|
||||
These tests require user authentication - provide client credentials using
|
||||
the following environment variables
|
||||
|
||||
::
|
||||
|
||||
'SPOTIPY_CLIENT_USERNAME'
|
||||
'SPOTIPY_CLIENT_ID'
|
||||
'SPOTIPY_CLIENT_SECRET'
|
||||
'SPOTIPY_REDIRECT_URI'
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
self.spotify = Spotify(
|
||||
client_credentials_manager=SpotifyClientCredentials())
|
||||
self.spotify.trace = False
|
||||
|
||||
muse_urn = 'spotify:artist:12Chz98pHFMPJEknJQMWvI'
|
||||
|
||||
def test_request_with_token(self):
|
||||
artist = self.spotify.artist(self.muse_urn)
|
||||
self.assertTrue(artist['name'] == 'Muse')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@ -1,13 +1,20 @@
|
||||
from spotipy.oauth2 import SpotifyOAuth
|
||||
import json
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import six.moves.urllib.parse as urllibparse
|
||||
from spotipy import SpotifyOAuth
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.pardir))
|
||||
|
||||
|
||||
try:
|
||||
import unittest.mock as mock
|
||||
except ImportError:
|
||||
import mock
|
||||
import six.moves.urllib.parse as urllibparse
|
||||
|
||||
patch = mock.patch
|
||||
DEFAULT = mock.DEFAULT
|
||||
@ -166,4 +173,5 @@ class TestSpotifyOAuth(unittest.TestCase):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
unittest.main()
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
# -*- coding: latin-1 -*-
|
||||
import spotipy
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import pprint
|
||||
|
||||
import requests
|
||||
from spotipy.client import SpotifyException
|
||||
from spotipy.oauth2 import SpotifyClientCredentials
|
||||
@ -9,6 +11,18 @@ from spotipy.oauth2 import SpotifyClientCredentials
|
||||
|
||||
class TestSpotipy(unittest.TestCase):
|
||||
|
||||
"""
|
||||
These tests require user authentication - provide client credentials using
|
||||
the following environment variables
|
||||
|
||||
::
|
||||
|
||||
'SPOTIPY_CLIENT_USERNAME'
|
||||
'SPOTIPY_CLIENT_ID'
|
||||
'SPOTIPY_CLIENT_SECRET'
|
||||
'SPOTIPY_REDIRECT_URI'
|
||||
"""
|
||||
|
||||
creep_urn = 'spotify:track:3HfB5hBU0dmBt8T0iCmH42'
|
||||
creep_id = '3HfB5hBU0dmBt8T0iCmH42'
|
||||
creep_url = 'http://open.spotify.com/track/3HfB5hBU0dmBt8T0iCmH42'
|
||||
@ -20,9 +34,9 @@ class TestSpotipy(unittest.TestCase):
|
||||
radiohead_urn = 'spotify:artist:4Z8W4fKeB5YxbusRsdQVPb'
|
||||
angeles_haydn_urn = 'spotify:album:1vAbqAeuJVWNAe7UR00bdM'
|
||||
|
||||
|
||||
bad_id = 'BAD_ID'
|
||||
|
||||
|
||||
def setUp(self):
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
self.spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||
@ -43,20 +57,22 @@ class TestSpotipy(unittest.TestCase):
|
||||
def test_album_tracks(self):
|
||||
results = self.spotify.album_tracks(self.pinkerton_urn)
|
||||
self.assertTrue(len(results['items']) == 10)
|
||||
|
||||
|
||||
def test_album_tracks_many(self):
|
||||
results = self.spotify.album_tracks(self.angeles_haydn_urn)
|
||||
tracks = results['items']
|
||||
total, received = results['total'], len(tracks)
|
||||
while received < total:
|
||||
results = self.spotify.album_tracks(self.angeles_haydn_urn, offset=received)
|
||||
results = self.spotify.album_tracks(
|
||||
self.angeles_haydn_urn, offset=received)
|
||||
tracks.extend(results['items'])
|
||||
received = len(tracks)
|
||||
|
||||
self.assertEqual(received, total)
|
||||
|
||||
def test_albums(self):
|
||||
results = self.spotify.albums([self.pinkerton_urn, self.pablo_honey_urn])
|
||||
results = self.spotify.albums(
|
||||
[self.pinkerton_urn, self.pablo_honey_urn])
|
||||
self.assertTrue('albums' in results)
|
||||
self.assertTrue(len(results['albums']) == 2)
|
||||
|
||||
@ -74,9 +90,9 @@ class TestSpotipy(unittest.TestCase):
|
||||
|
||||
def test_track_bad_urn(self):
|
||||
try:
|
||||
track = self.spotify.track(self.el_scorcho_bad_urn)
|
||||
self.spotify.track(self.el_scorcho_bad_urn)
|
||||
self.assertTrue(False)
|
||||
except spotipy.SpotifyException:
|
||||
except SpotifyException:
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_tracks(self):
|
||||
@ -125,18 +141,19 @@ class TestSpotipy(unittest.TestCase):
|
||||
def test_search_timeout(self):
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager, requests_timeout=.1)
|
||||
|
||||
try:
|
||||
results = sp.search(q='my*', type='track')
|
||||
sp.search(q='my*', type='track')
|
||||
self.assertTrue(False, 'unexpected search timeout')
|
||||
except requests.exceptions.Timeout:
|
||||
self.assertTrue(True, 'expected search timeout')
|
||||
|
||||
|
||||
def test_album_search(self):
|
||||
results = self.spotify.search(q='weezer pinkerton', type='album')
|
||||
self.assertTrue('albums' in results)
|
||||
self.assertTrue(len(results['albums']['items']) > 0)
|
||||
self.assertTrue(results['albums']['items'][0]['name'].find('Pinkerton') >= 0)
|
||||
self.assertTrue(results['albums']['items'][0]
|
||||
['name'].find('Pinkerton') >= 0)
|
||||
|
||||
def test_track_search(self):
|
||||
results = self.spotify.search(q='el scorcho weezer', type='track')
|
||||
@ -150,27 +167,20 @@ class TestSpotipy(unittest.TestCase):
|
||||
|
||||
def test_track_bad_id(self):
|
||||
try:
|
||||
track = self.spotify.track(self.bad_id)
|
||||
self.spotify.track(self.bad_id)
|
||||
self.assertTrue(False)
|
||||
except spotipy.SpotifyException:
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_track_bad_id(self):
|
||||
try:
|
||||
track = self.spotify.track(self.bad_id)
|
||||
self.assertTrue(False)
|
||||
except spotipy.SpotifyException:
|
||||
except SpotifyException:
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_unauthenticated_post_fails(self):
|
||||
with self.assertRaises(SpotifyException) as cm:
|
||||
self.spotify.user_playlist_create("spotify", "Best hits of the 90s")
|
||||
self.spotify.user_playlist_create(
|
||||
"spotify", "Best hits of the 90s")
|
||||
self.assertTrue(cm.exception.http_status == 401 or
|
||||
cm.exception.http_status == 403)
|
||||
cm.exception.http_status == 403)
|
||||
|
||||
def test_custom_requests_session(self):
|
||||
from requests import Session
|
||||
sess = Session()
|
||||
sess = requests.Session()
|
||||
sess.headers["user-agent"] = "spotipy-test"
|
||||
client_credentials_manager = SpotifyClientCredentials()
|
||||
with_custom_session = spotipy.Spotify(client_credentials_manager=client_credentials_manager, requests_session=sess)
|
||||
@ -184,7 +194,6 @@ class TestSpotipy(unittest.TestCase):
|
||||
self.assertTrue(with_no_session.user(user="akx")["uri"] == "spotify:user:akx")
|
||||
|
||||
|
||||
|
||||
'''
|
||||
Need tests for:
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user