defmodule Spotify.Player do @moduledoc """ Provides functions for retrieving and manipulating user's current playback. https://developer.spotify.com/documentation/web-api/reference/player/ """ use Spotify.Responder import Spotify.Helpers alias Spotify.{ Client, Context, CurrentlyPlaying, Device, Episode, History, Paging, Playback, Track } @doc """ Add an item to the user's playback queue. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/add-to-queue/) **Method**: `POST` **Optional Params**: `device_id` """ def enqueue(conn, uri, params \\ []) do url = params |> Keyword.put(:uri, uri) |> enqueue_url() conn |> Client.post(url) |> handle_response() end @doc """ iex> Spotify.Player.enqueue_url(device_id: "abc") "https://api.spotify.com/v1/me/player/queue?device_id=abc" """ def enqueue_url(params \\ []) do "https://api.spotify.com/v1/me/player/queue" <> query_string(params) end @doc """ Get the user's available devices. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/get-a-users-available-devices/) **Method**: `GET` """ def get_devices(conn) do url = devices_url() conn |> Client.get(url) |> handle_response() end @doc """ iex> Spotify.Player.devices_url "https://api.spotify.com/v1/me/player/devices" """ def devices_url do "https://api.spotify.com/v1/me/player/devices" end @doc """ Get information about the user's playback currently playing context. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/get-information-about-the-users-current-playback/) **Method**: `GET` **Optional Params**: `market`, `additional_types` """ def get_current_playback(conn, params \\ []) do url = player_url(params) conn |> Client.get(url) |> handle_response() end @doc """ iex> Spotify.Player.player_url(market: "US") "https://api.spotify.com/v1/me/player?market=US" """ def player_url(params \\ []) do "https://api.spotify.com/v1/me/player" <> query_string(params) end @doc """ Get the user's recently played tracks. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/get-recently-played/) **Method**: `GET` **Optional Params**: `limit`, `after`, `before` """ def get_recently_played(conn, params \\ []) do url = recently_played_url(params) conn |> Client.get(url) |> handle_response() end @doc """ iex> Spotify.Player.recently_played_url(limit: 50) "https://api.spotify.com/v1/me/player/recently-played?limit=50" """ def recently_played_url(params \\ []) do "https://api.spotify.com/v1/me/player/recently-played" <> query_string(params) end @doc """ Get the user's currently playing tracks. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/get-the-users-currently-playing-track/) **Method**: `GET` **Optional Params**: `market`, `additional_types` """ def get_currently_playing(conn, params \\ []) do url = currently_playing_url(params) conn |> Client.get(url) |> handle_response() end @doc """ iex> Spotify.Player.currently_playing_url(market: "US") "https://api.spotify.com/v1/me/player/currently-playing?market=US" """ def currently_playing_url(params \\ []) do "https://api.spotify.com/v1/me/player/currently-playing" <> query_string(params) end @doc """ Pause the user's playback. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/pause-a-users-playback/) **Method**: `PUT` **Optional Params**: `device_id` """ def pause(conn, params \\ []) do url = pause_url(params) conn |> Client.put(url) |> handle_response() end @doc """ iex> Spotify.Player.pause_url(device_id: "abc") "https://api.spotify.com/v1/me/player/pause?device_id=abc" """ def pause_url(params \\ []) do "https://api.spotify.com/v1/me/player/pause" <> query_string(params) end @doc """ Seek to position in currently playing track. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/seek-to-position-in-currently-playing-track/) **Method**: `PUT` **Optional Params**: `device_id` """ def seek(conn, position_ms, params \\ []) do url = params |> Keyword.put(:position_ms, position_ms) |> seek_url() conn |> Client.put(url) |> handle_response() end @doc """ iex> Spotify.Player.seek_url(device_id: "abc") "https://api.spotify.com/v1/me/player/seek?device_id=abc" """ def seek_url(params \\ []) do "https://api.spotify.com/v1/me/player/seek" <> query_string(params) end @doc """ Set repeat mode for the user's playback. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/set-repeat-mode-on-users-playback/) **Method**: `PUT` **Optional Params**: `device_id` """ def set_repeat(conn, state, params \\ []) when state in [:track, :context, :off] do url = params |> Keyword.put(:state, state) |> repeat_url() conn |> Client.put(url) |> handle_response() end @doc """ iex> Spotify.Player.repeat_url(device_id: "abc") "https://api.spotify.com/v1/me/player/repeat?device_id=abc" """ def repeat_url(params \\ []) do "https://api.spotify.com/v1/me/player/repeat" <> query_string(params) end @doc """ Set volume for the user's playback. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/set-volume-for-users-playback/) **Method**: `PUT` **Optional Params**: `device_id` """ def set_volume(conn, volume_percent, params \\ []) when volume_percent in 0..100 do url = params |> Keyword.put(:volume_percent, volume_percent) |> volume_url() conn |> Client.put(url) |> handle_response() end @doc """ iex> Spotify.Player.volume_url(device_id: "abc") "https://api.spotify.com/v1/me/player/volume?device_id=abc" """ def volume_url(params \\ []) do "https://api.spotify.com/v1/me/player/volume" <> query_string(params) end @doc """ Skip the user's playback to next track. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/skip-users-playback-to-next-track/) **Method**: `POST` **Optional Params**: `device_id` """ def skip_to_next(conn, params \\ []) do url = next_url(params) conn |> Client.post(url) |> handle_response() end @doc """ iex> Spotify.Player.next_url(device_id: "abc") "https://api.spotify.com/v1/me/player/next?device_id=abc" """ def next_url(params \\ []) do "https://api.spotify.com/v1/me/player/next" <> query_string(params) end @doc """ Skip the user's playback to previous track. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/skip-users-playback-to-previous-track/) **Method**: `POST` **Optional Params**: `device_id` """ def skip_to_previous(conn, params \\ []) do url = previous_url(params) conn |> Client.post(url) |> handle_response() end @doc """ iex> Spotify.Player.previous_url(device_id: "abc") "https://api.spotify.com/v1/me/player/previous?device_id=abc" """ def previous_url(params \\ []) do "https://api.spotify.com/v1/me/player/previous" <> query_string(params) end @doc """ Start/resume the user's playback. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/start-a-users-playback/) **Method**: `PUT` **Optional Params**: `device_id`, `context_uri`, `uris`, `offset`, `position_ms` """ def play(conn, params \\ []) do {query_params, body_params} = Keyword.split(params, [:device_id]) url = play_url(query_params) body = body_params |> Enum.into(%{}) |> Poison.encode!() conn |> Client.put(url, body) |> handle_response() end @doc """ iex> Spotify.Player.play_url(device_id: "abc") "https://api.spotify.com/v1/me/player/play?device_id=abc" """ def play_url(params \\ []) do "https://api.spotify.com/v1/me/player/play" <> query_string(params) end @doc """ Toggle shuffle for the user's playback. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/toggle-shuffle-for-users-playback/) **Method**: `PUT` **Optional Params**: `device_id` """ def set_shuffle(conn, state, params \\ []) when state |> is_boolean() do url = params |> Keyword.put(:state, state) |> shuffle_url() conn |> Client.put(url) |> handle_response() end @doc """ iex> Spotify.Player.shuffle_url(device_id: "abc") "https://api.spotify.com/v1/me/player/shuffle?device_id=abc" """ def shuffle_url(params \\ []) do "https://api.spotify.com/v1/me/player/shuffle" <> query_string(params) end @doc """ Transfer the user's playback. [Spotify Documentation](https://developer.spotify.com/documentation/web-api/reference/player/transfer-a-users-playback/) **Method**: `PUT` **Optional Params**: `play` """ def transfer_playback(conn, device_ids, params \\ []) do url = player_url() body = params |> Keyword.put(:device_ids, device_ids) |> Enum.into(%{}) |> Poison.encode!() conn |> Client.put(url, body) |> handle_response() end def build_response(%{"devices" => devices}) do Enum.map(devices, &to_struct(Device, &1)) end def build_response(body = %{"items" => _}) do build_paged_histories(body) end def build_response(body = %{"device" => _}) do body = body |> build_item() |> build_device() |> build_context() to_struct(Playback, body) end def build_response(body) do body = body |> build_item() |> build_context() to_struct(CurrentlyPlaying, body) end defp build_paged_histories(body) do %Paging{ href: body["href"], items: body["items"] |> build_histories(), limit: body["limit"], next: body["next"], offset: body["offset"], previous: body["previous"], total: body["total"] } end defp build_histories(histories) do Enum.map(histories, fn history -> %History{ track: to_struct(Track, history["track"]), played_at: history["played_at"], context: to_struct(Context, history["context"]) } end) end defp build_item(body = %{"item" => nil}), do: body defp build_item(body = %{"currently_playing_type" => "track"}) do Map.update!(body, "item", &to_struct(Track, &1)) end defp build_item(body = %{"currently_playing_type" => "episode"}) do Map.update!(body, "item", &to_struct(Episode, &1)) end defp build_device(body = %{"device" => _}) do Map.update!(body, "device", &to_struct(Device, &1)) end defp build_device(body), do: body defp build_context(body = %{"context" => nil}), do: body defp build_context(body = %{"context" => _}) do Map.update!(body, "context", &to_struct(Context, &1)) end end