defmodule Spotify.Playlist do
@moduledoc """
Functions for retrieving information about a user’s playlists and for
managing a user’s playlists.
Some endpoints return collections. Spotify wraps the collection in a paging object,
this API does the same. A single piece of data will not be wrapped.
There are two functions for each endpoint, one that actually makes the request,
and one that provides the endpoint:
Spotify.Playist.create_playlist(conn, "foo", "bar") # makes the POST request.
Spotify.Playist.create_playlist_url("foo", "bar") # provides the url for the request.
https://developer.spotify.com/web-api/playlist-endpoints/
"""
import Spotify.Helpers
use Spotify.Responder
alias Spotify.{
Client,
Paging
}
defstruct ~w[
collaborative
description
external_urls
followers
href
id
images
name
owner
public
snapshot_id
tracks
type
uri
]a
@doc """
Get a list of featured playlists.
[Spotify Documenation](https://developer.spotify.com/web-api/get-list-featured-playlists/)
**Valid params**: `locale`, `country`, `timestamp`, `limit`, `offset`
**Method**: `GET`
Spotify.Playlist.featured(country: "US")
# => {:ok, %{ items: [%Spotify.Playlist{..} ...]}}
"""
def featured(conn, params \\ []) do
url = featured_url(params)
conn |> Client.get(url) |> handle_response
end
@doc """
Get a list of featured playlists.
iex> Spotify.Playlist.featured_url(country: "US")
"https://api.spotify.com/v1/browse/featured-playlists?country=US"
"""
def featured_url(params \\ []) do
"https://api.spotify.com/v1/browse/featured-playlists" <> query_string(params)
end
@doc """
Get a category's playlists.
[Spotify Documentation](https://developer.spotify.com/web-api/get-categorys-playlists/)
**Valid params**: `country`, `limit`, `offset`
**Method**: `GET`
## Example:
Spotify.by_category(conn, "123")
# => {:ok, %{ items: [%Spotify.Playlist{..} ...]}}
"""
def by_category(conn, id, params \\ []) do
url = by_category_url(id, params)
conn |> Client.get(url) |> handle_response
end
@doc """
Get a category's playlists.
iex> Spotify.Playlist.by_category_url("123", [country: "US", limit: 5])
"https://api.spotify.com/v1/browse/categories/123/playlists?country=US&limit=5"
"""
def by_category_url(id, params \\ []) do
"https://api.spotify.com/v1/browse/categories/#{id}/playlists" <> query_string(params)
end
@doc """
Add the current user as a follower of a playlist.
[Spotify Documentation](https://developer.spotify.com/web-api/follow-playlist/)
**Optional Body Params**: `public`
**Method**: `PUT`
Spotify.Playlist.follow_playlist(conn, "123", "456")
# => :ok
"""
def follow_playlist(conn, owner_id, playlist_id, body \\ "") do
url = follow_playlist_url(owner_id, playlist_id)
conn |> Client.put(url, body) |> handle_response
end
@doc """
Add the current user as a follower of a playlist.
iex> Spotify.Playlist.follow_playlist_url("123", "456")
"https://api.spotify.com/v1/users/123/playlists/456/followers"
"""
def follow_playlist_url(owner_id, playlist_id) do
get_playlist_url(owner_id, playlist_id) <> "/followers"
end
@doc """
Remove the current user as a follower of a playlist.
[Spotify Documentation](https://developer.spotify.com/web-api/unfollow-playlist/)
**Method**: `DELETE`
Spotify.Playlist.unfollow_playlist(conn, "123", "456")
# => :ok
"""
def unfollow_playlist(conn, owner_id, playlist_id) do
url = unfollow_playlist_url(owner_id, playlist_id)
conn |> Client.delete(url) |> handle_response
end
@doc """
Remove the current user as a follower of a playlist.
iex> Spotify.Playlist.unfollow_playlist_url("123", "456")
"https://api.spotify.com/v1/users/123/playlists/456/followers"
"""
def unfollow_playlist_url(owner_id, playlist_id) do
follow_playlist_url(owner_id, playlist_id)
end
@doc """
Get a list of the playlists owned or followed by a Spotify user.
[Spotify Documentation](https://developer.spotify.com/web-api/get-list-users-playlists/)
**Method**: `GET`
** Optional Params: `limit`, `offset`
Spotify.Playlist.get_users_playlists(conn, "123", q: "foo", limit: 5)
# => {:ok, %{
# cursor: nil,
# href: ..,
# items: [%Spotify.Playlist{..} ...],
# limit: 20,
# next: nil,
# offset: 0,
# previous: nil,
# total: 20
# }
# }
"""
def get_users_playlists(conn, user_id, params \\ []) do
url = get_users_playlists_url(user_id, params)
conn |> Client.get(url) |> handle_response
end
@doc """
Get a list of the playlists owned or followed by a Spotify user.
iex> Spotify.Playlist.get_users_playlists_url("123", limit: 5)
"https://api.spotify.com/v1/users/123/playlists?limit=5"
"""
def get_users_playlists_url(user_id, params \\ []) do
"https://api.spotify.com/v1/users/#{user_id}/playlists" <> query_string(params)
end
@doc """
Get a list of the playlists owned or followed by the current Spotify user.
[Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/playlists/get-a-list-of-current-users-playlists/)
**Method**: `GET`
** Optional Params: `limit`, `offset`
Spotify.Playlist.get_users_playlists(conn, "123", q: "foo", limit: 5)
# => {:ok, %{
# cursor: nil,
# href: ..,
# items: [%Spotify.Playlist{..} ...],
# limit: 20,
# next: nil,
# offset: 0,
# previous: nil,
# total: 20
# }
# }
"""
def get_current_user_playlists(conn, params \\ []) do
url = get_current_user_playlists_url(params)
conn |> Client.get(url) |> handle_response
end
@doc """
Get a list of the playlists owned or followed by a Spotify user.
iex> Spotify.Playlist.get_current_user_playlists_url(limit: 5)
"https://api.spotify.com/v1/me/playlists?limit=5"
"""
def get_current_user_playlists_url(params \\ []) do
"https://api.spotify.com/v1/me/playlists" <> query_string(params)
end
@doc """
Get a playlist owned by a Spotify user.
[Spotify Documentation](https://developer.spotify.com/web-api/get-playlist/)
**Method**: `GET`
**Optional Params `fields, market`
Spotify.Playlist.get_playlist(conn, "123", "456")
# => {:ok, %Spotify.Playlist{..}}
"""
def get_playlist(conn, user_id, playlist_id, params \\ []) do
url = get_playlist_url(user_id, playlist_id, params)
conn |> Client.get(url) |> handle_response
end
@doc """
Get a playlist owned by a Spotify user.
iex> Spotify.Playlist.get_playlist_url("123", "456", market: "foo")
"https://api.spotify.com/v1/users/123/playlists/456?market=foo"
"""
def get_playlist_url(user_id, playlist_id, params \\ []) do
"https://api.spotify.com/v1/users/#{user_id}/playlists/#{playlist_id}" <> query_string(params)
end
@doc """
Get full details of the tracks of a playlist owned by a Spotify user.
[Spotify Documentation](https://developer.spotify.com/web-api/get-playlists-tracks/)
**Method**: `GET`
**Optional Params `fields`, `market`, `limit`, `offset`
Spotify.Playlist.get_playlist_tracks(conn, "123", "456")
# => {:ok, %Spotify.Playlist{..}}
"""
def get_playlist_tracks(conn, user_id, playlist_id, params \\ []) do
alias Spotify.Playlist.Track, as: Track
url = get_playlist_tracks_url(user_id, playlist_id, params)
conn |> Client.get(url) |> Track.handle_response()
end
@doc """
Get full details of the tracks of a playlist owned by a Spotify user.
iex> Spotify.Playlist.get_playlist_tracks_url("123", "456", limit: 5, offset: 5)
"https://api.spotify.com/v1/users/123/playlists/456/tracks?limit=5&offset=5"
"""
def get_playlist_tracks_url(user_id, playlist_id, params \\ []) do
playlist_tracks_url(user_id, playlist_id) <> query_string(params)
end
@doc false
def playlist_tracks_url(user_id, playlist_id) do
get_playlist_url(user_id, playlist_id) <> "/tracks"
end
@doc """
Create a playlist for a Spotify user. (The playlist will be empty until you add tracks.)
[Spotify Documentation](https://developer.spotify.com/web-api/create-playlist/)
**Method**: `POST`
**Body Params**: `name`, `public`
body = "\{\"name\": \"foo\"}"
Spotify.Playlist.create_playlist(conn, "123", body)
# => %Spotify.Playlist{..}
"""
def create_playlist(conn, user_id, body) do
url = create_playlist_url(user_id)
conn |> Client.post(url, body) |> handle_response
end
@doc """
Create a playlist for a Spotify user. (The playlist will be empty until you add tracks.)
iex> Spotify.Playlist.create_playlist_url("123")
"https://api.spotify.com/v1/users/123/playlists"
"""
def create_playlist_url(user_id) do
"https://api.spotify.com/v1/users/#{user_id}/playlists"
end
@doc """
Change a playlist’s name and public/private state. (The user must, of course, own the playlist.)
[Spotify Documentation](https://developer.spotify.com/web-api/change-playlist-details/)
**Method**: `PUT`
**Request Data)**: `name`, `public`
body = "{ \"name\": \"foo\", \"public\": true }"
Spotify.Playlist.change_playlist(conn, "123", "456", body)
# => :ok
"""
def change_playlist(conn, user_id, playlist_id, body) do
url = change_playlist_url(user_id, playlist_id)
conn |> Client.put(url, body) |> handle_response
end
@doc """
Change a playlist’s name and public/private state. (The user must, of course, own the playlist.)
iex> Spotify.Playlist.change_playlist_url("123", "456")
"https://api.spotify.com/v1/users/123/playlists/456"
"""
def change_playlist_url(user_id, playlist_id) do
get_playlist_url(user_id, playlist_id)
end
@doc """
Add one or more tracks to a user’s playlist.
[Spotify Documentation](https://developer.spotify.com/web-api/add-tracks-to-playlist/)
**Method**: `POST`
**Optional Params**: `uris`, `position`
You can also pass the URI param in the request body. If you don't want to
pass params, use an empty list. See Spotify docs and add_tracks/5.
body = Poison.encode!(%{ uris: [ "spotify:track:755MBpLqJqCO87PkoyBBQC", "spotify:track:1hsWu8gT2We6OzjhYGAged" ]})
Spotify.Playlist.add_tracks("123", "456", body, [])
# => {:ok, %{"snapshot_id" => "foo"}}
"""
def add_tracks(conn, user_id, playlist_id, body, params) do
url = add_tracks_url(user_id, playlist_id, params)
conn |> Client.post(url, body) |> handle_response
end
@doc """
Add one or more tracks to a user’s playlist.
[Spotify Documentation](https://developer.spotify.com/web-api/add-tracks-to-playlist/)
**Method**: `POST`
**Optional Params**: `uris`, `position`
You can also pass the URI param in the request body. See Spotify docs and add_tracks/4.
Spotify.Playlist.add_tracks("123", "456", uris: "spotify:track:4iV5W9uYEdYUVa79Axb7Rh")
# => {:ok, %{"snapshot_id" => "foo"}}
"""
def add_tracks(conn, user_id, playlist_id, params) do
url = add_tracks_url(user_id, playlist_id, params)
conn |> Client.post(url) |> handle_response
end
@doc """
Add one or more tracks to a user’s playlist.
iex> Spotify.Playlist.add_tracks_url("123", "456", uris: "spotify:track:4iV5W9uYEdYUVa79Axb7Rh")
"https://api.spotify.com/v1/users/123/playlists/456/tracks?uris=spotify%3Atrack%3A4iV5W9uYEdYUVa79Axb7Rh"
"""
def add_tracks_url(user_id, playlist_id, params \\ []) do
playlist_tracks_url(user_id, playlist_id) <> query_string(params)
end
@doc """
Remove one or more tracks from a user’s playlist.
[Spotify Documentation](https://developer.spotify.com/web-api/remove-tracks-playlist/)
**Method**: `DELETE`
**Request Data**: `tracks`
Spotify.Playlist.remove_tracks(conn, "123", "456")
# => {:ok, %{"snapshot_id": "foo"}}
"""
def remove_tracks(conn, user_id, playlist_id) do
url = playlist_tracks_url(user_id, playlist_id)
conn |> Client.delete(url) |> handle_response
end
@doc """
Remove one or more tracks from a user’s playlist.
iex> Spotify.Playlist.remove_tracks_url("123", "456")
"https://api.spotify.com/v1/users/123/playlists/456/tracks"
"""
def remove_tracks_url(user_id, playlist_id) do
playlist_tracks_url(user_id, playlist_id)
end
@doc """
Reorder a track or a group of tracks in a playlist.
[Spotify Documentation](https://developer.spotify.com/web-api/reorder-playlists-tracks/)
**Method**: `PUT`
**Required Request Body Data**: `range_start`, `insert_before`
**Optional Request Body Data**: `range_length`, `snapshot_id`
body = { \"range_start\": \"...\" }
Spotify.Playlist.change_playlist(conn, "123", "456", body)
# => {:ok, %{"snapshot_id" => "klq34klj..."} }
"""
def reorder_tracks(conn, user_id, playlist_id, body) do
url = playlist_tracks_url(user_id, playlist_id)
conn |> Client.put(url, body) |> handle_response
end
@doc """
Reorder a track or a group of tracks in a playlist.
iex> Spotify.Playlist.reorder_tracks_url("123", "456")
"https://api.spotify.com/v1/users/123/playlists/456/tracks"
"""
def reorder_tracks_url(user_id, playlist_id) do
playlist_tracks_url(user_id, playlist_id)
end
@doc """
Replace all the tracks in a playlist, overwriting its existing tracks. This
powerful request can be useful for replacing tracks, re-ordering existing
tracks, or clearing the playlist.
[Spotify Documentation](https://developer.spotify.com/web-api/replace-playlists-tracks/)
**Method**: `PUT`
**Optional Query Params**: `uris`
You can also pass the URI param in the request body. Use `replace_tracks/2`. See Spotify docs.
Spotify.Playlist.replace_tracks(conn, "123", "456", uris: "spotify:track:4iV5W9uYEdYUVa79Axb7Rh,spotify:track:adkjaklsd94h")
:ok
"""
def replace_tracks(conn, user_id, playlist_id, params) when is_list(params) do
url = replace_tracks_url(user_id, playlist_id, params)
conn |> Client.put(url) |> handle_response
end
def replace_tracks(conn, user_id, playlist_id, body) when is_binary(body) do
url = replace_tracks_url(user_id, playlist_id)
conn |> Client.put(url, body) |> handle_response
end
@doc """
Replace all the tracks in a playlist, overwriting its existing tracks. This
iex> Spotify.Playlist.replace_tracks_url("123", "456", uris: "spotify:track:4iV5W9uYEdYUVa79Axb7Rh,spotify:track:adkjaklsd94h")
"https://api.spotify.com/v1/users/123/playlists/456/tracks?uris=spotify%3Atrack%3A4iV5W9uYEdYUVa79Axb7Rh%2Cspotify%3Atrack%3Aadkjaklsd94h"
"""
def replace_tracks_url(user_id, playlist_id, params \\ []) do
playlist_tracks_url(user_id, playlist_id) <> query_string(params)
end
@doc """
Check to see if one or more Spotify users are following a specified playlist.
[Spotify Documentation](https://developer.spotify.com/web-api/check-user-following-playlist/)
**Method**: `GET`
**Query Params: `ids`
Spotify.Playlist.check_followers(conn, "123", "456", ids: "foo,bar")
# => {:ok, boolean}
"""
def check_followers(conn, owner_id, playlist_id, params) do
url = check_followers_url(owner_id, playlist_id, params)
conn |> Client.get(url) |> handle_response
end
@doc """
Check to see if one or more Spotify users are following a specified playlist.
iex> Spotify.Playlist.check_followers_url("123", "456", ids: "foo,bar")
"https://api.spotify.com/v1/users/123/playlists/456/followers/contains?ids=foo%2Cbar"
"""
def check_followers_url(owner_id, playlist_id, params) do
"https://api.spotify.com/v1/users/#{owner_id}/playlists/#{playlist_id}/followers/contains" <>
query_string(params)
end
@doc """
Implements the hook expected by the Responder behaviour
"""
def build_response(body) do
case body do
%{"items" => _items} = response -> build_paged_response(response)
%{"playlists" => playlists} -> build_paged_response(playlists)
_ -> to_struct(__MODULE__, body)
end
end
@doc false
defp build_paged_response(response) do
%Paging{
href: response["href"],
items: build_playlists(response["items"]),
limit: response["limit"],
next: response["next"],
offset: response["offset"],
previous: response["previous"],
total: response["total"]
}
end
@doc false
def build_playlists(playlists) do
Enum.map(playlists, &to_struct(__MODULE__, &1))
end
end