martincamen/laravel-radarr

Laravel integration for Radarr PHP SDK

Installs: 4

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/martincamen/laravel-radarr

0.1.4 2026-01-21 01:47 UTC

This package is auto-updated.

Last update: 2026-01-21 01:49:02 UTC


README

Laravel integration for the Radarr PHP SDK, providing a seamless experience for interacting with Radarr using unified domain models from php-arr-core.

Important

This project is still being developed and breaking changes might occur even between patch versions.

The aim is to follow semantic versioning as soon as possible.

Ecosystem

Package Description
radarr-php PHP SDK for Radarr
sonarr-php PHP SDK for Sonarr
jellyseerr-php PHP SDK for Jellyseerr
laravel-radarr Laravel integration for Radarr
laravel-sonarr Laravel integration for Sonarr
laravel-jellyseerr Laravel integration for Jellyseerr

Features

  • Unified API using canonical domain models from php-arr-core
  • Type-safe interactions with Radarr
  • Laravel facade with full IDE autocompletion
  • Testing utilities for mocking responses
  • Automatic service discovery via Laravel's package auto-discovery

Requirements

  • PHP 8.3+
  • Laravel 10.0+, 11.0+ or 12.0+

Installation

composer require martincamen/laravel-radarr

The package will auto-register its service provider in Laravel.

Configuration

Publish the configuration file:

php artisan vendor:publish --provider="MartinCamen\LaravelRadarr\RadarrServiceProvider"

Add the following environment variables to your .env file:

RADARR_HOST=localhost
RADARR_PORT=7878
RADARR_API_KEY=your-api-key
RADARR_USE_HTTPS=false
RADARR_TIMEOUT=30
RADARR_URL_BASE=

Configuration Options

Option Description Default
RADARR_HOST Hostname or IP address of your Radarr server localhost
RADARR_PORT Port number for your Radarr server 7878
RADARR_API_KEY Your Radarr API key (Settings > General > Security) -
RADARR_USE_HTTPS Use HTTPS for connections false
RADARR_TIMEOUT Request timeout in seconds 30
RADARR_URL_BASE URL base for reverse proxy subpaths (e.g., /radarr) -

Usage

Using the Facade

The Radarr facade provides access to the SDK client via an action-based API:

use MartinCamen\LaravelRadarr\Facades\Radarr;

// Get all active downloads
$downloads = Radarr::downloads()->all();

// Get all movies
$movies = Radarr::movies()->all();

// Get a specific movie by ID
$movie = Radarr::movies()->find(1);

// Get system information
$status = Radarr::system()->status();

Dependency Injection

You can also inject Radarr directly:

use MartinCamen\Radarr\Radarr;

class MovieController
{
    public function __construct(private Radarr $radarr) {}

    public function index()
    {
        return view('movies.index', ['movies' => $this->radarr->movies()->all()]);
    }
}

Working with Downloads

The downloads()->all() method returns a DownloadPage containing all active downloads:

use MartinCamen\LaravelRadarr\Facades\Radarr;
use MartinCamen\Radarr\Data\Responses\DownloadPage;

/** @var DownloadPage $downloadPage */
$downloadPage = Radarr::downloads()->all();

// Check if there are any downloads
echo "Active downloads: {$downloadPage->totalRecords}";

// Iterate over downloads
foreach ($downloadPage as $download) {
    echo $download->title;
    echo $download->status->value;
    echo $download->sizeleft;
}

// Get a specific download
$download = Radarr::downloads()->find(1);

// Get download status summary
$status = Radarr::downloads()->status();
echo "Total: {$status->totalCount}";
echo "Unknown: {$status->unknownCount}";

// Delete a download
Radarr::downloads()->delete(1);

// Bulk delete downloads
Radarr::downloads()->bulkDelete([1, 2, 3]);

Working with Movies

The movies()->all() method returns a MovieCollection:

use MartinCamen\LaravelRadarr\Facades\Radarr;
use MartinCamen\Radarr\Data\Responses\Movie;
use MartinCamen\Radarr\Data\Responses\MovieCollection;

// Get all movies
/** @var MovieCollection $movies */
$movies = Radarr::movies()->all();

foreach ($movies as $movie) {
    echo "{$movie->title} ({$movie->year})";
    echo $movie->status->value;
    echo $movie->monitored ? 'Monitored' : 'Not monitored';
}

// Get a specific movie by ID
$movie = Radarr::movies()->find(1);
echo $movie->title;

// Search for movies
$results = Radarr::movies()->search('Inception');

// Search by external IDs
$movie = Radarr::movies()->searchByTmdb(27205);
$movie = Radarr::movies()->searchByImdb('tt1375666');

// Add a new movie
$movie = Radarr::movies()->add([
    'title'            => 'Inception',
    'tmdbId'           => 27205,
    'qualityProfileId' => 1,
    'rootFolderPath'   => '/movies/',
]);

// Update a movie
$movie = Radarr::movies()->update(1, ['monitored' => false]);

// Delete a movie
Radarr::movies()->delete(1);

System

use MartinCamen\LaravelRadarr\Facades\Radarr;

// Get system status
$status = Radarr::system()->status();
echo $status->version;
echo $status->osName;

// Get system health
$health = Radarr::system()->health();
foreach ($health->warnings() as $warning) {
    echo $warning->type . ': ' . $warning->message;
}

// Get disk space information
$diskSpace = Radarr::system()->diskSpace();
foreach ($diskSpace as $disk) {
    echo $disk->path . ': ' . $disk->freeSpace;
}

// Get system tasks
$tasks = Radarr::system()->tasks();
$task = Radarr::system()->task(1);

// Get available backups
$backups = Radarr::system()->backups();

Response Types

All responses use typed DTOs from the SDK:

Type Description
MovieCollection Collection of movies
Movie Individual movie with metadata
DownloadPage Paginated downloads
Download Individual download item
SystemStatus System status information
HealthCheckCollection Collection of health checks
DiskSpaceCollection Collection of disk space info

Testing

Using the Fake

The package provides RadarrFake for testing:

use MartinCamen\LaravelRadarr\Facades\Radarr;

class MovieTest extends TestCase
{
    public function testDisplaysDownloads(): void
    {
        // Create a fake instance
        $fake = Radarr::fake();

        // Make request
        $response = $this->get('/downloads');

        // Assert the method was called
        $fake->assertCalled('downloads');
        $response->assertOk();
    }

    public function testGetsAllMovies(): void
    {
        $fake = Radarr::fake();

        // Make request that calls movies()->all()
        $this->get('/movies');

        // Assert called
        $fake->assertCalled('movies');
    }

    public function testNothingWasCalled(): void
    {
        $fake = Radarr::fake();

        // No API calls made
        $this->get('/about');

        $fake->assertNothingCalled();
    }
}

Custom Responses

You can provide custom responses to the fake:

use MartinCamen\LaravelRadarr\Facades\Radarr;
use MartinCamen\Radarr\Testing\Factories\DownloadFactory;
use MartinCamen\Radarr\Testing\Factories\MovieFactory;
use MartinCamen\Radarr\Testing\Factories\SystemStatusFactory;

public function testWithCustomMovies(): void
{
    Radarr::fake([
        'movies' => MovieFactory::makeMany(10),
    ]);

    $response = $this->get('/movies');

    $response->assertOk();
    $response->assertViewHas('movies');
}

public function testWithCustomDownloads(): void
{
    Radarr::fake([
        'downloads' => [
            'page'         => 1,
            'pageSize'     => 10,
            'totalRecords' => 2,
            'records'      => DownloadFactory::makeMany(2),
        ],
    ]);

    $response = $this->get('/downloads');

    $response->assertOk();
}

public function testWithCustomSystemStatus(): void
{
    Radarr::fake([
        'systemSummary'     => SystemStatusFactory::make([
            'version'      => '5.0.0.0',
            'isProduction' => true,
        ]),
    ]);

    $response = $this->get('/system');

    $response->assertSee('5.0.0.0');
}

Assertion Methods

The fake provides several assertion methods:

use MartinCamen\LaravelRadarr\Facades\Radarr;

$fake = Radarr::fake();

// Assert a method was called
$fake->assertCalled('downloads');

// Assert a method was not called
$fake->assertNotCalled('movies');

// Assert a method was called with specific parameters
$fake->assertCalledWith('movie', ['id' => 5]);

// Assert a method was called a specific number of times
$fake->assertCalledTimes('downloads', 3);

// Assert nothing was called
$fake->assertNothingCalled();

// Get all recorded calls
$calls = $fake->getCalls();

Example: Building a Dashboard

use MartinCamen\LaravelRadarr\Facades\Radarr;

class DashboardController extends Controller
{
    public function index()
    {
        // Get system status
        $status = Radarr::system()->status();
        $health = Radarr::system()->health();

        // Get active downloads
        $downloads = Radarr::downloads()->all();

        // Get all movies
        $movies = Radarr::movies()->all();

        return view('dashboard', [
            'version'       => $status->version,
            'isHealthy'     => $health->isEmpty(),
            'downloads'     => $downloads,
            'downloadCount' => $downloads->totalRecords,
            'movieCount'    => count($movies),
        ]);
    }
}

Error Handling

use MartinCamen\LaravelRadarr\Facades\Radarr;
use MartinCamen\ArrCore\Exceptions\AuthenticationException;
use MartinCamen\ArrCore\Exceptions\ConnectionException;
use MartinCamen\ArrCore\Exceptions\NotFoundException;

try {
    $movie = Radarr::movies()->find(999);
} catch (AuthenticationException $e) {
    // Invalid API key
    return back()->with('error', 'Invalid Radarr API key');
} catch (NotFoundException $e) {
    // Movie not found
    abort(404, 'Movie not found');
} catch (ConnectionException $e) {
    // Connection error
    logger()->error('Could not connect to Radarr: ' . $e->getMessage());

    return back()->with('error', 'Radarr server unavailable');
}

License

The MIT License (MIT). Please see License File for more information.

Credits

Built on top of the Radarr PHP SDK and php-arr-core.