diff --git a/.gitignore b/.gitignore index 51cbe85..dc48665 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,5 @@ coverage.xml # Sphinx documentation docs/_build/ + +.* diff --git a/docs/index.rst b/docs/index.rst index 4081370..8333741 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,10 +1,13 @@ +.. image:: images/spotify-web-api-doc.jpg + :width: 100 % + Spotipy =================================== -Spotipy is a lightweight Python library for the `Spotify Web API -`_. With *spotipy* +*Spotipy* is a lightweight Python library for the `Spotify Web API +`_. With *Spotipy* you get full access to all of the music data provided by the Spotify platform. -Here's a quick example of using *spotipy* to list the names of all the albums +Here's a quick example of using *Spotipy* to list the names of all the albums released by the artist 'Birdy':: import spotipy @@ -61,11 +64,13 @@ artist's name:: Features ======== *Spotipy* supports all of the features of the Spotify Web API including access -to all end points, and support for user authorization. +to all end points, and support for user authorization. For details on the +capabilities you are encouraged to review the `Spotify Web +API `_ documentation. Installation ============ -Install spotipy with:: +Install *Spotipy* with:: pip install SpotifyWebAPI @@ -78,39 +83,45 @@ Or you can get the source from github at https://github.com/plamere/spotipy Getting Started =============== -To use *spotipy* import the spotipy package, and create a Spotify object. For -methods that require authorization, pass the authorization token into the -Spotify constructor - -Non authorized requests:: +Non-Authorized requests +----------------------- +For methods that do not require authorization, simply create a Spotify object +and start making method calls like so:: import spotipy spotify = spotipy.Spotify() results = spotify.search(q='artist:' + name, type='artist') print results -Authorization -------------- +Authorized requests +------------------- Many methods require user authentication. For these requests you will need to generate an authorization token that indicates that the user has granted -permission for your application to perform the given task. Spotipy provides a +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 at +`My Applications +`_. + + +*Spotipy* provides a utility method ``util.prompt_for_user_token`` that will attempt to authorize the user. You can pass your app credentials directly into the method as arguments, or if you are reluctant to immortalize your app credentials in your source code, you can set environment variables like so:: - export CLIENT_ID='your-spotify-client-id' - export CLIENT_SECRET='your-spotify-client-secret' - export REDIRECT_URI='your-app-redirect-url' + export SPOTIPY_CLIENT_ID='your-spotify-client-id' + export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret' + export SPOTIPY_REDIRECT_URI='your-app-redirect-url' Call ``util.prompt_for_user_token`` method with the username and the desired scope (see `Using Scopes `_ for information about scopes) and credentials. This will coordinate the user authorization via -a the browser. The credentials are cached locally +your web browser. The credentials are cached locally and are used to automatically +re-authorized expired tokens. - -Authorized requests:: +Here's an example of getting user authorization to read a user's saved tracks:: import sys import spotipy @@ -135,17 +146,25 @@ Authorized requests:: else: print "Can't get token for", username +IDs URIs and URLs +----------------- +*Spotipy* supports a number of different ID types: -spotipy Package -=============== + - Spotify URI - The resource identifier that you can enter, for example, in + the Spotify Desktop client's search box to locate an artist, album, or + track. Example: spotify:track:6rqhFgbbKwnb9MLmUQDhG6 + - Spotify URL - An HTML link that opens a track, album, app, playlist or other + Spotify resource in a Spotify client. Example: + http://open.spotify.com/track/6rqhFgbbKwnb9MLmUQDhG6 + - Spotify ID - A base-62 number that you can find at the end of the Spotify + URI (see above) for an artist, track, album, etc. Example: + 6rqhFgbbKwnb9MLmUQDhG6 -:mod:`spotipy` Package ----------------------- +In general, any *Spotipy* method that needs an artist, album, track or playlist ID +will accept ids in any of the above form -.. automodule:: spotipy.__init__ - :members: - :undoc-members: - :show-inheritance: +API Reference +============== :mod:`client` Module -------------------- diff --git a/examples/long_track_test.dat b/examples/long_track_test.dat new file mode 100644 index 0000000..fac3f95 --- /dev/null +++ b/examples/long_track_test.dat @@ -0,0 +1,283 @@ +spotify:track:0qMujfRhXLalSaDtN0PPMS +spotify:track:0S7Dd8FfW5ZomBAwY3rBg6 +spotify:track:5gCvgOuAxw8YpHCV9m1xue +spotify:track:0eZoEIFWMNTt3BVejJdUH7 +spotify:track:3P6OwCX7Ofiaaqtvujb6i5 +spotify:track:2q3PUwv7bnSFHFn73WyzIv +spotify:track:2sOwqF4Meye7XjSiO2oZk8 +spotify:track:5Hfa4TyZO402MFD10VbRCv +spotify:track:6SJFk7LilJXZwp8rvzGc1T +spotify:track:1dVy8va6CN9sWd8ISPWbmg +spotify:track:2UC9CbjVQSCMHykP0D39lj +spotify:track:02LhttutJp836x9MmTjUXQ +spotify:track:2j5siP7TDM8p8KJYz21f7i +spotify:track:1QzEIizaV0H420lOVRa4dW +spotify:track:7Emg43gSQ281JmC5FKBX5X +spotify:track:6Ly0owXzUn5aNeTNBIOzKH +spotify:track:22WpTfGxNHK5fdBTbFKjvV +spotify:track:4jqMLKRvugl6ya7o9G40NP +spotify:track:5o9L8CttqYj339wDetGdcG +spotify:track:3LNr24GL6u2OdLVH7GqMlm +spotify:track:7exER11O6jaBmUWhOvWRGh +spotify:track:1NqsDKWgqhVVjCvDyArfWn +spotify:track:7AxQN7tWw0aHlS8yYG1mi4 +spotify:track:3aEMkgM7iVXWNqTuP9phSM +spotify:track:37JwzWYOOYz2in4tXNNISx +spotify:track:2jLRbx1FdLauLTpjvKTgII +spotify:track:50BttjUL1U1L3Ngb0DRUWw +spotify:track:2GYyXvlQHvhcP9KEJo7pQs +spotify:track:2x0supcZhd6NEH1nem9DnR +spotify:track:45aBkgJ9UV2XVvWrLMOsyd +spotify:track:4xVEXwEALvLrmW4aef7esn +spotify:track:558w6Ru8SJCNzk0xdmISqX +spotify:track:0JnBXtqagQOFV9w9x7N0K6 +spotify:track:5aUnqiF9Y3W0OITq0UJscm +spotify:track:0jPr0tQreoKXHl460Jhp3P +spotify:track:6loFvY6N6URSVSnTz2RZ7L +spotify:track:3YYdwYqIlz3MKTVQLkXQ9m +spotify:track:77t1U17P4Q6ihd8JOq8ODr +spotify:track:5um9oqJyIRSOxYi1r4X04f +spotify:track:3bEzNqaPcOW6lQrXafl6F6 +spotify:track:5iHVKPDXHF40LaBCrxBsGH +spotify:track:6QybCOHAvZVEierFVIzY6E +spotify:track:7qXqrMSj9gr2GUAdZDjknQ +spotify:track:6I658qHs4LntNGSUUn1JHW +spotify:track:1ODvt9aF7ZuJeUtQ3HHNAF +spotify:track:7iU2b4II1E0saCk9vgsO9h +spotify:track:3h9m1K11aR6MUYPoHI6uQY +spotify:track:5kiHXz2911MbTjORtQ2thG +spotify:track:1qYShm8Jvs8zY9ivWKUhj1 +spotify:track:07HTDHDHxuHwtvS7xMpCsF +spotify:track:0dLeXCoYP3LTzQShO0DWds +spotify:track:7qLEaxMiR8WUsCG1uOBsuO +spotify:track:2veYJl7RAW2lkveifGHYKT +spotify:track:5efdzHjhTXm3P32utkjZsB +spotify:track:6xKDnd8rau33dOcr4eaLGp +spotify:track:67q3zVsJsPRks4k0eomEWy +spotify:track:1zD5Vk9Ay0V8OOI4YKuoAf +spotify:track:2v9IJFdS1O3Xszio2DOq4J +spotify:track:1392JJKNqrtn6ZKQ8bqB6g +spotify:track:3KQuCRQ6J9unCt6fB9OLFw +spotify:track:0M2YiDrjeH9kCTVitG7GIZ +spotify:track:4QIUa0bsk6cmtyl9TsHpyX +spotify:track:6q7zNqL13uQ8cYeLJPAnvM +spotify:track:3Un3OOg3VQnVgzqYFwtSA1 +spotify:track:0xbF056L1Rh3aorkYrnrcw +spotify:track:6LPff9WXf0mo93hWLQDfW4 +spotify:track:6MVim3XIOHTUUJt6ZZ4xiI +spotify:track:4oopnnqYQep1bRRHjWI5NZ +spotify:track:2SylgYRXnwmYe5dVUswwVC +spotify:track:64PbCTNpfIfsYNnbRjrarf +spotify:track:0zvOZPdyqHPEWjvhyURQ5X +spotify:track:0CQpJlD9j8gkpF6vYpPBvE +spotify:track:2xJC5rQTpX9Yv5EhbpETkk +spotify:track:4hpx4xuGn53AH1nWVGRh8v +spotify:track:4xP5U2WqMJK20BO9D918RI +spotify:track:0NZCRmTQbH2CcTXrA1tINk +spotify:track:7CXdkXxOJrOWAwKKrSPlWS +spotify:track:6NmldQ2cNdas2Rv4YwIrfn +spotify:track:0NZCRmTQbH2CcTXrA1tINk +spotify:track:3s6bstAaZbC6uBHPuel3W6 +spotify:track:2hJ7E250KxFXuE0TCCfoI3 +spotify:track:1Sv7P3pIY2Zjzpen78OORc +spotify:track:5VD27c9f7BuDaRVplcnebl +spotify:track:1uyDxNgwyXIJRy87tyewDt +spotify:track:7nV61Rd3q3LwRUt5qQ5rtR +spotify:track:5Lp4xptZSf2khojxC8iehH +spotify:track:0IcFhAtZQqCgdv4ugyjQZx +spotify:track:0vyJfb5merhL1NtmrucJaH +spotify:track:1x95pWB3KeK3evKa1VrW6e +spotify:track:3HM8glYP7qh2VQ2DilsEAi +spotify:track:60TdUFHyUfcBmRuf4AMldq +spotify:track:1uqZw35kbgxuvb5nJJ5y23 +spotify:track:74sz92IUs02Bh2fJzXyGSK +spotify:track:583YTL8Fl6pCWtZAi2GvVZ +spotify:track:1dl7TO9hPWPaUwURKqBGmP +spotify:track:0ph9DIJozeJOEvIev5qVQk +spotify:track:4mai1CggFbdIpK8MEohA0K +spotify:track:6h7Kh7pGFAwB1dyghm0mZZ +spotify:track:7DOZPeLfQqkcskfKUKoAUf +spotify:track:3FPobLmheSF7QWzq4pDLD9 +spotify:track:3PRVwEDVVK5ITqwu0Hy84V +spotify:track:50xlAtqoFecexXj3N4kynJ +spotify:track:5vwudDPhjnuA1KrNsFjAHK +spotify:track:6BhyyrUEbOI7szsjgbzAju +spotify:track:3XfylwQhFCIoDvC0BNjCWt +spotify:track:0iuTv9sYunbo4zW6cykFYk +spotify:track:5y95ucn3laegC0ObJhlufv +spotify:track:0MkD7ugsiBFbK83ZwAvobZ +spotify:track:1UczOJLWGL9VQJVAePRMcI +spotify:track:4Ks83rDIAwNokEG4PYnog4 +spotify:track:2CgAKuEdwtx34U5T2rLyw4 +spotify:track:2H3YWZ3Q1PNtUA8z0mPpGQ +spotify:track:33F1I9sAEUcB7Q05tHh9fp +spotify:track:5vKOOD6x7YMqcvgxaGnt64 +spotify:track:4vnfKsDUJGaHqEnpNKLOL8 +spotify:track:0JbiyOEt6YuDFTZj7Rep8s +spotify:track:4DQTlpLapighigY8paBEd9 +spotify:track:38bq59et0KNcjTMQJAWDJs +spotify:track:2AckvF8zhoMhmZ49jmIf8O +spotify:track:0g0RzAZH3nlKWkl41CLyNT +spotify:track:5Og1ngUAa8N6GRdLJp81Pg +spotify:track:03W5lEf82eVBF8rjDxhbW2 +spotify:track:4VtD7qiPoHYpKAuOmTLyc2 +spotify:track:1Xn6hGSkbjbnOFKQxvk5Qh +spotify:track:7aiL6F8q7D10xQtXchzu2W +spotify:track:6HhZrrj25eb6hAcqa1jmIa +spotify:track:7568pJYdTxmQiyV2Pt3TAK +spotify:track:7sXcHlfKfEwPSGDrLmDbfB +spotify:track:57vgSkXvr4KkaCIJMWSFB2 +spotify:track:2T848jgfBpBt0vhw2LSKhN +spotify:track:1A3HGfeudhMFNd8b6Mswp8 +spotify:track:4DqnhrbWAH3I92TAqtBrGY +spotify:track:6jLrlevctgoeGPXDLEdt6L +spotify:track:2Ntx16XsOz8pMz3ygHodpS +spotify:track:02lTCqFw0RasK7xAqu5fqE +spotify:track:3Jxi6P3Y4bYXEAHhcYho4a +spotify:track:6urjT2UUnX83D8CDOPfux3 +spotify:track:4oobntmhVjfkWkSNAo9ijn +spotify:track:1yCxOSKbSlYAUbjeeH0Yv3 +spotify:track:4AMsQnCRSXL4x0C0b0i7kk +spotify:track:0WKdB7PG53c1QlDbQzqn7s +spotify:track:15zhodeybsv2mz5Yw7hS48 +spotify:track:4CL8fkzCyhM0DDlotIDDpr +spotify:track:7Cb1KVyKSOUauQLTofWKEw +spotify:track:0SfG2rMDw7ZviADcXv1TI0 +spotify:track:2j3PFZXmenUxgjjBUIod7F +spotify:track:0dOg1ySSI7NkpAe89Zo0b9 +spotify:track:6Pgm5NvlnLVqPvPtIMj6Dh +spotify:track:33OzFYIVWZPn0E6RHctiC9 +spotify:track:7yPvz9Z57Vq3DnA1LqTwER +spotify:track:6sWj81TNza7VqfspjWjHDc +spotify:track:2nXSfOUS7BmPhLRV6ehiml +spotify:track:1MqGKtY9L5qjPi8s7gX645 +spotify:track:7a61OH8U2s1OhVPgCuNPMZ +spotify:track:3fzE5vxFTZ2DRiIdKI4l4B +spotify:track:6YxJ9uq7ex1rcFfx6boYDo +spotify:track:3qnf1FH4LHe9bHXEuMUZoG +spotify:track:6Jb4MjZlwDOsKyqXXCw7X6 +spotify:track:35YJCWAB360MTp0AxSZgNB +spotify:track:4f2FDf06hmv5YptohyLQV8 +spotify:track:0pkIyrSYE0BRpw4nNsBlmq +spotify:track:1ek5AmqUXMkx3eQPytV1BN +spotify:track:4jRtPv8a9wcpm8gJEKQSlR +spotify:track:1Fv48qm7W9AR1PwVc3wS9A +spotify:track:1mUpXELX93AvTswzLLY0UT +spotify:track:1qvFHNSBXGOsryKOr3p03m +spotify:track:5pvIVmZJZIc8SE3Gk3sEye +spotify:track:5ynfc3x7H5t8shUZRZpb6N +spotify:track:48Wl0w5LmiqhWwYVK9Win7 +spotify:track:45qDQvSBricT3zn3jzAxnk +spotify:track:0Gh1GsynRMY3cZZY7G0dlY +spotify:track:01nP5PpbvUBcAIMQW5i1vP +spotify:track:26Sm4ymfC0TVUK2RnHlciw +spotify:track:1myBSHHET1Re4UTSGmneeH +spotify:track:2dTRTQXRSCo4zgiXlyYaY3 +spotify:track:5qKmpbegJWROssoQgo0r7O +spotify:track:5IT43uHiMbw4AdI9VcCZxm +spotify:track:2ggBhNH6UexpYnziaW78SG +spotify:track:600wNkX9UT5rB0HRceHxX7 +spotify:track:30dT0S656DlaJrtimk8ItR +spotify:track:1PCftEVEn0PihLine6dIHQ +spotify:track:788Cp8dfA6GWwyEP8qHXTG +spotify:track:4DHKG1Hewrb9fTzVUXRl2D +spotify:track:0RQ3uttlfwETe72tZZQZFw +spotify:track:6kLfEKc7z5trZKWCv8hCYX +spotify:track:4RcRScJt7v5FhaZaCAWQ0T +spotify:track:4aJKkm3GYi8rCYPbhV8r0b +spotify:track:7IU6s1cVja1qWFmXkmR7iA +spotify:track:6vZLotWyNDlzDjoqY0Ec0D +spotify:track:5I6Y18eR8JelTClXNKdL2B +spotify:track:3ZKSCv9AfXOUuFO9j27EOb +spotify:track:0m4RZWh8jsqwIFZFxpNJZI +spotify:track:36NwlLTSsboo9SeQpTE3Mo +spotify:track:0M7mWKqwTIaVjYyxfZmtTa +spotify:track:0gnTF8QD5apHcK86nvCkrp +spotify:track:5MF1TOtDyYMQIyBXSDnzSu +spotify:track:12UzVR0M7asW2MHAZRJk0I +spotify:track:6uJpoNDk8sgJlQ13hKwGWH +spotify:track:50GWfznvmLBhUlHYKMq9G8 +spotify:track:7mIEvNbJxo1aEAGd7DkiC3 +spotify:track:1BY78IlCc8KiZjYLi9tk0l +spotify:track:4oYbwL03t1isZD4cFPtCxM +spotify:track:7lPzpmqhKwMaETmOBVTamL +spotify:track:5RqFC823JhgZjcX2p5pLC2 +spotify:track:6EHBJHPgbFv2uEdljLTYUo +spotify:track:0MCkLZZP1CJXOzBe2XGcdm +spotify:track:42I483ip9VozNoMKfbbnls +spotify:track:0BK3KDnit2B9lGptYsOyNG +spotify:track:0cVwLfU8BXN9zxZ2HKns9h +spotify:track:6mBsRxVAfZ7TdrooLmxexO +spotify:track:6QyJ8AQSoH1zJFyf86E6mx +spotify:track:5Vo4Lu0SF93q8pHFo68UOa +spotify:track:5EyYnQ3F8sPaylsWFTR4Qg +spotify:track:5lTEhTjBY2grPGjLKFSuks +spotify:track:0kcGX9Z9Q5i6EHX1QLNXDp +spotify:track:3t4hsTZCob6hwJU2f5Pz3u +spotify:track:2xHRb4OLnfhQMdJSyMW2dU +spotify:track:21l0IzdoW75sT5TewUT22V +spotify:track:5wllnBkcq1IMlTXnaW6Jv3 +spotify:track:4Uvbm8ijckGf4xDer9SF9s +spotify:track:1zKkQ6gyZQOMw68CUCf8GX +spotify:track:6pi7OwWvCYaOvEqAfBYiM4 +spotify:track:34yStWRRrbosgMs32yMlc1 +spotify:track:7gSbqXLD5glv5w7giXInvf +spotify:track:7EaYzSnP0akAQVfCu4RFBX +spotify:track:4Iduy3277LDiuCztPw9NAS +spotify:track:4UBTrrSotbB1DaRbapsR0R +spotify:track:54fskci17LPbSCmE2qGAD5 +spotify:track:1H84cRYr4wzEwgFM9PGOE5 +spotify:track:5nfQ7FgSfCG5FRK0Xoxy3M +spotify:track:7tSlB26fVA76eCVJQz1ueH +spotify:track:2hftOwcKNudZraI6Edvh8t +spotify:track:6CZEhTgAiPCa4fAD269PlI +spotify:track:2dPKh2wXy4Fc1S9UcmHRNu +spotify:track:4UDWJipAonm3DzOvRIo5N2 +spotify:track:3Goagh1ioAxjfKA5W6eqNN +spotify:track:6tT1EQyFcOZfmZQf1wSjtb +spotify:track:5KNltwC6xlNHIzUrigMISL +spotify:track:1HpTDohERdRdSw195oPKUv +spotify:track:5X5rx4uRMEWwxD1Lwl2NQU +spotify:track:43dgoxSKLWvfeUWZ9uEEWK +spotify:track:3KRGfygdhSiGG9r5JmWFZV +spotify:track:7u3L8sB8NdL5UeARrFN536 +spotify:track:0fZQfEfq9JxUEy1FjqOiCZ +spotify:track:58TxkZIEZWtqPMn1Y4Vd3t +spotify:track:3P4J0WzZSXGpl9z8Suz5jO +spotify:track:37Z1knZBcsUQfc1jM1zrOu +spotify:track:0yHBzIb97dsuxcOkRhKU0v +spotify:track:3emSZCViwDicSLBi6SMIRX +spotify:track:3bL9LUHgTTqPeU7s3bqyMd +spotify:track:6864dMeIjWotTlWlbhUsbr +spotify:track:78bpVL8pZBGhQa6CV9Bvlq +spotify:track:7F3WX3rfpm29WDy8UkfKmg +spotify:track:3uQDfCKlwfK9Yz10JFcsC7 +spotify:track:2ZyTdkTn5h4xPgX48hWGdI +spotify:track:4qb2AKvnaDdvJJnKmxo9ST +spotify:track:1Nruw7r9cwfQVLz7j9Qc1b +spotify:track:5bOG5FKR5eJOhNYCIO4E35 +spotify:track:5ZCjhZABvYc50lt5zRPdgZ +spotify:track:2kSpNkYlQCRCZX0a6tW02a +spotify:track:7HUFClGakCCS6DUHkdey5M +spotify:track:3CbPsxgJB53v51wWqcY6oD +spotify:track:5twEsir35519mNkxfH9Lnv +spotify:track:2HRYa6iG1M5DRefO8pK2I3 +spotify:track:2x0supcZhd6NEH1nem9DnR +spotify:track:5bZI4j4gZQUj0ZkE2wER9O +spotify:track:0yuKuvDJlOf4GjUtf3OPjf +spotify:track:28BFxsobryXuZghzAGBImi +spotify:track:50nv5PDK8zVmdIC7KdBSOz +spotify:track:3kJ6B8jf7G2KRPELgntYOL +spotify:track:3HJ8LpromeQLHrP5XPuBL3 +spotify:track:2KPflscGoyKv5Kc6PG7KNe +spotify:track:6ytJGSzgBunW0VePRAyhNn +spotify:track:1QninLAEEtyzoDTCsGNrQz +spotify:track:7oyKc3RgnMaSRgwNTLCDgE +spotify:track:0PA9HmVnyHknT43go3tFz3 +spotify:track:5cp7armpdpEOfdkD5WiX6q +spotify:track:1qmJbXpVLydNcN6VTR40GU +spotify:track:2bdapwYVEGpGWxlx3iooAB +spotify:track:21YbiQuw6j4k6DOBzE79z2 +spotify:track:31WCZ6zpqXOz3Rljc0Yor8 +spotify:track:3Ozp5uFYtC4Q6X4L4ivBDv + diff --git a/examples/show_my_saved_tracks.py b/examples/show_my_saved_tracks.py index 0dbb512..ee972fa 100644 --- a/examples/show_my_saved_tracks.py +++ b/examples/show_my_saved_tracks.py @@ -1,11 +1,8 @@ # Adds tracks to a playlist -import pprint import sys - import spotipy -import spotipy.oauth2 as oauth2 import spotipy.util as util scope = 'user-library-read' @@ -20,8 +17,9 @@ token = util.prompt_for_user_token(username, scope) if token: sp = spotipy.Spotify(auth=token) - sp.trace = False results = sp.current_user_saved_tracks() - pprint.pprint(results) + for item in results['items']: + track = item['track'] + print track['name'] + ' - ' + track['artists'][0]['name'] else: print "Can't get token for", username diff --git a/spotipy/client.py b/spotipy/client.py index 3aeac95..a2dc9d8 100644 --- a/spotipy/client.py +++ b/spotipy/client.py @@ -22,7 +22,7 @@ class SpotifyException(Exception): class Spotify(object): ''' - Example usage: + Example usage:: import spotipy @@ -324,8 +324,7 @@ class Spotify(object): Parameters: - user - the id of the user - playlist_id - the id of the playlist - - tracks - the list of track URIs, URLs or IDs to add - to the playlist + - tracks - the list of track ids to add to the playlist ''' plid = self._get_id('playlist', playlist_id) ftracks = [ self._get_uri('track', tid) for tid in tracks] @@ -340,9 +339,10 @@ class Spotify(object): Parameters: - user - the id of the user - playlist_id - the id of the playlist - - tracks - the list of track URIs, URLs or IDs to add - to the playlist + - tracks - the list of track ids to add to the playlist + ''' + plid = self._get_id('playlist', playlist_id) ftracks = [ self._get_uri('track', tid) for tid in tracks] payload = { "tracks": [ {"uri": track} for track in ftracks] } @@ -356,14 +356,11 @@ class Spotify(object): Parameters: - user - the id of the user - playlist_id - the id of the playlist - - tracks - an array of objects containing Spotify URIs of the - tracks to remove with their current positions in - the playlist. For example: - [ - {"uri": "spotify:track:4iV5W9uYEdYUVa79Axb7Rh", "positions": [2] }, - {"uri": "spotify:track:1301WleyT98MSxVHPZCA6M", "positions": [7] } - ] + - tracks - an array of objects containing Spotify URIs of the tracks to remove with their current positions in the playlist. For example: + [ { "uri":"4iV5W9uYEdYUVa79Axb7Rh", "positions":[2] }, + { "uri":"1301WleyT98MSxVHPZCA6M", "positions":[7] } ] ''' + plid = self._get_id('playlist', playlist_id) ftracks = [ self._get_uri('track', tid) for tid in tracks] payload = { "tracks": ftracks } diff --git a/spotipy/oauth2.py b/spotipy/oauth2.py index 8fd91b3..8692500 100644 --- a/spotipy/oauth2.py +++ b/spotipy/oauth2.py @@ -37,7 +37,7 @@ class SpotifyOAuth(object): self.redirect_uri = redirect_uri self.state=state self.cache_path = cache_path - self.scope=self.normalize_scope(scope) + self.scope=self._normalize_scope(scope) def get_cached_token(self): token_info = None @@ -52,14 +52,14 @@ class SpotifyOAuth(object): if 'scope' not in token_info or self.scope != token_info['scope']: return None - if self.is_token_expired(token_info): - token_info = self.refresh_access_token(token_info['refresh_token']) + if self._is_token_expired(token_info): + token_info = self._refresh_access_token(token_info['refresh_token']) except IOError: pass return token_info - def save_token_info(self, token_info): + def _save_token_info(self, token_info): if self.cache_path: try: f = open(self.cache_path, 'w') @@ -70,7 +70,7 @@ class SpotifyOAuth(object): pass - def is_token_expired(self, token_info): + def _is_token_expired(self, token_info): now = int(time.time()) return token_info['expires_at'] < now @@ -112,10 +112,10 @@ class SpotifyOAuth(object): raise SpotifyOauthError(response.reason) token_info = response.json() token_info = self._add_custom_values_to_token_info(token_info) - self.save_token_info(token_info) + self._save_token_info(token_info) return token_info - def normalize_scope(self, scope): + def _normalize_scope(self, scope): if scope: scopes = scope.split() scopes.sort() @@ -123,7 +123,7 @@ class SpotifyOAuth(object): else: return None - def refresh_access_token(self, refresh_token): + def _refresh_access_token(self, refresh_token): payload = { 'refresh_token': refresh_token, 'grant_type': 'refresh_token'} @@ -143,7 +143,7 @@ class SpotifyOAuth(object): token_info = self._add_custom_values_to_token_info(token_info) if not 'refresh_token' in token_info: token_info['refresh_token'] = refresh_token - self.save_token_info(token_info) + self._save_token_info(token_info) return token_info def _add_custom_values_to_token_info(self, token_info): diff --git a/spotipy/util.py b/spotipy/util.py index e836a73..8df4572 100644 --- a/spotipy/util.py +++ b/spotipy/util.py @@ -23,22 +23,22 @@ def prompt_for_user_token(username, scope=None, client_id = None, ''' if not client_id: - client_id = os.getenv('CLIENT_ID') + client_id = os.getenv('SPOTIPY_CLIENT_ID') if not client_secret: - client_secret = os.getenv('CLIENT_SECRET') + client_secret = os.getenv('SPOTIPY_CLIENT_SECRET') if not redirect_uri: - redirect_uri = os.getenv('REDIRECT_URI') + redirect_uri = os.getenv('SPOTIPY_REDIRECT_URI') if not client_id: print ''' You need to set your Spotify API credentials. You can do this by setting environment variables like so: - export CLIENT_ID='your-spotify-client-id' - export CLIENT_SECRET='your-spotify-client-secret' - export REDIRECT_URI='your-app-redirect-url' + export SPOTIPY_CLIENT_ID='your-spotify-client-id' + export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret' + export SPOTIPY_REDIRECT_URI='your-app-redirect-url' Get your credentials at https://developer.spotify.com/my-applications