Files
image-drop/README.md
MEGASOL\simon.adams 0d0d9fbb9f added quick start
2025-08-26 15:28:21 +02:00

228 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Immich Drop Uploader
A tiny, zero-login web app for collecting photos/videos into your **Immich** server.
- **No accounts** — open the page, drop files, done
- **Queue with progress** via WebSocket (success / duplicate / error)
- **Duplicate prevention** (local SHA1 cache + optional Immich bulkcheck)
- **Original dates preserved** (EXIF → `fileCreatedAt` / `fileModifiedAt`)
- **Mobilefriendly**
- **.envonly config** (clean deploys) + Docker/Compose
- **Privacyfirst**: never lists server media; UI only shows the current session
---
## Table of contents
- [Quick start](#Quick_start)
- [Architecture](#architecture)
- [Folder structure](#folder-structure)
- [Requirements](#requirements)
- [Configuration (.env)](#configuration-env)
- [Quick start (Docker/Compose)](#quick-start-dockercompose)
- [How it works](#how-it-works)
- [Mobile notes](#mobile-notes)
- [Troubleshooting](#troubleshooting)
- [Security notes](#security-notes)
- [Development](#development)
- [License](#license)
---
## Quick start
Copy the docker-compose.yml and the .env file to a common folder,
update the .env file before executing the CLI commands to quick start the container.
### docker-compose.yml
```
version: "3.9"
services:
immich-drop:
image: ghcr.io/nasogaa/immich-drop:latest
pull_policy: always
container_name: immich-drop
restart: unless-stopped
# Load all variables from your repo's .env (PORT, IMMICH_BASE_URL, IMMICH_API_KEY, etc.)
env_file:
- ./.env
# Expose the app on the same port as configured in .env (defaults to 8080)
ports:
- 8080:8080
# Persist local dedupe cache (state.db) across restarts
volumes:
- immich_drop_data:/data
# Simple healthcheck
healthcheck:
test: ["CMD-SHELL", "python - <<'PY'\nimport os,urllib.request,sys; url=f\"http://127.0.0.1:{os.getenv('PORT','8080')}/\";\ntry: urllib.request.urlopen(url, timeout=3); sys.exit(0)\nexcept Exception: sys.exit(1)\nPY"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
volumes:
immich_drop_data:
```
### .env
```
HOST=0.0.0.0
PORT=8080
IMMICH_BASE_URL=http://REPLACE_ME:2283/api
IMMICH_API_KEY=REPLACE_ME
MAX_CONCURRENT=3
STATE_DB=/data/state.db
```
### CLI
```
docker compose pull
docker compose up -d
```
---
## Architecture
- **Frontend:** static HTML/JS (Tailwind). Drag & drop or “Choose files”, queue UI with progress and status chips.
- **Backend:** FastAPI + Uvicorn.
- Proxies uploads to Immich `/assets`
- Computes SHA1 and checks a local SQLite cache (`state.db`)
- Optional Immich dedupe via `/assets/bulk-upload-check`
- WebSocket `/ws` pushes peritem progress to the current browser session only
- **Persistence:** local SQLite (`state.db`) prevents reuploads across sessions/runs.
---
## Folder structure
```
immich_drop/
├─ app/ # FastAPI application (Python package)
│ ├─ __init__.py
│ ├─ app.py # uvicorn app:app
│ └─ config.py # loads .env from repo root
├─ frontend/ # static UI served at /static
│ ├─ index.html
│ └─ app.js
├─ main.py # thin entrypoint (python main.py)
├─ requirements.txt # Python deps
├─ .env # single config file (see below)
├─ Dockerfile
├─ docker-compose.yml
└─ README.md
```
---
## Requirements
- **Python** 3.11
- An **Immich** server + **API key**
---
## Configuration (.env)
```ini
# Server
HOST=0.0.0.0
PORT=8080
# Immich connection (include /api)
IMMICH_BASE_URL=http://REPLACE_ME:2283/api
IMMICH_API_KEY=REPLACE_ME
MAX_CONCURRENT=3
# Local dedupe cache
STATE_DB=./data/state.db # local dev -> ./state.db (data folder is created in docker image)
# In Docker this is overridden to /data/state.db by docker-compose.yml
```
You can keep a checkedin `/.env.example` with the keys above for onboarding.
---
## Quick start (Docker/Compose)
1) Put your settings in **.env** at the repo root (see below).
2) Build & run:
```bash
docker compose build
docker compose up -d
# open http://localhost:8080
```
A named volume stores `/data/state.db` so duplicates are remembered across container restarts.
---
## How it works
1. **Queue** Files selected in the browser are queued; each gets a clientside ID.
2. **Dedupe (local)** Server computes **SHA1** and checks `state.db`. If seen, marks as **duplicate**.
3. **Dedupe (server)** Attempts Immich `/assets/bulk-upload-check`; if Immich reports duplicate, marks accordingly.
4. **Upload** Multipart POST to `${IMMICH_BASE_URL}/assets` with:
- `assetData`, `deviceAssetId`, `deviceId`,
- `fileCreatedAt`, `fileModifiedAt` (from EXIF when available; else `lastModified`),
- `isFavorite=false`, `filename`, and header `x-immich-checksum`.
5. **Progress** Backend streams progress via WebSocket to the same session.
6. **Privacy** UI shows only the current sessions items. It never lists server media.
---
## Mobile notes
- Uses a **labelwrapped input** + short **ghostclick suppression** so the system picker does **not** reopen after tapping **Done** (fixes iOS/Android quirks).
- Draganddrop is desktoporiented; on touch, use **Choose files**.
---
## Troubleshooting
**Uploads dont start on phones / picker reopens**
Hardrefresh; current UI suppresses ghost clicks and resets the input.
If using a PWA/WebView, test in Safari/Chrome directly to rule out container quirks.
**WebSocket connects/disconnects in a loop**
Match schemes: `ws://` for `http://`, `wss://` for `https://`.
If behind a reverse proxy, ensure it forwards WebSockets.
**413 Request Entity Too Large**
If running behind nginx/Traefik/etc., bump body size limits (`client_max_body_size` for nginx).
**/assets returns 401**
Check `IMMICH_API_KEY` and ensure the base URL includes `/api` (e.g., `http://<host>:2283/api`).
**Duplicate detected but you expect an upload**
The proxy caches SHA1 in `state.db`. For a fresh run, delete that DB or point `STATE_DB` to a new file.
---
## Security notes
- The app is **unauthenticated** by design. Share the URL only with trusted people or keep it on a private network/VPN.
- The Immich API key remains **serverside**; the browser never sees it.
- No browsing of uploaded media; only ephemeral session state is shown.
---
## Development
Run with live reload:
```bash
python main.py
```
The backend contains docstrings so you can generate docs later if desired.
---
## License
MIT.