match test parsing in step 3 with step 2

This commit is contained in:
Josh Hawkins 2025-11-10 14:48:51 -06:00
parent 0b7788c33f
commit 53b9b00e10

View File

@ -14,6 +14,8 @@ import {
StreamRole, StreamRole,
TestResult, TestResult,
FfprobeStream, FfprobeStream,
FfprobeData,
FfprobeResponse,
CandidateTestMap, CandidateTestMap,
} from "@/types/cameraWizard"; } from "@/types/cameraWizard";
import { Label } from "../../ui/label"; import { Label } from "../../ui/label";
@ -168,7 +170,7 @@ export default function Step3StreamConfig({
); );
const testStream = useCallback( const testStream = useCallback(
(stream: StreamConfig) => { async (stream: StreamConfig) => {
if (!stream.url.trim()) { if (!stream.url.trim()) {
toast.error(t("cameraWizard.commonErrors.noUrl")); toast.error(t("cameraWizard.commonErrors.noUrl"));
return; return;
@ -176,28 +178,66 @@ export default function Step3StreamConfig({
setTestingStreams((prev) => new Set(prev).add(stream.id)); setTestingStreams((prev) => new Set(prev).add(stream.id));
axios try {
.get("ffprobe", { const response = await axios.get("ffprobe", {
params: { paths: stream.url, detailed: true }, params: { paths: stream.url, detailed: true },
timeout: 10000, timeout: 10000,
}) });
.then((response) => {
if (response.data?.[0]?.return_code === 0) {
const probeData = response.data[0];
const streams = probeData.stdout.streams || [];
const videoStream = streams.find( let probeData: FfprobeResponse | null = null;
if (
response.data &&
response.data.length > 0 &&
response.data[0].return_code === 0
) {
probeData = response.data[0];
}
if (!probeData) {
const error =
Array.isArray(response.data?.[0]?.stderr) &&
response.data[0].stderr.length > 0
? response.data[0].stderr.join("\n")
: "Unable to probe stream";
const failResult: TestResult = { success: false, error };
updateStream(stream.id, { testResult: failResult, userTested: true });
onUpdate({
candidateTests: {
...(wizardData.candidateTests || {}),
[stream.url]: failResult,
} as CandidateTestMap,
});
toast.error(t("cameraWizard.commonErrors.testFailed", { error }));
return;
}
let ffprobeData: FfprobeData;
if (typeof probeData.stdout === "string") {
try {
ffprobeData = JSON.parse(probeData.stdout as string) as FfprobeData;
} catch {
ffprobeData = { streams: [] } as FfprobeData;
}
} else {
ffprobeData = probeData.stdout as FfprobeData;
}
const streamsArr = ffprobeData.streams || [];
const videoStream = streamsArr.find(
(s: FfprobeStream) => (s: FfprobeStream) =>
s.codec_type === "video" || s.codec_type === "video" ||
s.codec_name?.includes("h264") || s.codec_name?.includes("h264") ||
s.codec_name?.includes("h265"), s.codec_name?.includes("hevc"),
); );
const audioStream = streams.find( const audioStream = streamsArr.find(
(s: FfprobeStream) => (s: FfprobeStream) =>
s.codec_type === "audio" || s.codec_type === "audio" ||
s.codec_name?.includes("aac") || s.codec_name?.includes("aac") ||
s.codec_name?.includes("mp3"), s.codec_name?.includes("mp3") ||
s.codec_name?.includes("pcm_mulaw") ||
s.codec_name?.includes("pcm_alaw"),
); );
const resolution = videoStream const resolution = videoStream
@ -217,7 +257,6 @@ export default function Step3StreamConfig({
fps: fps && !isNaN(fps) ? fps : undefined, fps: fps && !isNaN(fps) ? fps : undefined,
}; };
// Update the stream and also persist the candidate test result
updateStream(stream.id, { testResult, userTested: true }); updateStream(stream.id, { testResult, userTested: true });
onUpdate({ onUpdate({
candidateTests: { candidateTests: {
@ -226,35 +265,21 @@ export default function Step3StreamConfig({
} as CandidateTestMap, } as CandidateTestMap,
}); });
toast.success(t("cameraWizard.step3.testSuccess")); toast.success(t("cameraWizard.step3.testSuccess"));
} else { } catch (error) {
const error = response.data?.[0]?.stderr || "Unknown error"; const axiosError = error as {
const failResult: TestResult = { success: false, error }; response?: { data?: { message?: string; detail?: string } };
updateStream(stream.id, { message?: string;
testResult: failResult, };
userTested: true,
});
onUpdate({
candidateTests: {
...(wizardData.candidateTests || {}),
[stream.url]: failResult,
} as CandidateTestMap,
});
toast.error(t("cameraWizard.commonErrors.testFailed", { error }));
}
})
.catch((error) => {
const errorMessage = const errorMessage =
error.response?.data?.message || axiosError.response?.data?.message ||
error.response?.data?.detail || axiosError.response?.data?.detail ||
axiosError.message ||
"Connection failed"; "Connection failed";
const catchResult: TestResult = { const catchResult: TestResult = {
success: false, success: false,
error: errorMessage, error: errorMessage,
}; };
updateStream(stream.id, { updateStream(stream.id, { testResult: catchResult, userTested: true });
testResult: catchResult,
userTested: true,
});
onUpdate({ onUpdate({
candidateTests: { candidateTests: {
...(wizardData.candidateTests || {}), ...(wizardData.candidateTests || {}),
@ -264,14 +289,13 @@ export default function Step3StreamConfig({
toast.error( toast.error(
t("cameraWizard.commonErrors.testFailed", { error: errorMessage }), t("cameraWizard.commonErrors.testFailed", { error: errorMessage }),
); );
}) } finally {
.finally(() => {
setTestingStreams((prev) => { setTestingStreams((prev) => {
const newSet = new Set(prev); const newSet = new Set(prev);
newSet.delete(stream.id); newSet.delete(stream.id);
return newSet; return newSet;
}); });
}); }
}, },
[updateStream, t, onUpdate, wizardData.candidateTests], [updateStream, t, onUpdate, wizardData.candidateTests],
); );