mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-12-10 00:07:21 -06:00
Miscellaneous Fixes (#21193)
* Fix saving zone friendly name when it wasn't set * Fix UTF-8 handling for Onvif * Don't remove none directory for classes * Lookup all event IDs for review item immediately * Cleanup typing * Only fetch events when review group is open * Cleanup * disable debug paths switch for autotracking cameras * fix clickable birdseye --------- Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
This commit is contained in:
parent
dfd837cfb0
commit
4cf4520ea7
@ -710,7 +710,7 @@ def delete_classification_dataset_images(
|
|||||||
if os.path.isfile(file_path):
|
if os.path.isfile(file_path):
|
||||||
os.unlink(file_path)
|
os.unlink(file_path)
|
||||||
|
|
||||||
if os.path.exists(folder) and not os.listdir(folder):
|
if os.path.exists(folder) and not os.listdir(folder) and category.lower() != "none":
|
||||||
os.rmdir(folder)
|
os.rmdir(folder)
|
||||||
|
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
|
|||||||
@ -607,23 +607,27 @@ class Dispatcher:
|
|||||||
)
|
)
|
||||||
self.publish(f"{camera_name}/snapshots/state", payload, retain=True)
|
self.publish(f"{camera_name}/snapshots/state", payload, retain=True)
|
||||||
|
|
||||||
def _on_ptz_command(self, camera_name: str, payload: str) -> None:
|
def _on_ptz_command(self, camera_name: str, payload: str | bytes) -> None:
|
||||||
"""Callback for ptz topic."""
|
"""Callback for ptz topic."""
|
||||||
try:
|
try:
|
||||||
if "preset" in payload.lower():
|
preset: str = (
|
||||||
|
payload.decode("utf-8") if isinstance(payload, bytes) else payload
|
||||||
|
).lower()
|
||||||
|
|
||||||
|
if "preset" in preset:
|
||||||
command = OnvifCommandEnum.preset
|
command = OnvifCommandEnum.preset
|
||||||
param = payload.lower()[payload.index("_") + 1 :]
|
param = preset[preset.index("_") + 1 :]
|
||||||
elif "move_relative" in payload.lower():
|
elif "move_relative" in preset:
|
||||||
command = OnvifCommandEnum.move_relative
|
command = OnvifCommandEnum.move_relative
|
||||||
param = payload.lower()[payload.index("_") + 1 :]
|
param = preset[preset.index("_") + 1 :]
|
||||||
else:
|
else:
|
||||||
command = OnvifCommandEnum[payload.lower()]
|
command = OnvifCommandEnum[preset]
|
||||||
param = ""
|
param = ""
|
||||||
|
|
||||||
self.onvif.handle_command(camera_name, command, param)
|
self.onvif.handle_command(camera_name, command, param)
|
||||||
logger.info(f"Setting ptz command to {command} for {camera_name}")
|
logger.info(f"Setting ptz command to {command} for {camera_name}")
|
||||||
except KeyError as k:
|
except KeyError as k:
|
||||||
logger.error(f"Invalid PTZ command {payload}: {k}")
|
logger.error(f"Invalid PTZ command {preset}: {k}")
|
||||||
|
|
||||||
def _on_birdseye_command(self, camera_name: str, payload: str) -> None:
|
def _on_birdseye_command(self, camera_name: str, payload: str) -> None:
|
||||||
"""Callback for birdseye topic."""
|
"""Callback for birdseye topic."""
|
||||||
|
|||||||
@ -95,12 +95,21 @@ class OnvifController:
|
|||||||
|
|
||||||
cam = self.camera_configs[cam_name]
|
cam = self.camera_configs[cam_name]
|
||||||
try:
|
try:
|
||||||
|
user = cam.onvif.user
|
||||||
|
password = cam.onvif.password
|
||||||
|
|
||||||
|
if user is not None and isinstance(user, bytes):
|
||||||
|
user = user.decode("utf-8")
|
||||||
|
|
||||||
|
if password is not None and isinstance(password, bytes):
|
||||||
|
password = password.decode("utf-8")
|
||||||
|
|
||||||
self.cams[cam_name] = {
|
self.cams[cam_name] = {
|
||||||
"onvif": ONVIFCamera(
|
"onvif": ONVIFCamera(
|
||||||
cam.onvif.host,
|
cam.onvif.host,
|
||||||
cam.onvif.port,
|
cam.onvif.port,
|
||||||
cam.onvif.user,
|
user,
|
||||||
cam.onvif.password,
|
password,
|
||||||
wsdl_dir=str(Path(find_spec("onvif").origin).parent / "wsdl"),
|
wsdl_dir=str(Path(find_spec("onvif").origin).parent / "wsdl"),
|
||||||
adjust_time=cam.onvif.ignore_time_mismatch,
|
adjust_time=cam.onvif.ignore_time_mismatch,
|
||||||
encrypt=not cam.onvif.tls_insecure,
|
encrypt=not cam.onvif.tls_insecure,
|
||||||
@ -325,9 +334,15 @@ class OnvifController:
|
|||||||
presets = []
|
presets = []
|
||||||
|
|
||||||
for preset in presets:
|
for preset in presets:
|
||||||
self.cams[camera_name]["presets"][
|
# Ensure preset name is a Unicode string and handle UTF-8 characters correctly
|
||||||
(getattr(preset, "Name") or f"preset {preset['token']}").lower()
|
preset_name = getattr(preset, "Name") or f"preset {preset['token']}"
|
||||||
] = preset["token"]
|
|
||||||
|
if isinstance(preset_name, bytes):
|
||||||
|
preset_name = preset_name.decode("utf-8")
|
||||||
|
|
||||||
|
# Convert to lowercase while preserving UTF-8 characters
|
||||||
|
preset_name_lower = preset_name.lower()
|
||||||
|
self.cams[camera_name]["presets"][preset_name_lower] = preset["token"]
|
||||||
|
|
||||||
# get list of supported features
|
# get list of supported features
|
||||||
supported_features = []
|
supported_features = []
|
||||||
@ -563,6 +578,11 @@ class OnvifController:
|
|||||||
self.cams[camera_name]["active"] = False
|
self.cams[camera_name]["active"] = False
|
||||||
|
|
||||||
async def _move_to_preset(self, camera_name: str, preset: str) -> None:
|
async def _move_to_preset(self, camera_name: str, preset: str) -> None:
|
||||||
|
if isinstance(preset, bytes):
|
||||||
|
preset = preset.decode("utf-8")
|
||||||
|
|
||||||
|
preset = preset.lower()
|
||||||
|
|
||||||
if preset not in self.cams[camera_name]["presets"]:
|
if preset not in self.cams[camera_name]["presets"]:
|
||||||
logger.error(f"{preset} is not a valid preset for {camera_name}")
|
logger.error(f"{preset} is not a valid preset for {camera_name}")
|
||||||
return
|
return
|
||||||
|
|||||||
@ -441,7 +441,7 @@ export default function ZoneEditPane({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let friendlyNameQuery = "";
|
let friendlyNameQuery = "";
|
||||||
if (friendly_name) {
|
if (friendly_name && friendly_name !== zoneName) {
|
||||||
friendlyNameQuery = `&cameras.${polygon?.camera}.zones.${zoneName}.friendly_name=${encodeURIComponent(friendly_name)}`;
|
friendlyNameQuery = `&cameras.${polygon?.camera}.zones.${zoneName}.friendly_name=${encodeURIComponent(friendly_name)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -316,7 +316,7 @@ function ReviewGroup({
|
|||||||
date_style: "medium",
|
date_style: "medium",
|
||||||
});
|
});
|
||||||
|
|
||||||
const shouldFetchEvents = review?.data?.detections?.length > 0;
|
const shouldFetchEvents = open && review?.data?.detections?.length > 0;
|
||||||
|
|
||||||
const { data: fetchedEvents, isValidating } = useSWR<Event[]>(
|
const { data: fetchedEvents, isValidating } = useSWR<Event[]>(
|
||||||
shouldFetchEvents
|
shouldFetchEvents
|
||||||
|
|||||||
@ -134,10 +134,20 @@ function Live() {
|
|||||||
.sort((aConf, bConf) => aConf.ui.order - bConf.ui.order);
|
.sort((aConf, bConf) => aConf.ui.order - bConf.ui.order);
|
||||||
}, [config, cameraGroup, allowedCameras]);
|
}, [config, cameraGroup, allowedCameras]);
|
||||||
|
|
||||||
const selectedCamera = useMemo(
|
const selectedCamera = useMemo(() => {
|
||||||
() => cameras.find((cam) => cam.name == selectedCameraName),
|
if (!config || !selectedCameraName || selectedCameraName === "birdseye") {
|
||||||
[cameras, selectedCameraName],
|
return undefined;
|
||||||
);
|
}
|
||||||
|
const camera = config.cameras[selectedCameraName];
|
||||||
|
if (
|
||||||
|
camera &&
|
||||||
|
allowedCameras.includes(selectedCameraName) &&
|
||||||
|
camera.enabled_in_config
|
||||||
|
) {
|
||||||
|
return camera;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}, [config, selectedCameraName, allowedCameras]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="size-full" ref={mainRef}>
|
<div className="size-full" ref={mainRef}>
|
||||||
@ -146,6 +156,7 @@ function Live() {
|
|||||||
supportsFullscreen={supportsFullScreen}
|
supportsFullscreen={supportsFullScreen}
|
||||||
fullscreen={fullscreen}
|
fullscreen={fullscreen}
|
||||||
toggleFullscreen={toggleFullscreen}
|
toggleFullscreen={toggleFullscreen}
|
||||||
|
onSelectCamera={setSelectedCameraName}
|
||||||
/>
|
/>
|
||||||
) : selectedCamera ? (
|
) : selectedCamera ? (
|
||||||
<LiveCameraView
|
<LiveCameraView
|
||||||
|
|||||||
@ -28,12 +28,14 @@ type LiveBirdseyeViewProps = {
|
|||||||
supportsFullscreen: boolean;
|
supportsFullscreen: boolean;
|
||||||
fullscreen: boolean;
|
fullscreen: boolean;
|
||||||
toggleFullscreen: () => void;
|
toggleFullscreen: () => void;
|
||||||
|
onSelectCamera?: (cameraName: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function LiveBirdseyeView({
|
export default function LiveBirdseyeView({
|
||||||
supportsFullscreen,
|
supportsFullscreen,
|
||||||
fullscreen,
|
fullscreen,
|
||||||
toggleFullscreen,
|
toggleFullscreen,
|
||||||
|
onSelectCamera,
|
||||||
}: LiveBirdseyeViewProps) {
|
}: LiveBirdseyeViewProps) {
|
||||||
const { t } = useTranslation(["views/live"]);
|
const { t } = useTranslation(["views/live"]);
|
||||||
const { data: config } = useSWR<FrigateConfig>("config");
|
const { data: config } = useSWR<FrigateConfig>("config");
|
||||||
@ -181,13 +183,13 @@ export default function LiveBirdseyeView({
|
|||||||
canvasY >= parsedCoords.y &&
|
canvasY >= parsedCoords.y &&
|
||||||
canvasY < parsedCoords.y + parsedCoords.height
|
canvasY < parsedCoords.y + parsedCoords.height
|
||||||
) {
|
) {
|
||||||
navigate(`/#${cameraName}`);
|
onSelectCamera?.(cameraName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[playerRef, config, birdseyeLayout, navigate],
|
[playerRef, config, birdseyeLayout, onSelectCamera],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
|
|||||||
@ -252,6 +252,10 @@ export default function ObjectSettingsView({
|
|||||||
className="ml-1"
|
className="ml-1"
|
||||||
id={param}
|
id={param}
|
||||||
checked={options && options[param]}
|
checked={options && options[param]}
|
||||||
|
disabled={
|
||||||
|
param === "paths" &&
|
||||||
|
cameraConfig?.onvif?.autotracking?.enabled_in_config
|
||||||
|
}
|
||||||
onCheckedChange={(isChecked) => {
|
onCheckedChange={(isChecked) => {
|
||||||
handleSetOption(param, isChecked);
|
handleSetOption(param, isChecked);
|
||||||
}}
|
}}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user