chore: standardize security and quality foundations
Magent CI/CD / verify (push) Failing after 9m34s
Magent CI/CD / deploy-beta (push) Skipped

This commit is contained in:
2026-09-17 20:03:47 +12:00
parent 5639dbcb83
commit f852e7c941
127 changed files with 17928 additions and 10741 deletions
+73 -29
View File
@@ -1,36 +1,80 @@
'use client'
"use client";
import { useEffect, useState } from 'react'
import { authFetch, getApiBase } from '../../lib/auth'
import { useEffect, useState } from "react";
import { authFetch, getApiBase } from "../../lib/auth";
type AudioChoice = { language: { code: string } | null; originalEnabled?: boolean; canChange?: boolean; profileLanguage?: string }
type AudioChoice = {
language: { code: string } | null;
originalEnabled?: boolean;
canChange?: boolean;
profileLanguage?: string;
};
export default function RequestLanguage({ requestId, disabled, onApply }: {
requestId: string; disabled: boolean; onApply: (code: string) => Promise<void>
export default function RequestLanguage({
requestId,
disabled,
onApply,
}: {
requestId: string;
disabled: boolean;
onApply: (code: string) => Promise<void>;
}) {
const [choice, setChoice] = useState<AudioChoice | null>(null)
const [error, setError] = useState<string | null>(null)
const [revision, setRevision] = useState(0)
const [choice, setChoice] = useState<AudioChoice | null>(null);
const [error, setError] = useState<string | null>(null);
const [revision, setRevision] = useState(0);
useEffect(() => {
const controller = new AbortController()
void revision;
const controller = new AbortController();
void authFetch(`${getApiBase()}/requests/${requestId}/language`, { signal: controller.signal })
.then(async response => { if (!response.ok) throw new Error('Could not check the audio settings. Reload the request to try again.'); return response.json() })
.then(data => { if (!controller.signal.aborted) setChoice(data) })
.catch(e => { if (!controller.signal.aborted) setError(e.message) })
return () => controller.abort()
}, [requestId, revision])
if (error && !choice) return <p role="alert">{error}</p>
if (!choice?.language) return null
const code = choice.language.code
const name = new Intl.DisplayNames(['en'], { type: 'language' }).of(code) || code
return <section className="request-language-notice" aria-label="Audio language">
<h2>{name} audio {choice.originalEnabled ? 'enabled' : 'may need your approval'}</h2>
<p>This movie was originally made in {name}. An English dub may not exist. {choice.originalEnabled ? 'Radarr is set to accept its original audio.' : `The current audio requirement is ${choice.profileLanguage || 'set by the library'}. This can leave the request waiting even when an original-language release exists.`}</p>
<p>Accepting original audio keeps the quality requirements. Subtitles and individual release audio tracks are not guaranteed by title metadata.</p>
{choice.canChange && !choice.originalEnabled && <button type="button" disabled={disabled} onClick={async () => {
setError(null)
try { await onApply(code); setRevision(v => v + 1) } catch (e) { setError(e instanceof Error ? e.message : 'The audio choice could not be saved.') }
}}>Use {name} audio &amp; search</button>}
{error && <p role="alert">{error}</p>}
</section>
.then(async (response) => {
if (!response.ok) throw new Error("Could not check the audio settings. Reload the request to try again.");
return response.json();
})
.then((data) => {
if (!controller.signal.aborted) setChoice(data);
})
.catch((e) => {
if (!controller.signal.aborted) setError(e.message);
});
return () => controller.abort();
}, [requestId, revision]);
if (error && !choice) return <p role="alert">{error}</p>;
if (!choice?.language) return null;
const code = choice.language.code;
const name = new Intl.DisplayNames(["en"], { type: "language" }).of(code) || code;
return (
<section className="request-language-notice" aria-label="Audio language">
<h2>
{name} audio {choice.originalEnabled ? "enabled" : "may need your approval"}
</h2>
<p>
This movie was originally made in {name}. An English dub may not exist.{" "}
{choice.originalEnabled
? "Radarr is set to accept its original audio."
: `The current audio requirement is ${choice.profileLanguage || "set by the library"}. This can leave the request waiting even when an original-language release exists.`}
</p>
<p>
Accepting original audio keeps the quality requirements. Subtitles and individual release audio tracks are not
guaranteed by title metadata.
</p>
{choice.canChange && !choice.originalEnabled && (
<button
type="button"
disabled={disabled}
onClick={async () => {
setError(null);
try {
await onApply(code);
setRevision((v) => v + 1);
} catch (e) {
setError(e instanceof Error ? e.message : "The audio choice could not be saved.");
}
}}
>
Use {name} audio &amp; search
</button>
)}
{error && <p role="alert">{error}</p>}
</section>
);
}