# SpotifyEx
A simple Elixir client for the [Spotify Web API](https://developer.spotify.com/documentation/web-api).
## Installation
Add `spotifyex` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:spotifyex, "~> 0.1.0"}
]
end
```
## Quick Start
### 1. Get an Access Token
```elixir
# Build authorization URL
url = SpotifyEx.Auth.authorize_url(
"your_client_id",
"http://localhost:4000/callback",
scopes: ["playlist-modify-public", "playlist-read-private"]
)
# After user authorizes, exchange code for token
{:ok, tokens} = SpotifyEx.Auth.exchange_code(
code,
"your_client_id",
"your_client_secret",
"http://localhost:4000/callback"
)
access_token = tokens["access_token"]
```
### 2. Create a Client
```elixir
client = SpotifyEx.client(access_token)
```
### 3. Make API Calls
```elixir
# Search for an album
{:ok, results} = SpotifyEx.Search.search(client, "Radiohead OK Computer", type: "album")
# Get album tracks
album_id = results["albums"]["items"] |> List.first() |> Map.get("id")
{:ok, tracks} = SpotifyEx.Albums.get_album_tracks(client, album_id)
# Get track URIs
track_uris = Enum.map(tracks["items"], & &1["uri"])
# Create a playlist
{:ok, user} = SpotifyEx.Users.get_current_user(client)
{:ok, playlist} = SpotifyEx.Playlists.create_playlist(
client,
user["id"],
"My Playlist",
description: "Created with SpotifyEx"
)
# Add tracks to playlist
{:ok, _} = SpotifyEx.Playlists.add_tracks(client, playlist["id"], track_uris)
# Or replace all tracks (overwrite)
{:ok, _} = SpotifyEx.Playlists.replace_tracks(client, playlist["id"], track_uris)
```
## Modules
| Module | Description |
|--------|-------------|
| `SpotifyEx.Auth` | OAuth authentication (authorization code flow, token refresh) |
| `SpotifyEx.Search` | Search for albums, artists, tracks, playlists |
| `SpotifyEx.Albums` | Get album info, tracks, saved albums, new releases |
| `SpotifyEx.Artists` | Get artist info, albums, top tracks, related artists |
| `SpotifyEx.Tracks` | Get track info, audio features, recommendations |
| `SpotifyEx.Playlists` | Create, update, manage playlists |
| `SpotifyEx.Users` | Get user profiles, manage follows |
| `SpotifyEx.Player` | Playback control, queue management, recently played |
| `SpotifyEx.Shows` | Get show info, episodes, saved shows |
| `SpotifyEx.Episodes` | Get episode info, saved episodes |
| `SpotifyEx.Audiobooks` | Get audiobook info, chapters, saved audiobooks |
| `SpotifyEx.Chapters` | Get chapter info |
| `SpotifyEx.Categories` | Browse categories |
| `SpotifyEx.Genres` | Available genre seeds for recommendations |
| `SpotifyEx.Markets` | Available markets |
## Authentication
SpotifyEx supports the Authorization Code flow:
```elixir
# 1. Generate authorization URL
url = SpotifyEx.Auth.authorize_url(client_id, redirect_uri,
scopes: ["playlist-modify-public", "user-read-private"],
state: "random_state_string"
)
# 2. User visits URL and authorizes your app
# 3. Exchange authorization code for tokens
{:ok, %{
"access_token" => access_token,
"refresh_token" => refresh_token,
"expires_in" => 3600
}} = SpotifyEx.Auth.exchange_code(code, client_id, client_secret, redirect_uri)
# 4. Refresh token when expired
{:ok, %{"access_token" => new_token}} =
SpotifyEx.Auth.refresh_token(refresh_token, client_id, client_secret)
```
For server-to-server calls without user context, use Client Credentials:
```elixir
{:ok, %{"access_token" => token}} =
SpotifyEx.Auth.get_client_credentials(client_id, client_secret)
```
## Error Handling
All API calls return `{:ok, result}` or `{:error, %SpotifyEx.Error{}}`:
```elixir
case SpotifyEx.Albums.get_album(client, "invalid_id") do
{:ok, album} ->
IO.puts(album["name"])
{:error, %SpotifyEx.Error{status: 404, reason: :not_found}} ->
IO.puts("Album not found")
{:error, %SpotifyEx.Error{status: 401, reason: :unauthorized}} ->
IO.puts("Token expired, refresh needed")
{:error, %SpotifyEx.Error{reason: :rate_limited}} ->
IO.puts("Rate limited, try again later")
end
```
## License
MIT