Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# --- Version control ---
.git
.gitignore
.gitattributes
.github

# --- Editor / OS noise (any depth) ---
**/.DS_Store
**/*.swp
**/*.swo
**/*~
.idea
.vscode
.aider*

# --- Agent / dev tooling state ---
.claude
.cursorrules
.planning

# --- Git worktrees ---
.worktrees
worktrees

# --- Python virtualenvs and caches (any depth) ---
.venv
venv
**/__pycache__
**/*.py[cod]
**/*$py.class
.pytest_cache
.ruff_cache
.mypy_cache

# --- Local dev ---
local-config
recordings
**/*.db
**/*.db-wal
**/*.db-shm
.env
.env.*
**/*.env
viofosync.env
config.json
settings-audit.log

# --- Tests / docs / dev-only tooling ---
# The runtime image doesn't need any of these.
tests
docs
pyproject.toml
requirements-dev.txt

# --- Logs and scratch (any depth) ---
**/*.log
tmp
**/*.tmp
**/*.bak
29 changes: 29 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Pre-push gate. Mirrors .github/workflows/ci.yml so a CI failure
# can't get past the local push. Bypass once with `--no-verify`.
#
# Activated repo-wide via `git config core.hooksPath .githooks`
# (see CLAUDE.md).

set -euo pipefail

# Use the project venv if it exists; otherwise the system python.
# Prefer .venv to match the local dev convention in CLAUDE.md.
if [[ -x ".venv/bin/python" ]]; then
PY=".venv/bin/python"
else
PY="$(command -v python3 || command -v python)"
fi

if [[ -z "${PY:-}" ]]; then
echo "pre-push: no python interpreter found." >&2
exit 1
fi

echo "pre-push: ruff ($PY)"
"$PY" -m ruff check .

echo "pre-push: pytest ($PY)"
"$PY" -m pytest -q

echo "pre-push: all checks passed."
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: CI

on:
push:
branches: [main, web-ui]
pull_request:
branches: [main, web-ui]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- run: pip install -r requirements-dev.txt
- run: python -m ruff check .
- run: python -m pytest -q
21 changes: 21 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,24 @@ tmp
.DS_Store


.venv/*
recordings/*

# Python
__pycache__/
*.py[cod]
.pytest_cache/
.ruff_cache/

# App state / secrets
*.db
*.db-wal
*.db-shm
*.env
viofosync.env
config.json

# Editor
.venv/
docs/*
CLAUDE.md
26 changes: 23 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# CHANGELOG
# Changelog

## 1.0 (2024-09-18)
## v2.0 — 2026-05

* initial release
Major rewrite. Web UI replaces the cron CLI.

### Added
- Web UI on port 8080 with archive browser, download manager, GPX
journey map, and ffmpeg picture-in-picture exports.
- First-run setup wizard at `/setup`.
- Settings page (UI-driven config, hot-reloaded for runtime values,
restart-required for `WEB_HOST`/`WEB_PORT`).
- JSON config at `/config/config.json` replaces `viofosync.env`.

### Changed
- Docker image is webapp-only; cron CLI is no longer the primary path.
- Required env vars reduced to `PUID` / `PGID` / `TZ`.

### Migration
- Existing `viofosync.env` files are migrated to `config.json` on first
boot. The old file is preserved as a one-shot rollback path.

## v1.x

- Cron-driven CLI version. See git history.
74 changes: 48 additions & 26 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,36 +1,58 @@
FROM alpine:3.20.3
FROM alpine:3.23
LABEL maintainer="Rob Smith https://github.com/RobXYZ"

RUN apk add --no-cache bash python3 shadow tzdata \
&& useradd -UMr dashcam
# TARGETARCH is set automatically by `docker buildx build` (amd64,
# arm64, …). Plain `docker build` does NOT set it; in that case we
# fall back to `apk --print-arch`, which reports the actual
# container architecture (x86_64, aarch64, …) and is correct under
# both native builds and QEMU emulation.
ARG TARGETARCH

# System deps:
# - python3 + pip: runtime + installing web deps
# - ffmpeg: exports + thumbnails
# - bash, shadow, tzdata: entrypoint + PUID/PGID remapping
# - intel-media-driver, libva-utils (Intel x86_64 only): VA-API
# userspace + diagnostic tool. ffmpeg's h264_qsv / h264_vaapi
# need iHD_drv_video.so to talk to an Intel iGPU when the host
# maps /dev/dri into the container; without it the MFX runtime
# fails immediately with "MFX session: -9". `vainfo` from
# libva-utils is a one-liner diagnostic the operator can run via
# `docker exec` to verify the passthrough is wired up correctly.
# These packages don't exist on linux/arm64. The app's encoder
# probe (web/services/exporter.py) runtime-tests every candidate
# and falls back to libx264 software encode if QSV / VAAPI
# aren't available, so the missing packages on ARM degrade
# transparently.
RUN apk add --no-cache \
bash python3 py3-pip ffmpeg shadow su-exec tzdata && \
arch="${TARGETARCH:-$(apk --print-arch)}" && \
case "$arch" in \
amd64|x86_64) apk add --no-cache intel-media-driver libva-utils ;; \
esac && \
useradd -UMr dashcam

COPY COPYING /
COPY setuid.sh /setuid.sh
COPY entrypoint.sh /entrypoint.sh
COPY crontab /var/spool/cron/crontabs/dashcam

ENV ADDRESS="" \
PUID="" \
ENV PUID="" \
PGID="" \
KEEP="" \
GROUPING="" \
PRIORITY="" \
MAX_USED_DISK="" \
TIMEOUT="" \
DOWNLOAD_ATTEMPTS="" \
VERBOSE=0 \
QUIET="" \
CRON=1 \
DRY_RUN="" \
RUN_ONCE="" \
READ_ONLY="" \
GPS_EXTRACT="" \
HTML=""

COPY --chown=dashcam viofosync.sh /viofosync.sh
COPY --chown=dashcam viofosync.py /viofosync.py

RUN sed -i 's/\r$//' /entrypoint.sh /setuid.sh /viofosync.sh /viofosync.py \
&& chmod +x /viofosync.sh
RECORDINGS="/recordings"

# Install Python deps into the system site-packages. Alpine's
# pip refuses by default (PEP 668); --break-system-packages is
# safe inside a container.
COPY requirements.txt /requirements.txt
RUN pip install --no-cache-dir --break-system-packages \
-r /requirements.txt

COPY --chown=dashcam viofosync_lib /viofosync_lib
COPY --chown=dashcam web /web

EXPOSE 8080

RUN sed -i 's/\r$//' /entrypoint.sh /setuid.sh \
&& chmod +x /entrypoint.sh /setuid.sh

ENTRYPOINT [ "/entrypoint.sh"]
Loading
Loading