Go to file
2025-08-26 14:40:51 +02:00
.
2025-08-26 13:50:28 +02:00
.
2025-08-26 13:50:28 +02:00
2025-08-26 14:16:02 +02:00
2025-08-26 14:13:13 +02:00
.
2025-08-26 13:50:28 +02:00
.
2025-08-26 13:50:28 +02:00
2025-08-26 14:39:17 +02:00
.
2025-08-26 13:50:28 +02:00
2025-08-26 14:40:36 +02:00
.
2025-08-26 13:50:28 +02:00

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


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)

# 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:
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:

python main.py

The backend contains docstrings so you can generate docs later if desired.


License

MIT.

Description
No description provided
Readme MIT 1.7 MiB
Languages
Python 48%
HTML 36.7%
JavaScript 14.9%
Dockerfile 0.4%