Merge branch 'develop' into feature/render-360-originals

This commit is contained in:
Ömer Duran 2026-07-16 23:56:52 +02:00
commit 3439b311fa
No known key found for this signature in database
GPG key ID: 2550B0D579890013
279 changed files with 17394 additions and 11219 deletions

View file

@ -64,6 +64,8 @@
- **Share role/provider labels, not the selectable lists.** Display names live once in `frontend/src/options/auth.js` (`Roles()` / `Providers()` maps, with `RoleOptions(keys, labelKey)` / `ProviderOptions(keys, labelKey)` builders). Private editions (`plus`/`pro`/`portal`) import these and pass their own key list — the selectable sets legitimately differ per edition (cluster_admin, LDAP/AD, reduced Plus set) but the labels must not be re-listed.
- Extraction source of truth: root `make gettext-extract` (via `scripts/gettext-extract.sh`), which scans `frontend/src` plus available overlays in `plus/frontend`, `pro/frontend`, `portal/frontend`. Feature PRs do **not** commit the resulting `.pot`/`.po` churn — Weblate re-extracts on its refresh cycle (see `specs/frontend/translations.md`); a dedicated "Regenerate translation catalogs" commit is the exception.
- Avoid punctuation-only gettext keys (e.g. `$gettext("—")`) — they clutter `frontend/src/locales/translations.pot`.
- Catalog integrity gate: run `make gettext-lint` (`scripts/gettext-lint.mjs`) after any `.po`/`.pot` edit. It flags placeholder-set mismatches between `msgid` and `msgstr` (frontend `%{name}`, backend printf verbs), edge-whitespace drift, and `msgfmt -c` c-format fatals — defects that silently break variable substitution at runtime. Leading/trailing/internal whitespace inside a `msgid` is itself runtime-inert (`vue3-gettext` trims + collapses keys on load and lookup), so trailing-space findings are cleanliness, not correctness.
- Trimming a source string's trailing space must stay consistent across template + `.po` + `.pot`: trim the literal, then `make gettext-extract`. Caveat: `msgmerge --no-fuzzy-matching` treats the trimmed `msgid` as new, blanks its `msgstr`, and moves the old translation to an obsolete `#~` block — so carry that translation onto the active trimmed entry (collapse any folded multi-line `#~ msgstr`) before `make gettext-compile`, or every locale renders untranslated. This only fills `msgstr`, so Weblate merges it cleanly.
## Web Templates & Shared Assets

View file

@ -1,5 +1,5 @@
# Ubuntu 26.04 LTS (Resolute Raccoon)
FROM photoprism/develop:260629-resolute
FROM photoprism/develop:260709-resolute
# Harden npm usage by default (applies to npm ci / install in dev container)
ENV NPM_CONFIG_IGNORE_SCRIPTS=true

View file

@ -181,6 +181,8 @@ gettext-compile:
$(MAKE) -C frontend gettext-compile
gettext-clear-fuzzy:
./scripts/gettext-clear-fuzzy.sh
gettext-lint:
node scripts/gettext-lint.mjs
clean:
rm -f *.log .test*
[ ! -f "$(BINARY_NAME)" ] || rm -f $(BINARY_NAME)
@ -609,7 +611,7 @@ docker-pull:
$(DOCKER_COMPOSE) -f compose.latest.yaml pull --ignore-pull-failures
build-docker: docker-build
docker-build:
$(DOCKER_COMPOSE) --profile=all pull --ignore-pull-failures
$(DOCKER_COMPOSE) --profile=postgres --profile=keycloak pull --ignore-pull-failures
$(DOCKER_COMPOSE) down --remove-orphans
$(DOCKER_COMPOSE) build --pull
nvidia: nvidia-up

30
NOTICE
View file

@ -9,7 +9,7 @@ The following 3rd-party software packages may be used by or distributed with
PhotoPrism. Any information relevant to third-party vendors listed below are
collected using common, reasonable means.
Date generated: 2026-07-07
Date generated: 2026-07-09
================================================================================
@ -9061,8 +9061,8 @@ License: Apache-2.0 (https://github.com/go4org/go4/blob/a5071408f32f/LICENSE)
--------------------------------------------------------------------------------
Package: golang.org/x/crypto
Version: v0.53.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/crypto/+/v0.53.0:LICENSE)
Version: v0.54.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/crypto/+/v0.54.0:LICENSE)
Copyright 2009 The Go Authors.
@ -9095,8 +9095,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/image
Version: v0.43.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/image/+/v0.43.0:LICENSE)
Version: v0.44.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/image/+/v0.44.0:LICENSE)
Copyright 2009 The Go Authors.
@ -9129,8 +9129,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/mod/semver
Version: v0.37.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/mod/+/v0.37.0:LICENSE)
Version: v0.38.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/mod/+/v0.38.0:LICENSE)
Copyright 2009 The Go Authors.
@ -9163,8 +9163,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/net
Version: v0.56.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/net/+/v0.56.0:LICENSE)
Version: v0.57.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/net/+/v0.57.0:LICENSE)
Copyright 2009 The Go Authors.
@ -9231,8 +9231,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/sync/errgroup
Version: v0.21.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/sync/+/v0.21.0:LICENSE)
Version: v0.22.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/sync/+/v0.22.0:LICENSE)
Copyright 2009 The Go Authors.
@ -9265,8 +9265,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/sys
Version: v0.46.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/sys/+/v0.46.0:LICENSE)
Version: v0.47.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/sys/+/v0.47.0:LICENSE)
Copyright 2009 The Go Authors.
@ -9299,8 +9299,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
Package: golang.org/x/text
Version: v0.39.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/text/+/v0.39.0:LICENSE)
Version: v0.40.0
License: BSD-3-Clause (https://cs.opensource.google/go/x/text/+/v0.40.0:LICENSE)
Copyright 2009 The Go Authors.

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"
@ -383,7 +383,7 @@ msgstr "در حال پردازش آپلود..."
#: messages.go:202
msgid "Upload has been processed"
msgstr "%s بازیابی شده است"
msgstr "بارگذاری پردازش شده است"
#: messages.go:203
msgid "Selection approved"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-28 15:07+0000\n"
"Last-Translator: jean-louis67 <jean-louis.frenkel@orange.fr>\n"

View file

@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"
@ -15,8 +15,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=5; plural=n==1 ? 0 : n==2 ? 1 : (n>2 && n<7) ? 2 :(n>"
"6 && n<11) ? 3 : 4;\n"
"Plural-Forms: nplurals=5; plural=n==1 ? 0 : n==2 ? 1 : (n>2 && n<7) ? 2 :"
"(n>6 && n<11) ? 3 : 4;\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:112

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"
@ -418,7 +418,7 @@ msgstr "Trajno izbrisano"
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "Odabir je vraćen"
msgstr "%s je vraćen"
#: messages.go:211
msgid "Successfully verified"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"
@ -418,7 +418,7 @@ msgstr "بە هەمیشەیی سڕاوەتەوە"
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "هەڵبژاردەکە دووبارەکۆگاکرایەوە"
msgstr "%s دووبارە کۆگاکرایەوە"
#: messages.go:211
msgid "Successfully verified"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: DeepL <noreply-mt-deepl@weblate.org>\n"

View file

@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2026-06-27 10:28+0000\n"
"Last-Translator: Google Cloud Translation Basic <noreply-mt-google-"

View file

@ -145,11 +145,11 @@ services:
## Run/install on first startup (options: update tensorflow https intel gpu davfs yt-dlp):
PHOTOPRISM_INIT: "https"
## Computer Vision (https://docs.photoprism.app/getting-started/config-options/#computer-vision):
PHOTOPRISM_VISION_API: "true" # server: enables service API endpoints under /api/v1/vision (requires access token)
PHOTOPRISM_VISION_URI: "" # client: service URI, e.g. http://hostname/api/v1/vision (leave blank to disable)
PHOTOPRISM_VISION_KEY: "" # client: service access token (for authentication)
OLLAMA_BASE_URL: "http://ollama:11434" # use "https://ollama.com" for Ollama Cloud
OLLAMA_API_KEY: "" # API key required to access Ollama (optional)
PHOTOPRISM_VISION_API: "true" # server: enables service API endpoints under /api/v1/vision (requires access token)
PHOTOPRISM_VISION_URI: "${PHOTOPRISM_VISION_URI:-}" # client: service URI, e.g. http://hostname/api/v1/vision (leave blank to disable)
PHOTOPRISM_VISION_KEY: "${PHOTOPRISM_VISION_KEY:-}" # client: service access token (for authentication)
OLLAMA_BASE_URL: "${OLLAMA_BASE_URL:-http://ollama:11434}" # use "https://ollama.com" for Ollama Cloud
OLLAMA_API_KEY: "${OLLAMA_API_KEY:-}" # optional API key for Ollama Cloud
## Additional dependencies and tools:
TF_CPP_MIN_LOG_LEVEL: 1
GOCACHE: "${WORKING_DIR:-/go/src/github.com/photoprism/photoprism}/.local/gocache"

View file

@ -85,11 +85,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
cp -r /etc/skel/.config /root/.config && \
/scripts/install-go.sh && \
/scripts/install-go-tools.sh && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
cp /scripts/convert/policy.xml /etc/ImageMagick-6/policy.xml && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \

View file

@ -67,11 +67,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
libmatroska-dev libdvdread-dev libebml5 libgav1-bin libatomic1 \
iputils-ping dnsutils binutils binutils-gold \
&& \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -95,11 +95,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-hadolint.sh && \
/scripts/install-osv-scanner.sh && \
/scripts/install-gitleaks.sh && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
cp /scripts/convert/policy.xml /etc/ImageMagick-6/policy.xml && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \

View file

@ -87,11 +87,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
&& \
/scripts/install-mariadb.sh mariadb-client && \
/scripts/install-darktable.sh && \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -129,11 +129,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-darktable.sh && \
/scripts/install-go-tools.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -125,11 +125,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-darktable.sh && \
/scripts/install-go-tools.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -123,11 +123,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-chrome.sh && \
/scripts/install-go.sh && \
/scripts/install-go-tools.sh && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -72,11 +72,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-yt-dlp.sh && \
/scripts/install-libvips.sh && \
/scripts/install-libheif.sh && \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -108,11 +108,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-hadolint.sh && \
/scripts/install-osv-scanner.sh && \
/scripts/install-gitleaks.sh && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
cp /scripts/convert/policy.xml /etc/ImageMagick-6/policy.xml && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \

View file

@ -66,11 +66,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-mariadb.sh mariadb-client && \
/scripts/install-darktable.sh && \
/scripts/install-libheif.sh && \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -91,11 +91,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-go.sh && \
/scripts/install-go-tools.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
cp /scripts/convert/policy.xml /etc/ImageMagick-6/policy.xml && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \

View file

@ -66,11 +66,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-mariadb.sh mariadb-client && \
/scripts/install-darktable.sh && \
/scripts/install-libheif.sh && \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -91,11 +91,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-go.sh && \
/scripts/install-go-tools.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: ALL" >> /etc/sudoers.d/all && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
cp /scripts/convert/policy.xml /etc/ImageMagick-6/policy.xml && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \

View file

@ -68,11 +68,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-mariadb.sh mariadb-client && \
/scripts/install-darktable.sh && \
/scripts/install-libheif.sh && \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -96,11 +96,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
cp -r /etc/skel/.config /root/.config && \
/scripts/install-go.sh && \
/scripts/install-go-tools.sh && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
cp /scripts/convert/policy.xml /etc/ImageMagick-6/policy.xml && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \

View file

@ -71,11 +71,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-mariadb.sh mariadb-client && \
/scripts/install-darktable.sh && \
/scripts/install-libheif.sh && \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -99,11 +99,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
cp -r /etc/skel/.config /root/.config && \
/scripts/install-go.sh && \
/scripts/install-go-tools.sh && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
cp /scripts/convert/policy.xml /etc/ImageMagick-6/policy.xml && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \

View file

@ -72,11 +72,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-darktable.sh && \
/scripts/install-yt-dlp.sh && \
/scripts/install-libheif.sh && \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -109,11 +109,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
cp -r /etc/skel/.config /root/.config && \
/scripts/install-go.sh && \
/scripts/install-go-tools.sh && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
cp /scripts/convert/policy.xml /etc/ImageMagick-7/policy.xml && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \

View file

@ -72,11 +72,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-darktable.sh && \
/scripts/install-yt-dlp.sh && \
/scripts/install-libheif.sh && \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -112,11 +112,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-hadolint.sh && \
/scripts/install-osv-scanner.sh && \
/scripts/install-gitleaks.sh && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
cp /scripts/convert/policy.xml /etc/ImageMagick-7/policy.xml && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \

View file

@ -73,11 +73,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-darktable.sh && \
/scripts/install-yt-dlp.sh && \
/scripts/install-libheif.sh && \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -113,11 +113,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-hadolint.sh && \
/scripts/install-osv-scanner.sh && \
/scripts/install-gitleaks.sh && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
cp /scripts/convert/policy.xml /etc/ImageMagick-7/policy.xml && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \

View file

@ -71,11 +71,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
libmatroska-dev libdvdread-dev libebml5 libgav1-bin libatomic1 \
va-driver-all libva2 iputils-ping dnsutils binutils binutils-gold \
&& \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -99,11 +99,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
/scripts/install-hadolint.sh && \
/scripts/install-osv-scanner.sh && \
/scripts/install-gitleaks.sh && \
echo 'alias go=richgo ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo 'export PATH="$PATH:$HOME/.local/bin"' >> /etc/bash.bashrc && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
cp /scripts/convert/policy.xml /etc/ImageMagick-7/policy.xml && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \

View file

@ -115,11 +115,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
&& \
/scripts/install-yt-dlp.sh && \
/scripts/install-libheif.sh && \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -118,11 +118,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
libavcodec-extra \
&& \
/scripts/install-darktable.sh && \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -117,11 +117,9 @@ RUN echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80retries && \
libavcodec-extra \
&& \
/scripts/install-darktable.sh && \
echo 'alias ll="ls -alh"' >> /etc/skel/.bashrc && \
echo 'export PS1="\u@$DOCKER_TAG:\w\$ "' >> /etc/skel/.bashrc && \
/scripts/install-bashrc.sh && \
echo "ALL ALL=(ALL) NOPASSWD:SETENV: /scripts/entrypoint-init.sh" >> /etc/sudoers.d/init && \
/scripts/install-dircolors.sh && \
cp /etc/skel/.bashrc /root/.bashrc && \
/scripts/create-users.sh && \
install -d -m 0777 -o 1000 -g 1000 \
/photoprism/originals \

View file

@ -33,6 +33,7 @@ import Labels from "page/labels.vue";
import People from "page/people.vue";
import Library from "page/library.vue";
import Settings from "page/settings.vue";
import Services from "page/services.vue";
import Admin from "page/admin.vue";
import Cluster from "page/cluster.vue";
import Login from "page/auth/login.vue";
@ -676,6 +677,19 @@ export default [
},
props: { tab: "settings_content" },
},
{
name: "settings_collections",
path: "/settings/collections",
component: Settings,
meta: {
title: $gettext("Settings"),
requiresAuth: true,
admin: true,
settings: true,
background: "background",
},
props: { tab: "settings_collections" },
},
{
name: "settings_media",
path: "/settings/media",
@ -697,7 +711,7 @@ export default [
{
name: "settings_services",
path: "/settings/services",
component: Settings,
component: Services,
meta: {
title: $gettext("Settings"),
requiresAuth: true,
@ -705,7 +719,15 @@ export default [
settings: true,
background: "background",
},
props: { tab: "settings_services" },
beforeEnter: (to, from, next) => {
if ($session.loginRequired()) {
next({ name: loginRoute });
} else if (!$config.feature("services") || $config.deny("services", "manage")) {
next({ name: $session.getDefaultRoute() });
} else {
next();
}
},
},
{
name: "settings_account",

View file

@ -149,6 +149,8 @@ export default class Config {
} else {
this.setTheme("default");
}
this.setReduceMotion(this.getSettings()?.ui.reduceMotion);
}
loading() {
@ -209,6 +211,7 @@ export default class Config {
this.setBatchSize(values.settings);
await this.setLanguage(this.getLanguageLocale(), true);
this.setTheme(values.settings.ui.theme);
this.setReduceMotion(values.settings.ui.reduceMotion);
}
// Adjust album counts by access level.
@ -591,6 +594,16 @@ export default class Config {
}
}
// setReduceMotion toggles the "reduce-motion" class on the <html> element so CSS can
// suppress interface animations and transitions when the accessibility setting is enabled.
setReduceMotion(enabled) {
if (document && document.documentElement) {
document.documentElement.classList.toggle("reduce-motion", !!enabled);
}
return this;
}
// getSettings returns the current user's configuration settings.
getSettings() {
return this.values.settings;
@ -612,6 +625,7 @@ export default class Config {
this.setBatchSize(settings);
this.setLanguage(settings.ui.language, false);
this.setTheme(settings.ui.theme);
this.setReduceMotion(settings.ui.reduceMotion);
return this;
}

View file

@ -1,6 +1,7 @@
export default {
docs: "https://link.photoprism.app/docs",
userGuide: "https://docs.photoprism.app/user-guide/",
syncSettings: "https://docs.photoprism.app/user-guide/settings/sync/",
developerGuide: "https://docs.photoprism.app/developer-guide/",
developerSetup: "https://docs.photoprism.app/developer-guide/setup/",
firstSteps: "https://docs.photoprism.app/user-guide/first-steps/",

View file

@ -476,6 +476,21 @@ export default class $util {
return ($config.getSettings()?.ui?.openOnHover ?? true) && !$util.hasTouch();
}
// mapAnimateDuration returns the map fly-to animation duration in milliseconds, forcing 0
// (no animation) when the Reduce Motion accessibility setting is enabled. A non-negative
// overrideMs takes precedence over the global Maps.Animate preference.
static mapAnimateDuration(settings, overrideMs = -1) {
if (settings?.ui?.reduceMotion) {
return 0;
}
if (overrideMs >= 0) {
return overrideMs;
}
return settings?.maps?.animate ?? 0;
}
// isMobile returns true when the current user agent or touch capability indicates a mobile device.
// The `> 2` touch check covers iPads in desktop mode, where the user agent omits the mobile hint.
static isMobile() {

View file

@ -5,6 +5,15 @@ import { getAppSessionStorage, getAppStorage } from "common/storage";
const TouchStartEvent = "touchstart";
const TouchMoveEvent = "touchmove";
// Selector for the document's viewport meta tag.
const ViewportMetaSelector = 'meta[name="viewport"]';
// Viewport content that disables the browser's native pinch-zoom of the whole page.
const ViewportNoZoom = "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no";
// Token in a viewport content string indicating native zoom is already disabled.
const ViewportNoZoomToken = "user-scalable=no";
// True if debug and/or trace logs should be recorded.
const debug = window.__CONFIG__?.debug;
const trace = window.__CONFIG__?.trace;
@ -405,6 +414,7 @@ export class View {
this.scopes = [];
this.hideScrollbar = false;
this.preventNavigation = false;
this.savedViewportContent = "";
this.focusScopes = new Map();
// Tracks the most recent history position and derived navigation direction so components can
@ -555,6 +565,7 @@ export class View {
let hideScrollbar = this.len() > 2 ? this.hideScrollbar : false;
let disableScrolling = false;
let disableNavigationGestures = false;
let disableViewportZoom = false;
let preventNavigation = uid > 0 && !name.startsWith("PPage");
switch (name) {
@ -582,6 +593,7 @@ export class View {
hideScrollbar = true;
disableScrolling = true;
disableNavigationGestures = true;
disableViewportZoom = true;
preventNavigation = true;
break;
}
@ -661,6 +673,14 @@ export class View {
}
}
// Lock native pinch-zoom while a flagged overlay is active, restore it otherwise.
// Both helpers are idempotent, so re-applying the same state is a no-op.
if (disableViewportZoom) {
this.disableNativeZoom();
} else {
this.restoreNativeZoom();
}
if (debug) {
console.groupEnd();
}
@ -818,6 +838,47 @@ export class View {
return setFocus(el, selector, scroll);
}
// disableNativeZoom locks the viewport so the browser can't pinch-zoom the whole page
// while an overlay (e.g. the lightbox) handles zoom itself; restoreNativeZoom restores
// the saved content. Idempotent; assumes one active overlay (savedViewportContent is
// app-global), which View.apply() upholds by locking only for the top-of-stack view.
disableNativeZoom() {
if (this.savedViewportContent) {
return;
}
const viewport = document.querySelector(ViewportMetaSelector);
if (!viewport) {
return;
}
const content = viewport.getAttribute("content") || "";
// Nothing to restore if the base viewport already blocks zoom (e.g. the Zoom setting is off).
if (content.includes(ViewportNoZoomToken)) {
return;
}
this.savedViewportContent = content;
viewport.setAttribute("content", ViewportNoZoom);
}
// restoreNativeZoom restores the viewport content saved by disableNativeZoom, if any.
restoreNativeZoom() {
if (!this.savedViewportContent) {
return;
}
const viewport = document.querySelector(ViewportMetaSelector);
if (viewport) {
viewport.setAttribute("content", this.savedViewportContent);
}
this.savedViewportContent = "";
}
// Navigates to the specified URL, optionally with a delay set in milliseconds and a blocked user interface.
redirect(url, delay, blockUI) {
// Return if no URL was passed.

View file

@ -63,9 +63,15 @@ export default {
return {
visible: false,
actions: [],
openOnHover: this.$util.shouldOpenOnHover(),
};
},
computed: {
// openOnHover reactively reflects the user's menu open-on-hover preference so a settings
// change applies without a page reload (persistent menus keep no mount-time snapshot).
openOnHover() {
return this.$util.shouldOpenOnHover();
},
},
methods: {
show() {
this.actions = this.items().filter((action) => action.visible);

View file

@ -96,6 +96,7 @@
<script>
import Album, { MaxLength as AlbumMaxLength } from "model/album";
import { rules } from "common/form";
import { AlbumSortOrder } from "options/options";
export default {
name: "PAlbumEditDialog",
@ -118,16 +119,7 @@ export default {
model: new Album(),
growDesc: false,
loading: false,
sorting: [
{ value: "newest", text: this.$gettext("Newest First") },
{ value: "oldest", text: this.$gettext("Oldest First") },
{ value: "added", text: this.$gettext("Recently Added") },
{ value: "title", text: this.$gettext("Picture Title") },
{ value: "name", text: this.$gettext("File Name") },
{ value: "size", text: this.$gettext("File Size") },
{ value: "duration", text: this.$gettext("Video Duration") },
{ value: "relevance", text: this.$gettext("Most Relevant") },
],
sorting: AlbumSortOrder(),
category: null,
categories: this.$config.albumCategories(),
rules,

View file

@ -60,10 +60,16 @@ export default {
data() {
return {
open: false,
openOnHover: this.$util.shouldOpenOnHover(),
instances: [],
};
},
computed: {
// openOnHover reactively reflects the user's menu open-on-hover preference so a settings
// change applies without a page reload (persistent menus keep no mount-time snapshot).
openOnHover() {
return this.$util.shouldOpenOnHover();
},
},
mounted() {
this.refresh();
},

View file

@ -56,9 +56,15 @@ export default {
return {
visible: false,
actions: [],
openOnHover: this.$util.shouldOpenOnHover(),
};
},
computed: {
// openOnHover reactively reflects the user's menu open-on-hover preference so a settings
// change applies without a page reload (persistent menus keep no mount-time snapshot).
openOnHover() {
return this.$util.shouldOpenOnHover();
},
},
methods: {
show() {
this.actions = this.items().filter((action) => action.visible);

View file

@ -62,7 +62,7 @@ export default {
map: null,
marker: null,
position: [0.0, 0.0],
animate: this.animateDuration >= 0 ? this.animateDuration : settings.maps.animate,
animate: this.$util.mapAnimateDuration(settings, this.animateDuration),
options: {
container: null,
// Styles can be edited/created with https://maplibre.org/maputnik/.

View file

@ -556,6 +556,20 @@
</v-list-item-title>
</v-list-item>
<v-list-item
v-if="canManageServices"
:to="{ path: '/settings/services' }"
:exact="false"
variant="text"
class="nav-services"
:ripple="false"
@click.stop=""
>
<v-list-item-title :class="`menu-item`">
{{ $gettext(`Services`) }}
</v-list-item-title>
</v-list-item>
<v-list-item :to="{ name: 'license' }" :exact="true" variant="text" class="nav-license" :ripple="false" @click.stop="">
<v-list-item-title :class="`menu-item`">
{{ $gettext(`License`) }}
@ -814,6 +828,7 @@ export default {
canManagePhotos: canManagePhotos,
canManagePeople: this.$config.allow("people", "manage"),
canManageUsers: (!isPublic || isDemo) && this.$config.allow("users", "access_all"),
canManageServices: this.$config.feature("services") && this.$config.allow("services", "manage"),
appNameSuffix: appNameSuffix,
appName: this.$config.getName(),
appAbout: this.$config.getAbout(),

View file

@ -398,40 +398,12 @@ export default {
sortOptions() {
switch (this.context) {
case contexts.Archive:
return [
{ value: "newest", text: this.$gettext("Newest First") },
{ value: "oldest", text: this.$gettext("Oldest First") },
{ value: "added", text: this.$gettext("Recently Added") },
{ value: "archived", text: this.$gettext("Recently Archived") },
{ value: "title", text: this.$gettext("Picture Title") },
{ value: "name", text: this.$gettext("File Name") },
{ value: "size", text: this.$gettext("File Size") },
{ value: "duration", text: this.$gettext("Video Duration") },
];
return options.SortOrderOptions(["newest", "oldest", "added", "archived", "title", "name", "size", "duration"]);
case contexts.Hidden:
case contexts.Review:
return [
{ value: "newest", text: this.$gettext("Newest First") },
{ value: "oldest", text: this.$gettext("Oldest First") },
{ value: "added", text: this.$gettext("Recently Added") },
{ value: "title", text: this.$gettext("Picture Title") },
{ value: "name", text: this.$gettext("File Name") },
{ value: "size", text: this.$gettext("File Size") },
{ value: "duration", text: this.$gettext("Video Duration") },
];
return options.SortOrderOptions(["newest", "oldest", "added", "title", "name", "size", "duration"]);
default:
return [
{ value: "newest", text: this.$gettext("Newest First") },
{ value: "oldest", text: this.$gettext("Oldest First") },
{ value: "added", text: this.$gettext("Recently Added") },
{ value: "edited", text: this.$gettext("Recently Edited") },
{ value: "title", text: this.$gettext("Picture Title") },
{ value: "name", text: this.$gettext("File Name") },
{ value: "size", text: this.$gettext("File Size") },
{ value: "duration", text: this.$gettext("Video Duration") },
{ value: "similar", text: this.$gettext("Visual Similarity") },
{ value: "relevance", text: this.$gettext("Most Relevant") },
];
return options.SortOrderOptions(["newest", "oldest", "added", "edited", "title", "name", "size", "duration", "similar", "relevance"]);
}
},
},

View file

@ -253,7 +253,7 @@ export default {
type: String,
default: "",
},
// The parent passes `service.clone()` (see settings/services.vue) so the
// The parent passes `service.clone()` (see page/services.vue) so the
// dialog operates on a parent-owned clone mutations are intentional and
// do not bleed into the parent's list state. We accept it as `service` and
// alias it as `model` via the computed below so the existing template and

View file

@ -52,6 +52,17 @@ html.hide-scrollbar {
scrollbar-width: none;
}
/* Reduce interface animations and motion when the accessibility setting is enabled. */
html.reduce-motion *,
html.reduce-motion *::before,
html.reduce-motion *::after {
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
scroll-behavior: auto !important;
}
body.nojs::-webkit-scrollbar,
body.hide-scrollbar::-webkit-scrollbar,
html.hide-scrollbar ::-webkit-scrollbar {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more