#!/usr/bin/env python3 # trim-captures — prune old VOICE capture audio from /tmp/airband, keeping the durable detection log. # Safe by design: heard.jsonl (the detections Activity reads — channel + time) is SEPARATE and never # touched; this only deletes bulky .mp3 audio AFTER it's logged. It forces an ingest first (GET /api/heard, # which appends any new clip to heard.jsonl) and ABORTS if the dashboard is unreachable — so a not-yet-logged # clip can never be deleted. --dry-run to preview. import os, glob, time, sys, urllib.request CAP = os.environ.get("AIRBAND_DIR", "/tmp/airband") KEEP_HOURS = float(os.environ.get("CAP_KEEP_HOURS", "24")) DASH = os.environ.get("DASH_URL", "http://127.0.0.1:8157") DRY = "--dry-run" in sys.argv def main(): try: # log every current clip to heard.jsonl first urllib.request.urlopen(DASH + "/api/heard", timeout=10).read() except Exception as e: print(f"[trim] dashboard unreachable ({e}) — NOT trimming (clips may be unlogged)"); return cutoff = time.time() - KEEP_HOURS * 3600 mp3s = glob.glob(os.path.join(CAP, "*.mp3")) old = [m for m in mp3s if os.path.getmtime(m) < cutoff] freed = 0 for m in old: freed += os.path.getsize(m) if not DRY: try: os.remove(m) except OSError: pass # whisper sidecar (2026-07-10) rides with its clip — no orphan .txt buildup try: os.remove(m[:-4] + ".txt") except OSError: pass print(f"[trim{' DRY' if DRY else ''}] {len(mp3s)} clips on disk, deleted {len(old)} older than " f"{KEEP_HOURS:.0f}h, freed {freed//1024} KB; heard.jsonl untouched") if __name__ == "__main__": main()