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
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -52,6 +52,5 @@ coverage.xml
|
|||||||
# Sphinx documentation
|
# Sphinx documentation
|
||||||
docs/_build/
|
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
|
|
||||||
41
README.md
41
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
|
## Documentation
|
||||||
|
|
||||||
@ -43,7 +44,7 @@ sp = spotipy.Spotify()
|
|||||||
|
|
||||||
results = sp.search(q='weezer', limit=20)
|
results = sp.search(q='weezer', limit=20)
|
||||||
for i, t in enumerate(results['tracks']['items']):
|
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).
|
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).
|
||||||
@ -52,35 +53,3 @@ A full set of examples can be found in the [online documentation](http://spotipy
|
|||||||
## Reporting Issues
|
## 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.
|
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
|
|
||||||
|
|||||||
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
|
|
||||||
|
|
||||||
@ -27,6 +27,7 @@ released by the artist 'Birdy'::
|
|||||||
Here's another example showing how to get 30 second samples and cover art
|
Here's another example showing how to get 30 second samples and cover art
|
||||||
for the top 10 tracks for Led Zeppelin::
|
for the top 10 tracks for Led Zeppelin::
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
import spotipy
|
import spotipy
|
||||||
|
|
||||||
lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp'
|
lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp'
|
||||||
@ -35,14 +36,15 @@ for the top 10 tracks for Led Zeppelin::
|
|||||||
results = spotify.artist_top_tracks(lz_uri)
|
results = spotify.artist_top_tracks(lz_uri)
|
||||||
|
|
||||||
for track in results['tracks'][:10]:
|
for track in results['tracks'][:10]:
|
||||||
print 'track : ' + track['name']
|
print('track : ' + track['name'])
|
||||||
print 'audio : ' + track['preview_url']
|
print('audio : ' + track['preview_url'])
|
||||||
print 'cover art: ' + track['album']['images'][0]['url']
|
print('cover art: ' + track['album']['images'][0]['url'])
|
||||||
print
|
print()
|
||||||
|
|
||||||
Finally, here's an example that will get the URL for an artist image given the
|
Finally, here's an example that will get the URL for an artist image given the
|
||||||
artist's name::
|
artist's name::
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
import spotipy
|
import spotipy
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -57,7 +59,7 @@ artist's name::
|
|||||||
items = results['artists']['items']
|
items = results['artists']['items']
|
||||||
if len(items) > 0:
|
if len(items) > 0:
|
||||||
artist = items[0]
|
artist = items[0]
|
||||||
print artist['name'], artist['images'][0]['url']
|
print(artist['name'], artist['images'][0]['url'])
|
||||||
|
|
||||||
|
|
||||||
Features
|
Features
|
||||||
@ -87,10 +89,11 @@ Non-Authorized requests
|
|||||||
For methods that do not require authorization, simply create a Spotify object
|
For methods that do not require authorization, simply create a Spotify object
|
||||||
and start making method calls like so::
|
and start making method calls like so::
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
import spotipy
|
import spotipy
|
||||||
spotify = spotipy.Spotify()
|
spotify = spotipy.Spotify()
|
||||||
results = spotify.search(q='artist:' + name, type='artist')
|
results = spotify.search(q='artist:' + name, type='artist')
|
||||||
print results
|
print(results)
|
||||||
|
|
||||||
Authorized requests
|
Authorized requests
|
||||||
=======================
|
=======================
|
||||||
@ -99,16 +102,18 @@ generate an authorization token that indicates that the user has granted
|
|||||||
permission for your application to perform the given task. You will need to
|
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.
|
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
|
Even if your script does not have an accessible URL you will need to specify one
|
||||||
when registering your application where the spotify authentication API will
|
when registering your application which the Spotify authentication server will
|
||||||
redirect to after successful login. The URL doesn't need to work or be
|
redirect to after successful login. The URL doesn't need to be publicly
|
||||||
accessible, you can specify "http://localhost/", after successful login you
|
accessible, so you can specify "http://localhost/", and after succesfully
|
||||||
just need to copy the "http://localhost/?code=..." URL from your browser
|
authenticating your app, you can simply copy the
|
||||||
and paste it to the console where your script is running.
|
"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
|
`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:
|
*spotipy* supports two authorization flows:
|
||||||
@ -127,7 +132,7 @@ To support the **Authorization Code Flow** *Spotipy* provides a
|
|||||||
utility method ``util.prompt_for_user_token`` that will attempt to authorize the
|
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::
|
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::
|
you can set environment variables like so::
|
||||||
@ -140,12 +145,13 @@ Call ``util.prompt_for_user_token`` method with the username and the
|
|||||||
desired scope (see `Using
|
desired scope (see `Using
|
||||||
Scopes <https://developer.spotify.com/web-api/using-scopes/>`_ for information
|
Scopes <https://developer.spotify.com/web-api/using-scopes/>`_ for information
|
||||||
about scopes) and credentials. This will coordinate the user authorization via
|
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
|
with the authorization token appended. The credentials are cached locally and
|
||||||
are used to automatically re-authorized expired tokens.
|
are used to automatically re-authorized expired tokens.
|
||||||
|
|
||||||
Here's an example of getting user authorization to read a user's saved tracks::
|
Here's an example of getting user authorization to read a user's saved tracks::
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
import sys
|
import sys
|
||||||
import spotipy
|
import spotipy
|
||||||
import spotipy.util as util
|
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:
|
if len(sys.argv) > 1:
|
||||||
username = sys.argv[1]
|
username = sys.argv[1]
|
||||||
else:
|
else:
|
||||||
print "Usage: %s username" % (sys.argv[0],)
|
print("Usage: %s username" % (sys.argv[0],))
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
token = util.prompt_for_user_token(username, scope)
|
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()
|
results = sp.current_user_saved_tracks()
|
||||||
for item in results['items']:
|
for item in results['items']:
|
||||||
track = item['track']
|
track = item['track']
|
||||||
print track['name'] + ' - ' + track['artists'][0]['name']
|
print(track['name'] + ' - ' + track['artists'][0]['name'])
|
||||||
else:
|
else:
|
||||||
print "Can't get token for", username
|
print("Can't get token for", username)
|
||||||
|
|
||||||
Client Credentials Flow
|
Client Credentials Flow
|
||||||
=======================
|
=======================
|
||||||
@ -217,6 +223,7 @@ Here are a few more examples of using *Spotipy*.
|
|||||||
|
|
||||||
Add tracks to a playlist::
|
Add tracks to a playlist::
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
import pprint
|
import pprint
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -228,7 +235,7 @@ Add tracks to a playlist::
|
|||||||
playlist_id = sys.argv[2]
|
playlist_id = sys.argv[2]
|
||||||
track_ids = sys.argv[3:]
|
track_ids = sys.argv[3:]
|
||||||
else:
|
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()
|
sys.exit()
|
||||||
|
|
||||||
scope = 'playlist-modify-public'
|
scope = 'playlist-modify-public'
|
||||||
@ -238,15 +245,16 @@ Add tracks to a playlist::
|
|||||||
sp = spotipy.Spotify(auth=token)
|
sp = spotipy.Spotify(auth=token)
|
||||||
sp.trace = False
|
sp.trace = False
|
||||||
results = sp.user_playlist_add_tracks(username, playlist_id, track_ids)
|
results = sp.user_playlist_add_tracks(username, playlist_id, track_ids)
|
||||||
print results
|
print(results)
|
||||||
else:
|
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 the contents of every playlist owned by a user::
|
||||||
|
|
||||||
# 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
|
||||||
import sys
|
import sys
|
||||||
import spotipy
|
import spotipy
|
||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
@ -254,16 +262,16 @@ Shows the contents of every playlist owned by a user::
|
|||||||
def show_tracks(tracks):
|
def show_tracks(tracks):
|
||||||
for i, item in enumerate(tracks['items']):
|
for i, item in enumerate(tracks['items']):
|
||||||
track = item['track']
|
track = item['track']
|
||||||
print " %d %32.32s %s" % (i, track['artists'][0]['name'],
|
print(" %d %32.32s %s" % (i, track['artists'][0]['name'],
|
||||||
track['name'])
|
track['name']))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
username = sys.argv[1]
|
username = sys.argv[1]
|
||||||
else:
|
else:
|
||||||
print "Whoops, need your username!"
|
print("Whoops, need your username!")
|
||||||
print "usage: python user_playlists.py [username]"
|
print("usage: python user_playlists.py [username]")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
token = util.prompt_for_user_token(username)
|
token = util.prompt_for_user_token(username)
|
||||||
@ -273,9 +281,9 @@ Shows the contents of every playlist owned by a user::
|
|||||||
playlists = sp.user_playlists(username)
|
playlists = sp.user_playlists(username)
|
||||||
for playlist in playlists['items']:
|
for playlist in playlists['items']:
|
||||||
if playlist['owner']['id'] == username:
|
if playlist['owner']['id'] == username:
|
||||||
print
|
print()
|
||||||
print playlist['name']
|
print(playlist['name'])
|
||||||
print ' total tracks', playlist['tracks']['total']
|
print (' total tracks', playlist['tracks']['total'])
|
||||||
results = sp.user_playlist(username, playlist['id'],
|
results = sp.user_playlist(username, playlist['id'],
|
||||||
fields="tracks,next")
|
fields="tracks,next")
|
||||||
tracks = results['tracks']
|
tracks = results['tracks']
|
||||||
@ -284,7 +292,7 @@ Shows the contents of every playlist owned by a user::
|
|||||||
tracks = sp.next(tracks)
|
tracks = sp.next(tracks)
|
||||||
show_tracks(tracks)
|
show_tracks(tracks)
|
||||||
else:
|
else:
|
||||||
print "Can't get token for", username
|
print("Can't get token for", username)
|
||||||
|
|
||||||
|
|
||||||
More Examples
|
More Examples
|
||||||
@ -356,10 +364,12 @@ Spotipy authored by Paul Lamere (plamere) with contributions by:
|
|||||||
- corycorycory // corycorycory
|
- corycorycory // corycorycory
|
||||||
- Nathan Coleman // nathancoleman
|
- Nathan Coleman // nathancoleman
|
||||||
- Michael Birtwell // mbirtwell
|
- Michael Birtwell // mbirtwell
|
||||||
|
- Harrison Hayes // Harrison97
|
||||||
|
- Stephane Bruckert // stephanebruckert
|
||||||
|
|
||||||
License
|
License
|
||||||
=======
|
=======
|
||||||
https://github.com/plamere/spotipy/blob/master/LICENSE.txt
|
https://github.com/plamere/spotipy/blob/master/LICENSE.md
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
|
|
||||||
# Adds tracks to a playlist
|
# Adds tracks to a playlist
|
||||||
|
|
||||||
import pprint
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import spotipy
|
import spotipy
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import spotipy
|
|||||||
''' shows the albums and tracks for a given artist.
|
''' shows the albums and tracks for a given artist.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def get_artist(name):
|
def get_artist(name):
|
||||||
results = sp.search(q='artist:' + name, type='artist')
|
results = sp.search(q='artist:' + name, type='artist')
|
||||||
items = results['artists']['items']
|
items = results['artists']['items']
|
||||||
@ -13,6 +14,7 @@ def get_artist(name):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def show_artist_albums(artist):
|
def show_artist_albums(artist):
|
||||||
albums = []
|
albums = []
|
||||||
results = sp.artist_albums(artist['id'], album_type='album')
|
results = sp.artist_albums(artist['id'], album_type='album')
|
||||||
@ -21,13 +23,14 @@ def show_artist_albums(artist):
|
|||||||
results = sp.next(results)
|
results = sp.next(results)
|
||||||
albums.extend(results['items'])
|
albums.extend(results['items'])
|
||||||
seen = set() # to avoid dups
|
seen = set() # to avoid dups
|
||||||
albums.sort(key=lambda album:album['name'].lower())
|
albums.sort(key=lambda album: album['name'].lower())
|
||||||
for album in albums:
|
for album in albums:
|
||||||
name = album['name']
|
name = album['name']
|
||||||
if name not in seen:
|
if name not in seen:
|
||||||
print((' ' + name))
|
print((' ' + name))
|
||||||
seen.add(name)
|
seen.add(name)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import spotipy
|
|||||||
''' shows the albums and tracks for a given artist.
|
''' shows the albums and tracks for a given artist.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def get_artist(name):
|
def get_artist(name):
|
||||||
results = sp.search(q='artist:' + name, type='artist')
|
results = sp.search(q='artist:' + name, type='artist')
|
||||||
items = results['artists']['items']
|
items = results['artists']['items']
|
||||||
@ -13,6 +14,7 @@ def get_artist(name):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def show_album_tracks(album):
|
def show_album_tracks(album):
|
||||||
tracks = []
|
tracks = []
|
||||||
results = sp.album_tracks(album['id'])
|
results = sp.album_tracks(album['id'])
|
||||||
@ -25,6 +27,7 @@ def show_album_tracks(album):
|
|||||||
print()
|
print()
|
||||||
print(track)
|
print(track)
|
||||||
|
|
||||||
|
|
||||||
def show_artist_albums(id):
|
def show_artist_albums(id):
|
||||||
albums = []
|
albums = []
|
||||||
results = sp.artist_albums(artist['id'], album_type='album')
|
results = sp.artist_albums(artist['id'], album_type='album')
|
||||||
@ -36,17 +39,19 @@ def show_artist_albums(id):
|
|||||||
unique = set() # skip duplicate albums
|
unique = set() # skip duplicate albums
|
||||||
for album in albums:
|
for album in albums:
|
||||||
name = album['name'].lower()
|
name = album['name'].lower()
|
||||||
if not name in unique:
|
if name not in unique:
|
||||||
print(name)
|
print(name)
|
||||||
unique.add(name)
|
unique.add(name)
|
||||||
show_album_tracks(album)
|
show_album_tracks(album)
|
||||||
|
|
||||||
|
|
||||||
def show_artist(artist):
|
def show_artist(artist):
|
||||||
print('====', artist['name'], '====')
|
print('====', artist['name'], '====')
|
||||||
print('Popularity: ', artist['popularity'])
|
print('Popularity: ', artist['popularity'])
|
||||||
if len(artist['genres']) > 0:
|
if len(artist['genres']) > 0:
|
||||||
print('Genres: ', ','.join(artist['genres']))
|
print('Genres: ', ','.join(artist['genres']))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
|
|||||||
@ -7,7 +7,8 @@ import spotipy
|
|||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
sp.trace=False
|
sp.trace = False
|
||||||
|
|
||||||
|
|
||||||
def get_artist(name):
|
def get_artist(name):
|
||||||
results = sp.search(q='artist:' + name, type='artist')
|
results = sp.search(q='artist:' + name, type='artist')
|
||||||
@ -17,11 +18,12 @@ def get_artist(name):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def show_recommendations_for_artist(artist):
|
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']:
|
for track in results['tracks']:
|
||||||
print track['name'], '-', track['artists'][0]['name']
|
print(track['name'], '-', track['artists'][0]['name'])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
@ -32,4 +34,4 @@ if __name__ == '__main__':
|
|||||||
if artist:
|
if artist:
|
||||||
show_recommendations_for_artist(artist)
|
show_recommendations_for_artist(artist)
|
||||||
else:
|
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)
|
analysis = sp.audio_analysis(tid)
|
||||||
delta = time.time() - start
|
delta = time.time() - start
|
||||||
print(json.dumps(analysis, indent=4))
|
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()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
sp.trace=False
|
sp.trace = False
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
artist_name = ' '.join(sys.argv[1:])
|
artist_name = ' '.join(sys.argv[1:])
|
||||||
@ -33,4 +33,4 @@ for feature in features:
|
|||||||
analysis = sp._get(feature['analysis_url'])
|
analysis = sp._get(feature['analysis_url'])
|
||||||
print(json.dumps(analysis, indent=4))
|
print(json.dumps(analysis, indent=4))
|
||||||
print()
|
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()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
sp.trace=True
|
sp.trace = True
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
tids = sys.argv[1:]
|
tids = sys.argv[1:]
|
||||||
@ -22,4 +22,4 @@ if len(sys.argv) > 1:
|
|||||||
features = sp.audio_features(tids)
|
features = sp.audio_features(tids)
|
||||||
delta = time.time() - start
|
delta = time.time() - start
|
||||||
print(json.dumps(features, indent=4))
|
print(json.dumps(features, indent=4))
|
||||||
print ("features retrieved in %.2f seconds" % (delta,))
|
print("features retrieved in %.2f seconds" % (delta,))
|
||||||
|
|||||||
@ -24,7 +24,7 @@ if len(sys.argv) > 3:
|
|||||||
description = sys.argv[6]
|
description = sys.argv[6]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print ("Usage: %s username playlist_id name [public collaborative "
|
print("Usage: %s username playlist_id name [public collaborative "
|
||||||
"description]" % (sys.argv[0]))
|
"description]" % (sys.argv[0]))
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
@ -37,6 +37,6 @@ if token:
|
|||||||
results = sp.user_playlist_change_details(
|
results = sp.user_playlist_change_details(
|
||||||
username, playlist_id, name=name, public=public,
|
username, playlist_id, name=name, public=public,
|
||||||
collaborative=collaborative, description=description)
|
collaborative=collaborative, description=description)
|
||||||
print results
|
print(results)
|
||||||
else:
|
else:
|
||||||
print "Can't get token for", username
|
print("Can't get token for"), username
|
||||||
|
|||||||
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
import pprint
|
import pprint
|
||||||
import sys
|
import sys
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
import spotipy
|
import spotipy
|
||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
@ -14,16 +12,19 @@ if len(sys.argv) > 2:
|
|||||||
playlist_name = sys.argv[2]
|
playlist_name = sys.argv[2]
|
||||||
playlist_description = sys.argv[3]
|
playlist_description = sys.argv[3]
|
||||||
else:
|
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()
|
sys.exit()
|
||||||
|
|
||||||
token = util.prompt_for_user_token(username)
|
scope = "playlist-modify-public"
|
||||||
|
token = util.prompt_for_user_token(username, scope)
|
||||||
|
|
||||||
if token:
|
if token:
|
||||||
sp = spotipy.Spotify(auth=token)
|
sp = spotipy.Spotify(auth=token)
|
||||||
sp.trace = False
|
sp.trace = False
|
||||||
playlists = sp.user_playlist_create(username, playlist_name,
|
playlists = sp.user_playlist_create(username, playlist_name,
|
||||||
playlist_description)
|
description=playlist_description)
|
||||||
pprint.pprint(playlists)
|
pprint.pprint(playlists)
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
print("Can't get token for", username)
|
||||||
|
|||||||
@ -2,22 +2,18 @@
|
|||||||
|
|
||||||
from __future__ import print_function # (at top of module)
|
from __future__ import print_function # (at top of module)
|
||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import json
|
|
||||||
import spotipy
|
import spotipy
|
||||||
import time
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
sp.trace=True
|
sp.trace = True
|
||||||
try:
|
try:
|
||||||
print ('bad call 0')
|
print('bad call 0')
|
||||||
bad_artist_call = sp.artist('spotify:artist:12341234')
|
bad_artist_call = sp.artist('spotify:artist:12341234')
|
||||||
except spotipy.client.SpotifyException:
|
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')
|
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 sys
|
||||||
|
|
||||||
import spotipy
|
import spotipy
|
||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
import simplejson as json
|
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
username = sys.argv[1]
|
username = sys.argv[1]
|
||||||
@ -21,6 +19,6 @@ if token:
|
|||||||
sp.trace = False
|
sp.trace = False
|
||||||
results = sp.current_user_playlists(limit=50)
|
results = sp.current_user_playlists(limit=50)
|
||||||
for i, item in enumerate(results['items']):
|
for i, item in enumerate(results['items']):
|
||||||
print("%d %s" %(i, item['name']))
|
print("%d %s" % (i, item['name']))
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
print("Can't get token for", username)
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
# Shows the top artists for a user
|
# Shows the top artists for a user
|
||||||
|
|
||||||
import pprint
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import spotipy
|
import spotipy
|
||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
import simplejson as json
|
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
username = sys.argv[1]
|
username = sys.argv[1]
|
||||||
@ -21,10 +19,10 @@ if token:
|
|||||||
sp.trace = False
|
sp.trace = False
|
||||||
ranges = ['short_term', 'medium_term', 'long_term']
|
ranges = ['short_term', 'medium_term', 'long_term']
|
||||||
for range in ranges:
|
for range in ranges:
|
||||||
print "range:", range
|
print("range:", range)
|
||||||
results = sp.current_user_top_artists(time_range=range, limit=50)
|
results = sp.current_user_top_artists(time_range=range, limit=50)
|
||||||
for i, item in enumerate(results['items']):
|
for i, item in enumerate(results['items']):
|
||||||
print i, item['name']
|
print(i, item['name'])
|
||||||
print
|
print()
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
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 sys
|
||||||
|
|
||||||
import spotipy
|
import spotipy
|
||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
import simplejson as json
|
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
username = sys.argv[1]
|
username = sys.argv[1]
|
||||||
@ -21,11 +19,11 @@ if token:
|
|||||||
sp.trace = False
|
sp.trace = False
|
||||||
ranges = ['short_term', 'medium_term', 'long_term']
|
ranges = ['short_term', 'medium_term', 'long_term']
|
||||||
for range in ranges:
|
for range in ranges:
|
||||||
print "range:", range
|
print("range:", range)
|
||||||
results = sp.current_user_top_tracks(time_range=range, limit=50)
|
results = sp.current_user_top_tracks(time_range=range, limit=50)
|
||||||
for i, item in enumerate(results['items']):
|
for i, item in enumerate(results['items']):
|
||||||
print i, item['name'], '//', item['artists'][0]['name']
|
print(i, item['name'], '//', item['artists'][0]['name'])
|
||||||
print
|
print()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
print("Can't get token for", username)
|
||||||
|
|||||||
@ -10,4 +10,4 @@ username = uri.split(':')[2]
|
|||||||
playlist_id = uri.split(':')[4]
|
playlist_id = uri.split(':')[4]
|
||||||
|
|
||||||
results = sp.user_playlist(username, playlist_id)
|
results = sp.user_playlist(username, playlist_id)
|
||||||
print json.dumps(results, indent=4)
|
print(json.dumps(results, indent=4))
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
|
# removes tracks from a playlist
|
||||||
# Adds tracks to a playlist
|
|
||||||
|
|
||||||
import pprint
|
import pprint
|
||||||
import sys
|
import sys
|
||||||
@ -11,12 +10,14 @@ if len(sys.argv) > 3:
|
|||||||
username = sys.argv[1]
|
username = sys.argv[1]
|
||||||
playlist_id = sys.argv[2]
|
playlist_id = sys.argv[2]
|
||||||
track_ids_and_positions = sys.argv[3:]
|
track_ids_and_positions = sys.argv[3:]
|
||||||
track_ids = [ ]
|
track_ids = []
|
||||||
for t_pos in sys.argv[3:]:
|
for t_pos in sys.argv[3:]:
|
||||||
tid, pos = t_pos.split(',')
|
tid, pos = t_pos.split(',')
|
||||||
track_ids.append( { "uri" : tid, "positions": [ int(pos)] } )
|
track_ids.append({"uri": tid, "positions": [int(pos)]})
|
||||||
else:
|
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()
|
sys.exit()
|
||||||
|
|
||||||
scope = 'playlist-modify-public'
|
scope = 'playlist-modify-public'
|
||||||
@ -25,7 +26,8 @@ token = util.prompt_for_user_token(username, scope)
|
|||||||
if token:
|
if token:
|
||||||
sp = spotipy.Spotify(auth=token)
|
sp = spotipy.Spotify(auth=token)
|
||||||
sp.trace = False
|
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)
|
pprint.pprint(results)
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
print("Can't get token for", username)
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
|
# removes tracks to a playlist
|
||||||
# Adds tracks to a playlist
|
|
||||||
|
|
||||||
import pprint
|
import pprint
|
||||||
import sys
|
import sys
|
||||||
@ -21,7 +20,8 @@ token = util.prompt_for_user_token(username, scope)
|
|||||||
if token:
|
if token:
|
||||||
sp = spotipy.Spotify(auth=token)
|
sp = spotipy.Spotify(auth=token)
|
||||||
sp.trace = False
|
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)
|
pprint.pprint(results)
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
print("Can't get token for", username)
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# Replaces all tracks in a playlist
|
# Replaces all tracks in a playlist
|
||||||
|
|
||||||
import pprint
|
import pprint
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import spotipy
|
import spotipy
|
||||||
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import sys
|
import sys
|
||||||
import pprint
|
import pprint
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import spotipy
|
import spotipy
|
||||||
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import sys
|
import sys
|
||||||
import pprint
|
import pprint
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import spotipy
|
import spotipy
|
||||||
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import sys
|
import sys
|
||||||
import pprint
|
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
urn = sys.argv[1]
|
urn = sys.argv[1]
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import spotipy
|
import spotipy
|
||||||
import sys
|
import sys
|
||||||
import pprint
|
|
||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import spotipy
|
import spotipy
|
||||||
import sys
|
import sys
|
||||||
import pprint
|
|
||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
@ -22,7 +21,7 @@ if token:
|
|||||||
while response:
|
while response:
|
||||||
albums = response['albums']
|
albums = response['albums']
|
||||||
for i, item in enumerate(albums['items']):
|
for i, item in enumerate(albums['items']):
|
||||||
print(albums['offset'] + i,item['name'])
|
print(albums['offset'] + i, item['name'])
|
||||||
|
|
||||||
if albums['next']:
|
if albums['next']:
|
||||||
response = sp.next(albums)
|
response = sp.next(albums)
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import spotipy
|
import spotipy
|
||||||
import sys
|
import sys
|
||||||
import pprint
|
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
artist_name = sys.argv[1]
|
artist_name = sys.argv[1]
|
||||||
@ -22,6 +21,5 @@ try:
|
|||||||
print('Related artists for', name)
|
print('Related artists for', name)
|
||||||
for artist in related['artists']:
|
for artist in related['artists']:
|
||||||
print(' ', artist['name'])
|
print(' ', artist['name'])
|
||||||
except:
|
except BaseException:
|
||||||
print("usage show_related.py [artist-name]")
|
print("usage show_related.py [artist-name]")
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import spotipy
|
import spotipy
|
||||||
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import sys
|
import sys
|
||||||
import pprint
|
import pprint
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,3 @@ if __name__ == '__main__':
|
|||||||
results = sp.tracks(tids[start: start + max_tracks_per_call])
|
results = sp.tracks(tids[start: start + max_tracks_per_call])
|
||||||
for track in results['tracks']:
|
for track in results['tracks']:
|
||||||
print(track['name'] + ' - ' + track['artists'][0]['name'])
|
print(track['name'] + ' - ' + track['artists'][0]['name'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -16,4 +16,3 @@ sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
|||||||
sp.trace = True
|
sp.trace = True
|
||||||
user = sp.user(username)
|
user = sp.user(username)
|
||||||
pprint.pprint(user)
|
pprint.pprint(user)
|
||||||
|
|
||||||
|
|||||||
@ -1,18 +1,16 @@
|
|||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import spotipy
|
import spotipy
|
||||||
|
|
||||||
|
|
||||||
birdy_uri = 'spotify:artist:2WX2uTcsvV5OnS0inACecP'
|
birdy_uri = 'spotify:artist:2WX2uTcsvV5OnS0inACecP'
|
||||||
|
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
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']
|
albums = results['items']
|
||||||
while results['next']:
|
while results['next']:
|
||||||
results = spotify.next(results)
|
results = sp.next(results)
|
||||||
albums.extend(results['items'])
|
albums.extend(results['items'])
|
||||||
|
|
||||||
for album in albums:
|
for album in albums:
|
||||||
print((album['name']))
|
print((album['name']))
|
||||||
|
|
||||||
|
|||||||
@ -2,13 +2,12 @@
|
|||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import spotipy
|
import spotipy
|
||||||
|
|
||||||
|
|
||||||
lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp'
|
lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp'
|
||||||
|
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
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]:
|
for track in results['tracks'][:10]:
|
||||||
print('track : ' + track['name'])
|
print('track : ' + track['name'])
|
||||||
|
|||||||
@ -1,18 +1,16 @@
|
|||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import spotipy
|
import spotipy
|
||||||
import sys
|
|
||||||
|
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
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:
|
if len(sys.argv) > 1:
|
||||||
name = ' '.join(sys.argv[1:])
|
name = ' '.join(sys.argv[1:])
|
||||||
else:
|
else:
|
||||||
name = 'Radiohead'
|
name = 'Radiohead'
|
||||||
|
|
||||||
results = spotify.search(q='artist:' + name, type='artist')
|
results = sp.search(q='artist:' + name, type='artist')
|
||||||
items = results['artists']['items']
|
items = results['artists']['items']
|
||||||
if len(items) > 0:
|
if len(items) > 0:
|
||||||
artist = items[0]
|
artist = items[0]
|
||||||
print(artist['name'], artist['images'][0]['url'])
|
print(artist['name'], artist['images'][0]['url'])
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
import spotipy
|
import spotipy
|
||||||
import random
|
import random
|
||||||
import simplejson as json
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
generates a list of songs where the first word in each subsequent song
|
generates a list of songs where the first word in each subsequent song
|
||||||
@ -18,6 +17,7 @@ skiplist = set(['dm', 'remix'])
|
|||||||
max_offset = 500
|
max_offset = 500
|
||||||
seen = set()
|
seen = set()
|
||||||
|
|
||||||
|
|
||||||
def find_songs_that_start_with_word(word):
|
def find_songs_that_start_with_word(word):
|
||||||
max_titles = 20
|
max_titles = 20
|
||||||
max_offset = 200
|
max_offset = 200
|
||||||
@ -25,7 +25,7 @@ def find_songs_that_start_with_word(word):
|
|||||||
|
|
||||||
out = []
|
out = []
|
||||||
while offset < max_offset and len(out) < max_titles:
|
while offset < max_offset and len(out) < max_titles:
|
||||||
results = sp.search(q=word, type = 'track', limit=50, offset = offset)
|
results = sp.search(q=word, type='track', limit=50, offset=offset)
|
||||||
if len(results['tracks']['items']) == 0:
|
if len(results['tracks']['items']) == 0:
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -41,27 +41,29 @@ def find_songs_that_start_with_word(word):
|
|||||||
if '/' in name:
|
if '/' in name:
|
||||||
continue
|
continue
|
||||||
words = name.split()
|
words = name.split()
|
||||||
if len(words) > 1 and words[0] == word and words[-1] not in skiplist:
|
if len(words) > 1 and words[0] == word \
|
||||||
#print " ", name, len(out)
|
and words[-1] not in skiplist:
|
||||||
|
# print " ", name, len(out)
|
||||||
out.append(item)
|
out.append(item)
|
||||||
offset += 50
|
offset += 50
|
||||||
#print "found", len(out), "matches"
|
# print "found", len(out), "matches"
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def make_chain(word):
|
def make_chain(word):
|
||||||
which = 1
|
which = 1
|
||||||
while True:
|
while True:
|
||||||
songs = find_songs_that_start_with_word(word)
|
songs = find_songs_that_start_with_word(word)
|
||||||
if len(songs) > 0:
|
if len(songs) > 0:
|
||||||
song = random.choice(songs)
|
song = random.choice(songs)
|
||||||
print which, song['name'] + " by " + song['artists'][0]['name']
|
print(which, song['name'] + " by " + song['artists'][0]['name'])
|
||||||
which += 1
|
which += 1
|
||||||
word = song['name'].lower().split()[-1]
|
word = song['name'].lower().split()[-1]
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
title = ' '.join(sys.argv[1:])
|
title = ' '.join(sys.argv[1:])
|
||||||
make_chain(sys.argv[1].lower())
|
make_chain(sys.argv[1].lower())
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
# shows a user's playlists (need to be authenticated via oauth)
|
# shows a user's playlists (need to be authenticated via oauth)
|
||||||
|
|
||||||
import pprint
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
import spotipy
|
import spotipy
|
||||||
|
|
||||||
|
|||||||
@ -4,10 +4,13 @@ import sys
|
|||||||
import spotipy
|
import spotipy
|
||||||
import spotipy.util as util
|
import spotipy.util as util
|
||||||
|
|
||||||
|
|
||||||
def show_tracks(results):
|
def show_tracks(results):
|
||||||
for i, item in enumerate(results['items']):
|
for i, item in enumerate(results['items']):
|
||||||
track = item['track']
|
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 __name__ == '__main__':
|
||||||
@ -28,7 +31,8 @@ if __name__ == '__main__':
|
|||||||
print()
|
print()
|
||||||
print(playlist['name'])
|
print(playlist['name'])
|
||||||
print(' total tracks', playlist['tracks']['total'])
|
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']
|
tracks = results['tracks']
|
||||||
show_tracks(tracks)
|
show_tracks(tracks)
|
||||||
while tracks['next']:
|
while tracks['next']:
|
||||||
@ -36,4 +40,3 @@ if __name__ == '__main__':
|
|||||||
show_tracks(tracks)
|
show_tracks(tracks)
|
||||||
else:
|
else:
|
||||||
print("Can't get token for", username)
|
print("Can't get token for", username)
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,13 @@ playlists = sp.user_playlists(user)
|
|||||||
|
|
||||||
while playlists:
|
while playlists:
|
||||||
for i, playlist in enumerate(playlists['items']):
|
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']:
|
if playlists['next']:
|
||||||
playlists = sp.next(playlists)
|
playlists = sp.next(playlists)
|
||||||
else:
|
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
|
import spotipy.util as util
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
username = sys.argv[1]
|
username = sys.argv[1]
|
||||||
else:
|
else:
|
||||||
@ -23,7 +22,7 @@ if token:
|
|||||||
while tracks:
|
while tracks:
|
||||||
for item in tracks['items']:
|
for item in tracks['items']:
|
||||||
track = item['track']
|
track = item['track']
|
||||||
print(which, track['name' ], ' --', track['artists'][0]['name'])
|
print(which, track['name'], ' --', track['artists'][0]['name'])
|
||||||
which += 1
|
which += 1
|
||||||
tracks = sp.next(tracks)
|
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
|
six==1.10.0
|
||||||
11
setup.py
11
setup.py
@ -1,15 +1,18 @@
|
|||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
|
desc = """### A light weight Python library for the Spotify Web API"""
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='spotipy',
|
name='spotipy',
|
||||||
version='2.4.4',
|
version='2.6.1',
|
||||||
description='simple client for the Spotify Web API',
|
long_description=desc,
|
||||||
|
long_description_content_type='text/markdown',
|
||||||
author="@plamere",
|
author="@plamere",
|
||||||
author_email="paul@echonest.com",
|
author_email="paul@echonest.com",
|
||||||
url='http://spotipy.readthedocs.org/',
|
url='http://spotipy.readthedocs.org/',
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'requests>=2.3.0',
|
'requests>=2.20.0',
|
||||||
'six>=1.10.0',
|
'six>=1.10.0',
|
||||||
],
|
],
|
||||||
license='LICENSE.txt',
|
license='LICENSE.md',
|
||||||
packages=['spotipy'])
|
packages=['spotipy'])
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
VERSION='2.0.1'
|
from .client import * # noqa
|
||||||
from .client import Spotify, SpotifyException
|
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
|
from __future__ import print_function
|
||||||
import sys
|
|
||||||
import requests
|
__all__ = [
|
||||||
|
'Spotify',
|
||||||
|
'SpotifyException'
|
||||||
|
]
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import requests
|
||||||
import six
|
import six
|
||||||
|
|
||||||
""" A simple and thin Python library for the Spotify Web API
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class SpotifyException(Exception):
|
class SpotifyException(Exception):
|
||||||
def __init__(self, http_status, code, msg, headers=None):
|
def __init__(self, http_status, code, msg, headers=None):
|
||||||
@ -53,9 +57,10 @@ class Spotify(object):
|
|||||||
max_get_retries = 10
|
max_get_retries = 10
|
||||||
|
|
||||||
def __init__(self, auth=None, requests_session=True,
|
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 auth: An authorization token (optional)
|
||||||
:param requests_session:
|
:param requests_session:
|
||||||
@ -68,7 +73,8 @@ class Spotify(object):
|
|||||||
:param proxies:
|
:param proxies:
|
||||||
Definition of proxies (optional)
|
Definition of proxies (optional)
|
||||||
:param requests_timeout:
|
: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.prefix = 'https://api.spotify.com/v1/'
|
||||||
self._auth = auth
|
self._auth = auth
|
||||||
@ -107,36 +113,39 @@ class Spotify(object):
|
|||||||
|
|
||||||
if self.trace_out:
|
if self.trace_out:
|
||||||
print(url)
|
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
|
if self.trace: # pragma: no cover
|
||||||
print()
|
print()
|
||||||
print ('headers', headers)
|
print('Request headers:', headers)
|
||||||
print ('http status', r.status_code)
|
print('Response headers:', r.headers)
|
||||||
|
print('HTTP status', r.status_code)
|
||||||
print(method, r.url)
|
print(method, r.url)
|
||||||
if payload:
|
if payload:
|
||||||
print("DATA", json.dumps(payload))
|
print("Data", json.dumps(payload))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
except:
|
except BaseException:
|
||||||
if r.text and len(r.text) > 0 and r.text != 'null':
|
try:
|
||||||
|
msg = r.json()['error']['message']
|
||||||
|
except BaseException:
|
||||||
|
msg = 'error'
|
||||||
raise SpotifyException(r.status_code,
|
raise SpotifyException(r.status_code,
|
||||||
-1, '%s:\n %s' % (r.url, r.json()['error']['message']),
|
-1, '%s:\n %s' % (r.url, msg),
|
||||||
headers=r.headers)
|
headers=r.headers)
|
||||||
else:
|
|
||||||
raise SpotifyException(r.status_code,
|
try:
|
||||||
-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()
|
results = r.json()
|
||||||
|
except BaseException:
|
||||||
|
results = None
|
||||||
|
|
||||||
if self.trace: # pragma: no cover
|
if self.trace: # pragma: no cover
|
||||||
print('RESP', results)
|
print('Response:', results)
|
||||||
print()
|
print()
|
||||||
return results
|
return results
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _get(self, url, args=None, payload=None, **kwargs):
|
def _get(self, url, args=None, payload=None, **kwargs):
|
||||||
if args:
|
if args:
|
||||||
@ -154,21 +163,22 @@ class Spotify(object):
|
|||||||
if retries < 0:
|
if retries < 0:
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
sleep_seconds = int(e.headers.get('Retry-After', delay))
|
sleep_seconds = int(
|
||||||
print ('retrying ...' + str(sleep_seconds) + 'secs')
|
e.headers.get('Retry-After', delay))
|
||||||
|
print('retrying ...' + str(sleep_seconds) + 'secs')
|
||||||
time.sleep(sleep_seconds + 1)
|
time.sleep(sleep_seconds + 1)
|
||||||
delay += 1
|
delay += 1
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise
|
raise
|
||||||
print ('exception', str(e))
|
print('exception', str(e))
|
||||||
# some other exception. Requests have
|
# some other exception. Requests have
|
||||||
# been know to throw a BadStatusLine exception
|
# been know to throw a BadStatusLine exception
|
||||||
retries -= 1
|
retries -= 1
|
||||||
if retries >= 0:
|
if retries >= 0:
|
||||||
sleep_seconds = int(e.headers.get('Retry-After', delay))
|
sleep_seconds = int(e.headers.get('Retry-After', delay))
|
||||||
print ('retrying ...' + str(delay) + 'secs')
|
print('retrying ...' + str(delay) + 'secs')
|
||||||
time.sleep(sleep_seconds + 1)
|
time.sleep(sleep_seconds + 1)
|
||||||
delay += 1
|
delay += 1
|
||||||
else:
|
else:
|
||||||
@ -227,7 +237,7 @@ class Spotify(object):
|
|||||||
trid = self._get_id('track', track_id)
|
trid = self._get_id('track', track_id)
|
||||||
return self._get('tracks/' + trid)
|
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
|
""" returns a list of tracks given a list of track IDs, URIs, or URLs
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -236,7 +246,7 @@ class Spotify(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
tlist = [self._get_id('track', t) for t in tracks]
|
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):
|
def artist(self, artist_id):
|
||||||
""" returns a single artist given the artist's ID, URI or URL
|
""" 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
|
- offset - the index of the first item to return
|
||||||
- type - the type of item to return. One of 'artist', 'album',
|
- type - the type of item to return. One of 'artist', 'album',
|
||||||
'track' or 'playlist'
|
'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):
|
def user(self, user):
|
||||||
""" Gets basic profile information about a Spotify User
|
""" Gets basic profile information about a Spotify User
|
||||||
@ -382,6 +394,18 @@ class Spotify(object):
|
|||||||
plid = self._get_id('playlist', playlist_id)
|
plid = self._get_id('playlist', playlist_id)
|
||||||
return self._get("users/%s/playlists/%s" % (user, plid), fields=fields)
|
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,
|
def user_playlist_tracks(self, user, playlist_id=None, fields=None,
|
||||||
limit=100, offset=0, market=None):
|
limit=100, offset=0, market=None):
|
||||||
""" Get full details of the tracks of a playlist owned by a user.
|
""" 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,
|
limit=limit, offset=offset, fields=fields,
|
||||||
market=market)
|
market=market)
|
||||||
|
|
||||||
|
|
||||||
def user_playlist_create(self, user, name, public=True, description=''):
|
def user_playlist_create(self, user, name, public=True, description=''):
|
||||||
""" Creates a playlist for a user
|
""" Creates a playlist for a user
|
||||||
|
|
||||||
@ -411,7 +434,6 @@ class Spotify(object):
|
|||||||
"""
|
"""
|
||||||
data = {'name': name, 'public': public, 'description': description}
|
data = {'name': name, 'public': public, 'description': description}
|
||||||
|
|
||||||
|
|
||||||
return self._post("users/%s/playlists" % (user,), payload=data)
|
return self._post("users/%s/playlists" % (user,), payload=data)
|
||||||
|
|
||||||
def user_playlist_change_details(
|
def user_playlist_change_details(
|
||||||
@ -447,7 +469,8 @@ class Spotify(object):
|
|||||||
- user - the id of the user
|
- user - the id of the user
|
||||||
- name - the name of the playlist
|
- 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,
|
def user_playlist_add_tracks(self, user, playlist_id, tracks,
|
||||||
position=None):
|
position=None):
|
||||||
@ -487,8 +510,10 @@ class Spotify(object):
|
|||||||
- user - the id of the user
|
- user - the id of the user
|
||||||
- playlist_id - the id of the playlist
|
- playlist_id - the id of the playlist
|
||||||
- range_start - the position of the first track to be reordered
|
- range_start - the position of the first track to be reordered
|
||||||
- range_length - optional the number of tracks to be reordered (default: 1)
|
- range_length - optional the number of tracks to be reordered
|
||||||
- insert_before - the position where the tracks should be inserted
|
(default: 1)
|
||||||
|
- insert_before - the position where the tracks should be
|
||||||
|
inserted
|
||||||
- snapshot_id - optional playlist's snapshot ID
|
- snapshot_id - optional playlist's snapshot ID
|
||||||
"""
|
"""
|
||||||
plid = self._get_id('playlist', playlist_id)
|
plid = self._get_id('playlist', playlist_id)
|
||||||
@ -507,7 +532,7 @@ class Spotify(object):
|
|||||||
Parameters:
|
Parameters:
|
||||||
- user - the id of the user
|
- user - the id of the user
|
||||||
- playlist_id - the id of the playlist
|
- 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
|
- snapshot_id - optional id of the playlist snapshot
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -527,7 +552,9 @@ class Spotify(object):
|
|||||||
Parameters:
|
Parameters:
|
||||||
- user - the id of the user
|
- user - the id of the user
|
||||||
- playlist_id - the id of the playlist
|
- 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:
|
- 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":"4iV5W9uYEdYUVa79Axb7Rh", "positions":[2] },
|
||||||
{ "uri":"1301WleyT98MSxVHPZCA6M", "positions":[7] } ]
|
{ "uri":"1301WleyT98MSxVHPZCA6M", "positions":[7] } ]
|
||||||
- snapshot_id - optional id of the playlist snapshot
|
- snapshot_id - optional id of the playlist snapshot
|
||||||
@ -555,19 +582,26 @@ class Spotify(object):
|
|||||||
- playlist_id - the id of the playlist
|
- 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
|
Check to see if the given users are following the given playlist
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- playlist_owner_id - the user id of the playlist owner
|
- playlist_owner_id - the user id of the playlist owner
|
||||||
- playlist_id - the id of the playlist
|
- 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):
|
def me(self):
|
||||||
""" Get detailed profile information about the current user.
|
""" Get detailed profile information about the current user.
|
||||||
@ -586,17 +620,6 @@ class Spotify(object):
|
|||||||
'''
|
'''
|
||||||
return self._get('me/player/currently-playing')
|
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):
|
def current_user_saved_tracks(self, limit=20, offset=0):
|
||||||
""" Gets a list of the tracks saved in the current authorized user's
|
""" Gets a list of the tracks saved in the current authorized user's
|
||||||
"Your Music" library
|
"Your Music" library
|
||||||
@ -612,8 +635,9 @@ class Spotify(object):
|
|||||||
""" Gets a list of the artists followed by the current authorized user
|
""" Gets a list of the artists followed by the current authorized user
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- limit - the number of tracks to return
|
- limit - the number of artists to return
|
||||||
- after - ghe last artist ID retrieved from the previous request
|
- after - the last artist ID retrieved from the previous
|
||||||
|
request
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self._get('me/following', type='artist', limit=limit,
|
return self._get('me/following', type='artist', limit=limit,
|
||||||
@ -689,6 +713,27 @@ class Spotify(object):
|
|||||||
'''
|
'''
|
||||||
return self._get('me/player/recently-played', limit=limit)
|
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=[]):
|
def current_user_saved_albums_add(self, albums=[]):
|
||||||
""" Add one or more albums to the current user's
|
""" Add one or more albums to the current user's
|
||||||
"Your Music" library.
|
"Your Music" library.
|
||||||
@ -696,8 +741,17 @@ class Spotify(object):
|
|||||||
- albums - a list of album URIs, URLs or IDs
|
- albums - a list of album URIs, URLs or IDs
|
||||||
"""
|
"""
|
||||||
alist = [self._get_id('album', a) for a in albums]
|
alist = [self._get_id('album', a) for a in albums]
|
||||||
r = self._put('me/albums?ids=' + ','.join(alist))
|
return self._put('me/albums?ids=' + ','.join(alist))
|
||||||
return r
|
|
||||||
|
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=[]):
|
def user_follow_artists(self, ids=[]):
|
||||||
''' Follow one or more artists
|
''' Follow one or more artists
|
||||||
@ -713,6 +767,20 @@ class Spotify(object):
|
|||||||
'''
|
'''
|
||||||
return self._put('me/following?type=user&ids=' + ','.join(ids))
|
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,
|
def featured_playlists(self, locale=None, country=None, timestamp=None,
|
||||||
limit=20, offset=0):
|
limit=20, offset=0):
|
||||||
""" Get a list of Spotify featured playlists
|
""" Get a list of Spotify featured playlists
|
||||||
@ -801,20 +869,21 @@ class Spotify(object):
|
|||||||
Parameters:
|
Parameters:
|
||||||
- seed_artists - a list of artist IDs, URIs or URLs
|
- 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
|
- 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
|
- country - An ISO 3166-1 alpha-2 country code. If provided,
|
||||||
results will be playable in this country.
|
all results will be playable in this country.
|
||||||
|
|
||||||
- limit - The maximum number of items to return. Default: 20.
|
- 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
|
- min/max/target_<attribute> - For the tuneable track
|
||||||
in the documentation, these values provide filters and targeting on
|
attributes listed in the documentation, these values
|
||||||
results.
|
provide filters and targeting on results.
|
||||||
"""
|
"""
|
||||||
params = dict(limit=limit)
|
params = dict(limit=limit)
|
||||||
if seed_artists:
|
if seed_artists:
|
||||||
@ -869,36 +938,28 @@ class Spotify(object):
|
|||||||
else:
|
else:
|
||||||
return results
|
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):
|
def devices(self):
|
||||||
''' Get a list of user's available devices.
|
''' Get a list of user's available devices.
|
||||||
'''
|
'''
|
||||||
return self._get("me/player/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.
|
''' Get information about user's current playback.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- market - an ISO 3166-1 alpha-2 country code.
|
- 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.
|
''' Get user's currently playing track.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- market - an ISO 3166-1 alpha-2 country code.
|
- 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.
|
''' Transfer playback to another device.
|
||||||
Note that the API accepts a list of device ids, but only
|
Note that the API accepts a list of device ids, but only
|
||||||
actually supports one.
|
actually supports one.
|
||||||
@ -914,7 +975,8 @@ class Spotify(object):
|
|||||||
}
|
}
|
||||||
return self._put("me/player", payload=data)
|
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.
|
''' Start or resume user's playback.
|
||||||
|
|
||||||
Provide a `context_uri` to start playback or a album,
|
Provide a `context_uri` to start playback or a album,
|
||||||
@ -945,9 +1007,10 @@ class Spotify(object):
|
|||||||
data['uris'] = uris
|
data['uris'] = uris
|
||||||
if offset is not None:
|
if offset is not None:
|
||||||
data['offset'] = offset
|
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.
|
''' Pause user's playback.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -955,7 +1018,7 @@ class Spotify(object):
|
|||||||
'''
|
'''
|
||||||
return self._put(self._append_device_id("me/player/pause", device_id))
|
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.
|
''' Skip user's playback to next track.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -963,15 +1026,16 @@ class Spotify(object):
|
|||||||
'''
|
'''
|
||||||
return self._post(self._append_device_id("me/player/next", device_id))
|
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.
|
''' Skip user's playback to previous track.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- device_id - device target for playback
|
- 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.
|
''' Seek to position in current track.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -981,9 +1045,10 @@ class Spotify(object):
|
|||||||
if not isinstance(position_ms, int):
|
if not isinstance(position_ms, int):
|
||||||
self._warn('position_ms must be an integer')
|
self._warn('position_ms must be an integer')
|
||||||
return
|
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.
|
''' Set repeat mode for playback.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -993,9 +1058,12 @@ class Spotify(object):
|
|||||||
if state not in ['track', 'context', 'off']:
|
if state not in ['track', 'context', 'off']:
|
||||||
self._warn('invalid state')
|
self._warn('invalid state')
|
||||||
return
|
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.
|
''' Set playback volume.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -1008,9 +1076,12 @@ class Spotify(object):
|
|||||||
if volume_percent < 0 or volume_percent > 100:
|
if volume_percent < 0 or volume_percent > 100:
|
||||||
self._warn('volume must be between 0 and 100, inclusive')
|
self._warn('volume must be between 0 and 100, inclusive')
|
||||||
return
|
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.
|
''' Toggle playback shuffling.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@ -1021,7 +1092,10 @@ class Spotify(object):
|
|||||||
self._warn('state must be a boolean')
|
self._warn('state must be a boolean')
|
||||||
return
|
return
|
||||||
state = str(state).lower()
|
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):
|
def _append_device_id(self, path, device_id):
|
||||||
''' Append device ID to API path.
|
''' Append device ID to API path.
|
||||||
@ -1040,16 +1114,16 @@ class Spotify(object):
|
|||||||
fields = id.split(':')
|
fields = id.split(':')
|
||||||
if len(fields) >= 3:
|
if len(fields) >= 3:
|
||||||
if type != fields[-2]:
|
if type != fields[-2]:
|
||||||
self._warn('expected id of type %s but found type %s %s',
|
self._warn('expected id of type %s but found type %s %s' %
|
||||||
type, fields[-2], id)
|
(type, fields[-2], id))
|
||||||
return fields[-1]
|
return fields[-1]
|
||||||
fields = id.split('/')
|
fields = id.split('/')
|
||||||
if len(fields) >= 3:
|
if len(fields) >= 3:
|
||||||
itype = fields[-2]
|
itype = fields[-2]
|
||||||
if type != itype:
|
if type != itype:
|
||||||
self._warn('expected id of type %s but found type %s %s',
|
self._warn('expected id of type %s but found type %s %s' %
|
||||||
type, itype, id)
|
(type, itype, id))
|
||||||
return fields[-1]
|
return fields[-1].split('?')[0]
|
||||||
return id
|
return id
|
||||||
|
|
||||||
def _get_uri(self, type, id):
|
def _get_uri(self, type, id):
|
||||||
|
|||||||
@ -1,11 +1,21 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'is_token_expired',
|
||||||
|
'SpotifyClientCredentials',
|
||||||
|
'SpotifyOAuth',
|
||||||
|
'SpotifyOauthError'
|
||||||
|
]
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import requests
|
|
||||||
import os
|
|
||||||
import json
|
import json
|
||||||
import time
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
# Workaround to support both python 2 & 3
|
# Workaround to support both python 2 & 3
|
||||||
import six
|
import six
|
||||||
@ -17,7 +27,11 @@ class SpotifyOauthError(Exception):
|
|||||||
|
|
||||||
|
|
||||||
def _make_authorization_headers(client_id, client_secret):
|
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')}
|
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):
|
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
|
constructor or set SPOTIPY_CLIENT_ID and SPOTIPY_CLIENT_SECRET
|
||||||
environment variables
|
environment variables
|
||||||
"""
|
"""
|
||||||
@ -67,12 +81,14 @@ class SpotifyClientCredentials(object):
|
|||||||
|
|
||||||
def _request_access_token(self):
|
def _request_access_token(self):
|
||||||
"""Gets client credentials access token """
|
"""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,
|
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:
|
if response.status_code != 200:
|
||||||
raise SpotifyOauthError(response.reason)
|
raise SpotifyOauthError(response.reason)
|
||||||
token_info = response.json()
|
token_info = response.json()
|
||||||
@ -115,9 +131,9 @@ class SpotifyOAuth(object):
|
|||||||
self.client_id = client_id
|
self.client_id = client_id
|
||||||
self.client_secret = client_secret
|
self.client_secret = client_secret
|
||||||
self.redirect_uri = redirect_uri
|
self.redirect_uri = redirect_uri
|
||||||
self.state=state
|
self.state = state
|
||||||
self.cache_path = cache_path
|
self.cache_path = cache_path
|
||||||
self.scope=self._normalize_scope(scope)
|
self.scope = self._normalize_scope(scope)
|
||||||
self.proxies = proxies
|
self.proxies = proxies
|
||||||
|
|
||||||
def get_cached_token(self):
|
def get_cached_token(self):
|
||||||
@ -132,11 +148,13 @@ class SpotifyOAuth(object):
|
|||||||
token_info = json.loads(token_info_string)
|
token_info = json.loads(token_info_string)
|
||||||
|
|
||||||
# if scopes don't match, then bail
|
# 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
|
return None
|
||||||
|
|
||||||
if self.is_token_expired(token_info):
|
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:
|
except IOError:
|
||||||
pass
|
pass
|
||||||
@ -154,7 +172,8 @@ class SpotifyOAuth(object):
|
|||||||
|
|
||||||
def _is_scope_subset(self, needle_scope, haystack_scope):
|
def _is_scope_subset(self, needle_scope, haystack_scope):
|
||||||
needle_scope = set(needle_scope.split()) if needle_scope else set()
|
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
|
return needle_scope <= haystack_scope
|
||||||
|
|
||||||
def is_token_expired(self, token_info):
|
def is_token_expired(self, token_info):
|
||||||
@ -212,7 +231,8 @@ class SpotifyOAuth(object):
|
|||||||
headers = self._make_authorization_headers()
|
headers = self._make_authorization_headers()
|
||||||
|
|
||||||
response = requests.post(self.OAUTH_TOKEN_URL, data=payload,
|
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:
|
if response.status_code != 200:
|
||||||
raise SpotifyOauthError(response.reason)
|
raise SpotifyOauthError(response.reason)
|
||||||
token_info = response.json()
|
token_info = response.json()
|
||||||
@ -222,14 +242,13 @@ class SpotifyOAuth(object):
|
|||||||
|
|
||||||
def _normalize_scope(self, scope):
|
def _normalize_scope(self, scope):
|
||||||
if scope:
|
if scope:
|
||||||
scopes = scope.split()
|
scopes = sorted(scope.split())
|
||||||
scopes.sort()
|
|
||||||
return ' '.join(scopes)
|
return ' '.join(scopes)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def refresh_access_token(self, refresh_token):
|
def refresh_access_token(self, refresh_token):
|
||||||
payload = { 'refresh_token': refresh_token,
|
payload = {'refresh_token': refresh_token,
|
||||||
'grant_type': 'refresh_token'}
|
'grant_type': 'refresh_token'}
|
||||||
|
|
||||||
headers = self._make_authorization_headers()
|
headers = self._make_authorization_headers()
|
||||||
@ -240,12 +259,12 @@ class SpotifyOAuth(object):
|
|||||||
if False: # debugging code
|
if False: # debugging code
|
||||||
print('headers', headers)
|
print('headers', headers)
|
||||||
print('request', response.url)
|
print('request', response.url)
|
||||||
self._warn("couldn't refresh token: code:%d reason:%s" \
|
self._warn("couldn't refresh token: code:%d reason:%s"
|
||||||
% (response.status_code, response.reason))
|
% (response.status_code, response.reason))
|
||||||
return None
|
return None
|
||||||
token_info = response.json()
|
token_info = response.json()
|
||||||
token_info = self._add_custom_values_to_token_info(token_info)
|
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
|
token_info['refresh_token'] = refresh_token
|
||||||
self._save_token_info(token_info)
|
self._save_token_info(token_info)
|
||||||
return token_info
|
return token_info
|
||||||
@ -261,4 +280,3 @@ class SpotifyOAuth(object):
|
|||||||
|
|
||||||
def _warn(self, msg):
|
def _warn(self, msg):
|
||||||
print('warning:' + msg, file=sys.stderr)
|
print('warning:' + msg, file=sys.stderr)
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,31 @@
|
|||||||
|
# -*- 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
|
from __future__ import print_function
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'CLIENT_CREDS_ENV_VARS',
|
||||||
|
'prompt_for_user_token'
|
||||||
|
]
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from . import oauth2
|
from . import oauth2
|
||||||
|
|
||||||
import spotipy
|
import spotipy
|
||||||
|
|
||||||
def prompt_for_user_token(username, scope=None, client_id = None,
|
CLIENT_CREDS_ENV_VARS = {
|
||||||
client_secret = None, redirect_uri = None, cache_path = None):
|
'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
|
''' 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
|
constructor
|
||||||
@ -71,7 +89,7 @@ def prompt_for_user_token(username, scope=None, client_id = None,
|
|||||||
import webbrowser
|
import webbrowser
|
||||||
webbrowser.open(auth_url)
|
webbrowser.open(auth_url)
|
||||||
print("Opened %s in your browser" % auth_url)
|
print("Opened %s in your browser" % auth_url)
|
||||||
except:
|
except BaseException:
|
||||||
print("Please navigate here: %s" % auth_url)
|
print("Please navigate here: %s" % auth_url)
|
||||||
|
|
||||||
print()
|
print()
|
||||||
|
|||||||
@ -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
|
# -*- coding: utf-8 -*-
|
||||||
import json
|
|
||||||
|
import six.moves.urllib.parse as urllibparse
|
||||||
|
from spotipy import SpotifyOAuth
|
||||||
import io
|
import io
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.abspath(os.pardir))
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import unittest.mock as mock
|
import unittest.mock as mock
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import mock
|
import mock
|
||||||
import six.moves.urllib.parse as urllibparse
|
|
||||||
|
|
||||||
patch = mock.patch
|
patch = mock.patch
|
||||||
DEFAULT = mock.DEFAULT
|
DEFAULT = mock.DEFAULT
|
||||||
@ -166,4 +173,5 @@ class TestSpotifyOAuth(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
# -*- coding: latin-1 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import spotipy
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
import pprint
|
|
||||||
import requests
|
import requests
|
||||||
from spotipy.client import SpotifyException
|
from spotipy.client import SpotifyException
|
||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
@ -9,6 +11,18 @@ from spotipy.oauth2 import SpotifyClientCredentials
|
|||||||
|
|
||||||
class TestSpotipy(unittest.TestCase):
|
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_urn = 'spotify:track:3HfB5hBU0dmBt8T0iCmH42'
|
||||||
creep_id = '3HfB5hBU0dmBt8T0iCmH42'
|
creep_id = '3HfB5hBU0dmBt8T0iCmH42'
|
||||||
creep_url = 'http://open.spotify.com/track/3HfB5hBU0dmBt8T0iCmH42'
|
creep_url = 'http://open.spotify.com/track/3HfB5hBU0dmBt8T0iCmH42'
|
||||||
@ -20,9 +34,9 @@ class TestSpotipy(unittest.TestCase):
|
|||||||
radiohead_urn = 'spotify:artist:4Z8W4fKeB5YxbusRsdQVPb'
|
radiohead_urn = 'spotify:artist:4Z8W4fKeB5YxbusRsdQVPb'
|
||||||
angeles_haydn_urn = 'spotify:album:1vAbqAeuJVWNAe7UR00bdM'
|
angeles_haydn_urn = 'spotify:album:1vAbqAeuJVWNAe7UR00bdM'
|
||||||
|
|
||||||
|
|
||||||
bad_id = 'BAD_ID'
|
bad_id = 'BAD_ID'
|
||||||
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
self.spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
self.spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
@ -49,14 +63,16 @@ class TestSpotipy(unittest.TestCase):
|
|||||||
tracks = results['items']
|
tracks = results['items']
|
||||||
total, received = results['total'], len(tracks)
|
total, received = results['total'], len(tracks)
|
||||||
while received < total:
|
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'])
|
tracks.extend(results['items'])
|
||||||
received = len(tracks)
|
received = len(tracks)
|
||||||
|
|
||||||
self.assertEqual(received, total)
|
self.assertEqual(received, total)
|
||||||
|
|
||||||
def test_albums(self):
|
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('albums' in results)
|
||||||
self.assertTrue(len(results['albums']) == 2)
|
self.assertTrue(len(results['albums']) == 2)
|
||||||
|
|
||||||
@ -74,9 +90,9 @@ class TestSpotipy(unittest.TestCase):
|
|||||||
|
|
||||||
def test_track_bad_urn(self):
|
def test_track_bad_urn(self):
|
||||||
try:
|
try:
|
||||||
track = self.spotify.track(self.el_scorcho_bad_urn)
|
self.spotify.track(self.el_scorcho_bad_urn)
|
||||||
self.assertTrue(False)
|
self.assertTrue(False)
|
||||||
except spotipy.SpotifyException:
|
except SpotifyException:
|
||||||
self.assertTrue(True)
|
self.assertTrue(True)
|
||||||
|
|
||||||
def test_tracks(self):
|
def test_tracks(self):
|
||||||
@ -125,18 +141,19 @@ class TestSpotipy(unittest.TestCase):
|
|||||||
def test_search_timeout(self):
|
def test_search_timeout(self):
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager, requests_timeout=.1)
|
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager, requests_timeout=.1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
results = sp.search(q='my*', type='track')
|
sp.search(q='my*', type='track')
|
||||||
self.assertTrue(False, 'unexpected search timeout')
|
self.assertTrue(False, 'unexpected search timeout')
|
||||||
except requests.exceptions.Timeout:
|
except requests.exceptions.Timeout:
|
||||||
self.assertTrue(True, 'expected search timeout')
|
self.assertTrue(True, 'expected search timeout')
|
||||||
|
|
||||||
|
|
||||||
def test_album_search(self):
|
def test_album_search(self):
|
||||||
results = self.spotify.search(q='weezer pinkerton', type='album')
|
results = self.spotify.search(q='weezer pinkerton', type='album')
|
||||||
self.assertTrue('albums' in results)
|
self.assertTrue('albums' in results)
|
||||||
self.assertTrue(len(results['albums']['items']) > 0)
|
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):
|
def test_track_search(self):
|
||||||
results = self.spotify.search(q='el scorcho weezer', type='track')
|
results = self.spotify.search(q='el scorcho weezer', type='track')
|
||||||
@ -150,27 +167,20 @@ class TestSpotipy(unittest.TestCase):
|
|||||||
|
|
||||||
def test_track_bad_id(self):
|
def test_track_bad_id(self):
|
||||||
try:
|
try:
|
||||||
track = self.spotify.track(self.bad_id)
|
self.spotify.track(self.bad_id)
|
||||||
self.assertTrue(False)
|
self.assertTrue(False)
|
||||||
except spotipy.SpotifyException:
|
except SpotifyException:
|
||||||
self.assertTrue(True)
|
|
||||||
|
|
||||||
def test_track_bad_id(self):
|
|
||||||
try:
|
|
||||||
track = self.spotify.track(self.bad_id)
|
|
||||||
self.assertTrue(False)
|
|
||||||
except spotipy.SpotifyException:
|
|
||||||
self.assertTrue(True)
|
self.assertTrue(True)
|
||||||
|
|
||||||
def test_unauthenticated_post_fails(self):
|
def test_unauthenticated_post_fails(self):
|
||||||
with self.assertRaises(SpotifyException) as cm:
|
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
|
self.assertTrue(cm.exception.http_status == 401 or
|
||||||
cm.exception.http_status == 403)
|
cm.exception.http_status == 403)
|
||||||
|
|
||||||
def test_custom_requests_session(self):
|
def test_custom_requests_session(self):
|
||||||
from requests import Session
|
sess = requests.Session()
|
||||||
sess = Session()
|
|
||||||
sess.headers["user-agent"] = "spotipy-test"
|
sess.headers["user-agent"] = "spotipy-test"
|
||||||
client_credentials_manager = SpotifyClientCredentials()
|
client_credentials_manager = SpotifyClientCredentials()
|
||||||
with_custom_session = spotipy.Spotify(client_credentials_manager=client_credentials_manager, requests_session=sess)
|
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")
|
self.assertTrue(with_no_session.user(user="akx")["uri"] == "spotify:user:akx")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Need tests for:
|
Need tests for:
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user