Shared library for evidence intake products under Dynamic Devices Ltd.
Used as a git submodule at core/ by product repos:
| Product | Repo | Visibility |
|---|---|---|
| Reckless Rides UK | reckless-rides-uk | Public |
| Personal safety app | personal-safety-app | Private (org) |
This repo is public. It contains no credentials, no real incident media, and no victim data.
| Module | Purpose |
|---|---|
probe |
Read date/time, device, and GPS from photos and videos |
location |
ISO6709 parsing, map URLs, GPS zero/absent detection |
manifest |
Build evidence/v1 chain-of-custody manifests |
geojson |
Build GeoJSON from incident JSON (optional YouTube URL filter) |
media |
ffmpeg helpers: metadata strip, 16:9 letterbox, deface wrapper |
| Source | Time | Device | GPS |
|---|---|---|---|
iPhone .MOV (original) |
QuickTime tags | Yes | ISO6709 |
| Samsung JPEG (original) | EXIF | Yes | EXIF (zero if indoor/no fix) |
| WhatsApp video | Stripped | No | No |
| Chat/screenshot re-encode | Usually stripped | No | No |
Install exifread for JPEG probing: pip install -e ".[exif]".
As a submodule (typical for product repos):
git submodule update --init --recursive
pip install -e "./core[dev]"Standalone clone:
git clone https://github.com/DynamicDevices/evidence-core.git
cd evidence-core
pip install -e ".[dev]"# Human-readable report (exit code: 0=pass, 1=partial, 2=fail)
probe-media /path/to/file.MOV
probe-media /path/to/photo.jpg --json
probe-media /path/to/file.MOV --legacy-meta # ingest-compatible JSON
# GeoJSON from incident metadata files
build-geojson evidence/processed -o docs/data/incidents.geojson --require-youtube-url| Verdict | Meaning | Typical cause |
|---|---|---|
| PASS | Device, time, and real GPS | Outdoor original (e.g. iPhone MOV) |
| PARTIAL | Device and time; GPS missing or zero | Indoor shot, or location tags off |
| FAIL | Stripped or insufficient metadata | WhatsApp, screenshot, chat preview |
from evidence_core.probe import probe_file, format_report
from evidence_core.manifest import build_manifest, rides_legacy_manifest
from evidence_core.geojson import write_geojson
result = probe_file("/path/to/clip.MOV")
print(format_report(result))
write_geojson(
Path("evidence/processed"),
Path("docs/data/incidents.geojson"),
require_youtube_url=True,
)Product repos pin this submodule at core/ and add wrappers only:
| In product repo | In evidence-core |
|---|---|
Incident prefix (DEB-, VAWG-) |
Generic evidence/v1 schema |
| YouTube templates, OAuth, channel copy | Probe, manifest, geojson, media |
| Compliance / LIA per purpose | No secrets, synthetic test fixtures only |
| Real evidence files (gitignored) | — |
Bump core in a product repo:
cd core && git fetch && git checkout v0.1.0 && cd ..
git add core && git commit -m "Bump evidence-core to v0.1.0"Base manifest: schema/evidence-v1.manifest.json
schema:evidence/v1product: e.g.reckless-rides-ukincident_id: product prefix + timestamp + location + sequencelocation.map_visible: optional; geojson builder skips whenfalseextensions: product-specific (e.g. YouTube block in rides)
Rides manifests still emit dangerous-ebikers-evidence/v1 via rides_legacy_manifest() for back-compat.
pytestGitHub Actions runs on every push to main (pytest + CLI smoke).
Tagged with semver (v0.1.0, …). Product repos should pin the submodule to a release tag, not floating main, for reproducible ingest.
MIT — Dynamic Devices Ltd.