Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,44 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## [Unreleased]

## [0.4.0] — 2026-05-18

### Added
- `Phlex\Shared\Arr\ArrClientInterface` — common interface for Sonarr/Radarr
HTTP clients (queue, quality profiles, tags, test-connection).
- `Phlex\Shared\Arr\ArrClientFactory` — factory that instantiates Sonarr/Radarr
clients from instance config arrays.
- `Phlex\Shared\Arr\SyncResult` — immutable value object returned by sync flows.
- `Phlex\Shared\Arr\SonarrClient` — typed Sonarr v3 HTTP client.
- `Phlex\Shared\Arr\RadarrClient` — typed Radarr v3 HTTP client.
- `Phlex\Shared\Arr\BazarrClient` — typed Bazarr HTTP client.
- `Phlex\Shared\Arr\ProwlarrClient` — typed Prowlarr HTTP client.
- `Phlex\Shared\Arr\TrashGuidesProvider` — fetches TRaSH-Guides quality
profile + custom format JSON.
- `psr/log` runtime dependency to allow optional PSR-3 loggers on the arr
clients without pulling phlex-server's concrete `StructuredLogger`.

### Changed
- Arr classes now type-hint `Psr\Log\LoggerInterface` instead of phlex-server's
`StructuredLogger`, allowing the hub and any other PSR-3 consumer to inject
its own logger. Required for Step K.1 (arr clients shared between
phlex-server and phlex-hub) and K.3 (hub-side request fulfillment).

## [0.3.0] — 2026-05-17

### Added
- `Phlex\Shared\Auth\ProviderInterface` — core interface for pluggable external
authentication providers (OIDC, LDAP, SAML, passkeys). Zero I/O dependencies
so both phlex-server and phlex-hub can implement providers without pulling in
server/runtime dependencies.
- `Phlex\Shared\Auth\AuthResult` — immutable value object returned by
`ProviderInterface::authenticate()`. Captures success/failure, local userId,
provider externalId, error code, and arbitrary attributes (email, name,
avatarUrl …).
- `Phlex\Shared\Auth\UserInfo` — immutable value object returned by
`ProviderInterface::getUserInfo()`. Describes an external identity for
account linking and profile display.

## [0.2.0] — 2026-05-17

### Added
Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
"license": "MIT",
"require": {
"php": "^8.3",
"ext-curl": "*",
"psr/container": "^2.0",
"psr/event-dispatcher": "^1.0"
"psr/event-dispatcher": "^1.0",
"psr/log": "^3.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
Expand Down
Empty file removed src/Arr/.gitkeep
Empty file.
77 changes: 77 additions & 0 deletions src/Arr/ArrClientFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

namespace Phlex\Shared\Arr;

use Psr\Log\LoggerInterface;

/**
* Factory for creating Sonarr/Radarr API clients from config.
*
* @package Phlex\Shared\Arr
* @since 0.12.0
*/
class ArrClientFactory
{
/**
* @param array{
* sonarr?: array{url?: string, api_key?: string, enabled?: bool},
* radarr?: array{url?: string, api_key?: string, enabled?: bool}
* } $config Configuration array with sonarr/radarr sections.
*/
public function __construct(
private readonly array $config
) {
}

/**
* Creates a SonarrClient from the config.
*
* @param LoggerInterface|null $logger Optional logger instance.
* @return SonarrClient|null Client instance, or null if Sonarr is not enabled.
*/
public function createSonarrClient(?LoggerInterface $logger = null): ?SonarrClient
{
$sonarrConfig = $this->config['sonarr'] ?? [];

if (!($sonarrConfig['enabled'] ?? false)) {
return null;
}

$url = $sonarrConfig['url'] ?? 'http://localhost:8989';
$apiKey = $sonarrConfig['api_key'] ?? '';

if ($apiKey === '') {
$logger?->warning('Sonarr API key is empty but client is enabled');
return null;
}

return new SonarrClient($url, $apiKey, $logger);
}

/**
* Creates a RadarrClient from the config.
*
* @param LoggerInterface|null $logger Optional logger instance.
* @return RadarrClient|null Client instance, or null if Radarr is not enabled.
*/
public function createRadarrClient(?LoggerInterface $logger = null): ?RadarrClient
{
$radarrConfig = $this->config['radarr'] ?? [];

if (!($radarrConfig['enabled'] ?? false)) {
return null;
}

$url = $radarrConfig['url'] ?? 'http://localhost:7878';
$apiKey = $radarrConfig['api_key'] ?? '';

if ($apiKey === '') {
$logger?->warning('Radarr API key is empty but client is enabled');
return null;
}

return new RadarrClient($url, $apiKey, $logger);
}
}
46 changes: 46 additions & 0 deletions src/Arr/ArrClientInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace Phlex\Shared\Arr;

/**
* Common interface for Sonarr/Radarr API clients.
*
* @package Phlex\Shared\Arr
* @since 0.12.0
*/
interface ArrClientInterface
{
/**
* Returns the current download/activity queue.
*
* The Sonarr/Radarr v3 queue endpoint returns a paginated response of the
* shape `{records, page, pageSize, sortKey, sortDirection, totalRecords}`,
* so we expose this as `array<string, mixed>` rather than a list.
*
* @return array<string, mixed> Paginated queue response.
*/
public function getQueue(): array;

/**
* Returns available quality profiles.
*
* @return array<int, array<string, mixed>> Quality profiles.
*/
public function getQualityProfiles(): array;

/**
* Returns all configured tags.
*
* @return array<int, array<string, mixed>> Tags.
*/
public function getTagList(): array;

/**
* Tests connectivity and authentication with the *arr instance.
*
* @return bool True if connection is successful, false otherwise.
*/
public function testConnection(): bool;
}
Loading
Loading