# Frambe

Frambe

A lightweight, self-contained Docker web application that connects to your [Immich](https://immich.app/) server and displays photos in a beautiful full-screen slideshow — perfect for turning old tablets, spare screens, and Raspberry Pis into digital photo frames. ## ✨ Features - **Immich API Integration** — Connects securely via API key (kept server-side) - **Album Browser** — Select any album (owned or shared), random photos, or favorites only - **Person / Face Support** — Display photos of a specific person via Immich's face recognition - **Admin Dashboard** — Real-time WebSocket-based control panel for all connected frames - **Admin Authentication** — Optional username/password login to protect the admin dashboard - **REST API with Token Auth** — Control frames from Home Assistant, scripts, or external tools - **URL-Based Zero-Touch Launch** — Skip the setup screen entirely with query parameters - **Auto-Refresh** — Periodically checks for new photos added to the source album/person - **Smooth Crossfade** — Double-buffered image transitions with configurable duration - **Background Blur** — Blurred backdrop fills the space behind non-covering images - **Clock & Date Overlay** — Always know the time at a glance - **EXIF Info** — Shows photo location, date, and camera info - **Progress Bar** — Subtle indicator of time until next photo - **Touch Controls** — Tap left/right edges to navigate, centre to toggle overlay - **Keyboard Controls** — Arrow keys, Space, F (fullscreen), I (info), Esc (exit) - **Screen Wake Lock** — Prevents screen sleep on supported devices - **Responsive** — Works on any screen size from phone to TV - **Older Device Friendly** — Vanilla HTML/CSS/JS, no heavy frameworks - **Docker Containerised** — Single container, minimal footprint --- ## 🚀 Deployment ### Prerequisites - A running [Immich](https://immich.app/) server - An Immich API key (see below) - Docker and Docker Compose (recommended) — or Node.js 18+ for running from source ### 1. Get your Immich API Key 1. Open your Immich web interface 2. Click your profile picture → **Account Settings** → **API Keys** 3. Create a new key with `asset.read` and `album.read` permissions 4. Copy the key — you'll need it for the next step ### 2. Deploy with Docker Compose (recommended) ```bash git clone https://gitea.hideawaygaming.com.au/jessikitty/frambe.git cd frambe ``` Edit `docker-compose.yml` and set your `IMMICH_URL` and `IMMICH_API_KEY`: ```yaml environment: - IMMICH_URL=http://your-immich-server:2283 - IMMICH_API_KEY=your-api-key-here ``` Then start the container: ```bash docker compose up -d ``` Frambe is now running at `http://your-server:3030`. ### 3. Deploy with Docker Run If you prefer not to use Compose: ```bash docker build -t frambe . docker run -d \ --name frambe \ -p 3030:3000 \ -e IMMICH_URL=http://your-immich-server:2283 \ -e IMMICH_API_KEY=your-api-key \ --restart unless-stopped \ frambe ``` ### 4. Run from Source (development) ```bash git clone https://gitea.hideawaygaming.com.au/jessikitty/frambe.git cd frambe npm install ``` Create a `.env` file from the example: ```bash cp .env.example .env ``` Edit `.env` with your Immich URL and API key, then start the server: ```bash npm start ``` Frambe will be available at `http://localhost:3000`. ### Port Mapping The internal server runs on port **3000**. The Docker Compose config maps this to external port **3030** by default. You can change this in `docker-compose.yml`: ```yaml ports: - "8080:3000" # Access Frambe on port 8080 instead ``` --- ## 🔄 Upgrading ### Docker Compose (recommended) ```bash cd frambe git pull docker compose build docker compose up -d ``` Your configuration in `docker-compose.yml` is preserved — only the application code is rebuilt. ### Docker Run ```bash cd frambe git pull docker stop frambe docker rm frambe docker build -t frambe . docker run -d \ --name frambe \ -p 3030:3000 \ -e IMMICH_URL=http://your-immich-server:2283 \ -e IMMICH_API_KEY=your-api-key \ --restart unless-stopped \ frambe ``` ### From Source ```bash cd frambe git pull npm install npm start ``` ### Switching to a Specific Version Frambe uses git tags for releases. To pin to a specific version: ```bash git fetch --tags git checkout v1.4.1 # Replace with desired version docker compose build && docker compose up -d ``` To switch back to the latest: ```bash git checkout main git pull docker compose build && docker compose up -d ``` ### Upgrade Notes - **All upgrades are non-destructive** — Frambe stores no persistent data on disk. All configuration is via environment variables. - **No database migrations** — there is no database. Session tokens are in-memory and will reset on restart (users simply log in again). - **Check the changelog below** before upgrading major versions for any new required environment variables. --- ## 🔑 Authentication ### Admin Dashboard Login Protect the admin dashboard with a username and password: ```yaml environment: - ADMIN_USERNAME=admin - ADMIN_PASSWORD=your-secure-password ``` When `ADMIN_PASSWORD` is set, accessing `/admin` requires signing in. When not set, the dashboard is open (useful for trusted local networks). ### API Token for External Access Enable token-authenticated REST API access for Home Assistant, scripts, or other external tools: ```yaml environment: - FRAMBE_API_TOKEN=your-secret-token-here ``` --- ## 🔌 REST API When `FRAMBE_API_TOKEN` is configured, the following endpoints are available: ### List Connected Frames ``` GET /api/clients Authorization: Bearer your-secret-token-here ``` Returns all connected frame clients with their status, IP, name, and config. ### Send Command to a Frame ``` POST /api/clients/:id/command Authorization: Bearer your-secret-token-here Content-Type: application/json { "action": "next", "payload": {} } ``` Available actions: `start`, `stop`, `next`, `prev`, `sleep`, `wake`, `refresh`, `setSource`, `setConfig` ### Home Assistant Example ```yaml rest_command: frambe_next_photo: url: "http://frambe-server:3030/api/clients/{{ client_id }}/command" method: POST headers: Authorization: "Bearer your-secret-token-here" Content-Type: "application/json" payload: '{"action": "next"}' ``` Authentication can also be provided via `x-api-token` header or `?token=` query parameter. --- ## 🔗 Zero-Touch URL Parameters Skip the setup screen entirely by passing query parameters. This is ideal for dedicated frames — just bookmark the URL on each tablet: | URL | What it shows | |---|---| | `http://server:3030/?album=ALBUM_UUID` | Photos from a specific album | | `http://server:3030/?person=PERSON_UUID` | Photos of a specific person (face recognition) | | `http://server:3030/?favorites` | Favorite photos only | | `http://server:3030/?random` | Random photos from the library | You can find album and person UUIDs in Immich's web interface URL bar when viewing an album or person. --- ## ⚙️ Configuration All settings are via environment variables. Set them in `docker-compose.yml`, pass with `docker run -e`, or put them in a `.env` file when running from source. | Variable | Default | Description | |---|---|---| | `IMMICH_URL` | *(required)* | Your Immich server URL | | `IMMICH_API_KEY` | *(required)* | Immich API key | | `SLIDESHOW_INTERVAL` | `30` | Seconds between photos | | `TRANSITION_DURATION` | `2` | Crossfade duration in seconds | | `IMAGE_FIT` | `contain` | `contain` or `cover` | | `SHUFFLE` | `true` | Randomise photo order | | `BACKGROUND_BLUR` | `true` | Show blurred backdrop | | `SHOW_CLOCK` | `true` | Display clock overlay | | `SHOW_DATE` | `true` | Display date overlay | | `SHOW_EXIF` | `true` | Display photo metadata | | `SHOW_PROGRESS` | `true` | Display progress bar | | `INCLUDE_VIDEOS` | `true` | Include video assets in slideshow | | `REFRESH_INTERVAL` | `300` | Seconds between source refresh checks (new photos) | | `ALBUM_ID` | *(empty)* | Auto-start with specific album (env-based) | | `SHOW_FAVORITES_ONLY` | `false` | Auto-start with favorites (env-based) | | `ADMIN_USERNAME` | `admin` | Admin dashboard login username | | `ADMIN_PASSWORD` | *(empty)* | Admin dashboard password (leave empty to disable auth) | | `FRAMBE_API_TOKEN` | *(empty)* | API token for REST endpoint access (leave empty for open access) | | `PORT` | `3000` | Internal server port (Docker maps externally via compose) | --- ## 🎮 Controls ### Touch / Mouse - **Left 20%** of screen — Previous photo - **Centre 60%** — Toggle overlay (clock, info, close button) - **Right 20%** — Next photo ### Keyboard - `←` / `→` — Previous / Next photo - `Space` — Next photo - `F` — Toggle fullscreen - `I` — Toggle info overlay - `Esc` — Exit to album selection --- ## 📱 Tablet Setup Tips 1. Open the frame URL in your tablet's browser (use a `?album=` or `?person=` URL for zero-touch) 2. Add to Home Screen for a full-screen app experience 3. Enable kiosk mode or guided access to lock to the app 4. Disable screen timeout in your device settings --- ## 🏗️ Architecture ``` ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Browser │ HTTP │ Frambe │ API │ Immich │ │ (Tablet) │◄────────►│ (Node.js) │◄────────►│ Server │ └──────────────┘ :3030 └──────────────┘ :2283 └──────────────┘ ▲ ┌─────────┴─────────┐ │ REST API / WS │ │ (Home Assistant) │ └───────────────────┘ ``` The Node.js backend acts as a secure proxy — your Immich API key never reaches the browser. The frontend periodically polls the backend for new photos so albums stay up to date without restarting. --- ## 🏷️ Versioning Frambe follows [Semantic Versioning](https://semver.org/): - **Major** (`X.0.0`) — Large feature overhauls, breaking changes, or major UI redesigns - **Minor** (`0.X.0`) — New features, functionality additions, or significant improvements - **Patch** (`0.0.X`) — Bug fixes, small tweaks, and minor corrections ### Branches | Branch | Purpose | |---|---| | `main` | Stable releases — production-ready code | | `dev` | Development — latest features, may be unstable | ### Changelog #### v1.4.1 — Shared Albums - ✅ Album picker now shows **shared albums** alongside owned albums - ✅ Shared albums are visually marked with a "Shared" badge in the picker - ✅ Shared album icons use 🔗 to distinguish from owned 📁 albums - ✅ Deduplication ensures albums shared with yourself don't appear twice #### v1.4.0 — Admin Auth & REST API - ✅ Admin dashboard login with username/password authentication (env-based) - ✅ Session management with HttpOnly cookies (24-hour expiry, automatic cleanup) - ✅ API token authentication for external access (Home Assistant, scripts, curl) - ✅ REST endpoint: `GET /api/clients` — list all connected frames - ✅ REST endpoint: `POST /api/clients/:id/command` — send commands to frames - ✅ Multiple auth methods: Bearer token, `x-api-token` header, `?token=` query param - ✅ Auth status endpoint: `GET /api/auth/status` - ✅ Backwards compatible — auth is opt-in, disabled by default - 🆕 New env vars: `ADMIN_USERNAME`, `ADMIN_PASSWORD`, `FRAMBE_API_TOKEN` #### v1.3.0 — Admin Dashboard & Video Support - ✅ Real-time admin dashboard at `/admin` with WebSocket communication - ✅ Live frame management: start, stop, next, prev, sleep, wake, refresh - ✅ Remote source switching: change album, person, random, or favorites per frame - ✅ Remote config: adjust slideshow interval, toggle clock/date/EXIF/progress per frame - ✅ Frame naming and rename support (persists by IP) - ✅ Video playback support in slideshow (with `INCLUDE_VIDEOS` toggle) - ✅ Person / face recognition photo source via Immich's people API - ✅ Connection status indicators and auto-reconnect #### v1.2.1 — Bug Fixes - 🐛 Fixed port mapping (3030:3000 external:internal) - 🐛 Fixed URL parameter auto-launch not starting the slideshow #### v1.2.0 — Zero-Touch Launch & Auto-Refresh - ✅ URL query parameters for zero-touch launch (`?album=`, `?person=`, `?favorites`, `?random`) - ✅ Person / face support — display photos of a specific person - ✅ Periodic auto-refresh — new photos appear without restarting - ✅ App icon for home screen bookmarks - ✅ Default external port changed to 3030 - 🆕 New env var: `REFRESH_INTERVAL` #### v1.1.0 — Rebrand - ✅ Rebranded to Frambe #### v1.0.0 — Initial Release - ✅ Album browser with Immich API integration - ✅ Full-screen slideshow with smooth crossfade transitions - ✅ Double-buffered image loading for seamless display - ✅ Background blur behind non-covering images - ✅ Clock, date, and EXIF metadata overlays - ✅ Progress bar showing time until next photo - ✅ Touch controls (left/centre/right tap zones) - ✅ Keyboard controls (arrows, space, F, I, Esc) - ✅ Screen wake lock to prevent display sleep - ✅ Configurable via environment variables - ✅ Docker containerised deployment - ✅ Vanilla HTML/CSS/JS frontend — no frameworks, works on older devices --- ## 📄 License MIT