- Abstract ReleaseProvider interface (Gitea impl, swappable for GitHub/GitLab) - Background UpdateService with periodic checks, debounce, dismissed version persistence - Install type detection (installer/portable/docker/dev) with platform-aware asset matching - Download with progress events, silent NSIS reinstall, portable ZIP/tarball swap scripts - Version badge pulse animation, dismissible banner with icon buttons, Settings > Updates tab - Single source of truth: pyproject.toml version via importlib.metadata, CI stamps tag with sed - API: GET/POST status, check, dismiss, apply, GET/PUT settings - i18n: en, ru, zh (27+ keys each)
71 lines
2.5 KiB
Docker
71 lines
2.5 KiB
Docker
## Stage 1: Build frontend bundle
|
|
FROM node:20.18-slim AS frontend
|
|
WORKDIR /build
|
|
COPY package.json package-lock.json* ./
|
|
RUN npm ci --ignore-scripts
|
|
COPY esbuild.mjs tsconfig.json ./
|
|
COPY src/wled_controller/static/ ./src/wled_controller/static/
|
|
RUN npm run build
|
|
|
|
## Stage 2: Python application
|
|
FROM python:3.11.11-slim AS runtime
|
|
|
|
ARG APP_VERSION=0.0.0
|
|
|
|
LABEL maintainer="Alexei Dolgolyov <dolgolyov.alexei@gmail.com>"
|
|
LABEL org.opencontainers.image.title="LED Grab"
|
|
LABEL org.opencontainers.image.description="Ambient lighting system that captures screen content and drives LED strips in real time"
|
|
LABEL org.opencontainers.image.version="${APP_VERSION}"
|
|
LABEL org.opencontainers.image.url="https://git.dolgolyov-family.by/alexei.dolgolyov/wled-screen-controller-mixed"
|
|
LABEL org.opencontainers.image.source="https://git.dolgolyov-family.by/alexei.dolgolyov/wled-screen-controller-mixed"
|
|
LABEL org.opencontainers.image.licenses="MIT"
|
|
|
|
WORKDIR /app
|
|
|
|
# Install system dependencies for screen capture and health check
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
curl \
|
|
libxcb1 \
|
|
libxcb-randr0 \
|
|
libxcb-shm0 \
|
|
libxcb-xfixes0 \
|
|
libxcb-shape0 \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Install Python dependencies first (layer caching optimization).
|
|
# Copy pyproject.toml with a minimal package stub so pip can resolve deps.
|
|
# The real source is copied afterward, keeping the dep layer cached.
|
|
COPY pyproject.toml .
|
|
RUN sed -i "s/^version = .*/version = \"${APP_VERSION}\"/" pyproject.toml \
|
|
&& mkdir -p src/wled_controller && touch src/wled_controller/__init__.py \
|
|
&& pip install --no-cache-dir ".[notifications]" \
|
|
&& rm -rf src/wled_controller
|
|
|
|
# Copy source code and config (invalidates cache only when source changes)
|
|
COPY src/ ./src/
|
|
COPY config/ ./config/
|
|
|
|
# Copy built frontend bundle from stage 1
|
|
COPY --from=frontend /build/src/wled_controller/static/dist/ ./src/wled_controller/static/dist/
|
|
|
|
# Create non-root user for security
|
|
RUN groupadd --gid 1000 ledgrab \
|
|
&& useradd --uid 1000 --gid ledgrab --shell /bin/bash --create-home ledgrab \
|
|
&& mkdir -p /app/data /app/logs \
|
|
&& chown -R ledgrab:ledgrab /app
|
|
|
|
USER ledgrab
|
|
|
|
# Expose API port
|
|
EXPOSE 8080
|
|
|
|
# Health check
|
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
|
|
CMD curl -f http://localhost:8080/health || exit 1
|
|
|
|
# Set Python path
|
|
ENV PYTHONPATH=/app/src
|
|
|
|
# Run the application
|
|
CMD ["uvicorn", "wled_controller.main:app", "--host", "0.0.0.0", "--port", "8080"]
|