# Laravel Tautulli API Client

A Laravel Service Provider that wraps the [Tautulli API](https://github.com/Tautulli/Tautulli/wiki/Tautulli-API-Reference) using Guzzle, with full error handling and pagination support.

---

## File structure

```
config/
  tautulli.php                  ← Published config file

src/
  Exceptions/
    TautulliException.php       ← Base exception
    TautulliApiException.php    ← Tautulli API-level errors (result != success)
    TautulliHttpException.php   ← Network / HTTP transport errors
  Providers/
    TautulliServiceProvider.php   ← Laravel Service Provider
  Facades/
    Tautulli.php                ← Laravel Facade
  PaginatedResponse.php         ← Value object for paginated results
  TautulliClient.php            ← Core API client
  
```

---

## Installation

### 1. via Composer

```bash
composer require khatfield\laravel-tautulli
```

### 2. Publish & configure

```bash
php artisan vendor:publish --tag=tautulli-config
```

Then add these to your `.env`:

```dotenv
TAUTULLI_URL=http://localhost:8181
TAUTULLI_API_KEY=your_api_key_here
TAUTULLI_HTTP_ROOT=          # Optional sub-path, e.g. /tautulli
TAUTULLI_TIMEOUT=30
TAUTULLI_CONNECT_TIMEOUT=10
TAUTULLI_VERIFY_SSL=true
```

---

## Usage

### Via dependency injection

```php
use Khatfield\Tautulli\TautulliClient;

class PlexController extends Controller
{
    public function __construct(protected TautulliClient $tautulli) {}

    public function index()
    {
        $activity = $this->tautulli->getActivity();

        return view('plex.dashboard', compact('activity'));
    }
}
```

### Via the Facade

```php
use Khatfield\Tautulli\Facades\Tautulli;

$users = Tautulli::getUsers();
```

---

## Pagination

Any method returning a `PaginatedResponse` supports standard DataTables-style
pagination (`start` offset + `length`):

```php
// Fetch page 1 (rows 0–24)
$page = Tautulli::getHistory(start: 0, length: 25);

echo $page->currentPage();      // 1
echo $page->lastPage();         // e.g. 40
echo $page->recordsTotal;       // e.g. 1000
echo $page->hasMorePages();     // true

// Items are an Illuminate\Support\Collection
foreach ($page->data as $item) {
    echo $item['full_title'];
}

// Fetch next page
$nextStart = $page->nextPageStart(); // 25
$page2 = Tautulli::getHistory(start: $nextStart, length: 25);
```

### Fetch all pages at once

```php
// Returns a single flat Collection of every record (use with caution on large datasets)
$allHistory = Tautulli::getAllHistory([
    'media_type'   => 'movie',
    'order_column' => 'date',
    'order_dir'    => 'desc',
]);
```

### Using `paginate()` for arbitrary commands

```php
$page = Tautulli::paginate('get_users_table', start: 0, length: 10, params: [
    'order_column' => 'last_seen',
    'order_dir'    => 'desc',
]);
```

---

## Error handling

Three exception classes are thrown in different scenarios:

| Exception | When thrown |
|---|---|
| `TautulliHttpException` | Network failures, connection timeouts, HTTP errors (4xx/5xx) |
| `TautulliApiException` | Tautulli responds with `result != success` |
| `TautulliException` | Malformed / unexpected response bodies |

All three extend `TautulliException`, so you can catch them together or individually:

```php
use Khatfield\Tautulli\Exceptions\TautulliApiException;
use Khatfield\Tautulli\Exceptions\TautulliHttpException;
use Khatfield\Tautulli\Exceptions\TautulliException;

try {
    $activity = Tautulli::getActivity();
} catch (TautulliHttpException $e) {
    // Could not reach Tautulli — log, return cached data, etc.
    logger()->error('Tautulli unreachable', ['error' => $e->getMessage()]);
} catch (TautulliApiException $e) {
    // Tautulli returned an error response
    logger()->warning('Tautulli API error', ['message' => $e->getApiMessage()]);
} catch (TautulliException $e) {
    // Unexpected / malformed response
    logger()->error('Tautulli client error', ['error' => $e->getMessage()]);
}
```

---

## Extending

For any Tautulli command not yet wrapped as a dedicated method, use `command()`
or `paginate()` directly:

```php
// One-shot command
$result = Tautulli::command('get_server_pref', ['pref' => 'LogLevel']);

// Paginated command
$page = Tautulli::paginate('get_newsletter_log', start: 0, length: 25, params: [
    'order_column' => 'timestamp',
    'order_dir'    => 'desc',
]);

// All pages at once
$allItems = Tautulli::paginateAll('get_exports_table', params: ['section_id' => '1']);
```
