add endpoint

This commit is contained in:
Josh Hawkins 2026-01-04 11:29:26 -06:00
parent a636e37b6e
commit 97ee0c2f40
2 changed files with 79 additions and 3 deletions

View File

@ -25,7 +25,7 @@ from pydantic import ValidationError
from frigate.api.auth import allow_any_authenticated, allow_public, require_role
from frigate.api.defs.query.app_query_parameters import AppTimelineHourlyQueryParameters
from frigate.api.defs.request.app_body import AppConfigSetBody
from frigate.api.defs.request.app_body import AppConfigSetBody, MediaSyncBody
from frigate.api.defs.tags import Tags
from frigate.config import FrigateConfig
from frigate.config.camera.updater import (
@ -34,6 +34,7 @@ from frigate.config.camera.updater import (
)
from frigate.ffmpeg_presets import FFMPEG_HWACCEL_VAAPI, _gpu_selector
from frigate.models import Event, Timeline
from frigate.record.util import sync_all_media
from frigate.stats.prometheus import get_metrics, update_metrics
from frigate.util.builtin import (
clean_camera_user_pass,
@ -602,6 +603,68 @@ def restart():
)
@router.post("/media/sync", dependencies=[Depends(require_role(["admin"]))])
def sync_media(body: MediaSyncBody = Body(...)):
"""Sync media files with database - remove orphaned files.
Syncs specified media types: event snapshots, event thumbnails, review thumbnails,
previews, exports, and/or recordings.
Args:
body: MediaSyncBody with dry_run flag and media_types list.
media_types can include: 'all', 'event_snapshots', 'event_thumbnails',
'review_thumbnails', 'previews', 'exports', 'recordings'
Returns:
JSON response with sync results for each requested media type.
"""
try:
results = sync_all_media(
dry_run=body.dry_run, media_types=body.media_types, force=body.force
)
# Check if any operations were aborted or had errors
has_errors = False
for result_name in [
"event_snapshots",
"event_thumbnails",
"review_thumbnails",
"previews",
"exports",
"recordings",
]:
result = getattr(results, result_name, None)
if result and (result.aborted or result.error):
has_errors = True
break
content = {
"success": not has_errors,
"dry_run": body.dry_run,
"media_types": body.media_types,
"results": results.to_dict(),
}
if has_errors:
content["message"] = (
"Some sync operations were aborted or had errors; check logs for details."
)
return JSONResponse(
content=content,
status_code=200,
)
except Exception as e:
logger.error(f"Error syncing media files: {e}")
return JSONResponse(
content={
"success": False,
"message": f"Error syncing media files: {str(e)}",
},
status_code=500,
)
@router.get("/labels", dependencies=[Depends(allow_any_authenticated())])
def get_labels(camera: str = ""):
try:

View File

@ -1,6 +1,6 @@
from typing import Any, Dict, Optional
from typing import Any, Dict, List, Optional
from pydantic import BaseModel
from pydantic import BaseModel, Field
class AppConfigSetBody(BaseModel):
@ -27,3 +27,16 @@ class AppPostLoginBody(BaseModel):
class AppPutRoleBody(BaseModel):
role: str
class MediaSyncBody(BaseModel):
dry_run: bool = Field(
default=True, description="If True, only report orphans without deleting them"
)
media_types: List[str] = Field(
default=["all"],
description="Types of media to sync: 'all', 'event_snapshots', 'event_thumbnails', 'review_thumbnails', 'previews', 'exports', 'recordings'",
)
force: bool = Field(
default=False, description="If True, bypass safety threshold checks"
)