From d2b2f3d54d204b9cc86785cce2685c1843dbe35b Mon Sep 17 00:00:00 2001 From: Rui Alves Date: Mon, 11 Nov 2024 03:26:47 +0000 Subject: [PATCH] Use custom body for the export recordings endpoint (#14908) * Use custom body for the export recordings endpoint * Fixed usage of ExportRecordingsBody * Updated docs to reflect changes to export endpoint * Fix friendly name and source * Updated openAPI spec --- docs/static/frigate-api.yaml | 90 ++++++++++++++----- frigate/api/defs/__init__.py | 0 frigate/api/defs/request/__init__.py | 0 .../defs/request/export_recordinds_body.py | 20 +++++ frigate/api/export.py | 20 ++--- 5 files changed, 93 insertions(+), 37 deletions(-) create mode 100644 frigate/api/defs/__init__.py create mode 100644 frigate/api/defs/request/__init__.py create mode 100644 frigate/api/defs/request/export_recordinds_body.py diff --git a/docs/static/frigate-api.yaml b/docs/static/frigate-api.yaml index 9a6364e27..325af2850 100644 --- a/docs/static/frigate-api.yaml +++ b/docs/static/frigate-api.yaml @@ -7,7 +7,7 @@ info: servers: - url: https://demo.frigate.video/api - - url: http://localhost:5001/ + - url: http://localhost:5001/api paths: /auth: @@ -296,7 +296,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ReviewSetMultipleReviewedBody' + $ref: '#/components/schemas/ReviewModifyMultipleBody' responses: '200': description: Successful Response @@ -321,7 +321,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ReviewDeleteMultipleReviewsBody' + $ref: '#/components/schemas/ReviewModifyMultipleBody' responses: '200': description: Successful Response @@ -1141,11 +1141,11 @@ paths: type: number title: End Time requestBody: + required: true content: application/json: schema: - type: object - title: Body + $ref: '#/components/schemas/ExportRecordingsBody' responses: '200': description: Successful Response @@ -1408,6 +1408,14 @@ paths: - type: number - type: 'null' title: Max Length + - name: event_id + in: query + required: false + schema: + anyOf: + - type: string + - type: 'null' + title: Event Id - name: sort in: query required: false @@ -1518,7 +1526,7 @@ paths: anyOf: - type: string - type: 'null' - default: thumbnail,description + default: thumbnail title: Search Type - name: include_thumbnails in: query @@ -1590,6 +1598,22 @@ paths: - type: 'null' default: 00:00,24:00 title: Time Range + - name: has_clip + in: query + required: false + schema: + anyOf: + - type: boolean + - type: 'null' + title: Has Clip + - name: has_snapshot + in: query + required: false + schema: + anyOf: + - type: boolean + - type: 'null' + title: Has Snapshot - name: timezone in: query required: false @@ -2356,14 +2380,14 @@ paths: required: false schema: type: number - default: 1729274204.653048 + default: 1731275308.238304 title: After - name: before in: query required: false schema: type: number - default: 1729277804.653095 + default: 1731278908.238313 title: Before responses: '200': @@ -3262,6 +3286,27 @@ components: required: - subLabel title: EventsSubLabelBody + ExportRecordingsBody: + properties: + playback: + allOf: + - $ref: '#/components/schemas/PlaybackFactorEnum' + title: Playback factor + default: realtime + source: + allOf: + - $ref: '#/components/schemas/PlaybackSourceEnum' + title: Playback source + default: recordings + name: + type: string + maxLength: 256 + title: Friendly name + image_path: + type: string + title: Image Path + type: object + title: ExportRecordingsBody Extension: type: string enum: @@ -3313,6 +3358,18 @@ components: - total_alert - total_detection title: Last24HoursReview + PlaybackFactorEnum: + type: string + enum: + - realtime + - timelapse_25x + title: PlaybackFactorEnum + PlaybackSourceEnum: + type: string + enum: + - recordings + - preview + title: PlaybackSourceEnum RegenerateDescriptionEnum: type: string enum: @@ -3336,7 +3393,7 @@ components: - motion - camera title: ReviewActivityMotionResponse - ReviewDeleteMultipleReviewsBody: + ReviewModifyMultipleBody: properties: ids: items: @@ -3348,7 +3405,7 @@ components: type: object required: - ids - title: ReviewDeleteMultipleReviewsBody + title: ReviewModifyMultipleBody ReviewSegmentResponse: properties: id: @@ -3386,19 +3443,6 @@ components: - thumb_path - data title: ReviewSegmentResponse - ReviewSetMultipleReviewedBody: - properties: - ids: - items: - type: string - minLength: 1 - type: array - minItems: 1 - title: Ids - type: object - required: - - ids - title: ReviewSetMultipleReviewedBody ReviewSummaryResponse: properties: last24Hours: diff --git a/frigate/api/defs/__init__.py b/frigate/api/defs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/frigate/api/defs/request/__init__.py b/frigate/api/defs/request/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/frigate/api/defs/request/export_recordinds_body.py b/frigate/api/defs/request/export_recordinds_body.py new file mode 100644 index 000000000..eb6c15155 --- /dev/null +++ b/frigate/api/defs/request/export_recordinds_body.py @@ -0,0 +1,20 @@ +from typing import Union + +from pydantic import BaseModel, Field +from pydantic.json_schema import SkipJsonSchema + +from frigate.record.export import ( + PlaybackFactorEnum, + PlaybackSourceEnum, +) + + +class ExportRecordingsBody(BaseModel): + playback: PlaybackFactorEnum = Field( + default=PlaybackFactorEnum.realtime, title="Playback factor" + ) + source: PlaybackSourceEnum = Field( + default=PlaybackSourceEnum.recordings, title="Playback source" + ) + name: str = Field(title="Friendly name", default=None, max_length=256) + image_path: Union[str, SkipJsonSchema[None]] = None diff --git a/frigate/api/export.py b/frigate/api/export.py index c3299a4b0..1a360bb32 100644 --- a/frigate/api/export.py +++ b/frigate/api/export.py @@ -4,13 +4,13 @@ import logging import random import string from pathlib import Path -from typing import Optional import psutil from fastapi import APIRouter, Request from fastapi.responses import JSONResponse from peewee import DoesNotExist +from frigate.api.defs.request.export_recordinds_body import ExportRecordingsBody from frigate.api.defs.tags import Tags from frigate.const import EXPORT_DIR from frigate.models import Export, Previews, Recordings @@ -37,7 +37,7 @@ def export_recording( camera_name: str, start_time: float, end_time: float, - body: dict = None, + body: ExportRecordingsBody, ): if not camera_name or not request.app.frigate_config.cameras.get(camera_name): return JSONResponse( @@ -47,18 +47,10 @@ def export_recording( status_code=404, ) - json: dict[str, any] = body or {} - playback_factor = json.get("playback", "realtime") - playback_source = json.get("source", "recordings") - friendly_name: Optional[str] = json.get("name") - - if len(friendly_name or "") > 256: - return JSONResponse( - content=({"success": False, "message": "File name is too long."}), - status_code=401, - ) - - existing_image = json.get("image_path") + playback_factor = body.playback + playback_source = body.source + friendly_name = body.name + existing_image = body.image_path if playback_source == "recordings": recordings_count = (