# arr-sdk

Unified TypeScript SDK for Sonarr, Radarr, Lidarr, Readarr, and Prowlarr APIs.

## Features

- Full TypeScript support with types generated from official OpenAPI specs
- Native `fetch` API (no dependencies)
- Subpath exports for tree-shaking
- Async pagination helpers
- Comprehensive error handling
- Request/response hooks

## Installation

```bash
npm install arr-sdk
```

## Quick Start

### Sonarr

```typescript
import { SonarrClient } from 'arr-sdk/sonarr'

const sonarr = new SonarrClient({
  baseUrl: 'http://localhost:8989',
  apiKey: 'your-api-key'
})

// Get all series
const series = await sonarr.series.getAll()

// Search for a series
const results = await sonarr.series.lookup('Breaking Bad')

// Add a series
const newSeries = await sonarr.series.create({
  tvdbId: 81189,
  title: 'Breaking Bad',
  qualityProfileId: 1,
  rootFolderPath: '/tv'
})
```

### Radarr

```typescript
import { RadarrClient } from 'arr-sdk/radarr'

const radarr = new RadarrClient({
  baseUrl: 'http://localhost:7878',
  apiKey: 'your-api-key'
})

// Get all movies
const movies = await radarr.movie.getAll()

// Search for a movie
const results = await radarr.movie.lookup('The Matrix')

// Add a movie
const newMovie = await radarr.movie.create({
  tmdbId: 603,
  title: 'The Matrix',
  qualityProfileId: 1,
  rootFolderPath: '/movies'
})
```

### Lidarr

```typescript
import { LidarrClient } from 'arr-sdk/lidarr'

const lidarr = new LidarrClient({
  baseUrl: 'http://localhost:8686',
  apiKey: 'your-api-key'
})

// Get all artists
const artists = await lidarr.artist.getAll()

// Search for an artist
const results = await lidarr.artist.lookup('The Beatles')

// Add an artist
const newArtist = await lidarr.artist.create({
  foreignArtistId: 'b10bbbfc-cf9e-42e0-be17-e2c3e1d2600d',
  artistName: 'The Beatles',
  qualityProfileId: 1,
  metadataProfileId: 1,
  rootFolderPath: '/music'
})

// Get all albums
const albums = await lidarr.album.getAll()

// Get tracks for an album
const tracks = await lidarr.track.getByAlbumId(1)
```

### Readarr

```typescript
import { ReadarrClient } from 'arr-sdk/readarr'

const readarr = new ReadarrClient({
  baseUrl: 'http://localhost:8787',
  apiKey: 'your-api-key'
})

// Get all authors
const authors = await readarr.author.getAll()

// Search for an author
const results = await readarr.author.lookup('Stephen King')

// Add an author
const newAuthor = await readarr.author.create({
  foreignAuthorId: '12345-67890-abcdef',
  authorName: 'Stephen King',
  qualityProfileId: 1,
  metadataProfileId: 1,
  rootFolderPath: '/books'
})

// Get all books
const books = await readarr.book.getAll()

// Get books by author
const authorBooks = await readarr.book.getByAuthorId(1)
```

### Prowlarr

```typescript
import { ProwlarrClient } from 'arr-sdk/prowlarr'

const prowlarr = new ProwlarrClient({
  baseUrl: 'http://localhost:9696',
  apiKey: 'your-api-key'
})

// Get all indexers
const indexers = await prowlarr.indexer.getAll()

// Search across indexers
const results = await prowlarr.search.query({
  query: 'ubuntu',
  type: 'search'
})
```

## Configuration

```typescript
import { SonarrClient } from 'arr-sdk/sonarr'

const client = new SonarrClient({
  baseUrl: 'http://localhost:8989',
  apiKey: 'your-api-key',

  // Optional: custom timeout (default: 30000ms)
  timeout: 60000,

  // Optional: custom headers
  headers: {
    'X-Custom-Header': 'value'
  },

  // Optional: request/response hooks
  onRequest: (config) => {
    console.log('Request:', config.method, config.url.href)
  },
  onResponse: (response) => {
    console.log('Response:', response.status)
  },
  onError: (error) => {
    console.error('Error:', error.message)
  }
})
```

## Pagination

For endpoints that return paginated results:

```typescript
// Async generator for memory-efficient iteration
for await (const item of client.queue.getAll()) {
  console.log(item)
}

// Or get all results at once
const allItems = await client.queue.getAllArray()
```

## Error Handling

```typescript
import {
  ArrError,
  NotFoundError,
  UnauthorizedError,
  ValidationError
} from 'arr-sdk'

try {
  await client.series.getById(99999)
} catch (error) {
  if (error instanceof NotFoundError) {
    console.log('Series not found')
  } else if (error instanceof UnauthorizedError) {
    console.log('Invalid API key')
  } else if (error instanceof ValidationError) {
    console.log('Validation errors:', error.errors)
  } else if (error instanceof ArrError) {
    console.log('API error:', error.statusCode, error.message)
  }
}
```

## Breaking Changes

See [CHANGELOG.md](./CHANGELOG.md) for a complete list of breaking changes.

### Queue Options

The `quality` field in `GetQueueOptions` changed from `number` to `number[]`:

```typescript
// Before (v0.1.x)
await client.queue.get({ quality: 1 })

// After (v0.2.0+)
await client.queue.get({ quality: [1] })
```

## Available Resources

### Sonarr

- `series` - Series management
- `episode` - Episode management
- `episodeFile` - Episode file management
- `calendar` - Calendar/upcoming episodes (includes iCal feed)
- `queue` - Download queue
- `wanted` - Missing and cutoff unmet episodes
- `history` - Activity history
- `command` - Commands (refresh, scan, manualImport, etc.)
- `qualityProfile` - Quality profiles
- `qualityDefinition` - Quality definitions
- `rootFolder` - Root folders
- `tag` - Tags
- `indexer` - Indexer configuration
- `downloadClient` - Download client configuration
- `importList` - Import lists
- `notification` - Notifications
- `metadata` - Metadata providers
- `release` - Release search/grab
- `blocklist` - Blocklisted releases
- `system` - System info, health, logs, ping
- `filesystem` - Browse filesystem paths
- `mediaCover` - Download series cover images
- `config` - Host/UI/naming configuration

### Radarr

- `movie` - Movie management
- `collection` - Collection management
- `calendar` - Calendar/upcoming releases (includes iCal feed)
- `queue` - Download queue
- `wanted` - Missing and cutoff unmet movies
- `history` - Activity history
- `command` - Commands (refresh, scan, manualImport, etc.)
- `qualityProfile` - Quality profiles
- `qualityDefinition` - Quality definitions
- `customFormat` - Custom formats
- `rootFolder` - Root folders
- `tag` - Tags
- `indexer` - Indexer configuration
- `downloadClient` - Download client configuration
- `importList` - Import lists
- `notification` - Notifications
- `metadata` - Metadata providers
- `release` - Release search/grab
- `blocklist` - Blocklisted releases
- `system` - System info, health, logs, ping
- `filesystem` - Browse filesystem paths
- `mediaCover` - Download movie cover images
- `config` - Host/UI/naming configuration

### Lidarr

- `artist` - Artist management
- `album` - Album management
- `track` - Track management
- `trackFile` - Track file management
- `calendar` - Calendar/upcoming releases
- `queue` - Download queue
- `wanted` - Missing albums and cutoff unmet
- `history` - Activity history
- `command` - Commands (refresh, scan, etc.)
- `qualityProfile` - Quality profiles
- `qualityDefinition` - Quality definitions
- `metadataProfile` - Metadata profiles (Lidarr-specific)
- `rootFolder` - Root folders
- `tag` - Tags
- `system` - System info, health, logs, ping

### Readarr

- `author` - Author management
- `book` - Book management
- `edition` - Edition access (different book versions)
- `bookFile` - Book file management
- `calendar` - Calendar/upcoming releases
- `queue` - Download queue
- `wanted` - Missing books and cutoff unmet
- `history` - Activity history
- `command` - Commands (refresh, scan, etc.)
- `qualityProfile` - Quality profiles
- `qualityDefinition` - Quality definitions
- `metadataProfile` - Metadata profiles
- `rootFolder` - Root folders
- `tag` - Tags
- `system` - System info, health, logs, ping

### Prowlarr

- `indexer` - Indexer management
- `indexerStats` - Indexer statistics with filtering
- `indexerProxy` - Indexer proxies
- `application` - Application connections
- `appProfile` - App sync profiles
- `search` - Search across indexers
- `newznab` - Newznab/Torznab protocol (caps, search, download)
- `command` - Commands
- `history` - Search history
- `tag` - Tags
- `downloadClient` - Download clients
- `notification` - Notifications
- `system` - System info, health, logs, ping
- `filesystem` - Browse filesystem paths
- `localization` - Localization strings
- `config` - Configuration

## Tree-Shaking

Import only what you need:

```typescript
// Import only Sonarr (smaller bundle)
import { SonarrClient } from 'arr-sdk/sonarr'

// Import only Radarr
import { RadarrClient } from 'arr-sdk/radarr'

// Import only Lidarr
import { LidarrClient } from 'arr-sdk/lidarr'

// Import only Readarr
import { ReadarrClient } from 'arr-sdk/readarr'

// Import only Prowlarr
import { ProwlarrClient } from 'arr-sdk/prowlarr'

// Or import everything
import { SonarrClient, RadarrClient, LidarrClient, ReadarrClient, ProwlarrClient } from 'arr-sdk'
```

## Requirements

- Node.js >= 18.0.0 (uses native `fetch`)

## License

MIT
