#cloud-config

# Set hostname
hostname: photoprism-pi
fqdn: photoprism-pi.local

# Update and upgrade packages
package_update: true
package_upgrade: true

# Install required packages
packages:
  - apt-transport-https
  - ca-certificates
  - curl
  - gnupg
  - lsb-release
  - git
  - openssl
  - avahi-daemon

# Install Docker Engine (latest version)
runcmd:
  # Print welcome message
  - printf "\e[0s;35m[SETUP] Starting PhotoPrism installation on Raspberry Pi...\e[0m\n"
  
  # Uninstall old versions if they exist
  - printf "\e[0;35m[SETUP] Removing old Docker versions if present...\e[0m\n"
  - for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do apt-get remove -y $pkg || true; done
  - printf "\e[0;35m[SETUP] ✓ Old Docker versions removed or not present\e[0m\n"

  # Add Docker's official GPG key
  - printf "\e[0;35m[SETUP] Adding Docker repository GPG key...\e[0m\n"
  - apt-get update
  - apt-get install -y ca-certificates curl
  - install -m 0755 -d /etc/apt/keyrings
  - curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
  - chmod a+r /etc/apt/keyrings/docker.asc
  - printf "\e[0;35m[SETUP] ✓ Docker GPG key added\e[0m\n"

  # Add Docker repository
  - printf "\e[0;35m[SETUP] Adding Docker repository...\e[0m\n"
  - echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
  - apt-get update
  - printf "\e[0;35m[SETUP] ✓ Docker repository added\e[0m\n"

  # Install Docker Engine
  - printf "\e[0;35m[SETUP] Installing Docker Engine...\e[0m\n"
  - apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  - printf "\e[0;35m[SETUP] ✓ Docker Engine installed\e[0m\n"

  # Create directories for PhotoPrism and Traefik
  - printf "\e[0;35m[SETUP] Creating directory structure for PhotoPrism...\e[0m\n"
  - mkdir -p /opt/photoprism/photos
  - mkdir -p /opt/photoprism/storage
  - mkdir -p /opt/photoprism/database
  - mkdir -p /opt/photoprism/import
  - mkdir -p /opt/photoprism/originals
  - mkdir -p /opt/photoprism/traefik/certs
  - mkdir -p /opt/photoprism/traefik/conf.d
  - mkdir -p /etc/traefik
  - chown -R 1000:1000 /opt/photoprism
  - chmod -R 755 /opt/photoprism
  - chmod -R ug+rwX,o-rwx /opt/photoprism/storage
  - chmod -R ug+rwX,o-rwx /opt/photoprism/database
  - chmod -R ug+rwX,o-rwx /opt/photoprism/import
  - chmod -R ug+rwX,o-rwx /opt/photoprism/originals
  - chmod -R ug+rwX,o-rwx /opt/photoprism/photos
  - printf "\e[0;35m[SETUP] ✓ PhotoPrism directory structure created\e[0m\n"

  
  # Create mount points for external drives
  - printf "\e[0;35m[SETUP] Creating mount points for external drives...\e[0m\n"
  - mkdir -p /mnt/a
  - mkdir -p /mnt/b
  - mkdir -p /mnt/c
  - mkdir -p /mnt/d
  - chown -R 1000:1000 /mnt
  - printf "\e[0;35m[SETUP] ✓ External drive mount points created\e[0m\n"
  
  # Configure external drives in fstab
  - printf "\e[0;35m[SETUP] Configuring external drives in fstab...\e[0m\n"
  - |
    cat >> /etc/fstab << 'EOF'
    /dev/sda1  /mnt/a  auto  nofail,noatime,noauto,x-systemd.automount,x-systemd.device-timeout=10s,uid=1000,gid=1000  0  0
    /dev/sdb1  /mnt/b  auto  nofail,noatime,noauto,x-systemd.automount,x-systemd.device-timeout=10s,uid=1000,gid=1000  0  0
    /dev/sdc1  /mnt/c  auto  nofail,noatime,noauto,x-systemd.automount,x-systemd.device-timeout=10s,uid=1000,gid=1000  0  0
    /dev/sdd1  /mnt/d  auto  nofail,noatime,noauto,x-systemd.automount,x-systemd.device-timeout=10s,uid=1000,gid=1000  0  0
    EOF
  - printf "\e[0;35m[SETUP] ✓ External drives configured in fstab\e[0m\n"
  
  # Set up swap
  - printf "\e[0;35m[SETUP] Setting up swap space...\e[0m\n"
  - |
    cat > /usr/local/bin/swapon.sh << 'EOF'
    #!/usr/bin/env bash
    
    # add 8 GB of swap if no swap was configured yet
    if [[ -z $(swapon --show) ]]; then
      fallocate -l 8G /swapfile
      chmod 600 /swapfile
      mkswap /swapfile
      swapon /swapfile
      swapon --show
      free -h
      echo '/swapfile none swap sw 0 0' | tee -a /etc/fstab
    fi
    EOF
  - chmod +x /usr/local/bin/swapon.sh
  - /usr/local/bin/swapon.sh
  - printf "\e[0;35m[SETUP] ✓ Swap space configured\e[0m\n"
  
  # Verify the installation is successful
  - printf "\e[0;35m[SETUP] Verifying Docker installation...\e[0m\n"
  - docker run --rm hello-world
  - printf "\e[0;35m[SETUP] ✓ Docker installation verified\e[0m\n"
  
  # Ensure docker group exists and pi user is added to it
  - printf "\e[0;35m[SETUP] Ensuring pi user is in docker group...\e[0m\n"
  - getent group docker || groupadd docker
  - usermod -aG docker pi
  - printf "\e[0;35m[SETUP] ✓ Pi user added to docker group\e[0m\n"
  
  # Enable services
  - printf "\e[0;35m[SETUP] Enabling required services...\e[0m\n"
  - systemctl enable docker
  - systemctl enable avahi-daemon
  - printf "\e[0;35m[SETUP] ✓ Services enabled\e[0m\n"
  
  # Add a service to start PhotoPrism on boot
  - printf "\e[0;35m[SETUP] Creating PhotoPrism service...\e[0m\n"
  - |
    cat > /etc/systemd/system/photoprism.service << 'EOF'
    [Unit]
    Description=PhotoPrism Service
    After=docker.service network-online.target
    Requires=docker.service network-online.target
    
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    WorkingDirectory=/opt/photoprism
    ExecStart=/usr/bin/docker compose up -d
    ExecStop=/usr/bin/docker compose down
    
    [Install]
    WantedBy=multi-user.target
    EOF
  - printf "\e[0;35m[SETUP] ✓ PhotoPrism service created\e[0m\n"
  
  # Enable PhotoPrism service
  - printf "\e[0;35m[SETUP] Enabling and starting PhotoPrism service...\e[0m\n"
  - systemctl enable photoprism.service
  - systemctl start photoprism.service
  - printf "\e[0;35m[SETUP] ✓ PhotoPrism service started\e[0m\n"
  
  # Configure Avahi for .local domain
  - printf "\e[0;35m[SETUP] Restarting and configuring Avahi for .local domain...\e[0m\n"
  - systemctl restart avahi-daemon
  - printf "\e[0;35m[SETUP] ✓ Avahi configured for .local domain\e[0m\n"
  
  # Update MOTD and issue file with actual IP address
  - printf "\e[0;35m[SETUP] Updating MOTD and console login message with actual IP address...\e[0m\n"
  - chmod +x /usr/local/bin/update-motd-ip.sh
  - /usr/local/bin/update-motd-ip.sh
  - PRIMARY_IFACE=$(ip route | grep default | awk '{print $5}')
  - IP=$(ip addr show $PRIMARY_IFACE 2>/dev/null | grep -oP 'inet \K[\d.]+' || hostname -I | awk '{print $1}')
  - |
    cat > /etc/issue << EOF
    
                                                                   
      Welcome to PhotoPrism Pi!                                    
                                                                   
      You should soon be able to access the web interface
      by navigating to one of the following URLs:

      http://$IP:2342/                                             
      https://photoprism-pi.local/                                 
                                                                   
      For further information and help with troubleshooting:       
      https://docs.photoprism.app/photoprism-pi/                   
      https://docs.photoprism.app/getting-started/troubleshooting/ 
                                                                   
    EOF
  - printf "\e[0;35m[SETUP] ✓ MOTD and console login message updated with actual IP\e[0m\n"
  

  
# Write configuration files
write_files:
  - path: /usr/local/bin/update-motd-ip.sh
    permissions: '0755'
    content: |
      #!/bin/bash
      IP=$(hostname -I | awk '{print $1}')
      sed -i "s|http://<your IP address>:2342/|http://$IP:2342/|g" /etc/motd
      
  - path: /etc/motd
    permissions: '0644'
    content: |
      
      Welcome to PhotoPrism Pi!                                   
      
      You should soon be able to access the web interface
      by navigating to one of the following URLs:
                                             
      http://<IP address>:2342/                                       
      https://photoprism-pi.local/                                 
      
      Your initial password for the "admin" account is             
      "photoprismpi". Please change it after logging in for the    
      first time, especially if your device is connected to the    
      Internet or a shared network.                                
      
      For further information and help with troubleshooting:       
      https://docs.photoprism.app/photoprism-pi/                   
      https://docs.photoprism.app/getting-started/troubleshooting/ 
      
  - path: /opt/photoprism/compose.yaml
    permissions: '0644'
    content: |
      name: photoprism

      services:
        photoprism:
          image: photoprism/photoprism:latest
          depends_on:
            - mariadb
          restart: always
          security_opt:
            - seccomp=unconfined
            - apparmor=unconfined
          user: "1000:1000"
          ports:
            - "2342:2342"
          labels:
            - "traefik.enable=true"
            - "traefik.http.routers.photoprism.rule=Host(`photoprism-pi.local`)"
            - "traefik.http.routers.photoprism.entrypoints=websecure"
            - "traefik.http.routers.photoprism.tls=true"
            - "traefik.http.services.photoprism.loadbalancer.server.port=2342"
            - "traefik.docker.network=photoprism"
          environment:
            PHOTOPRISM_ADMIN_PASSWORD: "photoprismpi"
            PHOTOPRISM_AUTH_MODE: "passwd"
            PHOTOPRISM_SITE_URL: "https://photoprism-pi.local/"
            PHOTOPRISM_SITE_CAPTION: "AI-Powered Photos App"
            PHOTOPRISM_HTTP_COMPRESSION: "gzip"
            PHOTOPRISM_WORKERS: 3
            PHOTOPRISM_LOG_LEVEL: "info"
            PHOTOPRISM_TRACE: "false"
            PHOTOPRISM_READONLY: "false"
            PHOTOPRISM_EXPERIMENTAL: "false"
            PHOTOPRISM_DISABLE_CHOWN: "false"
            PHOTOPRISM_DISABLE_WEBDAV: "false"
            PHOTOPRISM_DISABLE_SETTINGS: "false"
            PHOTOPRISM_DISABLE_TENSORFLOW: "false"
            PHOTOPRISM_DISABLE_FACES: "false"
            PHOTOPRISM_DISABLE_CLASSIFICATION: "false"
            PHOTOPRISM_DISABLE_RAW: "false"
            PHOTOPRISM_RAW_PRESETS: "false"
            PHOTOPRISM_JPEG_QUALITY: 82
            PHOTOPRISM_FFMPEG_SIZE: 1920
            PHOTOPRISM_AUTO_INDEX: 300                     # delay before automatically indexing files in SECONDS when uploading via WebDAV (-1 to disable)
            PHOTOPRISM_AUTO_IMPORT: -1                     # delay before automatically importing files in SECONDS when uploading via WebDAV (-1 to disable)
            PHOTOPRISM_DETECT_NSFW: "false"                # automatically flags photos as private that MAY be offensive (requires TensorFlow)
            PHOTOPRISM_UPLOAD_NSFW: "true"                 # allow uploads that MAY be offensive
            PHOTOPRISM_UPLOAD_ALLOW: ""                    # restricts uploads to these file types (comma-separated list of EXTENSIONS; leave blank to allow all)
            PHOTOPRISM_UPLOAD_ARCHIVES: "true"             # allows upload of zip archives (will be extracted before import)
            PHOTOPRISM_UPLOAD_LIMIT: 5000                  # maximum size of uploaded files and uncompressed archive contents in MB
            PHOTOPRISM_ORIGINALS_LIMIT: 5000               # maximum size of original media files in MB (larger files are skipped)
            PHOTOPRISM_RESOLUTION_LIMIT: 300               # maximum resolution of original media files in Pixels (larger files are skipped)
            PHOTOPRISM_SIDECAR_YAML: "false"               # creates YAML sidecar files to back up picture metadata
            PHOTOPRISM_INDEX_SCHEDULE: ""                  # indexing SCHEDULE in cron format (e.g. "@every 3h" for every 3 hours; "" to disable)
            PHOTOPRISM_BACKUP_ALBUMS: "true"               # creates YAML files to back up album metadata
            PHOTOPRISM_BACKUP_DATABASE: "true"             # creates regular backups based on the configured schedule
            PHOTOPRISM_BACKUP_SCHEDULE: "daily"            # backup SCHEDULE in cron format (e.g. "0 12 * * *" for daily at noon) or at a random time (daily, weekly)
            PHOTOPRISM_DATABASE_DRIVER: "mysql"
            PHOTOPRISM_DATABASE_SERVER: "mariadb:3306"
            PHOTOPRISM_DATABASE_NAME: "photoprism"
            PHOTOPRISM_DATABASE_USER: "photoprism"
            PHOTOPRISM_DATABASE_PASSWORD: "insecure"
            PHOTOPRISM_INIT: "yt-dlp"
          working_dir: "/photoprism"
          volumes:
            - "/opt/photoprism/storage:/photoprism/storage"
            - "/opt/photoprism/originals:/photoprism/originals"
            - "/mnt:/photoprism/originals/mnt:slave"
            - "/opt/photoprism/import:/photoprism/import"

        mariadb:
          restart: always
          image: mariadb:11
          security_opt:
            - seccomp=unconfined
            - apparmor=unconfined
          command: --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120
          volumes:
            - "/opt/photoprism/database:/var/lib/mysql"
          environment:
            MARIADB_AUTO_UPGRADE: "1"
            MARIADB_INITDB_SKIP_TZINFO: "1"
            MARIADB_DATABASE: "photoprism"
            MARIADB_USER: "photoprism"
            MARIADB_PASSWORD: "insecure"
            MARIADB_ROOT_PASSWORD: "insecure"

        traefik:
          restart: always
          image: traefik:v3.6
          ports:
            - "80:80"
            - "443:443"
          volumes:
            - "/var/run/docker.sock:/var/run/docker.sock:ro"
            - "/opt/photoprism/traefik:/etc/traefik:rw"
          labels:
            - "traefik.enable=true"
          command:
            - "--api.insecure=false"
            - "--providers.docker=true"
            - "--providers.docker.exposedbydefault=false"
            - "--entrypoints.web.address=:80"
            - "--entrypoints.websecure.address=:443"
            - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
            - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
            - "--providers.docker.network=photoprism"
            - "--providers.docker.defaultRule=Host(`{{ normalize .Name }}.local`)"
            - "--log.level=DEBUG"

        watchtower:
          restart: always
          image: nickfedor/watchtower
          environment:
            WATCHTOWER_CLEANUP: "true"
            WATCHTOWER_POLL_INTERVAL: 7200
          volumes:
            - "/var/run/docker.sock:/var/run/docker.sock"

      networks:
        default:
          name: photoprism
          driver: bridge

  - path: /etc/avahi/avahi-daemon.conf
    permissions: '0644'
    content: |
      [server]
      #host-name=foo
      #domain-name=local
      #browse-domains=0pointer.de, zeroconf.org
      use-ipv4=yes
      use-ipv6=no
      allow-interfaces=eth0
      #deny-interfaces=eth1
      #check-response-ttl=no
      #use-iff-running=no
      #enable-dbus=yes
      #disallow-other-stacks=no
      #allow-point-to-point=no
      #cache-entries-max=4096
      #clients-max=4096
      #objects-per-client-max=1024
      #entries-per-entry-group-max=32
      ratelimit-interval-usec=1000000
      ratelimit-burst=1000

      [wide-area]
      enable-wide-area=yes

      [publish]
      #disable-publishing=no
      #disable-user-service-publishing=no
      #add-service-cookie=no
      #publish-addresses=yes
      publish-hinfo=no
      publish-workstation=no
      #publish-domain=yes
      #publish-dns-servers=192.168.50.1, 192.168.50.2
      #publish-resolv-conf-dns-servers=yes
      #publish-aaaa-on-ipv4=yes
      #publish-a-on-ipv6=no

      [reflector]
      #enable-reflector=no
      #reflect-ipv=no
      #reflect-filters=_airplay._tcp.local,_raop._tcp.local

      [rlimits]
      #rlimit-as=
      #rlimit-core=0
      #rlimit-data=8388608
      #rlimit-fsize=0
      #rlimit-nofile=768
      #rlimit-stack=8388608
      #rlimit-nproc=3

# Configure users
users:
  - name: pi
    gecos: PhotoPrism User
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: adm,dialout,cdrom,floppy,sudo,audio,dip,video,plugdev,netdev,docker
    shell: /bin/bash
    lock_passwd: false

# Set passwords
chpasswd:
  expire: false
  list: |
    pi:raspberry
    
# Automatically reboot after cloud-init completes
power_state:
  delay: "+1"
  mode: reboot
  message: "Rebooting system after cloud-init completes setup"
  timeout: 30
  condition: True
  
