Skip to content

lawl92/camrecord

Repository files navigation

camrecord

A minimal CCTV/NVR system in ~92KB. Records RTSP streams from IP cameras into 15-minute chunks, with a web UI to browse and play recordings, watch live streams, and manage storage.

Built as a replacement for Shinobi — no Docker, no Node.js, no database. Just bash, ffmpeg, and python3.

camrecord screenshot


Features

  • Records up to N cameras simultaneously as boundary-aligned 15-min MP4 chunks
  • Web UI — browse recordings by date, play at up to 32x speed, grid view for multiple cameras
  • Live view — watch any camera live directly in the browser (MSE, ~1-3s latency)
  • Auto-reconnect — cameras that drop (reboot, network hiccup) reconnect automatically
  • Watchdog — if a camera's recording process dies silently, it's respawned within 30s
  • Disk cleanup — daily cron deletes recordings older than N days
  • Mobile-friendly — responsive UI with swipe support and hamburger menu
  • Per-camera audio — optional AAC transcoding for cameras with incompatible audio codecs

Requirements

  • Linux (Debian/Ubuntu, Fedora/RHEL, or Arch)
  • ffmpeg
  • jq
  • python3 (stdlib only, no pip packages needed)
  • IP cameras with RTSP streams (Dahua, Hikvision, or any ONVIF-compatible camera)

Install

git clone https://github.com/youruser/camrecord.git
cd camrecord

# copy and edit the config with your cameras and storage path
cp config.example.json config.json
nano config.json

# run the installer (installs packages, creates systemd services, sets up cron)
sudo bash install.sh

Then open http://<your-server-ip>:8080 in your browser.


Config

{
  "output_base": "/mnt/recordings",
  "cameras": [
    {
      "name": "frontdoor",
      "url": "rtsp://admin:password@192.168.1.100:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif"
    },
    {
      "name": "garage",
      "url": "rtsp://admin:password@192.168.1.102:554/Streaming/Channels/101/",
      "transcode_audio": true
    }
  ]
}
Field Description
output_base Directory where recordings are stored. One subfolder per camera.
cameras[].name Camera name. Used as folder name (lowercased) and shown in the UI.
cameras[].url Full RTSP URL including credentials.
cameras[].transcode_audio Optional. Set true if the camera uses G.711/PCMU audio (common on Hikvision). Transcodes to AAC. Default: false (stream copy).

To add cameras later, edit config.json and restart the recorder:

sudo systemctl restart record

File structure

camrecord/
├── install.sh          # installer — run this first
├── config.json         # your config (gitignored, has credentials)
├── config.example.json # safe example for reference
├── record.sh           # recorder — spawns one ffmpeg per camera
├── server.py           # web server — recordings + live streams + API
├── viewer.html         # web UI
├── cleanup.sh          # deletes recordings older than N days
├── cleanup.log         # cleanup run history
├── record.service      # systemd unit (generated by install.sh)
└── camara-web.service  # systemd unit (generated by install.sh)

Recordings are stored in output_base:

/mnt/recordings/
├── frontdoor/
│   ├── 2026-05-01T00-00-00.mp4
│   ├── 2026-05-01T00-15-00.mp4
│   └── ...
└── backyard/
    └── ...

Services

Service Description
record.service Runs record.sh — one ffmpeg process per camera, watchdog every 30s
camara-web.service Runs server.py — serves the web UI on port 8080
# status
sudo systemctl status record
sudo systemctl status camara-web

# logs
journalctl -u record -f
journalctl -u camara-web -f

# restart after config changes
sudo systemctl restart record

Disk management

The installer adds a daily cron at 3am that deletes recordings older than 10 days:

0 3 * * * /path/to/camrecord/cleanup.sh 10 >> /path/to/camrecord/cleanup.log 2>&1

Change 10 to however many days you want to retain. To run it manually:

bash cleanup.sh 10

Keyboard shortcuts

Key Action
Space Play / pause
/ Seek ±10s
Shift + / Seek ±3s
/ Next / previous clip
Shift + / Next / previous camera
+ / - Speed up / slow down
f Fullscreen

Camera compatibility

Tested with:

  • Dahuartsp://user:pass@ip:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif
  • Hikvisionrtsp://user:pass@ip:554/Streaming/Channels/101/ (set transcode_audio: true if audio is broken)
  • Any ONVIF-compatible camera should work

License

MIT

About

Minimal CCTV/NVR — replaces Shinobi with 92KB of bash and Python

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors