Files
clearpilot/system/loggerd/deleter.py
Brian Hanson 8ae7ef6eaf dashcam: re-enable screen recorder, disable training data video
- Re-enable FrogPilot OMX screen recorder (H.264 MP4, 1440x720, 2Mbps)
- Auto-start recording when car is on, auto-stop when off
- Hide all recorder UI elements (invisible to driver)
- Add ScreenRecorderDebug param for bench testing without car
- Disable encoderd (camera .hevc files) — CAN/sensor logs still recorded
- Raise deleter free space threshold from 5GB to 9GB
- Deleter rotates oldest videos before log segments
- Add CLAUDE.md project documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 07:28:30 +00:00

114 lines
3.3 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import shutil
import threading
from openpilot.system.hardware.hw import Paths
from openpilot.common.swaglog import cloudlog
from openpilot.system.loggerd.config import get_available_bytes, get_available_percent
from openpilot.system.loggerd.uploader import listdir_by_creation
from openpilot.system.loggerd.xattr_cache import getxattr
# CLEARPILOT: increased from 5 GB to 9 GB to reserve space for screen recordings
MIN_BYTES = 9 * 1024 * 1024 * 1024
MIN_PERCENT = 10
DELETE_LAST = ['boot', 'crash']
# CLEARPILOT: screen recorder video directory
VIDEOS_DIR = '/data/media/0/videos'
PRESERVE_ATTR_NAME = 'user.preserve'
PRESERVE_ATTR_VALUE = b'1'
PRESERVE_COUNT = 5
def has_preserve_xattr(d: str) -> bool:
return getxattr(os.path.join(Paths.log_root(), d), PRESERVE_ATTR_NAME) == PRESERVE_ATTR_VALUE
def get_preserved_segments(dirs_by_creation: list[str]) -> list[str]:
preserved = []
for n, d in enumerate(filter(has_preserve_xattr, reversed(dirs_by_creation))):
if n == PRESERVE_COUNT:
break
date_str, _, seg_str = d.rpartition("--")
# ignore non-segment directories
if not date_str:
continue
try:
seg_num = int(seg_str)
except ValueError:
continue
# preserve segment and its prior
preserved.append(d)
preserved.append(f"{date_str}--{seg_num - 1}")
return preserved
def delete_oldest_video():
"""CLEARPILOT: delete the oldest screen recording MP4 when disk space is low."""
try:
if not os.path.isdir(VIDEOS_DIR):
return False
videos = sorted(
(f for f in os.listdir(VIDEOS_DIR) if f.endswith('.mp4')),
key=lambda f: os.path.getctime(os.path.join(VIDEOS_DIR, f))
)
if not videos:
return False
delete_path = os.path.join(VIDEOS_DIR, videos[0])
cloudlog.info(f"deleting video {delete_path}")
os.remove(delete_path)
return True
except OSError:
cloudlog.exception(f"issue deleting video from {VIDEOS_DIR}")
return False
def deleter_thread(exit_event):
while not exit_event.is_set():
out_of_bytes = get_available_bytes(default=MIN_BYTES + 1) < MIN_BYTES
out_of_percent = get_available_percent(default=MIN_PERCENT + 1) < MIN_PERCENT
if out_of_percent or out_of_bytes:
# CLEARPILOT: try deleting oldest video first, then fall back to log segments
if delete_oldest_video():
exit_event.wait(.1)
continue
dirs = listdir_by_creation(Paths.log_root())
# skip deleting most recent N preserved segments (and their prior segment)
preserved_dirs = get_preserved_segments(dirs)
# remove the earliest directory we can
for delete_dir in sorted(dirs, key=lambda d: (d in DELETE_LAST, d in preserved_dirs)):
delete_path = os.path.join(Paths.log_root(), delete_dir)
if any(name.endswith(".lock") for name in os.listdir(delete_path)):
continue
try:
cloudlog.info(f"deleting {delete_path}")
if os.path.isfile(delete_path):
os.remove(delete_path)
else:
shutil.rmtree(delete_path)
break
except OSError:
cloudlog.exception(f"issue deleting {delete_path}")
exit_event.wait(.1)
else:
exit_event.wait(30)
def main():
deleter_thread(threading.Event())
if __name__ == "__main__":
main()