Add Debian package and Gitea APT repository support
debian/control, postinst, prerm, postrm — standard dpkg package lifecycle debian/files/opt/dupfinder/dupfinder-setup.sh — interactive setup: checks Docker, detects NVIDIA GPU, prompts for photos/data paths, writes docker-compose.override.yml with GPU reservation if present, pulls image from registry (builds from source as fallback) debian/files/usr/local/bin/dupfinder — CLI wrapper: setup / start / stop / restart / status / logs / open / update debian/files/etc/systemd/system/dupfinder.service — systemd unit, guards against starting before setup has run debian/build-deb.sh — builds .deb and uploads to Gitea package registry; prints the exact apt sources.list line on success Install on any Debian/Ubuntu machine: echo "deb [trusted=yes] http://192.168.1.64:3000/api/packages/tocmo0nlord/debian bookworm main" \ | sudo tee /etc/apt/sources.list.d/dupfinder.list sudo apt update && sudo apt install dupfinder sudo dupfinder setup Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
167
debian/files/opt/dupfinder/dupfinder-setup.sh
vendored
Normal file
167
debian/files/opt/dupfinder/dupfinder-setup.sh
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
#!/bin/bash
|
||||
# DupFinder first-time setup — configure paths, pull image, write override
|
||||
set -e
|
||||
|
||||
CONF_FILE="/etc/dupfinder.conf"
|
||||
COMPOSE_DIR="/opt/dupfinder"
|
||||
OVERRIDE_YML="$COMPOSE_DIR/docker-compose.override.yml"
|
||||
IMAGE_NAME="tocmo0nlord/dupfinder:latest"
|
||||
DATA_DIR="/var/lib/dupfinder/data"
|
||||
APP_PORT=8765
|
||||
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||||
info() { echo -e "${CYAN}==> $*${NC}"; }
|
||||
ok() { echo -e "${GREEN} OK $*${NC}"; }
|
||||
err() { echo -e "${RED} !! $*${NC}"; }
|
||||
|
||||
# ── Root check ────────────────────────────────────────────────────────────────
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
err "Please run as root: sudo dupfinder setup"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo " ╔══════════════════════════════════════╗"
|
||||
echo " ║ DupFinder Setup ║"
|
||||
echo " ╚══════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# ── Load existing config as defaults ─────────────────────────────────────────
|
||||
[[ -f "$CONF_FILE" ]] && source "$CONF_FILE"
|
||||
: "${PHOTOS_PATH:=/mnt/photos}"
|
||||
: "${DATA_PATH:=$DATA_DIR}"
|
||||
: "${APP_PORT:=8765}"
|
||||
|
||||
# ── Check Docker ──────────────────────────────────────────────────────────────
|
||||
info "Checking Docker..."
|
||||
if ! command -v docker &>/dev/null; then
|
||||
err "Docker is not installed."
|
||||
echo " Install with: curl -fsSL https://get.docker.com | sh"
|
||||
exit 1
|
||||
fi
|
||||
if ! docker info &>/dev/null; then
|
||||
err "Docker daemon is not running."
|
||||
echo " Start with: sudo systemctl start docker"
|
||||
exit 1
|
||||
fi
|
||||
ok "Docker is running"
|
||||
|
||||
# ── Check docker compose ──────────────────────────────────────────────────────
|
||||
if ! docker compose version &>/dev/null; then
|
||||
err "docker compose (V2 plugin) not found. Update Docker or install docker-compose-plugin."
|
||||
exit 1
|
||||
fi
|
||||
ok "docker compose V2 available"
|
||||
|
||||
# ── Check NVIDIA GPU ──────────────────────────────────────────────────────────
|
||||
info "Checking GPU..."
|
||||
if command -v nvidia-smi &>/dev/null && nvidia-smi &>/dev/null; then
|
||||
GPU_NAME=$(nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null | head -1)
|
||||
ok "NVIDIA GPU detected: $GPU_NAME"
|
||||
GPU_AVAILABLE=true
|
||||
else
|
||||
echo " No NVIDIA GPU detected — will use CPU for perceptual hashing"
|
||||
GPU_AVAILABLE=false
|
||||
fi
|
||||
|
||||
# ── Photos path ───────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
info "Photos library path (mounted read-only):"
|
||||
echo " Current: $PHOTOS_PATH"
|
||||
read -rp " Path [Enter to keep]: " INPUT
|
||||
INPUT="${INPUT%\"}" ; INPUT="${INPUT#\"}" # strip quotes
|
||||
[[ -n "$INPUT" ]] && PHOTOS_PATH="$INPUT"
|
||||
|
||||
if [[ ! -d "$PHOTOS_PATH" ]]; then
|
||||
err "Path not found: $PHOTOS_PATH"
|
||||
echo " Create it or mount your drive first, then re-run setup."
|
||||
exit 1
|
||||
fi
|
||||
ok "Photos: $PHOTOS_PATH"
|
||||
|
||||
# ── Data path ─────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
info "Database storage path:"
|
||||
echo " Current: $DATA_PATH"
|
||||
read -rp " Path [Enter to keep]: " INPUT
|
||||
INPUT="${INPUT%\"}" ; INPUT="${INPUT#\"}"
|
||||
[[ -n "$INPUT" ]] && DATA_PATH="$INPUT"
|
||||
mkdir -p "$DATA_PATH"
|
||||
ok "Data: $DATA_PATH"
|
||||
|
||||
# ── Port ──────────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
read -rp " Web port [$APP_PORT]: " INPUT
|
||||
[[ -n "$INPUT" ]] && APP_PORT="$INPUT"
|
||||
ok "Port: $APP_PORT"
|
||||
|
||||
# ── Pull Docker image ─────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
info "Pulling Docker image ($IMAGE_NAME)..."
|
||||
if docker pull "$IMAGE_NAME"; then
|
||||
ok "Image pulled"
|
||||
else
|
||||
echo ""
|
||||
echo " Could not pull from registry. Trying to build from source..."
|
||||
if [[ -f "$COMPOSE_DIR/source/Dockerfile" ]]; then
|
||||
docker build -t "$IMAGE_NAME" "$COMPOSE_DIR/source"
|
||||
ok "Image built from source"
|
||||
else
|
||||
err "Neither pull nor local build succeeded."
|
||||
echo " Make sure you have internet access or the source files are present."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Write config + override ───────────────────────────────────────────────────
|
||||
info "Writing configuration..."
|
||||
|
||||
cat > "$CONF_FILE" <<EOF
|
||||
PHOTOS_PATH=$PHOTOS_PATH
|
||||
DATA_PATH=$DATA_PATH
|
||||
APP_PORT=$APP_PORT
|
||||
GPU_AVAILABLE=$GPU_AVAILABLE
|
||||
EOF
|
||||
chmod 600 "$CONF_FILE"
|
||||
|
||||
# Docker requires forward slashes
|
||||
PHOTOS_DOCKER="${PHOTOS_PATH//\\//}"
|
||||
DATA_DOCKER="${DATA_PATH//\\//}"
|
||||
|
||||
cat > "$OVERRIDE_YML" <<EOF
|
||||
services:
|
||||
dup-finder:
|
||||
image: $IMAGE_NAME
|
||||
ports:
|
||||
- "${APP_PORT}:8000"
|
||||
volumes:
|
||||
- "$PHOTOS_DOCKER:/photos:ro"
|
||||
- "$DATA_DOCKER:/data"
|
||||
EOF
|
||||
|
||||
# Add GPU reservation if available
|
||||
if [[ "$GPU_AVAILABLE" == "true" ]]; then
|
||||
cat >> "$OVERRIDE_YML" <<EOF
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: 1
|
||||
capabilities: [gpu]
|
||||
EOF
|
||||
fi
|
||||
ok "Config saved to $CONF_FILE"
|
||||
|
||||
# ── Start service ─────────────────────────────────────────────────────────────
|
||||
info "Starting DupFinder..."
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now dupfinder.service
|
||||
ok "Service started"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN} ╔══════════════════════════════════════════╗${NC}"
|
||||
echo -e "${GREEN} ║ DupFinder is running! ║${NC}"
|
||||
echo -e "${GREEN} ║ Open: http://localhost:$APP_PORT ║${NC}"
|
||||
echo -e "${GREEN} ╚══════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user