Add go2rtc streams to settings UI (#22531)

* Add go2rtc settings section

- create separate settings section for all go2rtc streams
- extract credentials mask code into util
- create ffmpeg module utility
- i18n

* add camera config updater topic for live section

to support adding go2rtc streams after configuring a new one via the UI

* clean up

* tweak delete button color for consistency

* tweaks
This commit is contained in:
Josh Hawkins
2026-03-19 10:33:42 -06:00
committed by GitHub
parent c93dad9bd9
commit e2bfa26719
8 changed files with 1246 additions and 43 deletions
@@ -8,6 +8,11 @@ import { Input } from "@/components/ui/input";
import type { ConfigFormContext } from "@/types/configForm";
import { cn } from "@/lib/utils";
import { getSizedFieldClassName } from "../utils";
import {
isMaskedPath,
hasCredentials,
maskCredentials,
} from "@/utils/credentialMask";
type RawPathsResponse = {
cameras?: Record<
@@ -22,9 +27,6 @@ type RawPathsResponse = {
>;
};
const MASKED_AUTH_PATTERN = /:\/\/\*:\*@/i;
const MASKED_QUERY_PATTERN = /(?:[?&])user=\*&password=\*/i;
const getInputIndexFromWidgetId = (id: string): number | undefined => {
const match = id.match(/_inputs_(\d+)_path$/);
if (!match) {
@@ -35,44 +37,6 @@ const getInputIndexFromWidgetId = (id: string): number | undefined => {
return Number.isNaN(index) ? undefined : index;
};
const isMaskedPath = (value: string): boolean =>
MASKED_AUTH_PATTERN.test(value) || MASKED_QUERY_PATTERN.test(value);
const hasCredentials = (value: string): boolean => {
if (!value) {
return false;
}
if (isMaskedPath(value)) {
return true;
}
try {
const parsed = new URL(value);
if (parsed.username || parsed.password) {
return true;
}
return (
parsed.searchParams.has("user") && parsed.searchParams.has("password")
);
} catch {
return /:\/\/[^:@/\s]+:[^@/\s]+@/.test(value);
}
};
const maskCredentials = (value: string): string => {
if (!value) {
return value;
}
const maskedAuth = value.replace(/:\/\/[^:@/\s]+:[^@/\s]*@/g, "://*:*@");
return maskedAuth
.replace(/([?&]user=)[^&]*/gi, "$1*")
.replace(/([?&]password=)[^&]*/gi, "$1*");
};
export function CameraPathWidget(props: WidgetProps) {
const {
id,