This release brings single sign-on, OCR text search with live text, and an important security fix: all multi-user instances should upgrade. Here is an overview of all the new features, improvements, and bug fixes since the last release.
Upstream:
🚀 LibrePhotos: OpenID Connect Single Sign-On
You can now log in through any OIDC identity provider (Keycloak, Authentik, Authelia, Zitadel, Google, Entra ID, and friends) via django-allauth. SSO logins mint the same JWT pair as password logins, so everything downstream behaves identically, and password login stays untouched. It is configured through an admin-editable SocialApp plus OIDC_ENABLED, OIDC_BUTTON_LABEL, and OIDC_ALLOW_SIGNUP (off by default) site settings, and ships with setup docs including the exact callback URL to register. The implementation is defensive by design: account linking requires a provider-verified email, ambiguous or blank email matches are refused, and SSO-provisioned accounts are never staff or superuser. (Implemented by dotanm)
🚀 LibrePhotos: Screenshot & Document Categories with OCR Text Search and Live Text
Screenshots and documents are now their own media categories with filters, search captions, stats counts, and a dedicated /screenshots page. Screenshots are detected deterministically (localized filename prefixes, Screenshots directories, a conservative PNG-without-camera-metadata fallback), documents via rule-based signals, and manual overrides always win. On top of that, an optional PP-OCRv6-based OCR sidecar extracts the text from your photos: full-text search finds photos by the text in them, and the photo viewer overlays selectable "live text" on the image so you can copy it right off a screenshot. OCR is off by default, so nothing changes until an admin picks an OCR model and runs the extraction job. A fast DB-only backfill classifies existing libraries.
🚀 LibrePhotos: Security Fix for select_all Bulk Endpoints (CVE-2026-57943)
Residual fixes for CVE-2026-57943 (#1980, #1981, #1982): the select_all branches of the bulk photo-edit endpoints (make public/private, hide/unhide, trash/restore, favorite, share, delete) built their write target from the shared read-path queryset builder, which drops the owner filter for public: true queries. Any authenticated user could therefore bulk-modify other users' public photos, for example flipping every public photo on the instance to private, hiding them, or moving them to trash. Private photos were never exposed. Every branch now binds the write to the requesting user, with cross-user regression tests for each endpoint.
- ✨ LibrePhotos: User-defined tags as a first-class entity: create your own tags and organize photos with them, independent of the ML-generated things
- ✨ LibrePhotos: Self-service password reset, rate-limited and enumeration-safe, closing one of the oldest open requests (#596), powered by admin-configurable outgoing email with SMTP and provider presets (Implemented by dotanm)
- ✨ LibrePhotos: Deploy-time feature flags:
FEATURE_*environment variables let admins disable individual features per deployment, and the Nextcloud integration is now behind an admin toggle - ✨ LibrePhotos: Kubernetes-ready liveness/readiness health endpoints plus example k8s manifests
- ✨ LibrePhotos: Configurable map tile provider: choose PhotoPrism, OpenStreetMap, or no map at all (Implemented by dotanm)
- ✨ LibrePhotos: Regular users can now see their own background jobs; the worker status view is no longer admin-only (Implemented by dotanm)
- ✨ LibrePhotos: Scan Phase 1 prefetches known file paths instead of issuing a query per file, making large rescans significantly faster (Implemented by dotanm)
- ✨ Frontend: Media-type filter: All / Photos / Videos toggle on search, user, place, thing, and person albums (Implemented by dotanm)
- ✨ Frontend: Server-side Select All: Add-to-album and Create-album now work on a whole query result without loading every photo into the browser (Implemented by dotanm)
- ✨ Frontend: Faces page improvements: recently tagged people are offered first in the tagging popup, and person groups can be folded and unfolded
- ✨ Backend: A backend test suite now runs in CI on every pull request
- 🔨 LibrePhotos: Worked through the open bug backlog, fixing 13 long-standing issues with a regression test for each: Nextcloud scanning/browsing/subfolders (#1066, #1030, #631), auto album generation stuck at 0% (#836), duplicated auto albums (#462), timeouts when tagging many faces (#897), slow album loading (#619), black video playback (#477), and more
- 🔨 LibrePhotos: Repaired the bugs surfaced by the documentation audit and reconciled the documentation with the code
- 🔨 LibrePhotos: Photo times are shown in the viewer's timezone, and CPU limits no longer kill the backend
- 🔨 LibrePhotos: Date edits are written as
XMP:DateCreated(the previous tag name was invalid and silently did nothing), and metadata edit history ordering is now deterministic - 🔨 LibrePhotos: Thumbnail fixes: UUID-addressed thumbnails are served correctly in direct mode and for
thumbnails_big, thumbnail dimensions are read locally so photos can no longer go invisible, and UUID person cover photos are accepted (Implemented by v-marinkov and dotanm) - 🔨 LibrePhotos: Faces & XMP: XMP face import is complete, named XMP faces are reconciled with existing people, person albums stay in sync when untagging faces, and person album photo lists get the right album ID (Implemented by v-marinkov)
- 🔨 LibrePhotos: Event album loading, lightbox, and add-to-album restored (Implemented by v-marinkov)
- 🔨 LibrePhotos: Media for album-shared photos is served instead of returning a 500 (Implemented by dotanm)
- 🔨 LibrePhotos: Photos with equal timestamps are ordered by filename (Implemented by terminalchai)
- 🔨 Frontend: The video player now says why a video will not play instead of guessing (Implemented by dotanm)
- 🔨 LibrePhotos: Stuck-job cleanup is scheduled automatically, so aged queue blockers no longer grey out the scan buttons forever (Implemented by Shaurya2k06)
- 🔨 Frontend: The worker-indicator popover is click-toggled so Cancel is reachable (Implemented by dotanm)
- 🔨 LibrePhotos: Deploy and admin fixes: the unified image no longer ships a stale
production.py, the constance admin no longer 500s onFACE_RECOGNITION_MODEL, and backend logging is configurable and single-sourced (#170) - 🔨 LibrePhotos: Live Photo companions are returned with their on-disk spelling, and stack review ordering is now deterministic
- 🔒 LibrePhotos: Security: ML model downloads are pinned to known hashes and third-party models are served from the LibrePhotos mirror, so a tampered or partial download can no longer land in the model directory
- ✨ LibrePhotos: Python 3.14, roughly 30 Renovate dependency updates across backend and frontend, and updated documentation: frontend contribution page rewritten and dev-server commands corrected
If you are interested in how I develop this application, you can watch me develop features live on my channel
Sponsoring development:
My work is sponsored by 1 awesome person!
If you like the work I do, then you can support me via GitHub sponsors or via PayPal