fix some bug in frontend
This commit is contained in:
+38
-5
@@ -57,6 +57,32 @@ def _clean_text(value: Optional[str]) -> Optional[str]:
|
||||
return cleaned or None
|
||||
|
||||
|
||||
def _sanitize_cfg_fields(cfg: AppConfig) -> bool:
|
||||
changed = False
|
||||
clean_api = _clean_text(cfg.mediamtx_api_url)
|
||||
clean_webrtc = _clean_text(cfg.mediamtx_webrtc_url)
|
||||
clean_user = _clean_text(cfg.mediamtx_api_user)
|
||||
clean_pass = _clean_text(cfg.mediamtx_api_pass)
|
||||
clean_recordings = _clean_text(cfg.recordings_dir)
|
||||
|
||||
if clean_api and clean_api != cfg.mediamtx_api_url:
|
||||
cfg.mediamtx_api_url = clean_api
|
||||
changed = True
|
||||
if clean_webrtc and clean_webrtc != cfg.mediamtx_webrtc_url:
|
||||
cfg.mediamtx_webrtc_url = clean_webrtc
|
||||
changed = True
|
||||
if clean_user != cfg.mediamtx_api_user:
|
||||
cfg.mediamtx_api_user = clean_user
|
||||
changed = True
|
||||
if clean_pass != cfg.mediamtx_api_pass:
|
||||
cfg.mediamtx_api_pass = clean_pass
|
||||
changed = True
|
||||
if clean_recordings and clean_recordings != cfg.recordings_dir:
|
||||
cfg.recordings_dir = clean_recordings
|
||||
changed = True
|
||||
return changed
|
||||
|
||||
|
||||
def _load_mediamtx_yml() -> dict:
|
||||
if not MEDIAMTX_YML_PATH.exists():
|
||||
raise HTTPException(status_code=500, detail="mediamtx_yml_not_found")
|
||||
@@ -96,6 +122,7 @@ def _build_mediamtx_view(data: dict, cfg: AppConfig) -> MediaMTXConfigView:
|
||||
|
||||
async def _sync_app_config_from_mediamtx() -> AppConfig:
|
||||
cfg = await store.load()
|
||||
_sanitize_cfg_fields(cfg)
|
||||
data = _load_mediamtx_yml()
|
||||
cfg.cameras = [
|
||||
Camera(name=c.name, rtsp_url=c.rtsp_url)
|
||||
@@ -133,6 +160,8 @@ def _restart_mediamtx() -> dict:
|
||||
|
||||
async def _apply_recording(enabled: bool) -> None:
|
||||
cfg = await store.load()
|
||||
if _sanitize_cfg_fields(cfg):
|
||||
await store.save(cfg)
|
||||
try:
|
||||
paths = await MediaMTXClient(
|
||||
api_url=cfg.mediamtx_api_url,
|
||||
@@ -140,8 +169,9 @@ async def _apply_recording(enabled: bool) -> None:
|
||||
password=cfg.mediamtx_api_pass,
|
||||
).list_paths_status()
|
||||
names = [it.get("name") for it in (paths.get("items") or []) if isinstance(it, dict) and it.get("name")]
|
||||
except Exception:
|
||||
names = [c.name for c in cfg.cameras]
|
||||
except httpx.HTTPError as e:
|
||||
logger.warning("scheduler_skip_apply_recording: mediamtx_unreachable (%s)", type(e).__name__)
|
||||
return
|
||||
if not names:
|
||||
return
|
||||
|
||||
@@ -150,7 +180,10 @@ async def _apply_recording(enabled: bool) -> None:
|
||||
username=cfg.mediamtx_api_user,
|
||||
password=cfg.mediamtx_api_pass,
|
||||
)
|
||||
await client.set_recording_bulk(names, enabled)
|
||||
try:
|
||||
await client.set_recording_bulk(names, enabled)
|
||||
except httpx.HTTPError as e:
|
||||
logger.warning("scheduler_apply_recording_failed: %s", type(e).__name__)
|
||||
|
||||
|
||||
scheduler = Scheduler(apply=_apply_recording)
|
||||
@@ -169,9 +202,9 @@ async def _scheduler_loop() -> None:
|
||||
"Set mediamtx_api_user/mediamtx_api_pass in api/data/config.json"
|
||||
)
|
||||
else:
|
||||
logger.exception("scheduler_tick_http_status_%s", code)
|
||||
logger.warning("scheduler_tick_http_status_%s", code)
|
||||
except httpx.HTTPError:
|
||||
logger.exception("scheduler_tick_http_error")
|
||||
logger.warning("scheduler_tick_http_error")
|
||||
except Exception:
|
||||
logger.exception("scheduler_tick_failed")
|
||||
finally:
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>My Trae Project</title>
|
||||
<title>IPCam OrangePi Dashboard</title>
|
||||
<script type="module">
|
||||
if (import.meta.hot?.on) {
|
||||
import.meta.hot.on('vite:error', (error) => {
|
||||
|
||||
@@ -12,3 +12,63 @@
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.light body {
|
||||
background-color: rgb(244 244 245);
|
||||
color: rgb(24 24 27);
|
||||
}
|
||||
|
||||
/* Light theme overrides for existing zinc-based utility classes in pages/cards/forms. */
|
||||
.light .border-zinc-800 {
|
||||
border-color: rgb(212 212 216);
|
||||
}
|
||||
|
||||
.light .border-zinc-700 {
|
||||
border-color: rgb(161 161 170);
|
||||
}
|
||||
|
||||
.light .bg-zinc-900\/20,
|
||||
.light .bg-zinc-900\/30 {
|
||||
background-color: rgb(255 255 255 / 0.82);
|
||||
}
|
||||
|
||||
.light .bg-zinc-950 {
|
||||
background-color: rgb(255 255 255);
|
||||
}
|
||||
|
||||
.light .bg-zinc-950\/10 {
|
||||
background-color: rgb(244 244 245 / 0.72);
|
||||
}
|
||||
|
||||
.light .bg-zinc-950\/30,
|
||||
.light .bg-zinc-950\/40 {
|
||||
background-color: rgb(228 228 231 / 0.78);
|
||||
}
|
||||
|
||||
.light .hover\:bg-zinc-900:hover {
|
||||
background-color: rgb(228 228 231);
|
||||
}
|
||||
|
||||
.light .hover\:bg-zinc-950\/30:hover {
|
||||
background-color: rgb(228 228 231 / 0.9);
|
||||
}
|
||||
|
||||
.light .text-zinc-100,
|
||||
.light .text-zinc-200 {
|
||||
color: rgb(24 24 27);
|
||||
}
|
||||
|
||||
.light .text-zinc-300,
|
||||
.light .text-zinc-400 {
|
||||
color: rgb(82 82 91);
|
||||
}
|
||||
|
||||
.light .text-zinc-500 {
|
||||
color: rgb(113 113 122);
|
||||
}
|
||||
|
||||
.light .from-zinc-950\/80 {
|
||||
--tw-gradient-from: rgb(255 255 255 / 0.88) var(--tw-gradient-from-position);
|
||||
--tw-gradient-to: rgb(255 255 255 / 0) var(--tw-gradient-to-position);
|
||||
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user