forked from Github/frigate
Compare commits
7 Commits
v0.10.0-be
...
v0.10.0-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1155af169 | ||
|
|
77c1f1bb1b | ||
|
|
ae3c01fe2d | ||
|
|
7a2a85d253 | ||
|
|
77c66d4e49 | ||
|
|
494e5ac4ec | ||
|
|
63b7465452 |
@@ -154,7 +154,8 @@ class DetectConfig(FrigateBaseModel):
|
||||
title="Maximum number of frames the object can dissapear before detection ends."
|
||||
)
|
||||
stationary_interval: Optional[int] = Field(
|
||||
title="Frame interval for checking stationary objects."
|
||||
title="Frame interval for checking stationary objects.",
|
||||
ge=1,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -658,10 +658,15 @@ def vod_ts(camera, start_ts, end_ts):
|
||||
# Determine if we need to end the last clip early
|
||||
if recording.end_time > end_ts:
|
||||
duration -= int((recording.end_time - end_ts) * 1000)
|
||||
clips.append(clip)
|
||||
durations.append(duration)
|
||||
|
||||
if duration > 0:
|
||||
clips.append(clip)
|
||||
durations.append(duration)
|
||||
else:
|
||||
logger.warning(f"Recording clip is missing or empty: {recording.path}")
|
||||
|
||||
if not clips:
|
||||
logger.error("No recordings found for the requested time range")
|
||||
return "No recordings found.", 404
|
||||
|
||||
hour_ago = datetime.now() - timedelta(hours=1)
|
||||
@@ -690,10 +695,12 @@ def vod_event(id):
|
||||
try:
|
||||
event: Event = Event.get(Event.id == id)
|
||||
except DoesNotExist:
|
||||
logger.error(f"Event not found: {id}")
|
||||
return "Event not found.", 404
|
||||
|
||||
if not event.has_clip:
|
||||
return "Clip not available", 404
|
||||
logger.error(f"Event does not have recordings: {id}")
|
||||
return "Recordings not available", 404
|
||||
|
||||
clip_path = os.path.join(CLIPS_DIR, f"{event.camera}-{id}.mp4")
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ class RecordingMaintainer(threading.Thread):
|
||||
.where(
|
||||
Event.camera == camera,
|
||||
(Event.end_time == None)
|
||||
| (Event.end_time >= recordings[0]["start_time"]),
|
||||
| (Event.end_time >= recordings[0]["start_time"].timestamp()),
|
||||
Event.has_clip,
|
||||
)
|
||||
.order_by(Event.start_time)
|
||||
@@ -171,7 +171,10 @@ class RecordingMaintainer(threading.Thread):
|
||||
|
||||
# if the event is in progress or ends after the recording starts, keep it
|
||||
# and stop looking at events
|
||||
if event.end_time is None or event.end_time >= start_time:
|
||||
if (
|
||||
event.end_time is None
|
||||
or event.end_time >= start_time.timestamp()
|
||||
):
|
||||
overlaps = True
|
||||
break
|
||||
|
||||
@@ -405,11 +408,40 @@ class RecordingCleanup(threading.Thread):
|
||||
|
||||
for f in files_to_check:
|
||||
p = Path(f)
|
||||
if p.stat().st_mtime < delete_before.get(p.parent.name, default_expire):
|
||||
p.unlink(missing_ok=True)
|
||||
try:
|
||||
if p.stat().st_mtime < delete_before.get(p.parent.name, default_expire):
|
||||
p.unlink(missing_ok=True)
|
||||
except FileNotFoundError:
|
||||
logger.warning(f"Attempted to expire missing file: {f}")
|
||||
|
||||
logger.debug("End expire files (legacy).")
|
||||
|
||||
def sync_recordings(self):
|
||||
logger.debug("Start sync recordings.")
|
||||
|
||||
# get all recordings in the db
|
||||
recordings: Recordings = Recordings.select()
|
||||
|
||||
# get all recordings files on disk
|
||||
process = sp.run(
|
||||
["find", RECORD_DIR, "-type", "f"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
files_on_disk = process.stdout.splitlines()
|
||||
|
||||
recordings_to_delete = []
|
||||
for recording in recordings.objects().iterator():
|
||||
if not recording.path in files_on_disk:
|
||||
recordings_to_delete.append(recording.id)
|
||||
|
||||
logger.debug(
|
||||
f"Deleting {len(recordings_to_delete)} recordings with missing files"
|
||||
)
|
||||
Recordings.delete().where(Recordings.id << recordings_to_delete).execute()
|
||||
|
||||
logger.debug("End sync recordings.")
|
||||
|
||||
def run(self):
|
||||
# Expire recordings every minute, clean directories every hour.
|
||||
for counter in itertools.cycle(range(60)):
|
||||
@@ -423,3 +455,4 @@ class RecordingCleanup(threading.Thread):
|
||||
if counter == 0:
|
||||
self.expire_files()
|
||||
remove_empty_directories(RECORD_DIR)
|
||||
self.sync_recordings()
|
||||
|
||||
@@ -199,7 +199,7 @@ export default function Event({ eventId, close, scrollRef }) {
|
||||
<img
|
||||
src={
|
||||
data.has_snapshot
|
||||
? `${apiHost}/clips/${data.camera}-${eventId}.jpg`
|
||||
? `${apiHost}/api/events/${eventId}/snapshot.jpg`
|
||||
: `data:image/jpeg;base64,${data.thumbnail}`
|
||||
}
|
||||
alt={`${data.label} at ${(data.top_score * 100).toFixed(1)}% confidence`}
|
||||
|
||||
Reference in New Issue
Block a user