diff --git a/frigate/api/media.py b/frigate/api/media.py index 6d66124a4..79c08e3d3 100644 --- a/frigate/api/media.py +++ b/frigate/api/media.py @@ -68,14 +68,17 @@ def imagestream(detected_frames_processor, camera_name, fps, height, draw_option while True: # max out at specified FPS time.sleep(1 / fps) - frame = detected_frames_processor.get_current_frame(camera_name, draw_options) + frame = detected_frames_processor.get_current_frame( + camera_name, draw_options) if frame is None: frame = np.zeros((height, int(height * 16 / 9), 3), np.uint8) width = int(height * frame.shape[1] / frame.shape[0]) - frame = cv2.resize(frame, dsize=(width, height), interpolation=cv2.INTER_LINEAR) + frame = cv2.resize(frame, dsize=(width, height), + interpolation=cv2.INTER_LINEAR) - ret, jpg = cv2.imencode(".jpg", frame, [int(cv2.IMWRITE_JPEG_QUALITY), 70]) + ret, jpg = cv2.imencode( + ".jpg", frame, [int(cv2.IMWRITE_JPEG_QUALITY), 70]) yield ( b"--frame\r\n" b"Content-Type: image/jpeg\r\n\r\n" + jpg.tobytes() + b"\r\n\r\n" @@ -111,16 +114,19 @@ def latest_frame(camera_name): camera_name, draw_options ) retry_interval = float( - current_app.frigate_config.cameras.get(camera_name).ffmpeg.retry_interval + current_app.frigate_config.cameras.get( + camera_name).ffmpeg.retry_interval or 10 ) if frame is None or datetime.now().timestamp() > ( - current_app.detected_frames_processor.get_current_frame_time(camera_name) + current_app.detected_frames_processor.get_current_frame_time( + camera_name) + retry_interval ): if current_app.camera_error_image is None: - error_image = glob.glob("/opt/frigate/frigate/images/camera-error.jpg") + error_image = glob.glob( + "/opt/frigate/frigate/images/camera-error.jpg") if len(error_image) > 0: current_app.camera_error_image = cv2.imread( @@ -140,11 +146,13 @@ def latest_frame(camera_name): if height < 1 or width < 1: return ( - "Invalid height / width requested :: {} / {}".format(height, width), + "Invalid height / width requested :: {} / {}".format( + height, width), 400, ) - frame = cv2.resize(frame, dsize=(width, height), interpolation=cv2.INTER_AREA) + frame = cv2.resize(frame, dsize=(width, height), + interpolation=cv2.INTER_AREA) ret, img = cv2.imencode( ".webp", frame, [int(cv2.IMWRITE_WEBP_QUALITY), resize_quality] @@ -155,14 +163,16 @@ def latest_frame(camera_name): return response elif camera_name == "birdseye" and current_app.frigate_config.birdseye.restream: frame = cv2.cvtColor( - current_app.detected_frames_processor.get_current_frame(camera_name), + current_app.detected_frames_processor.get_current_frame( + camera_name), cv2.COLOR_YUV2BGR_I420, ) height = int(request.args.get("h", str(frame.shape[0]))) width = int(height * frame.shape[1] / frame.shape[0]) - frame = cv2.resize(frame, dsize=(width, height), interpolation=cv2.INTER_AREA) + frame = cv2.resize(frame, dsize=(width, height), + interpolation=cv2.INTER_AREA) ret, img = cv2.imencode( ".webp", frame, [int(cv2.IMWRITE_WEBP_QUALITY), resize_quality] @@ -275,7 +285,8 @@ def submit_recording_snapshot_to_plus(camera_name: str, frame_time: str): 404, ) - nd = cv2.imdecode(np.frombuffer(image_data, dtype=np.int8), cv2.IMREAD_COLOR) + nd = cv2.imdecode(np.frombuffer( + image_data, dtype=np.int8), cv2.IMREAD_COLOR) current_app.plus_api.upload_image(nd, camera_name) return make_response( @@ -378,7 +389,8 @@ def recordings_summary(camera_name): "duration": round(recording_group.duration), } if day not in days: - days[day] = {"events": events_count, "hours": [hour_data], "day": day} + days[day] = {"events": events_count, + "hours": [hour_data], "day": day} else: days[day]["events"] += events_count days[day]["hours"].append(hour_data) @@ -392,7 +404,8 @@ def recordings(camera_name): after = request.args.get( "after", type=float, default=(datetime.now() - timedelta(hours=1)).timestamp() ) - before = request.args.get("before", type=float, default=datetime.now().timestamp()) + before = request.args.get("before", type=float, + default=datetime.now().timestamp()) recordings = ( Recordings.select( @@ -511,7 +524,8 @@ def recording_clip(camera_name, start_ts, end_ts): response.headers["Content-Disposition"] = "attachment; filename=%s" % file_name response.headers["Content-Length"] = os.path.getsize(path) response.headers["X-Accel-Redirect"] = ( - f"/cache/{file_name}" # nginx: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers + # nginx: https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers + f"/cache/{file_name}" ) return response @@ -521,7 +535,8 @@ def recording_clip(camera_name, start_ts, end_ts): @MediaBp.route("/vod//start//end/") def vod_ts(camera_name, start_ts, end_ts): recordings = ( - Recordings.select(Recordings.path, Recordings.duration, Recordings.end_time) + Recordings.select( + Recordings.path, Recordings.duration, Recordings.end_time) .where( Recordings.start_time.between(start_ts, end_ts) | Recordings.end_time.between(start_ts, end_ts) @@ -550,7 +565,8 @@ def vod_ts(camera_name, start_ts, end_ts): clips.append(clip) durations.append(duration) else: - logger.warning(f"Recording clip is missing or empty: {recording.path}") + logger.warning( + f"Recording clip is missing or empty: {recording.path}") if not clips: logger.error("No recordings found for the requested time range") @@ -588,7 +604,8 @@ def vod_hour_no_timezone(year_month, day, hour, camera_name): def vod_hour(year_month, day, hour, camera_name, tz_name): parts = year_month.split("-") start_date = ( - datetime(int(parts[0]), int(parts[1]), int(day), int(hour), tzinfo=timezone.utc) + datetime(int(parts[0]), int(parts[1]), int( + day), int(hour), tzinfo=timezone.utc) - datetime.now(pytz.timezone(tz_name.replace(",", "/"))).utcoffset() ) end_date = start_date + timedelta(hours=1) - timedelta(milliseconds=1) @@ -678,7 +695,8 @@ def label_snapshot(camera_name, label): return event_snapshot(event.id) except DoesNotExist: frame = np.zeros((720, 1280, 3), np.uint8) - ret, jpg = cv2.imencode(".jpg", frame, [int(cv2.IMWRITE_JPEG_QUALITY), 70]) + ret, jpg = cv2.imencode( + ".jpg", frame, [int(cv2.IMWRITE_JPEG_QUALITY), 70]) response = make_response(jpg.tobytes()) response.headers["Content-Type"] = "image/jpeg" @@ -689,7 +707,8 @@ def label_snapshot(camera_name, label): @MediaBp.route("//