README.md

# 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