gix bug again
This commit is contained in:
+38
-79
@@ -6,14 +6,7 @@ import type { AppConfigUpdate, MediaMtxConfigView } from "@/types/api";
|
|||||||
import { apiJson } from "@/utils/api";
|
import { apiJson } from "@/utils/api";
|
||||||
|
|
||||||
export default function Settings() {
|
export default function Settings() {
|
||||||
const {
|
const { config, isLoading, error, load } = useConfigStore();
|
||||||
config,
|
|
||||||
isLoading,
|
|
||||||
error,
|
|
||||||
load,
|
|
||||||
setSchedulerEnabled,
|
|
||||||
updateSchedule,
|
|
||||||
} = useConfigStore();
|
|
||||||
|
|
||||||
const [rtspUrl, setRtspUrl] = useState("");
|
const [rtspUrl, setRtspUrl] = useState("");
|
||||||
const [mtx, setMtx] = useState<MediaMtxConfigView | null>(null);
|
const [mtx, setMtx] = useState<MediaMtxConfigView | null>(null);
|
||||||
@@ -31,6 +24,8 @@ export default function Settings() {
|
|||||||
const [recordingsDir, setRecordingsDir] = useState("");
|
const [recordingsDir, setRecordingsDir] = useState("");
|
||||||
const [apiPort, setApiPort] = useState("8008");
|
const [apiPort, setApiPort] = useState("8008");
|
||||||
const [recordDeleteAfterDays, setRecordDeleteAfterDays] = useState("7");
|
const [recordDeleteAfterDays, setRecordDeleteAfterDays] = useState("7");
|
||||||
|
const [recordEnabled, setRecordEnabled] = useState(false);
|
||||||
|
const [schedulerEnabled, setSchedulerEnabledState] = useState(true);
|
||||||
|
|
||||||
const loadMtx = async () => {
|
const loadMtx = async () => {
|
||||||
setMtxBusy(true);
|
setMtxBusy(true);
|
||||||
@@ -38,7 +33,9 @@ export default function Settings() {
|
|||||||
try {
|
try {
|
||||||
const data = await apiJson<MediaMtxConfigView>("/mediamtx/config", { method: "GET" });
|
const data = await apiJson<MediaMtxConfigView>("/mediamtx/config", { method: "GET" });
|
||||||
setMtx(data);
|
setMtx(data);
|
||||||
setRecordDeleteAfterDays(String(data.record_delete_after_days ?? 7));
|
setRecordEnabled(Boolean(data.record_enabled));
|
||||||
|
const d = data.record_delete_after_days;
|
||||||
|
setRecordDeleteAfterDays(d === 1 || d === 3 || d === 7 ? String(d) : "7");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (typeof e === "object" && e && "status" in e) {
|
if (typeof e === "object" && e && "status" in e) {
|
||||||
const ex = e as { status: number; bodyText?: string };
|
const ex = e as { status: number; bodyText?: string };
|
||||||
@@ -61,6 +58,7 @@ export default function Settings() {
|
|||||||
setWeekdaysFrom(schedule.weekdays_from);
|
setWeekdaysFrom(schedule.weekdays_from);
|
||||||
setWeekdaysTo(schedule.weekdays_to);
|
setWeekdaysTo(schedule.weekdays_to);
|
||||||
setWeekendAllDay(schedule.weekend_all_day);
|
setWeekendAllDay(schedule.weekend_all_day);
|
||||||
|
setSchedulerEnabledState(Boolean(schedule.enabled));
|
||||||
}, [schedule]);
|
}, [schedule]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -100,15 +98,7 @@ export default function Settings() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSaveSchedule = async () => {
|
const onSaveAll = async () => {
|
||||||
await updateSchedule({
|
|
||||||
weekdays_from: weekdaysFrom,
|
|
||||||
weekdays_to: weekdaysTo,
|
|
||||||
weekend_all_day: weekendAllDay,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSaveBasicConfig = async () => {
|
|
||||||
setMtxBusy(true);
|
setMtxBusy(true);
|
||||||
setMtxError(null);
|
setMtxError(null);
|
||||||
setRestartMsg(null);
|
setRestartMsg(null);
|
||||||
@@ -125,15 +115,35 @@ export default function Settings() {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify(payload),
|
body: JSON.stringify(payload),
|
||||||
});
|
});
|
||||||
|
await apiJson("/mediamtx/record-delete-after", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ days: Number(recordDeleteAfterDays) }),
|
||||||
|
});
|
||||||
|
await apiJson("/scheduler/schedule", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
weekdays_from: weekdaysFrom,
|
||||||
|
weekdays_to: weekdaysTo,
|
||||||
|
weekend_all_day: weekendAllDay,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
await apiJson("/scheduler/enabled", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ enabled: schedulerEnabled }),
|
||||||
|
});
|
||||||
|
await apiJson("/mediamtx/recording", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ enabled: recordEnabled }),
|
||||||
|
});
|
||||||
await load();
|
await load();
|
||||||
await loadMtx();
|
await loadMtx();
|
||||||
setRestartMsg("Lưu config.json thành công");
|
setRestartMsg("Lưu config.json và mediamtx.yml thành công");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (typeof e === "object" && e && "status" in e) {
|
if (typeof e === "object" && e && "status" in e) {
|
||||||
const ex = e as { status: number; bodyText?: string };
|
const ex = e as { status: number; bodyText?: string };
|
||||||
setMtxError(`http_${ex.status}${ex.bodyText ? `: ${ex.bodyText}` : ""}`);
|
setMtxError(`http_${ex.status}${ex.bodyText ? `: ${ex.bodyText}` : ""}`);
|
||||||
} else {
|
} else {
|
||||||
setMtxError("failed_to_save_config");
|
setMtxError("failed_to_save_all");
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setMtxBusy(false);
|
setMtxBusy(false);
|
||||||
@@ -161,49 +171,6 @@ export default function Settings() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onToggleRecord = async (enabled: boolean) => {
|
|
||||||
setMtxBusy(true);
|
|
||||||
setMtxError(null);
|
|
||||||
try {
|
|
||||||
const data = await apiJson<MediaMtxConfigView>("/mediamtx/recording", {
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({ enabled }),
|
|
||||||
});
|
|
||||||
setMtx(data);
|
|
||||||
} catch (e) {
|
|
||||||
if (typeof e === "object" && e && "status" in e) {
|
|
||||||
const ex = e as { status: number; bodyText?: string };
|
|
||||||
setMtxError(`http_${ex.status}${ex.bodyText ? `: ${ex.bodyText}` : ""}`);
|
|
||||||
} else {
|
|
||||||
setMtxError("failed_to_toggle_recording");
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
setMtxBusy(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onChangeRecordDeleteAfter = async (days: number) => {
|
|
||||||
setMtxBusy(true);
|
|
||||||
setMtxError(null);
|
|
||||||
try {
|
|
||||||
const data = await apiJson<MediaMtxConfigView>("/mediamtx/record-delete-after", {
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({ days }),
|
|
||||||
});
|
|
||||||
setMtx(data);
|
|
||||||
setRecordDeleteAfterDays(String(data.record_delete_after_days ?? days));
|
|
||||||
} catch (e) {
|
|
||||||
if (typeof e === "object" && e && "status" in e) {
|
|
||||||
const ex = e as { status: number; bodyText?: string };
|
|
||||||
setMtxError(`http_${ex.status}${ex.bodyText ? `: ${ex.bodyText}` : ""}`);
|
|
||||||
} else {
|
|
||||||
setMtxError("failed_to_update_record_delete_after");
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
setMtxBusy(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onRestartDocker = async () => {
|
const onRestartDocker = async () => {
|
||||||
setMtxBusy(true);
|
setMtxBusy(true);
|
||||||
setRestartMsg(null);
|
setRestartMsg(null);
|
||||||
@@ -371,19 +338,19 @@ export default function Settings() {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => void onSaveBasicConfig()}
|
onClick={() => void onSaveAll()}
|
||||||
disabled={mtxBusy}
|
disabled={mtxBusy}
|
||||||
className="inline-flex items-center gap-2 rounded-md border border-zinc-700 bg-zinc-950/40 px-3 py-2 text-sm text-zinc-200 transition hover:bg-zinc-900 disabled:cursor-not-allowed disabled:opacity-60"
|
className="inline-flex items-center gap-2 rounded-md border border-zinc-700 bg-zinc-950/40 px-3 py-2 text-sm text-zinc-200 transition hover:bg-zinc-900 disabled:cursor-not-allowed disabled:opacity-60"
|
||||||
>
|
>
|
||||||
Save Config
|
Save All
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label className="flex items-center gap-2 text-sm text-zinc-200">
|
<label className="flex items-center gap-2 text-sm text-zinc-200">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={Boolean(mtx?.record_enabled)}
|
checked={recordEnabled}
|
||||||
onChange={(e) => void onToggleRecord(e.target.checked)}
|
onChange={(e) => setRecordEnabled(e.target.checked)}
|
||||||
className="h-4 w-4 rounded border-zinc-700 bg-zinc-950"
|
className="h-4 w-4 rounded border-zinc-700 bg-zinc-950"
|
||||||
/>
|
/>
|
||||||
MediaMTX record (pathDefaults.record)
|
MediaMTX record (pathDefaults.record)
|
||||||
@@ -392,8 +359,8 @@ export default function Settings() {
|
|||||||
<div>
|
<div>
|
||||||
<label className="text-xs text-zinc-400">recordDeleteAfter</label>
|
<label className="text-xs text-zinc-400">recordDeleteAfter</label>
|
||||||
<select
|
<select
|
||||||
value={String(mtx?.record_delete_after_days ?? recordDeleteAfterDays)}
|
value={recordDeleteAfterDays}
|
||||||
onChange={(e) => void onChangeRecordDeleteAfter(Number(e.target.value))}
|
onChange={(e) => setRecordDeleteAfterDays(e.target.value)}
|
||||||
disabled={mtxBusy}
|
disabled={mtxBusy}
|
||||||
className="mt-1 h-9 w-full rounded-md border border-zinc-800 bg-zinc-950 px-3 text-sm text-zinc-100 disabled:opacity-60"
|
className="mt-1 h-9 w-full rounded-md border border-zinc-800 bg-zinc-950 px-3 text-sm text-zinc-100 disabled:opacity-60"
|
||||||
>
|
>
|
||||||
@@ -406,8 +373,8 @@ export default function Settings() {
|
|||||||
<label className="flex items-center gap-2 text-sm text-zinc-200">
|
<label className="flex items-center gap-2 text-sm text-zinc-200">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={Boolean(schedule?.enabled)}
|
checked={schedulerEnabled}
|
||||||
onChange={(e) => void setSchedulerEnabled(e.target.checked)}
|
onChange={(e) => setSchedulerEnabledState(e.target.checked)}
|
||||||
className="h-4 w-4 rounded border-zinc-700 bg-zinc-950"
|
className="h-4 w-4 rounded border-zinc-700 bg-zinc-950"
|
||||||
/>
|
/>
|
||||||
Enable scheduler
|
Enable scheduler
|
||||||
@@ -444,14 +411,6 @@ export default function Settings() {
|
|||||||
Weekend: record all day
|
Weekend: record all day
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => void onSaveSchedule()}
|
|
||||||
disabled={isLoading}
|
|
||||||
className="inline-flex items-center gap-2 rounded-md border border-zinc-700 bg-zinc-950/40 px-3 py-2 text-sm text-zinc-200 transition hover:bg-zinc-900 disabled:cursor-not-allowed disabled:opacity-60"
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => void onRestartDocker()}
|
onClick={() => void onRestartDocker()}
|
||||||
|
|||||||
Reference in New Issue
Block a user