Fix Sonarr TV request policy and bump gateway to 0.1.40

This commit is contained in:
ponzischeme89
2026-08-14 10:30:25 +12:00
parent 5e2ed3d12e
commit 19f08e6293
11 changed files with 366 additions and 29 deletions
+15
View File
@@ -377,6 +377,21 @@ export interface IntegrationsResponse {
dropped: number;
}
export interface SonarrProfileOption {
id: number;
name: string;
recommended: boolean;
}
export interface SonarrRequestPolicy {
qualityProfileId: number;
searchImmediately: boolean;
profiles: SonarrProfileOption[];
recommendedId: number;
configured: boolean;
error?: string;
}
/* ---------- logs ---------- */
export interface LogEvent {
+53 -2
View File
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { api } from '../api/client';
import { useAction, useQuery } from '../lib/hooks';
import { useToast } from '../lib/toast';
@@ -18,7 +18,7 @@ import {
Tag,
Toggle,
} from '../components/ui';
import type { Integration, IntegrationEventOption, IntegrationsResponse } from '../api/types';
import type { Integration, IntegrationEventOption, IntegrationsResponse, SonarrRequestPolicy } from '../api/types';
/* Integrations: administrative events going out to somewhere else.
*
@@ -111,6 +111,8 @@ export function IntegrationsPage() {
<Banner message={error} />
<SonarrRequestCard />
{(data?.dropped ?? 0) > 0 ? (
<Note tone="warn">
{num(data?.dropped ?? 0)} events could not be queued for delivery. The queue is deliberately
@@ -168,6 +170,55 @@ export function IntegrationsPage() {
);
}
function SonarrRequestCard() {
const { wrap } = useToast();
const { busy, run } = useAction();
const { data, error, loading, reload } = useQuery<SonarrRequestPolicy>('/admin/api/sonarr-request-policy');
const [profileId, setProfileId] = useState(0);
const [searchImmediately, setSearchImmediately] = useState(false);
useEffect(() => {
if (data) {
setProfileId(data.qualityProfileId);
setSearchImmediately(data.searchImmediately);
}
}, [data]);
const save = () => run('sonarr-request-policy', async () => {
await wrap(
() => api.post('/admin/api/sonarr-request-policy', { qualityProfileId: profileId, searchImmediately }),
'Sonarr TV request policy saved.',
);
await reload();
});
const selected = data?.profiles.find((profile) => profile.id === profileId);
return (
<Card
title="Sonarr TV requests"
intro="The policy Memby uses when a viewer requests a television series. The series remains monitored; searching its existing episodes is an explicit choice."
icon="tv"
tone={data?.configured ? 'ok' : 'warn'}
actions={data?.configured ? <Tag tone="ok">configured</Tag> : <Tag tone="warn">needs attention</Tag>}
footer={<Button variant="primary" busy={busy === 'sonarr-request-policy'} disabled={loading || profileId <= 0} onClick={() => void save()}>Save Sonarr policy</Button>}
>
<Banner message={error ?? data?.error ?? ''} />
{loading ? <Loading rows={2} /> : (
<>
<div className="fields">
<Field label="Request quality profile" hint="Memby stores this Sonarr profile ID. 720p is the recommended safe default; Memby will never fall back to Any.">
<select value={profileId} onChange={(event) => setProfileId(Number(event.target.value))} disabled={!data?.profiles.length}>
<option value={0}>Choose a quality profile…</option>
{data?.profiles.map((profile) => <option key={profile.id} value={profile.id}>{profile.name}{profile.recommended ? ' recommended (720p)' : ''}</option>)}
</select>
</Field>
</div>
<Toggle label="Search for episodes immediately after request" hint="Off adds and monitors the series without searching its backlog. Enable only when requests should start an immediate episode search." checked={searchImmediately} onChange={setSearchImmediately} />
{selected ? <Note tone="info">Requested series will use <b>{selected.name}</b> (profile ID {selected.id}), be monitored using Membys existing all-episodes strategy, and {searchImmediately ? 'start an immediate search.' : 'not start an immediate search.'}</Note> : null}
</>
)}
</Card>
);
}
function IntegrationCard({
integration,
catalogue,
+1 -1
View File
@@ -33,7 +33,7 @@ export function RequestsPage() {
<>
<Card
title="Where a request goes"
intro="A movie or series is monitored and searched for immediately. The configured download service handles it from there."
intro="Movies follow Radarrs policy. Series follow the dedicated Sonarr request policy: monitored as normal, with backlog searching only when an operator enables it under Integrations."
icon="inbox"
tone="info"
actions={