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
Requires
- php: ^8.3
- driftingly/rector-laravel: ^2.1.9
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- martincamen/radarr-php: ^0.1
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.0
- orchestra/testbench: ^9.0|^10.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
- roave/security-advisories: dev-latest
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.