# Local media redaction apps

Use this reference when building a local browser app that accepts uploaded images/videos and redacts sensitive visual regions with blur or masks.

## Recommended implementation shape

- Backend: FastAPI + `python-multipart` for uploads, `StaticFiles` for a single-page UI, `/health`, `/download/{file}`.
- Prefer a two-stage API for videos: `/api/upload` stores the media and returns a `file_id`; `/api/preview` returns a blurred still from a selected frame using the current blur settings; `/api/render` runs the full image/video job only after the user approves the preview. Keep `/api/process` only as a backwards-compatible one-shot endpoint if useful.
- Image/video processing: OpenCV (`opencv-python-headless`) + NumPy + Pillow.
- Automatic adult-content region detection: `nudenet.NudeDetector` can detect exposed nipples, breasts, genitalia, anus/buttocks, etc. Filter its labels aggressively to avoid blurring faces/feet/armpits unless requested.
- Video stabilization/tracking: run detection every N frames, then smooth matched boxes with IoU-based association between current and previous detections. This is not full object tracking, but it is a quick reliable baseline for censor blur.
- Audio preservation: write a temporary silent MP4 from OpenCV, then use `ffmpeg` to mux the original audio track back with `-map 0:v:0 -map 1:a:0? -c:v copy -c:a aac -shortest`.
- Local access: if the user expects remote browser access, verify both `127.0.0.1:<port>/health` and the Tailscale serve/Funnel URL, not only the local port. For public access, `sudo tailscale funnel --bg --yes <port>` can expose the same hostname publicly; confirm `tailscale funnel status` says `Funnel on` and fetch `/health` through the HTTPS URL.

## Safety and UX notes

- The app should state that it is for legal/consensual content only.
- Prefer automatic detection when requested. Do not default to manual rectangle drawing if the user explicitly asks for automatic detection/tracking.
- For video, provide a frame preview before full compute: allow the user to choose frame index, blur strength, region margin, and detection interval, refresh the preview repeatedly, then launch the expensive render.
- Keep manual mask editing as an optional fallback for missed detections, not the primary workflow.
- Make blur strength, region margin, selected preview frame, and `detect_every` configurable.
- Surface detection counts and processing status honestly; do not claim accuracy guarantees.

## Testing pattern

- Unit-test pure functions: box clamping, IoU, smoothing, and blur application.
- API smoke-test upload/download with a synthetic non-sensitive image and a fake detector, so tests do not depend on adult fixtures.
- Run one real detector smoke test on a blank image to confirm the model imports and returns an empty list.
- Verify the live server with `/health` before handing off the URL.

## Pitfalls

- NudeNet detections can be version-dependent: labels may appear under `class` or `label`, and boxes are generally `[x, y, width, height]`.
- `curl -F file=@...` can be brittle in some command contexts; if it fails while the file exists, use Python `httpx` from the project venv for the API smoke test.
- Foreground package installs can be misclassified as long-lived processes by the terminal guard; split setup steps or run the install in a tracked background process with `notify_on_complete=true`.
