diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..94e5db0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +# Files/directories to exclude from Docker build context +venv +node_modules +__pycache__ +*.db +*.db.bak +image_selections.db* +.git diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a8cddf5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +# Dockerfile for SWIPER image-swipe application +# ------------------------------------------------ +# This image runs the built-in Python HTTP server provided by server.py. +# Pillow needs system libs so we install them via apt. + +FROM python:3.11-slim + +# Install system packages required by Pillow (JPEG, zlib) +RUN apt-get update \ + && apt-get install -y --no-install-recommends build-essential libjpeg-dev zlib1g-dev \ + && rm -rf /var/lib/apt/lists/* + +# Set work directory +WORKDIR /app + +# Install Python dependencies first (leverages Docker layer caching) +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +# Copy application source +COPY . . + +# Expose the default port +EXPOSE 8888 + +# Start the server +CMD ["python", "server.py"] diff --git a/README.md b/README.md index c810df7..e7b7f6f 100644 --- a/README.md +++ b/README.md @@ -56,3 +56,36 @@ This will reset and recalculate all `nsfw` flags so that the new filters work co - Python 3.x - Standard Python libraries (http.server, sqlite3, etc.) - Web browser with JavaScript enabled + +## Docker + +If you have Docker installed you can build and run the application in an isolated container: + +```bash +# Build image (only once) +docker build -t swiper-app . + +# Run the container on port 8888 +docker run --rm -p 8888:8888 swiper-app +``` + +Then open [http://localhost:8888](http://localhost:8888) in your browser. + +The Dockerfile uses a minimal Python 3.11 image, installs the Python dependencies from `requirements.txt`, exposes port 8888 and starts the app with `python server.py`. + +### Docker Compose + +A `docker-compose.yml` file is included so you can run the container with your image folders mounted automatically. + +```bash +# Build image (first time or when code changes) +docker compose up --build +``` + +This will: + +- Publish port **8888** on your host → container. +- Mount the portrait and landscape image folders (update paths in `docker-compose.yml` as needed) read-only into `/media/Portrait` and `/media/Landscape` inside the container. +- Set `IMAGE_DIRS=/media/Portrait:/media/Landscape` so the server finds the images. + +Adjust ports, folders or environment variables by editing `docker-compose.yml`. Remember to rebuild (`docker compose up --build`) after changes. diff --git a/config.py b/config.py index 50eb60e..64d0bfc 100644 --- a/config.py +++ b/config.py @@ -8,22 +8,31 @@ import os # Base directory of the repo (this file lives in the project root) BASE_DIR = os.path.dirname(os.path.abspath(__file__)) -# Paths to the folders that contain source images. Add as many as you like. -IMAGE_DIRS = [ - "/mnt/secret-items/sd-outputs/Sorted/Images/Portrait", - "/mnt/secret-items/sd-outputs/Sorted/Images/Landscape", +# Paths to the folders that contain source images. Can be overridden at runtime +# via the IMAGE_DIRS environment variable (colon-separated paths). +_IMAGE_DIRS_DEFAULT = [ + "/media/Portrait", + "/media/Landscape", ] -# Backwards-compatibility: first directory -IMAGE_DIR = IMAGE_DIRS[0] +_IMAGE_DIRS_ENV = os.getenv("IMAGE_DIRS") +if _IMAGE_DIRS_ENV: + IMAGE_DIRS = _IMAGE_DIRS_ENV.split(":") +else: + IMAGE_DIRS = _IMAGE_DIRS_DEFAULT +# Backwards-compatibility: first directory +IMAGE_DIR = IMAGE_DIRS[0] if IMAGE_DIRS else "" from typing import Optional -# SQLite database file that stores selections & metadata -DB_PATH = os.path.join(BASE_DIR, "image_selections.db") +# Data directory (override with DATA_DIR env var) +DATA_DIR = os.getenv("DATA_DIR", BASE_DIR) -# Default port for the HTTP server -PORT = 8000 +# SQLite database file that stores selections & metadata +DB_PATH = os.path.join(DATA_DIR, "image_selections.db") + +# Default port for the HTTP server (override with PORT env var) +PORT = int(os.getenv("PORT", 8888)) # --------------------------------------------------------------------------- # NSFW detection configuration diff --git a/database.py b/database.py index c9e2484..a6661d6 100644 --- a/database.py +++ b/database.py @@ -356,7 +356,9 @@ def sync_image_database() -> None: # Now, parse and store prompt details for the new images for row in rows: - rel_path, _, _, _, _, _, prompt = row + # row structure: (path, w, h, name, orientation, ts, prompt, nsfw_flag) + rel_path = row[0] + prompt = row[6] if prompt: parse_and_store_prompt_details(rel_path, prompt) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4da4440 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,33 @@ +services: + swiper: + build: . + container_name: swiper + # --- Environment overrides ------------------------------------------------ + # Set the port and the internal image directories list. The example below + # assumes two folders mounted at /media/Portrait and /media/Landscape inside + # the container. Adjust IMAGE_DIRS (colon-separated) and the volume mounts + # to reflect your own paths. + environment: + - PORT=8888 + - IMAGE_DIRS=/media/Portrait:/media/Landscape + # Directory inside the container where the SQLite DB will live + - DATA_DIR=/data + # ------------------------------------------------------------------------- + + # Map host port -> container port + ports: + - "8888:8888" + + # ------------------------------------------------------------------------- + # Volumes + # • Mount the host image folders into /media/ inside the container + # • Optionally mount a customised config.py to override defaults at build + # ------------------------------------------------------------------------- + volumes: + - /mnt/secret-items/sd-outputs/Sorted/Images/Portrait:/media/Portrait:ro + - /mnt/secret-items/sd-outputs/Sorted/Images/Landscape:/media/Landscape:ro + # Host data directory → container /data (holds image_selections.db) + - ./data:/data + # Uncomment the line below if you maintain a custom config.py alongside + # the compose file and want to override the image copy at runtime. + - ./config.py:/app/config.py:ro diff --git a/image_selections.db.bak b/image_selections.db.bak deleted file mode 100644 index 800af52..0000000 Binary files a/image_selections.db.bak and /dev/null differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..d16a110 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +# Python dependencies for SWIPER +tqdm==4.66.4 +Pillow==10.3.0