Fix Sonarr TV request policy and bump gateway to 0.1.40
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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 Memby’s existing all-episodes strategy, and {searchImmediately ? 'start an immediate search.' : 'not start an immediate search.'}</Note> : null}
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function IntegrationCard({
|
||||
integration,
|
||||
catalogue,
|
||||
|
||||
@@ -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 Radarr’s 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={
|
||||
|
||||
Reference in New Issue
Block a user