return correct mime type for thumbnail and latest frame endpoints

follow up to https://github.com/blakeblackshear/frigate/pull/19555
This commit is contained in:
Josh Hawkins 2025-08-22 06:52:51 -05:00
parent 2bfac4cb79
commit 457daabf1a
2 changed files with 13 additions and 10 deletions

View File

@ -10,6 +10,11 @@ class Extension(str, Enum):
jpg = "jpg" jpg = "jpg"
jpeg = "jpeg" jpeg = "jpeg"
def get_mime_type(self) -> str:
if self in (Extension.jpg, Extension.jpeg):
return "image/jpeg"
return f"image/{self.value}"
class MediaLatestFrameQueryParams(BaseModel): class MediaLatestFrameQueryParams(BaseModel):
bbox: Optional[int] = None bbox: Optional[int] = None

View File

@ -194,7 +194,7 @@ def latest_frame(
_, img = cv2.imencode(f".{extension.value}", frame, quality_params) _, img = cv2.imencode(f".{extension.value}", frame, quality_params)
return Response( return Response(
content=img.tobytes(), content=img.tobytes(),
media_type=f"image/{extension.value}", media_type=extension.get_mime_type(),
headers={ headers={
"Cache-Control": "no-store" "Cache-Control": "no-store"
if not params.store if not params.store
@ -219,7 +219,7 @@ def latest_frame(
_, img = cv2.imencode(f".{extension.value}", frame, quality_params) _, img = cv2.imencode(f".{extension.value}", frame, quality_params)
return Response( return Response(
content=img.tobytes(), content=img.tobytes(),
media_type=f"image/{extension.value}", media_type=extension.get_mime_type(),
headers={ headers={
"Cache-Control": "no-store" "Cache-Control": "no-store"
if not params.store if not params.store
@ -878,7 +878,7 @@ def event_snapshot(
def event_thumbnail( def event_thumbnail(
request: Request, request: Request,
event_id: str, event_id: str,
extension: str, extension: Extension,
max_cache_age: int = Query( max_cache_age: int = Query(
2592000, description="Max cache age in seconds. Default 30 days in seconds." 2592000, description="Max cache age in seconds. Default 30 days in seconds."
), ),
@ -903,7 +903,7 @@ def event_thumbnail(
if event_id in camera_state.tracked_objects: if event_id in camera_state.tracked_objects:
tracked_obj = camera_state.tracked_objects.get(event_id) tracked_obj = camera_state.tracked_objects.get(event_id)
if tracked_obj is not None: if tracked_obj is not None:
thumbnail_bytes = tracked_obj.get_thumbnail(extension) thumbnail_bytes = tracked_obj.get_thumbnail(extension.value)
except Exception: except Exception:
return JSONResponse( return JSONResponse(
content={"success": False, "message": "Event not found"}, content={"success": False, "message": "Event not found"},
@ -931,23 +931,21 @@ def event_thumbnail(
) )
quality_params = None quality_params = None
if extension in (Extension.jpg, Extension.jpeg):
if extension == "jpg" or extension == "jpeg":
quality_params = [int(cv2.IMWRITE_JPEG_QUALITY), 70] quality_params = [int(cv2.IMWRITE_JPEG_QUALITY), 70]
elif extension == "webp": elif extension == Extension.webp:
quality_params = [int(cv2.IMWRITE_WEBP_QUALITY), 60] quality_params = [int(cv2.IMWRITE_WEBP_QUALITY), 60]
_, img = cv2.imencode(f".{extension}", thumbnail, quality_params) _, img = cv2.imencode(f".{extension.value}", thumbnail, quality_params)
thumbnail_bytes = img.tobytes() thumbnail_bytes = img.tobytes()
return Response( return Response(
thumbnail_bytes, thumbnail_bytes,
media_type=f"image/{extension}", media_type=extension.get_mime_type(),
headers={ headers={
"Cache-Control": f"private, max-age={max_cache_age}" "Cache-Control": f"private, max-age={max_cache_age}"
if event_complete if event_complete
else "no-store", else "no-store",
"Content-Type": f"image/{extension}",
}, },
) )