From abe1100efadd7bffe6e320416ec4faa4d22f7085 Mon Sep 17 00:00:00 2001 From: "MEGASOL\\simon.adams" Date: Tue, 26 Aug 2025 14:40:36 +0200 Subject: [PATCH] update license and README.md --- README.md | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 170 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index b675471..2ce7e70 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,175 @@ -# Immich Drop Uploader – Clean Split (FastAPI + Static Frontend) +# Immich Drop Uploader -- **backend/** FastAPI server (upload proxy, WebSocket progress, runtime config API) -- **frontend/** Static HTML/JS (drag & drop, queue, ephemeral banner, settings modal) +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 SHA‑1 cache + optional Immich bulk‑check) +- **Original dates preserved** (EXIF → `fileCreatedAt` / `fileModifiedAt`) +- **Mobile‑friendly** +- **.env‑only config** (clean deploys) + Docker/Compose +- **Privacy‑first**: never lists server media; UI only shows the current session + +--- + +## Table of contents +- [Architecture](#architecture) +- [Folder structure](#folder-structure) +- [Requirements](#requirements) +- [Quick start (local)](#quick-start-local) +- [Quick start (Docker/Compose)](#quick-start-dockercompose) +- [Configuration (.env)](#configuration-env) +- [How it works](#how-it-works) +- [Endpoints](#endpoints) +- [Mobile notes](#mobile-notes) +- [Troubleshooting](#troubleshooting) +- [Security notes](#security-notes) +- [Development](#development) +- [License](#license) + +--- + +## 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 SHA‑1 and checks a local SQLite cache (`state.db`) + - Optional Immich de‑dupe via `/assets/bulk-upload-check` + - WebSocket `/ws` pushes per‑item progress to the current browser session only +- **Persistence:** local SQLite (`state.db`) prevents re‑uploads 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 checked‑in `/.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: -## Run ```bash -cd backend -python3 -m venv .venv -source .venv/bin/activate -pip install -r requirements.txt -cp .env.example .env # edit base URL, API key, CONFIG_TOKEN (optional) -uvicorn backend.main:app --reload --host 0.0.0.0 --port 8080 +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 client‑side ID. +2. **De‑dupe (local)** – Server computes **SHA‑1** and checks `state.db`. If seen, marks as **duplicate**. +3. **De‑dupe (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 session’s items. It never lists server media. + +--- + + +## Mobile notes + +- Uses a **label‑wrapped input** + short **ghost‑click suppression** so the system picker does **not** re‑open after tapping **Done** (fixes iOS/Android quirks). +- Drag‑and‑drop is desktop‑oriented; on touch, use **Choose files**. + +--- + +## Troubleshooting + +**Uploads don’t start on phones / picker re‑opens** +– Hard‑refresh; 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://:2283/api`). + +**Duplicate detected but you expect an upload** +– The proxy caches SHA‑1 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 **server‑side**; 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.