|
|
||
|---|---|---|
| .forgejo/workflows | ||
| templates | ||
| .dockerignore | ||
| CHANGELOG.md | ||
| Dockerfile | ||
| entrypoint.sh | ||
| jailarr.py | ||
| README.md | ||
| web.py | ||
👮 Jailarr
A Python-based monitoring system that tracks and stores MyOCV-based jail inmate rosters, and displays them in a simple web interface. It also sends real-time notifications via Apprise (supporting 80+ notification services).
Features
- Multi-Agency Support — Monitor multiple jail rosters simultaneously
- Real-time Monitoring — Customizable check interval (default: 1 hour)
- Modern Web Interface — Simple and intuitive web interface
- Booking Alerts — Sends notifications with mugshot photos for new arrests
- Release Tracking — Automatically detects and logs when inmates are released
- Change Detection — Tracks updates to charges, mugshots, and other inmate details
- Mugshot Versioning — Detects mugshot changes via image hashing and preserves old versions
- Image Archiving — Downloads and stores inmate mugshots locally
- Change History — Full audit log of all record modifications
- Inmate Awards — Optionally shows a small badge for inmates that excel in certain areas (enable it to find out more)
- Flexible Notifications — Supports Telegram, Discord, Slack, email, Pushover, and 80+ other services via Apprise
- Docker Support — Easy deployment with Docker Compose
Configuration
The monitor is configured through environment variables:
Core Settings
| Variable | Description | Required |
|---|---|---|
JSON_URLS |
Agency JSON endpoint(s), comma or newline separated | ✅ Yes |
APPRISE_URLS |
Notification service URL(s), comma-separated | No |
DB_PATH |
Path to SQLite database file | No (default: /data/inmates.db) |
CHECK_INTERVAL |
Time between scans in seconds | No (default: 3600 (1 hour)) |
WEB_PORT |
Port for web server | No (default: 5000) |
ENABLE_AWARDS |
Enable inmate awards | No (default: false) |
Notification Settings
Control which notification types are sent. Set to false to disable.
| Variable | Description | Default |
|---|---|---|
NOTIFY_NEW |
New inmate bookings | true |
NOTIFY_MUGSHOT |
Mugshot updates | true |
NOTIFY_CHARGES |
Charges updates | false |
NOTIFY_UPDATES |
Other field updates | false |
NOTIFY_STARTUP |
Send a message when the service starts | true |
Note: If
APPRISE_URLSis not set, all notifications are disabled and the monitor runs in silent/archive mode.
Notification Services (Apprise)
Jailarr uses Apprise for notifications. Configure one or more services via URL:
| Service | URL Format |
|---|---|
| Telegram | tgram://bot_token/chat_id or tgram://bot_token/chat_id:topic_id |
| Discord | discord://webhook_id/webhook_token |
| Slack | slack://token_a/token_b/token_c/#channel |
mailto://user:pass@gmail.com |
|
| Pushover | pover://user_key@api_token |
| Ntfy | ntfy://topic |
| Gotify | gotify://hostname/token |
Multiple services: Comma-separate URLs to notify multiple services simultaneously:
APPRISE_URLS=tgram://bot/chat,discord://id/token,ntfy://mytopic
See the full list of supported services.
Finding Your JSON URL
This app ONLY works with jail rosters that use the MyOCV platform. You must provide the JSON URL(s) for the roster(s) you want to monitor. The JSON URL usually follows this pattern:
https://cdn.myocv.com/ocvapps/{AGENCY_ID}/{RosterName}.json
Known JSON Endpoints
| Municipality | Agency ID | JSON URL |
|---|---|---|
| Chippewa County, MI | a20449768 |
https://cdn.myocv.com/ocvapps/a20449768/Chippewainmates.json |
| Dickinson County, MI | a135649801 |
https://cdn.myocv.com/ocvapps/a135649801/Dickinsoninmates.json |
| Houghton County, MI | a134149931 |
https://cdn.myocv.com/ocvapps/a134149931/Houghtoninmates.json |
| Mackinac County, MI | a109249781 |
https://cdn.myocv.com/ocvapps/a109249781/Mackinacinmates.json |
| Marquette County, MI | a39949855 |
https://cdn.myocv.com/ocvapps/a39949855/Marquetteinmates.json |
Different agencies may have slightly different JSON formats. Jailarr automatically normalizes field names and date formats across all supported agencies.
How to find your JSON URL
This is a somewhat complex task. Full writeup to come.
Notifications
Notification Types
| Event | Title | Includes Photo |
|---|---|---|
| New booking | 🚨 New Inmate Booking | ✅ Yes |
| Mugshot updated | 📷 Mugshot Updated | ✅ Yes |
| Charges updated | ⚖️ Charges Updated | ❌ No |
| Record updated | 📝 Inmate Record Updated | ❌ No |
First Run Behavior
On the first run (empty database), all inmates are added silently without sending notifications. This prevents a flood of alerts when initially populating the database. A startup message is still sent to confirm the monitor is online.
Example Notification
🚨 New Inmate Booking
Name: Smith, John
Age: 35
Gender: M
Booking Date: 2026-01-15 10:30:00
Charges:
OWI - OPERATING WHILE INTOXICATED - 1000.00
DRIVING WHILE LICENSE SUSPENDED - 500.00
Local Installation
Prerequisites
- Python 3.11+
- pip
-
Clone the repository:
git clone https://github.com/yourusername/jailarr.git cd jailarr -
Install dependencies:
pip install requests apprise python-dateutil flask -
Set environment variables:
# Single agency export JSON_URLS="https://cdn.myocv.com/ocvapps/a39949855/Marquetteinmates.json" # Or multiple agencies (comma-separated) export JSON_URLS="https://cdn.myocv.com/ocvapps/a39949855/Marquetteinmates.json,https://cdn.myocv.com/ocvapps/a135649801/Dickinsoninmates.json" export APPRISE_URLS="tgram://your_bot_token/your_chat_id" export DB_PATH="./data/inmates.db" -
Run the monitor:
python jailarr.py
Docker Deployment
Option 1: Using Pre-built Image (placeholder. images coming soon)
services:
jailarr:
image: placeholder-registry/jailarr:latest
container_name: jailarr
restart: unless-stopped
environment:
- JSON_URLS=https://cdn.myocv.com/ocvapps/a39949855/Marquetteinmates.json
- APPRISE_URLS=tgram://bot_token/chat_id
- CHECK_INTERVAL=3600
ports:
- "5000:5000"
volumes:
- ./data:/data
Option 2: Building the Image
# Build locally
docker build -t jailarr .
# Or with docker compose
docker compose build
Option 3: Mount Source Files (No Build)
If you prefer to mount the source files directly without building an image:
services:
jailarr:
image: python:3.11-slim
container_name: jailarr
restart: unless-stopped
command: >
sh -c "pip install requests apprise python-dateutil flask && sh /app/entrypoint.sh"
environment:
- PYTHONUNBUFFERED=1
- JSON_URLS=https://cdn.myocv.com/ocvapps/a39949855/Marquetteinmates.json
- APPRISE_URLS=tgram://bot_token/chat_id
- DB_PATH=/app/data/inmates.db
- CHECK_INTERVAL=3600
ports:
- "5000:5000"
volumes:
- ./jailarr:/app
Data Storage
The monitor stores data in two locations:
Database (/data/inmates.db)
inmates table:
| Column | Description |
|---|---|
record_id |
Composite key: {agency}_{inmate_id} |
agency |
Source roster (e.g., Marquette, Dickinson) |
inmate_id |
Original ID from the source roster |
name |
Inmate name |
age, gender, race |
Demographics |
height, weight |
Physical description (if available) |
booking_date |
Date/time of booking |
charges |
List of charges |
arresting_agency |
Agency that made the arrest (if available) |
image_url |
Original mugshot URL |
image_hash |
MD5 hash for change detection |
first_seen |
Unix timestamp when first detected |
last_seen |
Unix timestamp of last scan |
status |
active or released |
change_history table:
| Column | Description |
|---|---|
record_id |
Links to inmate |
field_name |
Which field changed |
old_value |
Previous value |
new_value |
Updated value |
changed_at |
Unix timestamp |
Images (/data/images/)
- Current mugshots:
{arrest_no}.jpg - Previous versions:
{arrest_no}_v1.jpg,{arrest_no}_v2.jpg, etc.