mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-20 15:18:21 +03:00
Fix recordings storage roots to ignore pseudo stat paths
This commit is contained in:
parent
ced95052ee
commit
51b66857a0
@ -37,8 +37,40 @@ router = APIRouter(tags=[Tags.recordings])
|
|||||||
def get_recordings_storage_usage(request: Request):
|
def get_recordings_storage_usage(request: Request):
|
||||||
storage_stats = request.app.stats_emitter.get_latest_stats()["service"]["storage"]
|
storage_stats = request.app.stats_emitter.get_latest_stats()["service"]["storage"]
|
||||||
|
|
||||||
configured_recording_paths = request.app.frigate_config.get_recordings_paths()
|
def normalize_storage_path(path: str) -> str:
|
||||||
recording_stats = [storage_stats.get(path, {}) for path in configured_recording_paths]
|
return str(Path(path)).rstrip("/") or "/"
|
||||||
|
|
||||||
|
def resolve_root_storage_stats(root_path: str) -> dict:
|
||||||
|
normalized_root = normalize_storage_path(root_path)
|
||||||
|
|
||||||
|
direct_stats = storage_stats.get(normalized_root, {})
|
||||||
|
if direct_stats:
|
||||||
|
return direct_stats
|
||||||
|
|
||||||
|
# Some stats payloads include date/hour pseudo-paths under a configured
|
||||||
|
# recordings root. In that case, use a descendant stat for the owning root
|
||||||
|
# without exposing the pseudo-path as a separate root entry.
|
||||||
|
descendant_candidates = [
|
||||||
|
(normalize_storage_path(path), stats)
|
||||||
|
for path, stats in storage_stats.items()
|
||||||
|
if normalize_storage_path(path).startswith(f"{normalized_root}/") and stats
|
||||||
|
]
|
||||||
|
|
||||||
|
if not descendant_candidates:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
descendant_candidates.sort(key=lambda item: len(item[0]))
|
||||||
|
return descendant_candidates[0][1]
|
||||||
|
|
||||||
|
configured_recording_paths = sorted(
|
||||||
|
{
|
||||||
|
normalize_storage_path(path)
|
||||||
|
for path in request.app.frigate_config.get_recordings_paths()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
recording_stats = [
|
||||||
|
resolve_root_storage_stats(path) for path in configured_recording_paths
|
||||||
|
]
|
||||||
total_mb = sum(stat.get("total", 0) for stat in recording_stats)
|
total_mb = sum(stat.get("total", 0) for stat in recording_stats)
|
||||||
|
|
||||||
if total_mb == 0:
|
if total_mb == 0:
|
||||||
@ -57,11 +89,13 @@ def get_recordings_storage_usage(request: Request):
|
|||||||
|
|
||||||
recording_roots = []
|
recording_roots = []
|
||||||
all_recording_roots = sorted(
|
all_recording_roots = sorted(
|
||||||
set(configured_recording_paths).union(root_camera_usages.keys())
|
set(configured_recording_paths).union(
|
||||||
|
normalize_storage_path(path) for path in root_camera_usages.keys()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
for root_path in all_recording_roots:
|
for root_path in all_recording_roots:
|
||||||
root_stats = storage_stats.get(root_path, {})
|
root_stats = resolve_root_storage_stats(root_path)
|
||||||
total = root_stats.get("total", 0)
|
total = root_stats.get("total", 0)
|
||||||
used = root_stats.get("used", 0)
|
used = root_stats.get("used", 0)
|
||||||
free = root_stats.get("free", 0)
|
free = root_stats.get("free", 0)
|
||||||
|
|||||||
@ -307,3 +307,39 @@ class TestHttpRecordingsStorage(BaseTestHttp):
|
|||||||
assert "/video1/2026-03-07/08" not in roots
|
assert "/video1/2026-03-07/08" not in roots
|
||||||
assert "/video1/2026-03-07/09" not in roots
|
assert "/video1/2026-03-07/09" not in roots
|
||||||
|
|
||||||
|
def test_recordings_storage_ignores_pseudo_root_storage_stat_entries(self):
|
||||||
|
self.minimal_config["cameras"]["back_yard"] = {
|
||||||
|
"ffmpeg": {
|
||||||
|
"inputs": [{"path": "rtsp://10.0.0.2:554/video", "roles": ["detect"]}]
|
||||||
|
},
|
||||||
|
"detect": {"height": 1080, "width": 1920, "fps": 5},
|
||||||
|
"path": "/video1",
|
||||||
|
}
|
||||||
|
|
||||||
|
self.test_stats["service"]["storage"]["/video1"] = {
|
||||||
|
"free": 600,
|
||||||
|
"mount_type": "ext4",
|
||||||
|
"total": 1000,
|
||||||
|
"used": 400,
|
||||||
|
}
|
||||||
|
self.test_stats["service"]["storage"]["/media/frigate/recordings/2026-03-07/10"] = {
|
||||||
|
"free": 700,
|
||||||
|
"mount_type": "ext4",
|
||||||
|
"total": 1000,
|
||||||
|
"used": 300,
|
||||||
|
}
|
||||||
|
self.test_stats["service"]["storage"]["/video1/2026-03-07/10"] = {
|
||||||
|
"free": 500,
|
||||||
|
"mount_type": "ext4",
|
||||||
|
"total": 1000,
|
||||||
|
"used": 500,
|
||||||
|
}
|
||||||
|
|
||||||
|
app = self._build_app()
|
||||||
|
|
||||||
|
with AuthTestClient(app) as client:
|
||||||
|
payload = client.get("/recordings/storage").json()
|
||||||
|
|
||||||
|
root_paths = {root["path"] for root in payload["recording_roots"]}
|
||||||
|
|
||||||
|
assert root_paths == {"/media/frigate/recordings", "/video1"}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user