updates to compose file .env file final one_time_linke release
This commit is contained in:
30
.env.example
30
.env.example
@@ -1,17 +1,25 @@
|
|||||||
# Backend host/port
|
# Server (dev only)
|
||||||
HOST=0.0.0.0
|
HOST=0.0.0.0
|
||||||
PORT=8080
|
PORT=8080
|
||||||
|
# Immich connection (include /api)
|
||||||
# Immich connection
|
IMMICH_BASE_URL=http://REPLACE_ME:2283/api
|
||||||
IMMICH_BASE_URL=http://127.0.0.1:2283/api
|
IMMICH_API_KEY=ADD-YOUR-API-KEY # needs: asset.upload; for albums also: album.create, album.read, albumAsset.create
|
||||||
IMMICH_API_KEY=ADD-YOUR-API-KEY #key needs asset.upload (default functions)
|
|
||||||
MAX_CONCURRENT=3
|
MAX_CONCURRENT=3
|
||||||
|
|
||||||
# Optional: Public upload page
|
# Public uploader page (optional) — disabled by default
|
||||||
PUBLIC_UPLOAD_PAGE_ENABLED=true
|
PUBLIC_UPLOAD_PAGE_ENABLED=TRUE
|
||||||
|
|
||||||
# Optional: Album name for public upload page
|
# Album (optional): auto-add uploads from public uploader to this album (creates if needed)
|
||||||
IMMICH_ALBUM_NAME=dead-drop #key needs album.create,album.read,albumAsset.create (extended functions)
|
IMMICH_ALBUM_NAME=dead-drop
|
||||||
|
|
||||||
|
# Local dedupe cache (SQLite)
|
||||||
|
STATE_DB=./data/state.db
|
||||||
|
|
||||||
|
# Base URL for generating absolute invite links (recommended for production)
|
||||||
|
# e.g., PUBLIC_BASE_URL=https://photos.example.com
|
||||||
|
#PUBLIC_BASE_URL=
|
||||||
|
|
||||||
|
# Session and security
|
||||||
|
SESSION_SECRET=SET-A-STRONG-RANDOM-VALUE
|
||||||
|
LOG_LEVEL=DEBUG
|
||||||
|
|
||||||
# Data path inside the container
|
|
||||||
STATE_DB=/data/state.db
|
|
||||||
|
|||||||
188
README.md
188
README.md
@@ -1,20 +1,24 @@
|
|||||||
# Immich Drop Uploader
|
# Immich Drop Uploader
|
||||||
|
|
||||||
A tiny, zero-login web app for collecting photos/videos into your **Immich** server.
|
A tiny web app for collecting photos/videos into your **Immich** server.
|
||||||
|
Admin users log in to create public invite links; invite links are always public-by-URL. A public uploader page is optional and disabled by default.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **No accounts** — open the page, drop files, done
|
- **Invite links (public)** — create upload links you can share with anyone
|
||||||
|
- **One‑time link claim** — first browser session claims a one‑time link; it can upload multiple files, others are blocked
|
||||||
|
- **Optional public uploader** — disabled by default; can be enabled via `.env`
|
||||||
- **Queue with progress** via WebSocket (success / duplicate / error)
|
- **Queue with progress** via WebSocket (success / duplicate / error)
|
||||||
- **Duplicate prevention** (local SHA‑1 cache + optional Immich bulk‑check)
|
- **Duplicate prevention** (local SHA‑1 cache + optional Immich bulk‑check)
|
||||||
- **Original dates preserved** (EXIF → `fileCreatedAt` / `fileModifiedAt`)
|
- **Original dates preserved** (EXIF → `fileCreatedAt` / `fileModifiedAt`)
|
||||||
- **Mobile‑friendly**
|
- **Mobile‑friendly**
|
||||||
- **.env‑only config** (clean deploys) + Docker/Compose
|
- **.env‑only config** (clean deploys) + Docker/Compose
|
||||||
- **Privacy‑first**: never lists server media; UI only shows the current session
|
- **Privacy‑first**: never lists server media; UI only shows the current session
|
||||||
- **Dark mode support** — automatically detects system preference, with manual toggle
|
- **Dark mode** — detects system preference; manual toggle persists across pages
|
||||||
- **Album integration** — auto-adds uploads to a configured album (creates if needed)
|
- **Albums** — add uploads to a configured album (creates if needed)
|
||||||
|
- **Copy + QR** — copy invite link and display QR for easy sharing
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -34,10 +38,10 @@ A tiny, zero-login web app for collecting photos/videos into your **Immich** ser
|
|||||||
|
|
||||||
---
|
---
|
||||||
## Quick start
|
## Quick start
|
||||||
Copy the docker-compose.yml and the .env file to a common folder,
|
You can run without a `.env` file by putting all settings in `docker-compose.yml` (recommended for deploys).
|
||||||
update the .env file before executing the CLI commands to quick start the container.
|
Use a `.env` file only for local development.
|
||||||
|
|
||||||
### docker-compose.yml
|
### docker-compose.yml (deploy without .env)
|
||||||
```yaml
|
```yaml
|
||||||
version: "3.9"
|
version: "3.9"
|
||||||
|
|
||||||
@@ -48,15 +52,25 @@ services:
|
|||||||
container_name: immich-drop
|
container_name: immich-drop
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
# Optional: Set album name for auto-adding uploads
|
# Configure all settings here (no .env required)
|
||||||
environment:
|
environment:
|
||||||
IMMICH_ALBUM_NAME: dead-drop # Optional: uploads will be added to this album
|
# Server (container port is 8080 by default)
|
||||||
|
HOST: 0.0.0.0
|
||||||
|
PORT: 8080
|
||||||
|
|
||||||
# Load all variables from your repo's .env (PORT, IMMICH_BASE_URL, IMMICH_API_KEY, etc.)
|
# Immich connection (must include /api)
|
||||||
env_file:
|
IMMICH_BASE_URL: https://immich.example.com/api
|
||||||
- ./.env
|
IMMICH_API_KEY: ${IMMICH_API_KEY}
|
||||||
|
|
||||||
# Expose the app on the same port as configured in .env (defaults to 8080)
|
# Optional behavior
|
||||||
|
IMMICH_ALBUM_NAME: dead-drop
|
||||||
|
PUBLIC_UPLOAD_PAGE_ENABLED: "false" # keep disabled by default
|
||||||
|
PUBLIC_BASE_URL: https://drop.example.com
|
||||||
|
|
||||||
|
# App internals
|
||||||
|
SESSION_SECRET: ${SESSION_SECRET}
|
||||||
|
|
||||||
|
# Expose the app on the host
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
|
|
||||||
@@ -76,18 +90,7 @@ volumes:
|
|||||||
immich_drop_data:
|
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
|
|
||||||
IMMICH_ALBUM_NAME=dead-drop # Optional: auto-add uploads to this album
|
|
||||||
STATE_DB=/data/state.db
|
|
||||||
```
|
|
||||||
|
|
||||||
### CLI
|
### CLI
|
||||||
```bash
|
```bash
|
||||||
docker compose pull
|
docker compose pull
|
||||||
@@ -97,6 +100,17 @@ docker compose up -d
|
|||||||
|
|
||||||
## New Features
|
## New Features
|
||||||
|
|
||||||
|
### 🔐 Login + Menu
|
||||||
|
- Login with your Immich credentials to access the menu.
|
||||||
|
- The menu lets you list/create albums and create invite links.
|
||||||
|
- The menu is always behind login; logout clears the session.
|
||||||
|
|
||||||
|
### 🔗 Invite Links
|
||||||
|
- Links are always public by URL (no login required to use).
|
||||||
|
- You can make links one‑time (claimed by the first browser session) or indefinite / limited uses.
|
||||||
|
- Set link expiry (e.g., 1, 2, 7 days). Expired links are inactive.
|
||||||
|
- Copy link and view a QR code for easy sharing.
|
||||||
|
|
||||||
### 🌙 Dark Mode
|
### 🌙 Dark Mode
|
||||||
- Automatically detects system dark/light preference on first visit
|
- Automatically detects system dark/light preference on first visit
|
||||||
- Manual toggle button in the header (sun/moon icon)
|
- Manual toggle button in the header (sun/moon icon)
|
||||||
@@ -133,19 +147,25 @@ docker compose up -d
|
|||||||
|
|
||||||
```
|
```
|
||||||
immich_drop/
|
immich_drop/
|
||||||
├─ app/ # FastAPI application (Python package)
|
├─ app/ # FastAPI application (Python package)
|
||||||
│ ├─ __init__.py
|
│ ├─ app.py # ASGI app (uvicorn entry: app.app:app)
|
||||||
│ ├─ app.py # uvicorn app:app
|
│ └─ config.py # Settings loader (reads .env/env)
|
||||||
│ └─ config.py # loads .env from repo root
|
├─ frontend/ # Static UI (served at /static)
|
||||||
├─ frontend/ # static UI served at /static
|
│ ├─ index.html # Public uploader (optional)
|
||||||
│ ├─ index.html
|
│ ├─ login.html # Login page (admin)
|
||||||
│ └─ app.js
|
│ ├─ menu.html # Admin menu (create invites)
|
||||||
├─ main.py # thin entrypoint (python main.py)
|
│ ├─ invite.html # Public invite upload page
|
||||||
├─ requirements.txt # Python deps
|
│ ├─ app.js # Uploader logic (drop/queue/upload/ws)
|
||||||
├─ .env # single config file (see below)
|
│ ├─ header.js # Shared header (theme + ping + banner)
|
||||||
|
│ └─ favicon.png # Tab icon (optional)
|
||||||
|
├─ data/ # Local dev data dir (bind to /data in Docker)
|
||||||
|
├─ main.py # Thin dev entrypoint (python main.py)
|
||||||
|
├─ requirements.txt # Python dependencies
|
||||||
├─ Dockerfile
|
├─ Dockerfile
|
||||||
├─ docker-compose.yml
|
├─ docker-compose.yml
|
||||||
└─ README.md
|
├─ .env.example # Example dev environment (optional)
|
||||||
|
├─ README.md
|
||||||
|
└─ screenshot.png # UI screenshot for README
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -156,25 +176,49 @@ immich_drop/
|
|||||||
- An **Immich** server + **API key**
|
- An **Immich** server + **API key**
|
||||||
|
|
||||||
---
|
---
|
||||||
## Configuration (.env)
|
# Local dev quickstart
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
Run with live reload:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
The backend contains docstrings so you can generate docs later if desired.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dev Configuration (.env)
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
# Server
|
# Server (dev only)
|
||||||
HOST=0.0.0.0
|
HOST=0.0.0.0
|
||||||
PORT=8080
|
PORT=8080
|
||||||
|
|
||||||
# Immich connection (include /api)
|
# Immich connection (include /api)
|
||||||
IMMICH_BASE_URL=http://REPLACE_ME:2283/api
|
IMMICH_BASE_URL=http://REPLACE_ME:2283/api
|
||||||
IMMICH_API_KEY=ADD-YOUR-API-KEY #key needs asset.upload (default functions)
|
IMMICH_API_KEY=ADD-YOUR-API-KEY # needs: asset.upload; for albums also: album.create, album.read, albumAsset.create
|
||||||
|
|
||||||
MAX_CONCURRENT=3
|
MAX_CONCURRENT=3
|
||||||
|
|
||||||
# Optional: Album name for auto-adding uploads (creates if doesn't exist)
|
# Public uploader page (optional) — disabled by default
|
||||||
IMMICH_ALBUM_NAME=dead-drop #key needs album.create,album.read,albumAsset.create (extended functions)
|
PUBLIC_UPLOAD_PAGE_ENABLED=TRUE
|
||||||
|
|
||||||
|
# Album (optional): auto-add uploads from public uploader to this album (creates if needed)
|
||||||
|
IMMICH_ALBUM_NAME=dead-drop
|
||||||
|
|
||||||
|
# Local dedupe cache (SQLite)
|
||||||
|
STATE_DB=./data/state.db
|
||||||
|
|
||||||
|
# Base URL for generating absolute invite links (recommended for production)
|
||||||
|
# e.g., PUBLIC_BASE_URL=https://photos.example.com
|
||||||
|
#PUBLIC_BASE_URL=
|
||||||
|
|
||||||
|
# Session and security
|
||||||
|
SESSION_SECRET=SET-A-STRONG-RANDOM-VALUE
|
||||||
|
LOG_LEVEL=DEBUG
|
||||||
|
|
||||||
# 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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@@ -197,52 +241,20 @@ You can keep a checked‑in `/.env.example` with the keys above for onboarding.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
## 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://<host>: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
|
## Security notes
|
||||||
|
|
||||||
- The app is **unauthenticated** by design. Share the URL only with trusted people or keep it on a private network/VPN.
|
- The menu and invite creation are behind login. Logout clears the session.
|
||||||
|
- Invite links are public by URL; share only with intended recipients.
|
||||||
|
- The default uploader page at `/` is disabled unless `PUBLIC_UPLOAD_PAGE_ENABLED=true`.
|
||||||
- The Immich API key remains **server‑side**; the browser never sees it.
|
- The Immich API key remains **server‑side**; the browser never sees it.
|
||||||
- No browsing of uploaded media; only ephemeral session state is shown.
|
- No browsing of uploaded media; only ephemeral session state is shown.
|
||||||
|
- Run behind HTTPS with a reverse proxy and restrict CORS to your domain(s).
|
||||||
|
|
||||||
---
|
## Usage flow
|
||||||
|
|
||||||
## Development
|
- Admin: Login → Menu → Create invite link (optionally one‑time / expiry / album) → Share link or QR.
|
||||||
|
- Guest: Open invite link → Drop files → Upload progress and results shown.
|
||||||
Run with live reload:
|
- Optional: Enable public uploader and set `IMMICH_ALBUM_NAME` for a default landing page.
|
||||||
|
|
||||||
```bash
|
|
||||||
python main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
The backend contains docstrings so you can generate docs later if desired.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -356,6 +356,15 @@ async def menu_page(request: Request) -> HTMLResponse:
|
|||||||
return RedirectResponse(url="/login")
|
return RedirectResponse(url="/login")
|
||||||
return FileResponse(os.path.join(FRONTEND_DIR, "menu.html"))
|
return FileResponse(os.path.join(FRONTEND_DIR, "menu.html"))
|
||||||
|
|
||||||
|
@app.get("/favicon.ico")
|
||||||
|
async def favicon() -> Response:
|
||||||
|
"""Serve favicon from /static/favicon.png if present (avoids 404 noise)."""
|
||||||
|
path = os.path.join(FRONTEND_DIR, "favicon.png")
|
||||||
|
if os.path.exists(path):
|
||||||
|
with open(path, "rb") as f:
|
||||||
|
return Response(content=f.read(), media_type="image/png")
|
||||||
|
return Response(status_code=204)
|
||||||
|
|
||||||
@app.post("/api/ping")
|
@app.post("/api/ping")
|
||||||
async def api_ping() -> dict:
|
async def api_ping() -> dict:
|
||||||
"""Connectivity test endpoint used by the UI to display a temporary banner."""
|
"""Connectivity test endpoint used by the UI to display a temporary banner."""
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ class Settings:
|
|||||||
"""App settings loaded from environment variables (.env)."""
|
"""App settings loaded from environment variables (.env)."""
|
||||||
immich_base_url: str
|
immich_base_url: str
|
||||||
immich_api_key: str
|
immich_api_key: str
|
||||||
max_concurrent: int = 3
|
max_concurrent: int
|
||||||
album_name: str = ""
|
album_name: str = ""
|
||||||
public_upload_page_enabled: bool = False
|
public_upload_page_enabled: bool = False
|
||||||
public_base_url: str = ""
|
public_base_url: str = ""
|
||||||
state_db: str = "./state.db"
|
state_db: str = ""
|
||||||
session_secret: str = ""
|
session_secret: str = ""
|
||||||
log_level: str = "INFO"
|
log_level: str = "INFO"
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ def load_settings() -> Settings:
|
|||||||
maxc = int(os.getenv("MAX_CONCURRENT", "3"))
|
maxc = int(os.getenv("MAX_CONCURRENT", "3"))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
maxc = 3
|
maxc = 3
|
||||||
state_db = os.getenv("STATE_DB", "./state.db")
|
state_db = os.getenv("STATE_DB", "/data/state.db")
|
||||||
session_secret = os.getenv("SESSION_SECRET") or secrets.token_hex(32)
|
session_secret = os.getenv("SESSION_SECRET") or secrets.token_hex(32)
|
||||||
log_level = os.getenv("LOG_LEVEL", "INFO").upper()
|
log_level = os.getenv("LOG_LEVEL", "INFO").upper()
|
||||||
return Settings(
|
return Settings(
|
||||||
|
|||||||
@@ -7,10 +7,15 @@ services:
|
|||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
#immich drop server ip
|
||||||
|
PUBLIC_BASE_URL: http://192.168.8.60:8080
|
||||||
|
# Immich connection
|
||||||
|
IMMICH_BASE_URL: http://192.168.8.60:2283/api
|
||||||
|
IMMICH_API_KEY: n7lO2oRFVhMXqI10YL8nfelIC9lZ8ND8AxZqx1XHiA
|
||||||
|
#Enable/Disable Public upload page to folder
|
||||||
|
PUBLIC_UPLOAD_PAGE_ENABLED: false
|
||||||
IMMICH_ALBUM_NAME: dead-drop
|
IMMICH_ALBUM_NAME: dead-drop
|
||||||
|
|
||||||
env_file:
|
|
||||||
- ./.env
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- immich_drop_data:/data
|
- immich_drop_data:/data
|
||||||
|
|||||||
BIN
frontend/favicon.png
Normal file
BIN
frontend/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>Immich Drop Uploader</title>
|
<title>Immich Drop Uploader</title>
|
||||||
|
<link rel="icon" type="image/png" href="/static/favicon.png" />
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<script>
|
<script>
|
||||||
tailwind.config = {
|
tailwind.config = {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>Immich Drop Uploader (Invite)</title>
|
<title>Immich Drop Uploader (Invite)</title>
|
||||||
|
<link rel="icon" type="image/png" href="/static/favicon.png" />
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<script>
|
<script>
|
||||||
tailwind.config = { darkMode: 'class' };
|
tailwind.config = { darkMode: 'class' };
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>Login – Immich Drop</title>
|
<title>Login – Immich Drop</title>
|
||||||
|
<link rel="icon" type="image/png" href="/static/favicon.png" />
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<script>
|
<script>
|
||||||
tailwind.config = { darkMode: 'class' };
|
tailwind.config = { darkMode: 'class' };
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>Menu – Immich Drop</title>
|
<title>Menu – Immich Drop</title>
|
||||||
|
<link rel="icon" type="image/png" href="/static/favicon.png" />
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<script>
|
<script>
|
||||||
tailwind.config = { darkMode: 'class' };
|
tailwind.config = { darkMode: 'class' };
|
||||||
|
|||||||
2
main.py
2
main.py
@@ -11,6 +11,6 @@ if __name__ == "__main__":
|
|||||||
load_dotenv()
|
load_dotenv()
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
host = os.getenv("HOST", "127.0.0.1")
|
host = os.getenv("HOST", "0.0.0.0")
|
||||||
port = int(os.getenv("PORT", "8080"))
|
port = int(os.getenv("PORT", "8080"))
|
||||||
uvicorn.run("app.app:app", host=host, port=port, reload=True)
|
uvicorn.run("app.app:app", host=host, port=port, reload=True)
|
||||||
|
|||||||
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 160 KiB |
Reference in New Issue
Block a user