Compare commits

...

3144 commits

Author SHA1 Message Date
Michael Mayer
0cecb5287f Search: Match folder album_path case-insensitively #5724
Folder search lowercases the query term, but album_path is VARBINARY and
compared byte-exact (case-sensitive) on MySQL/MariaDB, so a lowercased
term no longer matched uppercase folder paths. A parent folder still
appeared via its case-insensitive title, while child folders - matchable
only by path - dropped out of the results.

Add a dialect-aware PathLike helper: MySQL converts album_path to a
case-insensitive collation for the LIKE, SQLite and other dialects fall
back to a plain LIKE (SQLite is already ASCII case-insensitive). Only the
folder search filter is affected; byte-exact album_path identity lookups
are unchanged, so emoji and case-distinct folders stay distinct.
2026-07-16 16:53:28 +00:00
Michael Mayer
3f039866ff Sharing: Fix single-item access for shared smart albums #5727
Pictures shared only through a folder, moment, calendar, or region link
have no photos_albums row, so the by-UID and by-hash visibility checks
reported them out of scope and returned "Entity not found" - for example
when downloading a single image from a shared folder. The photo and file
visibility helpers now fall back to the shared album's filter, matching
what browsing and full-album downloads already allow. The fallback runs
only after the cheaper personal-scope check misses and skips regular
albums, so full-access and regular-share sessions add no queries.
2026-07-16 12:10:44 +00:00
Michael Mayer
4946bd2050 Vision: Add OpenAI service_tier via Service.Tier config #5725
Add a string-valued Service.Tier field (OpenAI-scoped) that is sent
verbatim as a top-level service_tier field in the Responses API request
body, reusing the existing Org/Project plumbing. Defaults empty
(backward compatible, OpenAI "auto") and supports ${ENV} expansion.

Bounded exponential-backoff retry on HTTP 429 is a separate follow-up
on the shared client (#5729).
2026-07-16 10:37:15 +00:00
Michael Mayer
5682b3df2e Docker: Allow Ollama and Vision env overrides via .env #5726
Make PHOTOPRISM_VISION_URI/KEY and OLLAMA_BASE_URL/OLLAMA_API_KEY
configurable through .env so Ollama Cloud can be tested without
editing compose.yaml directly.
2026-07-16 10:21:54 +00:00
Michael Mayer
311929ab27 Vision: Disable Ollama reasoning by default, refresh defaults #5728 #5726
- Default Service.Think to "false" for the Ollama engine via a new
  EngineInfo.DefaultThink applied in ApplyEngineDefaults; re-enable
  reasoning explicitly with Service.Think: "true".
- Replace the retired cloud default qwen3-vl:235b-instruct-cloud with
  minimax-m3:cloud, and refresh the self-hosted default from
  gemma3:latest to gemma4:latest.
- Warn on HTTP 404/410 (retired/renamed model) and other 4xx statuses
  in ollamaParser.Parse so failures are diagnosable instead of silent.
- Defensively strip a leading, tag-delimited <think>...</think> block
  from the response body.
- Update tests, regenerate testdata/vision.yml, and refresh package docs.
2026-07-16 10:21:49 +00:00
Michael Mayer
017e24927e Tests: Refine isolated test-folder cleanup and logging #5263 2026-07-12 06:31:52 +00:00
Keith Martin
b6687b6c29
Tests: Improve isolation and add fixes #5263
* Tests: fix random selection of deleted record causing test failure
* Tests: fix test folders being left after test
* Tests: ensure that required records are available
* Tests: make each package execute against it's own testdata folder to ensure no interpackage test failures
* Tests: add unit tests of CleanupTestFolder
* Tests:  Allow defer in TestMain
* Tests: rename testMain to runTestMain
2026-07-12 05:47:21 +02:00
Michael Mayer
79a3d36334 AI: Drop ROCm support from the llama.cpp install script
Only Vulkan and CPU (plus Intel SYCL) builds are installed now. Benchmarks
show Vulkan generally matches or beats the ROCm build for llama.cpp (except
some prompt-processing cases), while ROCm is far more complex to provision:
the prebuilt HIP backend needs a matching ROCm runtime, and consumer/iGPU
architectures such as gfx1150 additionally require HSA_OVERRIDE_GFX_VERSION
because rocBLAS ships no kernels for them. Vulkan drives NVIDIA, AMD, and
Intel GPUs on Linux with none of that setup, so auto-detection now selects
the Vulkan build for any supported GPU and the CPU build otherwise.
2026-07-10 10:40:58 +02:00
Cathie Integra
fb6e17ee69 Index: Resolve S2 cell in XMP branch, downgrade geocoding warn
When an XMP sidecar provides GPS coordinates, call UpdateLocation()
immediately so the S2 cell is resolved and cached in the local DB.
Without this, subsequent re-indexes always triggered a live geocoding
request (even though the coordinates were already known), producing a
spurious error on every re-index pass.

Downgrade the geocoding failure log in photo_location.go and
places/cell.go from Errorf to Warnf: a transient network failure to
the places service is non-fatal (the photo is indexed successfully,
just without a resolved place name) and must not surface as an
indexing error in the test suite.
2026-07-10 10:14:02 +02:00
Michael Mayer
98aa4d24ea AI: Add install-llamacpp.sh for llama.cpp Linux binaries
Installs prebuilt llama.cpp binaries from GitHub releases on AMD64/ARM64,
defaulting to the latest release or an explicit tag. Auto-detects the GPU
(sysfs PCI vendor IDs, lspci/nvidia-smi fallback) and picks ROCm, Vulkan,
or a plain CPU build, with a graceful fallback chain; NVIDIA GPUs get the
Vulkan build since upstream ships no CUDA build for Linux. Extracts into
<destdir>/lib/llama.cpp and symlinks the executables into <destdir>/bin
(the binaries carry RUNPATH "$ORIGIN"). Accelerator overridable via flags
or PHOTOPRISM_LLAMA_ACCEL; optional LLAMA_SHA256 verification.
2026-07-10 10:02:56 +02:00
Michael Mayer
c9362a6720 Docker: Refine smaller-skeleton bashrc setup for all images #5154 #5155
Follow-up to the contributor change that moves shell customization out of
per-user home directories:

- Migrate the resolute, trixie, and questing (+ slim) dev images to the
  shared install-bashrc.sh; the shared create-users.sh now hands users a
  minimal skeleton, so images still writing to /etc/skel/.bashrc would
  otherwise lose their aliases and prompt.
- Restore export PATH="$PATH:$HOME/.local/bin" (needed for claude/gh) in
  the full dev images by writing it to /etc/bash.bashrc; kept out of the
  slim and production images, which never had it.
- Guard the /etc/skel/.config copy in create-users.sh so production images
  without it don't emit a spurious error, and use rm -f /root/.bashrc.
- Fix the install-bashrc.sh header reference and silence an intentional
  SC2016 on the runtime-expanded PS1.
2026-07-10 00:56:15 +02:00
Alexis Lefebvre
44e7ed3f7e feat: use a smaller skeleton when calling useradd
# Conflicts:
#	docker/develop/armv7/Dockerfile
#	docker/develop/bookworm/Dockerfile
#	docker/develop/bullseye/Dockerfile
#	docker/develop/buster/Dockerfile
#	docker/develop/jammy/Dockerfile
#	docker/develop/lunar/Dockerfile
#	docker/develop/mantic/Dockerfile
#	docker/develop/noble/Dockerfile
#	docker/develop/oracular/Dockerfile
#	docker/develop/plucky/Dockerfile
2026-07-10 00:48:46 +02:00
Michael Mayer
1f9909d148 Develop: Make "docker-build" only pull the most important images
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-07-10 00:36:06 +02:00
Cathie Integra
cff0dcf92f Docker: Bump dev base image to develop:260709-resolute 2026-07-10 00:24:01 +02:00
Michael Mayer
c7a292e5a0 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-07-09 17:13:11 +02:00
Michael Mayer
12d043f809 Places: Reuse pooled transport and log geocoding host only 2026-07-09 15:08:40 +00:00
Michael Mayer
d06ea1e19f Rules: Note gettext-lint gate and msgid-trim workflow 2026-07-09 13:57:51 +00:00
Michael Mayer
d33d3f11ab Translations: Trim trailing space in a German catalog string 2026-07-09 12:58:07 +00:00
Michael Mayer
9f6b95d049 Translations: Trim redundant trailing spaces on services help text 2026-07-09 12:03:17 +00:00
Michael Mayer
f864348474 Translations: Restore dropped placeholders in ga, ja, ku, nl, fa 2026-07-09 11:43:01 +00:00
Michael Mayer
6b4dcb09bd Translations: Fix French grammar and recompile stale fr.json
A recent Weblate update changed six French strings in fr.po without
recompiling fr.json, leaving the JSON out of sync. Recompile fr.json to
match, and fix "plutôt qu'au cliquant" -> "plutôt qu'au clic" (invalid
French) in the Open on Hover hint.
2026-07-09 11:26:14 +00:00
Cathie Integra
0eecc6e99b Frontend: Recompile translation JSON 2026-07-09 13:17:46 +02:00
Cathie Integra
6a1dc7d194 Translations: Restore broken placeholder tokens in catalogs 2026-07-09 13:17:46 +02:00
Cathie Integra
d5fb43f3d8 Translations: Add gettext placeholder and whitespace lint script 2026-07-09 13:17:46 +02:00
Weblate
54e258d4eb Weblate: Update frontend translations 2026-07-09 13:05:41 +02:00
Theresa Gresch
543a7c4258 Tests: Adapt tests to changes 2026-07-08 16:13:02 +02:00
Michael Mayer
4acbfd3d1b Frontend: Recompile translation JSON
Recompile the frontend translation JSON files from the current .po
catalogs (the pulled Weblate updates plus the German/French/Hebrew
refinements) via `make gettext-compile`.
2026-07-08 12:34:13 +00:00
Michael Mayer
d08d136ce8 Frontend: Refine German, French, and Hebrew settings translations #5429
- German: use „Bereich" for the Folders hint to match the sibling
  sections, and phrase the Open on Hover hint as an imperative.
- French: switch the new Accessibility and feature hints from informal
  tutoiement to the infinitive/vouvoiement used elsewhere in the UI.
- Hebrew: use the singular imperative for Reduce Motion, „קטע" (section)
  for the Albums hint, and align the Open on Hover hint with the label's
  hover wording.
2026-07-08 12:34:13 +00:00
Weblate
af7e06e5d1 Weblate: Update frontend translations 2026-07-08 14:17:58 +02:00
Ömer Duran
6dc0acac13
Settings: Reorganize UI and add an Accessibility section #848 #799 #5429
* Frontend: Add settings for albums, favorites, folders, and media features

* Frontend: Enhance download settings for files and albums #848

* Frontend: Enhance download settings for files and albums #848

* Frontend: Update album download settings to restrict access to super admins

* Frontend: Add album sorting options to settings for super admins

* Frontend: Update download settings visibility

* Frontend: Refine download settings access control for user roles

* Tests: Add album, folder, moment, state, and month order selection options to page-model

* Frontend: Update access control for super admins in settings to include scope check

* Tests: Add new tests for download name and album order settings persistence

* Tests: Implement new tests for default album sort order persistence in settings

* Frontend: Move default album order settings

* Frontend: Add zoom accessibility option in settings #799

* Frontend: Update download name from "Share Identifier" to "Share Friendly" and refine hints for download options in settings

* Tests: Add new acceptance test for disabling album downloads while allowing file downloads in settings

* Frontend: Improve download options layout and hints

* Frontend: Refactor download options condition in settings page

* Frontend: Implement native zoom control in lightbox component

* Settings: Add Collections tab and move Services to its own page #848 #5429

- Add a super-admin Collections tab after Content holding the album
  Download and Sort Order settings; remove those cards from Content.
- Move Services from a settings tab to a dedicated page
  (page/services.vue) with a search toolbar and a Reload / Learn More
  action menu; link it from the navigation settings menu.
- Implement server-side services search (acc_name filter) with tests.
- De-duplicate the picture sort-order options into a shared
  SortOrderOptions builder in options.js.
- Update acceptance/unit tests and page models to match.

* Frontend: Regenerate translation catalogs #848 #5429

Ran `make gettext-extract` to pick up the new settings strings
(Collections, Features, Disable Downloads, and related messages) so
Weblate can translate them. Existing translations are preserved.

* Frontend: Move lightbox viewport-zoom handling into the view helper

- Move the viewport pinch-zoom lock/restore (disableNativeZoom /
  restoreNativeZoom + savedViewportContent) from lightbox.vue onto the
  View singleton in common/view.js.
- Drive it passively from View.apply() via a disableViewportZoom flag in
  the PLightbox case, alongside hideScrollbar / disableScrolling /
  disableNavigationGestures; lightbox.vue no longer references zoom.
- Make save/restore idempotent and extract the viewport constants.
- Cover the helpers and the apply() wiring in view.test.js.

* Settings: Add Accessibility section to General with Reduce Motion #848 #5429

- Move the page-zoom checkbox out of the feature-flags grid into a
  dedicated Accessibility card (super-admin only) with four toggles:
  Open on Hover, Reduce Motion, Hide Scrollbar, and Allow Page Zoom.
- Add a UI.ReduceMotion flag (defaults false) that toggles an
  html.reduce-motion class via config.setReduceMotion and suppresses map
  fly-to animations non-destructively (util.mapAnimateDuration).
- Make Open on Hover apply live by reading shouldOpenOnHover() through a
  reactive computed in the action/auth/lightbox menus; Zoom and Hide
  Scrollbar reload since they are baked into the server-rendered HTML.
- Reword two feature-grid hints to the "pictures" convention and cover
  the new helpers with Go and Vitest tests.

* Frontend: Regenerate translation catalogs #848 #5429

Ran `make gettext-extract` to pick up the new Accessibility settings
strings (Accessibility, Allow Page Zoom, Open on Hover, Hide Scrollbar,
Reduce Motion, and their hints) and the reworded feature-grid hints.
Existing translations are preserved.

---------

Co-authored-by: Michael Mayer <michael@photoprism.app>
2026-07-08 14:11:36 +02:00
Michael Mayer
a22c99dd12 Frontend: Upgrade Vitest, Vite, browserslist & Vue language server
- @vitest/coverage-v8 ^4.1.9 => ^4.1.10
- @vue/language-server ^3.3.5 => ^3.3.6
- browserslist ^4.28.4 => ^4.28.5
- vite ^8.1.0 => ^8.1.3
- vitest ^4.1.9 => ^4.1.10

Dev dependencies only; NOTICE (prod-only) unchanged.
2026-07-08 00:04:29 +00:00
Michael Mayer
138075fc0a Dependencies: Upgrade klauspost, geo, x/text & x/tools Go modules
- github.com/klauspost/compress v1.18.6 => v1.19.0
- github.com/klauspost/cpuid/v2 v2.3.0 => v2.4.0
- github.com/golang/geo => 20260706204034
- golang.org/x/text v0.38.0 => v0.39.0
- golang.org/x/tools v0.45.0 => v0.47.0 (indirect)

Run go mod tidy and regenerate NOTICE.
2026-07-07 23:57:52 +00:00
Michael Mayer
c9f21cd965 Server: Derive WebDAV proxy test paths from proxy.PathPrefix
TestIsWebDAVPath hardcoded the "/i/" proxy prefix, so it failed when
proxy.DefaultPathPrefix changed. Build the proxy cases from proxy.PathPrefix,
the same value IsWebDAVPath uses, so they track the configured prefix.
2026-07-07 23:47:57 +00:00
Michael Mayer
a693df1eaa WebDAV: Route favorite-flag sidecar errors to the system log #5715
WebDAVSetFavoriteFlag logged sidecar mkdir/write failures at error level on
the UI log stream with the raw error, leaking the absolute sidecar path.
Route them through event.SystemError with clean.Error, matching the request
error handling in the WebDAV logger.
2026-07-07 23:47:57 +00:00
Michael Mayer
7bea2dccfe WebDAV: Route request errors to the system log, not the UI #5715
All WebDAV write-method errors (PUT/DELETE/MOVE/COPY/MKCOL/...) now go to
the console-only system log instead of the in-app errors table and browser
log viewer, because golang.org/x/net/webdav embeds absolute server paths in
its messages. Operators still see full detail in the container/service logs.

A MKCOL against an already-existing collection is a benign probe used by
sync clients such as PhotoSync to test for a directory before creating it;
it returns 405 and is logged at debug rather than as an error.
2026-07-07 23:27:52 +00:00
Michael Mayer
d33bca4f48 Metadata: Fix XMP body serial and add tiff: field fallbacks #2260
Read the standard exifEX:BodySerialNumber property, which ExifTool and
Adobe emit; the previous exifEX:SerialNumber matched no compliant XMP
sidecar and silently fell through to aux:SerialNumber.

Add deprecated TIFF-schema fallbacks still emitted by some writers:
tiff:Software (Software), tiff:ImageDescription (Description), and
tiff:Copyright (Copyright).
2026-07-07 11:44:33 +00:00
Michael Mayer
b7e758c607 PWA: Only emit maskable icons when the variant exists #5696 2026-07-06 10:58:16 +00:00
Ömer Duran
4b33d3bd1a
PWA: Add maskable icons, lang/dir, and install screenshots #5696 2026-06-30 19:53:52 +02:00
Michael Mayer
25b99b3ec4 Convert: Gate RAW render rejection by file format #5673
Apply the RawTherapee stderr rejection (raw.DecoderErrors) only for a
gated set of formats (default .cr3) instead of every RAW format.
RawTherapee prints "Cannot use camera white balance" for any sensor it
cannot read, including bodies whose default-WB render is fine, so for
formats it alone can decode (e.g. .raw, .kdc) the warning-based discard
left nothing to index. CR3 is unchanged: a magenta render warns and
falls back to the embedded preview.
2026-06-30 14:04:59 +00:00
Michael Mayer
6dc3ecbf25 Metadata: Map XMP dc:subject to Subject field, not Keywords #2075 #2260
dc:subject is Adobe's "Keywords" panel, but PhotoPrism's Keywords,
Labels, and Subject fields serve distinct purposes. Route dc:subject to
the descriptive Details.Subject field only (matching the embedded/
ExifTool path, where data.Subject comes from the dc:subject-backed
Subject tag and data.Keywords from IPTC Keywords), never the Keywords
field. Multi-word entries keep their spaces; the value stays searchable
via IndexKeywords and still drives label matching.
2026-06-30 10:12:45 +00:00
Michael Mayer
38b50724f5 Convert: Prefer embedded preview over untrustworthy RAW render #5673 2026-06-30 07:49:32 +00:00
Michael Mayer
9f3d958b02 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-30 01:55:38 +02:00
Michael Mayer
1b572c0da7 Auth: Store session login_at as NULL when no client IP is set #5707 2026-06-29 23:28:12 +00:00
Cathie Integra
b2116154d3 Docker: Bump dev base image to develop:260629-resolute 2026-06-30 01:13:20 +02:00
Michael Mayer
b1a7a5d147 HEIC: Allow install-libheif.sh to upgrade held package #5708 2026-06-29 22:30:23 +00:00
Michael Mayer
50d4256b71 Frontend: Regenerate src/locales/json/fr.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-30 00:25:18 +02:00
Michael Mayer
5eeb0d6291 Convert: Verify RAW previews and prefer djxl for JPEG XL #5673 #5693 2026-06-29 21:59:48 +00:00
Michael Mayer
d330f0e05c Users: Apply 2FA changes for the cluster service principal 2026-06-29 21:59:48 +00:00
Michael Mayer
3e5ea71fb6 Users: Strengthen Add Account and built-in super-admin form gating 2026-06-29 21:59:48 +00:00
Cathie Integra
fd02897278 HEIC: Default install-libheif.sh to v1.23.1 #5708 2026-06-29 23:29:22 +02:00
Cathie Integra
95603b8f64 HEIC: Upgrade libheif from v1.23.0 to v1.23.1 #5708 2026-06-29 22:22:37 +02:00
Weblate
35caddae32 Weblate: Update backend translations 2026-06-28 19:14:37 +02:00
Weblate
fa4596883d Weblate: Update frontend translations 2026-06-28 19:14:10 +02:00
Cathie Integra
75e08934b8 AI: Add GPU/CUDA option to ONNX Runtime install script #5703 2026-06-28 15:53:46 +02:00
Cathie Integra
021bdeb428 Setup: Default to MariaDB 12.3 (LTS) in compose examples #5705 2026-06-28 15:15:27 +02:00
Michael Mayer
71c14fc68b Docs: Update tagline in README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-28 10:36:59 +02:00
Michael Mayer
ba82cefb83 Setup: Add PHOTOPRISM_OIDC_PROMPT to compose & Helm examples #5698
Lists the new OIDC authorization prompt option alongside the other
PHOTOPRISM_OIDC_ settings (in flag order) in the dev compose files and the
Plus Helm chart values/questions. Empty default preserves current behavior.
2026-06-27 12:39:25 +00:00
Michael Mayer
9d0aca64b8 OIDC: Add configurable authorization prompt option #5698
Add PHOTOPRISM_OIDC_PROMPT (--oidc-prompt) to forward the OpenID Connect
"prompt" parameter (login, select_account, consent) on the authorization
request, so a rejected user can re-authenticate or pick another account
instead of being silently signed in again. Unsupported values (including
"none", which would break interactive login) are dropped with a warning;
empty preserves the seamless-SSO default.
2026-06-27 12:35:04 +00:00
Michael Mayer
063f3c1245 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-27 13:41:03 +02:00
Michael Mayer
b1318d57fa Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-27 13:38:53 +02:00
Michael Mayer
f351d5a5a7 Frontend: Recompile translation JSON for new auth messages #5699 #5682 2026-06-27 11:34:54 +00:00
Michael Mayer
0575659c08 Frontend: Render auth error toasts in the current UI locale #5699 #5682 2026-06-27 11:34:54 +00:00
Michael Mayer
a2e8592dd5 Auth: Localize login/session/OIDC error responses via messageId #5699 #5682 2026-06-27 11:34:54 +00:00
Weblate
0293736a08 Weblate: Update frontend translations 2026-06-27 12:29:30 +02:00
Weblate
4c86c71417 Weblate: Update backend translations 2026-06-27 12:29:16 +02:00
Michael Mayer
68a6ad24f4 Translations: Regenerate .po and .pot files from source #5699
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-27 12:27:09 +02:00
Michael Mayer
d081997cff Frontend: Move batch edit dialog close button to toolbar start 2026-06-27 08:19:00 +00:00
Michael Mayer
03c22ca66c UX: Fix 404 page logo text rendering under RTL locales 2026-06-27 08:19:00 +00:00
Michael Mayer
69de3d7a05 Tests: Alias "app.vue" so Portal hooks.test.js resolves the root component 2026-06-26 13:45:38 +00:00
Ömer Duran
b2b1785126
Tests: Add unit tests for recent metadata, auth, and config changes #5697 2026-06-26 14:12:59 +02:00
Michael Mayer
9fe532914d Update tagline in README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-26 09:48:44 +02:00
Michael Mayer
d13b9e50ca Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-25 20:46:45 +02:00
Cathie Integra
16eb3fb708 Frontend: Revert dep bump that broke options.js in prod bundle
Reverts 0182c46bb. The webpack 5.107.2->5.108.0 bump changed prod-bundle
scope-hoisting so option-builders in src/options/options.js (Languages,
TimeZones, StartPages, MapsAnimate) threw "Cannot read properties of
undefined", breaking the login and Settings pages on all editions.
Re-apply the photo-sphere-viewer/tar patch bumps separately.
2026-06-25 20:11:57 +02:00
Michael Mayer
7654e676b7 Frontend: Remove unused babel-plugin-istanbul and dead Karma config #5659
The babel-plugin-istanbul coverage plugin was only wired into the retired karma.conf.js; Vitest measures coverage via @vitest/coverage-v8 (.babelrc has no plugins). Dropping it removes the orphaned @istanbuljs/load-nyc-config -> js-yaml@3 subtree and clears the GHSA-h67p-54hq-rp68 DoS advisory; npm audit now reports 0 vulnerabilities.
2026-06-25 16:29:40 +00:00
Michael Mayer
d2a2597ab6 Users: Centralize Add Account auth field gating in the user model 2026-06-25 16:24:55 +00:00
Michael Mayer
41fdb578b2 Users: Prevent a non-super-admin admin from locking out the super admin 2026-06-25 16:24:51 +00:00
Michael Mayer
0182c46bbb Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-25 18:18:08 +02:00
Michael Mayer
57e4de738e Vision: Fix data race in image classifier during parallel indexing #5694
Indexing workers share one classify.Model whose Run() built tensors into a single shared ImageTensorBuilder buffer with no lock, so concurrent classification corrupted images and produced garbage labels. Pool a per-call builder instead, restoring the pre-#5164 concurrency safety.

Add a concurrent regression test and consolidate the model benchmark.
2026-06-25 15:01:23 +00:00
Michael Mayer
80437299da OIDC: Send and validate a nonce on authorization requests #5695 2026-06-25 16:54:29 +02:00
Michael Mayer
9a25a19824 JPEG XL: Decode natively via libvips with "djxl" fallback #5693
Route JPEG XL through the native libvips path (govips jxlload) like
HEIC/AVIF, keeping the external "djxl" decoder as an automatic fallback
for runtimes whose libvips lacks JPEG XL support.

Decouple format enablement from "djxl": DisableJpegXL now stays enabled
when either the decoder is present or libvips can decode JPEG XL natively.
The libvips capability probe (thumb.JpegXLSupported) is cached and runs
only when no decoder is present, so config introspection on standard
installs (which ship "djxl") does not start libvips.

Add a shared assets/samples/dice.jxl fixture and focused tests for the
native conversion path, the djxl fallback command, and the capability
decision table.
2026-06-25 14:31:10 +00:00
Weblate
a88264df82 Weblate: Update backend translations 2026-06-25 15:47:49 +02:00
Theresa Gresch
cd0deacbc1 Tests: Make acceptance tests more stable 2026-06-25 15:29:11 +02:00
Cathie Integra
9ff36af70c Docs: Update project tagline in README 2026-06-25 15:00:42 +02:00
Michael Mayer
6b485b7308 Frontend: Regenerate src/locales/json/fr.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-24 23:03:31 +02:00
Michael Mayer
6ee98a14ad Auth: Chain RP-initiated OIDC logout on direct /logout entry #5684 2026-06-24 22:52:48 +02:00
Weblate
05669ccdcc Weblate: Update frontend translations 2026-06-24 21:21:20 +02:00
Michael Mayer
8a3c3fb8f1 Tests: Make TestService_Discovery use a local WebDAV server
Service discovery was probing the live https://www.photoprism.app/ and asserting
success, so the test broke when the website migrated to Hugo (no PROPFIND
support). Point it at a local httptest WebDAV-like server and allow the loopback
host via servicesCIDR, making the test deterministic and offline-safe.
2026-06-24 15:31:31 +00:00
Michael Mayer
11c074cb85 Auth: Delegate cluster OIDC logout to the Portal end-session endpoint #5684
On a cluster-OIDC Sign-Out the instance now delegates the Portal session and the
upstream RP-logout to the Portal's end-session endpoint instead of doing them
itself: revokePeerSessions skips the Portal peer's backend DELETE (still clearing
its storage), and DeleteSession skips clearing the OP session cookie when it
returns a providerLogoutUri — otherwise the Portal OP could not resolve the
session (via that cookie) to chain the upstream logout. onLogout now resolves to
the chosen landing URL so the /logout route guard follows the provider logout URL
too. Adds the oidcLogout client-config accessor and an instance.portal session
marker so the Portal peer is identified explicitly rather than by URL shape.
2026-06-24 15:22:04 +00:00
Michael Mayer
50976f427e Auth: Add RP-initiated OIDC logout via PHOTOPRISM_OIDC_LOGOUT #5684 #5433
Sign-out of an OIDC session redirects the browser to the provider's
discovered end_session_endpoint (id_token_hint + absolute
post_logout_redirect_uri) when PHOTOPRISM_OIDC_LOGOUT is enabled, so the
provider SSO session ends and the next login re-prompts. Opt-in (default
off); local/LDAP logout and providers without an end-session endpoint fall
back to local logout.

Adds the shared CE /api/v1/oauth/logout route and OAuthLogoutHandler hook
plus the Portal OP end_session_endpoint advertised in the Portal discovery
document, for Portal builds to serve via the override hook.
2026-06-24 17:21:00 +02:00
Cathie Integra
3f096a592b Links: Use canonical trailing-slash form for website URLs 2026-06-24 17:20:30 +02:00
Michael Mayer
e1c9eafe88 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-24 10:45:53 +02:00
Michael Mayer
95ae2be80c Frontend: Harden i18n positional shim against literal % in translations #5682
interpolatePositional now matches only real Go fmt verb letters and disallows the space flag, so a literal percent in a translated message (e.g. "100% sicher") is not mistaken for a verb and corrupted. Adds a regression test.
2026-06-23 13:30:22 +00:00
Michael Mayer
c5658a053d API: Align i18n.Response Go field names with JSON keys #5682
Rename the Response struct fields to match their json tags (Err to Error, Msg to Message) and the Error() method to ErrorString() to avoid a field/method clash; update callers and tests. JSON wire format is unchanged.
2026-06-23 12:42:57 +00:00
Michael Mayer
fd8448d6de UX: Name message fields messageId/messageParams in i18n payloads #5682
Rename the i18n notification/error envelope fields from id/params to messageId/messageParams across the WS notify Data and the i18n.Response body, so they are unambiguous next to session, log, and correlation ids. Updates the frontend consumers (notify.vue, api.js), tests, swagger, and the event/locales READMEs.
2026-06-23 12:22:30 +00:00
Michael Mayer
2fd9e93247 Tests: Fix label toast assertions after %{name} change #5682
labels.vue now notifies via $gettext("Removed/Added %{name}"); update the expected toast strings to match.
2026-06-23 12:07:01 +00:00
Michael Mayer
f5373ccec6 UX: Render backend error responses in the current UI locale #5682
The i18n.Response envelope now carries the untranslated source id and params; the frontend (api.js) renders them via Tp in the user's UI locale, with the server-rendered error/message as the instance-locale fallback. Common not-found/conflict/bad-request handlers were switched from hardcoded literals and raw err.Error() to Abort/i18n.Message helpers, so they benefit automatically.
2026-06-23 12:06:49 +00:00
Michael Mayer
49c6535c81 Storage: Fix duf path lookup to resolve the containing mount #5683
FindByPath now resolves a path's containing filesystem by longest-prefix match against the raw mount list, instead of the df-style display filter that hides overlay/pseudo roots. This fixes PathInfo/Free/StorageLow for paths like "/" whose mount is hidden (e.g. a container overlay root), which previously resolved to an arbitrary masked tmpfs.
2026-06-23 11:18:13 +00:00
Michael Mayer
a12d287c19 Docs: Document per-user notification localization in READMEs #5682
Describe the event *Msg structured payload and frontend per-user rendering in the event and backend-locales READMEs; fix a stale go-generate path (/internal/i18n to /pkg/i18n).
2026-06-23 09:23:31 +00:00
Michael Mayer
9ec70731e2 UX: Fix notification messages that bypassed translation #5682
Route user-facing notifications through extractable $gettext (aliased ctx.$gettext is not extracted), wrap hardcoded English strings, replace concatenation with interpolation, and drop redundant English backend label toasts already covered by localized frontend ones.
2026-06-23 09:06:56 +00:00
Michael Mayer
9ecdb0ae26 UX: Render backend notifications in the current UI locale #5682
Backend *Msg helpers now publish the untranslated message id and params alongside the rendered fallback; the frontend translates the id and applies a positional-placeholder shim so notifications render in each user's UI language.
2026-06-23 09:06:46 +00:00
Michael Mayer
544a4cfef2 Lightbox: Handle each Escape press once in face-marker mode #5672 2026-06-23 10:51:21 +02:00
Michael Mayer
a930ae24d7 Assets: Normalize locales/he/default.po
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-23 10:20:08 +02:00
Michael Mayer
deb2a5b71d Weblate: Update frontend translation .json files #5681
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-23 10:19:07 +02:00
Weblate
2f70683d0d Weblate: Update frontend translations 2026-06-23 10:18:02 +02:00
Michael Mayer
bf8e559091 Frontend: Update .po, .pot, and .json translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-23 10:11:52 +02:00
Michael Mayer
bc33917ac7 Frontend: Update .json translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-23 09:43:43 +02:00
Weblate
7a8fc6d01e Weblate: Update frontend translations 2026-06-23 09:42:48 +02:00
Michael Mayer
0954426eb4 Frontend: Update locales.js & regenerate .po and .pot translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-23 09:29:12 +02:00
Cathie Integra
d3d9bbe09f Helm: Bump Plus chart to 1.1.2 and refine DB password secret #5661
Skip storing the inline database password in the chart-managed secret when
database.passwordSecretName references an external secret, fix the env-var
template formatting, document precedence, and surface the new values in the
Rancher questions form.
2026-06-23 08:01:48 +02:00
Brodie Kurczynski
4a9fc0314e
Helm: Allow referencing external secret for database password #5661
* Helm: Allow referencing external secret for database password
* Helm: Document database.passwordSecretName in values and README
2026-06-23 07:58:19 +02:00
Ömer Duran
4443c892ef
UX: Refine face-marker overlay performance and interaction #5672 #5677 2026-06-23 07:38:23 +02:00
Michael Mayer
b61345584b Frontend: Document webpack to Vite migration plan #5679
Add a README section mapping the current webpack build to its Vite
equivalents, and record the vue3-gettext 4.x ESM-only blocker (webpack
cannot resolve `fs` from pofile) that motivates the migration.
2026-06-22 20:17:34 +00:00
Michael Mayer
8b0cf318b0 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-22 21:47:20 +02:00
Michael Mayer
83e6796e40 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-22 21:46:50 +02:00
Michael Mayer
8fea28399b Weblate: Update JSON translation file #5674
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-22 21:41:14 +02:00
Weblate
baadd6940e Weblate: Update frontend translations 2026-06-22 21:38:26 +02:00
Weblate
bc20d156aa Weblate: Update backend translations 2026-06-22 21:35:55 +02:00
Michael Mayer
c650f38f18 Docs: Clarify checking off met Acceptance Criteria in GitHub issues 2026-06-18 12:40:54 +00:00
Michael Mayer
1350d9fe85 RAW: Fall back to embedded JPEG previews for unsupported files #5673 2026-06-18 12:29:55 +00:00
Michael Mayer
74339513f4 Lightbox: Native icon buttons, contain inline-editor Enter #1307 #4966 2026-06-18 10:33:16 +00:00
Michael Mayer
1854e69094 Gettext: Regenerate .po and .pot translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-18 11:47:42 +02:00
Michael Mayer
63e0f02727 Lightbox: Pause slideshow on any content interaction #352 #5623 #5671 2026-06-18 11:43:15 +02:00
Theresa Gresch
acb04f2a05 Tests: Improve acceptance tests 2026-06-18 11:31:03 +02:00
Weblate
790181a743 Weblate: Update backend translations 2026-06-18 11:15:04 +02:00
Ömer Duran
3b21cf111b
Lightbox: Stop slideshow on sphere gestures #352 #4718 #5623 #5671 2026-06-18 11:13:59 +02:00
Michael Mayer
d52554fc50 Lightbox: Add 16K thumbnails and refine 360° viewer routing #5669 #5623 2026-06-17 04:12:41 +00:00
Michael Mayer
4ab00fa32d Config: Raise thumbnail and conversion size limits to 16K #5669 2026-06-17 04:12:40 +00:00
Michael Mayer
43506ad883 Thumbs: Add 16K (15360px) fit size for photos and videos #5669 #5623 2026-06-17 04:12:40 +00:00
Michael Mayer
f894157191 Docs: Update LICENSE notice files #352 #4718 #5623 2026-06-17 03:38:36 +02:00
Michael Mayer
6006e08a38 Frontend: Update deps in package.json and package-lock.json #352 #4718 #5623 2026-06-17 03:29:55 +02:00
Ömer Duran
3ea547a564
Lightbox: Add support for 360° photos and videos #352 #4718 #5623
* Lightbox: Add 360° photo and video sphere viewer support

Wires Photo Sphere Viewer v5 into the lightbox for equirectangular
media. Backend detects UsePanoramaViewer and IsPhotosphere markers
alongside ProjectionType, and exposes Panorama + Projection in the
viewer / search result DTOs so the frontend can dispatch on the
projection type. The renderer (ThreeJS + PSV core + video plugin +
equirectangular video adapter) is lazy-loaded into a dedicated
webpack chunk so the base bundle is unchanged for users with no
360° media. PhotoPrism's existing lightbox controls drive the
underlying HTMLVideoElement that the PSV adapter creates for 360°
videos. Includes Vitest coverage for the sphere helper and the
lightbox dispatch, plus a TestCafe smoke spec and three new
ExifTool metadata fixtures.

* Lightbox: Fix 360° controls leak, hide zoom button, add sidebar icon

* Lightbox: Fix 360° touch panning and navigation arrows

* Lightbox: Fix fast swipe switching photos on 360° slides

Suppress PhotoSwipe swipe/drag navigation at its source via the dispatched pointer hook while a sphere slide is active, since the per-element gesture trap is outrun by a fast swipe whose pointer leaves the sphere container (touch-capable Windows). UI controls stay excluded so buttons and arrows still navigate.

* Lightbox: Route only equirectangular media to the 360° viewer

Routing was based on the loose photo_panorama flag for videos, which is also
true for cubemap and merely-wide (aspect > 1.9) videos, so non-equirectangular
media wrongly opened, distorted, in the sphere viewer. Route strictly on the
equirectangular projection for both photos and videos. Surface the video file's
projection in the viewer DTO via Photo.MediaProjection() (the primary search row
is a poster JPEG with no projection). Add an MP4 metadata-detection test.

* Lightbox: Open tagless 2:1 360° videos in the sphere viewer

Many 360° videos carry no projection tag PhotoPrism can read, so strict
equirectangular-projection routing left them in the flat player. Fall back to
equirectangular's defining 2:1 frame for panorama-flagged videos without a
projection, via is360Equirectangular() in common/sphere.js, while cubemap and
ultrawide (~2.35:1) clips stay flat.

* Tests: Make the 360° sphere video test assert instead of skipping
2026-06-17 03:26:25 +02:00
Michael Mayer
bf081bd68b Users: Add canEnableLogin() to gate the Web Login toggle 2026-06-17 00:26:18 +00:00
Michael Mayer
a2e708e7ab Meta: Update go-mp4, regenerate NOTICE, fix XMP doc spelling #2260 #5563
Bump abema/go-mp4 to v1.7.1 (only outdated direct dependency) and tidy
go.sum, pruning stale checksums left by the XMP sidecar merge. Regenerate
the license NOTICE for the updated dependency.

Use US-English spelling in the new XMP sidecar comments and tests, and
drop a specs/ reference from internal/meta/README.md so the public package
doc has no link into the private subrepo. Regenerate dialect_mysql.go from
SQL.
2026-06-17 00:14:33 +00:00
Ömer Duran
86efc1c982
Index: Improve support for metadata in XMP sidecar files #2260 #2828 #5563
* Meta: Add XMP sidecar fixture corpus for reader rewrite #2260
* Meta: Replace XMP sidecar reader with antchfx/xmlquery #2260
* Meta: Add XMP sidecar reader test suite #2260
* Meta: Assert XMP GPS extraction on Apple/Adobe sidecars #2828
* Meta: Apply XMP sidecar metadata to photo and primary file #2260
* Meta: Resolve XMP sidecar time zone via shared helper #2260
* Meta: Derive panorama & caption keywords on XMP sidecar reads #2260
* Meta: Assert XMP sidecar GPS override and malformed-file handling #2260
* Meta: Tidy XMP sidecar reader comments and reuse logName local #2260
* Meta: Fix XMP sidecar capture-time priority OffsetTime handling #2260
* Meta: Address XMP sidecar review feedback #2260
2026-06-17 01:53:28 +02:00
Michael Mayer
ee0b1a616a Search: Sort geo "near" results by distance to the photo #5643
A "near=<uid>" geo search set the S2 cell but left the form lat/lng at
zero, so results sorted by distance from the (0,0) origin instead of
the referenced picture. Use the picture's own position in the ORDER BY,
falling back to time order when it has no usable coordinates.
2026-06-16 23:19:46 +00:00
Michael Mayer
50e1e595de Places: Group coincident map photos by screen proximity #5643
Past the cluster zoom threshold, group un-clustered photo features by
projected screen distance instead of exact coordinates, so pictures at
the same place stack into one counter marker even when their stored
coordinates differ slightly (GPS jitter, tile quantization). Key each
stack by a stable member UID and open it by its bounding box so the
panel lists exactly those pictures.
2026-06-16 23:19:37 +00:00
Michael Mayer
bad538e51b Index: Do not assign OriginalName to indexed files #5668
Stop deriving a file's OriginalName from cached metadata during indexing.
The ExifTool JSON cache is keyed by content hash, so a renamed file was
re-indexed against the old name and surfaced it as OriginalName, making
cards show a stale name while the sidebar showed the current one.

OriginalName is now set only from the explicit import original name, so
plain-indexed files no longer carry one and imported files are unaffected.
2026-06-16 17:21:56 +00:00
Michael Mayer
74a95fc748 ACL: Generate CLI role & auth-provider help from role tables #5667
Add pkg/txt.JoinOr plus acl.RolesCliUsageString and UserRoleUsageFor so the users/clients --role and --auth help derive from the role tables instead of hand-maintained literals, filtering the app/uploader aliases and visitor. Each edition lists its own roles; federatable contexts (LDAP, OIDC group-role, cluster grants) use ClusterInstanceRoles.
2026-06-16 11:57:44 +02:00
Cathie Integra
8e219a006c Setup: Remove pre-rendered pkg/linux/README.html
dl.photoprism.app now renders README.html on demand from README.md
(Caddy/goldmark), so the hand-maintained HTML copy is redundant.
2026-06-16 11:36:21 +02:00
Cathie Integra
f1d5ae2ba2 ACL: Add ClusterInstanceRoles source of truth for group-role help 2026-06-16 09:32:15 +02:00
Cathie Integra
d78966141a Build: Add tag-release.sh and tag-release Makefile target 2026-06-16 07:45:40 +02:00
Michael Mayer
f31db8a03b Tests: Add missing $util.shouldOpenOnHover mock to people-tab suite #5666
PActionMenu reads $util.shouldOpenOnHover() in data(); the suite only
passed because PActionMenu was stubbed. Complete the $util mock so the
tests no longer depend on that stub to hide the call, which otherwise
fails with "this.$util.shouldOpenOnHover is not a function".
2026-06-16 03:12:34 +00:00
Michael Mayer
2f94755af6 People: Seed type-ahead cache on name save to fix stale suggestions #5666
Naming faces in quick succession left the second new name out of the
people type-ahead until a manual reload, because eviction relied on the
subjects WS event, which can lag the next focus-triggered read.

Marker.setName() and Face.setName() now seed the shared people cache with
the saved name so it is suggestible immediately; the rename path seeds via
recognized.vue (Subject.update() also backs hide/show, so it can't host the
seed). Harden the cache itself: get() snapshots an epoch so a fetch that
resolves after an evict/upsert no longer clobbers the slot with stale data,
and upsertPeople merges idempotently. Reload new.vue suggestions on focus
to match the photo people tab.
2026-06-16 02:57:58 +00:00
Michael Mayer
cbc548d771 Frontend: Revert menu/action icons back to vertical dots
see c13c260

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-16 04:02:33 +02:00
Michael Mayer
bf14649ce4 Places: Stack photos at identical coordinates on the map #5643
Group un-clustered geo features by exact coordinates so that pictures
sharing a spot render as one stack marker with a counter instead of
overlapping, hidden duplicates once zoomed past the cluster threshold.
Clicking such a stack opens the location's collection panel rather than
a radius search that surfaced unrelated nearby photos.

Key the embedded photo list by latlng so an already-open panel re-runs
its search for the newly selected cluster or stack.
2026-06-16 01:56:03 +00:00
Michael Mayer
fe0a59a138 Users: Exclude remote LDAP accounts from canHavePassword() 2026-06-16 00:41:34 +00:00
Michael Mayer
85d58f7cbe Users: Add canHavePassword() to gate password change actions 2026-06-16 00:30:13 +00:00
Michael Mayer
75a5e1ee0b Auth: Log anonymous API requests at debug level instead of warning #5647
Only warn when a request presents a token that is rejected; requests
without any credentials (e.g. the web app loading public config before
login) are routine and now logged at debug level, reducing log noise.
2026-06-15 23:56:56 +00:00
Michael Mayer
c45ee6e54f Auth: Revoke derived sessions & gate app passwords by login state #5647
- Add scoped session revocation (RevokeSessions / RevokeDerivedSessions)
  shared by the user-update API and the CLI: a privilege-level change now
  revokes logins and app-password-derived sessions while keeping the app
  passwords themselves, so configured devices keep working.
- Identify app-password-derived sessions by auth_method "session".
- Deny app passwords on the REST API when the account cannot log in
  (DenyLogIn); WebDAV access stays governed by CanUseWebDAV.
- Reduce the WebDAV auth cache expiration to one minute.
- Add IsSystemOrInvalid; allow deleting the initial admin account and skip
  re-initializing a deactivated or deleted admin in InitAccount.
- Move session-revocation scopes to pkg/authn and extend tests.
2026-06-15 23:41:01 +00:00
Michael Mayer
aff25636b5 People: Fix name-save re-entry and avoid full-list refetch #5666
Guard recognized.vue onSave against re-submission while the people cache
resolves by setting busy before the async lookup. Drop updatePersonList so
Browse Pictures / Set Cover no longer evict and refetch the whole people
list; the name combobox reloads suggestions on focus and WS events keep
the cache current. Make the people-tab test seed via a mocked getPeople.
2026-06-15 16:50:35 +00:00
Michael Mayer
997ff2e70d People: Load name suggestions from typeahead cache #5666
Move the people name list out of the client config into the shared
typeahead cache (getPeople, backed by GET /api/v1/subjects), matching
labels and albums. Consumers load suggestions on demand and the cache
evicts on people.* / subjects.* events and clears on logout; the
config.js people machinery is removed and ClientConfig keeps only
count.people for the navigation badge.
2026-06-15 14:38:04 +00:00
Michael Mayer
6addeaa7a4 People: Scope client config people list to authorized roles #5666
Groundwork for the people type-ahead cache: include the people list and
count in the client config only for roles that may view or search people,
and omit the list from the global config.updated broadcast. Clients load
it via GET /config and keep it current through people.* events.
2026-06-15 13:45:38 +00:00
Michael Mayer
a3f9df12ca Tests: Fix cleanup album revert helper for deleted albums #5646
helperAfterEach reverted photos before restoring albums, so re-adding a
photo to an album a test soft-deleted targeted a dead UID, 404'd, and
cascaded into helperFailures. Determine album changes first so the photo
loop can skip albums revertAlbums restores (recreated foreign-owned ones
get a new UID), and tolerate 404 on add-to-album.
2026-06-15 13:04:25 +00:00
Michael Mayer
2fd0ed8631 Events: UID-only camera/lens/country payloads & people refetch #5663 #1307
Make the cameras/lenses/countries content-channel events publish only a
stable identity ([]string of slug or ISO code) instead of full entity
models, matching the UID-only invariant of every other content channel.
The update path no longer republishes count.* (an edit does not change
the count).

Restore surgical people updates: onPeople refetches only the affected
people by UID via Subject.search (refetchPeople) and upserts them in
place instead of forcing a full client-config reload (a #1307 regression).

Document the dormant folders.*/faces.* subscribers (no publisher, not
forwarded) and fix the misleading payload example in the event README.
2026-06-15 11:37:26 +00:00
Michael Mayer
1b2ce048b2 Frontend: Update axios, vitest, playwright & coverage-v8
Pin axios 1.18.0 (security-hardening minor: strips sensitive headers on cross-origin redirects, rejects malformed http/https URLs, tightens prototype-pollution defenses; no breaking changes). Bump vitest and coverage-v8 to 4.1.9, playwright to ^1.61.0. OSV-Scanner clean for both ecosystems.
2026-06-15 10:23:12 +00:00
Michael Mayer
0e79cf9eca Backend: Update golang/geo and refresh NOTICE
Bump golang/geo to 20260612074446 (same module license). go mod tidy also drops a stale golang.org/x/net v0.55.0 checksum.
2026-06-15 10:23:07 +00:00
Michael Mayer
2c278cbd96 Import: Fix data race in import destination settings #5607 #5652
GetDest() lazily wrote the shared ImportSettings.Dest on every call, so
parallel ImportWorker goroutines raced on it. Make GetDest side-effect
free and normalize an invalid stored pattern once in Settings.Propagate.

Also align the per-hash indexing lock added in #5652 with code style.
2026-06-15 09:58:52 +00:00
Kevin Nowald
4f341768e4
Index: Serialize indexing of byte-identical files to avoid duplicates #5607 #5652 2026-06-15 11:31:49 +02:00
Weblate
f88a870379 Weblate: Update backend translations 2026-06-15 11:28:47 +02:00
Michael Mayer
8422fb8ddd Locales: Regenerate backend translations for #5663 2026-06-15 09:25:44 +00:00
Michael Mayer
bc327016ad Metadata: Add Camera Make and Model updates via CLI & API #5663 #5656
Mirror the lens make/model editing surface for cameras: entity UpdateMakeModel/SaveForm, form validation, query, search, the GET/PUT /api/v1/cameras endpoints, and the cameras CLI command, plus a cameras ACL resource and scope.

Also tidy the lens surface for parity: self-validating SaveForm, empty make/model guard, X-Count search header, service-role grant, the empty-id/slug docs, and order cameras before lenses everywhere.
2026-06-15 09:25:44 +00:00
Keith Martin
7c6546ce19
API: Search X-Count header for Labels and Services #5649
* API: Add X-Count response headers for services and labels.
* API: update swagger annotations for response headers
2026-06-15 10:00:08 +02:00
Keith Martin
c3eda657fd
Metadata: Add Lens Make and Model updates via CLI & API #5644 #5656
Adds the ability to override a lens's Make/Model (e.g. fixing Pentax lenses that ExifTool decodes as `4 38`) via a new photoprism lenses update CLI command and a `PUT /api/v1/lenses/:id endpoint`, plus a `GET /api/v1/lenses` search endpoint, a new lenses ACL resource, and an lenses ls list command.
2026-06-15 09:37:32 +02:00
Michael Mayer
41369dd5ce Tests: Fix duplicate testIDs and inverted reversion logic #5646 2026-06-15 07:11:00 +00:00
Keith Martin
3a4140b686 Tests: add ability to run the reversion tests, remove outdated config, remove console.log and mark test as skipped due to inability to test 2026-06-15 08:53:33 +02:00
Keith Martin
389b361a25 Tests: Improve test logging (when SHOW_LOGS is true in environment 2026-06-15 08:53:33 +02:00
Keith Martin
541c554206 Tests: Fix issue with NotYetExisting being clicked due to middle of dialog box selection issue 2026-06-15 08:53:33 +02:00
Keith Martin
b8a2091e6c Tests: Performance improvements and utilisation of reversion capabilities 2026-06-15 08:53:33 +02:00
Keith Martin
592a9958e1 Tests: Implement beforeEach, afterEach and before for after each test change reversions 2026-06-15 08:53:33 +02:00
Keith Martin
9ca202b65a Tests: Add Reversion capability and tests thereof 2026-06-15 08:53:33 +02:00
Keith Martin
c7afdf09dd Tests: Enable elapsed time logging for each acceptance test 2026-06-15 08:53:33 +02:00
Michael Mayer
e88751a501 Config: Add bloom, flower, ring & shutter app icons #5662
Adds four selectable app-icon variants with optimized SVGs and full PNG size sets. bloom and ring use a round canvas like logo; flower and shutter use the rounded-square canvas. Updates the frontend icon resolver, app-icon help text, and config tests, and strips editor data-name attributes from the existing icons.
2026-06-15 06:29:43 +00:00
Michael Mayer
9605d87731 Tests: Isolate reaction redaction subtest from mutation fixtures 2026-06-14 16:38:34 +00:00
Michael Mayer
b24e84f5f5 Frontend: Upgrade Vitest to v4 and Vite to v8 to drop esbuild #5659 2026-06-14 16:15:51 +00:00
Michael Mayer
9f373a909c Frontend: Update deps in package.json and package-lock.json 2026-06-14 17:43:11 +02:00
Michael Mayer
c6cab2856d Photos: Limit by-UID label, marker & file edits to the session scope #1307
Single-photo label add/remove/update, marker create/update/clear, file
unstack, orientation, and delete now apply the same shared-scope
visibility predicate as photo search and update, so by-UID and by-hash
edits stay consistent with album and photo updates and never act on
content outside the session's shared view. File-scoped handlers gate on
the resolved file's owning photo. Full-access sessions skip the check
with no database query via PhotoSessionSeesEverything.
2026-06-14 15:37:57 +00:00
Michael Mayer
a9f5996b43 Frontend: Update JSON translation files #5658
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-14 16:13:43 +02:00
Weblate
748e60c6dd Weblate: Update frontend translations 2026-06-14 16:12:59 +02:00
Michael Mayer
0f2629a11f Frontend: Regenerate translation catalogs 2026-06-14 14:08:13 +00:00
Michael Mayer
015c4efdb7 UX: Fix active-item contrast in the data-table items-per-page select
VDataTable.color is forwarded only to the footer, where it sets the
items-per-page select's itemColor; "background" rendered the selected
option as low-contrast text-background. Use surface-variant to match the
regular <v-select> active color across all themes (it does not theme the
table — VDataTable/VTable never read color).
2026-06-14 14:05:08 +00:00
Weblate
9d1f9017c3 Weblate: Update frontend translations 2026-06-14 16:03:35 +02:00
Michael Mayer
6ca27c827b Cluster: Add GroupsSrc to the node DTO for group-config provenance 2026-06-14 12:06:28 +00:00
Michael Mayer
0b0efaeddd Auth: Replace OIDC login error alert with the notification toast 2026-06-14 10:24:13 +00:00
Michael Mayer
ae1069b0c4 UX: Remove border-radius from .v-avatar.nav-logo in navigation.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-14 11:22:41 +02:00
Cathie Integra
38821507eb Config: Add oidcEnabled and ldapEnabled client config helpers 2026-06-14 10:46:58 +02:00
Cathie Integra
5aae042e2b Docker: Skip "cgroupfs-mount" when no apt install candidate exists 2026-06-13 17:08:46 +02:00
Michael Mayer
e1bf7096c8 Cluster: Accept all instance roles in group config, tolerate spaces 2026-06-13 12:54:54 +00:00
Michael Mayer
974321b8a1 Cluster: Re-register node config on restart via OAuth credentials 2026-06-13 12:54:48 +00:00
Michael Mayer
e832784856 Users: Prevent disabling own super admin status and web login 2026-06-12 20:36:35 +00:00
Michael Mayer
e308fd7b58 Auth: Land cluster sign-out on the Portal login without return_to 2026-06-12 19:56:44 +00:00
Michael Mayer
9f9fce0976 Tests: Update stale portal paths after frontend URI change 2026-06-12 19:56:38 +00:00
Michael Mayer
d594edd5de Cluster: Declare per-node group config via instance env/flags 2026-06-12 18:52:54 +00:00
Michael Mayer
d091958a60 Cluster: Collect OIDC groups at login for group-based admission 2026-06-12 16:08:38 +00:00
Cathie Integra
babb44115f HEIC: Build libheif archives for Debian trixie too #5653 2026-06-12 09:05:27 +02:00
Cathie Integra
b9e6158557 Docker: Bump dev base image to develop:260611-resolute 2026-06-11 18:42:54 +02:00
Cathie Integra
d25713867f HEIC: Bump libheif .deb build targets to v1.23.0 #5653 2026-06-11 18:19:15 +02:00
Michael Mayer
ebf4a88183 Tests: Add unit tests for label and subject change notifications #1307 2026-06-11 17:54:02 +02:00
Michael Mayer
ae9a10431a Frontend: Add User isCurrentUser, isAdmin & isClusterAdmin helpers 2026-06-11 15:49:30 +00:00
Michael Mayer
d26412bcca Auth: Normalize a super admin's role to the running edition 2026-06-11 15:49:30 +00:00
Michael Mayer
7486982342 Events: Refactor entity change notifications for sharing features #1307 2026-06-11 15:40:57 +00:00
Cathie Integra
3930bc7f4b HEIC: Default install-libheif.sh to v1.23.0 #5653 2026-06-11 13:37:57 +02:00
Cathie Integra
7b623997ec HEIC: Upgrade libheif from v1.22.2 to v1.23.0 #5653 2026-06-11 12:35:50 +02:00
Michael Mayer
bdd2a468bd Vision: Bound the service API response read size 2026-06-11 10:02:17 +00:00
Michael Mayer
e8a04a7d4f JWT: Bound the JWKS response read size 2026-06-11 10:02:17 +00:00
Michael Mayer
0f2de0fc15 WebDAV: Bound sync download size to the originals limit 2026-06-11 09:51:36 +00:00
Michael Mayer
487b0c0ec3 Http: Recognize additional reserved IPv4 ranges 2026-06-11 09:37:40 +00:00
Michael Mayer
71a82a9ac9 Auth: Refine passcode recovery code comparison 2026-06-11 09:37:40 +00:00
Michael Mayer
08945d25d7 Frontend: Resolve theme asset icons by basename or /_theme path
themeAssetUri now accepts a bare filename (logo.svg, the recommended
form since the theme author can't get the mount path wrong) as well as a
root-relative /_theme/... path, resolving either against the base URI so
they load on path-prefixed deployments. Absolute, protocol-relative, data,
and already-prefixed values pass through. Memoized via memoize-one (the
base URI is fixed once the config is loaded).
2026-06-11 10:46:14 +02:00
Cathie Integra
81eccd7647 Build: Install distribution libvips-dev when recent enough, gate PPA 2026-06-11 09:57:46 +02:00
Michael Mayer
b6e8ad2d60 WebDAV: Limit PUT upload size to the configured originals limit
Cap the WebDAV PUT request body at OriginalsLimitBytes when an originals limit is configured, so a single upload cannot stream an unbounded body to disk past the per-file ceiling; no-op when unlimited. Adds a load-bearing regression test.
2026-06-10 20:40:28 +00:00
Michael Mayer
d3a94bb8a8 Auth: Keep the deep-link target on a manual OIDC sign-in
onOidcLogin arms the per-tab OIDC attempt guard instead of the post-login redirect-loop guard, so an authenticated return within the loop window resumes the stored deep link or Portal return_to rather than discarding it. Updates the login spec test to pin the guard choice.
2026-06-10 20:08:36 +00:00
Michael Mayer
5c6e30260f Photos: Test that in-scope reactions are redacted for shared sessions
Add a guest regression case asserting the like endpoint returns an in-scope picture with identifying metadata stripped, so dropping the per-session redaction call fails a test rather than regressing silently.
2026-06-10 19:24:29 +00:00
Michael Mayer
856600cd02 Photos: Scope photo reactions to the session's shared view
Apply the same per-session visibility gate and response redaction the photo read and update endpoints already use, so the favorite (like/dislike) routes return only what the session is entitled to see. Adds guest regression subtests for both routes. #1307
2026-06-10 18:57:11 +00:00
Michael Mayer
014f5752f4 Setup: Fix DigitalOcean firewall status detection in check.sh
The status checks captured redirected command output, so the csf and firewalld branches never evaluated correctly (firewalld was reported active unconditionally). Use systemctl is-active --quiet instead.
2026-06-10 18:25:05 +00:00
Michael Mayer
e232ea7de7 Build: Verify SHA-256 checksums when installing s6-overlay & yt-dlp
Stage each download in a temporary file and verify it against the SHA-256 published by the upstream release (s6-overlay per-asset .sha256, yt-dlp SHA2-256SUMS) before installing. Abort on mismatch and warn when no manifest is published so older pinned tags still install.
2026-06-10 18:25:05 +00:00
Michael Mayer
88321bcda9 Docker: Remove unused goproxy module-proxy image and build target
The goproxy caching module proxy was a temporary workaround for build rate limits that no longer apply, and nothing references the published image (no compose service, CI step, or GOPROXY target).
2026-06-10 18:24:59 +00:00
Michael Mayer
1ca21007b3 Build: Update Go toolchain to 1.26.4 and refresh x/net and x/sys
Bumps the go.mod toolchain directive and the dummy OIDC fixture to
go1.26.4, clearing the GO-2026-5037/5038/5039 stdlib advisories. Updates
golang.org/x/net to v0.56.0 (NOTICE regenerated) and the fixture's
golang.org/x/sys to v0.46.0. osv-scanner --recursive returns zero
advisories and the full Go suite passes.
2026-06-10 18:06:19 +00:00
Michael Mayer
8b09cfe76e Photos: Limit by-UID and batch photo edits to the session scope
Single-photo update/approve/set-primary and batch archive/restore/approve/private/delete now apply the same shared-scope visibility predicate as photo search, so by-UID and bulk edits stay consistent with album updates and never act on content outside the session's shared scope. Visibility is evaluated against both the client and user role for client sessions. Full-access sessions skip the check with no database query via PhotoSessionSeesEverything / SelectedPhotoUIDsForSession.
2026-06-10 19:49:27 +02:00
Michael Mayer
22c1789c14 WebDAV: Harden joinUnderBase against drive-letter and backslash paths
Normalize separators, reject drive-letter prefixes, and verify
containment with filepath.Rel instead of a string prefix, matching the
pkg/fs ZIP safe-join. Extend TestJoinUnderBase to mirror TestSafeJoin
coverage and lock the handler surface via WebDAVFileName.
2026-06-10 17:44:13 +00:00
Michael Mayer
b59ebb994b Frontend: Resolve theme icon paths against the base URI
A theme-provided icon (theme variables.icon, e.g. /_theme/logo.svg) was
used verbatim, so on a path-prefixed deployment the browser requested it
without the /i/<node> base and got a 404 (the custom logo silently fell
back). Resolve it through a themeAssetUri helper in getIcon/getLoginIcon;
absolute, protocol-relative, data, and already-prefixed paths pass through
and root deployments are unaffected.
2026-06-10 19:02:34 +02:00
Michael Mayer
8c5e29771b Frontend: Upgrade axios from 1.16.1 to 1.17.0
Security-hardening and bug-fix minor release; no breaking changes for
our usage. Keeps the exact pin (no caret) per the high-risk-package
policy. Verified with make audit, OSV-Scanner, build-js, and test-js.
2026-06-10 16:55:39 +00:00
Michael Mayer
4b7565b3ac Auth: Show OIDC sign-in errors persistently and arm the loop guard
An OIDC sign-in failure (e.g. a cluster 'no access to this instance'
denial) was shown only as a transient toast the user could miss and
retry into a denial loop. Render it as a persistent, dismissible alert
on the login form instead, driven by the existing session.error bridge.
Also mark the redirect-loop guard when the user clicks the OIDC button,
so a bounce-back is recognized like the /login route guard's auto-redirect.
2026-06-10 16:22:42 +00:00
Michael Mayer
0379692a46 OIDC: Surface account-collision reconcile hint and add --auth-issuer
When an OIDC login matches a pre-existing non-OIDC account, log a
specific operator remedy (the exact 'users mod --auth oidc --auth-id'
command) to the audit and login-error logs instead of a bare provider
mismatch; the user-facing page stays a generic credentials error so the
account is not disclosed. Add a 'users mod --auth-issuer' flag so the
documented manual reconcile can pin the OIDC issuer, scoping the link to
that provider instead of matching any issuer with the same subject.
2026-06-10 15:31:34 +00:00
Michael Mayer
a7ee3c2e19 Config: Add PHOTOPRISM_SITE_NAME to compose examples and Helm charts
Also align the SITE_* inline doc comments with the CLI flag help.
2026-06-10 14:28:50 +00:00
Michael Mayer
785ae60a9d API: Add SiteName field to the generated swagger.json 2026-06-10 14:28:33 +00:00
Michael Mayer
f29413c7eb Tests: Replace customer names with neutral placeholders
Use "Acme Media" instead of real customer names in the SiteName and node DisplayName test fixtures.
2026-06-10 14:28:33 +00:00
Michael Mayer
6f5ffe7c2b Frontend: Add siteName to the client config test fixture 2026-06-10 14:28:33 +00:00
Michael Mayer
37116057b7 Frontend: List the Portal first in the instance switcher
listReachableInstances orders peers by ascending base-path so the Portal (origin root "/") leads, then co-located instances by path.
2026-06-10 14:28:33 +00:00
Michael Mayer
2b94975eb5 Config: Improve site option descriptions in CLI flag help 2026-06-10 14:28:33 +00:00
Michael Mayer
245ecc565e Config: Prefer SiteName for app name and site title
AppName() resolves to an explicit AppName, then SiteName (SITE_NAME), then SiteTitle. SiteTitle() falls back to SiteName when neither a SiteTitle nor an AppName is set, so an instance branded only via SITE_NAME stays consistent.
2026-06-10 14:28:33 +00:00
Cathie Integra
a10de3b616 Config: Add SITE_NAME option and use siteName for instance labels 2026-06-10 14:28:22 +02:00
Theresa Gresch
cf48930343 Tests: Adapt acceptance tests to changes 2026-06-10 14:16:25 +02:00
Cathie Integra
31e5d24d5a Frontend: Prefer configured app name in instance switcher labels 2026-06-10 14:10:18 +02:00
Michael Mayer
68c5d3b00e Frontend: Move the instance selector page under page/auth 2026-06-10 10:21:09 +00:00
Michael Mayer
56d9ea1bab Develop: Upgrade base image from :260603-resolute to :260610-resolute
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-10 06:44:52 +02:00
Michael Mayer
189284c61d Docs: Reflect the /portal default Portal web UI prefix 2026-06-10 04:43:50 +00:00
Michael Mayer
d34284994d Frontend: Update Portal route examples in comments to /portal 2026-06-10 04:39:26 +00:00
Michael Mayer
bf9866750f Frontend: Preserve an out-of-edition role in the user role selector 2026-06-10 04:08:30 +00:00
Michael Mayer
9d77c5fb36 Frontend: Regenerate translation JSON files 2026-06-10 03:31:17 +00:00
Weblate
c65be41692 Weblate: Update frontend translations 2026-06-10 05:27:57 +02:00
Michael Mayer
a4310674cd NOTICE: Regenerate after dependency updates 2026-06-10 03:24:26 +00:00
Michael Mayer
1fad248031 ONNX: Upgrade onnxruntime_go to v1.31.0 and runtime to 1.26.0 2026-06-10 03:24:26 +00:00
Michael Mayer
3f8b38c222 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-10 05:07:03 +02:00
Michael Mayer
f205dd63ca Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-06-10 05:06:34 +02:00
Michael Mayer
6cb38abb43 Settings: Add UI OpenOnHover setting for hover menus #5650 2026-06-10 02:48:10 +00:00
Michael Mayer
14edf40abd OIDC: Drop residual cluster-OIDC gate on provisioned account email 2026-06-10 02:13:27 +00:00
Michael Mayer
a8849d111d Frontend: Scope instance role-select menu font-size to its overlay 2026-06-10 01:18:22 +00:00
Michael Mayer
71aeb26137 OIDC: Store email only when the token marks it verified 2026-06-10 00:04:26 +00:00
Michael Mayer
1bbb915167 Rules: Note untranslated technical labels and shared option labels 2026-06-09 22:47:57 +00:00
Michael Mayer
c61cc18e67 Frontend: Share role/provider option labels, untranslate identifiers 2026-06-09 22:47:57 +00:00
Michael Mayer
10dc504427 Frontend: Regenerate translation catalogs 2026-06-09 22:47:44 +00:00
Michael Mayer
03a7c7c37b Rules: Note FeatureSettings flag cascade and app-password identification 2026-06-09 17:36:30 +00:00
Michael Mayer
cb48c209b6 Auth: Gate app passwords behind a settings feature flag #5647
Adds an AppPasswords feature flag (default on) so app passwords can be disabled, closing the bypass where an app password minted by an OIDC-provisioned user keeps working after the account expires. When off, minting (oauth/token and auth add) is rejected and existing app passwords are no longer accepted on the REST API (403) or WebDAV (401). App passwords are identified by their session auth provider (IsApplication), covering every grant type. The Apps and Devices affordance is hidden for sessions that may not change a password; operators can force it off via PHOTOPRISM_DISABLE_FEATURES.
2026-06-09 17:36:24 +00:00
Michael Mayer
d0d956410c OIDC: Scope the RP state cookie to the instance OIDC base path
The relying-party state and PKCE cookies were left at the zitadel default Path=/, so on a shared-domain proxy (instances served under /i/<tenant>) they reached the callback only if the proxy rewrote the Set-Cookie path. They are now scoped to <base>/api/v1/oidc, covering both the login leg and the redirect callback, so they survive to the callback regardless of any proxy rewrite.
2026-06-09 15:36:35 +00:00
Michael Mayer
7881849b63 Cluster: Redirect cluster-OIDC sign-out to the Portal login
A user who signed in via cluster OIDC now returns to the Portal login (re-auth via OIDC) on sign-out instead of the instance's local form. The /logout route awaits the cluster-wide sign-out so the Portal OP cookie is cleared before the redirect, avoiding a silent re-SSO.
2026-06-09 15:36:24 +00:00
Michael Mayer
7232cc23a4 OIDC: Render a branded page when the RP code exchange fails
The OIDC RP callback handler returned without writing a response when
CodeExchangeUserInfo failed (e.g. a missing/expired state cookie), leaving
the raw zitadel error ("failed to get state: http: named cookie not present")
on screen with no way forward. CodeExchangeUserInfo now runs the exchange
against a recorder so the handler's raw error never reaches the browser, and
the callback renders the branded auth.gohtml page (which returns the user to
login) instead of a dead-end. Set-Cookie headers from a successful exchange
are still propagated.
2026-06-09 13:11:02 +00:00
Michael Mayer
6d0add2e69 Cluster: Address review findings on sign-out, OIDC bootstrap, errors
- /logout route guard now signs out cluster-wide: session.signOut shares
  revokePeerSessions with logoutEverywhere, so a direct /logout revokes peer
  sessions and clears shared storage too, not just the current session.
- Decouple PHOTOPRISM_CLUSTER_OIDC from the auto-join/theme toggles: InitConfig
  now always runs resolveNodeOIDCClient for an instance (join/theme moved into
  bootstrapClusterNode), so a registered node re-wires its OIDC RP on restart
  even with both bootstrap toggles disabled.
- Map redirected OAuth server_error / temporarily_unavailable to ErrUnexpected
  instead of "Invalid credentials", so a Portal-side failure isn't shown as a
  credential problem.
2026-06-09 10:38:22 +00:00
Michael Mayer
b88429f557 Cluster: Compact code comments in the OIDC follow-up changes 2026-06-09 10:20:17 +00:00
Michael Mayer
2d2dc47968 Frontend: Fix cluster sign-out to clear peer tokens from raw storage
logoutEverywhere read and cleared peer sessions through this.localStorage /
this.sessionStorage, which are NamespacedStorage wrappers (getAppStorage).
Enumerating or clearing a cross-namespace key through a wrapper double-prefixed
it (pp🅰️pp🅱️...), so peer session.token keys were left behind after Sign Out
even though the server sessions were revoked. Unwrap to the raw underlying store
first. The vitest case now constructs the session with a NamespacedStorage, as
the app does, so it would catch the regression.
2026-06-09 10:09:05 +00:00
Michael Mayer
872af5d8fd Cluster: Add cluster OIDC, branded authorize errors, and sign-out
Implements three OIDC follow-ups from specs/portal/cluster-oidc.md:

- Zero-touch instance OIDC RP config: PHOTOPRISM_CLUSTER_OIDC derives the
  OIDC RP client_id/secret from the node client credentials and defaults
  the issuer to the instance's own origin (scheme.OriginURL), so a single
  boot reaches a working Portal login. Explicit oidc-client/secret/uri win.
- Human-friendly authorize errors: redirectable errors 302 back to the
  validated redirect_uri; non-redirectable ones content-negotiate a
  branded HTML page (oauth-error.gohtml) vs JSON via shared helpers in
  internal/api/oauth_error.go. The RP callback surfaces inbound ?error=.
- Cluster-wide Sign-Out (Tier 2): session.logoutEverywhere fans out a
  best-effort DELETE per peer session, clears their storage, then signs
  out locally; session-delete clears the OP cookie on any shared-domain
  OIDC-against-Portal node (OIDCSessionCookieClearPath).
2026-06-09 09:39:01 +00:00
Michael Mayer
0a9e40d659 Frontend: Open the instance frontend route in the nav switcher 2026-06-09 08:16:14 +00:00
Michael Mayer
aae8137168 Cluster: Drop SiteCaption from the node DisplayName fallback 2026-06-09 07:56:45 +00:00
Michael Mayer
02819e6688 Frontend: Hide the Portal root path in the instance switcher 2026-06-09 07:23:09 +00:00
Michael Mayer
680469e781 Cluster: Add a per-instance node DisplayName field 2026-06-09 07:23:05 +00:00
Michael Mayer
680f1fef51 Auth: Drop the hard seed-admin lock in User.SaveForm 2026-06-09 04:18:36 +00:00
Michael Mayer
8f7866617a Docs: Document the API JSON field-casing convention
Add the TitleCase (entity-backed) vs camelCase (generated/artificial) rule to the
API package guide and the api-and-config rule's API Shape Checklist.
2026-06-09 03:18:15 +00:00
Michael Mayer
96f84c37e2 Frontend: Point the portal vitest alias at the cluster-instance model 2026-06-09 03:18:15 +00:00
Michael Mayer
427313c6c7 Frontend: Refine the navigation auth menu and instance switcher
Show the instance app icon and base path in the switcher, persisting the icon
alongside the SiteUrl and title per namespace (default to the logo when none is
set). Add a Manage Account item gated on the account feature, and open the menu
on hover like the other action menus.
2026-06-09 00:41:43 +00:00
Michael Mayer
c3c75dad18 Frontend: Rename PUserMenu to PAuthMenu and add a nav menu affordance
Move component/navigation/user-menu.vue to component/auth/menu.vue (and the
matching Vitest), and add an mdi-dots-horizontal affordance icon to the user
info row so the avatar overlay menu is discoverable.
2026-06-08 23:38:22 +00:00
Michael Mayer
c13c26002e Frontend: Switch menu/action icons from vertical to horizontal dots
Replaces mdi-dots-vertical with mdi-dots-horizontal for the navigation
mobile menu trigger and the p-action-menu default icon, and rotates the
lightbox PhotoSwipe menu-button SVG to match (kept centered in its 16x16
viewBox).
2026-06-08 23:08:36 +00:00
Michael Mayer
f3f358b766 Tests: Remove obsolete navigation showAccountSettings cases
showAccountSettings moved out of navigation.vue when the instance switcher
became the shared user menu; account settings is now a declarative sidebar
link. The avatar menu stays covered by user-menu.test.js.
2026-06-08 22:59:17 +00:00
Michael Mayer
927caa362b Frontend: Redirect CE admin/cluster/instances stubs to default route
These pages only exist as Plus/Pro/Portal overlays; in editions without
the overlay they now redirect to the user's default route via
$session.getDefaultRoute() instead of rendering a placeholder.
2026-06-08 22:59:13 +00:00
Ömer Duran
f07da222cf
Cluster: Polish the Portal admin accounts and instances UI 2026-06-08 15:47:44 +02:00
Ömer Duran
36c1bfcfb4 Tests: Resolve portal common/user-format overlay in vitest config
Add the per-file alias so portal vitest resolves the shared common/user-format formatters to the portal overlay, matching the existing common/instance-grants entry.
2026-06-08 11:14:38 +00:00
Ömer Duran
166b9513f1
Frontend: Hide the Places settings card on the Portal 2026-06-05 21:03:40 +02:00
Ömer Duran
1b5b54aaad
Frontend: Style the Portal Cluster Access role selector 2026-06-05 21:03:39 +02:00
Ömer Duran
75d4419b9b
Frontend: Relabel the user menu logout action to "Sign Out" 2026-06-05 21:03:39 +02:00
Ömer Duran
eefc11a31b
Frontend: Reject non-http(s) URLs in the instance switcher 2026-06-05 21:03:39 +02:00
Ömer Duran
3652ae7b76
Frontend: Add instance selector route with a CE stub page 2026-06-05 21:03:39 +02:00
Ömer Duran
8e73783ddd
Tests: Drop blank lines between Portal OpenID config subtests 2026-06-05 21:03:38 +02:00
Ömer Duran
ce5e10fef3
API: Set Cache-Control no-store on the session response 2026-06-05 21:03:38 +02:00
Ömer Duran
3e5522aa80
Auth: Set the OIDC OP session cookie for user sessions only
Skip user-less sessions whose signal NoUser() rejects, warn on the ephemeral key fallback, and keep a manager's delete-by-ref-id from wiping its own OP cookie.
2026-06-05 21:03:38 +02:00
Ömer Duran
cdc671677d
Auth: Let the cluster JWT sync privilege-level user fields
Thread admin authorization into SaveForm via byAdmin so the user-less cluster service principal can persist login/role/WebDAV instead of silently dropping them.
2026-06-05 21:03:38 +02:00
Ömer Duran
fddab77506
Auth: Apply Portal-granted role on OIDC instance login
Honor the pp_role claim (gated by pp_issuer_kind) over the group mapping so an instance login reflects the role the Portal granted, restricted to federatable roles.
2026-06-05 21:03:36 +02:00
Michael Mayer
366e576087 Frontend: Open the navigation user menu above the avatar
The explicit overlay z-index already keeps the teleported menu above the sidebar,
so anchor it back to location=top (above the avatar) instead of opening it to the
right of the navigation.
2026-06-03 21:01:49 +00:00
Michael Mayer
454998711e Frontend: Keep the navigation user menu above the sidebar
The menu content teleports to body, so a nav-scoped z-index does not apply. Set
an explicit overlay z-index and open it beside the drawer (location=end) so it is
no longer partially covered by the navigation.
2026-06-03 19:52:00 +00:00
Michael Mayer
dffb81ab31 Frontend: Move the instance switcher into the shared navigation user menu
Add a shared component/navigation/user-menu.vue (Settings / Switch Instance /
Log Out) wired into the navigation avatar, so every edition gets the switcher.
Instances record their identity under their storage namespace at session auth and
clear it on logout (common/instances + session.js), and the menu lists same-origin
peers that hold a live session. Keeps the distinctive base-path instanceLabel and
the post-login redirect loop guard. Replaces the bootstrap-time directory recording.
2026-06-03 19:42:56 +00:00
Michael Mayer
368ef7912b Auth: Store a signed session reference in the OP cookie, not the token
The OP session cookie stored the raw bearer token with a full-session lifetime,
so a leak of the cookie value was a usable credential against the whole API. It
now carries an HMAC-signed reference to the session id (a hash of the token,
useless as a bearer) with a 10-minute TTL refreshed on each session GET. The key
is persisted under the Portal config keys directory. The authorize handler
resolves the session via OIDCSessionCookieSession. Needs a coordinated SSO e2e
round in the Portal test env before merge.
2026-06-03 19:15:45 +00:00
Michael Mayer
be82697be2 Frontend: Alias portal common/instance-grants in the portal vitest config
Lets the Portal admin/users.vue page (which keeps the common/instance-grants
overlay) be imported under the portal vitest config so its methods can be
unit-tested.
2026-06-03 19:05:11 +00:00
Michael Mayer
d48ef12c99 Auth: Keep OIDC RP state and PKCE cookies Secure on HTTPS
Gate the OIDC relying-party cookie handler's WithUnsecure() on the existing
insecure flag instead of applying it unconditionally, so the round-trip state
(CSRF defense) and PKCE code_verifier cookies retain the Secure attribute on
HTTPS deployments. Addresses audit finding OJW-260603-02 (GO-HTTP-005).
2026-06-03 16:10:39 +00:00
Michael Mayer
51c4eed71e Auth: Serve Portal OIDC OP endpoints under /api/v1/oauth/* #4368 #4369
Move the Portal OIDC OP authorize/token/userinfo onto the shared CE
/api/v1/oauth/* routes (the reserved #4368/#4369 stubs) and drop the parallel
root /oauth/* set.

- Add overridable handler hooks (oauth_handlers.go) mirroring
  server.WebDAVHandler; OAuthToken delegates only the authorization_code grant
  (gated on a form content type) and keeps client_credentials/password/session
  unchanged; userinfo now serves GET and POST.
- Scope the OP session cookie to /api/v1/oauth (base-path aware) so the browser
  still sends it to the moved authorize endpoint instead of looping.
- Stop the proxy re-scoping instance->Portal authorize redirects
  (portalRootPathPrefixes -> /api/v1/oauth/).
- Point discovery at issuer + /api/v1/oauth/*; fix the JWKS URL base-path
  doubling for sub-path deployments (also in CE openid.go).
2026-06-03 15:28:05 +00:00
Michael Mayer
6b8ae165fb Auth: Accept EdDSA ID tokens in the OIDC relying party 2026-06-03 17:12:59 +02:00
Michael Mayer
c908ec5563 Auth: Advertise use and alg in the Ed25519 JWKS 2026-06-03 17:12:59 +02:00
Michael Mayer
b213d1efdd Frontend: Break post-login redirect loops on the login route 2026-06-03 17:12:59 +02:00
Michael Mayer
62da6ce738 Auth: Add OIDC OP session cookie for top-level navigations 2026-06-03 17:12:59 +02:00
Michael Mayer
a4afba69c6 Auth: Authorize cluster JWT for instance user management 2026-06-03 17:12:59 +02:00
Michael Mayer
46dcda2665 Frontend: Label instance switcher by distinctive base-path segment 2026-06-03 17:12:59 +02:00
Michael Mayer
dafba872a2 Frontend: Add shared browser-storage instance directory for switcher 2026-06-03 17:12:59 +02:00
Michael Mayer
f0fe14a449 Frontend: Add cluster_admin role label and Portal vitest config
Adds the Cluster Admin label to the auth role map and a Portal-specific vitest
config for the portal/frontend overlay tests.
2026-06-03 17:12:59 +02:00
Michael Mayer
49acee4afe Auth: Restrict OIDC-mapped account roles to federatable roles
OIDCGroupRoles and OIDCRole drop non-federatable roles, and the OIDC redirect
apply paths use acl.FederatedRoleUpdate, so an external identity provider cannot
assign cluster_admin/visitor as an account role or change an existing operator
account on login.
2026-06-03 17:12:59 +02:00
Michael Mayer
fbe8a6889b Auth: Add cluster_admin role with admin-tier and federation helpers
Adds the Portal-only cluster_admin operator role (declared in CE, registered
only on Portal builds), the acl.AdminRoles/IsAdminRole admin-tier set, and the
acl.IsFederatedRole/FederatedRoleUpdate helpers that keep cluster_admin and
visitor out of externally mapped account roles. SuperAdmin resolves to
cluster_admin on registered builds, SaveForm keeps an admin-level role on a
self-save, and UpdateUser rejects self-role changes. RoleStrings.Strings hides
visitor and none from the CLI role help.
2026-06-03 17:12:59 +02:00
Cathie Integra
e81794a533 Docker: Bump dev base image to develop:260603-resolute (Go 1.26.4) 2026-06-03 17:11:28 +02:00
Michael Mayer
9c96ffecc4 Event: Use first event segment as the system log prefix
Multi-segment events now log as "config: database › connect" instead of
"system: config › database › connect"; single-segment events keep the
generic "system: " prefix. The hub message is unchanged so the frontend
log viewer still shows the full joined event.
2026-06-03 14:58:01 +00:00
Michael Mayer
717b21c5ec Backend: Call clip.Bytes directly and drop the txt.ClipBytes facade #5638 2026-06-03 09:50:56 +00:00
Michael Mayer
d33bac96cb Entity: Rename Sanitize* to Clip* and string.go to clip.go 2026-06-03 09:50:56 +00:00
Michael Mayer
f70d6c113b Entity: Clip album, photo, and folder paths via shared ClipPath #5615 2026-06-03 09:34:40 +00:00
Michael Mayer
395bd76ee3 Backend: Print top-level CLI errors to stderr, not the DB logger #5637 2026-06-03 08:58:30 +00:00
Michael Mayer
5bf4a73aba Config: Report database errors via the system log, not the DB #5637 2026-06-03 08:42:57 +00:00
Michael Mayer
188aba723f Backend: Report recovered panics via SystemLog, not the DB logger #5637 2026-06-03 08:29:40 +00:00
Michael Mayer
2d3aa02dac Backend: Clip VARBINARY text columns by bytes to avoid write errors #5638 2026-06-03 08:04:40 +00:00
Michael Mayer
deb3723fd6 Albums: Clip album_path to the column byte budget on write #5615 2026-06-03 07:53:16 +00:00
Michael Mayer
87f3f6a64a Backend: Recover from panics in background tasks and album restore #5637 2026-06-03 07:45:07 +00:00
Michael Mayer
22ac0b4153 Backend: Log recovered panics with stack trace before exit #5637 2026-06-03 07:37:04 +00:00
Cathie Integra
332f3c4cd6 Helm: Bump Plus chart to 1.1.1 (appVersion 260601) 2026-06-01 23:52:11 +02:00
Michael Mayer
a7d098548e Video: Document codec detection and chunk scans in package docs #5617 2026-06-01 18:44:21 +00:00
Michael Mayer
23802d4fd9 Video: Validate ISO BMFF sample-entry framing in codec head scan #5617 2026-06-01 18:12:31 +00:00
Michael Mayer
6d692cf9dc Frontend: Update vue/compiler-sfc 3.5.35, tar 7.5.16, coverage-v8 3.2.6 2026-06-01 17:46:50 +00:00
Michael Mayer
9df865989a Config: Anchor report Storage section at storage-path, not config-path
OptionsReportSections and YamlReportSections started the Storage group at
config-path, but storage-path and storage-free precede it in the flag and
field order, so they were rendered under the preceding Logging section in
show config-options / config-yaml and the generated reference docs. Anchor
the Storage section at storage-path so those options group correctly.
2026-06-01 15:56:08 +00:00
Michael Mayer
cd44267bce API: Cover shared-only session access to the files endpoint
Add a GetFile subtest asserting a shared-only (guest) session receives no
file details from /api/v1/files/:hash, locking in the per-session access
behavior. Per-photo file scope is covered separately by
search.TestFileVisibleToSession.
2026-06-01 15:21:10 +00:00
Michael Mayer
7d9fee0aa4 Config: Default storage-free to -1, disabling the disk probe #5613
The runtime free-space probe can misreport on network mounts, fuse
layers, and container overlays, so default it off as a safety measure.

The default lives in the config layer (DefaultStorageFree = -1) rather
than in the disk package, whose DefaultStorageLowPct stays 1.0. Test
configs build options directly (StorageFree = 0), so they keep falling
back to the disk default and the existing storage tests stay enabled
unchanged; only the production flag default disables the probe.
Operators opt in with a 1-99 percentage.
2026-06-01 14:52:54 +00:00
Michael Mayer
186a11b007 Entity: Document VARBINARY index-prefix limit and byte-exact paths #5614 #5615
Record that album_path is now a byte-exact VARBINARY column (alongside
album_slug, album_filter, photo_path) and that folder albums dedupe by
album_filter, in internal/entity/README.md. Add an Index Prefix Limits
note to the migrate README and AGENTS: InnoDB caps key prefixes at 767
bytes on COMPACT/REDUNDANT row formats, so VARBINARY prefix indexes use
512 by convention.
2026-06-01 11:42:59 +00:00
Michael Mayer
128bd2d8be Albums: Store album_path as VARBINARY for byte-exact paths #5614 #5615
album_path mirrors photos.photo_path (already VARBINARY(1024)) and is
compared against it directly, but was VARCHAR with the utf8mb4_unicode_ci
collation, which collapses case and most emoji. That made album_path = ?
lookups collation-fuzzy and forced byte-exact re-checks in Go.

Store it as VARBINARY(1024) so folder album path comparisons are
byte-exact at the database, consistent with album_slug, album_filter,
and photo_path. The MySQL migration preserves the existing 768-byte
prefix index. SQLite compares TEXT byte-exact by default, so no SQLite
migration is needed.
2026-06-01 11:34:41 +00:00
Michael Mayer
f1a016ebcd Config: Make TempPath test independent of TMPDIR and run order
tempPath() builds its fallback from os.TempDir(), which is not always
"/tmp" (e.g. when TMPDIR is set), so the hardcoded "/tmp/photoprism_"
prefix made the test fail in such environments. Derive the expected
prefix from os.TempDir() instead, and reset the cached TempPath() global
so the assertions no longer depend on test execution order.
2026-06-01 11:21:46 +00:00
Michael Mayer
d6249107a0 Moments: Dedup folder albums by filter, not slug #5615 #5614
Folder album slugs are not unique identities: long nested paths are
truncated to ClipSlug runes and slug.Make drops emoji, so distinct
sibling folders can share one album_slug. Deduplicate folder albums by
album_filter (the serialized path) instead, and keep slug matching only
for non-folder album types.

This stops RemoveDuplicateMoments from deleting legacy folder rows with
an empty album_path that merely share a truncated slug, which the
indexer then recreated on every run. The empty/NULL album_path escape
hatch in the previous byte-exact path guard no longer applies.
2026-06-01 11:18:30 +00:00
Cathie Integra
4a99556725 Docker: Update develop base image to 260531-resolute 2026-05-31 08:24:29 +02:00
Michael Mayer
25d86c9c50 Backend: Update deps in go.mod, go.sum, and license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-31 04:24:34 +02:00
Michael Mayer
d5549e792c Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-31 04:23:57 +02:00
Michael Mayer
7e46f5c7ac Registry: Assert List membership so tests pass on shared MariaDB DB
The registry test config isolates each test via its own SQLite file, but on
MariaDB every test shares the acceptance database, so List()'s global node query
also returns nodes created by other tests. Assert that the expected node is
listed and the non-node records are not, via a listNodeByName helper, instead of
an exact result count.
2026-05-31 01:35:10 +00:00
Michael Mayer
8bf671b0b8 Entity: Document timestamps and database test specifics
Add internal/entity/README.md covering the second-precision timestamp behavior,
the time helpers, MariaDB strict-mode test gotchas, and the utf8mb4 emoji
collation pitfalls so they don't have to be rediscovered.
2026-05-31 01:13:31 +00:00
Michael Mayer
41ecbf9095 Entity: Store created and updated timestamps with second precision
The schema stores created_at/updated_at as DATETIME without fractional seconds,
so set gorm.NowFunc to entity.Now() (UTC truncated to the second). This keeps
in-memory and persisted times in sync and makes timestamp comparisons behave the
same on SQLite and MariaDB. Adapt the affected tests to compare with Sub() in a
sane range or a clearly past base instead of strict sub-second ordering, and give
the duplicate-client registry test distinct update times.
2026-05-31 01:13:27 +00:00
Michael Mayer
3c00d6fea9 Tests: Use valid fixture IDs so entity tests pass on MariaDB
MariaDB strict mode rejects empty primary keys and out-of-range or oversized
values that SQLite accepts. Give the affected entity tests valid IDs: existing
fixtures where the row is additive, and throwaway in-range IDs where a real
reference would overwrite seeded data.
2026-05-31 00:23:23 +00:00
Michael Mayer
61a89f9ae0 Users: Set the user UID when creating user settings
CreateUserSettings inserted an empty UserSettings, leaving the user_uid
primary key blank. Build it with NewUserSettings so the row carries the UID;
MariaDB strict mode rejected the missing value.
2026-05-31 00:23:18 +00:00
Michael Mayer
c569c02e9e Moments: Guard folder album dedup against slug collisions #5615 #5614
Legacy folder slugs drop emoji (slug.Make), so two siblings collide on the
VARBINARY album_slug and RemoveDuplicateMoments deleted one each pass while
the indexer recreated it. Skip folder albums whose album_path differs
byte-exact via HEX(), which compares the same on MariaDB and SQLite.
2026-05-31 00:23:12 +00:00
Michael Mayer
0d1b45e00a Albums: Keep emoji sibling folders distinct on MariaDB #5366
MariaDB's utf8mb4_unicode_ci collation collapses most emoji, so album_path
lookups matched a sibling folder and merged the two albums. Re-check the
path byte-exact in Go in FindFolderAlbum, the UpdateFolder dedup, and the
slug-collision scope check.
2026-05-31 00:23:05 +00:00
Michael Mayer
51f1fc2df9 Users: Log denied attempts to update another account #5619 2026-05-30 23:03:17 +00:00
Michael Mayer
8cd8f41861 Convert: Abort the run when storage runs out mid-convert #5613 2026-05-30 22:39:22 +00:00
Michael Mayer
bf12724d10 Upload: Report a full disk as insufficient storage #5613 2026-05-30 22:23:14 +00:00
Michael Mayer
e3c1296b06 Thumbs: Respect the files quota and stop on a full disk #5613 2026-05-30 22:23:14 +00:00
Michael Mayer
a015a0044d Index: Abort the scan when storage runs out mid-run #5613 2026-05-30 22:23:14 +00:00
Michael Mayer
b7d637d5dd Storage: Map out-of-space writes to the insufficient-storage error #5613 2026-05-30 22:23:14 +00:00
Michael Mayer
a57ca16bb3 Video: Name the matched exclude entry and apply it to transcode #5617
Add Formats.Match to report which exclude-list entry matched, and use it in the
remux, download, transcode, and index skip messages instead of always printing
the codec (which could be empty or differ from the entry the user configured).

Also apply the exclude list when building "videos transcode" plans so excluded
files are skipped during dry runs and real runs, and report exclusion clearly
when no preview image can be generated for an excluded video.
2026-05-30 21:50:55 +00:00
Michael Mayer
c691b8cbe0 Video: Probe video codecs from the file head in a single scan #5617
Combine the HEVC and MagicYUV sample-entry scans into one pass over the file
head, so the probe reads the head only once when go-mp4 does not report the
codec directly. Rename the scan limit to HeadScanLimit and group the
sample-entry chunk sets in brands.go.
2026-05-30 21:37:14 +00:00
Michael Mayer
9e5b94189e Video: Recognize MagicYUV in the probe and exclude the VFW wrapper #5617
Recognize MagicYUV sample entries in the built-in go-mp4 probe and consider the
probe's codec in addition to the metadata codec when applying the FFmpeg exclude
list, so a video can be matched even when one detector misses it. Rename the
shared sample-entry scan limit to CodecHeadScanLimit.

Also exclude the Matroska Video for Windows wrapper (v_ms/vfw/fourcc) by default,
since its actual codec is not exposed by metadata and the format is uncommon.
2026-05-30 21:29:12 +00:00
Michael Mayer
803ee6ce69 Video: Improve codec detection and exclude-list alias matching #5617
Read the video codec from the AVI VideoCodec metadata tag instead of falling
back to the container name, so codec-based entries on the FFmpeg exclude list
are applied during indexing.

Match exclude-list codecs by their canonical alias so the original name
reported by a metadata tool (e.g. m8ra), the human-readable name (magicyuv),
and the canonical FourCC (magy) are treated as equivalent. Add h264/h265
aliases and make magy the canonical MagicYUV codec name.
2026-05-30 21:02:19 +00:00
Michael Mayer
a230e60d4f FFmpeg: Add vulkan init target and provision Vulkan drivers #5631
Add a vulkan target to scripts/dist/Makefile so PHOTOPRISM_INIT="vulkan"
installs mesa-vulkan-drivers and vulkan-tools directly, and extend
install-gpu.sh to provision the Mesa Vulkan drivers for detected Intel and AMD
GPUs plus vulkan-tools for NVIDIA verification.
2026-05-30 20:14:14 +00:00
Michael Mayer
b223d12ff2 FFmpeg: Document hardware AVC encoder packages #5631 #5630
Add README files for the vaapi, intel, nvidia, and vulkan encoder packages
covering the FFmpeg flags, devices, supported formats, required system packages,
and FFmpeg 8 notes such as the VA-API filter-device requirement.
2026-05-30 20:14:14 +00:00
Michael Mayer
5242964330 FFmpeg: Fix duplicate hwupload in Vulkan transcoding command #5631
encode.FormatNV12 already ends in hwupload, so appending it again produced
"format=nv12,hwupload,hwupload", which fails because the frames are already on
the GPU. Build the filter from FormatNV12 directly to upload exactly once, and
add a gated Vulkan case to the transcode command tests.
2026-05-30 20:14:14 +00:00
Michael Mayer
c5b5362649 FFmpeg: Use PHOTOPRISM_FFMPEG_TEST_ENCODER to opt into HW tests #5630
The transcode tests gated their real hardware run on PHOTOPRISM_FFMPEG_ENCODER,
but the package init() unconditionally unset that variable, so the hardware path
never executed and an FFmpeg 8 regression like #5630 could pass unnoticed.

Switch the opt-in to a dedicated PHOTOPRISM_FFMPEG_TEST_ENCODER variable so real
VAAPI/QSV/NVENC transcodes run when enabled on a matching host, while a runtime
PHOTOPRISM_FFMPEG_ENCODER value still cannot trigger them by accident.
2026-05-30 19:02:16 +00:00
Michael Mayer
465d8e0245 FFmpeg: Fix VAAPI transcoding by setting the filter device #5630
FFmpeg 8 no longer derives a filter hardware device from "-hwaccel
vaapi" alone, so the "format=nv12,hwupload" step aborts with "A hardware
device reference is required to upload frames to." and PhotoPrism falls
back to software encoding.

Initialize a named VAAPI device and reference it for both decoding
(-hwaccel_device) and filtering (-filter_hw_device). When no device path
is configured, FFmpeg auto-detects the default render node.
2026-05-30 17:40:21 +00:00
Michael Mayer
89a0bd7399 Commands: Prevent config command tests from polluting the originals directory 2026-05-30 16:13:21 +00:00
Michael Mayer
924c80f78c FS: Prefer relative over absolute paths in directory detection #5629 2026-05-30 16:10:46 +00:00
Michael Mayer
0f63292ae2 Docs: Shorten CODE_OF_CONDUCT.md 2026-05-30 13:09:40 +02:00
Michael Mayer
e8299c83ba Docs: Update CODE_OF_CONDUCT.md 2026-05-30 13:01:17 +02:00
Michael Mayer
b04233f2f4 Backend: Use strings.SplitSeq for split-and-iterate loops #5599
Replace strings.Split with the lazy strings.SplitSeq iterator (Go 1.23+)
in loops that only range over the tokens, avoiding the intermediate
slice allocation. The yielded substrings are identical to Split, so
behavior is unchanged. Applies the suggestion from #5599 to its three
sites (CIDR parsing, WebDAV hidden-path, overlay path checks) and
extends it to two more split-and-iterate loops in the server compression
negotiator and MCP config-options builder for consistency. The slice
returning splitPath helper is intentionally left on strings.Split.
2026-05-30 09:49:47 +00:00
Michael Mayer
03129c9129 Vector: Reorganize package into topic-based files #4669
Split the catch-all values.go into one file per concept, each mirrored
by its test: distance.go, norm.go, stats.go, product.go, centroid.go,
plus the mean methods folded into mean.go and Copy/Dim/Sum into
vector.go. Remove values.go, values_test.go, and values_more_test.go so
functionality and tests live where developers expect them.

Hoist the two 512-dimensional face embeddings shared by the distance,
norm, and cosine tests into fixtures_test.go, removing the previous
triplication, and decompose the monolithic TestVector into per-concept
tests. Close pre-existing coverage gaps in the integer converters and
the GeometricMean/HarmonicMean method wrappers, bringing the package to
100% statement coverage. Pure code movement; no behavior change.
2026-05-30 09:44:03 +00:00
Michael Mayer
40b170ecb0 Vector: Add Normalize, Normalized, and Centroid helpers #4669
Prepare pkg/vector for a future refactoring of internal/ai/face without
touching the face package yet. Normalize scales a vector to unit length
(L2) in place and leaves a zero vector unchanged; Normalized returns a
normalized copy. Centroid returns the element-wise mean of a set of
vectors, ignoring entries whose length differs from the first and
averaging over the vectors actually included. Together with the existing
EuclideanDist, EuclideanNorm, and NewVector helpers these cover the math
currently hand-rolled in the face embeddings code. Fully covered by
tests (100% of the new functions).
2026-05-30 09:17:00 +00:00
Michael Mayer
a685b3f051 Vector: Add package doc comment and license header #4669
The root file of the vector package was missing the standard package
description and AGPL header required by the Go style rules. The vendored
alg subpackage keeps its own MIT license and is left unchanged.
2026-05-30 07:51:06 +00:00
Michael Mayer
e678231f34 Vector: Fix cosine distance, geometric mean, and copy semantics #4669
CosineDist now returns a true cosine distance (1 - similarity), so
identical vectors yield 0; the previous similarity behavior moves to a
new CosineSimilarity function/method. GeometricMean no longer treats a
zero element as an uninitialized accumulator: zeros now correctly yield
0 and negative inputs return NaN. NewVector copies float64 and Vector
inputs so the result is independent of the source slice, matching the
other converters. Norm uses absolute values so odd powers (L1) stay
well-defined for negative components, variance is simplified, and the
numeric error paths return NaN instead of the Epsilon sentinel. Add
focused tests for the mean, distance, norm, and copy helpers.
2026-05-30 07:51:06 +00:00
Michael Mayer
5511814dde Faces: Harden DBSCAN worker partitioning against zero step #5628
Extract the per-worker scan range size into partitionSize() and floor
it at 1 so the nearest() dispatch loop always advances and terminates,
even if the worker count exceeds the number of data points. The size
based numWorkers buckets keep points >= workers today, so this is a
defensive guard against future tuning. Add focused tests for the helper
and a high-worker end-to-end case.
2026-05-30 07:40:09 +00:00
Michael Mayer
418a018f6e Faces: Remove unused OPTICS clusterer from pkg/vector/alg #5628
The vendored OPTICS implementation was never invoked: face clustering
uses DBSCAN (alg.DBSCANWithProgress), and OPTICS() had no callers or
tests. Removing it also drops a latent no-op loop (PVS-Studio V8016)
in extract(). Drop the now-orphaned errZeroXi and update the rangeJob
comment and README to match. See discussion #5628.
2026-05-30 07:15:18 +00:00
Michael Mayer
a75ce62b9d API: Fix incorrect hash parameter name in GetVideo Swagger annotation 2026-05-29 13:14:19 +00:00
Michael Mayer
2a944d931d Search: Exclude deleted files and document per-session scope checks #1307
FileVisibleToSession excludes soft-deleted file rows; PhotoVisibleToSession's UnscopedDb use is documented (archived handling deferred to ScopeVisiblePhotos, full-access short-circuits). Adds TestUserPhotos_ScopeAuthorization pinning that a restricted session may scope only to albums it owns or has shared.
2026-05-29 08:20:26 +00:00
Michael Mayer
68716b5c2b Photos: Reduce identifying metadata for shared-only sessions #1307
RedactForSession also clears the camera serial, XMP DocumentID, and per-file InstanceID for shared-only/unregistered sessions, matching common EXIF/XMP privacy practice; FileName, PhotoUID, and FileUID are kept.
2026-05-29 08:20:26 +00:00
Michael Mayer
ba616af18f Frontend: Preload lightbox sidebar metadata for all sessions #1307
fetchPhoto and preloadNextPhoto no longer skip GET /photos/:uid for shared-only sessions; the endpoint reduces detail server-side, so the sidebar preloads for every session and the per-section ACL gates decide what renders.
2026-05-29 08:20:26 +00:00
Michael Mayer
5f8ea3aba0 API: Reduce photo detail in responses for shared-only sessions
GetPhoto returns a reduced view for sessions limited to shared content: album membership is restricted to the albums shared with the session, and labels, people, and owner/storage metadata are omitted. Full-access sessions are unaffected. Adds Photo.RedactForSession, in preparation for upcoming sharing features.
2026-05-29 05:26:56 +00:00
Michael Mayer
5f9f1bc55b API: Scope photo reads and updates to the session
GetPhoto, GetPhotoYaml, and UpdatePhoto now limit access to pictures within the session's shared scope via the shared search helpers, with no change for full-access sessions. GetAlbum reports out-of-scope albums as not found for consistency with photos and files. In preparation for upcoming sharing features.
2026-05-29 07:04:47 +02:00
Michael Mayer
763757cc4b API: Scope file lookup and zip selection to the session
GetFile and the zip selection now limit results to the session's shared scope via the shared search helpers, consistent with photo search and in preparation for upcoming sharing features. No change for full-access sessions.
2026-05-29 07:04:47 +02:00
Michael Mayer
e6aa402d9c Search: Add reusable per-session photo and file scope helpers
Introduces ScopePhotosForSession, ScopeVisiblePhotos, PhotoVisibleToSession, and FileVisibleToSession, and refactors searchPhotos to reuse the shared predicate, in preparation for upcoming sharing features. Full-access sessions short-circuit without an extra query.
2026-05-29 07:04:47 +02:00
Michael Mayer
c786eb6df9 Build: Centralize npm targets in root Makefile and align flags
Define npm clean-install, install, update, and audit commands once in the
root Makefile and have frontend/Makefile delegate via $(MAKE) -C .., so the
single root node_modules and package-lock.json are used. Standardize the
--ignore-scripts/--no-audit/--no-fund/--no-update-notifier flag order across
all npm invocations and drop the no-op --no-audit from npm audit.
2026-05-29 04:40:23 +00:00
Michael Mayer
e39f9f20a6 Index: Reassign primary when current primary is deleted #5625
FixPrimaries counted soft-deleted files as primaries, so a photo whose
primary was deleted kept photo_quality = -1 and stayed in Hidden even
with a present, valid preview file. Also clear the primary flag from
soft-deleted files so a present file is promoted and quality recovers.
2026-05-29 02:51:31 +00:00
Michael Mayer
4f5dd196de Thumbs: Abort thumbnail generation on insufficient storage #5613
The thumbs command wrote new previews into the thumb cache regardless of
free disk space, unlike the indexer and converter. Add a start-of-scan and
per-file storage check mirroring Index.storageLow() so generation aborts
with a clear, localized message when the storage volume is critically low.
2026-05-29 00:50:15 +00:00
Michael Mayer
a9557b0e11 Tests: Restore DB connection settings in RunWithTestContext #5613
A command that rewrites the in-memory database connection (e.g. cluster
register persisting provisioned MySQL credentials) made the post-command
RegisterDb() block in connectDb's 60s retry loop reaching an unreachable
server, silently delaying the commands test suite. Snapshot the connection
settings before the run and restore them before re-opening so follow-up
checks reconnect to the per-suite SQLite test DB.
2026-05-29 00:42:59 +00:00
Michael Mayer
5d899fea4b Frontend: Block uploads and imports on insufficient storage #5613
Gate the upload dialog and import page on a new $config.insufficientStorage()
helper (files quota reached OR storage folder low), mirroring the backend
Config.InsufficientStorage(). Fix the upload dialog test config mock and add
unit coverage for the new config helpers.
2026-05-29 00:15:44 +00:00
Michael Mayer
36da6af565 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-29 01:57:17 +02:00
Michael Mayer
3b38a4a2a5 Config: Improve low storage detection #5613 2026-05-29 01:45:04 +02:00
Michael Mayer
741373b852 Docs: Add comment on scripts to Dockerfile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-28 13:16:06 +02:00
Cathie Integra
9b2313ede0 HEIC: Hold photoprism-libheif on Resolute and warn against apt libheif1 #5621 2026-05-27 10:41:38 +02:00
Cathie Integra
733dbf00a9 Docker: Run install-libvips.sh before install-libheif.sh on Jammy #5621 2026-05-27 09:52:13 +02:00
Cathie Integra
df152c4fb8 Docker: Replace libvips-dev with runtime variant in slim images #5621 2026-05-27 08:47:33 +02:00
Cathie Integra
2da791be8d HEIC: Install equivs stub to supersede apt's libheif* packages #5621 2026-05-27 08:29:29 +02:00
Cathie Integra
04f90575f8 HEIC: Build and install libheif as a real .deb on Resolute #5621 2026-05-27 08:24:56 +02:00
Michael Mayer
bb5d524b7d Develop: Upgrade base image to 260527-resolute #5620 #5621
Includes the latest dependencies like libheif v1.22.2:
https://dl.photoprism.app/dist/libheif/

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-27 05:01:26 +02:00
Cathie Integra
83fbca10c2 HEIC: Default install-libheif.sh to v1.22.2 and switch Resolute base #5621 2026-05-27 04:17:19 +02:00
Cathie Integra
de799b1456 HEIC: Add libyuv-dev to libheif build dependencies #5621 2026-05-27 04:00:48 +02:00
Cathie Integra
551d1978d7 HEIC: Install aom-tools as a libheif build dependency #5621 2026-05-27 03:57:28 +02:00
Cathie Integra
21f045d257 HEIC: Upgrade libheif from v1.21.2 to v1.22.2 #5621 2026-05-27 03:49:04 +02:00
Michael Mayer
860f937abe Docker: Remove Pebble binary from Ubuntu base images #5620
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-27 03:25:22 +02:00
Michael Mayer
8abdf595bf Storage: Propagate insufficient-storage to CLI exit and index 507 #5613 2026-05-26 23:34:33 +00:00
Michael Mayer
5783756179 Commands: Count remux exclude skips #5617 2026-05-26 20:41:56 +00:00
Michael Mayer
290d1a13e0 API: Improve user profile authorization checks and code comments #5619
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-26 22:10:58 +02:00
Michael Mayer
f136ae3b21 Frontend: Update deps in package.json and package-lock.json 2026-05-26 16:25:19 +00:00
Michael Mayer
f9a364d713 Go: Update deps in go.mod, go.sum, and license NOTICE file 2026-05-26 16:25:13 +00:00
Michael Mayer
85c59b1468 Testing: Document subtest blank-line convention 2026-05-26 16:09:20 +00:00
Michael Mayer
80ac70cc6a FFmpeg: Use atomic.Pointer for thread-safe Exclude list access #5617 2026-05-26 15:57:59 +00:00
Michael Mayer
d2e8c7afad Config: Add option to exclude video formats from FFmpeg #5617 2026-05-26 15:36:42 +00:00
Michael Mayer
cd17444807 Thumbs: Strip ICC for SizeColors and PNG convert retry #5616 #5612 2026-05-26 05:14:50 +00:00
Michael Mayer
15885d8c94 Thumbs: Retry PNG export without ICC profile on iCCP reject #5616 #5612 2026-05-26 04:38:50 +00:00
Michael Mayer
abaf8613e4 Auth: Use highlight color for stay-signed-in checkbox #5476 2026-05-26 04:17:51 +00:00
Michael Mayer
757fc49eb6 Folders: Add long-ASCII regression test for RemoveDuplicateMoments #5615 2026-05-26 02:38:39 +00:00
Michael Mayer
bf9bbfb5fb Folders: Fix slug collision on long ASCII paths #5614 #5615 2026-05-26 02:34:48 +00:00
Michael Mayer
d755a8b9d0 Config: Add STORAGE_SKIP_CHECK env var to bypass disk-low probe #5613 2026-05-26 01:59:38 +00:00
Michael Mayer
696c3cd4da Storage: Gate convert/backup/zip writes and centralize Err sentinels #5613 2026-05-26 01:35:06 +00:00
Michael Mayer
089eb0e22b Index: Log walk cancel at info level and suppress duplicate low-storage #5613 2026-05-26 00:43:56 +00:00
Michael Mayer
dd2c9e3e88 Storage: Refine low-storage logging and extract walk-error sentinels #5613 2026-05-26 00:32:35 +00:00
Michael Mayer
1c5e933a59 Index: Surface insufficient-storage cause in walk-result log #5613 2026-05-25 23:58:50 +00:00
Michael Mayer
fb6166b490 Storage: Extend insufficient-storage gates to imports and writes #5613 2026-05-25 23:56:21 +00:00
Michael Mayer
269ea465be Develop: Update traefik service config in compose.yaml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-26 01:41:06 +02:00
Michael Mayer
e8ea0ea80c Auth: Rename isValidRedirectUrl to invalidRedirectUrl for call-site clarity 2026-05-25 18:39:27 +00:00
Michael Mayer
2c5bf792a3 Auth: Generalize login-redirect guard via isValidRedirectUrl helper 2026-05-25 18:38:29 +00:00
Michael Mayer
3f7f450894 Auth: Refuse login-page URLs as the post-login redirect target 2026-05-25 18:36:49 +00:00
Michael Mayer
6a4463e2c3 Auth: Cap /login auto-OIDC redirect at one attempt per browser tab 2026-05-25 16:51:18 +00:00
Michael Mayer
67d5a58aa0 Thumbs: Check thumbnail dimensions before stripping metadata #5613 2026-05-25 15:06:25 +00:00
Michael Mayer
b0cfa26e62 Vision: Demote benign NSFW non-JPEG warning to debug log 2026-05-25 15:00:32 +00:00
Michael Mayer
fd5ef513d1 Docs: Bump remaining 2025 copyright stamps to 2026 2026-05-25 14:46:32 +00:00
Michael Mayer
0141fb6c0e Docs: Bump copyright year to 2026 in frontend JS files 2026-05-25 14:40:40 +00:00
Michael Mayer
570a563748 Docs: Bump copyright year to 2026 in Go package headers 2026-05-25 14:39:38 +00:00
Michael Mayer
bbdc5b749b Thumbs: Wrap libvips export errors with destination and dimensions #5613 #5612 2026-05-25 14:31:02 +00:00
Michael Mayer
0f01057dba Index: Abort early when storage is critically low #5613 #5612 2026-05-25 14:27:21 +00:00
Michael Mayer
e01df7a498 Config: Include 'users' in DefaultJWTAllowedScopes for cluster proxy 2026-05-25 12:12:11 +00:00
Michael Mayer
ef7a9db950 Cluster: Add scheme.ResolveAdvertiseURL helper for SiteUrl-aligned paths 2026-05-25 11:49:33 +00:00
Michael Mayer
825c8c6a2d Backend: Compact code comments and drop duplicate package headers 2026-05-25 11:47:44 +00:00
Michael Mayer
2f2ee81f50 Config: Fix PostgreSQL DSN recursion (#47, #4831) 2026-05-25 09:56:21 +00:00
Michael Mayer
d0b896564d Migrations: Add internal/entity/migrate package documentation #47 #4831
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-25 11:34:29 +02:00
Michael Mayer
45b44436dc Frontend: Lift /cluster route gate to login-required for chooser tab 2026-05-24 14:30:18 +00:00
Michael Mayer
b2e2da52fb Cluster: Accept RedirectURIs in PATCH /api/v1/cluster/nodes/{uuid} 2026-05-24 14:08:54 +00:00
Michael Mayer
000cbe2a78 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-24 15:32:24 +02:00
Michael Mayer
111c04ee19 Auth: Honor return_to query parameter on /login route
The Portal OIDC OP at /oauth/authorize redirects unauthenticated browsers
to /portal/admin/login?return_to=<authorize URL> via a top-level
navigation, so the global router guard's setLoginRedirectUrl path never
runs and the deep link is lost. The /login route now reads return_to
itself, validates it via safeReturnTo (root-relative paths or same-origin
absolutes only; protocol-relative and backslash-prefixed values rejected
as open-redirect bait), and records it through the existing
loginRedirect machinery so followLoginRedirectUrl honors it after a
successful local or LDAP login.
2026-05-24 13:01:46 +00:00
Michael Mayer
468526c50a Config: Wire PHOTOPRISM_PORTAL_OIDC_* env vars and accessors
Operators can now tune the Portal OIDC OP without recompiling. Four new
options thread through the standard yaml/CLI/env layers:

- PHOTOPRISM_PORTAL_OIDC_ISSUER         override for the discovery /
                                        ID-token issuer URL (defaults to
                                        site-url)
- PHOTOPRISM_PORTAL_OIDC_TTL            access/ID-token lifetime, clamped
                                        to [60, 900] s; default 300
- PHOTOPRISM_PORTAL_OIDC_CODE_TTL       authorization-code lifetime,
                                        clamped to [30, 300] s; default 60
- PHOTOPRISM_PORTAL_OIDC_DEFAULT_POLICY chooser | direct; default chooser

Config.PortalOIDC{Issuer,TTL,CodeTTL,DefaultPolicyChooser} expose the
values for handler use. The OIDC handler wiring to read them ships in the
portal subrepo.
2026-05-24 13:01:37 +00:00
Michael Mayer
32902d2c63 Cluster: Skip Location rewrite for Portal-root paths in proxy
The portal proxy was prefixing the per-instance path scope onto absolute
Location headers whose host matched the proxy, breaking instance-to-Portal
redirects like the Pro OIDC RP pointing at the Portal authorize endpoint.
Paths under /oauth/, /.well-known/, and /portal/ are now recognized as
Portal-root and left untouched.
2026-05-24 12:28:02 +00:00
Michael Mayer
8a28f605df Config: Refactor database driver parsing and detection #47 #4831 2026-05-24 12:24:10 +02:00
Michael Mayer
e3cd90bc43 Cluster: Add Portal OIDC discovery doc at /.well-known/openid-configuration 2026-05-24 06:43:11 +00:00
Michael Mayer
1618d5cd98 Auth: Use acl.RolePortal for pp_issuer_kind instead of local constant 2026-05-24 06:36:41 +00:00
Michael Mayer
f33cce28e4 Auth: Add IssueUser for Portal OIDC ID/access tokens 2026-05-24 06:29:08 +00:00
Michael Mayer
12ab14ea9c Cluster: Add OIDC group/role/redirect fields to ClientData 2026-05-24 05:00:17 +00:00
Michael Mayer
d8a6555592 Ollama: Update inline environment variable docs in compose.nvidia.yaml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-23 09:45:18 +02:00
Cathie Integra
771bc3688c Docker: Tune Ollama defaults: flash-attention on, telemetry opt-outs 2026-05-23 09:41:12 +02:00
Michael Mayer
0544f71c12 Develop: Honor WORKING_DIR in Dockerfile WORKDIR via compose build arg 2026-05-22 22:26:24 +00:00
Michael Mayer
9588d93aa4 Develop: Ignore .gitconfig files in dev environment
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-22 23:55:19 +02:00
Theresa Gresch
c6428da761 Tests: Adapt tests to frontend changes and cover additional improvements 2026-05-22 15:38:20 +02:00
Michael Mayer
deb42b0e29 CLI: Reject flags placed after positional arguments #5604 2026-05-22 11:54:54 +00:00
Michael Mayer
7b0d64bef9 Develop: Make compose working_dir and paths configurable via WORKING_DIR 2026-05-22 09:03:34 +00:00
Michael Mayer
8ee2d47673 GitHub: Refine bug report template
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-22 10:31:45 +02:00
Michael Mayer
7c158901b5 GitHub: Refine bug report and feature request templates
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-22 10:21:27 +02:00
Michael Mayer
10e2ae654a GitHub: Refine bug report and feature request templates 2026-05-22 07:59:23 +00:00
Michael Mayer
055c9f0a6b Helm: Add chart for PhotoPrism on Kubernetes #3460 #5603 2026-05-22 06:48:37 +00:00
Michael Mayer
257c9554fb Assets: Align .buildignore across editions 2026-05-22 06:48:32 +00:00
Michael Mayer
ee2cb4352f Setup: Add .rsyncignore and gitignore private setup/Makefile 2026-05-22 06:48:29 +00:00
Michael Mayer
91d27f7e6e Docs: Update copyright year in Dockerfiles, scripts, and Go files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-22 07:56:59 +02:00
Cathie Integra
e5910c2586 Docs: Document NSFW flag gating and call-graph in package READMEs 2026-05-21 16:25:06 +02:00
Cathie Integra
dab3a762bf Config: Clarify NSFW flag help text and drop stale TensorFlow note 2026-05-21 15:42:19 +02:00
Michael Mayer
ceb3086be1 Develop: Increase stop_grace_period to 15s for MariaDB & PostgreSQL
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-21 13:31:27 +02:00
Michael Mayer
822cbf325a FFmpeg: Add h264_vulkan video transcoding support #5592 2026-05-21 09:44:41 +00:00
Michael Mayer
bf4a680d72 Faces: Add "faces config" subcommand to list face options #5597
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-21 11:17:37 +02:00
Michael Mayer
7abc5164a8 Vision: Preserve case of model identifiers in vision.yml #5594
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-20 21:02:58 +02:00
Michael Mayer
06e50f3783 Frontend: Gate Add-to-Album, Batch Edit, and Labels tab on name length #5584
The backend setters Album.SetTitle and Label.SetName silently truncate
with an ellipsis once the input exceeds 160 chars and still return 2xx,
so the three remaining "create new" surfaces showed a green success
against an entity the user did not intend. Refuse the save client-side
when the typed name exceeds the per-entity MaxLength: the Add-to-Album
combobox in component/photo/album/dialog.vue, the Albums + Labels chip
selectors in component/photo/batch-edit.vue (gated through a new
max-length prop on component/input/chip-selector.vue), and the Labels
tab combobox in component/photo/edit/labels.vue all surface a "Name is
too long" error instead of dispatching the request.
2026-05-20 18:40:18 +00:00
Michael Mayer
fdb6cde287 Develop: Fix "specified::" typo in compose service comments #5590
Drops the stray second colon at the end of the "Only starts if … profile
is specified:" comment block in compose.nvidia.yaml and the three
setup/docker compose files. Pure cosmetic cleanup so all gated services
use identical phrasing across the dev and end-user compose variants.
2026-05-20 16:31:35 +00:00
Michael Mayer
0e14ef111d Develop: Document COMPOSE_PROFILES in .env.example, tighten comments #5590
Compose reads COMPOSE_PROFILES from .env automatically (no --profile flag
needed on every invocation), so adding it to .env.example lets developers
opt into the new "postgres" profile (or any other) once and forget about
it. Drive-by trims "Only starts this service if..." to "Only starts if..."
across compose.yaml, compose.nvidia.yaml, and the three setup/docker
compose files so all gated services use the same shorter phrasing.
2026-05-20 16:30:01 +00:00
Michael Mayer
69e27ba461 Develop: Gate postgres on a compose profile, normalize comments #5590
The default development stack runs on MariaDB (PHOTOPRISM_DATABASE_DRIVER
is "mysql", and the photoprism service depends_on only "mariadb"), so the
postgres container should not start on a plain "docker compose up". Add
profiles: [ "all", "postgres" ] so users opt in via --profile postgres,
align every gated service to the same image / comment / profiles /
stop_grace_period shape, add the missing per-block "docker compose
--profile X up -d" examples, fix pre-existing "::" typos, and correct
"qsql" to "psql" in the photoprism service environment comments across
compose.yaml, compose.intel.yaml, and compose.nvidia.yaml.
2026-05-20 16:20:11 +00:00
Michael Mayer
12dbe82d36 Video: Tag HEVC remux output hvc1 and unify MP4 chunk scans #5593
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-20 17:57:40 +02:00
Michael Mayer
57a56e8572 HEIC: Refresh libheif install/build script comments for v1.21 #5543
libheif 1.21 renamed the CLI binaries: heif-convert is now a symlink to
heif-dec and heif-thumbnailer is no longer shipped at all. Updating the
header and inline comments in install-libheif.sh and build-libheif.sh
to match what the scripts actually produce on current libheif releases.
2026-05-20 15:01:40 +00:00
Michael Mayer
1b8ea51a2f Config: Normalize Site/CDN base URLs to strip default ports #5590
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-20 16:59:53 +02:00
Michael Mayer
9540931a16 Go: Update indirect deps in go.mod, go.sum, and license NOTICE file 2026-05-20 11:35:47 +00:00
Michael Mayer
c9722af97e Go: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-20 13:16:46 +02:00
Michael Mayer
5c993ebb6d Frontend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-20 13:13:28 +02:00
Michael Mayer
b41bc70e39 Develop: Add "docker-down" target to Makefile #5590
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-20 13:01:19 +02:00
Michael Mayer
d35a45eb4c Develop: Change default POSTGRES_PORT from 5432 to 4002 #5590
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-20 12:59:26 +02:00
Michael Mayer
2ed5872909 Develop: Upgrade base image from 260510-resolute to 260520-resolute
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-20 12:50:54 +02:00
Michael Mayer
f7085cfb1d Develop: Honor MARIADB_PORT and POSTGRES_PORT overrides #5590 2026-05-20 09:44:12 +00:00
Michael Mayer
edfd01460c Docs: Drop historical framing from CODEMAP cluster CLI bullet 2026-05-20 08:12:37 +00:00
Michael Mayer
a20b891c58 AI: Apply steady-state rule to face package README 2026-05-20 07:50:35 +00:00
Michael Mayer
faa90a7208 Frontend: Align tests with shared meta-markers-toggle face-marker class #4966 2026-05-20 07:11:25 +00:00
Michael Mayer
0f1b7f9bd4 Frontend: Gate Unassign on edit mode, rename markersEdit/onClearSubject #4966 2026-05-20 06:35:59 +00:00
Theresa Gresch
f9634b308c Tests: Adapt tests to frontend changes 2026-05-19 16:52:16 +02:00
Michael Mayer
444fe13185 Frontend: Truncate long album & label chips in batch edit dialog #4966 2026-05-19 14:20:38 +00:00
Michael Mayer
5462828516 Develop: Predictable host ports, split TRAEFIK_/SERVICES_ bind hosts #5590 2026-05-19 13:31:28 +00:00
Michael Mayer
1647cbfe88 Frontend: Document login.next and login.logout in common README #5506 2026-05-19 11:47:08 +00:00
Michael Mayer
1b95b8e043 OIDC: Gate auto-redirect on deep-link arrivals, keep form usable #5506 2026-05-19 11:46:23 +00:00
Michael Mayer
7ba4dc1bf6 Frontend: Tune lightbox theme for face markers, retire ESLint-Prettier glue #4966
- Refactor `meta.css` face-marker palette to consume theme tokens (Path A):
  default rect → `on-surface`; named-marker stroke → `primary`; draft →
  `accent`; hover → `primary-darken-1`; handle → `primary-darken-1` fill +
  `primary` stroke; Confirm pill → `primary-darken-2`; Cancel pill →
  `highlight-lighten-1`; Remove pill → `remove`; Back button → `surface`.
- Retune the `lightbox` theme block to support the rebind: `primary
  #F2F3F3 → #9E8FC9` (muted purple), `accent #2D2E2E → #BDAFE4` (lavender),
  `surface #151515 → #181818`, `surface-bright → #1c1c1c`, `button →
  #242424`, `highlight #424041 → #3c3c3c`, `remove → #cd4645`. Effectively
  reverts the `surface-variant ↔ on-surface-variant` swap and re-introduces
  an explicit `.v-tooltip.v-theme--lightbox` override in `lightbox.css`.
- Bump `variations.darken` to 2 so `--v-theme-primary-darken-2` resolves.
- Swap the in-template button order in `markers.vue` to Cancel-left /
  Confirm-right for both the pending-add and remove-confirm popovers.
- Add inline comments to the `default.add` and updated `lightbox`
  entries so each color's purpose stays documented at the source.
- Drop `eslint-plugin-prettier` (its `prettier/prettier` rule was already
  `"off"`, making the plugin inert). Replace `plugin:prettier/recommended`
  with a direct `eslint-config-prettier` extend; keep ESLint's own
  `indent` / `quotes` / `brace-style` rules as the JS formatter.
- Tell ESLint to ignore `*.{css,scss,sass}` so Prettier owns CSS
  unambiguously; wire `npm run fmt-css` / `npm run lint-css` Prettier
  passes into `npm run fmt` / `npm run lint` so `make fmt-js` and
  `make lint-js` cover stylesheets too.
- Drop `eslint-plugin-prettier` from the dev-container global install
  list and the `frontend/tests/README.md` dependency table; regenerate
  `NOTICE` files.
2026-05-19 09:56:09 +00:00
Michael Mayer
f928844a40 Frontend: Refactor lightbox theme colors and chip-selector tokens #4966
- Centralize sidebar/PhotoSwipe caption link styling via new `.text-html`
  class in `text.css`; drops the previous `info`-token overload.
- Swap lightbox `surface-variant` ↔ `on-surface-variant` so Vuetify
  tooltips render dark natively (remove `.v-tooltip` override). Lift
  `on-surface` to `#f9fafb`, `primary` to `#F2F3F3`, `highlight` to
  `#424041`.
- Add cross-theme `add` color token to `ui.js` (dark `#3a6e73`, light
  `#cce3de`); register `add` and `remove` in Vuetify color variations.
- Rename chip-selector classes from color-named to action-named
  (`chip--add` / `chip--remove` / `chip--default` plus `--mixed` partial
  variants); double selectors (`.chip.chip--*`) to win over the UA
  `[role="button"] { color: inherit }` reset.
- Tune `remove` saturation in `ui.js`, `default`, and `lavender` themes.
- Bind face-marker chrome in `meta.css` to theme tokens: default rect +
  removing rect → `on-surface` / `remove`; Cancel pill → `button`;
  Remove pill → `remove`; pill text → `on-surface`.
- Remove the hardcoded `menuBgColor` literal in `lightbox.vue` and the
  redundant `.meta-caption a:hover` rule in `lightbox.css`.
- Update chip-selector vitest for renamed classes; Prettier auto-format
  in `views.css` and `vuetify.css`.
2026-05-19 06:41:36 +00:00
Michael Mayer
7ed0fc44d3 Frontend: Drop unused "escape-string-regexp" dep, refresh tooling
Removes the top-level "escape-string-regexp" dependency, which has no
direct consumer in our source. The v4 line lives on as a transitive
dep of "eslint" and "sanitize-html"; "webpack-bundle-analyzer" keeps
its nested v5 copy. Net dep-tree shape is unchanged.

Also bumps "@vue/language-server" to ^3.3.0, adds "vuln" and "tools"
phony aliases in the Makefile, and aligns the frontend "audit" target
with the root one (--no-fund --no-audit).

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-19 01:04:49 +00:00
Michael Mayer
74569ba846 Develop: Make compose.yaml configurable via CUSTOM_* env vars #5590
Adds env-var interpolation for the bind host, host ports (HTTP/HTTPS,
MariaDB, PostgreSQL, LDAP), bridge-network name, and PHOTOPRISM_SITE_URL
so developers can spin up parallel dev environments via .env overrides.
Templates the traefik.docker.network labels on every Traefik-routed
service to follow the network rename, fixes the photoprism-vision and
dummy-ldap router/service name collisions, and documents the available
knobs in a new .env.example template (whitelisted in .gitignore).

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-19 00:04:49 +00:00
Michael Mayer
2fc71540a9 Config: Strip default HTTP and HTTPS ports from the site URL #5590
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-19 01:05:23 +02:00
Michael Mayer
a46e0ec1c6 GitHub: Refine questions in feature request template and form
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-19 00:43:43 +02:00
Michael Mayer
671b411a42 GitHub: Update feature-request.yml form
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-19 00:34:28 +02:00
Michael Mayer
6806d2c230 GitHub: Update feature-request.yml forms
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-19 00:32:13 +02:00
Michael Mayer
71f2c927b6 GitHub: Update feature-request.yml forms
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-19 00:30:40 +02:00
Michael Mayer
ba8a4a88c8 GitHub: Update feature-request.yml forms
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-19 00:29:13 +02:00
Michael Mayer
92947ba55f GitHub: Update feature-request.yml forms
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-19 00:25:16 +02:00
Michael Mayer
101b70f775 GitHub: Update issue forms
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-19 00:23:27 +02:00
Michael Mayer
ddd2b19910 GitHub: Update issue templates and forms
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-19 00:19:12 +02:00
Michael Mayer
e5f289aaf9 Rules: Uppercase RFC 2119 keywords in GitHub Issues sections #5584 2026-05-18 19:19:44 +00:00
Michael Mayer
b92897949c Frontend: Emit after-leave from settings password dialog 2026-05-18 16:07:00 +00:00
Michael Mayer
f5725a35ad Rules: Note RFC 2119 keyword preservation in title-case rules #5584 2026-05-18 15:44:21 +00:00
Michael Mayer
50439efc77 Tests: Add validate-gate vitest cases for small edit dialogs #5584 2026-05-18 15:33:48 +00:00
Michael Mayer
1eb81ba432 Frontend: Trim user input at the model layer and rules.text #5584 2026-05-18 15:33:32 +00:00
Michael Mayer
10592bf8d7 Backend: Clip over-length input in clean.Name and clean.State #5584 2026-05-18 15:33:16 +00:00
Michael Mayer
2636fd404b Rules: Update GitHub issue description writing rules
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-18 17:29:18 +02:00
Michael Mayer
47fa9dbe96 Rules: Update shared code comment writing rules
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-18 17:03:15 +02:00
Theresa Gresch
a53b54039b Tests: Adapt tests to frontend changes 2026-05-18 16:44:41 +02:00
Michael Mayer
a0cfcb080e Frontend: Increase available space for captions in the sidebar #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-18 15:38:52 +02:00
Michael Mayer
8fe9fda014 Frontend: Truncate long album & label chips in lightbox sidebar #4966 2026-05-18 13:31:16 +00:00
Michael Mayer
01e5f46276 Frontend: Fix sidebar media type and taken date for guests #4966
For limited-access sessions the empty Photo placeholder seeded by
Photo.getDefaults() short-circuited fileIcon / fileTypeName to "image"
and formatTime to "Unknown", masking the Thumb model's real values.
Gate both reads on this.photo.UID so they fall through to the Thumb
(matches the existing fileInfo guard).
2026-05-18 11:43:52 +00:00
Michael Mayer
464798234a Frontend: Refresh lightbox dynamic caption on sidebar edit #4966
Move caption HTML rendering into the captions plugin (`common/captions.js`)
via `formatCaption(model)` and add `refreshCaption(slide)` so edits made in
the sidebar surface on the overlay when the sidebar collapses. The lightbox
now subscribes to `photos.updated` and patches Title / Caption on slide
models so cross-tab edits also refresh the dynamic caption.
2026-05-18 11:03:29 +00:00
Michael Mayer
949b97f53e Frontend: Make is*/has* predicates return Boolean #4966 2026-05-18 10:11:55 +00:00
Michael Mayer
a7289862e0 Frontend: Make Util.isMobile() return a Boolean #4966 2026-05-18 09:49:16 +00:00
Michael Mayer
218600cc66 Go: Update deps in go.mod, go.sum, and license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-18 11:28:08 +02:00
Michael Mayer
c012700f29 Frontend: Update deps in package.json and package-lock.json #4966 #5585
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-18 11:27:36 +02:00
Michael Mayer
d46f980560 Weblate: Update frontend/src/locales/json/fr.json #5589
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-18 11:21:14 +02:00
Weblate
f64ec572fc Weblate: Update frontend translations 2026-05-18 11:20:10 +02:00
Michael Mayer
73e2eb2898 Frontend: Move .p-meta-* styles from lightbox.css to meta.css #1548 #4966 2026-05-18 08:12:15 +00:00
Michael Mayer
079e85b0ee Frontend: Move face-marker overlay to meta/face/markers.vue #1548 #4966 2026-05-18 08:04:43 +00:00
Michael Mayer
ebf872d5dd Frontend: Rename lightbox 'info' sidebar state to 'sidebar' #4966 #5580 2026-05-18 07:48:42 +00:00
Michael Mayer
408c6fc6aa Develop: Add 'format' umbrella target to Makefile 2026-05-18 07:48:26 +00:00
Michael Mayer
e2ba6eb241 Config: Drop unreachable DatabaseDriverName switch cases #5588 2026-05-17 15:03:41 +00:00
Michael Mayer
18214b2494 DSN: Align ParseDriver and detectDriver alias sets #5588 2026-05-17 15:03:41 +00:00
Michael Mayer
c8390a2e8d Config: Centralize SQL driver identifiers in pkg/dsn #5588 2026-05-17 14:47:43 +00:00
Michael Mayer
ea05645668 Cleanup: Use US English spelling in code comments 2026-05-17 13:46:24 +00:00
Michael Mayer
85221460e9 Search: Use parameterized queries for user search input #5587 2026-05-17 13:46:20 +00:00
Michael Mayer
5ada2aa40a Rules: Update shared code comment writing rules
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-17 15:42:31 +02:00
Michael Mayer
d5649e1309 Rules: Update GitHub issue description writing rules
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-17 15:29:23 +02:00
Michael Mayer
29efda150c Frontend: Remove floating-vue and consolidate on Vuetify tooltips #4966 2026-05-17 11:06:28 +00:00
Michael Mayer
df21d77d30 Frontend: Skip lightbox-sidebar edit on link clicks & compact comments #4966 2026-05-17 09:41:51 +00:00
Michael Mayer
7b18d32143 Rules: Update multi-paragraph JS/Go code comment rules
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-17 11:37:44 +02:00
Michael Mayer
de3f1d134d Rules: Update comment-rules for multi-paragraph descriptions
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-17 11:25:05 +02:00
Michael Mayer
6ec45db03b Rules: Reorder comment-rule bullets and link real paths
Move the 'leave it out / multi-paragraph comments belong elsewhere'
clause ahead of the indent-examples bullet so the priority order reads
high-to-low, and point the off-source destinations at the real specs/
directory and README.md files instead of generic prose.
2026-05-17 09:21:53 +00:00
Michael Mayer
b06475c266 Rules: Consolidate JS/Go code comment guidance into shared file
Move the duplicated doc-comment guidance out of go-code-style.md and
frontend-rules.md into .claude/rules/code-comments.md so both languages
share one source. Mirror the same block in AGENTS.md for Codex, which
does not load .claude/rules/. Raise the follow-up line cap from 1-2 to
up to 3 to match what compact comments actually need in practice.
2026-05-17 09:13:47 +00:00
Michael Mayer
6c54bbc58d Frontend: Hide caption overlay when sidebar opens with lightbox #4966 2026-05-16 19:26:08 +00:00
Michael Mayer
735fa5b3db OIDC: Auto-redirect deep links and preserve return URL #5506
PHOTOPRISM_OIDC_REDIRECT only fired for the root path; deep links under
/library/* fell through to the SPA bootstrap, which served the local
login page with a manual "Continue with OIDC" button. The deep-link
URL was also dropped on the OIDC roundtrip because $session.loginRedirect
lived only in memory, which the IdP bounce wipes.

The login page now auto-triggers OIDC on mount when the flag is on, and
$session persists the redirect target in namespaced storage under a key
(login.next) that survives auth.gohtml's session.* clear. A one-shot
login.logout flag set on signOut suppresses one auto-trigger so an
explicit logout shows the login form once.

Also adds a /logout SPA route so direct visits behave like the navigation
menu action. The new $session.signOut() snapshots the auth token, fires
the server DELETE with it (so the response is 200 and no 401 echo
re-raises the logout flag), then resets client state synchronously.
2026-05-16 17:22:42 +00:00
Michael Mayer
ee89d73ca7 Settings: Save service password and API key on edit #5558
AccPass and AccKey are tagged json:"-" on the backend so they're absent
from GET responses. The base Model only tracked keys present in the
response, so getValues(true) silently dropped credential edits and the
PUT body never carried them.

Adds a generic getWriteOnly() hook on the base Model (parallel to
getDefaults()): subclasses declare write-only fields and the constructor
seeds them into __originalValues so the existing change-diff machinery
detects user edits. Service overrides it for AccPass and AccKey.
2026-05-16 16:20:53 +00:00
Michael Mayer
b0e76449b9 Weblate: Update frontend translations #4966 #5585
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-16 16:50:57 +02:00
Weblate
ff03aaac0b Weblate: Update frontend translations 2026-05-16 16:50:04 +02:00
Michael Mayer
01d19c24ae Frontend: Regenerate translation catalogs #4966
Refreshes `#:` source-path references after the sidebar relocation
from component/sidebar/ to component/lightbox/sidebar(.vue|/toolbar.vue).
No string changes.
2026-05-16 14:44:24 +00:00
Michael Mayer
c20363f1e9 Frontend: Relocate sidebar under component/lightbox/ #4966
Renames the sidebar component to reflect its only mount point: the
lightbox. Bundles file moves, name renames, template tags, imports,
CSS class renames, and acceptance + vitest selector sweeps so the
build never lands half-renamed.

- frontend/src/component/sidebar/info.vue -> lightbox/sidebar.vue
- frontend/src/component/sidebar/inline-toolbar.vue -> lightbox/sidebar/toolbar.vue
- PSidebarInfo -> PLightboxSidebar; PSidebarInlineToolbar -> PLightboxSidebarToolbar
- .p-sidebar-info -> .p-lightbox-sidebar (and the toolbar variant)
- vitest files relocated; gettext catalog regen deferred to next pass.
2026-05-16 14:39:23 +00:00
Michael Mayer
781c9147ba Frontend: Add class "action-save" to meta dialog confirm buttons #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-16 16:23:21 +02:00
Michael Mayer
260e8b6bfb Frontend: Gate metadata-popover saves and fix Unknown-date render #5584
Camera popover (component/meta/camera/dialog.vue): wraps the inputs in
<v-form ref="form" v-model="valid">, seeds validate() in afterEnter, and
gates confirm() on $refs.form.validate() with a "Changes could not be
saved" toast on failure. Save button binds :disabled="!valid" so the
disabled state mirrors the datetime popover's :disabled="invalidDate"
pattern and the user sees the gate before clicking.

Datetime popover (component/meta/datetime/dialog.vue): setTime() now
flips invalidDate when the time field is malformed (previously
short-circuited and left the flag stale, so Confirm stayed enabled
against bad input). Time field gains :error="invalidDate" for visual
consistency with the Day/Month/Year siblings.

Both popovers rename the primary action from "Confirm" to "Save" with a
matching aria-label, aligning with the regular Edit Dialog. The
action-confirm CSS class stays for selector compatibility with the
acceptance tests.

Sidebar (component/sidebar/info.vue): formatTime() now delegates to
photo.getDateString(true) when the full Photo is loaded, so Day/Month/
Year=-1 (Unknown) values render via the model's existing fallback
(Unknown / year / month + year) instead of the padded "Jan 1, 2024"
shape. The Thumb model from viewer.Result doesn't carry Year/Month/
Day, so the fallback to the Thumb's plain TakenAtLocal format still
covers the brief pre-load window.
2026-05-16 14:10:51 +00:00
Michael Mayer
499ac5d009 Frontend: Tighten Photo numeric caps and reveal inline errors #5584
ISO, F Number, and Focal Length on the Edit Dialog and Camera popover
previously capped at 1048576, much wider than the backend's SetExposure
clamps (ISO and FocalLength <= 128000, FNumber <= 256). The looser caps
let the rule pass values the server then quietly rejects. Tightens each
to match the backend, adds Exposure: 64 to PhotoMaxLength, and routes
the Exposure rule through PhotoMaxLength.Exposure instead of a hardcoded
literal.

Drops the bare hide-details attribute from Country, Altitude, ISO,
Exposure, F Number, and Focal Length on both surfaces so the rule's
inline error renders below the input on overflow. Date/time inputs
(Day/Month/Year/Time autocompletes + the standalone DateTime dialog)
stay as-is: autocompletes can only emit valid items, the Time field
combines rules.time() with the :error="invalidDate" visual cue and the
form-validate save gate.
2026-05-16 13:26:39 +00:00
Michael Mayer
04f5dd922f Frontend: Validate inline-text input against backend VARCHAR caps #5584
Adds per-entity MaxLength constants on model/{photo,label,subject,album}.js
mirroring the backend VARCHAR widths, and routes every inline-text input
in the Edit Dialog, Batch Edit, sidebar inline editor, Photo Labels /
People tabs, New People page, and the Label / Album / People edit dialogs
through the shared rules.text(...) factory in common/form.js. Deletes the
$config.get('clip') = 160 anti-pattern that rejected valid 200-char titles
and 1024-char rights fields, and drops the bare `hide-details` attribute
that masked the inline error slot.

Adds a $refs.form.validate() gate to the Edit Dialog and Batch Edit save
handlers, mirroring page/settings/account.vue, so an overlength field
blocks the save with $notify.error("Changes could not be saved") instead
of firing photo.update() against invalid input. For the sidebar inline
editor (no parent v-form) confirmField() now checks the field's
fieldRegistry.maxLength imperatively and keeps the editor open on
overflow; navigation arrows then route through confirmDiscardPending,
which opens the existing discard dialog with a "Discard invalid changes?"
label so the user explicitly chooses to revert or stay.

Includes focused vitest cases for the new caps, the form-validate gate
on both dialogs, the sidebar imperative check, and the new discard-dialog
overflow branch.
2026-05-16 12:46:15 +00:00
Michael Mayer
38e7022765 Frontend: Gate batch-edit albums/labels on feature flags and reorder
Hides the Labels and Albums sections in the Batch Edit dialog when
the matching deployment feature is disabled or the session lacks
the `labels:search` / `albums:search` grant, mirroring the gate
pattern already in `sidebar/info.vue`. Skips the typeahead prefetch
for any disabled section so a deployment with both features off
spends no round-trip on data the dialog never reads. Also moves the
Albums row above Labels so the order matches the lightbox sidebar.
2026-05-16 10:44:09 +00:00
Michael Mayer
11f30f7edc Frontend: Restrict Prettier to CSS and JSON via .prettierignore
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-16 10:34:38 +02:00
Michael Mayer
39216b2bd6 Frontend: Update code formatting rules in eslint.config.mjs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-16 10:09:35 +02:00
Michael Mayer
e7729425fb Frontend: Apply curly autofix sweep to frontend/tests #4966 2026-05-16 08:03:43 +00:00
Michael Mayer
700c308dc3 Frontend: Loosen indent/quotes to warn; add brace-style rule #4966 2026-05-16 08:03:39 +00:00
Michael Mayer
5a144af643 Frontend: Disable Prettier reflow; enforce indent/quotes via ESLint #4966 2026-05-16 08:00:43 +00:00
Michael Mayer
bdd33df25b Frontend: Enforce braced if-bodies via ESLint curly rule #4966 2026-05-16 07:40:10 +00:00
Michael Mayer
e92c4ee80b Frontend: Revert ineffective v-tooltip fix and reformat info.vue #4966 2026-05-16 07:21:23 +00:00
Michael Mayer
0cfdb05a10 Frontend: Update documentation link for v-tooltip in app.js #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-16 09:00:33 +02:00
Michael Mayer
ce1dc46757 Frontend: Move albums above labels in lightbox sidebar #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-16 00:11:20 +02:00
Michael Mayer
c79cb1f022 Frontend: Compact verbose CSS comments in lightbox.css 2026-05-15 18:03:26 +00:00
Michael Mayer
073261ce8d Scripts: Compact check-file comment in check-api-request-limits 2026-05-15 17:53:40 +00:00
Michael Mayer
f9ae856fd7 Backend: Compact verbose comments in thumb, AI face, and pkg/fs 2026-05-15 17:50:08 +00:00
Michael Mayer
e5620f0e76 Backend: Compact verbose comments in entity and photoprism workers 2026-05-15 17:50:08 +00:00
Michael Mayer
c802b05e09 Backend: Compact verbose comments in config and MCP handler 2026-05-15 17:50:08 +00:00
Michael Mayer
2e93a02195 Server: Compact verbose comments in compress and static helpers 2026-05-15 17:50:08 +00:00
Michael Mayer
918a0c2259 Frontend: Compact verbose comments in lightbox and sidebar #4966 2026-05-15 17:35:37 +00:00
Michael Mayer
069b3cd87b Frontend: Compact verbose comments in model/ modules #4966 2026-05-15 17:35:33 +00:00
Michael Mayer
f89a0922a3 Frontend: Compact verbose comments in common/ modules #4966 2026-05-15 17:35:29 +00:00
Michael Mayer
ae2645dbc8 Frontend: Compact verbose code comments in lightbox and sidebar #4966 2026-05-15 17:17:52 +00:00
Michael Mayer
7616a6cdab Frontend: Polish lightbox sidebar with QA feedback #4966 2026-05-15 16:30:23 +00:00
Michael Mayer
4516ce0894 Frontend: Remove custom color from links in info sidebar #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-15 17:39:36 +02:00
Michael Mayer
005c34dd5e Frontend: Fix People discard dialog races and stacked Add-name prompt #4966 2026-05-15 15:37:51 +00:00
Michael Mayer
a37882418f Frontend: Show real metadata for limited roles in lightbox sidebar #4966 2026-05-15 14:22:15 +00:00
Michael Mayer
78c2bb5b30 Agents: Tighten doc-comment rules for compact code comments #4966 2026-05-15 14:00:19 +00:00
Michael Mayer
6973feaed8 Frontend: Keep chip-toolbar Save/Undo visible and fix re-add #4966 2026-05-15 12:02:18 +00:00
Michael Mayer
f6a5dc8412 Go: Update deps in go.mod, go.sum, and license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-15 08:25:31 +02:00
Michael Mayer
ae4e330e2e Frontend: Update deps in package.json and package-lock.json #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-15 08:24:55 +02:00
Michael Mayer
140d241b84 Frontend: Show lightbox controls after resizing and adjust CSS #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-15 08:12:38 +02:00
Michael Mayer
f88e85e4f3 Frontend: Mount face-marker overlay in read-only display mode for viewers
Drops shouldShowEditButton() from the <p-face-marker-overlay> v-if so
non-editable users (Plus / Pro viewer role, anyone reaching the eye
toggle in the sidebar) actually see marker rectangles AND the
in-overlay Back button when they activate display mode. The previous
gate required edit permission, so viewers entered face-marker mode
(chrome hidden), saw nothing, and had no way to exit. Edit gestures
stay gated separately by the overlay's isEditMode flag and the
lightbox-side onCreateFaceMarker / onRemoveFaceMarker /
toggleFaceMarkerEdit handlers that re-check shouldShowEditButton().
Pre-existing bug; surfaced while testing the recent ACL-driven
sidebar refactor (#4966).
2026-05-14 17:34:38 +00:00
Michael Mayer
1d6698da04 Frontend: Gate sidebar visibility on ACL grants, not a static role list
Replaces the static SidebarRestrictedRoles array ("guest", "visitor",
"contributor") and the User/Session isSidebarRestricted helpers with
per-resource $config.allow(resource, perm) checks. The frontend now
mirrors the backend's authority (internal/auth/acl/rules.go) instead
of duplicating policy: each sidebar section reads the same ACL grant
the server uses to redact the JSON response. Drift fix on the way —
"contributor" wasn't a CE role and the static list silently allowed
the "viewer" role full sidebar access without any spec saying so.

New per-section computeds in sidebar/info.vue:
- canViewLibrary  -> $config.allow("photos", "access_library")
  Gates camera, lens, file name, and the rights / notes cluster
  (photographer-EXIF privacy fields).
- canViewPeople   -> $config.allow("people", "search")
- canViewLabels   -> $config.allow("labels", "search")
- canViewAlbums   -> $config.allow("albums", "search")
- canViewPlaces   -> $config.allow("places", "view")

lightbox.vue's fetchPhoto / preloadNextPhoto guards switch from
$session.isSidebarRestricted() to $config.deny("photos",
"access_library") so sessions without library access still skip
the extra GET /photos/:uid calls.
2026-05-14 14:52:34 +00:00
Michael Mayer
7230254a5a Frontend: Add Ctrl+H to toggle the lightbox caption #5580
PhotoSwipe Dynamic Caption overlay can now be hidden via Ctrl+H so
the photo takes the full canvas without leaving the lightbox or
opening the sidebar. State persists to localStorage as
`lightbox.caption` (mirrors the existing `lightbox.info` flag), so
the user's choice survives slide nav, lightbox close/reopen, and
page reload. The toggle gates the forked dynamic-caption plugin's
panAreaSize adjustment via a new `enabled` option and routes the
layout recompute through this.resize(true) after $nextTick (the
.hide-caption class binding is reactive), so the photo actually
reclaims the caption's reserved vertical space when not width-
bound by aspect ratio. Shortcut sits inside the existing input-
focus gate, is inert in face-marker mode, and is a no-op when the
sidebar is open (captions render in the sidebar there). Also adds
mouse-driven Show/Hide Caption entries to the lightbox dropdown
menu, mirroring the Archive/Restore mutually-exclusive pattern.
2026-05-14 13:33:46 +00:00
Michael Mayer
8089214483 Frontend: Regenerate src/locales/json/fr.json #4966 #5579
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-14 11:30:27 +02:00
Weblate
68c6a0a789 Weblate: Update frontend translations 2026-05-14 11:29:34 +02:00
Michael Mayer
c1e4680861 Frontend: Regenerate translation files #4966 #5578
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-14 11:21:28 +02:00
Weblate
77d3e23b52 Weblate: Update frontend translations 2026-05-14 11:19:33 +02:00
Michael Mayer
d68676ad41 Frontend: Regenerate translation catalogs #4966
Picks up the "Edit Faces" / "Remove Name" → "Edit" / "Unassign"
renames from the previous commit. "Edit" was already broadly
translated; "Unassign" is freshly active and needs new translations
across locales. "Remove Name" demoted to obsolete (#~) with prior
translations preserved.
2026-05-14 09:08:57 +00:00
Michael Mayer
34ecdb08d6 Frontend: Tighten face-marker toolbar labels (Edit, Unassign) #4966
Renames the People-section toggle from "Edit Faces" to "Edit" — the
mdi-pencil icon plus surrounding section context already convey the
scope, and the shorter label aligns with the rest of the inline-toolbar
pencil affordances. Renames the marker-name eject tooltip from "Remove
Name" to "Unassign", which more accurately describes the action (the
subject assignment is removed, not the name as text). Same string now
covers both edit-dialog and sidebar surfaces. Also reorders a couple
of v-btn attributes for consistency.
2026-05-14 09:08:50 +00:00
Michael Mayer
7252c82695 Frontend: Replace "subject" icon in lightbox sidebar #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-14 10:45:41 +02:00
Michael Mayer
231d3c6291 Frontend: Replace "artist" icon in lightbox sidebar #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-14 10:33:11 +02:00
Michael Mayer
f741f8e103 Frontend: Skip sidebar row tooltip when no icon anchors it #4966
Notes uses `icon: null` so Vuetify's default `'end center'` tooltip
location anchors against an empty prepend slot, putting the tooltip
in a visually inconsistent place vs sibling rows. Gate the tooltip
on the row having an icon so Notes (and any future no-icon row in
detailsFields) skips the tooltip entirely — matches Title and
Caption above which never had one. The "Notes" / placeholder text
is already visible inline as the add-prompt, so no information is
lost.
2026-05-14 07:33:13 +00:00
Michael Mayer
15dabc5dcd Frontend: Highlight matching face marker on sidebar hover #4966
Hovering a person row in the lightbox sidebar's People section now
sets a thicker purple stroke + glow on the matching face-marker rect
on the image, making the visual link between the row and the box
unambiguous in both display and edit modes. Implementation routes
through a new hoveredMarkerUid field on the $faceMarkers singleton
that the lightbox forwards as a prop to the overlay. Reverse
direction (rect hover → sidebar row) isn't wired since rects carry
pointer-events: none — recorded for future work in the singleton +
CSS comments. Also drops two redundant text-align: start declarations
on .meta-title / .meta-caption (defaults already match).
2026-05-14 07:06:10 +00:00
Michael Mayer
30e41c12d5 Frontend: Move Archive shortcut to Ctrl+X, gate keys on input focus #4966
Adds an input/textarea/contenteditable focus gate at the top of the
lightbox onShortCut handler so Ctrl+A select-all, Ctrl+C copy, etc.
no longer trigger global lightbox actions when a sidebar inline
editor or edit-dialog field has focus. Migrates the Archive/Restore
binding from KeyA to KeyX (Gmail/Outlook-style mnemonic) so the
canonical select-all chord stays free for text editing in addition
to the focus gate. Updates the matching face-marker disabled-shortcut
list and acceptance + vitest test cases.
2026-05-14 06:39:19 +00:00
Michael Mayer
ee775026e4 Frontend: Merge sidebar text fields, add Undo + commit-on-Enter #4966
Unifies Subject / Artist / Copyright / License / Keywords / Notes
into a single icon-prepended row layout (Option A from the proposal),
adds per-field maxLength sourced from new PhotoMaxLength constants
mirroring the backend VARCHAR caps, fixes a pre-existing textarea
auto-grow regression caused by a static min-height override in
lightbox.css, wires Enter-to-commit on the single-line fields via a
commitOnEnter registry flag, and adds an Undo affordance + new
hideEditUndo / hideEditSave toggles for A/B testing the inline
toolbar chrome.
2026-05-14 06:38:53 +00:00
Michael Mayer
367af097f0 Frontend: Replace action-verb literals with ACTION_* consts #4966
common/event.js now exports six action-verb constants (ACTION_CREATED,
ACTION_UPDATED, ACTION_DELETED, ACTION_ARCHIVED, ACTION_RESTORED,
ACTION_EDITED) and composes ENTITY_MUTATIONS from them so there is one
source of truth. Every onUpdate(ev, data) switch in the frontend now
references the symbols instead of the literal strings — eight cache /
page-level handlers across albums, labels, library/browse, photos,
people, the album-photos view, and the photo edit dialog.

The motivation is navigation: grep / IDE find-references on
"updated" or "created" is overwhelmed by Vue lifecycle hooks, Date
methods, prose in comments, and unrelated occurrences of the same
English word. ACTION_UPDATED finds only the event-handling sites.
The count.* subtype switch in common/config.js stays on string
literals because those are count category names, not entity-mutation
verbs.
2026-05-14 03:37:38 +00:00
Michael Mayer
10f7e4493f Frontend: Migrate inline title/text rules to rules.text factory #4966
Replaces eight per-component titleRule / textRule / markerNameRule
arrow functions across the album / label / people edit dialogs, the
photo edit details panel, and the sidebar inline editors with the
existing rules.text(required, min, max, label) factory in
common/form.js. The factory is already null-, undefined-, and
object-safe via its typeof v !== "string" short-circuit, so this
removes a class of latent v.length crashes and produces label-
specific localized error messages ("Title is too long",
"Name is too long", etc.) instead of one generic string.

Also deletes six dead-code titleRule definitions in album/toolbar,
page/albums, page/labels, page/library/browse, and the two People
pages — defined in data() but never referenced from the template.

While there, harden two inconsistencies in form.js:
- isTime now short-circuits on non-string / empty inputs to match
  the other is* helpers (isEmail, isUrl, isLat, etc.).
- rules.time(true) validity rule short-circuits on empty input so
  "Invalid time" isn't flashed alongside "This field is required"
  — matches the email(true) / url(true) pattern.
2026-05-14 02:55:20 +00:00
Michael Mayer
1bff9aab90 Frontend: Guard photo/edit/labels nameRule against null/object input #4966
The v-combobox initializes newLabelModel = null and validates :rules on
mount, so nameRule must tolerate null, strings (free-text entry), and
item objects (return-object). Pre-fix the rule did v.length and threw
"Cannot read properties of null (reading 'length')" on every Edit
Dialog open. Six vitest cases pin the contract.
2026-05-14 02:35:30 +00:00
Michael Mayer
accce40ce3 Events: Add photos.edited cache invalidation for batch edits #4966
Backend emits a new lightweight photos.edited event from
batch_photos_edit.go via the generic event.EntitiesEdited helper, so the
frontend can drop stale Photo._cache LRU entries after a batch save
without the per-UID payload storm that PublishPhotoEvent would
otherwise produce. The frontend's cache layers route through a shared
subscribeEntityActions helper that subscribes once per namespace and
filters by action verb against ENTITY_MUTATIONS, so any future entity-
mutation verb joins via one edit on each side. Page-level wildcard
subscribers learn a new "edited" case so the cards list refreshes on
return-to-view.
2026-05-14 02:35:24 +00:00
Michael Mayer
d2787fa0b7 Frontend: Rename face-marker "draw" mode to "edit" mode #4966
Align the internal naming with the user-facing "Edit Faces" toggle.
Mode constant FaceMarkerDraw → FaceMarkerEdit (value "draw" → "edit");
singleton draw() → edit() and isDraw → isEdit; lightbox method
toggleFaceMarkerDraw → toggleFaceMarkerEdit; sidebar emit + listener
toggle-face-marker-draw → toggle-face-marker-edit; overlay computed
isDrawMode → isEditMode; CSS class .is-drawing → .is-edit. The
per-pointer InteractionDraw constant ("draw" string) stays untouched
— that names the drag-to-create-rectangle gesture inside edit mode,
distinct from the mode itself.
2026-05-13 23:55:21 +00:00
Michael Mayer
8c18b77d02 Frontend: Per-role People-section toggle; pencil exits to null #4966
Editable users now see ONLY the pencil / pencil-off "Edit Faces"
toggle (.meta-faces-edit); non-editable users see ONLY the eye /
eye-off "Show face markers" toggle (.meta-markers-toggle, gated on
people.length > 0). Draw mode is a strict superset of display mode
for editable users — both freeze playback, hide chrome, and gate
the conflict-only keyboard shortcuts — so a separate display toggle
adds no value and was confusing in the two-button layout.

toggleFaceMarkerDraw's exit path now lands on `null` instead of
stepping down to FaceMarkerDisplay (the historical ✓ Done semantic
needed the eye toggle as a second affordance to land on display
mode — gone with the single-button-per-role model, so the pencil
would get stuck "on" without this change).

toggleFaceMarkerMode gate relaxed from shouldShowEditButton() to
featPeople: non-editable users can now toggle display mode via the
eye button. Sidebar onToggleFaceMarkerMode similarly dropped its
isEditable guard. The shortcut-gate test is parametrized over both
display and draw mode to pin that the inert key set applies in
both.
2026-05-13 23:35:03 +00:00
Michael Mayer
4e2c335a65 Frontend: Delete dead isInputElement & isMediaElement exports #4966
Both helpers in common/view.js had zero source consumers after the
preventNavigationTouchEvent rewrite. isInputElement was historically
used to exempt button taps from the unconditional touchmove
preventDefault (name was misleading — it only matched HTMLButtonElement,
not real inputs); the rewrite inlines a broader closest('button, input,
textarea, select, a[href], [role=button]') check instead.
isMediaElement was historically used to also fire preventDefault on
touchstart of canvas-area img/video/canvas targets (likely a defense
against iOS default touch behavior on photos, but
.pswp__img { -webkit-touch-callout: default; } in lightbox.css
re-enables the iOS save-image callout anyway); the user-clarified
handler intent is edge-only, so this branch is no longer needed.
2026-05-13 23:13:09 +00:00
Michael Mayer
607af6d6ed Frontend: Forward wheel zoom in draw mode; scope nav suppressor to edges #4966
Mouse-wheel zoom no longer works in face-marker draw mode because the
overlay's pointer-events: auto (needed for drag-to-draw) swallows wheel
events that PhotoSwipe sits in a sibling subtree from. Add a @wheel
listener on the overlay root that re-dispatches a synthetic WheelEvent
on pswp.element so zoom-to-cursor works identically to display mode.

Rewrite preventNavigationTouchEvent to a 30 px edge-band-scoped
suppressor. The previous implementation preventDefault()ed every
non-button touchmove anywhere on the page while the lightbox was open,
which made the sidebar / dialog content / menus unscrollable on iPad.
The handler now fires only when the touch sits inside the leftmost,
rightmost, or topmost 30 px band of the viewport — and even then it
exempts taps on interactive widgets (button, input, textarea, select,
a[href], [role=button], including taps that land on a nested glyph
inside a button) so the overlay's top-left Back button and the
sidebar's right-edge action buttons stay tap-reliable.

Add 21 regression cases for preventNavigationTouchEvent in
common/view.test.js with a minimal TouchEvent polyfill — jsdom doesn't
ship one and the handler's first guard is `ev instanceof TouchEvent`,
so without the polyfill the function silently no-ops in tests.
2026-05-13 23:05:58 +00:00
Michael Mayer
42e181aff3 Frontend: Regenerate translations #4966 #5576
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-14 00:18:16 +02:00
Michael Mayer
02012bd694 Frontend: Gate conflicting keyboard shortcuts in face-marker mode #4966
While face-marker mode is active, suppress shortcuts that open
chrome we hide (Period menu+select, KeyL menu+like), stack a
competing modal (KeyE Edit Dialog), fire silent destructive
mutations (KeyA archive), or contradict the entry-only-pause /
overlay-stays-mounted contracts (KeyS slideshow, Space play,
ArrowLeft / ArrowRight slide-nav). Escape, Tab, KeyI, KeyD, KeyF,
KeyM stay enabled — Escape and KeyI already exit face-marker mode
in lockstep; the others are non-destructive display-only.
Implemented as a single isShortcutDisabledInFaceMarkerMode
predicate consulted at the head of onShortCut and onKeyDown.
2026-05-14 00:15:03 +02:00
Michael Mayer
777d20bde3 Frontend: Move face-marker removal from combobox hazard to edit mode #4966
The per-row mdi-close button inside the marker combobox read as
"clear input" but actually rejected the face marker on the backend
without confirmation — a real hazard. Retire the button entirely:
sidebar #append-inner now only renders the mdi-eject for named
markers. Add a click-to-remove flow on the face-marker overlay
instead: in edit mode, clicking an existing unnamed marker rect
opens an inline confirm pill (mdi-delete ✓ / mdi-close ✕) anchored
to the marker. Targeted rect gains a red --removing outline. ✓
emits the new `remove` event the lightbox routes to
onRemoveFaceMarker; ✕ dismisses. Escape clears a pending remove
first; leaving draw mode clears it too. Named markers stay
non-removable here — eject first.

Rename the sidebar +/Done toggle to a pencil/pencil-off Edit Faces
toggle (CSS class meta-marker-add → meta-faces-edit) to signal the
toggle now covers both add and remove. Names of named markers stay
visible in edit mode so the user can tell named (untouchable) from
unnamed (clickable) markers at a glance.
2026-05-14 00:15:03 +02:00
Weblate
89bffa1d1a Weblate: Update frontend translations 2026-05-13 23:49:39 +02:00
Michael Mayer
7963cf2207 Frontend: Hide lightbox chrome & add Back button in face-marker mode #4966
While face-marker mode is active the standard PhotoSwipe chrome over
the canvas (top-bar buttons including close, prev/next arrows,
caption, counter, custom video controls) is hidden via CSS — in draw
mode the overlay's pointer capture made them unreachable anyway, and
in display mode they would fire on a paused-video / disabled state.
The face-marker overlay grows its own circular Back button
(mdi-arrow-left, RTL-aware, top-left in LTR / top-right in RTL) with
its own pointer-events so it works in both modes. Click emits cancel,
which the lightbox already binds to exitFaceMarkerMode — the single
explicit exit affordance from face-marker mode. Sidebar chrome stays
reachable.
2026-05-13 21:17:48 +00:00
Michael Mayer
1ec6a35016 Frontend: Extract face-marker state into singleton; drop local array #4966
Move faceMarkerMode, markersBusy, and pendingNameMarkerUid out of the
lightbox data() into common/face-markers.js — a reactive singleton
imported by both lightbox.vue and sidebar/info.vue, removing the
view.faceMarkerMode bridge. The sidebar reads the singleton directly
and continues to emit transition requests; the lightbox stays the
policy owner and writes through the singleton's setters. Replace the
local faceMarkers data array with a markers computed that returns
photo.getMarkers(true); reloadFaceMarkers() is gone and the overlay
re-renders via Vue reactivity on file.Markers (syncMarkerInFile stays
to bridge API-result Marker instances back into the raw entry).
2026-05-13 17:05:45 +00:00
Michael Mayer
771150a7c8 Frontend: Simplify face-marker mode state & switch menu-icon to null #4966
Replace .pswp--adding-marker imperative class toggle with declarative
:class="{'face-marker-mode': faceMarkerMode}" on .p-lightbox__content;
playback (video + slideshow) now pauses on entry into either display
or draw mode and is NOT resumed on exit. Rename toggleMarkersVisible
to toggleFaceMarkerMode and toggleAddingMarker to toggleFaceMarkerDraw
across the lightbox, sidebar emits/handlers, and tests. Switch every
:menu-icon="false" to :menu-icon="null" (typed IconValue form) to
silence Vuetify prop warnings.
2026-05-13 16:36:42 +00:00
Michael Mayer
d1c2e883f5 Frontend: Regenerate src/locales/translations.pot #4966 #5574
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-13 14:09:26 +02:00
Michael Mayer
aa772b62c0 Frontend: Update src/locales/json/fr.json #5574
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-13 14:08:12 +02:00
Weblate
385566adee Weblate: Update frontend translations 2026-05-13 14:07:28 +02:00
Michael Mayer
be0e5f127b Frontend: Sidebar map marker opens the Adjust Location dialog #4966
The MapLibre default marker is rendered as a <button>, so the
browser styled it with `cursor: pointer` even though no click
handler was attached — a phantom affordance. As an interim
improvement, wire the marker to `openLocationDialog` for editable
sessions and remove the pointer cursor for everyone else.

`<p-map>` (`component/map.vue`) gained a `markerClickable` prop:
when true, it attaches a click listener on the marker's DOM
element that emits `marker-clicked` with the marker's
`{ lat, lng }` (and stops propagation), and adds an
`is-marker-clickable` class to the `.p-map` root for cursor
scoping. The marker stays keyboard-activatable via the existing
<button> semantics.

`places.css` defaults `.p-map .maplibregl-marker { cursor: default }`
and restores `pointer` only under `.p-map.is-marker-clickable`, so
read-only sessions no longer see a misleading affordance.

In the sidebar (`component/sidebar/info.vue`), the embedded map
passes `:marker-clickable="isEditable"` and binds
`@marker-clicked="openLocationDialog"`. `openLocationDialog`
already gates internally on `isEditable && featPlaces`, so the
event side is defense-in-depth.
2026-05-13 12:00:14 +00:00
Michael Mayer
4f3a850108 Frontend: Click-to-edit sidebar rows + merged file/location rows #4966
Every editable sidebar row is now itself the primary click target.
Click the row -> opens the matching dialog (Date / Camera / Lens /
Location) or enters the matching inline edit (Title / Caption /
Subject / Artist / Copyright / License / Keywords / Notes). The
pencil icons remain available as a secondary affordance but are
hidden by default via a new `hideEditPencils: true` data flag plus
a `.hide-edit-pencils` parent rule in lightbox.css; save and undo
buttons in the chip-section toolbars stay reachable because they
carry their own class names.

Two helper methods route the dispatch: `onTextRowClick(field, value)`
(edit mode -> startEditing, read-only -> $util.copyText) and
`onLocationRowClick()` (editable -> open dialog, read-only +
coords -> copyLatLng, read-only + placeName -> copyText). The new
`open<X>Dialog` methods gate `isEditable` (and `featPlaces` for
location) inside the method body, so the template never inlines
the gate.

File row consolidated into a single two-line v-list-item
(`meta-file`) with `prepend-icon="fileIcon"` (new computed mapping
media.Type to mdi glyphs); title is fileInfo, subtitle is fileName.
Click-to-copy is the only affordance — no pencil, no dialog.
`fileName` now returns `null` (not "") for restricted sessions and
the no-photo state so Vuetify's subtitle gate (`props.subtitle !=
null`) skips rendering an empty subtitle element. Historical
`metadata__file-info` / `metadata__file-name` classes retired in
favor of the consistent `meta-file`.

Location row consolidated similarly via new `locationTitle`,
`locationSubtitle`, `locationRowVisible`, `locationRowClickable`,
`coordinatesLine` computeds. New `getLatLngShort()` on the Thumb
model uses 4-digit precision and an en-space separator; `getLatLng()`
also bumped from regular space to en-space for consistency.

CSS polish: places.css sidebar map switches from `min-height: 259px`
+ `aspect-ratio: 1` to `height: 200px`, freeing vertical space;
one v-divider between camera/lens and location removed.

Tests + acceptance pins updated to the new merged-row class and
the `null` semantic.
2026-05-13 11:37:38 +00:00
Michael Mayer
a5c27bba76 Frontend: Drop sidebar combobox chevrons and polish lightbox theme #4966
Sidebar inputs drop variant="plain" to pick up the project-wide
solo-filled default. Marker, Labels, and Albums comboboxes use
:menu-icon="false" unconditionally; the Edit Dialog People tab,
New Person page, and location-search autocomplete adopt the same
chevron-off convention. Labels / Albums placeholders standardised
on "Select or create labels/albums".

Lightbox theme: surface raised to #151515, surface-bright to #171717
so it stays brighter than surface, highlight softened to #383838;
new fill-opacity, theme-overlay-multiplier, and *-emphasis-opacity
variables; color and variable comments rewritten and trimmed.

lightbox.css: migrate inline-input geometry from per-rule min-height
and padding overrides to --v-input-control-height + --v-field-padding-*
custom properties; drop the redundant .meta-inline-menu .v-list
secondary-light lift; reword the scrollbar TODO as a deliberate
follow-up.

The marker-chevron test was renamed and rewritten to assert
unconditional chevron absence on every marker row.
2026-05-13 09:38:42 +00:00
Michael Mayer
93bb435203 Frontend: Hide marker combobox chevron when the marker is named #4966 2026-05-12 12:57:50 +00:00
Michael Mayer
3eb6a42633 Frontend: Refine People-section face-marker exit semantics #4966 2026-05-12 11:41:45 +00:00
Michael Mayer
566ca155fc Frontend: Clear sidebar label combobox on Enter like albums #4966 2026-05-12 11:05:46 +00:00
Michael Mayer
a5e9dfeb0b Frontend: Refactor sidebar action icons to v-btn and tune theme #4966 2026-05-12 09:50:05 +00:00
Michael Mayer
05a305793e Frontend: Treat all punctuation as separators in normalizeTitle #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-12 10:48:33 +02:00
Michael Mayer
2655a53848 Frontend: Collapse face-marker UI booleans into a state machine #4966
Replaces lightbox.markersVisible + lightbox.addingMarker with a single faceMarkerMode field (null | FaceMarkerDisplay | FaceMarkerDraw). The state-enum constants live in options/face-marker.js so the lightbox, the face-marker overlay's mode prop, and the sidebar's derived markersVisible / addingMarker computeds all reference the same source of truth — no string literals to drift.

The previous two booleans encoded one invalid combination (draw mode without markers visible) that the code carefully avoided but never enforced; the enum makes it unrepresentable. The watcher on faceMarkerMode owns playback pause / resume, the toggleMarkersVisible and toggleAddingMarker exit paths both route through a single exitFaceMarkerMode helper (which clears the local faceMarkers array too), and hideInfo now fully exits face-marker UI when active so a closed sidebar can't strand the overlay over a resumed video.

Also drops the one-line cancelAddingMarker delegate (F2-2): the overlay's removed @cancel emit was the only consumer; the template @cancel binding and onEscapeKey now point at exitFaceMarkerMode directly.
2026-05-11 18:19:38 +00:00
Michael Mayer
07560603d2 Frontend: Escape hides face-marker UI before closing lightbox #4966
Exiting Add Face mode (✓ Done or Escape) now also clears markersVisible / faceMarkers so the resumed video is no longer painted with stale boxes that anchor to the JPG cover. Escape from display-only mode (eye toggle without Add Face) follows the same priority chain: hide the overlay first, close the lightbox only when no face-marker UI is active. Routed via a shared exitFaceMarkerMode() helper called from both toggleAddingMarker's exit path and cancelAddingMarker.
2026-05-11 17:46:46 +00:00
Michael Mayer
d379b1e0d9 Frontend: Letterbox-aware face marker bounds and Escape routing #4966
Two related overlay refinements for video / Live / Animated slides where the JPG cover is CSS-stretched to the slide container box:

1. updateBounds now insets the bounds rect by the letterbox / pillarbox gap derived from the image's naturalWidth/naturalHeight. The <img class=pswp__image> takes the parent's height: 100% via CSS, but the inscribed image content honours object-fit: contain — so getBoundingClientRect returns the BOX, not the displayed image. The previous behaviour rendered face markers across the black bars (faces looked TALL). An image load listener triggers re-computation once natural dimensions are available.

2. The window-level keydown listener was removed in favour of the documented onShortCut + @keydown.esc.exact pattern (see frontend/src/common/README.md). The overlay now exposes a public handleEscape() method that the lightbox's onEscapeKey calls via ref: when an in-flight draw / move / resize or unconfirmed pending rect exists the overlay consumes the key; otherwise the lightbox decides between exiting draw mode (cancelAddingMarker) and closing the lightbox (close). Previously Escape during draw mode closed the lightbox via the v-dialog handler.
2026-05-11 17:35:15 +00:00
Michael Mayer
b7006e7aa4 Frontend: Swap video for still JPG while drawing a face region #4966
A paused HTMLVideoElement holds an arbitrary frame, not the still image the face markers were detected on, so the rectangles never align with anything. Add a pswp--adding-marker class on the PhotoSwipe root while addingMarker is true; existing .pswp__media CSS rules already flip .pswp__image visible and .pswp__video / .pswp__play hidden — extend them to honour the new class for video, Live, and Animated slides. Trigger a face-marker-overlay scheduleUpdate() after the swap so bounds re-anchor on the now-visible <img>.
2026-05-11 17:34:40 +00:00
Michael Mayer
2d419ccaa7 Frontend: Show original media file name in sidebar for video #4966
The sidebar's fileName computed used to surface primaryFile().Name, which for video / Live / Animated photos is the generated JPEG cover and renders as 'foo.mp4.jpg'. Route through Photo.originalFile() first so the user-facing path matches the cards view (getOriginalName()).
2026-05-11 17:34:22 +00:00
Michael Mayer
ecc6a0c58a Frontend: Pause playable media while drawing a face region #4966
Auto-playing video, Live Photo, and Animated all kept running while addingMarker was true, defeating accurate face-region selection. A watch on addingMarker now routes every flip through pausePlaybackForAddingMarker / restorePlaybackAfterAddingMarker, capturing the playing state on entry and only resuming on exit if the user had been actively playing. hideInfo also clears addingMarker so closing the sidebar mid-draw tears down the overlay and resumes playback.
2026-05-11 17:03:35 +00:00
Michael Mayer
0513a9f9d0 Frontend: Harden sidebar marker rename against races and WS snapback #4966
Locale-aware findKnownPerson (no en lock-in); sort knownPeople via locale-aware localeCompare. Add per-draft editing flag so syncMarkerDrafts leaves typed text alone during concurrent WS updates. Gate confirmMarkerName on markersBusy, marker.Invalid, and a 200ms destructive-action window stamped by onRemoveMarker / onEjectMarker. Store markerUid (not the transient Marker instance) in addNameDialog; re-derive the live marker via findMarker(uid) at commit. Scope cancelMarkerName blur to the marker row's own input.
2026-05-11 17:03:29 +00:00
Michael Mayer
65a982ee7c Frontend: Drop chip-selector blur commit hook entirely #4966
The previous fix (a81082a26) kept @blur="onInputBlur" with a
relatedTarget guard so ArrowDown navigation wouldn't commit typed
prefixes. In practice the blur hook had no reachable trigger left
once that guard was in place — neither Tab nor click-outside
actually fired the commit. Drop the @blur binding and the
onInputBlur helper entirely; commits now happen only on Enter
(`onEnter`) or when v-combobox emits a real item-object selection
(`onComboboxChange`). Pending typed text is discarded when focus
leaves the field, which matches how the sidebar combobox already
behaves. Test pin rewritten to assert both halves of the contract:
ArrowDown does not commit, Enter still does.
2026-05-11 12:46:41 +00:00
Michael Mayer
b06483c47b Batch: Resolve label adds via FirstOrCreateLabel for homophone safety
The batch-edit dialog routed user-typed label adds through
entity.FindLabel(title, true) and only fell back to
FirstOrCreateLabel when FindLabel reported not-found. FindLabel's
slug fallback is not homophone-safe: when the user typed `吻`
(kiss, pinyin `wěn`) and only `问` (ask, same pinyin slug `wen`)
existed, FindLabel returned `问` and the new chip silently
disappeared on Save because the photo-label join was created
against the wrong label.

ensureLabelUID and ApplyLabels now call FirstOrCreateLabel
directly. That path goes through findLabelByExactName, which
applies acceptLabelSlugMatch: a slug-only collision against a
first-created homophone (LabelSlug == CustomSlug) is rejected, so
FirstOrCreateLabel falls through to creating a new row with a
deterministic disambiguating slug (e.g. `wen-bf535866`). FindLabel
itself is intentionally left unchanged — its callers (vision label
normalizer, slug-string lookups in tests) rely on the slug
fallback for non-homophone scenarios.
2026-05-11 12:26:44 +00:00
Michael Mayer
a81082a267 Frontend: Stop chip-selector from committing on ArrowDown blur #4966
Vuetify's v-combobox shifts DOM focus from the input to the first
v-list-item in the dropdown menu when the user presses ArrowDown.
The chip-selector's @blur handler treated that focus shift as
"user is leaving the field — commit pending text," which silently
turned typed prefixes (e.g. `ca`) into brand-new chips before the
user could highlight `Camping` and press Enter.

The blur handler now inspects relatedTarget and skips the commit
when focus moves into a v-list-item or any descendant of a
v-overlay-container / v-list / v-menu. Tabbing or clicking to a
sibling field still commits as before. The chip-selector backs the
Labels and Albums inputs in the batch-edit dialog (and the file
dialog), so the regression was visible in both surfaces.
2026-05-11 12:26:33 +00:00
Michael Mayer
9788c2b06f Frontend: Restore sidebar chip link click vs × remove split #4966
Earlier in the chip-removal refactor onChipActivate started toggling
pending removal whenever isEditable, which made the entire chip area
act as a remove button instead of the long-standing link gesture.
Click + Enter on a chip now always route through navigateToLabel /
navigateToAlbum (in both editable and read-only contexts); pending
removal lives on the × icon's own @click handler and the keyboard
Delete / Backspace path via onChipDelete. The × icon gains a `Remove`
tooltip and a `meta-chip__remove` class for future styling hooks.
Existing "toggles removal on click" tests rewritten as "navigates
even when editable" pins so the regression cannot return silently.
2026-05-11 11:21:00 +00:00
Michael Mayer
a6f6cd03b4 Frontend: Subscribe typeahead cache to labels/albums.created #4966
Adding a brand-new label or album from any consumer left the
typeahead cache stale until something else evicted it. The cache
already listened for labels.updated / labels.deleted / albums.updated
/ albums.deleted / config.updated but not the *.created channels
that the entity layer fires from FirstOrCreateLabel and Album.Save.
Result: typing the just-added label or album on a subsequent photo
returned no autocomplete match, even though the row existed
server-side. Subscribing to labels.created and albums.created
evicts the relevant slot so the next read repopulates.

Refreshes the module-level comment to reflect what each backend
event actually publishes (entity-layer EntitiesCreated for create,
PublishLabelEvent/PublishAlbumEvent for update, EntitiesDeleted for
batch delete). Adds matching Vitest cases mirroring the existing
labels.updated / albums.updated tests.
2026-05-11 11:09:50 +00:00
Michael Mayer
d86583a0a2 Frontend: Auto-commit and undo chip removals in sidebar #4966
Soft-removed labels and albums now vanish from the layout (filtered
out by new visibleLabels / visibleAlbums computeds) instead of
turning red with an undo-icon swap. The chip-row wrapper disappears
once every chip in the section is queued for removal, so no empty
box hovers above the combobox.

A new Undo icon in the section toolbar (next to the existing
Apply check) restores all pending removals in one click, wired via
the shared inline-toolbar's new canUndo prop. Pending removals
auto-commit silently on slide navigation and lightbox close, just
like inline-text auto-commit on blur — the discard-pending dialog
only fires for typed combobox text, marker drafts, and the open
Add-name confirmation. Adds Vitest coverage for the new
visibleLabels / visibleAlbums computeds, undoChipRemovals,
auto-commit in confirmDiscardPending, and the inline-toolbar's
canUndo / undo emit contract.
2026-05-11 10:46:09 +00:00
Michael Mayer
3be40cee95 Frontend: Align PMetaDatetimeDialog name with kebab CSS class #4966
Rename PMetaDateTimeDialog to PMetaDatetimeDialog so Vue's
PascalCase-to-kebab mapping produces <p-meta-datetime-dialog>,
matching the .p-meta-datetime-dialog CSS scope class. Pre-rename
the template tag was <p-meta-date-time-dialog> (three words) while
the CSS class compressed to "datetime"; aligning the component
name on the compact form removes that inconsistency for good.
2026-05-11 09:57:12 +00:00
Michael Mayer
cec34a4c30 Frontend: Rename meta dialog components to PMeta* #4966
Rename PCameraDialog, PDateTimeDialog, PLocationDialog, and
PLocationInput to PMetaCameraDialog, PMetaDateTimeDialog,
PMetaLocationDialog, and PMetaLocationInput so the symbol mirrors
the new meta/<domain>/ directory tree introduced in 177771c5c.
CSS scope classes, template tags, Vitest stubs, and TestCafe
page-model selectors update in lockstep so the kebab-case CSS
class and the PascalCase component name stay derived from each
other (.p-meta-camera-dialog etc.).
2026-05-11 09:52:37 +00:00
Michael Mayer
177771c5cc Frontend: Group metadata dialogs under meta/<domain>/ #4966
Move the three metadata-adjustment dialogs out of sidebar/ and
location/ into a shared meta/<domain>/ tree so they read as
reusable metadata editors rather than sidebar-internal helpers
(the location dialog was already imported by the Edit Dialog and
batch-edit). Matching Vitest files relocate alongside their
sources. Component names (PCameraDialog, PDateTimeDialog,
PLocationDialog, PLocationInput) are preserved.
2026-05-11 09:38:17 +00:00
Weblate
b8ae7979d8 Weblate: Update frontend translations 2026-05-11 11:31:57 +02:00
Michael Mayer
35e46215c9 Frontend: Refine sidebar Date & Time and Camera Info dialogs #4966
Rename the dialog titles to "Adjust Date & Time" and "Adjust Camera
Info" to mirror the existing "Adjust Location" wording, and align the
layout with the project's canonical dialog convention: v-card-text
carries only the shared "dense" class, action buttons live in a
sibling v-card-actions, and the local breathing room sits on v-row
via "py-2" so the v-card-text class stays uniform across dialogs.
2026-05-11 09:16:30 +00:00
Michael Mayer
ad00bf3fec Frontend: Group special themes after default in themes.js #4966 2026-05-11 07:34:59 +00:00
Michael Mayer
b2d116eb64 Frontend: Annotate theme color tokens and variables #4966 2026-05-11 07:31:56 +00:00
Michael Mayer
29a994a648 Rules: Refine and dedupe agent rules, fix stale Vuex claim 2026-05-11 07:17:54 +00:00
Michael Mayer
bbc5d8715b Frontend: Regenerate src/locales/*.json #4966 #5568
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-10 19:37:09 +02:00
Weblate
60885b567d Weblate: Update frontend translations 2026-05-10 19:35:57 +02:00
Michael Mayer
21ffa21221 Frontend: Update translations in src/locales/*.po #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-10 19:31:06 +02:00
Michael Mayer
9d3d96de83 Frontend: Avoid <template> inside SVG to unblock gettext-extract #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-10 19:30:21 +02:00
Michael Mayer
7c6731cdc8 Frontend: Refine sidebar tooltip, dialog colors, and file row #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-10 19:19:01 +02:00
Michael Mayer
211c3eb64d Frontend: Refine sidebar album combobox and lightbox theme tokens #4966
Switch the sidebar album input to v-combobox so free-text Enter creates a
new album (mirroring labels) instead of v-autocomplete auto-committing a
substring-filtered match. Drop the fuzzy startsWith/includes fallback in
onAlbumEnter so typing `test` no longer silently merges into an existing
`LRUTEST-ALBUM-…`. Map album options to plain {Title, UID} objects and
make onAlbumSelected a silent no-op on transient non-object updates so
the combobox stays usable while typing.

Restore the lightbox theme's surface-variant to a contrasting light grey
(#bdbdbd) — the previous #242628 blended into the `selected` row bg and
made Vuetify-active items invisible because VCombobox defaults bind
`text-surface-variant` onto the matched row. Invert on-surface-variant
to keep the pair sane and add a scoped tooltip CSS rule so lightbox
tooltips render dark with light text instead of inheriting the now-light
surface-variant block.
2026-05-10 14:13:09 +00:00
Michael Mayer
5a0a7199aa API: Add config.updated broadcast tests to api_client_config_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-10 15:07:37 +02:00
Theresa Gresch
aad39291a5 MCP: Add HTTP scope-gate tests for admin app password #5024 2026-05-10 15:00:43 +02:00
Michael Mayer
0d960aa36a Go: Bump toolchain to 1.26.3 to clear stdlib CVE advisories
Upstream Go's May 2026 release patches 8 stdlib advisories that fired
against the previously declared toolchain (1.26.2):

- GO-2026-4918 / CVE-2026-33814 (HTTP/2 SETTINGS_MAX_FRAME_SIZE loop)
- GO-2026-4971 / CVE-2026-39836 (net.Dial NUL byte panic, Windows)
- GO-2026-4976 / CVE-2026-39825 (ReverseProxy URL param forwarding)
- GO-2026-4977 / CVE-2026-42499 (net/mail consumePhrase quadratic)
- GO-2026-4980 / CVE-2026-39826 (html/template escaper bypass XSS)
- GO-2026-4981 / CVE-2026-33811 (net long CNAME crash)
- GO-2026-4982 / CVE-2026-39823 (html/template meta URL escape XSS)
- GO-2026-4986 / CVE-2026-39820 (net/mail consumeComment quadratic)

osv-scanner --recursive now reports 0 advisories. The go directive
floor stays at 1.25.0 so developers without GOTOOLCHAIN=auto can still
build with any Go >= 1.25.0.
2026-05-10 12:49:59 +00:00
Michael Mayer
e61b591ccf Rules: Note subrepo committer-identity workaround in safety rule 2026-05-10 12:20:30 +00:00
Michael Mayer
44429bdbbb MCP: Gate stdio on DisableMCP and add scope regression test #5024 2026-05-10 11:54:34 +00:00
Michael Mayer
808961525a Docs: Document MCP stdio auth requirement for write-capable tools #5024 2026-05-10 11:21:00 +00:00
Michael Mayer
8713e6b1ff Go: Update go-sqlite3 to v1.14.44 to fix GCC 15 warnings #5543 2026-05-10 10:02:28 +00:00
Cathie Integra
366bebddca Develop: Switch default base image to Ubuntu 26.04 LTS (Resolute) #5543 2026-05-10 11:32:40 +02:00
Michael Mayer
e759b234a5 Config: Improve auto-detection of indexing worker count #5567
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-10 10:16:11 +02:00
Michael Mayer
8b0f369bda Develop: Upgrade base image from 260505-questing to 260509-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-09 18:08:46 +02:00
Michael Mayer
1f21aea628 Go: Update deps in go.mod, go.sum, and license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-09 17:54:56 +02:00
Michael Mayer
12a5fdd153 Frontend: Update deps in package.json and tests in info.test.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-09 17:39:41 +02:00
Michael Mayer
60f4779565 Config: Refactor flag default reporting and harden Markdown rendering
- Rework CliFlag.Default() to read the documented default through
  cli.DocGenerationFlag.GetDefaultText() instead of GetValue(); urfave
  snapshots the source-code default in Apply() before reading the
  environment, so reports stay stable across deployments and no longer
  echo operator-supplied env values for runtime-mutated string flags.

- Add a Secret annotation on CliFlag for sensitive options. When set,
  Default() collapses to DocDefault (or "") so secrets like
  admin-password, oidc-secret, database-password, auth-secret,
  node-client-secret, join-token, download-token, preview-token, and
  vision-key never appear in `photoprism show config-options` or
  downstream consumers of the same report data.

- Convert index-workers from IntFlag to StringFlag with the new
  IndexWorkersAuto = "auto" sentinel, matching the convention already
  used by thumb-color, thumb-filter, and database-driver. Options.
  IndexWorkers becomes a string; Config.IndexWorkers() parses it once
  and keeps the existing CPU/SQLite caps. yaml.v2 silently coerces the
  legacy `IndexWorkers: 4` form into the string field, so existing
  operator config files load unchanged. Drops the dynamic
  cpuid.CPU.PhysicalCores/2 default and the previous DocDefault hack.
  Regenerated swagger.json picks up the new string type.

- Harden the Markdown report renderer (pkg/txt/report/markdown.go) by
  backslash-escaping `<` and `>` in row and header cells alongside the
  existing `|` and `* * *` escapes. Prevents arbitrary HTML from being
  emitted into downstream HTML pipelines that render the table source.

- Fix two pre-existing lint findings surfaced by the newer
  golangci-lint: misspell `marshalling` -> `marshaling` and replace a
  field-by-field struct literal with a same-shape type conversion
  (staticcheck S1016).

- Add coverage for every new code path: Default() Secret/env-override
  regression, GetDefaultText/strconv.Unquote round-trip, parseIndexWorkers
  branch matrix, ApplyCliContext index-workers string binding, the YAML
  round-trip across `auto`/quoted/bare-int/empty forms, and the Markdown
  angle-bracket escape.
2026-05-09 15:09:54 +00:00
Cathie Integra
1858490de0 Develop: Add install-doctl.sh and install-hcloud.sh scripts 2026-05-09 09:57:38 +02:00
Michael Mayer
346d56bdb0 Develop: Update Makefile and scripts/dist/install-codex.sh
The current version of Codex does not have a "general_analytics" flag.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-08 09:05:46 +02:00
Michael Mayer
a719f680a9 Frontend: Hide assigned items and sort Batch Edit dropdowns #4966
availableLabelOptions and availableAlbumOptions become computeds that
hide anything already in labelItems / albumItems (matched by
$util.normalizeTitle so case and punctuation variants collapse) and
sort the survivors via locale-aware localeCompare. Raw cache results
live on cachedLabelOptions / cachedAlbumOptions so resolveLabelFromText
can still find canonical matches for items already in the chip list.

Brings the Batch Edit dialog in line with the Edit Dialog labels tab
and the lightbox sidebar — every label/album typeahead now filters
already-assigned items out of the dropdown and sorts alphabetically.
2026-05-06 21:39:56 +00:00
Michael Mayer
89242a70eb Frontend: Sort sidebar label & album dropdowns alphabetically #4966
The shared typeahead cache returns the cap-bounded result in whatever
order the backend's search?order=name produced, which in practice is
not reliably alphabetical (and would mis-sort Hebrew or Cyrillic
strings under naive byte-order anyway). loadChipOptions now applies a
locale-aware localeCompare with sensitivity:base + numeric:true after
the cache resolves, so the dropdown reads naturally in any language.
2026-05-06 21:31:53 +00:00
Michael Mayer
178861b5ba Frontend: Hide assigned labels and skip re-add in Edit Dialog #4966
Two related dedup fixes for the Edit Dialog labels combobox:

addLabel now bails out without calling the backend when the typed
name resolves (via $util.normalizeTitle) to a label already on the
photo. The backend treats a re-add as an update and was emitting
"Label updated" + "added <name>" toast pairs whenever a user picked
an existing chip from the dropdown.

labelOptions becomes a computed that filters the cached label list by
the same normalized-name comparison and sorts the survivors via
locale-aware localeCompare. The dropdown now only surfaces actionable
suggestions, in alphabetical order — assigned labels disappear from
the list reactively the moment view.model.Labels updates.
2026-05-06 21:27:25 +00:00
Michael Mayer
93b0b1e3f5 Frontend: Align Edit Dialog labels menu with input column #4966
Anchors the v-combobox menu at "bottom start" with minWidth:0 so the
dropdown's start edge tracks the input's start edge in both LTR and
RTL — Vuetify's default "bottom" + wider min-width otherwise pushes
the menu leftward into the photo-thumbnail column under the table.
Also adds density="compact" on the combobox itself to match the
lightbox sidebar's typography. Verified in browser at sub-pixel
alignment for English (delta 0.16 px) and Hebrew (delta 0.16 px).
2026-05-06 20:45:26 +00:00
Michael Mayer
e538e96ba0 Frontend: Hide menu icon and stop re-pop on Edit Dialog labels #4966
Adds menu-icon="" to suppress the v-combobox dropdown chevron in
the Edit Dialog labels tab — the comfortable-density row positions
the chevron visibly below the input baseline, since the auto-open on
focus is the discovery affordance instead. Wires v-model:menu plus a
suppressMenuOpen debounce so committing a selection no longer re-pops
the dropdown via Vuetify's search-changed watcher when the bound
model is cleared. Mirrors the chip-selector pattern.
2026-05-06 20:25:25 +00:00
Michael Mayer
bd3bec9cd1 Frontend: Upgrade Edit Dialog labels tab to combobox #4966
Replaces the bare <v-text-field> for new-label entry with a
<v-combobox> mirroring the sidebar pattern. The combobox sources its
suggestions from the shared typeahead cache and applies the same
$util.normalizeTitle canonical-match dedup as the sidebar's
addLabelImmediate (typing 'Hello Cat' resolves to an existing
'hello-cat' label instead of creating a duplicate). autofocus is
explicitly omitted because v-combobox auto-opens its menu on focus
and would lay out the dropdown before the tab geometry settles.
2026-05-06 20:07:22 +00:00
Michael Mayer
6ca665e19e Frontend: Use shared typeahead cache in batch-edit dialog #4966
Replaces the per-mount Promise.all([Album.search, Label.search]) in
fetchAvailableOptions with typeaheadCache.getAlbums / getLabels.
Opening the batch-edit dialog while the lightbox sidebar is also
editable now costs zero extra round-trips, and a label or album
created elsewhere shows up next time the dialog opens via the cache's
WS-driven invalidation.
2026-05-06 20:07:15 +00:00
Michael Mayer
f0edfd933d Frontend: Always render sidebar label & album combobox #4966
Drops the pencil-to-edit gesture for the lightbox info sidebar's chip
sections. The combobox/autocomplete row now stays mounted whenever the
section is editable, chip × icons are visible whenever isEditable, and
the toolbar ✓ only appears when there are pending REMOVALS. Per-field
input/search/key/options state lives under chipState.<field> so the
two comboboxes don't share scratch refs anymore. cancelEditing is
scoped to inline-text rollback; chip state clears via resetInlineEdits
on discard-pending. The sidebar consumes typeahead suggestions through
the new typeahead-cache module and reloads on combobox @focus to pick
up post-eviction freshness.
2026-05-06 20:07:10 +00:00
Michael Mayer
b3a582a9fb Frontend: Add shared label & album typeahead cache #4966
Adds frontend/src/common/typeahead-cache.js as a module-scope cache
that dedupes Label.search and Album.search across the sidebar info
panel, the batch-edit dialog, and the edit-dialog labels tab. WS
events (labels.updated/deleted, albums.updated/deleted, config.updated
for album deletes) evict the cache; concurrent callers share the same
in-flight promise, and session.logout clears both lists. Cap warning
behavior moves out of the sidebar into the cache implementation.
2026-05-06 20:07:01 +00:00
Michael Mayer
cc93833e57 Frontend: Align sidebar combobox menus and chip focus #4966
Sidebar inline dropdowns (Add label, Add to album, marker name
combobox) now structurally match every other Vuetify v-select /
v-autocomplete menu in the app:

- Drops the custom 1px-solid border + opaque .v-overlay__content
  background that no other menu draws. Only the inner .v-list is
  given a background; the standard MD elevation shadow alone draws
  the edge.
- Lifts the inner .v-list to secondary-light (#1e1e1e) so it sits
  visibly above the combobox input's surface-bright (#141417) bg
  instead of merging into it.
- Forwards { density: "compact" } via :list-props on each
  combobox/autocomplete (the documented Vuetify API for sizing the
  menu items, separate from the input field's own density prop).
  Title font drops to 0.8125rem so the menu typography matches the
  sidebar's other inline-edit text.

Polishes related chip styling:

- The chip :focus-visible ring now uses rgba(--v-theme-on-surface,
  0.5) instead of bright --v-theme-primary (#ebebeb), so the ring
  is clearly more prominent than the chip's 12%-alpha resting
  border without reading as a near-white halo on the dark sidebar
  and without reusing a notification token.
- Removes the unreachable .meta-chip--pending-add rule (additions
  go through the instant-save path now and never enter chipState).
2026-05-06 16:44:00 +00:00
Michael Mayer
676b2677cf Frontend: Tone down bright lightbox theme tokens for sidebar UX #4966
The original lightbox theme was sized for a basic image viewer with
no editable controls. The info sidebar now embeds dialogs, inline
editors, autocomplete dropdowns, and chip selectors — surfaces that
bind theme tokens which were previously invisible. Three values
were too bright on the near-black lightbox surface:

- highlight: #9c9c9c -> #3d3f40  (PConfirmDialog confirm button —
  was a near-white block, now a credible dark-grey button)
- selected: #9c9c9c -> #3d3f40  (Vuetify-internal selection
  surfaces: active list item, autocomplete-active row, and the
  on-selected fallback in views.css — same fix as highlight)
- hover-opacity: 0.019 -> 0.06,
  focus-opacity: 0.022 -> 0.08
  (lightbox was inheriting the dark-base defaults, which over a
  near-white overlay color left dropdown hover and keyboard-focus
  states almost invisible)

Scoped to the lightbox theme — every other theme keeps its current
highlight/selected values. The lightbox primary, info, and on-
surface tokens were left alone since they show up in many places
(focus rings, button text, captions) and would cascade unexpectedly.
2026-05-06 17:40:28 +02:00
Michael Mayer
1292ae24bc Frontend: Align discard dialog with PConfirmDialog convention #4966
Drops the icon="" / confirm-color="info" overrides on the discard-
unsaved-changes dialog so it inherits the same icon-left-of-title
layout and bg-highlight confirm button that every other call site
of <p-confirm-dialog> uses (see album/toolbar.vue, photo/toolbar
.vue, settings/apps.vue, etc.). Picks mdi-alert-circle-outline for
the icon — neutral warning, fits the "you may lose unsaved input"
question without implying permanent deletion.
2026-05-06 17:40:28 +02:00
Michael Mayer
7146de4cdd Frontend: Save sidebar label and album additions instantly #4966
Replaces the staged "type -> green pending chip -> click toolbar
check" flow for label and album additions with an instant-save
path. Removals stay batched under the toolbar check icon so users
can still toggle a chip back into place without an Undo.

- onLabelEnter / onLabelSelected fire Photo.addLabel(name) right
  away. The model's setValues(r.data) chain repopulates this.photo
  .Labels with the backend-canonical name, so the chip appears as
  a real meta-chip--primary with no transient pending-add state.
- onAlbumSelected fires Photo.addToAlbum(albumUID) right away.
  onAlbumEnter for brand-new titles still runs Album.save() first
  and chains addToAlbum once a UID exists.
- onAlbumEnter now tries a normalized exact match against
  albumOptions (via $util.normalizeTitle) before falling back to
  the existing fuzzy startsWith / includes lookup, so typed
  variants like "hello-cat" resolve to an existing "Hello Cat"
  album instead of silently creating a near-duplicate.
- addLabelImmediate cross-checks labelOptions and uses the
  canonical existing-label name when normalized-equal, so typed
  "Hello Cat" reuses an existing "hello-cat" label and the user
  sees the saved name immediately.
- startChipEditing bumps the typeahead cap from 1000 to 5000 and
  emits a console.warn when the response equals the cap (a strong
  signal it was truncated; not surfaced via $notify because the
  typical user can't act on it).
- chipState drops the additions arrays - additions never enter
  chipState anymore - and confirmAlbums migrates from raw
  $api.delete/post to Photo.removeFromAlbum, so all album-
  membership writes share one model code path.

Failure paths surface $notify.error("Failed to save changes") and
do not leave a transient chip behind. Discard-pending dialog still
fires for typed-but-uncommitted text (chipSearch) and for batched
removals.
2026-05-06 17:40:27 +02:00
Michael Mayer
26e86ead3e Frontend: Rename normalizeLabelTitle to normalizeTitle #4966
The helper is reused for album titles in upcoming sidebar work, so
the label-only name no longer fits. Renames the static method on
$util plus the matching wrapper (normalizeLabelTitleForCompare ->
normalizeTitleForCompare) in batch-edit.vue, the component prop
contract stays the same. No behavior change.
2026-05-06 17:40:27 +02:00
Michael Mayer
9f34fcf09e Frontend: Add Photo.addToAlbum and Photo.removeFromAlbum #4966
Adds two model methods on Photo for album-membership writes that
mirror the backend album-photo endpoints:

- Photo.addToAlbum(albumUID): POST /albums/<uid>/photos with
  { photos: [this.UID] }, then evict the LRU cache and refetch the
  canonical photo so this.Albums reflects the saved state.
- Photo.removeFromAlbum(albumUID): DELETE /albums/<uid>/photos with
  the same evict + refind.

The explicit refind is necessary because the backend publishes
albums.updated (not photos.updated) for membership changes, so the
photos.updated WS subscriber doesn't auto-evict here.

The Photo-level method names overlap with Thumb.addToAlbum /
removeFromAlbum on purpose: those operate at the photo-grid layer
and flip a Removed flag for lightbox menu visibility (see
lightbox.vue onRemoveFromAlbum). Both contracts are pinned in
their respective tests so a future "consolidation" PR doesn't
collapse them.
2026-05-06 17:40:27 +02:00
Theresa Gresch
a836a49261 Tests: Use triggerPhotoViewerAction to close lightbox in sidebar-edit 2026-05-06 16:42:34 +02:00
Michael Mayer
10389c8b74 Frontend: Scope lightbox onTabKey to its container ref #4966
Replace the unconditional @keydown.tab.stop on the v-dialog with
@keydown.tab="onTabKey" plus a runtime guard: stopPropagation now
fires only when document.activeElement is inside this.$refs.container
(or .content as a fallback). PhotoSwipe's _focusRoot() Tab trap stays
suppressed for the typical case (focus inside the lightbox tree, user
tabbing through chips and pencils), and a Tab event that bubbles up
through the dialog from a teleported autocomplete menu or any other
DOM context outside the lightbox tree can still reach PhotoSwipe.

Adds five unit tests covering the inside / outside / fallback / no-ref
/ no-event branches.
2026-05-06 13:03:37 +00:00
Michael Mayer
d9b314eafb Frontend: Detect more sidebar pending edits before nav #4966
hasPendingEdit() was missing two signals, so swiping or pressing the
arrow keys silently dropped typed-but-uncommitted text in the labels
combobox / albums autocomplete and the open Add-name marker prompt.
Add both: typed text in chipSearch while editingField is 'labels' or
'albums', and addNameDialog.visible. resetInlineEdits() also dismisses
an open Add-name dialog so the Discard path leaves the sidebar fully
clean. Existing wrapPswpNavGuards / onChange post-facto rollback already
route through this method, so the discard confirmation now appears for
the missed cases without any new wiring.
2026-05-06 12:09:16 +00:00
Michael Mayer
b98a346cf9 Frontend: Stop sidebar inline keys from closing the lightbox #4966
Add .stop to every @keydown handler on sidebar editors and the three
nested dialogs (datetime, camera, location). The Vuetify v-dialog above
the lightbox listens for @keydown.esc.exact.stop=close, and PhotoSwipe's
document handler still consumes a few printable keys. Without .stop,
Esc on a textarea closed the editor AND the lightbox, Esc on a nested
dialog closed both modals at once, and Esc on the labels combobox /
albums autocomplete closed the lightbox without ever cancelling the
chip edit (Vuetify's default escape doesn't stop propagation).

Also: add @keydown.escape.stop.prevent=cancelEditing to the labels
combobox and albums autocomplete (their template had no escape
handler), and call clearChipInput() inside cancelEditing so typed-but-
uncommitted chip text doesn't survive a cancel.
2026-05-06 11:56:12 +00:00
Michael Mayer
7cc26e99bd Frontend: Stop sidebar Tab at v-dialog and inset chip focus ring #4966
Move Tab interception from the PhotoSwipe-event bridge (onPswpKeyDown)
to a generic v-dialog @keydown.tab.stop handler. PhotoSwipe's Tab path
only calls _focusRoot() — a focus trap that Vuetify's v-dialog and
PhotoPrism's $view trap (common/view.js) already provide more
generically — so stopping the bubble at the dialog root is enough,
no PhotoSwipe-specific hook required. onPswpKeyDown stays for the
"z" / printable-key case where we still need to defeat the
toggleZoom shortcut while a textarea or input is focused.

Also: shift the .meta-chip:focus outline to outline-offset: -2px so
the focus ring renders inside the chip area instead of being clipped
when chips wrap against the sidebar edge.
2026-05-06 13:04:44 +02:00
Michael Mayer
ebea14a170 Frontend: Let sidebar inputs and Tab through PhotoSwipe key trap #4966
PhotoSwipe's _onKeyDown listens on document and consumes "z" for
toggleZoom and Tab for _focusRoot, so plain typing into the info
sidebar's textareas dropped "z" and Tab snapped focus back to the
lightbox root, leaving sidebar chips and pencils unreachable by
keyboard. Add an onPswpKeyDown bridge that listens via the lightbox's
own keydown event and calls preventDefault on the dispatched event so
PhotoSwipe's switch returns early (per its own defaultPrevented gate).
Two cases: Tab while the sidebar is open (regardless of focus), and
any key when an INPUT, TEXTAREA, or contentEditable element inside
the sidebar is focused. Registered once via this.lightbox.on, which
PhotoSwipe Lightbox replays onto each pswp instance on open.
2026-05-06 13:04:44 +02:00
Michael Mayer
27bcb78470 Frontend: Add keyboard support for sidebar chips #4966
Make label and album chips focusable (tabindex=0) and bind Enter +
Delete/Backspace via two new helpers: onChipActivate covers click and
Enter (navigates outside edit mode, toggles pending removal inside),
onChipDelete covers Delete and Backspace (no-op outside edit mode,
toggles inside). Vue 3's .delete keydown modifier captures both Delete
and Backspace, so one binding handles both keys.

Also: tighten the cache-freshness comment in confirmLabels to name the
.then((r) => this.setValues(r.data)) chain on Photo.addLabel /
removeLabel, so the next reader can verify the local-patch contract
without grepping model/photo.js. Resolves the documentation half of
proposal item L5 (the asymmetry with confirmAlbums is intentional and
already justified).
2026-05-06 13:04:43 +02:00
Ömer Duran
4005aea4fe
Tests: Stabilize sidebar-edit-003 and add HEIF JPEG fallback coverage #5554 #4966 #4965 #5509
* Tests: Stabilize sidebar-edit-003 and add HEIF JPEG fallback coverage

* Tests: Stabilize lightbox sidebar-edit suite on fast systems
2026-05-06 12:41:51 +02:00
Michael Mayer
aa4d51bed1 Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-06 10:33:28 +02:00
Michael Mayer
511f0cf793 Frontend: Update deps in package.json and package-lock.json #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-06 10:30:16 +02:00
Michael Mayer
05cd8fab17 Go: Update "github.com/golang/geo" in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-06 10:28:26 +02:00
Michael Mayer
ccccd95f78 Commands: Improve video failure summaries 2026-05-06 08:01:33 +00:00
Michael Mayer
0192e55f32 Commands: Resolve low-risk golangci-lint findings 2026-05-06 07:50:37 +00:00
Michael Mayer
bd7066e0c3 Commands: Count file download failures & pluralize logs 2026-05-06 07:50:27 +00:00
Michael Mayer
d90bf1f5d5 Frontend: Consolidate sidebar chip-state for labels/albums #4966
Replace four flat arrays (pendingLabel{Additions,Removals},
pendingAlbum{Additions,Removals}) with one chipState object keyed by
field, plus four generic helpers (isChipPendingRemoval,
togglePendingChipRemoval, removePendingChipAdd, resetChipState) that
take field + key. addPendingLabel / addPendingAlbum stay specialized
because their validation differs (string vs object input).

Also: route the chip-section header check/pencil through the existing
PSidebarInlineToolbar; add meta-labels / meta-albums classes for
parity with the per-field hooks; surface a notify.error on
confirmLabels / confirmAlbums rejection (was silent); document the
local-patch vs evict-and-refind asymmetry between addLabel/removeLabel
and the raw album-membership API; suppress the empty .metadata__chips
container when entering edit mode with zero existing chips and zero
pending additions, and hide the redundant 'Add label/album' prompt
while editing. Tests updated to the new state shape and method
signatures (140 sidebar/info tests still pass).
2026-05-05 14:10:48 +00:00
Michael Mayer
f12109f12c Develop: Upgrade base image from 260504-questing to 260505-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-05 15:44:40 +02:00
Michael Mayer
4cb160c07e Frontend: Consolidate sidebar metadata fields via registry #4966
Replace four near-identical Subject/Artist/Copyright/License blocks
and the parallel Keywords/Notes blocks with two v-for loops over a
shared fieldRegistry computed (key, label, icon, read/write, display
mode, optional sanitized-html computed pointer). The registry is also
the lookup table for getFieldValue/setFieldValue, so each field's
label, model path, and rendering rule live in exactly one place.

Also: extract the check/pencil icon pair into PSidebarInlineToolbar,
swap the shared template ref for a function ref so the focus path
keeps working when the editors live inside v-for, and add
showDetailsSection/shouldShowFieldRow computed to replace the 6-term
OR gating expression. Net diff: -272 / +181 lines, no behavior change.
2026-05-05 13:03:55 +00:00
Cathie Integra
b0d6f94416 Setup: List chromium-common explicitly in install-chrome.sh package set 2026-05-05 14:56:27 +02:00
Michael Mayer
7f1b6f80af Frontend: Fix inline-edit focus stealing in info sidebar #4966
startEditing() used querySelector(.meta-inline-edit input) which matched
the first such element in the DOM. The People combobox shares that class
and renders above subject/artist/copyright/license/keywords/notes, so
clicking any of those add-prompts focused a marker input instead of the
clicked field. Replace the DOM query with a shared template ref on the
mutually-exclusive inline editors and add meta-<field> / meta-inline-<field>
hooks to all rows for consistent styling and test selectors.
2026-05-05 14:21:50 +02:00
Cathie Integra
6609b709d6 Setup: Document chromium runtime dependencies in install-chrome.sh 2026-05-05 12:50:26 +02:00
Cathie Integra
369edd3556 Setup: Install chromium from PhotoPrism's internal mirror with XtraDeb fallback 2026-05-05 12:47:25 +02:00
Michael Mayer
c03aebe5e2 Docs: Align AGENTS and CODEMAP files with frontend/README
AGENTS.md: add frontend/ to package-doc paths and point at
frontend/README.md for pin/override/dep policy.

frontend/AGENTS.md: new "Dependencies & Pins" section briefs agents
on the pins-are-intentional rule, the workspace npm install location,
and the orphan-audit pattern.

frontend/CODEMAP.md: trim the duplicated Vuetify pin paragraph and
link to frontend/README.md as the canonical rationale; keep the
upstream-issue caveats since they relate to component bindings.

Refresh Last Updated dates on all four files.
2026-05-05 10:17:28 +00:00
Michael Mayer
70582c903b Rules: Capture session learnings on pins, deps, and specs/ links
frontend-rules.md: new "Frontend Dependencies & Pins" section
points at frontend/README.md as the canonical pin doc, restates
the pins-are-intentional rule, and documents the workspace npm
install location plus the orphan-audit pattern.

commit-and-docs-style.md: explicit no-specs/-in-public rule with
the AGENTS.md/CLAUDE.md exception; note that gh issue create lacks
a --type flag so issue type must be set via the web UI.

sources-of-truth.md: add frontend/README.md to the package-README
list and call out its pin/override/orphan content directly.
2026-05-05 10:14:44 +00:00
Michael Mayer
eb49c285d7 Frontend: Retire redundant minimatch override
The "minimatch@~3.0": "^3.1.3" override was added on 2026-04-27 to
force-patch the ReDoS chain when postcss-url's locked minimatch@3.0.8
was the active vulnerability. With postcss-url removed, no consumer
in the tree pins to ~3.0.x anymore — every remaining minimatch
request (^3.0.4 from babel-plugin-istanbul/test-exclude and
eslint-plugin-node, ^3.1.5 from the eslint family, ^9.0.4 / ^10.1.1
from modern tooling) resolves naturally to a patched version.

Verification: removing the override leaves the lockfile byte-identical
("up to date in 932ms"), npm audit reports zero vulnerabilities, and
all installed minimatch versions are 3.1.5 / 5.1.x / 9.0.9 / 10.2.5
(no <3.1.4 entry). Build and 1055 vitest tests pass.
2026-05-05 10:13:03 +00:00
Michael Mayer
4410269cc2 Frontend: Drop unused @testing-library/react and vite-tsconfig-paths
Both were added during the Vitest framework integration (#4990) but
never referenced in any source file or test config — npm ls confirms
zero transitive consumers. PhotoPrism is Vue, so the React testing
library is not applicable; @testing-library/jest-dom (the actually
used helper) stays. The TS-paths resolver was speculatively added
when the Vite config was first stubbed and was never wired up.

README's "Known Unused" table is replaced with a short "Auditing for
Orphaned Dependencies" section so the sweep pattern (rg + npm ls)
is documented for future cleanups.
2026-05-05 10:07:55 +00:00
Michael Mayer
8339ed1b26 Frontend: Drop orphaned cheerio dependency from package.json
Cheerio was originally pulled in alongside easygettext@2.17.0 in May
2022 (commit d600d5faf), where easygettext declared cheerio@^1.0.0-rc.3
as a runtime dep for HTML parsing in the gettext-extract flow. When
easygettext was replaced by vue3-gettext / vue-gettext-extract in
October 2025 (commit ab9a0a969 / #1152), cheerio was overlooked and
left as a top-level dep with no consumers.

The exact pin to 1.0.0-rc.12 was set in September 2024 (commit
ab9e156c9, bundled into an unrelated UX commit) after an August 2024
bump to ^1.0.0 broke easygettext's ^1.0.0-rc.3 peer constraint. That
rationale evaporated when easygettext was removed; the lockfile
reverse-search confirms zero current consumers.

npm ls cheerio --all returns only the direct top-level entry; no
source files import it. make audit, make build-js, make test-js
(1055 passed / 13 skipped) all stay clean after removal.
2026-05-05 09:59:09 +00:00
Michael Mayer
3f9ac173c4 Frontend: Shorten docs in README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-05 11:47:25 +02:00
Michael Mayer
3012786d82 Docs: Drop private subrepo references from public files
Sweeps top-level CODEMAP/GLOSSARY, package READMEs under internal/,
and a handful of source-comment references that linked to the private
specs/ subrepo. AGENTS.md hints stay (agent-instruction document) and
the agent-skill linking targets in Makefile are guarded with
directory checks.
2026-05-05 09:40:18 +00:00
Michael Mayer
f95aec73a3 Frontend: Drop private subrepo references from README
Removes specs/ links from the public package README so external
readers don't hit 404s and the existence of the private specs
subrepo isn't leaked.
2026-05-05 09:35:19 +00:00
Michael Mayer
68f9088629 Frontend: Add README documenting deps, pin rationale, and ESM blockers
Captures why specific packages are pinned (vuetify, axios, cheerio),
which transitive overrides exist and why, and which major upgrades
are currently blocked by CJS config files. Includes add/remove/bump
checklists so future contributors can avoid duplicate research.
2026-05-05 09:31:54 +00:00
Michael Mayer
044af03a6d Frontend: Bump axios from 1.15.2 to 1.16.0 in package.json
The supply-chain compromise that drove the original 1.14.0 quarantine
(malicious 1.14.1/0.30.4 from a hijacked maintainer account) was fully
remediated upstream weeks ago, so 1.16.0 is safe. Keeps the exact-pin
style recommended for high-risk packages.
2026-05-05 09:29:31 +00:00
Michael Mayer
c3fb3d53ca Frontend: Bump routine deps in package.json and package-lock.json
Updates four low-risk packages within their existing major lines:
@vue/compiler-sfc 3.5.18 -> 3.5.33 (track vue runtime), webpack-bundle-analyzer
4.10.2 -> 5.3.0 (CJS-compatible, drops Node <20.9), babel-plugin-polyfill-corejs3
0.13.0 -> 0.14.2, vite-tsconfig-paths 5.1.4 -> 6.1.1.
2026-05-05 09:27:18 +00:00
Michael Mayer
a2dce2b06c Frontend: Drop unused postcss-url and @vitejs/plugin-react
Removes two stale dependencies that have no code references in any
frontend/, plus/frontend/, pro/frontend/, or portal/frontend/ tree.
postcss-url was a 2019 leftover and is the only consumer of the
unpatched minimatch <=3.1.3 ReDoS chain (GHSA-3ppc-4f35-3m26,
GHSA-7r86-cg39-jmmj, GHSA-23c5-xmqv-rm74); npm audit now reports
zero vulnerabilities.
2026-05-05 09:22:20 +00:00
Michael Mayer
624733778a Frontend: Upgrade "workbox-webpack-plugin" to ^7.4.1 in package.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-05 11:05:22 +02:00
Michael Mayer
4e6251b42b GitHub: Use issue type property instead of bug/idea labels 2026-05-05 09:02:55 +00:00
Michael Mayer
7f7e203ed1 Tests: Filter jsdom false-positive CSS parser warnings #5538
The jsdom upgrade to 29.x makes the default virtualConsole forward
"Could not parse CSS stylesheet" jsdomErrors to stderr, flooding
make test-js with one bare line per Vuetify-flavored stylesheet.
Drop only the noise across that surface; surface other CSS errors
with their parser cause.
2026-05-04 22:13:02 +00:00
Michael Mayer
1057b548dc Labels: Reuse renamed label when re-added by previous name #5531 2026-05-04 21:13:57 +00:00
Michael Mayer
81b763798e Frontend: Pin Vuetify to 3.12.2 to fix dropdown flash-close #5538
Vuetify 3.12.3 added an onFocusout handler to VAutocomplete, VSelect,
and VCombobox (commit 3d33e2f, fixing Vuetify upstream #22697) that
flips isFocused=false on any blur whose relatedTarget is outside the
textfield. The handler closes long dropdowns on open because the
virtual scroller unmounts the focused list item during the scroll-to-
selected-index pass that runs right after the menu opens, producing a
transient blur with relatedTarget=null. Pinning Vuetify to 3.12.2 (the
last release without the regression) is the cleanest fix; explored
workarounds (list-props navigation-strategy=track, capture-phase
focusout suppression with activator refocus, menu-props attach=true)
all had unacceptable side effects.

The pin is documented inline in three places that cross-reference each
other: package.json (//vuetify field), frontend/CODEMAP.md (Runtime &
Plugins), and frontend/src/common/view.js (sibling-menu gate comment
block). The original GitHub issue #5538 has been updated with the full
root-cause analysis. A separate follow-up issue #5556 tracks the minor
.v-field--focused linger that 3.12.2 still has (PhotoPrism is currently
unaffected because the relevant inputs aren't on screen together).

Includes incidental cssnano (7.1.8 -> 7.1.9) and postcss (8.5.13 ->
8.5.14) patch bumps from \`make -C frontend update\` after the pin.
2026-05-04 19:18:44 +00:00
Michael Mayer
b78fb89869 Frontend: Update JS deps in package.json and package-lock.json #5538
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-04 17:52:16 +02:00
Michael Mayer
d92d5c6739 ONNX: Upgrade runtime from v1.25.0 to v1.25.1 #5555 2026-05-04 11:48:50 +00:00
Michael Mayer
2ad8c40023 Go: Upgrade mysql, mcp-go-sdk, and onnxruntime_go modules #5555
Bumps:
- github.com/go-sql-driver/mysql v1.9.3 -> v1.10.0
- github.com/modelcontextprotocol/go-sdk v1.5.0 -> v1.6.0
- github.com/yalue/onnxruntime_go v1.28.0 -> v1.30.0

go-sdk v1.6.0 dropped the implicit default that previously rejected
cross-origin requests when StreamableHTTPOptions.CrossOriginProtection
was nil (modelcontextprotocol/go-sdk#906). internal/api/mcp.go now
sets the field explicitly so that /api/v1/mcp keeps verifying the
Origin header on the streamable HTTP transport.

onnxruntime_go v1.30.0 stays at ORT_API_VERSION 25, so the bundled
native runtime does not need to change for this bump alone.
2026-05-04 11:48:46 +00:00
Cathie Integra
6c5095f5dc Build: Propagate docker buildx exit code from buildx-multi.sh #5553 2026-05-04 12:46:50 +02:00
Michael Mayer
8775d79b7c Docs: Update rules against mixing Debian/Ubuntu apt sources
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-04 12:42:33 +02:00
Cathie Integra
96f4d73a12 Docs: Add rule against mixing Debian/Ubuntu apt sources in image builds #5553 2026-05-04 12:34:39 +02:00
Theresa Gresch
a2f8b23b19 Tests: Make acceptance-*-restart targets stop the daemon first 2026-05-04 11:52:25 +02:00
Cathie Integra
84491de31b Build: Switch Ubuntu ARM64 chromium source from Bookworm to XtraDeb PPA #5553 2026-05-04 11:10:54 +02:00
Cathie Integra
597cec8e75 Build: Make Bookworm chromium lib whitelist conditional on Jammy #5553 2026-05-04 10:47:41 +02:00
Cathie Integra
a32b6da645 Build: Whitelist chromium runtime libs from Bookworm on Ubuntu ARM64 #5553 2026-05-04 10:18:14 +02:00
Cathie Integra
d89fcbffd8 Build: Bump dev Dockerfile to develop:260504-questing #5553 2026-05-04 09:33:02 +02:00
Cathie Integra
7134c2eceb Build: Add docker-develop-legacy target for Jammy images #5553 2026-05-04 09:09:55 +02:00
Cathie Integra
b8fb5374f0 HEIC: Default install-libheif.sh to v1.21.2 #5553 2026-05-04 08:49:14 +02:00
Cathie Integra
91099333b4 Build: Skip dav1d plugin on Jammy + fail libheif build loudly #5553 2026-05-04 08:39:16 +02:00
Cathie Integra
976e48796b HEIC: Keep install-libheif.sh on v1.20.2 until v1.21.2 archives ship #5553 2026-05-04 07:56:12 +02:00
Cathie Integra
88feed0d55 HEIC: Upgrade libheif from v1.20.2 to v1.21.2 #5553 2026-05-04 07:55:56 +02:00
Michael Mayer
38a20d2552 Server: Align README validator wording with code & spec #5552
internal/server/README.md still listed both `If-Modified-Since` and
`If-None-Match` as active validators for `PrecompressedStatic`. The
handler does not set an `ETag`, so the active validator pair on
`/static/*` and `/c/static/*` is `Last-Modified` + `If-Modified-Since`
only — matching the doc comment in `static_precompressed.go` and the
"Conditional requests" subsection of `specs/platform/http-compression.md`.
2026-05-03 13:51:14 +00:00
Michael Mayer
f22cba92d3 Build: Run precompress.js after npm build in build-js targets #5552
The repo Makefile and dev image both export NPM_CONFIG_IGNORE_SCRIPTS=true
to harden npm against malicious supply-chain scripts. That flag also
suppresses lifecycle hooks like postbuild and prewatch, so the
precompress hooks registered in frontend/package.json never fire under
the standard build flow. Wiring `node scripts/precompress.js`
explicitly into build-js (and `--clean` into watch-js) keeps the
security-conscious npm flag intact while guaranteeing siblings exist
after every release-track build and that stale siblings are wiped
before watch-mode dev iteration starts.

The npm hooks remain registered as a backup for ad-hoc `npm run build`
invocations where IGNORE_SCRIPTS is off.
2026-05-03 13:44:12 +00:00
Michael Mayer
9bbe7e27a0 Server: Serve precompressed static asset siblings #5552
Adds PrecompressedStatic handler in internal/server/static_precompressed.go,
wired by routes_static.go for /static/*filepath (bundled) and
/c/static/*filepath (custom). When a .zst or .gz sibling is on disk and
the client's Accept-Encoding allows it, the handler streams the
sibling via http.ServeContent — preserving Last-Modified and
If-Modified-Since revalidation, deriving Content-Type from the identity
filename so service-worker registration and SRI continue to work, and
setting an explicit Content-Length that http.ServeContent omits when
Content-Encoding is in effect.

Range requests always serve identity (the byte offsets in Content-Range
correspond to identity bytes), and PHOTOPRISM_HTTP_COMPRESSION=none
disables encoded-sibling selection so the operator switch stays
consistent with the runtime middleware. Vary: Accept-Encoding is
emitted only when the response could realistically vary by encoding.

Both /static/* and /c/static/* are added to NewShouldCompressFn's
exclusion list so the runtime middleware never re-encodes an
already-encoded body.
2026-05-03 13:43:59 +00:00
Michael Mayer
da169dc669 Frontend: Pre-compress static bundle assets at build time #5552
Adds frontend/scripts/precompress.js, a Node script that walks
assets/static/build/ and emits .gz (zlib level 9) and .zst (zlib level
19) siblings for every JS, CSS, JSON, SVG, font, source map, and small
text asset. Already-encoded binaries (woff2, png, jpg, ...) and
no-savings files (smaller than 1 KiB or compressing to >95% of source)
are skipped. Every emitted sibling is round-tripped through
gunzipSync / zstdDecompressSync so a corrupt sibling never reaches
disk.

Wired as the npm `postbuild` hook so `npm run build` produces siblings,
and as `prewatch` (`--clean`) so `npm run watch` removes any stale
siblings from a prior production build before webpack's first emit.

The built-in node:zlib zstd API requires Node 22.15 or later; engines
constraint bumped accordingly and frontend/tests/README.md aligned.
2026-05-03 13:43:44 +00:00
Michael Mayer
5c6976355b Header: Add "Range" request header constant 2026-05-03 13:43:26 +00:00
Michael Mayer
6ce0608356 Config: Realign HTTP_COMPRESSION comments in sample compose files #5550
Removes 5 trailing spaces between the value and the # comment on the
PHOTOPRISM_HTTP_COMPRESSION line so it lines up with neighboring
PHOTOPRISM_* entries again. Cosmetic-only follow-up to the zstd
value flip, which left the comment column 5 cols too far right in
the files where the previous spacing was preserved verbatim.
2026-05-03 11:04:31 +00:00
Michael Mayer
ba08980b95 Entity: Fix nil-DB race in async count/cover updates #5551
UpdateCountsAsync and UpdateCoversAsync now register with a shared
WaitGroup so config.CloseDb can drain in-flight goroutines via
entity.WaitForAsyncJobs before nilling the DB provider. Both
synchronous helpers also bail out cleanly when entity.Db() is nil,
and the async wrappers recover so future shutdown races log instead
of crashing the test process.
2026-05-03 10:49:28 +00:00
Michael Mayer
5a9e4b6031 Config: Default to "zstd,gzip" in sample compose files #5550
Flips the operator-facing default across all sample compose files,
the Linux package defaults, and the Portainer stack env so QA
exercises zstd end-to-end before the next release. The armv7
samples keep their "none" value to spare the CPU on small devices;
only the comment was broadened.
2026-05-03 10:10:48 +00:00
Michael Mayer
083d437ec4 Server: Add zstd compression support #5550
Negotiates zstd alongside gzip via PHOTOPRISM_HTTP_COMPRESSION as a
comma-separated preference list (e.g. "zstd,gzip"); legacy "gzip",
"none", and the empty string keep behaving as before. Bypasses
Connection: Upgrade, predicate-excluded paths, HEAD (with Vary kept),
4xx/5xx, 206, 204, and 304. Weakens strong ETags on the encoding path
so caches don't reuse a compressed body for a different coding.
2026-05-03 10:10:33 +00:00
Michael Mayer
660bec4110 Sidebar: Rename info.vue "p" computed to "photo" #5547 2026-04-29 18:33:08 +00:00
Ömer Duran
6c3ac3b108 Sidebar: Bind dialog photo prop via $view alias #5505 2026-04-29 20:18:53 +02:00
Michael Mayer
942ecde80e Repo: Ignore ".playwright-mcp/" run artifacts 2026-04-29 14:07:45 +00:00
Michael Mayer
9b0d19c60e Claude: Document when to delegate UI tests to "ui-tester" 2026-04-29 14:06:48 +00:00
Michael Mayer
a021783922 Claude: Add "ui-tester" subagent and allow Playwright MCP for it
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-29 15:58:31 +02:00
Cathie Integra
090f9242c2 Docs: Align Title Case rules with Chicago-style spec 2026-04-29 14:54:15 +02:00
Cathie Integra
7f4b9ad668 Scripts: Use absolute "/root/.cache/npm" path in install-nodejs.sh
When invoked as "sudo bash install-nodejs.sh" by an unprivileged user, "~"
expanded to the calling user's home before sudo elevated, so root's
".npmrc" ended up with "cache=/home/<user>/.cache/npm" and subsequent
"sudo npm install -g" runs left root-owned cache dirs inside the user's
home. Hardcode the path so the cache always lands under root.
2026-04-28 14:47:38 +02:00
Michael Mayer
bb53e9e972 Tests: Migrate Thumb archive/restore tests to global Mock adapter #5505
Convert success-path tests for Thumb.archive / restore /
removeFromAlbum to the global axios-mock-adapter Mock from
fixtures.js, with URL + payload pinned through Mock.history. Add
persistent mocks for batch/photos/restore and albums/:uid/photos
(DELETE) so the new tests have something to land on.

Rejection tests intentionally keep vi.spyOn($api, ...).
mockRejectedValueOnce(err) — axios-mock-adapter matches handlers
in registration order, so a replyOnce(500) registered in a test
cannot override the persistent reply(200) already declared in
fixtures.js. Documented inline in the archive describe.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-28 07:51:52 +00:00
Michael Mayer
f950d8eacd Frontend: Document Thumb-only optimistic-mutation contract #5505
Refresh the doc comments on Photo.archive() and Thumb.archive() /
restore() / removeFromAlbum() to spell out why the optimistic
Archived/Removed flip lives only on Thumb (the lightbox menu reads
this.model?.Archived directly) while Photo.archive() stays minimal
(no Vue component reads photo.Archived; the photos.archived WS
handler in page/photos.vue removes the row via removeResult).
Comment-only change, no behavior change.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-28 07:51:33 +00:00
Michael Mayer
551e5fa29c Backend: Update deps in go.mod and go.sum; update license NOTICE #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-28 09:07:04 +02:00
Michael Mayer
3f0725df2d Frontend: Update deps in package.json and package-lock.json #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-28 09:01:53 +02:00
Michael Mayer
86f84aa1ee Frontend: Move photo cache & mutations to Thumb, expand WS evicts #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-28 08:58:47 +02:00
Michael Mayer
ceb11f4cf8 Frontend: Suppress vue/no-v-html for sanitized sidebar caption & notes 2026-04-28 00:11:50 +00:00
Michael Mayer
35a78807eb Frontend: Drop unused catch bindings & callback args 2026-04-28 00:05:42 +00:00
Michael Mayer
199cf69cac Frontend: Declare emits on dialog & service components #5505 2026-04-28 00:01:52 +00:00
Michael Mayer
1988f5ea34 Tests: Pin post-logout race and lightbox fetchPhoto race guard #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-28 01:52:33 +02:00
Michael Mayer
d3c182b9d5 Frontend: Harden ModelCache cancellation, snapshot routing & TTL #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-28 01:51:56 +02:00
Michael Mayer
0a5e5c643d Docs: Update .claude/rules/frontend-rules.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-28 01:51:23 +02:00
Michael Mayer
9779cd9946 Frontend: Rename model to service to clear no-mutating-props #5546
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-28 00:30:22 +02:00
Michael Mayer
1a2a32a5d6 Frontend: Update spec path references after moving document #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 23:58:31 +02:00
Michael Mayer
be64e3f3f6 Tests: Pin lightbox prefetch bypass for restricted sessions #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 23:44:47 +02:00
Michael Mayer
1b48f89d56 Tests: Pin Session cache invalidation and restricted-role gating #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 23:44:14 +02:00
Michael Mayer
c04cb4f360 Frontend: Roll back sidebar save paths when update() rejects #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 23:43:38 +02:00
Michael Mayer
09ce6b12ce Lightbox: Move prefetch policy behind Photo.prefetchAround #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 23:22:18 +02:00
Michael Mayer
28c3f6d636 Frontend: Migrate LRU cache onto the shared ModelCache helper #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 23:21:53 +02:00
Michael Mayer
7f927778f7 Frontend: Add reusable ModelCache helper with full Vitest coverage #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 23:21:00 +02:00
Michael Mayer
3af38e67b9 Tests: Cover every dialog field in sidebar-edit acceptance #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 21:02:34 +02:00
Michael Mayer
1ca5b743b7 Sidebar: Roll back camera dialog state on save failure #5505
confirmCamera() applied the dialog payload optimistically and then
called photo.update() fire-and-forget. A rejected save left the
sidebar showing values that never reached the backend with no error
surfaced. Now the handler attaches a .catch that calls
photo.rollback() — Photo.update() only resets __originalValues on
success, so the snapshot still holds the pre-mutation state on
failure — and notifies the user via $notify.error.

Adds three Vitest cases: optimistic mutation rolls back when
update() rejects, stays applied when it resolves, and is skipped
when the photo has no UID.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 21:02:20 +02:00
Michael Mayer
5ec99661d3 Model: Add rollback() and document base Model semantics #5505
The base Model now exposes a generic rollback() that restores every
tracked field from __originalValues (deep-cloning objects so post-
rollback mutations don't bleed into the snapshot). It's the natural
inverse of wasChanged() and lets optimistic-then-fail flows undo a
local mutation without per-field bookkeeping at the call site.

Adds doc comments to constructor / setValues / getValues /
originalValue / wasChanged / getDefaults explaining the
__originalValues snapshot contract, the scalarOnly flag, and how
getValues() coercion uses getDefaults() type hints.

Expands rest.test.js to cover the previously-untested paths:
setValues scalarOnly + chaining + reserved-key handling, getValues
changed-flag + type coercion + pass-through, originalValue lookup
and fallback, wasChanged true/false/post-rollback, plus four
rollback cases (scalar, deep-cloned object, chaining, no-op).

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 21:01:06 +02:00
Michael Mayer
7a611b6d66 Lightbox: Read sidebar state via $view.getData() #5505
Apply the pattern from photo/edit/labels.vue. The lightbox is a $view
scope, so the sidebar can read parent state through
`view: this.$view.getData()` and write back to it without triggering
vue/no-mutating-props. Collapses 8 prop bindings on <p-sidebar-info>
to :uid="model.UID", drops update:modelValue, and initializes
lightbox.photo to new Photo() so the sidebar can read view.photo.X
without nullable chains.

Resolves the 15 vue/no-mutating-props errors flagged in the #5505
review.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 16:42:18 +02:00
Michael Mayer
510a368e6e Photo: Refresh LRU cache via "photos.updated" events #5505
The backend already publishes "photos.updated" / "photos.deleted" via
PublishPhotoEvent (internal/api/api_event.go) on every API mutation.
Listen for them in model/photo.js so the LRU stays in sync with backend
state without each mutator having to remember to evict. Drops the 13
manual Photo.evictCache(this.UID) calls from toggleLike, togglePrivate,
like, unlike, addLabel, activateLabel, renameLabel, removeLabel,
setPrimaryFile, unstackFile, deleteFile, changeFileOrientation,
and update.

Also covers external mutations (other tabs, indexer, batch operations)
that previously left stale cache entries.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 16:41:18 +02:00
Michael Mayer
d83285361b Frontend: Update common/util.js and model/user.js + tests #5505
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 12:53:58 +02:00
Ömer Duran
f85150fb9f
Lightbox: Add inline metadata editing and face markers #4965 #4966 #5505
* Frontend: Expand lightbox sidebar with full photo metadata #1307 #4965

* Frontend: Add inline editing to lightbox sidebar metadata #1307 #4966

* Frontend: Add component tests for sidebar dialogs and inline editing #1307 #4966

* Frontend: Refine lightbox sidebar metadata UX

* Frontend: Refine lightbox sidebar metadata rows and editing flow #1307 #4966 #4965

* Frontend: Add face marker management to lightbox sidebar #1307 #4966 #1548 #5081

* Photos: Restrict viewer sidebar for guest, visitor, contributor #1307

* Photos: Use viewer endpoint for restricted sidebar roles #1307

* Sidebar: Allow emoji and Unicode in label normalization

* Sidebar: Inline metadata editing, marker UX, and cross-tab links #1307 #1548

* Tests: Sidebar edit, face markers, and share-link acceptance coverage #1307 #1548

* Sidebar: Hide private albums from cross-link chips #1307

* Tests: Fix face marker drawing flakiness and close obstruction

* Tests: Fix unhandled visualViewport error in Vuetify overlay tests

* Sidebar: Refine marker chip icons

* Sidebar: Gate named marker rename behind eject #1307

* Tests: Added test name prefix.

* Photo: Isolate cached photos to prevent unsaved-edit leaks

* Tests: Add sidebar dialog edit and persistence coverage #1307

---------

Co-authored-by: graciousgrey <theresagresch@gmail.com>
2026-04-27 12:33:49 +02:00
Michael Mayer
aaeb5c92b8 Frontend: Bump axios to 1.15.2 and drop legacy supply-chain pins
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 11:59:52 +02:00
Michael Mayer
64f91789c9 OIDC: Treat unknown dummy clients as confidential web clients #5545
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 11:40:27 +02:00
Michael Mayer
1e9e3f2552 OIDC: Upgrade photoprism/dummy-oidc image from :251210 to :260427 #5545
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 11:35:54 +02:00
Michael Mayer
64838087bd OIDC: Refresh dummy fixture against zitadel/oidc/v3 #5545
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 11:33:18 +02:00
Michael Mayer
036d67b58f Backend: Upgrade Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 11:23:23 +02:00
Michael Mayer
c86c0369e9 Frontend: Upgrade JS deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 11:14:31 +02:00
Michael Mayer
9875a1de5a Build: Upgrade base image from 260424-questing to 260427-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 10:25:41 +02:00
Michael Mayer
6cb5684ed2 Build: Fix resolute ARM64 chromium libjpeg, use apt libheif #5543
install-chrome.sh now pins Debian Bookworm to apt priority 100 with
chromium-* elevated to 990, preventing apt from "upgrading" unrelated
Ubuntu packages like libjpeg-dev to Bookworm's higher-versioned one
(which would pull libjpeg62-turbo-dev and collide with Ubuntu's
libjpeg-turbo8-dev). The conflict affected all Ubuntu+Bookworm-
chromium ARM64 builds; Resolute happened to surface it first.

The Resolute Dockerfiles now install libheif (1.21.2) from the
Resolute apt repo and explicitly pull the codec plugins, replacing
the older 1.20.2 archive previously fetched by install-libheif.sh.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 09:43:29 +02:00
Michael Mayer
53906f2bde Build: Drop software-properties-common from trixie develop image #5542
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 09:14:05 +02:00
Michael Mayer
c7ef450ed4 Build: Add Makefile targets for Debian Trixie base images #5542
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 09:07:50 +02:00
Michael Mayer
e2a200b116 Build: Add Makefile targets for Ubuntu Resolute base images #5543
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 09:03:44 +02:00
Michael Mayer
297f6eda98 Build: Add Ubuntu 26.04 LTS (Resolute Raccoon) base images #5543
Adds docker/develop/resolute/ and docker/develop/resolute-slim/ as
direct clones of the questing images with the base image, OCI labels,
and top-of-file comment switched to resolute. Test builds can be created
once the final "ubuntu:resolute" image is published on Docker Hub.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 08:43:52 +02:00
Michael Mayer
14b605df2f Build: Add Debian 13 (Trixie) develop and base images #5542
Adds docker/develop/trixie/ (full) and docker/develop/trixie-slim/
images based on the Bookworm images, with ImageMagick 7 policy path,
s6-overlay parity with Questing, and Trixie packages for libjxl,
va-driver, nvenc, postgresql-client, and ripgrep.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 08:33:26 +02:00
Michael Mayer
757714515e Build: Bundle Hadolint, OSV-Scanner, Gitleaks in develop images
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-27 08:17:04 +02:00
Michael Mayer
8d0eeb012f Build: Add install scripts for Hadolint, OSV-Scanner, Gitleaks
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-26 14:26:10 +02:00
Michael Mayer
e377056b6d Makefile: Add combined skills target
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-26 14:07:52 +02:00
Michael Mayer
6a1fb99b92 Makefile: Add agents-skills alias for codex-skills
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-26 12:52:24 +02:00
Cathie Integra
c489ea5b0b Build: Skip "cgroupfs-mount" when not in apt index (Ubuntu 26.04)
Ubuntu 26.04 ("resolute") and Debian trixie+ no longer ship the
"cgroupfs-mount" package — modern systemd handles cgroup v2 mounting
natively. With the package gone from the index, the existing
"apt-get install" line aborted with:

  E: Package 'cgroupfs-mount' has no installation candidate

before Docker itself was installed. Probe the index via "apt-cache show"
and include the package only when it is actually available; older
distros that still ship it are unaffected.
2026-04-25 14:45:39 +02:00
Cathie Integra
79a5192cf7 Build: Make install-chrome.sh safe to run via curl | sudo bash
Two issues prevented the script from running cleanly when piped into
sudo (the most reliable invocation over SSH):

1. The header recommended `bash <(curl …)`, but with sudo the process
   substitution opens /dev/fd/63 in the unprivileged parent shell and
   the elevated bash cannot read it — the script aborted with
   `bash: /dev/fd/63: No such file or directory`. Replace with the
   `curl -fsSL … | sudo bash` pattern (and keep an explicit
   download-then-run fallback). Also call out the broken sudo + process
   substitution form so users do not retry it.

2. With stdin piped to bash, `gpg --dearmor` tried to write status to
   /dev/tty and failed with `gpg: cannot open '/dev/tty'`, breaking the
   keyring import (and silently leaving an empty keyring on a fresh
   host). Pass `--no-tty --batch --yes` to both gpg calls.

Tested end-to-end on Ubuntu 26.04 ("resolute") via
`curl -fsSL …/install-chrome.sh | sudo bash` from a clean state
(no preexisting keyring or apt list): keyring valid OpenPGP file, deb
fetched and installed, `google-chrome --version` returns 147.0.7727.116.
2026-04-25 14:44:56 +02:00
Michael Mayer
c1e9d80692 CLI: Document urfave/cli v2 to v3 upgrade analysis and decision
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-25 10:31:38 +02:00
Michael Mayer
452bdde31e ONNX: Upgrade runtime from v1.24.1 to v1.25.0 and bump onnxruntime_go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-24 18:06:54 +02:00
Michael Mayer
b263651c5e Build: Upgrade base image from 260417-questing to 260424-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-24 17:12:43 +02:00
Michael Mayer
5bda752118 Build: Add shared .telemetry file to opt out of CLI telemetry
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-24 16:42:21 +02:00
Cathie Integra
989227097a Docs: Clarify NPM_CONFIG_IGNORE_SCRIPTS default and rebuild override 2026-04-21 07:56:17 +02:00
Michael Mayer
7d39b2d9fe API: Extend check-api-request-limits.sh for ServeHTTP and direct reads
- Flag <name>.ServeHTTP(<writer>, c.Request) calls without a nearby
  LimitRequestBodyBytes so SDK-delegated handlers (MCP today, future
  SDKs tomorrow) are held to the same body-cap contract as BindJSON.
- Also flag direct reads via io.ReadAll, io.LimitReader,
  json.NewDecoder, xml.NewDecoder, and yaml.NewDecoder on c.Request.Body

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-20 13:55:29 +02:00
Michael Mayer
a61d284134 MCP: Cap /api/v1/mcp body size and shorten session idle timeout #5024
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-20 13:54:07 +02:00
Cathie Integra
543d43ab6a Docker: Raise BuildKit step log size/speed limits in buildx-multi.sh
Set BUILDKIT_STEP_LOG_MAX_SIZE=5 MiB and BUILDKIT_STEP_LOG_MAX_SPEED=10 MiB/s
on both the local and remote ssh://arm multibuilder nodes so long apt-get
transcripts on unstable Ubuntu bases aren't truncated during preview builds.
2026-04-18 11:45:28 +02:00
Michael Mayer
c37fdf51a7 Translations: Update frontend/src/locales/json/*.json #5536
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-18 11:37:10 +02:00
Weblate
d53f8f0fd2 Weblate: Update frontend translations 2026-04-18 11:35:06 +02:00
Michael Mayer
4599cc07ce MCP: Expose DisableMCP via ClientConfig for frontend gating #5024 #5536
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-18 11:31:31 +02:00
Michael Mayer
0cf372af79 Config: Add PHOTOPRISM_DISABLE_MCP to compose.yaml & charts #5024 #5536
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-18 11:09:52 +02:00
Michael Mayer
da224d309e MCP: Add "DisableMCP" option to disable /api/v1/mcp #5024 #5536
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-18 11:08:58 +02:00
Michael Mayer
d529f7fe4a Docs: Document heading style as Chicago-style title case
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-18 09:41:11 +02:00
Michael Mayer
ac9c9cf27b MCP: Remove experimental gate test and update documentation #5024
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-18 08:08:29 +02:00
Michael Mayer
825b8049cf MCP: Remove experimental gate from /api/v1/mcp registration #5024
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-18 07:51:57 +02:00
Michael Mayer
51976b7f5c Search: Add NOT & AND operators to label filter #5535
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-17 17:25:18 +02:00
Michael Mayer
15036786bc Claude: Auto-accept file edits in project settings.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-17 12:45:07 +02:00
Michael Mayer
1ced5cbf1e Backend: Update github.com/zitadel/oidc/v3 in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-17 11:57:35 +02:00
Michael Mayer
55edaeae57 Claude: Add project settings.json with shared team defaults
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-17 11:51:48 +02:00
Michael Mayer
85ca9dfb19 Develop: Upgrade base image from 260413-questing to 260417-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-17 09:44:52 +02:00
Cathie Integra
8e5ece95a3 Scripts: Install Mermaid CLI and Chromium for ARM64 in dev images 2026-04-17 09:38:37 +02:00
Cathie Integra
7e6773e94e Claude: Compact repo rules to reduce context size 2026-04-17 08:16:17 +02:00
Michael Mayer
79b3f569a8 API: Fix incorrect Swagger response schemas and "Fore more" typos
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-15 15:56:13 +02:00
Michael Mayer
be98c04d0d Docker: Document directory layout and legacy image policy in README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-15 15:20:53 +02:00
Michael Mayer
c46deb6129 Go: Upgrade "govips" to v2.18.0 (requires libvips 8.14 or later)
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-15 15:09:23 +02:00
Michael Mayer
edb6f2f2b1 Go: Upgrade dependencies (gocron, oidc, mcp-sdk, x/*, sqlite3, otel)
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-15 14:58:05 +02:00
Michael Mayer
7db82af193 API: Document "GET /api/v1/photos/view" in swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-15 14:01:19 +02:00
Cathie Integra
fcbfbfd8be Docs: Disable Co-Authored-By: Claude trailer in CLAUDE.md 2026-04-14 10:40:34 +02:00
Cathie Integra
ee6ff221a0 Docs: Note "--ignore-scripts" for npm outside the dev image
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:11:51 +02:00
Michael Mayer
1beb83b554 Develop: Upgrade base image from 260331-questing to 260413-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-13 14:06:20 +02:00
Michael Mayer
6d29459aca Build: Add Codex skill bundles and auto-link target to Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-13 13:00:49 +02:00
Michael Mayer
26a5c06762 Claude: Run "claude update" if already installed and add render-pdf deps
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-13 12:49:04 +02:00
Michael Mayer
0c226fafcf Header: Add ContentTypeEventStream and reuse in MCP code #5024
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-13 09:18:40 +02:00
Michael Mayer
6704b217d8 MCP: Document constants and vars, export ToolNames/ResourceURIs #5024
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-13 09:09:12 +02:00
Michael Mayer
fdfe46c7b3 MCP: Add stdio smoke test and mcpAppMetadata coverage #5024 #5519
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-13 08:57:46 +02:00
Michael Mayer
342b03e317 MCP: Drop "internalmcp" alias and use "mcp" package name directly #5024
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-13 08:48:52 +02:00
Michael Mayer
4f14ed90c0 MCP: Remove "prototype" wording for production-readiness #5024 #5519
- Rewrite package doc, struct comments, log line, and route-registration
  comment so they describe the MCP server as a first-class feature
  rather than a pre-release prototype. The "Usage" strings on
  MCPCommands / MCPServeCommand were updated separately and stay
  unchanged.
- Drop "in this prototype" from the edition-advisory warning emitted by
  list_config_keys; the message now reads "edition filtering is
  advisory; results come from the current <edition> build metadata".
- Rewrite internal/mcp/README.md: new "Scope" section with
  in-scope/out-of-scope invariants, corrected authorization summary
  (admin + API client roles + manager in Pro/Portal, anonymous in
  public mode for the registered read-only tools), and a clearer
  "Current Capabilities" block.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-13 08:46:07 +02:00
Michael Mayer
16fc758f54 MCP: Allow anonymous access in public mode for demo deployments #5024
- Drop the public-mode 403 short-circuit in internal/api/mcp.go. In
  public mode api.Session() returns the default public session, so
  Auth(c, acl.ResourceMCP, acl.ActionView) + s.Abort(c) authorize
  anonymous callers naturally. This enables the prototype to run on
  demo.photoprism.app and similar showcase installations without
  loosening the auth path or adding another toggle.
- The exemption is only safe because every currently registered tool
  returns static reference metadata derived from config.Flags and
  form.Report(&form.SearchPhotos{}) — no database access, no per-user
  state, no secrets, no mutations. A handler-level comment captures
  that contract so a future tool that does not fit cannot slip in
  unnoticed.
- Flip the public-mode test case (ForbiddenPublicMode ->
  AllowedPublicMode) in internal/api/mcp_test.go to a full anonymous
  initialize + notifications/initialized + tools/call round-trip
  against both registered tools, so any future tightening of the
  policy regresses loudly.
- Update internal/mcp/README.md: the Authorization bullets now
  describe the public-mode path, the Rate Limiting note reflects that
  CE/Plus have no generic throttle in public mode, and a new
  "Extending the Tool Surface" section documents the contract every
  new tool must uphold plus the three supported extension paths
  (two-server factory, per-tool context checks, SDK middleware).

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-13 08:19:29 +02:00
Michael Mayer
df13ea9e02 MCP: Refine auth flow, JWT scope, and find_search_filters #5024 #5519
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-10 13:40:22 +02:00
Ömer Duran
e2f8474309
MCP: Add read-only Model Context Protocol prototype #5024 #5519
* MCP: Add internal read-only prototype #5024

* MCP: Fix edition detection, section assignment, and input validation #5024

* MCP: Add authenticated HTTP endpoint with ACL and experimental gate #5024

* MCP: Document client compatibility and config examples #502

* MCP: Refine ACL grants and finalize prototype polish #5024 #5519

Signed-off-by: Michael Mayer <michael@photoprism.app>

* MCP: Update go.sum #5024 #5519

Signed-off-by: Michael Mayer <michael@photoprism.app>

* MCP: Update license NOTICE files #5024 #5519

Signed-off-by: Michael Mayer <michael@photoprism.app>

---------

Signed-off-by: Michael Mayer <michael@photoprism.app>
Co-authored-by: Michael Mayer <michael@photoprism.app>
2026-04-10 12:51:11 +02:00
Michael Mayer
32f8bd9896 Claude: Align rules with AGENTS.md and fix test coverage placement
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-09 19:52:49 +02:00
Michael Mayer
8640dee635 Docs: Split AGENTS guides into a hierarchical structure
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-09 19:28:14 +02:00
Michael Mayer
997ca175be Claude: Add rules files and update CLAUDE.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-09 18:22:16 +02:00
Michael Mayer
f0f3ce400f Docs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-08 09:34:07 +02:00
Michael Mayer
a8ec6f9cbb Develop: Refactor project configuration directory structure
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-08 09:25:48 +02:00
Michael Mayer
0759dfc946 Frontend: Use monospaced font for .p-log-message in logs.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-01 15:28:52 +02:00
Michael Mayer
e0333cb43b Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-01 15:26:06 +02:00
Michael Mayer
cbcebe8de4 Frontend: Update src/locales/json/*.json after translation removals
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-01 15:25:44 +02:00
Michael Mayer
568432df88 Images: Prefer native HEIF and AVIF conversion via libvips #5509
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-01 15:18:21 +02:00
Michael Mayer
812faccae6 Clean-up: Drop imaging and pigo library integrations #5353 #5508 #668
Also drops github.com/esimov/pigo since it requires the imaging lib.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-04-01 13:47:42 +02:00
graciousgrey
defb003db3 Tests: Adapt tests to frontend changes 2026-03-31 16:57:29 +02:00
Michael Mayer
e313f0e0bc Thumb: Bound TIFF image decodes to file size
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-31 15:16:23 +02:00
Michael Mayer
4b18fe1a45 Develop: Add bubblewrap package to base images
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-31 15:01:20 +02:00
Michael Mayer
3eb2b4f76f Develop: Upgrade base image from 260309-questing to 260331-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-31 09:45:40 +02:00
Michael Mayer
1f1770257d Weblate: Update frontend/src/locales/json/fr.json #5503
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-31 09:24:02 +02:00
Weblate
5cd13fa137 Weblate: Update frontend translations 2026-03-31 09:22:53 +02:00
Michael Mayer
ca4f063052 Frontend: Pin "axios" to v1.14.0 to mitigate supply chain attack
see https://socket.dev/blog/axios-npm-package-compromised

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-31 08:52:23 +02:00
Michael Mayer
9a7fdc4cdc Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-31 08:50:35 +02:00
lif
c86a461e3a
Vision: Save sidecar YAML after metadata updates #5493 2026-03-29 15:02:14 +02:00
Michael Mayer
898e8aa9d1 Audit: Add trace helper for quiet session cleanup logs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-29 14:21:18 +02:00
Michael Mayer
224816b531 Frontend: Remove upload button style in src/css/vuetify.css #1216
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-28 12:57:09 +01:00
Michael Mayer
1365169928 WebDAV: Preserve collection slashes in client requests #3541
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-28 12:41:46 +01:00
Michael Mayer
d32e9d754e Backend: Update Go deps in go.mod/go.sum, align server gzip 404 test
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-28 12:19:12 +01:00
Michael Mayer
31efae3731 Frontend: Refactor layout and usability of dialog toolbars #1216
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-28 11:56:21 +01:00
Michael Mayer
24e7d6fd72 Frontend: Improve usability of upload dialog #1216
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-28 11:55:22 +01:00
Weblate
af064b2405 Weblate: Update frontend translations 2026-03-28 11:53:17 +01:00
Michael Mayer
17653a43fa Frontend: Update translations.pot #1216
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-28 11:51:27 +01:00
Michael Mayer
25b0d53cd5 Auth: Improve layout of login form in src/page/auth/login.vue #5476
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-28 09:54:30 +01:00
Michael Mayer
a41ef30237 Frontend: Upgrade dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-28 09:35:57 +01:00
Michael Mayer
a7b72c981c Translations: Update frontend/src/locales/json/fr.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-28 09:35:14 +01:00
graciousgrey
08fb7d88e4 Update SPONSORS.md 2026-03-14 14:04:16 +02:00
Weblate
d4e143cf3f Weblate: Update frontend translations 2026-03-10 20:42:53 +01:00
Ömer Duran
95099a5f78 Frontend: Upgrade Vuetify from ~3.11.9 to ^3.12.0 #5452 2026-03-10 12:31:48 +01:00
Michael Mayer
01e0719c67 Ollama: Change default cloud model to "qwen3-vl:235b-instruct-cloud"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-10 08:55:27 +01:00
Michael Mayer
dad865a009 Vector: Decouple DBSCAN progress logging 2026-03-09 15:21:29 +00:00
Michael Mayer
6cc0fe49c9 Faces: Merge PR #5481 2026-03-09 15:19:30 +00:00
Michael Mayer
ce5bde84ab Web Upload: Reduce icon size in drop area #1216
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-09 13:51:24 +01:00
Keith Martin
bcf0c0fb28 faces: improve information logging in long running processes so they provide a status up every 15 minutes 2026-03-09 22:35:52 +10:00
Michael Mayer
e052fd3eaf Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-09 11:49:28 +01:00
Michael Mayer
75064a1c1f Develop: Upgrade base image from 260301-questing to 260309-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-09 11:35:32 +01:00
Michael Mayer
c2335dc31b API: Do not broadcast session-specific tokens via config.updated event
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-09 11:09:17 +01:00
Michael Mayer
fb436fd8bd Translations: Update frontend/src/locales/json/*.json #1216
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-09 10:53:35 +01:00
Weblate
43fd75d969 Weblate: Update frontend translations 2026-03-09 10:52:58 +01:00
Michael Mayer
194e4ccb26 Web Upload: Update frontend "translations.pot" and "*.po" files #1216
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-09 10:50:59 +01:00
Michael Mayer
ba95e3a728 Web Upload: Support Drag & Drop #1216
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-09 10:39:36 +01:00
Michael Mayer
a71718e8ba Translations: Update frontend/src/locales/json/fr.json #5479
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-09 09:27:54 +01:00
Weblate
51a0a3f384 Weblate: Update frontend translations 2026-03-09 09:26:30 +01:00
Michael Mayer
19c8afd5cb Web Upload: Update frontend "translations.pot" and "*.po" files #1216
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-09 09:25:16 +01:00
Michael Mayer
1a110df2e0 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 15:38:31 +01:00
Michael Mayer
c8b4d8f4f3 Backend: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 15:37:45 +01:00
Michael Mayer
b3216d3a87 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 15:36:13 +01:00
Michael Mayer
e9a714098d Security: Add API request-limit regression check script
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 15:12:32 +01:00
Michael Mayer
859e5d9b4b Frontend: Harden splash links for safer new-tab navigation
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 14:41:21 +01:00
Michael Mayer
04c57e2b96 Frontend: Fix OIDC session restore and logout cleanup #5476
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 14:27:39 +01:00
Michael Mayer
9219d14d3f API: Export request limit helpers and align test guidance
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 13:49:50 +01:00
Michael Mayer
cc7064b5a9 Logs: Improve log messages in API and share audit paths
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 12:53:20 +01:00
Michael Mayer
c1ae7b46fa OIDC: Retry provider init after transient discovery failure #5478
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 11:56:53 +01:00
Michael Mayer
ceb5e232b0 Backend: Update github.com/ugjka/go-tz/v2 in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 11:33:04 +01:00
Michael Mayer
c60f76d0c9 Auth: Update frontend translations #5476
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 11:32:26 +01:00
Weblate
8c4f8b3f3a Weblate: Update frontend translations 2026-03-08 11:28:08 +01:00
Michael Mayer
885c770eeb Auth: Add "Stay signed in on this device" login toggle #5476
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 11:25:40 +01:00
Michael Mayer
dc9c23c69d API: Extend pre-parse request limits to more JSON handlers
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-08 10:29:34 +01:00
Michael Mayer
958cdb9f33 API: Enforce pre-parse body limits for login and uploads
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 15:31:30 +01:00
Michael Mayer
6ca0380fbe Frontend: Tighten caption sanitization and XSS sink checks
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 15:30:35 +01:00
Michael Mayer
5b8868b656 Security: Canonicalize HTTPS redirects
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 14:45:59 +01:00
Michael Mayer
e2ff8cd15d Server: Use canonical host for AutoTLS HTTP redirects
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 14:31:03 +01:00
Michael Mayer
329779c774 Search: Reuse label helpers for homophone-aware lookups #5227 #5238
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 12:06:25 +01:00
Michael Mayer
168834a157 Entity: Fix cell lookups
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 11:48:20 +01:00
Michael Mayer
8ef21bc895 Entity: Fix photo-label caching #5227 #5238
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 11:48:07 +01:00
Michael Mayer
5c0582d85e Entity: Fix label homophone lookups and photo-label caching #5227 #5238
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 11:43:25 +01:00
Michael Mayer
b9f12eaf37 Folders: Improve slug collision handling for Unicode paths #5366
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 11:16:21 +01:00
Michael Mayer
a237bf7932 WebDAV: Link webdav/README.md in AGENTS.md and CODEMAP.md #5474
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 10:46:28 +01:00
Michael Mayer
360a25e9c4 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 10:24:35 +01:00
Michael Mayer
8c01f6fab6 WebDAV: Harden Transfer Safeguards & Fallback Diagnostics #5474
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 10:13:38 +01:00
Michael Mayer
a6db7f9fe1 WebDAV: Improve timeout handling and add hidden file filtering #3541
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 09:54:43 +01:00
Michael Mayer
bed7ca2285 WebDAV: Fall Back to Depth-1 Directory Discovery #3541
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-07 09:32:07 +01:00
Michael Mayer
fed54e97f0 Docs: Update CONTRIBUTING.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-06 19:10:40 +01:00
Michael Mayer
0303bc56d9 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-06 18:49:34 +01:00
Michael Mayer
a80953e8f3 Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-06 18:48:07 +01:00
Michael Mayer
39ea7add37 Assets: Rename example fixtures directory to "samples"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-06 18:47:33 +01:00
Michael Mayer
f8ab3b5042 Backend: Upgrade github.com/yalue/onnxruntime_go from v1.26.0 to v1.27.0
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-06 18:23:18 +01:00
Michael Mayer
20fd49f2ac Media: Improve layered TIFF & PSD preview support #5383
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-06 18:14:48 +01:00
Michael Mayer
c945acf62d Docs: Update CLAUDE.md with Markdown formatting guidelines
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-06 15:12:32 +01:00
Michael Mayer
4291932e3a Docs: Add CLAUDE.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-06 13:54:57 +01:00
Michael Mayer
567d30cfba Frontend: Reformat .js, .mjs, and .vue files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-06 13:48:22 +01:00
Michael Mayer
5c2290680d Build: Update Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-06 09:43:38 +01:00
Michael Mayer
2ee4f30a53 Config: Update ARMv7 compose env vars to current option names
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-05 22:15:52 +01:00
Michael Mayer
fad9d53958 Config: Reformat CLI flag usage descriptions
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-05 09:54:29 +01:00
Michael Mayer
ba8ae47e5a Config: Exclude inline non-flag fields from config-yaml report
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-05 04:37:29 +01:00
Michael Mayer
0ae82d3683 Server: Export WebDAV response helper for PROPFIND content type #5472
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-04 16:03:33 +01:00
Michael Mayer
7b96a768d5 WebDAV: Harden response headers for interoperability #5472
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-04 15:23:10 +01:00
Michael Mayer
ecdc49ad33 Server: Add HTTP security hardening config options #5471
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-04 10:12:57 +01:00
Michael Mayer
80338bdebc Media: Harden Vision URL fetching against SSRF and DoS
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-03 17:54:03 +01:00
Michael Mayer
b0fda99e2c Lint: Resolve gosec findings and add embedding dist benchmark
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-03 17:17:49 +01:00
Michael Mayer
f2aabb9bcd Security: Add gosec fixes with shared URL and fs validation helpers
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-03 16:38:41 +01:00
Michael Mayer
85263a0da6 Tests: Isolate photoprism test storage and document fixture setup
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-03 15:10:59 +01:00
Michael Mayer
a89d638e22 Vision/AI: Document FaceNet corruption/reinstall guidance
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-03 14:41:05 +01:00
Michael Mayer
82e6d294ba Backend: Update github.com/zitadel/oidc/v3 and github.com/golang/geo
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-03 11:48:08 +01:00
Michael Mayer
69dcce1619 Frontend: Update postcss in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-03 11:46:35 +01:00
Michael Mayer
f58335cb4b Build: Backport libvips in Jammy images and document 8.14+
- add scripts/dist/install-libvips.sh for Jammy backport installs
- switch jammy and jammy-slim Dockerfiles to use the new installer
- document libvips 8.14+ requirement in setup/pkg/linux docs
- update thumb/README.md and regenerate setup/pkg/linux/README.html

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-03 11:43:28 +01:00
Michael Mayer
f0b7c6c863 Portal: Update PHOTOPRISM_DATABASE_PROVISION_DSN related docs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-03 10:46:30 +01:00
Michael Mayer
9e722dfc7d Thumbs: Update github.com/davidbyttow/govips/v2 version in NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-03 09:25:34 +01:00
Michael Mayer
d365e86a50 Thumbs: Update github.com/davidbyttow/govips/v2 from v2.16.0 to v2.17.0
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-02 19:34:25 +01:00
Michael Mayer
9022309706 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-02 19:26:13 +01:00
Michael Mayer
fcb8bc60c4 Proxy: Rename portal-proxy-prefix to portal-proxy-uri
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-02 19:20:41 +01:00
Michael Mayer
23baa5bd70 Portal: Document test-env log archiving and clean rebuild workflow
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-02 10:23:08 +01:00
Michael Mayer
9c6263dac8 Frontend: Scope WebDAV dialog URLs to instance base path #2391
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-02 09:44:05 +01:00
Michael Mayer
2ee5f1337e PWA: Use scope-relative manifest URLs for iOS path-based installs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 23:33:44 +01:00
Michael Mayer
349cea2d2b PWA: Use scope-relative start_url for path-based installs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 22:48:13 +01:00
Michael Mayer
7ffb034990 Frontend: Namespace login autocomplete by storageNamespace
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 19:42:56 +01:00
Michael Mayer
532ddbd270 ACL: Add "audit" permission for audit API endpoints
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 17:24:49 +01:00
Michael Mayer
181f5140fc LDAP: Update test config in .ldap.cfg
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 16:32:55 +01:00
Michael Mayer
47cec1222a Backend: Run "make fmt-go"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 14:07:14 +01:00
Michael Mayer
eb81069210 Backend: Update github.com/gin-gonic/gin to v1.12.0 in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 14:06:53 +01:00
Michael Mayer
37473902fe Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 14:05:51 +01:00
Keith Martin
019d3e18d3
OIDC: Add handling to AuthID so that SQLite doesn't corrupt on save #4951 #5309
* OIDC: Add handling to AuthID so that SQLite doesn't corrupt on save with long numbers
* Entity: Ensure that AuthID wrap/unwrap is used for auth_user and auth_sessions, and that auth_sessions wrap/unwrap on create/save/find as required
* Entity: hard code toggle off wrap/unwrap, implement dbms migration change to pre-create/alter tables with auth_id in SQLite and pre-create for MariaDB
* Entity: revert wrap/unwrap for AuthID
* Migrate: Comment out MySQL statements required for GormV2
* Entity: revert authID to authId as per review
* Migrate: wrap authid changes in transaction (rollback if any errors), and drop migration tables
* migrate: correct tx.Error use, impove commit/rollback so no silent failures, remove excess err variable.
2026-03-01 13:58:02 +01:00
Michael Mayer
ed65deb83a Develop: Add config dir defaults to base images and compose.yaml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 12:56:53 +01:00
Michael Mayer
6a5cb1f20d Develop: Upgrade base image from 260221-questing to 260301-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 12:47:24 +01:00
Michael Mayer
9d27e5aae4 Dockerfiles: Add env defaults to develop base images
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 12:40:52 +01:00
Michael Mayer
54618b7117 Dockerfiles: Add openssh-client package to develop base images
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-03-01 12:26:51 +01:00
Peter Briggs
3c97d604fc Improve Caddy 2 description in websockets.vue
Reword for clarity and remove duplicate sentence.
2026-02-28 19:05:26 +01:00
Alexis Lefebvre
6d2b7d57a1
CLI: Update description of vision save command #5378 2026-02-28 19:01:06 +01:00
Michael Mayer
3866ed978b Docs: Mention optional "gh issue view" command in AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-28 16:41:13 +01:00
Michael Mayer
d86812c0cb Makefile: Add gh install target and explicit issue-editing rule
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-28 16:30:18 +01:00
Michael Mayer
da6ab3fab0 Docs: Improve GitHub issue description guidance in AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-28 15:05:09 +01:00
Michael Mayer
75cea34e32 Docs: Improve GitHub issue & docs writing guidance in AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-28 14:47:43 +01:00
Michael Mayer
ee4aaa4e4e Docs: Update commit message guidance in AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-28 13:23:39 +01:00
Michael Mayer
3484da8033 Frontend: Migrate npm lockfile handling to root workspace #5458
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-27 13:34:13 +01:00
Michael Mayer
962695394e GitHub: Update commit message and issue writing guidelines
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-27 12:32:16 +01:00
Ömer Duran
87bc9b9d18 Frontend: Rename root package 2026-02-27 11:41:30 +01:00
Ömer Duran
3d628a06bc Frontend: Add npm workspaces and root ESLint config for IDE auto-detection 2026-02-27 11:41:30 +01:00
Michael Mayer
99d34a9c8f Security: Update http/security/scan-paths.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-27 00:21:10 +01:00
Michael Mayer
a570da6335 Feedback: Remove UI route and disable API endpoint
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 23:30:43 +01:00
Michael Mayer
2575b0e953 Config: Report services-cidr under Networking section #5461
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 23:02:58 +01:00
Michael Mayer
6bc8527097 Cluster: Revalidate portal proxy cache & tighten OAuth scope usage
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 22:42:05 +01:00
Michael Mayer
5334ef3a68 Cluster: Require OAuth for existing-node register mutations
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 22:06:53 +01:00
Michael Mayer
a3afc43ad2 Frontend: Update webpack from v5.105.2 to 5.105.3 in package.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 20:03:02 +01:00
Michael Mayer
f1f92bc35b Backend: Update golang.org/x/net in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 20:02:03 +01:00
Michael Mayer
34be2f0bd8 Cluster: Protect register mutations and enforce CIDR gate
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 19:59:33 +01:00
Michael Mayer
694276cc6b Services: Add CIDR allowlist for discovery and WebDAV traffic #5461
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 18:18:40 +01:00
Michael Mayer
7476231235 Server: Fix remaining gosec/revive issues in internal/server
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 16:01:47 +01:00
Michael Mayer
a7223337e0 Docs: Specify commit message format in AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 15:58:30 +01:00
Michael Mayer
c91726d969 Server: Disable implicit proxy trust and add spoof tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 15:57:40 +01:00
Michael Mayer
92d222a308 Config: Gate node roles by edition and align tests/lint
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 15:37:55 +01:00
Michael Mayer
78c0fb897b Pkg: Update http/security/scan-paths.go and hash_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 13:45:07 +01:00
Michael Mayer
038d38d552 Security: Extend denylist coverage for names, paths and extensions #5459
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-26 11:01:15 +01:00
Michael Mayer
31515f9524 Security: Harden web overlay serving via shared security checks
https://github.com/photoprism/photoprism/issues/5459
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-25 17:01:39 +01:00
Michael Mayer
5e358376c3 Portal: Align docs, specs, and QA guides with new features/changes
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-25 10:41:25 +01:00
Michael Mayer
241a457bac Weblate: Update frontend/src/locales/json/fr.json #5460
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-25 03:05:08 +01:00
Weblate
54a2ba34bb Weblate: Update frontend translations 2026-02-25 03:04:08 +01:00
Michael Mayer
260829840f Frontend: Update "@eslint/eslintrc" in package.json & package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-25 03:03:13 +01:00
Michael Mayer
b2f137f240 Security: Generate hashed scan paths from resource list
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-25 03:01:13 +01:00
Michael Mayer
18061fb536 Config: Refactor frontend URI handling for configurable base paths
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-25 00:55:16 +01:00
Michael Mayer
bcb6d39332 Server: Add web overlay handler for unmatched routes #5459
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 20:02:58 +01:00
Michael Mayer
d6286a25b3 Config: Rename configPath() to resolveConfigPath() in config_storage.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 16:53:37 +01:00
Michael Mayer
3c2f26161a CLI: Refactor unzipSafe() in internal/commands/cluster_theme_pull.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 12:17:01 +01:00
Michael Mayer
0e91ef5ba2 Index: Expanded folder-album reconciliation scope when needed #5437
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 12:15:58 +01:00
Michael Mayer
7211eb1d12 Config: Centralize options patch persistence and update related docs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 10:20:16 +01:00
Michael Mayer
855d39f332 Frontend: Disable table border spacing in vuetify.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 09:01:31 +01:00
Michael Mayer
a79eb6e1a4 Cluster: Refactor configuration and secret persistence
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 06:57:35 +01:00
Michael Mayer
fbaf356b1d Cluster: Fix stale secret retry auth and stop implicit DB provisioning
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 04:20:19 +01:00
Michael Mayer
8b61ffc8aa Cluster: Retry credential refresh without stale node UUID
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 03:35:40 +01:00
Michael Mayer
50ded66db3 Cluster: Endure complete registration payload in node/bootstrap.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 03:14:17 +01:00
Michael Mayer
a4849207dd Config: Fix deriveNodeNameAndDomainFromHttpHost() in config_cluster.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 02:32:45 +01:00
Michael Mayer
d5ecab8827 Proxy: Define /i/ as DefaultPathPrefix for shared-domain deployments
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-24 01:15:23 +01:00
Michael Mayer
3f8e74f6d4 CLI: Standardize path validation and exit codes #5457
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 23:00:05 +01:00
Michael Mayer
21b75618c6 Index: Update CODEMAP.md and internal/photoprism/README.md #5437
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 22:42:08 +01:00
Michael Mayer
37c6a23367 Index: Reconcile existing folder albums on forced rescans #5437
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 22:32:08 +01:00
Michael Mayer
ed95e9a929 Ignore Rules: Normalize paths and trim Docker build context
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 19:37:55 +01:00
Michael Mayer
d08363470e Docs: Add GLOSSARY.md file, update AGENTS.md, and ignore files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 19:30:36 +01:00
Michael Mayer
b7109ef4f7 Docs: Add logging terminology to AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 17:36:18 +01:00
Michael Mayer
e0a9e63c89 Frontend: Upgrade "maplibre-gl" from v5.18.0 to v5.19.0
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 17:17:07 +01:00
Michael Mayer
a78d9d16c9 Frontend: Update translations in src/locales/json/*.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 17:10:17 +01:00
Weblate
f3f1091fd4 Weblate: Update frontend translations 2026-02-23 17:08:37 +01:00
Michael Mayer
a0070dce1c Cluster: Improve usage of canonical terms in code/docs based on glossary
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 16:16:29 +01:00
Michael Mayer
27e05fe067 Vision: Add tests to document JSON handling for Ollama and OpenAI #5450
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 14:35:11 +01:00
Michael Mayer
8ba783c2f4 Makefile: Add "format-tables" target to fix Markdown table formatting
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 13:36:22 +01:00
Michael Mayer
5ff9cc5b7a Ollama: Add thinking response fallback for captions #5455
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 13:35:34 +01:00
Michael Mayer
0da0f025dd Txt: Update stopwords.txt and stopwords.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 04:39:29 +01:00
Michael Mayer
c1467cb3f5 Cluster: Rename the "tenant" node role to "instance" for accuracy
This more accurately reflects the multi-instance architecture.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 04:27:43 +01:00
Michael Mayer
4a71ce84e4 Frontend: Update locales/translations.pot and *.po
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 03:57:27 +01:00
Michael Mayer
a7f5857714 Frontend: Update locales/de.po and locales/json/de.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 03:46:21 +01:00
Michael Mayer
4450bd1ae1 Frontend: Update locales/translations.pot and *.po
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 03:31:26 +01:00
Michael Mayer
5f50802384 Cluster: Rename the "app" node role to "tenant"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-23 03:27:11 +01:00
Michael Mayer
75c2378c4a Frontend: Downgrade Vuetify from ^3.12.0 to ~3.11.9 (breaking changes)
Vuetify 3.12.0 includes breaking changes for VTreeview and VList:
reworked indentation and spacing in trees and nested lists
see https://github.com/vuetifyjs/vuetify/releases/tag/v3.12.0

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-22 22:17:47 +01:00
Michael Mayer
82b1a554a9 Docs: Update AGENTS.md and CODEMAP.md to align with gettext improvements
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-22 17:21:44 +01:00
Michael Mayer
267fabffa9 Backend: Update filippo.io/edwards25519 from v1.1.0 to v1.2.0
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-22 16:53:14 +01:00
Michael Mayer
26821ee6f1 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-22 16:41:26 +01:00
Michael Mayer
18c7ac32ff Makefile: Add "gettext-compile" target to regenerate frontend json files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-22 16:39:43 +01:00
Michael Mayer
9932df5a32 Frontend: Add scripts/gettext-extract.sh, update translations.pot
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-22 16:35:42 +01:00
Michael Mayer
45bfdf30c3 Docs: Update paths in README.md, AGENT.md, and CODEMAP.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-22 15:33:19 +01:00
Michael Mayer
f66dff6030 Git: Update .gitignore
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-22 00:31:05 +01:00
Michael Mayer
384a2bf351 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-22 00:28:54 +01:00
Michael Mayer
e326bd3d67 Update Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-21 08:42:19 +01:00
Michael Mayer
ccae73e9de Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-21 07:13:10 +01:00
Michael Mayer
d4e4c1eef7 Build: Upgrade develop image from 260220-questing to 260221-questing
Includes the latest NodeJS v24, Eslint v9, and TestCafe v3.7.4.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-21 06:09:50 +01:00
Michael Mayer
5fb0356305 Frontend: Upgrade NodeJS from 22 to 24 in scripts/dist/install-nodejs.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-21 05:50:37 +01:00
Michael Mayer
ad7458c94e Backend: Change Markdown table alignment in internal/ and pkg/
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-21 05:13:57 +01:00
Michael Mayer
7e891b696b Frontend: Change table alignment in src/common/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-21 05:12:39 +01:00
Michael Mayer
270b3d1683 Frontend: Update TestCafe from v3.7.2 to v3.7.4
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-21 05:11:52 +01:00
Michael Mayer
ce65fc7e7b Dev: Update Dockerfiles, Makefile, .gitignore, and .dockerignore
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-21 00:53:36 +01:00
Michael Mayer
0ce0588fd5 Tests: Improve stability of TestZip in internal/api/zip_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 19:06:42 +01:00
Michael Mayer
2d2b93a83c Library: Revert problematic .ppignore changes in index/import #5447
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 18:56:11 +01:00
Michael Mayer
a41b718763 Thumbs: Document impact of the new JPEG encoder/decoder in Go 1.26
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 17:35:20 +01:00
Michael Mayer
9570a9aad5 Docs: Update notes on root-level task files in AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 15:39:06 +01:00
Michael Mayer
a09f8fc5aa Backend: Upgrade Go dependencies in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 15:25:55 +01:00
Michael Mayer
91a342300d Frontend: Upgrade Vuetify from v3.11.8 to v3.12.0 in package.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 15:05:31 +01:00
Michael Mayer
2ac3ae8caf Dev: Add local repo & todo artifacts to .gitignore and .dockerignore
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 14:31:31 +01:00
Michael Mayer
a2b7615c93 Go: Apply go fix modernizations across backend packages
Run `go fix ./...` and keep mechanical modernization updates.

- Replace `interface{}` with `any` in signatures and local types
- Apply formatter/style cleanups from go1.26 tooling
- Keep `omitempty` behavior-preserving simplifications suggested by fix
- No functional feature changes intended

Validation:
- go test ./... -run '^$' -count=1 (Go 1.26.0)
- GOTOOLCHAIN=go1.24.10 go test ./... -run '^$' -count=1

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 03:54:33 +01:00
Michael Mayer
4653e14b6d Tests: Tolerate minor TensorFlow label uncertainty drift
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 03:10:28 +01:00
Michael Mayer
97ad37be6d Develop: Upgrade base image from 260209-questing to 260220-questing
Includes ONNX Runtime v1.24.1 and other updated deps.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 02:46:44 +01:00
Michael Mayer
273aa53ad0 Backend: Upgrade github.com/yalue/onnxruntime_go from v1.25.0 to v1.26.0
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 02:38:48 +01:00
Michael Mayer
ef7eb1367f Backend: Update github.com/dustinkirkland/golang-petname in go.mod & sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 02:19:46 +01:00
Michael Mayer
8b75a943f1 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 02:19:03 +01:00
Michael Mayer
09ce485725 Config: Add "theme-url" option (pro/portal) and URI credential redaction
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-20 02:15:52 +01:00
Michael Mayer
f6d202615a Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-18 23:29:45 +01:00
Michael Mayer
58690d14d2 Config: Update report.go and report_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-18 21:40:10 +01:00
graciousgrey
13daad21e6 Tests: Update testcaferc.json 2026-02-16 14:55:44 +01:00
Michael Mayer
ac1b04f840 Update style notes in AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-14 12:22:53 +01:00
Michael Mayer
cd7affffeb Cleanup: Fix formatting of Markdown files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-14 12:10:43 +01:00
Michael Mayer
d0b09206fb Docs: Add Title Case rules to AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-14 11:53:03 +01:00
Michael Mayer
7b2d073a0f Config: Improve NormalizePathPrefix validation & tests #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-14 10:46:32 +01:00
Michael Mayer
89f4cb4e34 Config: Add portal-proxy-prefix option for multi-tenant setups #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-14 10:26:12 +01:00
Michael Mayer
6867626c9a Docs: Shorten "Context & Constraints" to "Constraints"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-14 08:23:27 +01:00
Michael Mayer
49b8948341 Develop: Add "postgres:18-alpine" database service to compose.yaml #4831
Removes compose.postgres.yaml because it isn't needed anymore.

Related Issue:
- #47

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-13 23:31:59 +01:00
Michael Mayer
5af656d019 Docs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-13 17:03:13 +01:00
Michael Mayer
19660fb41c CI: Remove .opensourcefinder-verify
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-13 13:46:29 +01:00
Michael Mayer
919c71e155 CI: Add .opensourcefinder-verify
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-13 13:36:06 +01:00
Michael Mayer
4a07c1a53c Folders: Repair stale emoji folder album titles #5366
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-13 12:58:33 +01:00
Michael Mayer
f671f7da49 API/Docs: Update internal/api/swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-13 12:46:01 +01:00
Michael Mayer
3cb7a64a7a Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-13 12:45:23 +01:00
Michael Mayer
1ed55f25d3 API: Gate additional endpoints to prevent CDNs from caching
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-12 19:38:06 +01:00
Michael Mayer
3dbf6d359a Metadata: Clamp invalid Google JSON GPS coordinates to geo bounds #5373
Also see: https://github.com/photoprism/photoprism/issues/5445

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-11 13:42:58 +01:00
Michael Mayer
4742cfd3ca Frontend: Add tests/README.md and update CODEMAP.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-11 12:26:15 +01:00
Michael Mayer
92fea4ad9f Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-11 11:35:14 +01:00
Michael Mayer
5af3ab04ca UX: Update docs with info about Library > Hidden #5391
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-11 11:32:18 +01:00
Michael Mayer
66cbe94886 UX: Display error details in results under Library > Hidden #5391
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-11 10:51:30 +01:00
Michael Mayer
5fe33d4cbe Folders: Fix emoji child paths overwriting parent folder albums #5366
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-10 18:08:30 +01:00
Michael Mayer
a232298c2a Index: Fix photos mislabeled as image after video merge #5418
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-10 17:55:24 +01:00
Michael Mayer
4dfc69dee6 Places: Update entity/photo_location_test.go #5445
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-10 17:36:47 +01:00
Michael Mayer
5b4ac68288 Places: Fix minor GPS boundary overshoots in S2 mapping #5445
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-10 17:29:51 +01:00
Michael Mayer
1a1ff63565 Library: Fix .ppignore inconsistently ignoring related media files #5447
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-10 16:53:18 +01:00
Michael Mayer
1e9d9ecb23 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-10 14:54:59 +01:00
Michael Mayer
a94df841b1 Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-10 14:53:38 +01:00
Michael Mayer
96039adc39 Portal: Adjust navigation options in web UI
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-10 14:51:04 +01:00
Michael Mayer
2dd6a1a333 MariaDB: Drop legacy "preview" user in scripts/sql/mariadb-init.sql
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-10 12:49:04 +01:00
Michael Mayer
1463c98f3c OIDC: Update Keycloak schema dump in scripts/sql/mariadb-init.sql
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-10 12:42:09 +01:00
Michael Mayer
c6c16c5355 OIDC: Update Keycloak client settings in scripts/sql/mariadb-init.sql
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-10 12:34:42 +01:00
Michael Mayer
9fbef7cf64 WebDAV: Improve redirect and read/write request method handling
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-10 11:45:32 +01:00
Michael Mayer
de9a067065 Portal: Disable WebDAV endpoints
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-09 18:31:33 +01:00
Michael Mayer
dc7d49a7ee Develop: Upgrade base image from 260130-questing to 260209-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-09 14:31:51 +01:00
Michael Mayer
93304987de Backend: Update github.com/zitadel/oidc/v3 in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-09 14:14:11 +01:00
Michael Mayer
dc093b6b70 Frontend: Update dependencies in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-09 14:13:33 +01:00
Michael Mayer
2ed5fc185c Scripts: Update FFmpeg installation script #5303 #5439
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-09 14:06:31 +01:00
Michael Mayer
df5efb61a2 Backend: Clean up error handling and unit tests in pkg/...
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-09 12:31:29 +01:00
Michael Mayer
f07f46fec8 Backend: Clean up error handling and unit tests in internal/ packages
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-09 12:00:33 +01:00
Michael Mayer
5fab1d8a70 Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-08 18:38:08 +01:00
Michael Mayer
47b1664131 Backend: Update golang.org/x/sys in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-08 18:37:06 +01:00
Michael Mayer
733307c43f Frontend: Namespace local storage to run multiple nodes on a domain #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-08 18:35:05 +01:00
Michael Mayer
1c1c9365b6 CLI: Init config in "photoprism stop" via InitCore() to avoid bootstrap
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-07 13:57:15 +01:00
Michael Mayer
7dbf5dd9ff Cluster: Exclude proxy path prefix from gzip compression and sec headers
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-07 12:43:05 +01:00
Michael Mayer
cf6cf46c55 CLI: Init config in "photoprism config" via InitReport() to avoid delays
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-07 12:02:50 +01:00
Michael Mayer
3ea307405f CI: Add "mariadb-init" target to Makefile and update mariadb-init.sql
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-06 15:11:33 +01:00
Michael Mayer
f4574b7db4 Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-06 12:35:35 +01:00
Michael Mayer
5fd1e13a96 Cluster: Don't enforce TLS for internal connections
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-06 12:34:10 +01:00
Ömer Duran
91732984c6
Tests: Move cluster-node test and add pro Vitest config (#5434) 2026-02-05 09:37:04 +01:00
Michael Mayer
eb7535cbeb Portal: Add path-based proxy routing and config flag
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-02 06:51:43 +01:00
Michael Mayer
8e5a68b9a0 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-02 04:14:04 +01:00
Michael Mayer
29da82c9ff Frontend: Update dependencies in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-02 04:12:09 +01:00
Michael Mayer
1f6760e088 Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-02-01 02:15:32 +01:00
Michael Mayer
5fb94ba178 Develop: Upgrade base image from 260121-questing to 260130-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-30 18:07:29 +01:00
Michael Mayer
61c93b9c62 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-30 17:25:10 +01:00
Michael Mayer
9609725bc0 Frontend: Update dependencies in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-30 17:24:39 +01:00
Michael Mayer
ee9bda2243 Tests: Run "make fmt-go"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-30 17:24:13 +01:00
Michael Mayer
4691279600 CI: Add "audit" targets to Makefile and frontend/Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-30 17:11:01 +01:00
graciousgrey
82cb436621 Tests: Fix failing test 2026-01-29 18:37:53 +01:00
Michael Mayer
8400dda02b Download: Add script flags to install "yt-dlp" nightly and master builds
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-28 11:10:12 +01:00
Michael Mayer
68c1b35801 Weblate: Update translations in locales/json/ro.json #5423
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-28 10:21:13 +01:00
Weblate
cfe97bd76d Weblate: Update frontend translations 2026-01-28 10:19:44 +01:00
Alexis Lefebvre
8ffbdbffb0
Setup: Fix typo “enviconment” in compose config examples #5424 2026-01-28 09:32:28 +01:00
Michael Mayer
4a0214691a Frontend: Make test conditional in vitest/model/cluster-node.test.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-28 09:29:36 +01:00
Michael Mayer
c3f748ba1b Frontend: Fix lint configuration in eslint.config.mjs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-28 09:28:35 +01:00
Michael Mayer
dbc070012a Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-28 09:12:55 +01:00
Michael Mayer
2891fdbc65 Backend: Update Go dependencies in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-28 09:08:09 +01:00
Michael Mayer
5373194266 CI: Add security vulnerability check targets to Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-28 08:59:14 +01:00
Michael Mayer
de3f871e62 Scripts: Fix MODEL_21K_LABELS_URL in download-nasnet.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-24 13:13:08 +01:00
graciousgrey
20df956c46 Tests: Adapt testcafe command to run on latest chrome 2026-01-23 18:50:28 +01:00
Michael Mayer
26b5cbafcd Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-21 18:21:17 +01:00
Michael Mayer
e3430f76cd Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-21 18:12:17 +01:00
Michael Mayer
19a092bdb6 Develop: Upgrade to new Docker base image, including Go v1.25.6
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-21 18:11:21 +01:00
Michael Mayer
6ce64ab624 Docs: Remove excessive whitespace
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-20 08:41:30 +01:00
Michael Mayer
aeee5af0e2 Docs: Update guidance on timestamp & ID usage in tests and documentation
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-20 08:38:37 +01:00
graciousgrey
b03bd90a05 Translations: update lv.json 2026-01-16 13:36:04 +01:00
Cathie Integra
e8b2f02248
Weblate: Update frontend translations (#5422)
Co-authored-by: Weblate <noreply@weblate.org>
2026-01-16 13:19:03 +01:00
Cathie Integra
2abc9cdf4a
Weblate: Update backend translations (#5420)
Co-authored-by: Weblate <noreply@weblate.org>
2026-01-16 13:18:09 +01:00
Fox Silver
6a15b564cf Update Makefile for latest Ubuntu
Latest Docker build is using Ubuntu 25.10, the darkfile init is failing due to using older ubuntu version repos and incompatible dependencies.
2026-01-13 08:07:27 +01:00
graciousgrey
8f298857a6 Translations: Add latvian 2026-01-09 12:00:03 +01:00
Cathie Integra
d54e59a2b8
Weblate: Update backend translations (#5410)
Co-authored-by: Weblate <noreply@weblate.org>
2026-01-09 11:07:29 +01:00
Cathie Integra
a5ccfb5709
Weblate: Update frontend translations (#5409)
Co-authored-by: Weblate <noreply@weblate.org>
2026-01-09 11:06:55 +01:00
Michael Mayer
7e3a88268a Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-07 13:40:14 +01:00
Michael Mayer
581e54f817 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-01-07 13:39:50 +01:00
graciousgrey
52cedfd4bd Search: Improve search filter description 2026-01-06 11:28:51 +01:00
Ömer Duran
cdf00beda4
Tests: Improve test isolation and cleanup in vitest suites (#5387)
* Tests: Improve test isolation and cleanup in vitest suites

* Tests: Add component tests for navigation, photo toolbar, and file editing

* Tests: Remove unused notification spies from batch edit component tests

* Tests: update Vitest `$notify` mock to use `vi.fn()` and include `info` method.
2025-12-30 13:03:10 +01:00
Michael Mayer
1b09c2b8e3 Frontend: Update webpack.config.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-29 10:40:32 +01:00
Michael Mayer
833e82bb9c Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-29 10:17:33 +01:00
Michael Mayer
e6ed84bc7f Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-29 10:17:03 +01:00
Michael Mayer
79a5afd2f5 Vips: Skip all images that already have an ICC profile #5389
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-29 10:14:13 +01:00
Michael Mayer
69acd58e12 Vips: Only call GetString() if interop index exists #5389
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-29 10:02:49 +01:00
Michael Mayer
82c5989b30 Fix error handling in mediafile_vision.go and convert_video_avc.go #5398
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-29 09:36:47 +01:00
Michael Mayer
8296708037 CLI: Adjust search query used in "photoprism video" subcommands
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-23 15:17:55 +01:00
Michael Mayer
b34cbda28a ONNX: Upgrade develop base image from 251211 to 251223-questing #5394
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-23 12:44:36 +01:00
Michael Mayer
b381012a01 ONNX: Upgrade runtime from v1.22.0 to v1.23.2 #5394
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-23 12:31:09 +01:00
Michael Mayer
28eb11d468 TensorFlow: Trigger explicit GC to free C-allocated tensor memory #5394
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-23 12:06:26 +01:00
Michael Mayer
898f6bc69b CLI: Improve "photoprism video" subcommands
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-21 18:47:19 +01:00
Michael Mayer
4b8c41b96d CLI: Add "photoprism video" subcommands
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-21 17:36:57 +01:00
graciousgrey
572b6e7311 Update sponsors.md 2025-12-17 08:53:04 +01:00
Michael Mayer
d4287ef81a Server: Refactor Gzip exclusions to use a custom func #5384
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-12 12:57:58 +01:00
Michael Mayer
c8268dfcf9 Server: Remove blank lines in gzip_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-12 11:34:05 +01:00
Michael Mayer
526974d441 Server: Upgrade github.com/gin-contrib/gzip from v1.2.3 to v1.2.5
Related Issues/PRs:
- https://github.com/gin-contrib/gzip/issues/122
- https://github.com/gin-contrib/gzip/pull/123

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-12 11:31:03 +01:00
Michael Mayer
5cd316fe17 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-12 11:08:04 +01:00
Michael Mayer
88ee6ec8d4 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-12 10:57:13 +01:00
Michael Mayer
492f96f549 Dev: Upgrade base image from 251208-questing to 251211-questing #5361
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-11 11:28:26 +01:00
Michael Mayer
d62824ea23 CI: Fix typo in docker/develop/questing/Dockerfile #5361
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-11 11:17:04 +01:00
Michael Mayer
e50dafe3e1 Setup: Add OLLAMA_API_KEY and OLLAMA_BASE_URL to Compose files #5361
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-10 11:26:40 +01:00
Michael Mayer
18889cc21f AI: Remove OLLAMA_BASE_URL default from Dockerfiles #5361
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-10 11:09:37 +01:00
Michael Mayer
4e18b689fe Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-10 10:56:04 +01:00
Michael Mayer
728abc2d71 Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-10 10:55:24 +01:00
Michael Mayer
75f183aa25 AI: Add support for OLLAMA_BASE_URL env expansion in vision.yml #5361
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-10 10:52:26 +01:00
Michael Mayer
d5c56d4e7e Dev: Update dummy oidc and webdav images in compose.yaml files #5381
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-10 09:21:42 +01:00
Michael Mayer
5f9fe5d62a Backend: Update Go dependencies in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-10 09:20:35 +01:00
Michael Mayer
184deb20d2 WebDAV: Enable the "dummy-webdav" service to shut down gracefully
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-10 08:56:53 +01:00
Michael Mayer
471ec0318b OIDC: Update dependencies of the "dummy-oidc" service & add tests #5381
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-10 08:55:27 +01:00
Michael Mayer
b7dd9371a4 Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-09 14:00:13 +01:00
Michael Mayer
dc508ff496 CI: Shorten .prettierignore files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-08 10:14:22 +01:00
Michael Mayer
6f580e7e12 Docs: Reformat AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-08 10:13:47 +01:00
Michael Mayer
5e646de74c Go: Upgrade base image from 251121-questing to 251208-questing #5374
Go v1.25.5 includes the following fixes and improvements:
- https://github.com/golang/go/issues/76464
- https://github.com/golang/go/issues/76461
- https://github.com/golang/go/issues/76360
- https://github.com/golang/go/issues/76245

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-08 10:11:37 +01:00
Michael Mayer
fd4519ec0b Backend: Update ONNX and OIDC deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-05 15:07:40 +01:00
Michael Mayer
152c45d2b6 Config: Reduce MinWakeupInterval from 1m to 1s
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-05 15:04:38 +01:00
Michael Mayer
e4c571fa5b Setup: Change Ubuntu base image version from 24.04.2 to 24.04.3 #4414
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-05 14:02:12 +01:00
Michael Mayer
7d139bd364 AI: Ensure default caption model only runs manual #5361
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-04 16:20:39 +01:00
Michael Mayer
f295a4bac3 AI: Set default Model & URI depending on OLLAMA_API_KEY env var #5361
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-04 16:10:29 +01:00
Michael Mayer
52ac4a91e0 AI: Update model Options overview in docs to align with code #5361
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-03 11:00:05 +01:00
Michael Mayer
2660bacdec AI: Use OLLAMA_API_KEY as API auth token if specified #5361
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-03 10:47:08 +01:00
Michael Mayer
d4aef5cf49 AI: Rename vision.ApiRequestOptions to vision.ModelOptions
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-02 17:05:22 +01:00
Michael Mayer
068d5dbfe5 Add .editconfig to specify editor defaults
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-12-02 16:48:43 +01:00
graciousgrey
5fc3afcbef Tests: Improve acceptance tests 2025-12-02 11:03:11 +01:00
graciousgrey
2990a59138 Tests: Fix typo in test fixtures 2025-12-02 11:02:05 +01:00
Michael Mayer
b3068414cd Frontend: Set BUILD_ENV=development for "npm run watch" #5358
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-30 20:36:56 +01:00
Michael Mayer
22e3c6d6d8 Metrics: Adjust ACL rules for endpoint access #5355
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-30 11:05:32 +01:00
Michael Mayer
96fe2c70a7 Metrics: Use string constants in API endpoint #5355
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-30 10:50:26 +01:00
Michael Mayer
dc19035d8f Metrics: Add file system and account usage info #5355
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-30 10:43:58 +01:00
Michael Mayer
314987f5ba Backend: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-29 09:48:07 +01:00
Michael Mayer
602f059348 Makefile: Add "fmt-swag" alias for "swag-fmt"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-29 09:47:44 +01:00
Michael Mayer
0cbfcea2e8 Frontend: Update lint deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-29 09:43:50 +01:00
Michael Mayer
511f1b00e4 Weblate: Update frontend/src/locales/json/fr.json #5351
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-29 09:41:38 +01:00
Weblate
5267ea6dfa Weblate: Update frontend translations 2025-11-29 08:36:45 +01:00
graciousgrey
75515d3653 Tests: Improve acceptance tests to be more stable 2025-11-28 10:32:00 +01:00
Michael Mayer
d19c70e8e7 CI: Update preview and release targets in Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 20:24:26 +01:00
Michael Mayer
7ae88f0d7c AI: Update vision docs to align with the implementation #5234
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 19:57:03 +01:00
Michael Mayer
015125b5d1 AI: Auto-add model defaults when loading "vision.yml" #5234
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 19:49:30 +01:00
Michael Mayer
1bcc3970f8 Backend: Update github.com/go-co-op/gocron/v2 in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 19:49:30 +01:00
graciousgrey
1203d23ccb Tests: Add tests #271 2025-11-27 18:59:29 +01:00
Michael Mayer
059e6baedf API: Improve logging in batch edit request handler #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 17:54:05 +01:00
Michael Mayer
c7ffcbc8df Clipboard: Enforce MaxItems limit when performing range-selects #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 17:06:53 +01:00
Michael Mayer
a11b5cafab Frontend: Use context name constants in page/album/photos.vue
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 16:40:33 +01:00
Michael Mayer
b9f5ea8659 Frontend: Reformat src/common/*.js with ESLint & Prettier
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 16:36:38 +01:00
Michael Mayer
9231bfc8f8 Frontend: Introduce reusable context constants across components & tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 16:34:32 +01:00
Michael Mayer
bf781b9b37 OIDC: Add "Entra App Roles" section to README.md #5334
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 15:28:07 +01:00
Michael Mayer
53b21eb5a0 OIDC: Update README.md #5334
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 13:16:10 +01:00
Michael Mayer
4d0bddf74a Frontend: Update translation .json files #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 12:40:19 +01:00
Weblate
1c4a2bc1c1 Weblate: Update frontend translations 2025-11-27 12:39:10 +01:00
Michael Mayer
78173c2b3f UX: Adjust styles for batch edit selection preview #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 12:37:30 +01:00
Weblate
78f51cc19b Weblate: Update frontend translations 2025-11-27 12:35:46 +01:00
Michael Mayer
25d0c7469a Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 12:11:51 +01:00
Michael Mayer
66599070f1 OIDC: Update README.md #5334
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 12:06:48 +01:00
Michael Mayer
6318c3ddc8 OIDC: Update README.md #5334
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 12:06:17 +01:00
Michael Mayer
6c50ee0ade OIDC: Merge groups, add inline code docs, and improve README.md #5334
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 12:02:57 +01:00
Michael Mayer
9d378f2041 OIDC: Update README.md #5334
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 11:52:54 +01:00
Michael Mayer
12e06fe7d3 Update .gitignore and .dockerignore files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 10:41:20 +01:00
Michael Mayer
c31ee5af8a CLI: Omit Hidden flag in documentation if it is false
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-27 10:12:34 +01:00
Michael Mayer
72b6f5cb2c Frontend: Update translation *.po files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-26 13:11:17 +01:00
Michael Mayer
53fa588457 UX: Fix whitespace in component/upload/dialog.vue
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-26 13:09:55 +01:00
Michael Mayer
87741e13d9 UX: Change order of feature flag toggles in Settings > General
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-26 13:05:29 +01:00
Michael Mayer
d8937c5921 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-26 12:28:57 +01:00
Michael Mayer
27f85c9491 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-26 12:28:42 +01:00
Michael Mayer
30013dd152 UX: Update translations for flag descriptions in Settings > General
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-26 12:24:35 +01:00
Weblate
ff2b81ef05 Weblate: Update frontend translations 2025-11-26 12:23:04 +01:00
Weblate
d9864fe946 Weblate: Update frontend translations 2025-11-26 12:18:25 +01:00
Weblate
78d18bbcc5 Weblate: Update frontend translations 2025-11-26 12:14:05 +01:00
Weblate
c2c211c14e Weblate: Update frontend translations 2025-11-26 12:12:18 +01:00
Weblate
b504b5902b Weblate: Update frontend translations 2025-11-26 12:09:29 +01:00
Michael Mayer
484f688685 Merge branch 'pr5339' into develop
# Conflicts:
#	frontend/src/locales/af.po
#	frontend/src/locales/ar.po
#	frontend/src/locales/be.po
#	frontend/src/locales/bg.po
#	frontend/src/locales/ca.po
#	frontend/src/locales/cs.po
#	frontend/src/locales/da.po
#	frontend/src/locales/de.po
#	frontend/src/locales/el.po
#	frontend/src/locales/es.po
#	frontend/src/locales/et.po
#	frontend/src/locales/eu.po
#	frontend/src/locales/fa.po
#	frontend/src/locales/fi.po
#	frontend/src/locales/fr.po
#	frontend/src/locales/ga.po
#	frontend/src/locales/he.po
#	frontend/src/locales/hi.po
#	frontend/src/locales/hr.po
#	frontend/src/locales/hu.po
#	frontend/src/locales/id.po
#	frontend/src/locales/it.po
#	frontend/src/locales/ja.po
#	frontend/src/locales/ko.po
#	frontend/src/locales/ku.po
#	frontend/src/locales/lt.po
#	frontend/src/locales/ms.po
#	frontend/src/locales/nb.po
#	frontend/src/locales/nl.po
#	frontend/src/locales/pl.po
#	frontend/src/locales/pt.po
#	frontend/src/locales/pt_BR.po
#	frontend/src/locales/ro.po
#	frontend/src/locales/ru.po
#	frontend/src/locales/sk.po
#	frontend/src/locales/sl.po
#	frontend/src/locales/sv.po
#	frontend/src/locales/th.po
#	frontend/src/locales/tr.po
#	frontend/src/locales/uk.po
#	frontend/src/locales/vi.po
#	frontend/src/locales/zh.po
#	frontend/src/locales/zh_TW.po
2025-11-26 11:57:04 +01:00
Michael Mayer
85cffcac06 Frontend: Update translation *.po files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-26 11:55:23 +01:00
Weblate
3fab21503c Weblate: Update frontend translations 2025-11-26 10:54:17 +00:00
Michael Mayer
261e722362 Merge branch 'pr5338' into develop
# Conflicts:
#	frontend/src/locales/af.po
#	frontend/src/locales/ar.po
#	frontend/src/locales/be.po
#	frontend/src/locales/bg.po
#	frontend/src/locales/ca.po
#	frontend/src/locales/cs.po
#	frontend/src/locales/da.po
#	frontend/src/locales/de.po
#	frontend/src/locales/el.po
#	frontend/src/locales/es.po
#	frontend/src/locales/et.po
#	frontend/src/locales/eu.po
#	frontend/src/locales/fa.po
#	frontend/src/locales/fi.po
#	frontend/src/locales/fr.po
#	frontend/src/locales/ga.po
#	frontend/src/locales/he.po
#	frontend/src/locales/hi.po
#	frontend/src/locales/hr.po
#	frontend/src/locales/hu.po
#	frontend/src/locales/id.po
#	frontend/src/locales/it.po
#	frontend/src/locales/ja.po
#	frontend/src/locales/ko.po
#	frontend/src/locales/ku.po
#	frontend/src/locales/lt.po
#	frontend/src/locales/ms.po
#	frontend/src/locales/nb.po
#	frontend/src/locales/nl.po
#	frontend/src/locales/pl.po
#	frontend/src/locales/pt.po
#	frontend/src/locales/pt_BR.po
#	frontend/src/locales/ro.po
#	frontend/src/locales/ru.po
#	frontend/src/locales/sk.po
#	frontend/src/locales/sl.po
#	frontend/src/locales/sv.po
#	frontend/src/locales/th.po
#	frontend/src/locales/tr.po
#	frontend/src/locales/uk.po
#	frontend/src/locales/vi.po
#	frontend/src/locales/zh.po
#	frontend/src/locales/zh_TW.po
2025-11-26 11:53:53 +01:00
Google Cloud Translation Basic
163193a5cf Translated using Weblate (Irish)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/ga/
2025-11-26 10:50:03 +00:00
DeepL
653713b14a Translated using Weblate (Vietnamese)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/vi/
2025-11-26 10:50:02 +00:00
Google Cloud Translation Basic
c1e7c87fe1 Translated using Weblate (Basque)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/eu/
2025-11-26 10:50:02 +00:00
Google Cloud Translation Basic
9609958556 Translated using Weblate (Belarusian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/be/
2025-11-26 10:50:02 +00:00
Google Cloud Translation Basic
f7f6850b72 Translated using Weblate (Afrikaans)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/af/
2025-11-26 10:50:02 +00:00
DeepL
7d1a086ad7 Translated using Weblate (Estonian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/et/
2025-11-26 10:50:02 +00:00
Google Cloud Translation Basic
12a045e103 Translated using Weblate (Persian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/fa/
2025-11-26 10:50:02 +00:00
DeepL
16811c998c Translated using Weblate (Slovenian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/sl/
2025-11-26 10:50:01 +00:00
DeepL
f4f55e1988 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/uk/
2025-11-26 10:50:01 +00:00
Google Cloud Translation Basic
6253561090 Translated using Weblate (Catalan)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/ca/
2025-11-26 10:50:01 +00:00
DeepL
77fd4b1641 Translated using Weblate (Finnish)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/fi/
2025-11-26 10:50:01 +00:00
DeepL
f1bae94fdf Translated using Weblate (Greek)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/el/
2025-11-26 10:50:01 +00:00
DeepL
e5369bc81b Translated using Weblate (Arabic)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/ar/
2025-11-26 10:50:01 +00:00
DeepL
8c6b034c24 Translated using Weblate (Thai)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/th/
2025-11-26 10:50:01 +00:00
Google Cloud Translation Basic
0e94c35ea2 Translated using Weblate (Malay)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/ms/
2025-11-26 10:50:01 +00:00
Google Cloud Translation Basic
8550fd83cc Translated using Weblate (Croatian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/hr/
2025-11-26 10:50:00 +00:00
DeepL
2748e902d6 Translated using Weblate (Lithuanian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/lt/
2025-11-26 10:50:00 +00:00
DeepL
07050ace41 Translated using Weblate (Swedish)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/sv/
2025-11-26 10:50:00 +00:00
DeepL
5223e54780 Translated using Weblate (Turkish)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/tr/
2025-11-26 10:50:00 +00:00
DeepL
dd182558bb Translated using Weblate (Bulgarian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/bg/
2025-11-26 10:50:00 +00:00
DeepL
75dc2b357a Translated using Weblate (Romanian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/ro/
2025-11-26 10:50:00 +00:00
Google Cloud Translation Basic
414add794c Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/zh_Hant/
2025-11-26 10:50:00 +00:00
DeepL
8e42a0788e Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/zh_Hans/
2025-11-26 10:49:59 +00:00
DeepL
dd3e9f2b4b Translated using Weblate (Slovak)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/sk/
2025-11-26 10:49:59 +00:00
DeepL
0cd83d5e1f Translated using Weblate (Russian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/ru/
2025-11-26 10:49:59 +00:00
DeepL
3c3cec29de Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/pt_BR/
2025-11-26 10:49:59 +00:00
DeepL
5e91226e83 Translated using Weblate (Portuguese)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/pt/
2025-11-26 10:49:59 +00:00
DeepL
7cc45d96e7 Translated using Weblate (Polish)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/pl/
2025-11-26 10:49:59 +00:00
DeepL
cd981f995b Translated using Weblate (Dutch)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/nl/
2025-11-26 10:49:59 +00:00
DeepL
fbfeeb0a83 Translated using Weblate (Norwegian Bokmål)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/nb_NO/
2025-11-26 10:49:58 +00:00
Google Cloud Translation Basic
924d64275c Translated using Weblate (Kurdish)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/ku/
2025-11-26 10:49:58 +00:00
DeepL
3baeafccd6 Translated using Weblate (Korean)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/ko/
2025-11-26 10:49:58 +00:00
DeepL
2f57a615a3 Translated using Weblate (Japanese)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/ja/
2025-11-26 10:49:58 +00:00
DeepL
1344214a85 Translated using Weblate (Italian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/it/
2025-11-26 10:49:58 +00:00
DeepL
efeb417ecf Translated using Weblate (Indonesian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/id/
2025-11-26 10:49:58 +00:00
DeepL
30dbc20218 Translated using Weblate (Hungarian)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/hu/
2025-11-26 10:49:58 +00:00
Google Cloud Translation Basic
28ec21a71c Translated using Weblate (Hindi)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/hi/
2025-11-26 10:49:57 +00:00
DeepL
ce37f007b1 Translated using Weblate (Hebrew)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/he/
2025-11-26 10:49:57 +00:00
DeepL
cbcdf420ca Translated using Weblate (French)
Currently translated at 98.8% (828 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/fr/
2025-11-26 10:49:57 +00:00
DeepL
5d74228442 Translated using Weblate (Spanish)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/es/
2025-11-26 10:49:57 +00:00
Admin
3a6f46dd30 Translated using Weblate (German)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/de/
2025-11-26 10:49:57 +00:00
DeepL
a54ba88946 Translated using Weblate (German)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/de/
2025-11-26 10:49:57 +00:00
DeepL
5e480c4ca4 Translated using Weblate (Danish)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/da/
2025-11-26 10:49:57 +00:00
DeepL
62a7d06ae8 Translated using Weblate (Czech)
Currently translated at 100.0% (838 of 838 strings)

Translation: PhotoPrism/Frontend
Translate-URL: https://translate.photoprism.app/projects/photoprism/frontend/cs/
2025-11-26 10:49:57 +00:00
Michael Mayer
969687cc74 UX: Improve feature flag descriptions in Settings > General
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-26 11:49:47 +01:00
Michael Mayer
1b1cc883ca UX: Improve feature flag descriptions in Settings > General
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-26 11:30:24 +01:00
Michael Mayer
7a354dc963 UX: Refactor batch edit Labels & Albums selector combobox #271 #5328
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 17:15:54 +01:00
Michael Mayer
76ed4787b4 Frontend: Remove "slider-color" from <v-tabs> after Vuetify upgrade
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 15:02:52 +01:00
Michael Mayer
d1ee51e8e1 Frontend: Fix navigation padding and colors after Vuetify upgrade
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 14:53:53 +01:00
Michael Mayer
ebed7fa5b4 Go: Replace strings.Split() with strings.SplitSeq() #5337
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 14:26:29 +01:00
Michael Mayer
590213572b Frontend: Fix tab slider color after Vuetify upgrade
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 13:31:28 +01:00
Michael Mayer
1631aecea6 Pkg: Add fs/README.md to document performance & security improvements
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 13:09:48 +01:00
Michael Mayer
897dfe7264 Docs: Clarify rules in AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 12:06:22 +01:00
graciousgrey
578edf6f28 AI: Improve vision readme 2025-11-25 11:37:39 +01:00
Michael Mayer
957383c708 API: Update swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 11:22:22 +01:00
Michael Mayer
ad197f5f91 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 11:22:06 +01:00
Michael Mayer
c3e9bcc088 Backend: Update go.mod, go.sum, and license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 11:21:43 +01:00
Michael Mayer
bbdc4a33f3 Vision: Update README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 11:08:20 +01:00
Michael Mayer
36d8b0e997 Vision: Update README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 11:05:46 +01:00
Michael Mayer
53503fe0b8 Vision: Update model.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 10:44:31 +01:00
Michael Mayer
1a12c96f0c Docs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 10:15:13 +01:00
Michael Mayer
ede42ecd5a Docs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-25 10:01:26 +01:00
Michael Mayer
64f73f156a Thumbs: Improve README.md and inline docs in vips_icc.go #5178
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-24 17:31:55 +01:00
graciousgrey
66926905fd Thumbs: Update README.md 2025-11-24 15:45:43 +01:00
Michael Mayer
536a91f261 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-24 14:44:38 +01:00
Michael Mayer
7be5131787 Frontend: Update translation .json files #5336
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-24 14:43:12 +01:00
Weblate
40b2ccfbbd Weblate: Update frontend translations 2025-11-24 14:42:21 +01:00
Michael Mayer
a02162846b AI: Improve model configuration and documentation #5123 #5232 #5322
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-24 14:41:13 +01:00
Michael Mayer
46b3a126f0 Docs: Update CODEMAP.md #5334
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-24 10:34:40 +01:00
Michael Mayer
3e66d9b4bd CI: Update the "dummy-webdav" and "dummy-oidc" images to 251124
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-24 10:34:15 +01:00
Michael Mayer
3d90ab1468 OIDC: Update internal/auth/oidc/README.md #5334
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 16:38:53 +01:00
Michael Mayer
cc94683533 OIDC: Update internal/auth/oidc/README.md #5334
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 16:33:11 +01:00
Michael Mayer
5f0ade87f5 OIDC: Add support for Microsoft Entra ID security groups #5334
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 16:04:25 +01:00
Michael Mayer
73fa8fb86f OIDC: Add internal/auth/oidc/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 15:23:12 +01:00
Michael Mayer
762901346e API: Regenerate swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 14:18:25 +01:00
Michael Mayer
3495493933 Backend: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 14:10:57 +01:00
Michael Mayer
38a1ef0c75 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 14:09:42 +01:00
Michael Mayer
5a5c99ee9c Backend: Update "github.com/prometheus/common" in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 14:09:12 +01:00
Michael Mayer
42d549853d Advanced Settings: Update frontend/src/locales/json/*.json #5310 #5332
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 14:06:53 +01:00
Weblate
e8d4770f41 Weblate: Update frontend translations 2025-11-23 14:05:46 +01:00
Michael Mayer
98f11964ff Advanced Settings: "Disable TensorFlow" -> "Disable Faces" #5310
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 14:01:11 +01:00
Michael Mayer
19f083c719 Thumbs: Enhance embedding of ICC profiles based on InteropIndex #5178
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 12:56:58 +01:00
Michael Mayer
ab2ba2e72a JPEG: Embed Adobe RGB ICC profile with an InteropIndex tag #5178
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 10:07:30 +01:00
Michael Mayer
6fabd096ee Batch Edit: Add mutex.BatchEdit to prevent concurrent edits #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 09:38:34 +01:00
Michael Mayer
7fbc0897c3 CI: Apply Go linter recommendations to entity.ManuallyAddedFaces() #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 08:51:31 +01:00
Michael Mayer
6630a5a07c CI: Apply Go linter recommendations to "internal/thumb/..." #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-23 08:47:17 +01:00
Michael Mayer
7c0f0b41ba CI: Apply Go linter recommendations to "internal/config" packages #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 20:00:53 +01:00
Michael Mayer
57c9096d1f CI: Apply Go linter recommendations to "internal/service" packages #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 17:57:25 +01:00
Michael Mayer
699ad5b50c CI: Apply Go linter recommendations to "internal/commands" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 17:55:26 +01:00
Michael Mayer
0e6328a33d Tests: Add pkg/capture/capture_test.go #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 16:23:47 +01:00
Michael Mayer
ed96f381b9 Media: Improve ReadUrl() implementation and tests #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 16:23:13 +01:00
Michael Mayer
149f5e5731 CI: Apply Go linter recommendations to remaining "pkg/..." code #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 16:14:43 +01:00
Michael Mayer
90ab65a9b0 Zip: Harden fs.Unzip() implementation in pkg/fs #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 14:32:23 +01:00
Michael Mayer
4d280e82e2 CI: Update CODEMAP.md #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 14:13:59 +01:00
Michael Mayer
889de682c4 CI: Apply Go linter recommendations to "internal/event" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 14:10:56 +01:00
Michael Mayer
9334a9a201 CI: Apply Go linter recommendations to "photoprism" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 14:02:40 +01:00
Michael Mayer
c80cf0779f Tests: Update mediafile_heic_test.go after fix in "internal/meta" #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 13:12:38 +01:00
Michael Mayer
e693fd668f CI: Apply Go linter recommendations to "internal/server" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 13:09:32 +01:00
Michael Mayer
43bca10b4e CI: Apply Go linter recommendations to "internal/ffmpeg" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 12:58:11 +01:00
Michael Mayer
153ebd5905 Docs: Update photoprism/dl/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 12:52:15 +01:00
Michael Mayer
2a00122dd1 Docs: Add photoprism/dl/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 12:51:47 +01:00
Michael Mayer
162b383f31 Docs: Add internal/meta/README.md to document the "meta" package
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 12:48:58 +01:00
Michael Mayer
10d6ca36b7 CI: Apply Go linter recommendations to "internal/meta" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 12:38:24 +01:00
Michael Mayer
7391066fb0 CI: Apply Go linter recommendations to "internal/form" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 12:09:21 +01:00
Michael Mayer
c909c0bd5a CI: Apply Go linter recommendations to "thumb" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 11:55:19 +01:00
Michael Mayer
75bc6d754c CI: Apply Go linter recommendations to "ai/tensorflow" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 11:47:17 +01:00
Michael Mayer
b954de52e9 CI: Apply Go more linter recommendations to "ai/face" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 11:38:45 +01:00
Michael Mayer
59c8754ca3 CI: Apply Go more linter recommendations to "ai/nsfw" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 11:33:28 +01:00
Michael Mayer
780a870f5c CI: Apply Go more linter recommendations to "ai/classify" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 11:30:58 +01:00
Michael Mayer
4682791253 CI: Apply Go linter recommendations to "ai/classify" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 11:19:30 +01:00
Michael Mayer
53da18754b CI: Apply Go linter recommendations to "ai/vision" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 11:15:17 +01:00
Michael Mayer
2002d39bfc Batch: Apply Go linter recommendations #271 #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 10:51:35 +01:00
Michael Mayer
cca86c08c7 Batch: Perform priority comparison after resolving the PhotoLabel #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 10:31:50 +01:00
Michael Mayer
6e0416db34 Backend: Apply linter recommendations to "backup" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 10:22:52 +01:00
Michael Mayer
24e29a89ff Backend: Apply linter recommendations to "photoprism/dl" package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 10:22:05 +01:00
Michael Mayer
cc651a84d0 Workers: Apply "golangci-lint" recommendations #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 10:22:05 +01:00
graciousgrey
01c8dd0a10 Tests: Add more test cases #271 2025-11-22 10:19:15 +01:00
Michael Mayer
4eac10c9d1 API: Apply "golangci-lint" recommendations #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 09:25:01 +01:00
Michael Mayer
264bc78d51 Backend: Remove legacy Go build tags #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-22 09:24:28 +01:00
Michael Mayer
d023139c12 TestMain: Handle "defer" before os.Exit #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 18:58:36 +01:00
Michael Mayer
6c50a87632 Auth: Apply "golangci-lint" recommendations #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 16:22:42 +01:00
Michael Mayer
52ab802731 Pkg: Apply "golangci-lint" recommendations to txt/... packages #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 16:16:42 +01:00
Michael Mayer
7cb639da89 Pkg: Apply "golangci-lint" recommendations to rnd package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 15:40:26 +01:00
Michael Mayer
5e4e6d988c Pkg: Apply "golangci-lint" recommendations to authn & dsn packages #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 15:33:23 +01:00
Michael Mayer
23529d0472 Pkg: Apply "golangci-lint" recommendation to clean package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 15:28:04 +01:00
Michael Mayer
9d86b2a512 Settings: Use PHOTOPRISM_DISABLE_FEATURES to initialize default features
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 15:19:15 +01:00
Michael Mayer
82b0ecea65 Config: Apply "golangci-lint" recommendation to customize package #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 14:16:03 +01:00
Michael Mayer
b2448e5be0 CI: Upgrade base image from 251113-questing to 251121-questing #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 14:07:46 +01:00
Michael Mayer
ce92f56900 Batch: Update internal/photoprism/batch/README.md #271 #5324
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 13:57:17 +01:00
Michael Mayer
46d53d63f8 Dockerfiles: Add "binutils" and "binutils-gold" packages #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 13:36:29 +01:00
Michael Mayer
82e94efbbb Backend: Update "golang.org/x/crypto" in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 13:04:28 +01:00
Michael Mayer
41256b47c8 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 13:04:08 +01:00
Michael Mayer
0c39c7334b Weblate: Update frontend/src/locales/json/fr.json #5329
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 13:03:38 +01:00
Weblate
89f45766b8 Weblate: Update frontend translations 2025-11-21 13:02:02 +01:00
Michael Mayer
41cb9dc55a CI: Add ./.../internal/... to fmt-go and test-go Make targets #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 13:01:20 +01:00
Michael Mayer
be7c1f9607 Batch: Improve test label cleanup in apply_labels_test.go #271 #5324
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 12:30:48 +01:00
Michael Mayer
7fedc4603e Batch: Improve test fixture handling in apply_labels_test.go #271 #5324
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 12:15:59 +01:00
Michael Mayer
54106a5791 CI: Document "make lint", "make lint-go", & "make lint-js" targets #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 10:42:21 +01:00
Michael Mayer
f4858212d1 Services: Resolve issues in node/bootstrap.go and options_apply.go #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 10:30:19 +01:00
Michael Mayer
83c644df68 Scripts: Update dist/install-go-tools.sh #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 10:29:06 +01:00
Michael Mayer
5c8a6d93f6 CI: Add revive.toml & "make lint-go" target, improve .golangci.yml #5330
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 10:28:43 +01:00
Michael Mayer
f0607ac64c Entity: Fix code comments in auth_user.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 08:56:55 +01:00
Michael Mayer
8fc9f807de Develop: Add .golangci.yml and update install-go-tools.sh script
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-21 08:56:25 +01:00
Michael Mayer
b45abbd0cd Config: Fix fallback that loads defaults from config/defaults.yml #5325
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-20 18:42:06 +01:00
Michael Mayer
2e85caa6b0 Batch: Update YAML file backups for all referenced albums #271 #5324
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-20 17:36:33 +01:00
Michael Mayer
117c8db73b Batch: Pre-create new albums/labels to improve performance #271 #5324
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-20 16:56:14 +01:00
Michael Mayer
ad2470ca04 Batch: Add helpful Items receivers to values_item.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-20 16:20:17 +01:00
Michael Mayer
fa3aba1667 Batch: Keep existing label with higher priority in apply_labels.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-20 15:49:13 +01:00
Michael Mayer
c573f0975e Batch: Refine code and add table-driven tests for label removal action
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-20 15:42:42 +01:00
Michael Mayer
5b23f306d3 Batch: Reformat internal/photoprism/batch.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-20 15:22:47 +01:00
Michael Mayer
51a6380e44 Upload: Update album YAML backups when photos have been added
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-20 14:39:06 +01:00
Michael Mayer
1a9e795dad Batch Edit: Refine styles and settings for location input #271 #5324
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-20 13:05:27 +01:00
Michael Mayer
19b8b6363c Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-19 14:39:44 +01:00
Michael Mayer
30c0e8c4e7 Downloads: Improve playlist error handling in "internal/photoprism/dl"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-19 14:39:00 +01:00
Michael Mayer
2687242098 Frontend: Update deps in package.json and package-lock.json #271 #5324
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-19 14:35:23 +01:00
Michael Mayer
606c877349 Batch Edit: Regenerate frontend translation .json files #271 #5324 #5327
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-19 14:34:03 +01:00
Michael Mayer
ea6f98fc3e Batch Edit: Disable API endpoint if feature is disabled #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-19 14:31:19 +01:00
graciousgrey
b67efd9cd3 Tests: Adapt acceptance tests to run more stable 2025-11-19 14:29:36 +01:00
graciousgrey
cb20f771bb Tests: Adapt acceptance test targets to work with latest chrome 2025-11-19 14:29:36 +01:00
Weblate
8d44b82664 Weblate: Update frontend translations 2025-11-19 14:00:26 +01:00
Michael Mayer
c20426c839 Assets: Regenerate locales/el/default.po
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-19 11:25:53 +01:00
Michael Mayer
9c6d3e2903 Batch Edit: Update frontend translations .pot and .po files #271 #5324
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-19 11:25:35 +01:00
Weblate
d32751300a Weblate: Update backend translations 2025-11-19 11:23:52 +01:00
Ömer Duran
1e00d1f52e
UX: Add batch edit dialog and API endpoints #271 #5324
Signed-off-by: Michael Mayer <michael@photoprism.app>
Co-authored-by: Michael Mayer <michael@photoprism.app>
Co-authored-by: graciousgrey <theresagresch@gmail.com>
2025-11-19 11:20:34 +01:00
Michael Mayer
18806935fd Config: Disable AuthSecret in options.go (currently unused)
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-16 11:17:07 +01:00
Michael Mayer
4a0f9bfa7a AI: Update face flag notes in internal/config/report_sections.go #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-16 10:57:45 +01:00
Michael Mayer
6438b70d70 Config: Improve documentation in internal/config/README.md #5325
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-16 10:10:48 +01:00
Michael Mayer
315b49c1e6 Config: Add fallback to load defaults from "config/defaults.yml" #5325
Config.DefaultsYaml() resolves the default options YAML file. When
PHOTOPRISM_DEFAULTS_YAML points to a readable file it will be used;
otherwise it falls back to `defaults.{yml,yaml}` inside the active
config directory.

This allows instances without `/etc/photoprism/defaults.yml` to
still load local defaults, e.g., in containerized environments.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-16 09:06:12 +01:00
Michael Mayer
217c5a44e3 Watchtower: Use nickfedor/watchtower instead of containrrr/watchtower
Required or compatibility with Docker 29.0.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-15 16:07:34 +01:00
Michael Mayer
d1991b19c3 Docs: Update internal/config/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-15 15:21:46 +01:00
Michael Mayer
b8d9b0de0e Docs: Update internal/config/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-15 15:14:30 +01:00
Michael Mayer
5bbd129b91 Docs: Update internal/config/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-15 15:13:40 +01:00
Michael Mayer
fcdaf9f6f3 Docs: Add internal/config/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-15 15:06:30 +01:00
Weblate
4e07996518 Weblate: Update frontend translations 2025-11-15 07:09:40 +01:00
Michael Mayer
6e82481944 OIDC: Ensure ID tokens fit into the auth_sessions.id_token column #5294
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-14 17:02:17 +01:00
Michael Mayer
d89ac51159 AI: Update internal/ai/vision/ollama/README.md #5123 #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-14 15:22:54 +01:00
Michael Mayer
74ddb46968 AI: Read Qwen3-VL Ollama model response from Thinking field #5123 #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-14 15:11:24 +01:00
Michael Mayer
ccee474a80 AI: Add schema/README.md as labels schema reference #5322 #5123 #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-14 14:22:48 +01:00
Michael Mayer
ae63c05baf AI: Link engine docs in AGENTS.md and CODEMAP.md files #5322 #5123 #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-14 14:16:38 +01:00
Michael Mayer
5340480b32 AI: Add internal/ai/vision/ollama/README.md #5322 #5123 #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-14 14:11:26 +01:00
Michael Mayer
ac3963f44f AI: Restructure documentation in internal/ai/vision/README.md #5322
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-14 13:43:37 +01:00
Michael Mayer
bd33500cf4 AI: Update documentation link in internal/ai/vision/README.md #5322
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-14 12:12:17 +01:00
Michael Mayer
0cf194b3ff AI: Update internal/api/swagger.json #5322
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-14 12:06:19 +01:00
Michael Mayer
d35dd08dea AI: Set OpenAI API service key via OPENAI_API_KEY(_FILE) variable #5322
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-14 12:04:44 +01:00
Michael Mayer
3aa3c504e7 AI: Added test coverage for the Ollama transport helpers #5322
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-14 11:20:26 +01:00
Michael Mayer
d76acdb69f AI: Generate Captions & Labels using the OpenAI Responses API #5322
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-14 11:10:40 +01:00
Ömer Duran
46d5e33c8c
Tests: Enhance Vitest setup and add PLightbox component tests (#5320) 2025-11-13 09:47:43 +01:00
Michael Mayer
e8a97b0438 OIDC: Only start Keycloak with the "all", "auth", or "keycloak" profiles
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-13 09:24:23 +01:00
Michael Mayer
23a0210ef4 Develop: Upgrade base image from 251018-questing to 251113-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-13 09:23:16 +01:00
promalert
5d0aa1068c refactor: use b.Loop() to simplify the code and improve performance
Signed-off-by: promalert <promalert@outlook.com>
2025-11-13 08:54:42 +01:00
Michael Mayer
a8f4286100 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-12 17:40:13 +01:00
Michael Mayer
b39da9459d Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-12 17:39:54 +01:00
Michael Mayer
1749bd9478 Backend: Regenerate assets/locales/el/default.po
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-12 17:39:37 +01:00
Michael Mayer
09a149e8a2 Frontend: Update line numbers if src/locales/*.po and translations.pot
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-12 17:39:07 +01:00
Michael Mayer
7e6e1e6379 Frontend: Update code examples in src/common/README.md #5145 #5307 #5313
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-12 12:39:50 +01:00
Michael Mayer
efb720c152 Dialogs: Listen to @keydown.esc.exact and update src/common/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-12 12:13:39 +01:00
Michael Mayer
c039972d6a Frontend: Add "Keyboard Event Handling" section to src/common/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-12 10:02:23 +01:00
Michael Mayer
b8bdd707d6 Frontend: Update src/locales/json/el.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-12 08:58:10 +01:00
Weblate
0c56943bd7 Weblate: Update backend translations 2025-11-12 08:41:10 +01:00
Michael Mayer
86d56454cd UX: Add afterEnter/afterLeave handlers to merge dialog #5145 #5307 #5313
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-12 08:40:14 +01:00
Weblate
3916b503e6 Weblate: Update frontend translations 2025-11-12 08:33:24 +01:00
Ömer Duran
df82ad124f Frontend: Add focus management and view hooks to location dialog #5313 2025-11-12 08:33:06 +01:00
Michael Mayer
0452663717 UX: Refactor findFocusElement() & resolveFocusTarget() #5145 #5307 #5313
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-11 10:51:13 +01:00
Michael Mayer
17faa4900f UX: Update frontend/src/common/README.md #5145 #5307 #5313
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-11 10:01:40 +01:00
Michael Mayer
f3fe93b73c UX: Update frontend/src/common/README.md #5145 #5307 #5313
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-11 05:29:12 +01:00
Michael Mayer
05e4fdf67c UX: Remove custom focus traps in dialog components #5145 #5307
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-11 04:05:09 +01:00
Michael Mayer
9a8621dfc2 UX: Disable "openOnClick" for name menu props #5145 #5307
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-11 03:42:55 +01:00
Michael Mayer
d391f834b1 Docs: Add "Frontend Focus Management" to Repository Guidelines
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-11 03:26:54 +01:00
Michael Mayer
326de57fd8 UX: Don't prevent focus from leaving to .v-overlay.v-menu #5145 #5307
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-11 03:16:28 +01:00
Michael Mayer
acaaf91fdb UX: Add frontend/src/common/README.md #5145 #5307
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-11 02:30:53 +01:00
Michael Mayer
31450eed1a UX: Add automatic focus trap for dialogs to common/view.js #5145 #5307
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-11 02:10:47 +01:00
Michael Mayer
cd9d33eda0 UX: Refactor "tabindex" to improve navigation and autofocus #5145 #5307
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-10 22:19:02 +01:00
Michael Mayer
b46cb4d03f Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-10 16:26:22 +01:00
Michael Mayer
c7cbfc11a1 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-10 16:25:44 +01:00
Ömer Duran
2cc186074a
UX: Improve people name editing and confirm dialog focus management (#5307)
* Frontend: Improve people name editing and confirmation UX

Adds better menu control and confirmation dialog handling for editing people names in photo edit and new people pages. Ensures only one menu is open at a time, improves keyboard accessibility, and prevents conflicting confirmation dialogs. Also updates event handling and emits for dialog and people components.

* Frotend: clear model fields on cancel in people dialogs #5145

* Frontend: Enable menu opening on click in people edit and new pages #5145

* Frontend: Enhance confirmation dialog with improved keyboard accessibility #5145

* Frontend: Refactor name confirmation handling in people edit and new pages #5145

* Frontend: Update name setting logic in people edit and new pages #5145

* People: Adjust menuProps and add focus trap to PConfirmDialog #5307

Signed-off-by: Michael Mayer <michael@photoprism.app>

---------

Signed-off-by: Michael Mayer <michael@photoprism.app>
Co-authored-by: Michael Mayer <michael@photoprism.app>
2025-11-10 16:21:03 +01:00
Michael Mayer
70821fb7d0 CSS: Change single to double quotes in root.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-10 13:12:58 +01:00
Michael Mayer
9661742972 CSS: Use variables to define app fonts, refactor text and splash styles
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-10 13:05:55 +01:00
graciousgrey
7989b88299 Tests: Update test name 2025-11-10 10:33:19 +01:00
graciousgrey
7cc9d4147e Search: Improve inline comments and annotations 2025-11-07 16:42:55 +01:00
Michael Mayer
d5b0b18411 Config: Add deprecation note to DISABLE_TENSORFLOW in flags.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-07 08:56:39 +01:00
Michael Mayer
c50c744d45 Config: Shorten disable-tensorflow usage description in flags.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-06 18:17:45 +01:00
Michael Mayer
d166320ef9 Config: Improve disable-tensorflow usage description in flags.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-06 18:12:55 +01:00
Keith Martin
6d0016b1df
Frontend: Improve acceptance test performance #5298
* Tests: improve openNav, and add ability to close all event notifications.
* Tests: improve search with wait for notifications to expire, then using notifications to determine search completion.
* Tests: improve getPhotoCount by using notifications for completion of photo load.  Add fast and slow photo load waits.
* Tests: add fast and slow load detection via notifications
* Tests: replace waits with notification detection
* Tests: refactor tests to work more efficiently with notifications
* Tests: comment out execution time and p-notify__close logging.  Remove slow version of waits.
* Make: allow acceptance tests to be run with --ignore-errors, and make each multi window test run as separate instance
* Frontend: ensure that closing a notification resets the timer for the next notification
* Tests: move notification handling to single notifications.js file
* Tests: move photoCount as changing cards view doesn't generate event when there is one photo
* Tests: remove commented code
* Tests: enable environment variable SHOW_LOGS  (true) to show timings and click actions for waits
* Tests: add Delete, Import, Index, Unstack, and Upload notification waits.
2025-11-04 11:29:37 +01:00
Michael Mayer
5afb634edf Scripts: Update install-proxysql-admin.sh and install-devops-tools.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-04 11:24:30 +01:00
Michael Mayer
3290c9062c Scripts: Update install-proxysql-admin.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-04 11:03:47 +01:00
Michael Mayer
e4544046b3 Scripts: Update dist/install-devops-tools.sh & install-proxysql-admin.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-04 10:51:35 +01:00
Michael Mayer
facda060cb Scripts: Update dist/install-devops-tools.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-04 10:30:18 +01:00
Michael Mayer
fed83ca3d6 Frontend: Update src/locales/json/fr.json #5305
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-04 10:02:02 +01:00
Weblate
3124f41d6e Weblate: Update frontend translations 2025-11-04 09:54:02 +01:00
Michael Mayer
e5315f0f06 Scripts: Improve dist/install-proxysql-admin.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-04 09:26:44 +01:00
Michael Mayer
28ad040402 Scripts: Update install-devops-tools.sh, add install-proxysql-admin.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-04 08:57:28 +01:00
Michael Mayer
06df64281d Config: Move database DSN-related functionality to "pkg/dsn" #47 #5285
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-03 13:40:34 +01:00
Michael Mayer
40097b6285 Config: Improve database host and port parsing #47 #5285
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-03 11:41:18 +01:00
Michael Mayer
c1abbeead3 Config: Refactor DSN parser struct #47 #5285
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-03 10:32:07 +01:00
Michael Mayer
8a2373ec8c Config: Add DSN parsing for PostgreSQL #47 #5285
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-03 09:46:48 +01:00
Michael Mayer
656a7dcab3 Config: Auto-add required DSN params, mask passwords in reports #5285
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-03 09:12:45 +01:00
Michael Mayer
c67a36d311 Scripts: Update dist/install-devops-tools.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-02 21:04:25 +01:00
Michael Mayer
fbdef6ca33 Scripts: Add dist/install-devops-tools.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-02 20:26:02 +01:00
Michael Mayer
aef24bb29a Cluster: Add config option to sync and drop ProxySQL user accounts #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-02 19:34:57 +01:00
Michael Mayer
d6a41e5032 Config: Add environment variable to disable the database version check
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-02 16:49:35 +01:00
Michael Mayer
2554e0189c Docs: Add shellcheck rule for script development
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-02 15:50:22 +01:00
Michael Mayer
bbee0993e0 Pkg: Use ProjectRoot variable in path_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-02 11:56:43 +01:00
Michael Mayer
3874bc5422 Config: Enhance tests for configuration and database file names #5304
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-02 11:49:00 +01:00
Michael Mayer
d6f0e808eb Config: Support YAML filenames with alternative extensions #5304
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-02 11:33:40 +01:00
Michael Mayer
50e77e3a9d Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-01 12:07:08 +01:00
Michael Mayer
5a64253a69 Translations: Update frontend/src/locales/json/*.json #5302
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-01 12:06:28 +01:00
Weblate
ee18897ea9 Weblate: Update frontend translations 2025-11-01 12:05:36 +01:00
Michael Mayer
761de55046 Translations: Change "No server connection" to "Lost server connection"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-01 12:01:50 +01:00
Michael Mayer
50157f9559 Lightbox: Hide captions when playing videos in slideshows
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-11-01 11:47:48 +01:00
Michael Mayer
f3996494dd Cluster: Allow configuration of database and user prefix #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-31 21:30:42 +01:00
Michael Mayer
c6c501c555 Update license NOTICE files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-31 18:28:34 +01:00
Michael Mayer
18e98d3a87 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-31 18:21:08 +01:00
Michael Mayer
e35d28f333 Backend: Update deps go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-31 18:20:36 +01:00
Michael Mayer
82f5c5f818 Cluster: Change "photoprism_" database / user prefix to "cluster_" #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-31 18:18:18 +01:00
Michael Mayer
755ebe0aee Cluster: Rename RoleInstance to RoleApp in service/cluster/roles.go #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-31 16:46:42 +01:00
Michael Mayer
ef1f0f3bb2 AI: Enhance "GET /api/v1/metrics" endpoint with additional stats #213
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-31 15:38:10 +01:00
Michael Mayer
0a1b5071fd AI: Allow users to use a custom source for TensorFlow labels #5011 #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-30 12:40:03 +01:00
Michael Mayer
46b219770a AI: Allow users to disable default models through their vision.yml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-30 12:04:50 +01:00
Michael Mayer
4fe1bc0f9a API: Improve Swagger annotations and update swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-30 11:50:31 +01:00
Michael Mayer
f2eebe2912 API: Improve Swagger annotations and update swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-30 11:47:40 +01:00
Michael Mayer
5ea9f3bc4e API: Improve Swagger annotations and update swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-30 11:41:33 +01:00
Michael Mayer
bfee1918c1 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-30 11:30:09 +01:00
Michael Mayer
412b629764 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-30 11:29:12 +01:00
Michael Mayer
6552aa3bc2 Frontend: Add Util.openExternalUrl() with noopener/noreferrer safeguards
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-30 11:18:04 +01:00
Michael Mayer
5ad391068d API: Add missing Swagger annotations and update swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-30 11:00:16 +01:00
Michael Mayer
3a0eaebb82 Config: Disable image classification independently of TensorFlow #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-30 10:41:20 +01:00
Michael Mayer
42edf100ee Vision: Allow use of configured service key for API authentication #5299
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-30 10:02:16 +01:00
Michael Mayer
5365e214ad Cluster: Shorten log messages in node/bootstrap.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-29 20:14:01 +01:00
Michael Mayer
fb79e58468 AI: Adjust face recognition config defaults #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-29 17:24:11 +01:00
Michael Mayer
38770b6892 AI: Fix and improve label normalization in vision package #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-29 17:21:12 +01:00
Michael Mayer
630506e021 Auth: Remove redundant preview/download token wiring for JWT #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-29 15:21:49 +01:00
Michael Mayer
6e43f14476 Auth: Adjust JWT default scope and ACL, add tests #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-29 14:28:26 +01:00
Michael Mayer
e1e673be7f API: Refactor "GET /api/v1/config" endpoint for JWT sessions #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-29 12:29:12 +01:00
Michael Mayer
99cf43261d Frontend: Make sure admins can see usage info in navigation.vue
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-29 11:06:08 +01:00
Michael Mayer
91c7052c1f Docs: Update CODEMAP.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-29 10:51:41 +01:00
Michael Mayer
e93ceba659 Auth: Enhance JWT session creation and token IDs #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-29 10:23:44 +01:00
Michael Mayer
30c584559c Auth: Improve readability of clientRole() in entity/auth_session.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-29 08:09:09 +01:00
Michael Mayer
f696f0325e Auth: Improve readability of entity/auth_client.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-29 07:39:20 +01:00
Michael Mayer
1408e99135 Auth: Fix client role lookup in auth_session.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-28 19:34:55 +01:00
Michael Mayer
b988ba046c API: Add debug logs to api_auth_jwt.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-28 16:22:18 +01:00
Michael Mayer
7b05f55211 Config: Add DefaultJWTAllowedScopes variable to config_cluster.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-28 14:58:32 +01:00
Michael Mayer
d0555a3fd7 Docs: Update CODEMAP.md and AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-28 14:44:11 +01:00
Michael Mayer
03086682c3 Config: Add tests to config_cluster_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-28 14:31:23 +01:00
Michael Mayer
8090e49d1a Config: Add comment in config_cluster.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-28 14:24:27 +01:00
Michael Mayer
22bd999e91 Config: Improve handling of secret files in config_cluster.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-28 14:13:35 +01:00
Michael Mayer
7f5803554e Config: Improve documentation of AdvertiseUrl()
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-28 13:19:07 +01:00
Michael Mayer
dac96b5051 API: Adjust advertise URL validation in cluster_nodes_register.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-28 13:08:52 +01:00
Michael Mayer
d01601d1e8 Config: Improve logging in config_cluster.go #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-27 19:18:16 +01:00
Michael Mayer
0f68b65da6 Config: Add authentication logs to cluster/node/bootstrap.go #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-27 19:06:49 +01:00
Michael Mayer
0140b1e07f Config: Allow to ParseDatabaseDSN if driver is not SQLite #5285
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-27 18:36:16 +01:00
Michael Mayer
ceab5e619d Config: Add register fallback to cluster/node/bootstrap.go #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-27 17:50:50 +01:00
Michael Mayer
0d1eedb9a5 Config: Remove caching from NodeClientSecret() #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-27 16:59:23 +01:00
Michael Mayer
4a182599b8 Cluster: Fix Config.NodeClientSecret() #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-27 16:51:07 +01:00
Michael Mayer
107888a8da Cluster: Improve theme installation and startup logs #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-27 16:20:26 +01:00
Michael Mayer
714fdef5b9 Frontend: Update src/page/settings.vue
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-27 14:09:45 +01:00
Michael Mayer
5f9b90bba8 Cluster: Shorten error log messages in cluster_nodes_register.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 15:49:44 +01:00
Michael Mayer
d19bf02233 Cluster: Use creds.Driver instead of provisioner.DatabaseDriver
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 15:02:28 +01:00
Michael Mayer
04aaf514b1 Cluster: Persist database credentials in cluster_nodes_register.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 14:48:04 +01:00
Keith Martin
b644be320f
Tests: add Too many requests handling capability by default into page.login, add rate limiting test (#5293) 2025-10-26 13:56:51 +01:00
Michael Mayer
70b8867b6d AI: Reduce face.MatchDist from 0.43 to 0.42 #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 13:33:17 +01:00
Michael Mayer
544dd55263 AI: Reduce face.MatchDist from 0.46 to 0.43 #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 12:52:42 +01:00
Michael Mayer
31b00cbe1c Faces: Use ClusterRadius as default in background.go and children.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 11:42:55 +01:00
Michael Mayer
dd8698c938 Cluster: Shorten log message in node/bootstrap.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 11:34:22 +01:00
Michael Mayer
e8f0e45890 AI: Remove legacy PHOTOPRISM_FACE_ variables from face/config.go #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 10:53:58 +01:00
Michael Mayer
1a37a01897 Backend: Update github.com/yalue/onnxruntime_go in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 10:44:14 +01:00
Michael Mayer
9508fbf934 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 10:43:40 +01:00
Michael Mayer
64a29d4a5c AI: Add face matching config options #5167
This commit adds the following new config options:
- FaceClusterRadius
- FaceCollisionDist
- FaceEpsilonDist
- FaceMatchChildren
- FaceMatchBackground

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 10:40:08 +01:00
Michael Mayer
72a9a53426 AI: Rename SampleRadius to ClusterRadius and increase cap to 0.42 #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 10:08:59 +01:00
Michael Mayer
c53ac3353b AI: Add face.CollisionDist variable for face comparison #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 09:50:25 +01:00
graciousgrey
100883ea9a Update SPONSORS.md 2025-10-26 09:15:49 +01:00
Michael Mayer
3236a32a2b AI: Refactor face package configuration and reporting #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-26 09:02:11 +01:00
Michael Mayer
f94219404e CLI: Improve output of "photoprism config" command #5285
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-24 13:51:19 +02:00
Michael Mayer
5ad8a06a44 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-24 10:01:57 +02:00
Michael Mayer
e072e5bd85 Frontend: Update translations #5291
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-24 10:01:14 +02:00
Weblate
f35af9725a Weblate: Update frontend translations 2025-10-24 09:59:35 +02:00
Ömer Duran
d333bd2d2c
UX: Improve behavior of dropdowns in the Add to Album and Upload dialogs #5177 #5290 2025-10-24 09:55:18 +02:00
graciousgey
212869679c Tests: Adapt acceptance tests 2025-10-24 09:11:22 +02:00
Michael Mayer
b91a7380ea Media: Associate ".mp.jpg" and ".mp.jpeg" files with ImageJpeg #5289
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 18:23:24 +02:00
Michael Mayer
f2313b8dfe Cluster: Shortened log message in node/bootstrap.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 14:09:22 +02:00
Michael Mayer
3f16de1e97 Server: Improve stability of WebDAV write tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 13:33:15 +02:00
Michael Mayer
eb5ac014c2 Config: Adjust default face SizeThreshold and ClusterSizeThreshold #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 13:14:07 +02:00
Michael Mayer
a611f9eaa0 Config: Normalize DSN in DatabaseDriver() method #5279
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 11:06:27 +02:00
Michael Mayer
357c19a379 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 10:53:28 +02:00
Michael Mayer
c91adadb3b Frontend: Update styles in text.css and vuetify.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 10:53:12 +02:00
Michael Mayer
b64c04df40 Frontend: Update src/locales.js, regenerate .po and .json files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 10:52:47 +02:00
Weblate
49b2e7d4e0 Weblate: Update frontend translations 2025-10-23 10:40:49 +02:00
Michael Mayer
22ed81a65d Frontend: Update src/locales.js and regenerate locales/*.po
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 10:19:11 +02:00
Michael Mayer
75ed91a9a4 Frontend: Update src/locales/json/fr.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 09:52:47 +02:00
Michael Mayer
f901759834 Translations: Regenerate frontend and backend *.po files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 09:51:31 +02:00
Michael Mayer
dd2ada0651 Frontend: Remove "#, fuzzy" from translations in src/locales/fr.po
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 09:49:27 +02:00
Weblate
7b97a5d43f Weblate: Update frontend translations 2025-10-23 09:28:43 +02:00
Michael Mayer
0858a2b65f Auth: Add "photoprism show scopes" command to list all supported scopes
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 09:25:08 +02:00
Michael Mayer
6609e9c998 CLI: Refactor authentication subcommand flags
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-23 09:04:30 +02:00
Michael Mayer
9514542d44 Auth: Extend user accounts with custom scope setting
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-22 19:58:56 +02:00
Weblate
c5312d6eda Weblate: Update backend translations 2025-10-22 10:26:26 +02:00
Michael Mayer
dca68e653a Frontend: Update src/locales/json/*.json translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-22 10:08:59 +02:00
Weblate
75bb3bebbe Weblate: Update frontend translations 2025-10-22 10:07:58 +02:00
Michael Mayer
ab3d8478dd Merge remote-tracking branch 'photoprismci/weblate-photoprism-frontend' into develop
# Conflicts:
#	frontend/src/locales/af.po
#	frontend/src/locales/be.po
#	frontend/src/locales/ca.po
#	frontend/src/locales/eu.po
#	frontend/src/locales/fa.po
#	frontend/src/locales/fr.po
#	frontend/src/locales/ga.po
#	frontend/src/locales/he.po
#	frontend/src/locales/hi.po
#	frontend/src/locales/hr.po
#	frontend/src/locales/ku.po
#	frontend/src/locales/ms.po
#	frontend/src/locales/th.po
#	frontend/src/locales/vi.po
#	frontend/src/locales/zh_TW.po
2025-10-22 10:01:00 +02:00
Michael Mayer
0d196ad5dc Frontend: Update src/locales/*.po and translations.pot
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-22 09:55:49 +02:00
Michael Mayer
1148a56bc3 Revert "Frontend: Update translations.pot"
This reverts commit 504d92efaa.
2025-10-22 09:51:50 +02:00
Weblate
76aa3eb11c Weblate: Update frontend translations 2025-10-22 07:51:28 +00:00
Michael Mayer
f9a2e54476 Frontend: Disable msgmerge fuzzy matching with vue3-gettext
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-22 09:51:13 +02:00
Michael Mayer
504d92efaa Frontend: Update translations.pot
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-22 09:07:35 +02:00
Michael Mayer
5e58e51f79 Frontend: Add SeverityPalette to model/logs.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-22 08:49:29 +02:00
Michael Mayer
a2dfdc24b6 Frontend: Correct log levels in logs.js and update tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-22 08:18:18 +02:00
Michael Mayer
55da70e955 Config: Add system warning log when DatabaseDsn is used #5279
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-22 08:16:49 +02:00
Michael Mayer
5606366d86 Backend: Update github.com/golang/geo in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-21 17:43:28 +02:00
Michael Mayer
572ddae06d Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-21 17:42:26 +02:00
Michael Mayer
dbaf8cef60 Frontend: Add AuditSeverityOptions in src/model/logs.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-21 17:42:08 +02:00
Michael Mayer
f0e8680404 Frontend: Update .json translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-21 17:29:01 +02:00
Michael Mayer
4be8d08251 i18n: Update .po and .json translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-21 17:24:41 +02:00
Weblate
73d6df3a2f Weblate: Update frontend translations 2025-10-21 17:19:20 +02:00
Michael Mayer
44518801fa Cluster: Improve API endpoint logs and headers
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-21 17:04:16 +02:00
Michael Mayer
53f7643583 Cluster: Improve API endpoint and CLI command logs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-21 16:51:24 +02:00
Michael Mayer
5b7ea44eb5 Config: Retain support for DatabaseDsn in YAML files #5279
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-21 16:22:06 +02:00
Michael Mayer
8d9b75c9a7 Remove Developer Notes from README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-21 15:11:59 +02:00
Michael Mayer
69c816d616 Logs: Replace status string literals with generic constants
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-21 15:08:10 +02:00
Michael Mayer
cd7fa6adca Logs: Add package pkg/log/status to provide generic outcome constants
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-21 14:42:05 +02:00
Michael Mayer
91e4d72e1b Portal: Hide severity levels that are currently not used for audit logs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-20 19:22:00 +02:00
Michael Mayer
e1b51bbc34 Cluster: Add comments and improve code formatting in registry/client.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-20 18:49:38 +02:00
Michael Mayer
227a8cf8a4 API: Improve audit log in cluster_nodes_register.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-20 18:48:39 +02:00
Michael Mayer
ce304abd2c API: Update endpoints to return HTTP 201 when a new resource was created
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-20 16:46:59 +02:00
Michael Mayer
ddc37e08ab API: Improve audit logs in cluster_nodes_register.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-20 14:53:11 +02:00
Michael Mayer
c5b5feee47 CLI: Add audit logs to cluster management commands
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-20 14:49:25 +02:00
Michael Mayer
252aff2a6b API: Improve audit log messages in the cluster endpoint handlers
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-20 14:29:40 +02:00
Michael Mayer
ced4be2e40 API: Improve audit log messages in cluster_nodes_register.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-20 12:53:18 +02:00
Michael Mayer
54d8470f90 API: Improve logging in cluster_nodes_register.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-20 06:20:20 +02:00
Michael Mayer
46f70c174f Config: Improve caching tests in config_cluster.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-20 02:22:07 +02:00
Michael Mayer
3624e73d36 Config: Add a simple cache to reduce disk I/O under stress
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-20 01:41:19 +02:00
Michael Mayer
f23069dd2c Security: Improve credential handling across the cluster tooling #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-20 00:06:17 +02:00
Michael Mayer
83d69f59cc Config: Refactor internal/config/config_cluster.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 22:16:31 +02:00
Michael Mayer
bc83e00273 CLI: Refactor cluster_helpers.go and cluster_theme_pull_oauth_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 22:16:07 +02:00
Michael Mayer
5d6e46b87f Develop: Add package "htop" to docker/develop/questing/Dockerfile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 22:13:33 +02:00
Michael Mayer
72f88be5fe Docs: Update /pkg/service/http/... -> /pkg/http/...
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 21:35:16 +02:00
Michael Mayer
a921f82a17 Pkg: Move /service/http/... to /http/... and add package /http/dns
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 21:08:48 +02:00
Michael Mayer
dacb5794f5 Server: Reformat routes_wellknown.go for better readability
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 19:00:38 +02:00
Michael Mayer
50abe4ddaf Config: Automatically download, install and activate cluster theme #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 16:09:26 +02:00
Michael Mayer
122f8f6dd1 Docs: Update specs and CODEMAP.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 14:32:56 +02:00
Michael Mayer
e6959e7e96 Cluster: Report Config.About() instead of Config.Name() as app name #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 14:30:10 +02:00
Michael Mayer
695b33f097 Cluster: Change conf.AppName() to Name() in node register request #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 13:15:45 +02:00
Michael Mayer
1b85f84943 Cluster: Add AppName, AppVersion and Theme request/response fields #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 12:44:21 +02:00
Michael Mayer
1c0f68aa39 Logs: Fix mismatch between audit log placeholders and parameters
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 09:03:07 +02:00
Michael Mayer
1ba41b6656 PWA: Update CODEMAP.md files #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 08:44:36 +02:00
Michael Mayer
89a9362fa8 PWA: Update webpack.config.js #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 08:22:28 +02:00
Michael Mayer
3aa5a3902f PWA: Prevent .ttf and .woff font precaching #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 08:14:21 +02:00
Michael Mayer
6d0f720574 PWA: Reduce Workbox service worker precaching #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 08:11:43 +02:00
Michael Mayer
fd2a386c71 PWA: Improve handling of service worker requests #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 07:25:50 +02:00
Michael Mayer
5cae6af468 PWA: Handle hashed Workbox runtime requests #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 06:08:12 +02:00
Michael Mayer
2616fc9610 Frontend: Refactor themes.Get() function and related tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 04:54:05 +02:00
Michael Mayer
ad1a6dfac1 Portal: Disable index, metadata, share, and sync background workers
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 03:42:49 +02:00
Michael Mayer
1a5dca4871 Cluster: Update assertions in config_cluster_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 03:17:52 +02:00
Michael Mayer
9ce87e6d61 Cluster: Update api/cluster_theme.go and config/config_cluster.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 03:12:34 +02:00
Michael Mayer
6ed9d2715a Cluster: Improve defaultClusterDomain() in bootstrap.go #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 02:52:57 +02:00
Michael Mayer
a779c5d89a Cluster: Auto-derive Advertise/Site URLs from node name #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 02:40:06 +02:00
Michael Mayer
bad4b84267 Cluster: Improve log messages in internal/service/cluster/node #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 02:12:45 +02:00
Michael Mayer
6802be48a4 Frontend: Update locales/json/fr.json #5275
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 01:36:40 +02:00
Michael Mayer
b28aaa6c2c Frontend: Add $util.openUrl() helper function to enhance security
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 01:35:01 +02:00
Weblate
8e73ce9a2d Weblate: Update frontend translations 2025-10-19 01:16:05 +02:00
Michael Mayer
baa08b7558 Frontend: Reformat CSS files with Prettier
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 01:12:18 +02:00
Michael Mayer
47553d5346 Frontend: Add rel="noopener" to external links
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 00:47:45 +02:00
Michael Mayer
47d1a11c2d Cluster: Update CODEMAP.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-19 00:06:43 +02:00
Michael Mayer
b5c4fd3dcf Cluster: Refactor registration and database provisioning
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 23:54:56 +02:00
Michael Mayer
b47ee0fddc Cluster: Refactor request/response structs and JSON serialization
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 17:42:22 +02:00
Michael Mayer
04f015bdf0 Cluster: Improve logging in node/bootstrap.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 16:19:08 +02:00
Michael Mayer
dc7ca44165 Backend: Upgrade deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 14:06:35 +02:00
Michael Mayer
b829090e15 Develop: Increase stop_grace_period in compose.yaml service configs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 12:44:28 +02:00
Michael Mayer
f99466293a Develop: Add stop_grace_period to compose.yaml service configs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 12:42:01 +02:00
Michael Mayer
5a95d972a8 PWA: Improve service worker server endpoint #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 12:30:38 +02:00
Michael Mayer
f65d473171 Docker: Upgrade base image from Ubuntu 25.04 to 25.10 (Questing) #5276
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 12:11:02 +02:00
Michael Mayer
c4bb774195 libheif: Upgrade library version from v1.19.7 to v1.20.2 #5276
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 11:55:13 +02:00
Michael Mayer
580751a051 Docker: Add Makefile targets and Dockerfiles for Ubuntu 25.10 #5276
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 10:49:09 +02:00
Michael Mayer
7c8438a47f PWA: Update license NOTICE files #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 09:53:14 +02:00
Michael Mayer
7872e7f967 Frontend: Remove "server" package and update "eslint" #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 09:46:39 +02:00
Michael Mayer
0cb58db96b Config: Improve comments and tests for StaticFile methods #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 09:37:28 +02:00
Michael Mayer
627acaf64e PWA: Add fs constants for "assets.json" and "manifest.json" #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 09:23:53 +02:00
Michael Mayer
5bfa9803f1 PWA: Add code comments to internal/server/routes_webapp.go #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 09:16:33 +02:00
Michael Mayer
bf6d7e4f94 Config: Add StaticBuildFile() and StaticImgFile() functions #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-18 09:09:56 +02:00
Michael Mayer
703f355c09 PWA: Include minimal no-op service worker for tests #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 20:41:22 +02:00
Michael Mayer
0354fad37e Demo: Improve protection against AI-generated reports #5269
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 19:34:39 +02:00
Michael Mayer
b400666a17 PWA: Update license NOTICE files #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 17:01:33 +02:00
Michael Mayer
977dd2bafd PWA: Replace "@lcdp/offline-plugin" with "workbox-webpack-plugin" #5274
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 16:52:42 +02:00
Michael Mayer
ab9a0a969b Frontend: Use vue-gettext-extract instead of gettext-extract #1152
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 16:05:32 +02:00
Michael Mayer
0a727de361 GitHub: Delete question.yml and question.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 13:33:08 +02:00
Michael Mayer
07b0938bf2 GitHub: Update question.yml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 13:31:08 +02:00
Michael Mayer
565001f56e GitHub: Update question.yml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 13:30:38 +02:00
Michael Mayer
da8ab3b302 GitHub: Add ISSUE_TEMPLATE/config.yml and update question.yml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 13:28:50 +02:00
Michael Mayer
f58d319aa1 GitHub: Update feature-request.yml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 13:17:58 +02:00
Michael Mayer
fe4edf8f9b GitHub: Update feature-request.yml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 13:15:03 +02:00
Michael Mayer
e218a503c3 GitHub: Update feature-request.yml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 13:13:21 +02:00
Michael Mayer
82807110e4 GitHub: Update bug_report.yml and feature-request.yml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 13:10:31 +02:00
Michael Mayer
dcb1f91938 GitHub: Update .github/ISSUE_TEMPLATE/bug_report.yml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 12:59:58 +02:00
Michael Mayer
575e09a797 GitHub: Update .github/ISSUE_TEMPLATE/bug_report.yml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 12:57:57 +02:00
Michael Mayer
c5b764abea GitHub: Update issue templates and form in .github/ISSUE_TEMPLATE
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 12:51:38 +02:00
Michael Mayer
7eae368b3c GitHub: Update forms in .github/ISSUE_TEMPLATE
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 12:49:45 +02:00
Michael Mayer
942650bb2f GitHub: Add YML files to define form fields based on existing templates
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 12:44:39 +02:00
Michael Mayer
b42c3f8945 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 11:55:43 +02:00
Michael Mayer
56c8843572 Lightbox: Set closing to false after leave #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-17 11:55:16 +02:00
Michael Mayer
865b1513ee Lightbox: Improve logging of media error events #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-16 18:02:03 +02:00
Michael Mayer
d64db46239 Lightbox: Log video.load() errors in debug mode #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-16 17:36:24 +02:00
Michael Mayer
3142c39c84 Lightbox: Explicitly load video when flipping preload flag #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-16 17:05:06 +02:00
Michael Mayer
2227aa57b2 Portal: Add cluster admin UI #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-16 16:21:56 +02:00
Michael Mayer
76f372f8f8 Lightbox: Enhance iOS compatibility when playing videos #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-16 16:18:55 +02:00
Michael Mayer
f7a0711c87 Frontend: Update package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-16 10:29:02 +02:00
Michael Mayer
e6ac194b61 Lightbox: Don't set is-playing class in playVideo() #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-16 08:32:22 +02:00
Michael Mayer
effed76095 Lightbox: Refactor video playback and styles #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-16 07:20:43 +02:00
Michael Mayer
cb9d8d236a Config: Move Portal flag to ClientConfig struct
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-15 23:32:54 +02:00
Michael Mayer
0ef0c79766 Config: Add Portal feature flag
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-15 23:19:51 +02:00
Michael Mayer
0aa34a4775 Develop: Upgrade base image from 251010-plucky to 251014-plucky
Includes the latest Go release v1.25.3

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-15 15:29:57 +02:00
Michael Mayer
ed1e5e1236 Docs: Update Title Case headings rule for documents
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-15 14:22:04 +02:00
Michael Mayer
7bb9bf0a91 Docs: Update Playwright MCP Usage
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-15 13:11:30 +02:00
Michael Mayer
71c0137446 Backend: Update github.com/golang/geo in go.mod & go.sum; update NOTICE
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-14 21:20:00 +02:00
Michael Mayer
b1fc7ed55c Entity: Add missing json and yaml struct field tags; update swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-14 21:18:34 +02:00
Michael Mayer
3f6c7062bc Develop: Allow to use internal/tmp/ as scratch space for testing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-14 21:12:11 +02:00
Michael Mayer
bd3fad6457 Demo: Add protection against AI-generated vulnerability reports #5269
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-14 20:47:25 +02:00
Michael Mayer
32ab48921b Lightbox: Remove @mousedown and @pointerdown handlers #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-14 18:02:17 +02:00
Michael Mayer
37c8c83a3f Lightbox: Improve debug logs #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-14 16:41:44 +02:00
Michael Mayer
74fd3e7913 Docs: Update license NOTICE
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-14 16:09:28 +02:00
Michael Mayer
118b082ac0 Frontend: Update deps in package.json and package-lock.json #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-14 16:08:07 +02:00
Michael Mayer
bd1d4f45b9 UX: Refactor esc keydown handlers #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-14 16:07:34 +02:00
Michael Mayer
66852ac6cb Lightbox: Remove close-on-back as it is handled by view.js #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-14 15:58:44 +02:00
Michael Mayer
2ce3772958 Lightbox: Disable close-on-back and add close on esc down #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-14 15:54:54 +02:00
Michael Mayer
25c1375c4c UX: Refactor Lightbox close event handling #5258 #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-14 15:00:38 +02:00
Michael Mayer
74abddb3aa Backend: Downgrade github.com/gin-contrib/gzip in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-13 10:40:28 +02:00
Michael Mayer
c9fdb4c518 Lightbox: Only watchAvailability if video.castable is false #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-13 10:34:05 +02:00
Michael Mayer
8fc557a428 Backend: Update github.com/gin-contrib/gzip in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-13 10:26:48 +02:00
Michael Mayer
34751d5898 Frontend: Update deps in package.json and package-lock.json#5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-13 10:26:13 +02:00
Michael Mayer
3686895f42 Lightbox: Remove videoAvailabilityListener on abort #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-13 10:22:40 +02:00
Michael Mayer
3c25e1c9fa Lightbox: Abort any existing AbortController before reattaching #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-13 10:14:43 +02:00
Michael Mayer
0a9eb50fcc Lightbox: Rename data.ctrlVideoListeners to data.events #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-13 10:04:22 +02:00
Michael Mayer
3007706a20 Lightbox: Update frontend/CODEMAP.md #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-13 09:54:36 +02:00
Michael Mayer
8f97672930 Frontend: Replace } catch (_) { with } catch {
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-13 09:46:01 +02:00
Michael Mayer
58e040c5ac Lightbox: Use AbortController to clean up the event handlers #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-13 09:40:57 +02:00
Michael Mayer
fc46808d03 Lightbox: Improve state management when playing videos #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-13 05:50:14 +02:00
Michael Mayer
0b0f312b3e Backend: Upgrade all packages from "math/rand" to "math/rand/v2"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 21:34:07 +02:00
Michael Mayer
954070871e CLI: Update remux policy and metadata docs #5261
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 20:01:31 +02:00
Michael Mayer
829d4291fd CLI: Improve photoprism dl command with additional flags #5261
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 19:41:08 +02:00
Michael Mayer
f3deeee655 Lightbox: Improve memory and event management #5260
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 17:44:03 +02:00
Michael Mayer
131f584b8e Places: Improve memory and event management #5259
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 17:06:02 +02:00
Michael Mayer
2b10245e50 Lightbox: Use this.subscriptions as array #5258
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 15:45:00 +02:00
Michael Mayer
e1fcbe024f Lightbox: Regenerate .po translation files #5258
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 15:15:29 +02:00
Michael Mayer
864934d085 Lightbox: Refactor touch and pointer event listeners #5258
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 15:03:45 +02:00
Michael Mayer
8b9d2e6459 Frontend: Improve browser capabilities check #5047
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 12:38:52 +02:00
Michael Mayer
5bc5d28b78 UX: Improve event handling in components/lightbox.vue #5258
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 12:22:52 +02:00
Michael Mayer
f55611762f Docs: Update CODEMAP.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 10:56:18 +02:00
Michael Mayer
e8473ae22a Docs: Update CODEMAP.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 10:54:37 +02:00
Michael Mayer
bce39eabfc Docs: Update SPlaywright MCP Usage guidelines
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 10:49:45 +02:00
Michael Mayer
6969e3e8a1 Docs: Update Safety & Data guidelines
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-12 09:25:54 +02:00
Michael Mayer
024a6727fe Frontend: Regenerate JSON translation files #5177
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-11 15:46:02 +02:00
Weblate
ef117ba842 Weblate: Update frontend translations 2025-10-11 15:45:22 +02:00
Michael Mayer
e145ae359d Frontend: Regenerate translations.pot #5177
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-11 15:44:03 +02:00
Michael Mayer
064bd5051c Frontend: Regenerate JSON translation files #5177
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-11 15:26:12 +02:00
Weblate
143f91e1b4 Weblate: Update frontend translations 2025-10-11 15:24:15 +02:00
Michael Mayer
864b8eadee Frontend: Regenerate translations.pot #5177
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-11 15:21:45 +02:00
Michael Mayer
4924114a53 Clean: Add Yes/No/Bool funcs consistent with strconv.ParseBool() #5191
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-11 14:35:39 +02:00
Michael Mayer
c9dc431a71 API: Add force flag and update docs for DELETE /api/v1/albums/UID #5122
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-11 14:11:29 +02:00
Ömer Duran
3e87ad9809
UX: Improve "Add to Album" dialog to support multiple albums #5177
* Frontend: add multi-select to Add to Album and support multi-target actions
* Tests: Adapt acceptance tests to changes
* Frontend: Enhance clipboard functionality by adding input validation and deduplication for album UIDs across multiple components
* Tests: Enhance album functionality tests to support adding/removing photos from multiple albums and address album duplication bug
* Tests: Improve page mdoel and remove .only
* Frontend: Increase max-width of photo album dialog from 390 to 500
* Tests: Remove unused triggerAlbumDialogAndType method
* Frontend: Remove deep watcher from album dialog and implement deduplication logic for selected albums in upload dialog
* Frontend: Update album dialog placeholder text
* Tests: Refactor album duplication test for clarity and consistency
* Tests: Cover additional test cases
* Tests: Improve acceptance tests
* Frontend: Remove error logging
* Frontend: Add utility functions for album selection and implement watcher in dialog
* Frontend: Enhance album creation logic to handle partial failures and improve user feedback
* Frontend: Fix title casing for album selection chips in dialog
* Frontend: Fix title rendering logic for album selection chips in dialog

---------

Co-authored-by: graciousgrey <theresagresch@gmail.com>
2025-10-11 13:43:41 +02:00
Michael Mayer
a3c298f617 Frontend: Add browser capabilities check #5047
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-11 12:48:30 +02:00
Michael Mayer
c0f02637a9 Forms: Improve validation to support "+" signs in email addresses #5254
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-11 11:24:10 +02:00
graciousgrey
cfb3fd18c1 Tests: Adapt tests to changes 2025-10-10 21:51:55 +02:00
Michael Mayer
e6dd2020bb Albums: Run UpdateClientConfig asynchronously #5253
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 20:25:20 +02:00
Michael Mayer
c5d17c579c Albums: Improve performance when setting/refreshing cover images #5253
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 17:51:55 +02:00
Michael Mayer
92d21af697 AI: Do not run face detection on-demand by default #5167 #5234
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 16:28:36 +02:00
Michael Mayer
958ea37fa0 AI: Do not run face detection on-schedule by default #5167 #5234
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 16:22:42 +02:00
Michael Mayer
cda6ecac83 UX: Increase person menu from opacity-80 to opacity-85 #4151 #797 #5249
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 16:04:46 +02:00
Michael Mayer
054be35f92 UX: Disable input autofocus on mobile devices #5213
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 16:03:52 +02:00
Michael Mayer
5d587cbbf2 Frontend: Update JSON translation files #4151 #797 #5249 #5252
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 14:27:59 +02:00
Weblate
e1275c97a3 Weblate: Update frontend translations 2025-10-10 14:27:18 +02:00
Michael Mayer
b28f55ff59 UX: Refactor person action menu in edit dialog #4151 #797 #5249
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 14:23:59 +02:00
Michael Mayer
f26f6ecd17 Backend: Refactor new enum package and yes/no matching #5191
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 13:40:51 +02:00
Keith Martin
b1822229ca
Backend: Improve Yes/No capabilities #5191
* Backend: improve Yes/No capabilities
* Backend: constants package with Yes/No maps and True/False strings
* Backend: rename constants to enum
* Backend: correct case on russian Yes, more tests
* Enum: utilise enum package
2025-10-10 13:15:15 +02:00
Ömer Duran
1d216f2dfc
UX: New Action Menu for Faces in People Editing Tab #4151 #797 #5249
* Frontend: Add 3-dot menu for face actions in people page #4151 #797
* Tests: Add unit test for manual cover setting in subjects API #4151 and #797
* Tests: Add unit tests for face actions in PeopleTab component #4151 #797
* Tests: Enhance face action functionality in PeopleTab with new tests for removing faces and setting person cover #4151 #797
2025-10-10 13:02:31 +02:00
Michael Mayer
1778c7e46c UX: Adjust thinking theme colors in options/themes.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 12:38:35 +02:00
Michael Mayer
091cd19086 UX: Update thinking theme surface color in options/themes.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 12:28:20 +02:00
Michael Mayer
a8fcf7cca2 Frontend: Update docs on Playwright MCP Usage
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 10:50:28 +02:00
Michael Mayer
31312b3e93 Frontend: Update docs on Playwright MCP Usage
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 10:22:50 +02:00
Michael Mayer
e8ceba4e2f Database: Update entity/schema/mariadb.sql
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 09:47:01 +02:00
Michael Mayer
6e41c46db0 API: Update swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 09:45:52 +02:00
Michael Mayer
85a0543df5 Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 09:45:27 +02:00
Michael Mayer
ed2809b1e7 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 09:38:59 +02:00
Michael Mayer
e0b4c5d136 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 09:38:44 +02:00
Michael Mayer
4ab48cd461 Develop: Update Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 09:36:37 +02:00
Michael Mayer
670bc823c2 Develop: Upgrade base image from 251007-plucky to 251010-plucky
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 09:18:34 +02:00
Michael Mayer
fde403e3e1 Frontend: Update CODEMAP.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 09:13:20 +02:00
Michael Mayer
6373e487fc Frontend: Add docs on Playwright MCP Usage
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 09:05:43 +02:00
Michael Mayer
d36e83d2ef Develop: Remove whitespace from docker/develop/plucky/Dockerfile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 08:52:45 +02:00
Michael Mayer
1273991a7d Develop: Add xvfb and fonts to docker/develop/plucky/Dockerfile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-10 08:47:49 +02:00
Michael Mayer
4215243ab6 Cluster: Add comments to service/cluster/provisioner/database.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 17:23:19 +02:00
Michael Mayer
7c2bb9bd30 API: Remove leftover MariaDB databases and users from cluster tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 17:19:37 +02:00
Michael Mayer
01af8dd2ff CLI: Add internal/api/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 16:40:21 +02:00
Michael Mayer
e9c34f5f80 CLI: Add internal/commands/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 16:34:56 +02:00
Michael Mayer
97ab742f6b Docs: Move note on metadata sources
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 16:14:41 +02:00
Michael Mayer
683d1f90e8 Docs: Move note on shared CLI flag helpers
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 16:08:10 +02:00
Michael Mayer
132a12cae4 Docs: Add note on shared CLI flag helpers
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 16:04:31 +02:00
Michael Mayer
84cb9d9855 CLI: Reorder flags of cluster management commands
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 15:58:04 +02:00
Michael Mayer
9d968ab357 CLI: Refactor "dry-run" and "yes" command flags to use helper functions
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 15:41:35 +02:00
Michael Mayer
f125bfd638 Docs: Document preferred CLI command flags and arguments order
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 15:05:43 +02:00
Michael Mayer
81b8ed8182 Cluster: Ensure credentials are deleted after tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 14:56:45 +02:00
Michael Mayer
b46a6aef77 Metadata: Add USB to pkg/txt/specialwords.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 13:51:09 +02:00
Michael Mayer
03ca4031a5 Frontend: Update "all" route in src/app/routes.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 12:57:21 +02:00
Michael Mayer
3563d3f13c Frontend: Remove unnecessary saveWindowScrollPos() calls #5211
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 12:32:41 +02:00
Michael Mayer
0dbe118186 Frontend: Restore scroll state on back navigation #5211
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 11:57:19 +02:00
graciousgrey
c9c50fd31e Tests: Adapt tests to changes 2025-10-09 11:16:25 +02:00
Michael Mayer
a8487bf793 Frontend: Update deps in package.json and package-lock.json #5211
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 10:29:57 +02:00
Michael Mayer
db0c1a4c1d Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-09 10:29:25 +02:00
Michael Mayer
1117e0b1dc UX: Increase BatchSize from 60 to 180 in model/album.js #5211
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 19:24:02 +02:00
Michael Mayer
354414a5e1 Vision: Allow to combine default model config with custom run type #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 17:46:03 +02:00
Michael Mayer
77d6b7fe00 UX: Update "Thinking" surface theme color in options/themes.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 17:13:37 +02:00
Michael Mayer
401d910b2f Specs: Prevent auto-generated docs from getting edited manually
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 15:41:52 +02:00
Michael Mayer
3efb69483e Faces: Update README.md #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 15:08:37 +02:00
Michael Mayer
8571600a1b Faces: Update README.md #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 15:04:22 +02:00
Michael Mayer
316cd2c919 Faces: Update README.md #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 14:46:05 +02:00
Michael Mayer
87b63b71dc Faces: Update README.md #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 14:37:11 +02:00
Michael Mayer
7d05767a8f Faces: Update timestamp in README.md #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 14:35:48 +02:00
Michael Mayer
9e888703c5 Faces: Add face kinds reference to README.md #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 14:35:33 +02:00
Michael Mayer
7e64ecb77a Config: Reorganized function order in config_faces.go #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 14:02:43 +02:00
Michael Mayer
729b4c4bdb Config: Return face.EngineNone in FaceEngine() when config is nil #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 13:58:54 +02:00
Michael Mayer
3bd17fb1a2 Config: Return face.EngineNone in FaceEngine() when config is nil #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 13:54:14 +02:00
Michael Mayer
251a8dfd4a Config: Update config_vision.go and config_faces_test.go #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 13:50:48 +02:00
Michael Mayer
a302955c02 Faces: Remove PHOTOPRISM_FACE_ENGINE_RUN config option #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 13:41:51 +02:00
Michael Mayer
26b937d8b0 Config: Update config_faces.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 12:35:49 +02:00
Michael Mayer
77c9959f12 Faces: Update README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 12:35:07 +02:00
Michael Mayer
62661f597f Faces: Update internal/ai/face/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 11:34:47 +02:00
Michael Mayer
756c6fe9c1 Faces: Update internal/ai/face/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 11:33:41 +02:00
Michael Mayer
d693e2235c Setup: Update link in setup/pkg/linux/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 11:28:08 +02:00
Michael Mayer
81344c9ab1 Docs: Add style notes to AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 11:23:23 +02:00
Michael Mayer
5b83aea1f5 Setup: Update package installation docs in setup/pkg/linux/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 11:23:23 +02:00
graciousgrey
012a7605f5 Backend: Update count in scheduleModels 2025-10-08 11:14:01 +02:00
Michael Mayer
73312ada41 Setup: Update package installation docs in setup/pkg/linux/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 10:53:09 +02:00
Michael Mayer
5610f8fafb Setup: Update package installation docs in setup/pkg/linux/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 10:43:04 +02:00
Michael Mayer
3b5d185e8c Setup: Update package installation docs in setup/pkg/linux/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 10:31:14 +02:00
Michael Mayer
a59134ebd6 Setup: Update package installation docs in setup/pkg/linux/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-08 10:13:12 +02:00
Michael Mayer
9b56b4ec01 Faces: Add note on background filtering to background.go and docs #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 23:10:06 +02:00
Michael Mayer
22d8a63bfe Develop: Upgrade base image from 251006-plucky to 251007-plucky
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 22:36:32 +02:00
Michael Mayer
87b540b438 Scripts: Add shellcheck annotations and fix reported issues
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 22:32:31 +02:00
Michael Mayer
ab60112f99 AI: Update download-scrfd.sh script #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 22:16:19 +02:00
Michael Mayer
1eac265978 AI: Rename "scrfs" to "scrfd" in config and download script #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 22:12:37 +02:00
Michael Mayer
3693db0946 AI: Change download URL of scrfd model in download-scrfs.sh #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 21:54:21 +02:00
Michael Mayer
7fa6dfe0b5 Config: Set SystemLog level based on application log level #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 21:30:19 +02:00
Michael Mayer
9f22a2f73e Faces: Use system log in internal/photoprism/faces_optimize.go #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 21:19:39 +02:00
Michael Mayer
4bbba226b7 Security: Add a system log for publishing internal warnings and errors
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 21:08:04 +02:00
Michael Mayer
0d27cee391 Faces: Change search to return all face markers, regardless of src #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 20:01:43 +02:00
Michael Mayer
68e1ddcc89 AI: Improve conflict resolution when merging face clusters #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 18:58:21 +02:00
Michael Mayer
3502251f7e AI: Improve logging of face cluster merge conflicts #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 17:52:02 +02:00
Michael Mayer
698ef753e2 Frontend: Update src/locales/json/fr.json #5243
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 16:44:12 +02:00
Weblate
99c4c4bea6 Weblate: Update frontend translations 2025-10-07 16:42:52 +02:00
Michael Mayer
221d3196f4 Index: Refactor IndexOptions to determine vision tasks from Config #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 16:22:41 +02:00
Michael Mayer
f5e233194f Frontend: Update Thinking theme colors in src/options/themes.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 14:57:10 +02:00
Michael Mayer
2ff6eae58a Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 14:56:39 +02:00
Michael Mayer
5989c3578d AI: Run face detection after indexing if CPU threads <= 2 #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 14:28:41 +02:00
Michael Mayer
c71e4c8828 AI: Ensure face detection only runs once (during or after index) #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 14:16:11 +02:00
Michael Mayer
3b3a01317b AI: Add IndexedAt time to indicate when a photo was fully indexed #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 13:57:01 +02:00
Michael Mayer
8640e60c14 AI: Refactor face detection code #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-07 11:28:52 +02:00
Michael Mayer
04dd4ba24d Develop: Upgrade base image from 251004-plucky to 251006-plucky #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-06 19:07:50 +02:00
Michael Mayer
94f8a5f35d AI: Improve Face Detection with an ONNX-based model #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-06 18:51:49 +02:00
Michael Mayer
677e190b6e AI: Adjust Pigo parameters for improved Face Detection #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-06 11:51:43 +02:00
Michael Mayer
ea693e9ab7 Faces: Improve "photoprism faces audit --fix" command
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-05 18:52:30 +02:00
Michael Mayer
00d41144a0 Faces: Migrate & normalize face.Children from Embeddings to Clusters
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-05 18:11:18 +02:00
Michael Mayer
4b625d8217 Faces: Migrate out-of-distribution (OOD) embeddings to face.Background
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-05 17:38:13 +02:00
Michael Mayer
dcd4e684ae UX: Disable "public" filter under Search > Private
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-05 05:12:49 +02:00
Michael Mayer
240ee9f0ce AI: Do not add portrait or people labels from face markers #5232
Related issues: #5233 (reset command), #5234 (schedule for models)

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-05 04:37:20 +02:00
Michael Mayer
e5dc335bcf AI: Include NSFW flag & score when generating labels with Ollama #5232
Related issues: #5233 (reset command), #5234 (schedule for models)

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-05 04:23:36 +02:00
Michael Mayer
79654170eb Ollama: Remove code fences and commentary from JSON API responses
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 16:46:55 +02:00
Michael Mayer
fba00a843c Config: Add "test-hub" target to Makefile and improve log messages
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 15:59:34 +02:00
Michael Mayer
47b7a0faf7 Develop: Upgrade base image from 250930-plucky to 251004-plucky
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 15:57:52 +02:00
Michael Mayer
a988459ef0 Dockerfiles: Update environment variables and their defaults
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 15:07:40 +02:00
Michael Mayer
4275290f93 Dockerfiles: Remove optional and database password env variables
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 14:58:04 +02:00
Michael Mayer
b71ec5bce1 Config: Fix assets path and disable hub updates when running unit tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 14:16:11 +02:00
Michael Mayer
133afda8ce Frontend: Update JSON translation files #5241
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 11:06:39 +02:00
Weblate
17030940c8 Weblate: Update frontend translations 2025-10-04 11:06:00 +02:00
Michael Mayer
875275828e UX: Update class attributes for the action buttons in the Edit dialog
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 11:03:01 +02:00
Michael Mayer
6a84a2536e UX: Rename "Apply" button to "Save" and add aria-label attributes
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 11:00:35 +02:00
Weblate
12df9cb954 Weblate: Update frontend translations 2025-10-04 10:58:47 +02:00
Michael Mayer
ac9d33a1b0 UX: Change "Close" button to "Discard" when there are unsaved changes
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 10:40:36 +02:00
Michael Mayer
28017c47c6 Frontend: Reduce "Thinking" theme focus-opacity
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 10:38:37 +02:00
Michael Mayer
84b9f1bb1b Frontend: Adjust "Thinking" user interface theme colors
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 10:35:10 +02:00
Michael Mayer
f56dd6b197 Labels: Add Thumb and ThumbSrc properties to the frontend model #4151
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 10:00:24 +02:00
Michael Mayer
8dd3197b8c Frontend: Make Subject model a Collection #4151
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-04 09:58:49 +02:00
Michael Mayer
d7ee54ec58 API: Update Thumb/ThumbSrc for subjects and labels #4151
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-03 23:17:07 +02:00
Michael Mayer
241f1df4c4 Frontend: Add a "Collection" model type for use in lightbox.vue #4151
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-03 18:14:18 +02:00
Michael Mayer
2cc0ef7eae MariaDB: Document terminal command for running SQL statements
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-03 16:37:44 +02:00
Michael Mayer
c40bf0b47d Frontend: Update CODEMAP.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-03 14:18:57 +02:00
Michael Mayer
dc9b8d78da Frontend: Update "Thinking" user interface theme
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-03 14:09:10 +02:00
Michael Mayer
b23fc123d7 Frontend: Add new "Thinking" user interface theme
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-03 13:51:15 +02:00
Michael Mayer
006123c94c Frontend: Update deps in package.json and package-lock.json #5211
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-03 12:54:17 +02:00
Michael Mayer
99e06f5f95 UX: Improve window scroll position restoration when navigating #5211
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-03 12:47:47 +02:00
Michael Mayer
a6f153b065 Faces: Add in-memory veto cache to avoid conflicts #4669 #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 23:00:44 +02:00
Michael Mayer
30dfacaab7 Faces: Optimize matching performance with spatial index #4669 #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 22:00:11 +02:00
Michael Mayer
8fdf405288 Faces: Optimize distance-based matching #4669 #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 21:27:55 +02:00
Michael Mayer
f7dff58f2e Faces: Normalize stored face embeddings and distances #4669 #5167
Run `photoprism faces audit --fix` to normalize existing embeddings.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 21:04:35 +02:00
Michael Mayer
cdee55fdf8 Faces: Add README.md for detection & embeddings #4669 #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 20:15:47 +02:00
Michael Mayer
dcb3dd6f18 Faces: Optimized midpoint computation and performance #4669 #5167
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 19:21:29 +02:00
Michael Mayer
d19d59632d Vision: Improve performance of Areas.Relative() in face/area.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 17:35:54 +02:00
Michael Mayer
9d81edcff7 Vision: Add comments and tests for internal/ai/face/landmarks.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 17:18:52 +02:00
letreturn
c57cacb834
Benchmarks: Use b.Loop() to simplify the code and enhance performance #5226
Signed-off-by: letreturn <letreturn@outlook.com>
2025-10-02 17:00:13 +02:00
Michael Mayer
1d984fb8b0 Docs: Improve code comments in internal/entity/passcode.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 16:27:22 +02:00
Michael Mayer
6218c7dda6 Docs: Update code comments in internal/entity/category.go and details.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 16:19:57 +02:00
Michael Mayer
5dda30e7e9 Docs: Improve code comments in internal/entity/country.go and cell.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 16:19:24 +02:00
Michael Mayer
0893e1ac80 Docs: Improve code comments in internal/entity/auth*.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 16:15:18 +02:00
Michael Mayer
71f00e9f4f Docs: Improve code comments in internal/entity/src.go and string.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 16:08:22 +02:00
Michael Mayer
c22201331d Docs: Improve code comments in internal/entity/entity*.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 16:05:56 +02:00
Michael Mayer
51083caef8 Docs: Improve code comments in internal/entity/label*.go and keyword.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 16:03:02 +02:00
Michael Mayer
7a5b623a83 Docs: Improve code comments in internal/entity/album*.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 15:59:38 +02:00
Michael Mayer
cdea0e5664 Docs: Improve code comments in internal/entity/file*.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 15:55:44 +02:00
Michael Mayer
59b54663d8 Docs: Improve code comments in internal/entity/photo*.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 15:52:05 +02:00
Michael Mayer
0ca3310f0a Backend: Fix internal/service/cluster/provisioner/naming_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 15:15:45 +02:00
Michael Mayer
b00dd133db Test: Use PascalCase names for all Go subtests in /pkg
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 15:03:47 +02:00
Michael Mayer
94b6631b3d Test: Use PascalCase names for all Go subtests in /internal
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 14:50:02 +02:00
Michael Mayer
c68493da8a Test: Document use of CamelCase names for Go subtests in /internal
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 14:40:09 +02:00
Michael Mayer
54d5659a93 Vision: Move PriorityFromTopicality() to topicality.go #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 14:18:36 +02:00
Michael Mayer
1aa6fe4f35 Vision: Export PriorityFromTopicality() in label_normalizer.go #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 14:16:11 +02:00
Michael Mayer
713beeff0f Labels: Improve conversion of topicality scores into priorities #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 14:12:11 +02:00
Michael Mayer
c57387d119 AI: Add "on-newly-indexed" alias for "newly-indexed" in RunTypes #5234
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 13:26:57 +02:00
Michael Mayer
088bdff69d Frontend: Update JSON translation files #5232 #5237
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 13:18:46 +02:00
Weblate
662d233fa3 Weblate: Update frontend translations 2025-10-02 13:17:42 +02:00
Michael Mayer
470724f75a Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 13:15:00 +02:00
Michael Mayer
b2805a63a3 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 13:14:43 +02:00
Michael Mayer
c81f9f4b3f Frontend: Fix update target in Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 13:14:07 +02:00
Michael Mayer
746f26724c AI: Improve the generation, sorting, and filtering of labels #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-02 13:08:52 +02:00
graciousgrey
ac91c98ed0 AI: Decouple NSFW detection from label generation #5234 2025-10-02 12:53:07 +02:00
Michael Mayer
fe0d51a5ac Labels: Change defaultOrder in frontend/src/page/labels.vue
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 19:52:21 +02:00
Michael Mayer
6cbc7aa20c Labels: Sort results by picture count instead of label name
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 19:39:03 +02:00
Michael Mayer
858840c59a Scripts: Update version in dist/install-nuclei.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 18:30:57 +02:00
Michael Mayer
7dd3218493 Entity: Fix Map type alias in internal/entity/migrate/migrate.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 09:58:18 +02:00
Michael Mayer
8490e79a46 AI: Remove duplicate comments from label_normalizer.go #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 09:25:08 +02:00
Michael Mayer
0eca39428f AI: Use classify.Rules and a new prompt to improve Ollama labels #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 09:20:51 +02:00
Michael Mayer
54d96f613b CLI: Ensure vision reset command and worker use same default src #5233
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 08:52:28 +02:00
Michael Mayer
a49cecd5f7 Entity: Re-add Map shorthand alias for map[string]interface{}
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 08:48:45 +02:00
Michael Mayer
6ddcc8a585 Develop: Update .gitignore and .dockerignore files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 02:00:20 +02:00
Michael Mayer
bd1be3346e AI: Prevent adding labels without title or slug #5232 #5233 #5234
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 01:40:34 +02:00
Michael Mayer
9b5ee0513b AI: Allow underscores in vision model names #5232 #5233 #5234
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 00:59:40 +02:00
Michael Mayer
b52c66624f AI: Update comments in the internal/ai/vision/ollama and openai engines
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 00:37:49 +02:00
Michael Mayer
6490d158be AI: Refactor engine defaults in internal/ai/vision/** #5232 #5233 #5234
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-10-01 00:27:36 +02:00
Michael Mayer
838adee3eb Backend: Refactor middleware naming and improve code comments #5235
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 23:25:53 +02:00
Michael Mayer
873454ddd2 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 23:10:24 +02:00
Michael Mayer
07f1d2a434 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 23:09:36 +02:00
Michael Mayer
9315e87d45 NVIDIA: Refactor ffmpeg.DefaultAvcEncoder() function
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 22:51:10 +02:00
Michael Mayer
46ae2fa208 Docs: improve testing notes in AGENTS.mdd
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 22:22:45 +02:00
Michael Mayer
bb503a7322 WebDAV: Use isolated test environments for server/webdav_write_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 22:17:13 +02:00
Michael Mayer
983cbb50ff API: Add const, func, and struct comments for easier troubleshooting
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 22:02:43 +02:00
Michael Mayer
bbf6580512 Meta: Add const, func, and struct comments for easier troubleshooting
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 22:00:30 +02:00
Michael Mayer
ece066fb47 Event: Add code comments for easier troubleshooting #5235
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 21:55:54 +02:00
Michael Mayer
8c59d17993 Config: Add code comments for easier troubleshooting #5235
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 21:54:22 +02:00
Michael Mayer
6d551c5939 Query: Add code comments for easier troubleshooting #5235
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 21:46:42 +02:00
Michael Mayer
f49328345e Index: Fix in-memory Files/Photos lookup tables #5235
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 21:30:21 +02:00
Michael Mayer
e3925d779f Backend: Improve inline code comments
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 20:41:36 +02:00
Michael Mayer
52cc66af6d AI: Improve entity.Photo.ShouldGenerateLabels() check #5232 #5233 #5234
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 18:31:21 +02:00
Michael Mayer
7de88e0ec9 Develop: Upgrade base image from 250922-plucky to 250930-plucky
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 16:18:39 +02:00
Michael Mayer
fddd3c9626 Scripts: Update dist/install-yt-dlp.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 16:06:50 +02:00
Michael Mayer
4d4cac446e Docker: Add package xxd to develop/plucky/Dockerfile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 15:52:45 +02:00
Michael Mayer
d782a43c2b AI: Configure vision model execution and scheduling #5232 #5233 #5234
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 15:51:48 +02:00
graciousgrey
0c9f82a641 Makefile: Remove unused test targets 2025-09-30 13:02:23 +02:00
Michael Mayer
3f8f39e117 AI: Add a setting to specify when vision models should run #5234
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 10:52:11 +02:00
Michael Mayer
47def3c791 API: Removed unused code from api_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 01:28:49 +02:00
Michael Mayer
70aced3b12 API: Remove temporary SQLite files before running tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 01:27:16 +02:00
Michael Mayer
9c5abb05ad AI: Generate caption/labels in the background after indexing #5232 #5233
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-30 01:18:55 +02:00
Michael Mayer
327e1d587e AI: Automatically set model defaults and use default source #5232 #5233
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-29 23:09:29 +02:00
Michael Mayer
84e11829dc CLI: Refactor "photoprism vision" subcommands #5233
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-29 21:39:36 +02:00
Michael Mayer
e21174c297 CLI: Add txt.JoinAnd() helper function to format lists of items #5233
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-29 19:25:47 +02:00
Michael Mayer
7ae7ce9edd Tests: Update entity.FindPhoto() usage example
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-29 19:03:52 +02:00
Michael Mayer
ee46794509 CLI: Add "photoprism vision reset" command to reset metadata #5233
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-29 18:59:52 +02:00
Michael Mayer
114f4033e0 Docs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-29 17:25:14 +02:00
Michael Mayer
72de6c8db7 AI: Add Model.Provider value to set defaults by provider type #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-29 14:20:30 +02:00
Michael Mayer
40c5c4d712 AI: Add ApiFormat constants to vision/ollama and vision/openai #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-29 11:58:42 +02:00
Michael Mayer
e4f78a19ac Backend: Remove temporary SQLite files before running unit tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-29 11:49:10 +02:00
Michael Mayer
7cc758346f AI: Add source "ollama" for labels generated with Ollama models #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-29 11:45:08 +02:00
Michael Mayer
3f9d6863db Vision: Add ModelTypeGenerate for multi-modal models that return JSON
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-29 10:39:09 +02:00
Michael Mayer
3e14eed7d7 Scripts: Update success and error messages
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-29 09:47:29 +02:00
Michael Mayer
8a7c61f467 AI: Generate Labels using the Ollama API #5232
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-28 13:29:49 +02:00
Michael Mayer
cf06f52025 AI: Add vision/ollama and vision/openai packages for service integration
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-28 11:07:43 +02:00
Michael Mayer
a58fa36f34 Develop: Add "build-docker" as an alias for "docker-build" to Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-27 11:59:18 +02:00
Michael Mayer
7919b9ddc2 Develop: Improved "npm-version" and "codex-version" output in Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-27 11:56:08 +02:00
Michael Mayer
1e7786ad1c Develop: Update "npm" install targets in Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-27 11:47:12 +02:00
Michael Mayer
e888b0ddb1 FFmpeg: Remove unstable "directory is unwritable" tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-27 11:46:27 +02:00
Michael Mayer
44f561b7d6 CLI: Add "photoprism dl --format-sort" flag and dl-method env variable
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 15:51:50 +02:00
Michael Mayer
cbda4abe7a Downloads: Add CLI reference to photoprism/dl/README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 14:35:37 +02:00
Michael Mayer
a3dac7c707 Metadata: Update folder_test.go, photo_estimate_test.go, country_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 11:44:27 +02:00
Michael Mayer
4d91f5ffdf Metadata: Update TestCountryCode in pkg/txt/country_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 11:27:16 +02:00
Michael Mayer
1b48cb2a25 Metadata: Remove ambiguous location names from countries.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 11:25:56 +02:00
Michael Mayer
58180accee Config: Require secure cluster join tokens >= 24 chars #98 #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 11:01:48 +02:00
Michael Mayer
52337eba27 Cluster: Renamed service/cluster/instance to cluster/node #98 #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 07:01:09 +02:00
Michael Mayer
90f62a732e API: Add internal/api/cluster_metrics_test.go #98 #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 06:59:05 +02:00
Michael Mayer
bc6c34cb2b API: Add GET /api/v1/cluster/metrics endpoint #98 #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 06:36:23 +02:00
Michael Mayer
9f119a8cfa Auth: Return and persist ClusterCIDR when registering a node #98 #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 06:17:31 +02:00
Michael Mayer
66e2027c10 Auth: Shorten code comments in pkg/clean/scope.go #98 #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 05:55:50 +02:00
Michael Mayer
bd66110c18 Auth: Improve code comments in internal/auth/acl/scopes.go #98 #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 05:53:28 +02:00
Michael Mayer
07658dac69 Docs: Recommend acl.Scope* functions for scope checks #98 #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 05:49:23 +02:00
Michael Mayer
108b2c2df4 Auth: Recommend acl.ScopeAttrPermits / acl.ScopePermits #98 #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 05:45:59 +02:00
Michael Mayer
48a965a7cc API: Refactor JWT-based request authorization #98 #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 05:32:30 +02:00
Michael Mayer
32c054da7a CLI: Added JWT issuance and diagnostics sub commands #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-26 02:38:49 +02:00
Michael Mayer
566eed05e0 Backend: Remove temporary SQLite files after running unit tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-25 23:21:48 +02:00
Michael Mayer
660c0a89db Backend: Introduce optimized test config helpers to improve performance
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-25 23:09:52 +02:00
Michael Mayer
ebb0410b20 Docs: Add reminder to keep "Last Updated" lines updated
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-25 20:28:08 +02:00
Michael Mayer
7e419f7419 Docs: Add "Last Updated" timestamps to AGENTS.md and CODEMAP.md files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-25 20:08:45 +02:00
Michael Mayer
633d4222ab Auth: Improve JWKS Fetch Concurrency & Timeouts #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-25 18:46:24 +02:00
Michael Mayer
bae8ceb3a7 Auth: Support asymmetric JSON Web Tokens (JWT) and Key Sets (JWKS) #5230
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-25 17:52:44 +02:00
Michael Mayer
4828c0423d Docs: Update Go package documentation requirements
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-25 14:22:23 +02:00
Michael Mayer
cb81f9be12 FFmpeg: Add descriptions to encoder packages in internal/ffmpeg/
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-25 14:20:35 +02:00
Michael Mayer
4ea6e12a10 Docs: Update development quick tips
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-24 13:05:25 +02:00
Michael Mayer
41a7045c26 Docs: Update descriptions of permission variables
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-24 09:59:56 +02:00
Michael Mayer
c202a09241 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-24 08:29:09 +02:00
Michael Mayer
61ced7119c Auth: Refactor cluster configuration and provisioning API endpoints #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-24 08:28:38 +02:00
Michael Mayer
3baabebf50 Docs: Update Go test guidelines
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-23 16:39:13 +02:00
Michael Mayer
0a66f1476d Develop: Upgrade base image from 250912-plucky to 250922-plucky
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 11:10:06 +02:00
Michael Mayer
59fb8e2b4c API: Update Swagger usage notes
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 10:56:34 +02:00
Michael Mayer
8930cb7b79 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 10:46:22 +02:00
Michael Mayer
ade3b40a42 Docker: Add "python" symlink to develop/plucky/Dockerfile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 10:45:12 +02:00
Michael Mayer
9ea5f0596c Backend: Add security-focused tests, harden WebDAV and use safe.Download
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 10:42:53 +02:00
Michael Mayer
a22babe3d1 API: Update swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 06:20:47 +02:00
Michael Mayer
bfd26c55e3 Config: Update visibility/order of cluster options and flags #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 05:37:54 +02:00
Michael Mayer
578fbe4d10 API: Add missing Swagger endpoint annotations and update swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 04:12:02 +02:00
Michael Mayer
c8964fdc6b Make: Improve "reset-sqlite" target to delete all SQLite test databases
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 04:06:24 +02:00
Michael Mayer
eca06dcdfb Config: Remove redundant InitializeTestData tests
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 03:34:51 +02:00
Michael Mayer
38cdde5518 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 03:33:32 +02:00
Michael Mayer
2a113f167d Docs: Update CODEMAP.md and AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 03:24:56 +02:00
Michael Mayer
91804b9652 Backend: Improve Copy()/Move() and increase pkg/internal test coverage
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-22 03:07:51 +02:00
Michael Mayer
458a320bb8 Pkg: Add fs.Exists() function to check for any existing file/dir/link
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-21 23:09:33 +02:00
Michael Mayer
c312c0d109 Docs: Update CODEMAP.md and AGENTS.md #5220
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-21 19:58:56 +02:00
Michael Mayer
6e33575ba7 CLI: Skip help sub-commands in "photoprism show commands" output #5220
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-21 19:51:22 +02:00
Michael Mayer
d6cb6b7a2e CLI: Add "photoprism show commands" command to generate CLI docs #5220
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-21 19:34:39 +02:00
Michael Mayer
f1c57c72d8 CLI: Flatten config options output when using the "--json" flag #5220
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-21 16:52:56 +02:00
Michael Mayer
25253afcf2 Docs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-21 14:41:57 +02:00
Michael Mayer
f878ca0cb0 Docs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-21 14:39:56 +02:00
Michael Mayer
93493aba28 Docs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-21 14:17:54 +02:00
Michael Mayer
6901225a2b CLI: Add "--json" as an additional output format to show commands #5220
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-21 13:46:59 +02:00
Michael Mayer
ecdec6b408 CLI: Update Download CLI developer docs and testing hints #5219
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-20 14:59:48 +02:00
Michael Mayer
f7fe6b569a CLI: Improve "photoprism dl" post-processing and default settings #5219
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-20 14:36:41 +02:00
Michael Mayer
5e84da55e5 CLI: Improve "photoprism dl" to download multiple URLs with auth #5219
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-20 13:14:58 +02:00
Michael Mayer
d447adc59c Index: Don't fail if thumbs for a sidecar file cannot be created
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-19 07:53:06 +02:00
Michael Mayer
41da164469 Backend: Add fix for concurrent cleanups to convert_sidecar_json.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-19 07:06:33 +02:00
Michael Mayer
29ca2c1331 CLI: Improve "photoprism cluster" sub-commands #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-19 06:52:45 +02:00
Michael Mayer
2fe48605a2 Auth: Update cluster/instance/bootstrap.go and registry/client.go #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-19 05:21:17 +02:00
Michael Mayer
75af48c0c0 API: Refactor the node registry to use the entity.Client model #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-19 04:15:53 +02:00
Michael Mayer
13e1c751d4 API: Update entity.Client and cluster config options #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-19 01:13:32 +02:00
Michael Mayer
f6f4b85e66 Specs: Update AGENTS.md and CODEMAP.md to reflect code changes
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-19 01:10:23 +02:00
Michael Mayer
eee1b3fbfc Import: Fix duplicates handling in internal/photoprism/import_worker.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 18:05:13 +02:00
Michael Mayer
ce2d793a48 API: Update internal/api/cluster_nodes_register_test.go #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 17:57:58 +02:00
Michael Mayer
83a12fb58b API: Clean up nodes dir in internal/api/api_test.go #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 17:51:23 +02:00
Michael Mayer
1315df8c1f Auth: Reformat internal/auth/acl/roles_test.go #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 17:39:50 +02:00
Michael Mayer
c9e6b7c22b Auth: Add tests to internal/auth/acl/roles_test.go #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 17:35:11 +02:00
Michael Mayer
518079450e Docs: Update quick start tips
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 17:32:26 +02:00
Michael Mayer
aa5368e00a Docs: Update quick start tips
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 17:29:19 +02:00
Michael Mayer
1c3009d9b5 Auth: Add alias for RoleNone and improve unit tests coverage #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 17:10:39 +02:00
Michael Mayer
2818a9e6a8 Auth: Add "instance" and "service" roles, fix entity/auth_client.go #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 15:23:06 +02:00
Michael Mayer
464a64339f Tests: Fix internal/photoprism/import_worker_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 15:07:14 +02:00
Michael Mayer
b40e4c5597 CLI: Improve usage descriptions of client/user management commands #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 14:30:19 +02:00
Michael Mayer
887a39e7d9 Auth: Add "node" and "portal" roles, refactor session entity #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 13:33:18 +02:00
Michael Mayer
2a116cffb3 API: Remove auth check from cluster health endpoint #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 10:28:02 +02:00
Michael Mayer
1f10dcaf85 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 09:52:43 +02:00
Michael Mayer
202d513019 Scripts: Update dist/install-nodejs.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 09:52:02 +02:00
Michael Mayer
e221a8ee73 Frontend: Update npm install targets in Makefile and package.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 09:51:11 +02:00
Michael Mayer
fb27969e30 Dev: Add "git-pull" target to Makefile (pulls all changes)
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 09:05:57 +02:00
Michael Mayer
4a7c355d28 Specs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-18 08:45:30 +02:00
Michael Mayer
c7380111b2 Specs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-17 14:49:20 +02:00
Michael Mayer
40a4dbfe26 API: Improve cluster theme endpoint and tests #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-17 14:28:30 +02:00
Michael Mayer
1ab4c32ee8 Specs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-17 14:25:51 +02:00
Michael Mayer
19b09ebf0b Specs: Update AGENTS.md and CODEMAP.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-17 12:01:52 +02:00
Michael Mayer
00088d66cd Specs: Update AGENTS.md and CODEMAP.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-17 11:56:36 +02:00
Michael Mayer
e04df34453 Specs: Add CODEMAP.md and frontend/CODEMAP.md files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-17 00:50:23 +02:00
Michael Mayer
e1d031bea7 Config: Add cluster instance bootstrap and registration hook #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-16 23:30:23 +02:00
Michael Mayer
ec8ea96f31 Specs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-16 23:17:56 +02:00
Michael Mayer
b3fec4a2f5 Specs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-16 22:12:50 +02:00
Michael Mayer
0ce82056ca Specs: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-16 21:42:35 +02:00
Michael Mayer
dbf1650c1c CLI: Add cluster operations and management commands #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-16 18:09:09 +02:00
Michael Mayer
5db044284b Frontend: Update Makefile, package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-16 18:06:11 +02:00
Michael Mayer
3c821a3ea7 Frontend: Add "@ctrl/tinycolor" version override to package.json
Popular Tinycolor npm Package Compromised in Supply Chain Attack:
https://socket.dev/blog/tinycolor-supply-chain-attack-affects-40-packages

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-16 10:34:51 +02:00
Michael Mayer
5a4e03eff0 Update .gitignore and .dockerignore files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-15 15:04:39 +02:00
Michael Mayer
a4cd1ac1fd API: Move "service/cluster" package from "pkg" to "internal" #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-15 13:40:56 +02:00
Michael Mayer
ea8d413deb Config: Add "portal-uuid" to report.go and improve usage description #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-15 10:55:40 +02:00
Michael Mayer
b5c9e9f160 Docs: Update AGENTS.md file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-15 10:44:36 +02:00
Quentin BARON
d3775f02e6 API: Add cluster operations endpoints to manage and register nodes #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-15 06:43:43 +02:00
Michael Mayer
efbcf34588 Docs: Update AGENTS.md file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-15 04:43:37 +02:00
Michael Mayer
ced562dfb3 API: Update swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-14 21:40:55 +02:00
Michael Mayer
e639c962d7 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-14 20:13:42 +02:00
Michael Mayer
efd55b50d9 Update license NOTICE files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-14 20:13:13 +02:00
Michael Mayer
8de7fa35af CI: Add Instructions for GitHub Copilot
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-14 20:12:15 +02:00
Michael Mayer
970a0a190e Config: Improve site-url and internal-url usage descriptions #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-14 14:51:23 +02:00
Michael Mayer
f0b9faac8b Setup: Fix typo in WEBUI_URL example
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-13 15:21:57 +02:00
Michael Mayer
023fbe3a1d Pkg: Add service/cluster package & rename media/http → service/http #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-13 12:58:28 +02:00
Michael Mayer
3f11165f61 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-13 04:12:10 +02:00
Michael Mayer
c36e66c847 Config: Add fs.ExtYml file extension const for transitioning to ".yaml"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-13 02:09:22 +02:00
Michael Mayer
dbf0fa6c25 Scripts: Add dist/install-codex.sh and update Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-13 01:23:50 +02:00
Michael Mayer
4ea628af5c Dev: Update Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 23:40:37 +02:00
Michael Mayer
cd81094d25 Setup: Add "open-webui" service to compose.yaml config examples
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 16:13:17 +02:00
graciousgrey
11c7d9f7af API: Improve swagger annotations 2025-09-12 15:46:49 +02:00
Michael Mayer
64da1d36ed AI: Fix "photoprism-vision" service in compose.yaml (development only)
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 15:29:52 +02:00
Michael Mayer
e45a23f9a4 AI: Add "open-webui" service to compose.yaml (development only)
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 15:28:59 +02:00
Michael Mayer
cc93144bcb Develop: Upgrade base image from 250907-plucky to 250912-plucky
Includes additional CLI tool packages for development.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 14:06:48 +02:00
Michael Mayer
7ff62e0194 Config: Update flags and options for cluster configuration #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 13:52:37 +02:00
Michael Mayer
ce6546c635 Docker: Update env variables in compose.yaml files (development only)
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 13:15:52 +02:00
Michael Mayer
b894079f62 Dev: Reformat Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 13:11:52 +02:00
Michael Mayer
7bed1cd46a Dev: Update "dep-codex" target in Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 13:11:03 +02:00
Michael Mayer
886794874d Docs: Update AGENTS.md file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 13:10:26 +02:00
Michael Mayer
55755f6ede Dev: Add ".local" to ignore files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 13:10:07 +02:00
Michael Mayer
acdf91d668 Dockerfiles: Add system packages for the development environment
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 13:07:53 +02:00
Michael Mayer
f84bfbefaa Docker: Update Dockerfiles for development base images
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 11:38:32 +02:00
Michael Mayer
9d79f448bd Docs: Update AGENTS.md file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 11:34:56 +02:00
Michael Mayer
3f519b7a87 Docker: Update compose.yaml files for development environment
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 11:17:41 +02:00
Michael Mayer
cdbd6a9fb6 Dev: Update .gitignore and .dockerignore files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 11:16:35 +02:00
Michael Mayer
aaf222e29b Docs: Update AGENTS.md file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 10:49:48 +02:00
Michael Mayer
29dcf7070c Docs: Update AGENTS.md file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 10:35:57 +02:00
Michael Mayer
9bb323f965 Docs: Update AGENTS.md file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-12 10:26:48 +02:00
Michael Mayer
0d572032a9 API: Add GET /cluster/theme endpoint and refactor config package #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-11 06:47:45 +02:00
Michael Mayer
68d387778e Frontend: Harden NPM usage and add version overrides to package.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 12:56:40 +02:00
Michael Mayer
71f5bab407 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 11:24:37 +02:00
Michael Mayer
08616ae426 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 11:24:14 +02:00
graciousgrey
5ee5974188 AI: Increase vision client timeout 2025-09-09 10:56:12 +02:00
Michael Mayer
ea5dd3c002 Develop: Add a note about the naming of photoprism binaries to AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 09:55:36 +02:00
Michael Mayer
28b9c39f1b Develop: Update AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 09:10:53 +02:00
Michael Mayer
f948cd4efb Develop: Update Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 05:21:38 +02:00
Michael Mayer
a806ef8d71 Develop: Update tips for watching frontend changes in AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 04:44:50 +02:00
Michael Mayer
c27052a735 Develop: Add Docker Compose examples in AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 04:40:20 +02:00
Michael Mayer
4f3b694164 Develop: Improve Docker Compose examples in AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 04:28:37 +02:00
Michael Mayer
634445fb97 Develop: Add docker compose logs -f example to AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 04:25:22 +02:00
Michael Mayer
6cdca39fad Develop: Add a note about Windows to AGENTS.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 04:18:29 +02:00
Michael Mayer
6a57daffb4 Develop: Refine examples and context in AGENTS.md file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 04:10:46 +02:00
Michael Mayer
13730174fe Develop: Add/update "help" and "list" targets in Makefiles
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 03:36:37 +02:00
Michael Mayer
632cc1f425 Develop: Update AGENTS.md file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 02:44:19 +02:00
Michael Mayer
f0df9d2c88 Develop: Shorten AGENTS.md file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 02:30:11 +02:00
Michael Mayer
5afc09ecaf Develop: Add AGENTS.md file
Provides guidelines and context for coding agents:
- https://agents.md/
- https://agentsmd.net/

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-09 02:24:14 +02:00
graciousgrey
cc0661eff6 AI: Improve rules.yml 2025-09-08 10:16:25 +02:00
Michael Mayer
a6f66127fb Config: Update Progressive Web App (PWA) flag usage and defaults
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-07 22:03:05 +02:00
Michael Mayer
7d3978cfd4 UX: Update Default and Lightbox themes in frontend/src/options/themes.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-07 19:29:12 +02:00
Michael Mayer
e7d4bc509d Frontend: Update deps in package.json and package-lock.json #5014 #5087
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-07 16:25:48 +02:00
Michael Mayer
d44b85a0df Frontend: Update src/locales/json/fr.json #5196
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-07 16:08:01 +02:00
Michael Mayer
b0c3572432 Backend: Refactor function calls with missing params... after Go update
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-07 16:02:54 +02:00
Michael Mayer
cb9ada8478 Develop: Upgrade base image from 250822-plucky to 250907-plucky
Includes Go v1.25.1

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-07 15:30:17 +02:00
Ömer Duran
95c6743b2c
Tests: Remove Karma / Mocha and switch to Vitest #4995 #5014 #5087
* Tests: Remove unused Karma configuration and test files

This commit deletes the Karma configuration file and  test files that are no longer needed

* Tests: Refactor setup file for Vitest and remove legacy vue-setup.js

* Tests: Update truncate test case to use Vitest string

* Tests: Add unit tests for PLocationInput component using Vitest

* Tests: Improve unit tests for PLoadingBar component

* Tests: Move karma test to vitest

* Frontend: Update deps in package-lock.json

* Tests: Adapt test to vitest

* Tests: Refactor Makefile and package.json for test commands
2025-09-07 15:29:01 +02:00
Michael Mayer
22863b8b0f Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-07 14:58:55 +02:00
Michael Mayer
351c3688b8
Merge pull request #5196 from photoprismci/weblate-photoprism-frontend 2025-09-04 20:25:20 +02:00
Weblate
95ac440d28 Weblate: Update frontend translations 2025-09-04 18:02:04 +00:00
Michael Mayer
2e3d187938 API: Update swagger.json endpoint documentation
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-03 16:34:32 +02:00
Michael Mayer
e7e49c3644 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-03 16:33:29 +02:00
Michael Mayer
f2ec047c85 Frontend: Update *.json translation files in src/locales/json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-03 16:18:24 +02:00
Weblate
9545cd8a3e Weblate: Update frontend translations 2025-09-03 16:17:26 +02:00
Michael Mayer
34c66ebfdd Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-03 16:13:14 +02:00
Michael Mayer
22d7e65f3f Frontend: Refactor source name translations in the edit dialog
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-03 16:11:53 +02:00
Michael Mayer
f5a4aacc5c Videos: Log ffmpeg command in debug mode #5189
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-03 11:48:06 +02:00
Michael Mayer
c36bb566af Videos: Refine still image extraction with ffmpeg #5189
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-03 11:44:09 +02:00
Michael Mayer
a88580af7c AI: Update compose.yaml config examples #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-02 11:06:11 +02:00
Michael Mayer
9ea676c7e5 AI: Add "photoprism vision sources" CLI command #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-02 11:01:52 +02:00
Michael Mayer
2dc82bfa48 Videos: Improve log message when image extraction fails #5189
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 18:12:12 +02:00
Michael Mayer
ff2c3b9559 Videos: Skip non-keyframes when extracting images with FFmpeg #5189
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 18:02:23 +02:00
Michael Mayer
a0b44b2ca2 Setup: Update Ollama service examples in compose.yaml files #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 16:03:27 +02:00
Michael Mayer
c3537b10e5 AI: Use "gemma3" as default caption model #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 14:54:49 +02:00
Keith Martin
aa6c62abcb
Search: Add escaping capability for the characters "|" and "&" #5188
* Backend: Add query escape capability
* Tests: escape capability verification
* Backend: Clean up comments and remove commented out code.
2025-09-01 14:00:26 +02:00
Michael Mayer
19fff8b0bf Setup: Update Ollama service examples in compose.yaml files #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 13:07:22 +02:00
Michael Mayer
fccdc50e6e AI: Update ApiRequestOptions in internal/ai/vision/api_request.go #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 12:21:38 +02:00
Michael Mayer
7de8ee88d8 Setup: Update Ollama service examples in compose.yaml files #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 12:08:33 +02:00
Michael Mayer
2c17b21569 AI: Update caption model defaults to work with Ollama #127 #5123 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 11:18:28 +02:00
Michael Mayer
09e8a15a7f AI: Update testdata/vision.yml #127 #5123 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 10:52:50 +02:00
Michael Mayer
6c61eb5010 AI: Change Ollama caption default prompt #127 #5123 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 10:51:50 +02:00
Michael Mayer
6766cc330d AI: Add Ollama options to model configuration #127 #5123 #5011
This also renames the Meta option to TensorFlow so it is clear these
values are to configure TensorFlow models only.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 10:13:16 +02:00
Michael Mayer
b887ef9aed Config: Refactor options and command flags
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 10:04:05 +02:00
Michael Mayer
de4b8b9539 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 10:02:04 +02:00
Michael Mayer
8241f1c559 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-09-01 10:01:44 +02:00
Jarrad Whitaker
fc37974015 pull out interopindex/icc stuff to func, avoid clobbering existing profile 2025-08-30 19:25:55 +10:00
Jarrad Whitaker
2f5cc62d45 rename adobe rgb icc profile 2025-08-30 19:25:55 +10:00
Jarrad Whitaker
229df02bfb warn -> debug 2025-08-29 22:41:44 +10:00
Michael Mayer
fd6216ad3a CLI: Update command flag description in migrations.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-29 10:03:22 +02:00
Jarrad Whitaker
69c1c37197 tweak interopindex -> icc, fix typo, more comments 2025-08-29 10:55:52 +10:00
Jarrad Whitaker
ac3d5a0c58 move colors/icc into thumbs/icc + asets 2025-08-29 10:55:52 +10:00
Jarrad Whitaker
b5ed90d0cf bump licence of image 2025-08-29 10:23:04 +10:00
Jarrad Whitaker
ad5d15887d embed ICC profile into thumbs with InteroperabilityIndex=R03 2025-08-29 10:23:04 +10:00
Michael Mayer
a8dd73737f CLI: Update command flag usage descriptions
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 19:36:08 +02:00
Michael Mayer
619949ffc1 CLI: Update usage description of "backup-database" flag
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 19:29:20 +02:00
Michael Mayer
0357bc9abd CLI: Update usage descriptions for Boolean command flags
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 19:10:36 +02:00
Michael Mayer
68590ab408 API: Update metrics endpoint swagger documentation #213
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 16:16:42 +02:00
Michael Mayer
27d6834a22 Thumbs: Update package config, add IccProfilesPath & ExamplesPath #5178
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 15:39:12 +02:00
Michael Mayer
1b437c38f4 Auth: Add portal resource grants #98
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 12:14:50 +02:00
graciousgrey
5b61fe3782 Tests: Improve unit test to be case-insensitive 2025-08-28 11:42:18 +02:00
Michael Mayer
7bebf3bd60 API: Update swagger endpoint documentation #5133
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 11:20:00 +02:00
Michael Mayer
0823dceab1 API: Update swagger endpoint documentation #5133
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 11:13:28 +02:00
Michael Mayer
8337eb268c API: Update swagger endpoint documentation #5133
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 11:00:19 +02:00
Michael Mayer
b1eda7abe1 API: Update swagger endpoint documentation #5133
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 10:56:30 +02:00
Michael Mayer
cfe1bf62fd Backend: Update github.com/stretchr/testify in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 09:54:32 +02:00
Michael Mayer
45e998d941 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 09:54:11 +02:00
Michael Mayer
0cb4acbc20 Develop: Add "traefik.docker.network" label to compose.yaml files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-28 09:52:44 +02:00
Michael Mayer
a1ea21161b API: Update swagger endpoint documentation
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-27 17:16:03 +02:00
Michael Mayer
e9fca94656 API: Update swagger endpoint documentation
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-27 17:08:06 +02:00
Michael Mayer
2e15e1868f API: Update swagger endpoint documentation
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-27 16:57:02 +02:00
Michael Mayer
9980cf5bdc AI: Reduce vision API client timeout from 10 to 5 minutes
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-27 09:54:37 +02:00
Michael Mayer
6e50ef0135 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-26 08:58:38 +02:00
Michael Mayer
09ce6c77de Develop: Update .gitignore
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-26 08:56:03 +02:00
Michael Mayer
16dc286976 Develop: Add Docker Compose "down" target to Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-26 08:54:52 +02:00
Michael Mayer
46683a155c Backend: Upgrade Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-26 08:54:17 +02:00
Michael Mayer
7470924a84 Develop: Add upload config options to compose.yaml files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-26 08:44:37 +02:00
Michael Mayer
8a976825bf Develop: Add start-traefik and stop-traefik targets to Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-25 09:45:45 +02:00
Keith Martin
e80c1e1df7
Docker: Ensure that cmd.sh terminates its child processes when the parent script closes #5172
* Scripts: Ensure that child processes are terminated when parent script closes
* Scripts: Exclude pgrep process id from kill
2025-08-24 12:44:38 +02:00
Michael Mayer
c7e71bbbe2 CLI: Refactor photoprism/dl test suite
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-23 14:31:39 +02:00
Michael Mayer
37908ca3b5 Develop: Upgrade base image from 250808-plucky to 250822-plucky
Includes the latest dependencies, such as Go v1.25.0.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-22 15:28:19 +02:00
Michael Mayer
2a8e991550 CLI: Skip remaining YouTube download tests until issues are resolved
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-22 15:08:24 +02:00
Michael Mayer
a55a4f8ae4 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-22 10:58:56 +02:00
Michael Mayer
eba9e89380 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-22 10:58:28 +02:00
Oleksandr Redko
589ed92904
Videos: Refactor slice to array conversion (#5150) 2025-08-22 10:55:28 +02:00
Michael Mayer
41804a262b CLI: Skip YouTube download tests until issues are resolved
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-20 13:17:50 +02:00
graciousgrey
597593f4ee Tests: Adapt fixtures to have valid slugs 2025-08-19 19:44:23 +02:00
Michael Mayer
e3e034cc68 Index: Refactor error logging to happen inside IndexRelated() #5166
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-19 12:31:43 +02:00
Michael Mayer
0bce60c046 Index: Improve logging when PDF documents cannot be indexed #5166
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-19 12:24:29 +02:00
Michael Mayer
13177b0c32 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-19 09:58:37 +02:00
Michael Mayer
af7983b77c Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-19 09:56:14 +02:00
Michael Mayer
4da369d8b8 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-16 16:47:07 +02:00
raystlin
519a6ab34a
AI: Add TensorFlow model shape detection #127 #5164
* AI: Added support for non BHWC models

Tensorflow models use BHWC by default, however, if we are using
converted models, we can find that the expected input is BCHW. Now the
input is configurable (although the restriction of being dimesion 4 is
still there) via Shape parameter on the input definition. Also, the
model instrospection will try to deduce the input shape from the model
signature.

* AI: Added more tests for enum parsing

ShapeComponent was missing from the tests

* AI: Modified external tests to the new url

The path has been moved from tensorflow/vision to tensorflow/models

* AI: Moved the builder to the model to reuse it

It should reduce the amount of allocations done

* AI: fixed errors after merge

Mainly incorrect paths and duplicated variables
2025-08-16 15:55:59 +02:00
Michael Mayer
2a7351ee9a Database Schema: Update internal/entity/schema/mariadb.sql
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-16 11:46:27 +02:00
Michael Mayer
ff00681137 Scripts: Add dist/export-help.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-15 22:47:15 +02:00
Michael Mayer
21c8b18bf0 API: Update internal/api/swagger.json #5133
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-13 16:16:35 +02:00
Michael Mayer
a7a41fe000 API: Add OPTIONS wildcard handler to serve CORS preflight requests #5133
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-13 15:59:38 +02:00
Michael Mayer
d47b38bc8b Server: Add standard liveness/readiness check endpoints
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-13 13:07:01 +02:00
Michael Mayer
52204ee246 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-13 13:02:20 +02:00
Michael Mayer
3d4e2bde49 Setup: Update compose.yaml examples
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-12 17:33:10 +02:00
Weblate
05a550aa8a Weblate: Update frontend translations 2025-08-12 16:45:00 +02:00
Michael Mayer
f55a7190fc Frontend: Update .json translation files #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-11 18:11:10 +02:00
Weblate
0f999703c3 Weblate: Update frontend translations 2025-08-11 18:09:31 +02:00
Michael Mayer
db3a2b0309 Frontend: Update .po translation files #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-11 18:07:36 +02:00
Weblate
39be3d7122 Weblate: Update frontend translations 2025-08-11 18:06:46 +02:00
Michael Mayer
db22069997 Frontend: Add "batch" source and translation to edit dialog #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-11 18:06:04 +02:00
Michael Mayer
745a0a3661 Batch Edit: Increase source priority of changes to 64 (like manual) #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-11 18:02:39 +02:00
Michael Mayer
242083080d AI: Increase timeout for API client requests from 1 to 10 minutes
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-10 20:34:54 +02:00
Michael Mayer
e7db7efc58 Frontend: Update install and update targets in Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-10 17:22:43 +02:00
Michael Mayer
dbfe4e5dc1 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-10 17:13:29 +02:00
Michael Mayer
a890f8da16 Backend: Update Go dependencies in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-10 14:42:29 +02:00
Michael Mayer
c22c5c0151 CLI: Update count flag usage in commands.go, find.go, and vision_run.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-10 14:41:51 +02:00
Michael Mayer
6655a66e8f Develop: Upgrade base image from 250805-plucky to 250808-plucky #127
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-08 19:25:43 +02:00
Michael Mayer
875880110b Build: Simplify assets/.buildignore file #127
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-08 19:09:17 +02:00
Michael Mayer
ab0bd1c732 Config: Change default vision model assets path to assets/models/ #127
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-08 19:06:56 +02:00
Michael Mayer
2b48fe20dd Frontend: Update src/locales/json/en.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-08 19:00:16 +02:00
Weblate
ca8490d048 Weblate: Update frontend translations 2025-08-08 10:32:43 +02:00
Michael Mayer
2b9a3c9924 Setup: Update compose.yaml config examples #5123
Related Documentation:
- https://github.com/photoprism/photoprism-docs/pull/203
- https://docs.photoprism.app/developer-guide/vision/caption-generation/

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-06 20:13:07 +02:00
graciousgrey
3c84771c01 AI: Update rules.yml to work with original ImageNet1k labels 2025-08-06 17:22:58 +02:00
Michael Mayer
a6d840056c Media: Log underlying error when MIME type detection fails #5149
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-06 09:59:38 +02:00
Michael Mayer
0d24ec5abb Develop: Create default network in custom compose YAML files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-05 11:12:01 +02:00
Michael Mayer
fb6d920b1b Develop: Upgrade base image from 250724-plucky to 250805-plucky #5149
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-05 11:10:48 +02:00
Michael Mayer
9c7c6c3d27 Docker: Preinstall "libmagic-mgc" package for media type detection #5149
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-05 10:56:29 +02:00
Michael Mayer
16ac7a9d11 Batch Edit: Add SrcBatch to internal/entity/src.go #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-05 10:09:46 +02:00
Michael Mayer
9388cb7f66 Backend: Update license NOTICE file #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-05 10:09:21 +02:00
Michael Mayer
29c70cb0a9 Backend: Update deps in go.mod and go.sum #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-05 10:07:38 +02:00
Michael Mayer
6a20ca45b5 Frontend: Update deps in package.json and package-lock.json #5081 #5087
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-05 10:05:54 +02:00
Michael Mayer
34065a6bf8 AI: Allow to use defaults when having a custom vision.yml #127 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-04 13:24:27 +02:00
Michael Mayer
b241fa621d AI: Refactor error logs in internal/ai packages #127 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-04 12:14:23 +02:00
Michael Mayer
b7dc81fe29 Frontend: Update deps in package.json and package-lock.json #5081 #5087
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-04 10:47:03 +02:00
Michael Mayer
f83d77e40a AI: Make built-in model names lowercase in internal/ai/vision #127 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-04 10:32:08 +02:00
Michael Mayer
3177a61f75 AI: Update log messages and tests in internal/ai/classify #127 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-04 10:31:39 +02:00
Michael Mayer
523605f7d7 AI: Update log messages in internal/ai/tensorflow/labels.go #127 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-04 10:08:03 +02:00
Michael Mayer
10fe7d2b40 AI: Make error messages lower case in ai/tensorflow/info.go #127 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-04 10:00:09 +02:00
Michael Mayer
75785ff2f3 Merge branch 'develop' into feature/custom-tf-model-127 2025-08-04 09:58:18 +02:00
Michael Mayer
f6c922be00 AI: Update inline comments in internal/ai/tensorflow/info.go #127 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-04 09:57:09 +02:00
Michael Mayer
a80bdf065f AI: Improve logging in "photoprism vision run" command #5011 #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-02 10:58:32 +02:00
Michael Mayer
977d06b560 AI: Fix logging in "photoprism vision run" command #5011 #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-02 10:47:20 +02:00
Michael Mayer
c2b4af2a3a AI: Improve "photoprism vision run" command #5011 #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-02 10:19:31 +02:00
Michael Mayer
fd3f6311d4 Backend: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-01 18:14:56 +02:00
Michael Mayer
5246677ffa Backend: Update deps in go.mod and go.sum #5011 #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-01 14:37:58 +02:00
Michael Mayer
6e955523b6 AI: Add "--count" flag to the photoprism vision run command #5011 #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-01 14:37:36 +02:00
Michael Mayer
1bd9bb9d0c Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-01 14:32:03 +02:00
Michael Mayer
98e9daf687 Server: Add "trusted-platform" config option
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-08-01 13:51:03 +02:00
Michael Mayer
31901ff2e3 Server: Add "proxy-ip-header" config option
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-29 13:16:14 +02:00
Michael Mayer
e5dcf23f0c Config: Add "trusted-proxy" defaults to pkg/media/http/header/cidr.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-29 12:11:05 +02:00
Michael Mayer
0f5b774b06 Scripts: Update dist/install-forward-dns.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-29 09:54:41 +02:00
Michael Mayer
34b71f800e Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-28 16:35:58 +02:00
Michael Mayer
2df90b45fa Scripts: Update dist/install-forward-dns.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-28 16:35:27 +02:00
Michael Mayer
8ea7494456 Scripts: Add dist/install-forward-dns.sh to set up a forward DNS service
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-27 12:44:47 +02:00
Michael Mayer
96137a849a Scripts: Add dist/install-k8s-tools.sh for managing Kubernetes clusters
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-27 09:20:53 +02:00
raystlin
aeba5bfc4c Added labels download to model_external_test
If a model needs to have its labels downloaded from another source, it
can now be added to the test information.
2025-07-26 22:27:20 +00:00
raystlin
eef76ded5f Added new params to vision models for completion
ResizeOperation and ColorChannelOrder, just to have them on the
examples.
2025-07-26 21:43:12 +00:00
raystlin
b4ac12c301 Merge branch 'develop' into feature/custom-tf-model-127 2025-07-26 21:24:05 +00:00
Michael Mayer
38cafb1c2b Scripts: Add dist/add-swap.sh to help configure swap on Linux
see https://docs.photoprism.app/getting-started/troubleshooting/docker

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-26 10:21:33 +02:00
raystlin
3b1e1bb32a Added tests for resize operations
And fixed a typo detected by using them.
2025-07-25 22:22:19 +00:00
raystlin
e704ccfc47 Merge branch 'develop' into feature/custom-tf-model-127 2025-07-25 21:22:28 +00:00
Michael Mayer
fe7af9ec91 Backend: Update deps in go.mod, go.sum, and license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-24 20:27:35 +02:00
Michael Mayer
8149d4c63a Setup: Update compose.yaml config examples #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-24 15:46:41 +02:00
Michael Mayer
fce72f01a2 Develop: Upgrade base image from 250709-plucky to 250724-plucky
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-24 15:40:09 +02:00
Michael Mayer
d622c4d214 Setup: Upgrade traefik image version from v3.4 to v3.5
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-24 15:17:17 +02:00
Michael Mayer
468080ec6d Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-24 14:55:36 +02:00
Michael Mayer
4c24973a24 Setup: Update compose.yaml examples and add ollama service #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-24 13:07:11 +02:00
Michael Mayer
9d5a5d848a Develop: Add .project, .vscode, and *.tmproj to .gitignore file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-23 02:32:44 +02:00
Michael Mayer
5a7c5613b1 CLI: Refactor internal/commands/reset.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-23 00:53:34 +02:00
Michael Mayer
4b5e3b574a Index: Improve generation, caching and logging of labels #5011 #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-22 22:09:00 +02:00
Michael Mayer
99159f072a Frontend: Update json translation files #1152 #5129
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-22 20:50:56 +02:00
Weblate
f0939094fc Weblate: Update frontend translations 2025-07-22 20:50:13 +02:00
Michael Mayer
a851e325dd Frontend: Update templates to always have a context for "Archive" #1152
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-22 20:48:16 +02:00
Michael Mayer
0ff2d0df5e Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-22 20:47:12 +02:00
Michael Mayer
f6d9ff8e43 Backend: Regenerate .po translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-22 20:09:21 +02:00
Michael Mayer
f1a33a5516 Frontend: Regenerate .po translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-22 20:09:08 +02:00
Michael Mayer
3dcc33260e Frontend: Update src/locale/json/ar.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-22 20:07:31 +02:00
Michael Mayer
7dd870fcf1 Scripts: Add Kustomize to dist/install-admin-tools.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-22 20:06:20 +02:00
graciousgrey
1afc7d955a Translations: Add context #1152 2025-07-22 17:10:52 +02:00
graciousgrey
b2d36b395b Tests: Add unit tests 2025-07-22 13:01:22 +02:00
Weblate
3448d1a635 Weblate: Update backend translations 2025-07-21 17:32:44 +02:00
Weblate
02ab8caef1 Weblate: Update frontend translations 2025-07-21 17:32:16 +02:00
Michael Mayer
da86263390 AI: Use defaults when returning classify label from response #5011 #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-21 12:19:55 +02:00
Michael Mayer
ae42af54d8 AI: Generate captions using the Ollama API #5011 #5123
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-21 10:43:49 +02:00
graciousgey
f67ba0e634 Tests: Adapt acceptance tests #465 2025-07-18 18:27:01 +02:00
raystlin
1912f17aaf Changed InputOrder to ColorChannelOrder
The previous name was not clear enough.
2025-07-17 21:26:50 +00:00
Michael Mayer
6a803a8614 Search: Improve camera and lens filter notes in form annotations #5113
https://docs.photoprism.app/user-guide/search/filters/#filter-reference
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-17 12:23:14 +02:00
Michael Mayer
57f4e39b33 Search: Improve type filter description in form annotations #5113
https://docs.photoprism.app/user-guide/search/filters/#filter-reference
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-17 12:15:00 +02:00
Michael Mayer
aa533ff7ef Search: Improve position filter descriptions in form annotations #5113
https://docs.photoprism.app/user-guide/search/filters/#filter-reference
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-17 12:03:29 +02:00
Michael Mayer
3ff0a30469 Metadata: Improve search filter and media type documentation #5113
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-17 11:55:20 +02:00
Michael Mayer
6cccef7ae8 Backend: Update deps in go.mod, go.sum, and license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-16 18:35:38 +02:00
Michael Mayer
c6f7a6f373 Frontend: Update deps in package-lock.json #5087
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-16 18:35:04 +02:00
Michael Mayer
ddd343d528 Frontend: Refactor user model and permission checks #5087
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-16 18:29:35 +02:00
Michael Mayer
c05fe19ba9 AI: Default to the 720x720 fit thumb for generating captions #3438 #5011
These changes also auto assign labels based on the generated captions.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-16 14:58:44 +02:00
graciousgrey
b608eae3e5 Tests: Add unit tests #683 2025-07-16 14:25:39 +02:00
graciousgrey
df61612d73 Tests: Add unit tests #5111 2025-07-16 14:13:15 +02:00
Michael Mayer
f7f403fef7 AI: Add link to qwen2.5vl release notes in vision/caption.go #3438 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-15 18:12:56 +02:00
Michael Mayer
1c5cea7683 Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-15 18:03:21 +02:00
Michael Mayer
2a7e06e35f Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-15 18:03:05 +02:00
raystlin
adc4dc0f74 Added new parameters to model input.
New parameters have been added to define the input of the models:
* ResizeOperation: by default center-crop was being performed, now it is
  configurable.
* InputOrder: by default RGB was being used as the order for the array
  values of the input tensor, now it can be configured.
* InputInterval has been changed to InputIntervals (an slice). This
  means that every channel can have its own interval conversion.
* InputInterval can define now stddev and mean, because sometimes
  instead of adjusting the interval, the stddev and mean of the training
data should be use.
2025-07-15 13:31:31 +00:00
Michael Mayer
4bc9cd6ca2 AI: Add "source" flag to the "photoprism vision run" command #3438 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-15 12:52:02 +02:00
Michael Mayer
eb8d2062a5 AI: Update caption prompt and replace existing captions #3438 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-15 11:23:03 +02:00
Michael Mayer
4e6e0d287b API: Add mock album and label items to batch edit form for testing #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-15 10:25:03 +02:00
Michael Mayer
546635f8b6 AI: Update photoprism vision default prompt for captioning #3438 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-15 05:13:33 +02:00
Michael Mayer
ff229e1bd0 AI: Update photoprism vision defaults for captioning #3438 #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-15 00:51:46 +02:00
Michael Mayer
e029a64632 AI: Update photoprism vision defaults for captioning #5011
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-14 23:32:00 +02:00
Michael Mayer
e2763c4aee Frontend: Update .po and .json translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-14 20:11:30 +02:00
Andres Hočevar
e24d8f532a Quickfix spanish locale 2025-07-14 20:09:42 +02:00
Weblate
2ad1466e06 Weblate: Update frontend translations 2025-07-14 20:09:18 +02:00
Michael Mayer
a571a228e6 Backend: Upgrade github.com/klauspost/cpuid/v2 in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-14 19:32:01 +02:00
Michael Mayer
f7a6b0fa6c Config: Add an option to disable the web user interface #5111
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-14 19:30:24 +02:00
Michael Mayer
88126e3e48 Search: Add "reverse" query param to sort results in reverse order #683
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-14 18:08:05 +02:00
Michael Mayer
66cd55461f API: Always send and expect "mixed" fields in batch edit endpoint #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-14 11:13:04 +02:00
Michael Mayer
65b8503f63 API: Allow batch edit fields to be empty in requests and responses #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-14 10:42:34 +02:00
Michael Mayer
6e859ceecb Frontend: Add inline code comments for clipboard use #5106
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-14 09:33:30 +02:00
Michael Mayer
2b4234da00 Frontend: Update .json translation files #5106
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-14 09:27:01 +02:00
Michael Mayer
28873182be Auth: Activate 2FA, even if the recovery code cannot be copied #5106
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-14 09:23:02 +02:00
Michael Mayer
a910795525 Setup: Update service image names for the Raspberry Pi #4414 #5100
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-11 16:36:36 +02:00
Michael Mayer
d5816e0f9f Setup: Update compose.yaml defaults for the Raspberry Pi #4414 #5100
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-11 16:30:59 +02:00
Michael Mayer
f1cfe8d406 Scripts: Refactor dist/heif-convert.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-11 12:00:05 +02:00
Michael Mayer
aca000854c Scripts: Add doctl CLI command to install-admin-tools.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-11 11:59:46 +02:00
Ömer Duran
312f8e10be
Raspberry Pi: Upgrade mariadb version in compose.yaml #4414 #5100
* Setup: Update mariadb version
* Setup: Remove unnecessary mariadbd from MariaDB container command
2025-07-11 11:58:33 +02:00
Michael Mayer
1fa7b455a1 Tests: Reformat .js test files with "npm run fmt" #5087
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-11 06:01:23 +02:00
Michael Mayer
86401086ba Frontend: Add ContentTypeMp4AvcHigh to common/media.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-11 06:00:06 +02:00
Michael Mayer
342519a518 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-11 03:33:59 +02:00
Michael Mayer
ad653db969 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-11 03:33:38 +02:00
Michael Mayer
675c2a3f95 Setup: Add build script for the PhotoPrismPi SD card image #4414
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-11 00:37:44 +02:00
Michael Mayer
78f5a48b0b Setup: Remove "Ofelia" from DigitalOcean app image docs #4414
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-10 22:08:38 +02:00
Michael Mayer
e6a1b54547 Setup: Reorganize config files for Raspberry Pi and DigitalOcean #4414
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-10 22:02:38 +02:00
Ömer Duran
287b921d4f
Setup: Update user-data for PhotoPrismPI #5099
* Setup: Update user-data for PhotoPrismPI
* Setup: Replaces '<your IP address>' with '<IP address>'
2025-07-10 16:49:08 +02:00
Michael Mayer
31614697a2 API: Update Swagger docs of batch edit endpoint #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-10 11:16:23 +02:00
Michael Mayer
2229ee32fb API: Add batch.PhotosResponse and update Swagger docs #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-10 11:08:17 +02:00
Michael Mayer
41dc0febba API: Rename album and label value to "items" in batch edit response #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-10 10:28:47 +02:00
Michael Mayer
50c345f0ad API: Add empty Albums and Labels to the batch edit response #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-10 10:18:01 +02:00
Michael Mayer
38da638f88 API: Improve logging of bad request errors across all endpoints #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-10 09:38:36 +02:00
Michael Mayer
6bfbad40af API: Add batch edit form validation error to gin.Context #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-10 09:06:11 +02:00
Michael Mayer
02ef7dbdee Develop: Upgrade base image from 250703-plucky to 250709-plucky
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-09 16:48:38 +02:00
Michael Mayer
845813d642 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-09 16:48:22 +02:00
graciousgrey
f99fee1fe7 Tests: Add unit tests #465 2025-07-09 14:57:32 +02:00
graciousgrey
ee443c066b Tests: Add unit tests #5089 2025-07-09 14:42:01 +02:00
graciousgrey
02109cf4e6 Tests: Add unit tests #5038 2025-07-09 14:42:01 +02:00
Michael Mayer
38e331a48d Intel QSV: Add libvpl2 if PHOTOPRISM_INIT is set to "intel" #4967 #5098
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-09 14:13:28 +02:00
Ömer Duran
61683015f2
Places: Refactor Adjust Location dialog to reuse the p-map component #465 #5097
* Places: refactor location dialog to reuse PMap component
* Places: Refactor map and location dialog components coordinate validation
* Places: Update map and location dialog components to use coordinates array for better validation
* Places: Rename coordinates prop to latlng in map and location components for consistency
* Places: Simplify latlng watcher
* Places: Map component with animation settings and handle missing style images
2025-07-09 13:26:26 +02:00
Michael Mayer
9ad5a533af Backend: Update github.com/golang/geo in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-08 10:41:03 +02:00
Michael Mayer
2481de49c4 API: Improve form and tests for POST /batch/photos/edit endpoint #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-08 10:40:45 +02:00
Michael Mayer
004feeb708 Index: Re-determine media types when "Complete Rescan" is selected #5096
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-07 17:22:15 +02:00
Michael Mayer
d28b3101e0 Build: Update .buildignore and .dockerignore files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-07 12:44:59 +02:00
Michael Mayer
8fcc2a232b Live Photos: Reset duration and improve type checks when indexing #5089
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-07 11:15:02 +02:00
Michael Mayer
5ad7f6318b Live Photos: Require video type MOV as sidecar for HEIC and JPEG #5089
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-06 14:04:15 +02:00
Michael Mayer
cedc8799d3 Places: Update compose.yaml config examples #883
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-06 11:24:50 +02:00
Michael Mayer
5860b01248 Live Photos: Delete pkg/media/video/live.go #5089
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-06 11:10:24 +02:00
Michael Mayer
f80ac62e6b Live Photos: Only flag actual Live and Motion Photos as "Live" #5089
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-06 11:07:25 +02:00
Michael Mayer
57349bdb99 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-06 11:04:34 +02:00
Michael Mayer
0fc3ec8183 Frontend: Update .json translation files #5089 #5092
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-06 11:02:58 +02:00
Weblate
b582133df7 Weblate: Update frontend translations 2025-07-06 11:00:25 +02:00
Michael Mayer
037c0351d9 Docs: Update internal/api/swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-06 10:58:31 +02:00
Michael Mayer
ff6151f84a Docs: Update license NOTICE files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-06 10:58:05 +02:00
Michael Mayer
3ff0ec01be Frontend: Add translations and update .po translation files #5089
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-06 10:57:12 +02:00
Michael Mayer
595b116ae6 Config: Update automatically generated docs for configuration options
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-04 10:51:13 +02:00
Michael Mayer
73374cb325 Backup: Do not delete old dumps when filename is set manually #5088
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-03 20:59:54 +02:00
Michael Mayer
77ac3b545f Darktable: Update install-darktable.sh script
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-03 20:38:02 +02:00
Michael Mayer
c49ba11288 Frontend: Reformat karma.conf.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-03 19:46:38 +02:00
Michael Mayer
395ee8426e Develop: Upgrade base image from 250630-plucky to 250703-plucky
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-03 19:34:44 +02:00
Michael Mayer
d43ec9492a Frontend: Update install-nodejs.sh script
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-03 19:27:30 +02:00
Michael Mayer
20a82df0e8 Frontend: Remove package eslint-plugin-promise
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-03 19:27:10 +02:00
Michael Mayer
55704fea58 Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-03 12:58:35 +02:00
Michael Mayer
02d8525ade Places: Add config option to specify location details locale #465 #883
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-03 12:58:20 +02:00
Michael Mayer
4b1cc5d424 API: Update swagger.json #465
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-02 20:45:22 +02:00
Michael Mayer
829611c37f API: Update Swagger docs for the /api/v1/places endpoints #465
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-02 20:42:48 +02:00
graciousgey
cb208bc09f Tests: Adapt acceptance tests to changes 2025-07-02 17:14:22 +02:00
Michael Mayer
24b7b03f7b CSS: Move embedded map styles to css/places.css #465 #5080 #5082
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-02 12:23:45 +02:00
Michael Mayer
1b4b478067 Frontend: Update translations in fr.json #5086
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-02 11:57:36 +02:00
Weblate
76f6f2d52f Weblate: Update frontend translations 2025-07-02 11:56:34 +02:00
Michael Mayer
5b152ac542 Metadata: Reset the day string value to 01 if exact day is unknown #5038
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-02 11:33:13 +02:00
Michael Mayer
d7298eeb80 Backend: Update github.com/golang/geo in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-02 11:07:13 +02:00
Michael Mayer
c18d04e104 Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-02 11:00:18 +02:00
Michael Mayer
8b5b06d116 API: Add unit tests for new /api/v1/places endpoints #465 #5080 #5082
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-02 10:59:07 +02:00
Michael Mayer
7fb447897e Location: Update .json frontend translation files #465 #5080 #5082
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-01 17:33:17 +02:00
Weblate
9c5470744f Weblate: Update frontend translations 2025-07-01 17:30:53 +02:00
Michael Mayer
bd4ca7b848 Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-01 17:28:46 +02:00
Michael Mayer
3a74db145a Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-01 17:28:33 +02:00
Michael Mayer
6bf5e03336 Backend: Regenerate assets/locales/js/default.po
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-01 17:27:27 +02:00
Michael Mayer
24025524ab Location: Update .po frontend translation files #465 #5080 #5082
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-01 17:27:08 +02:00
Michael Mayer
80ba7e9934 Location: Change "No results" message in dialog.vue #465 #5080 #5082
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-01 17:26:38 +02:00
Michael Mayer
a5c50b1301 Places: Refactor Location API, Dialog and Input #465 #5080 #5082
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-01 17:21:26 +02:00
Michael Mayer
318d38a1da Places: Round coordinates returned by s2.LatLng() #465 #5080
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-01 10:19:39 +02:00
Michael Mayer
08ae7b0229 Places: Add new package pkg/geo/latlng #465 #5080
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-07-01 10:12:54 +02:00
Ömer Duran
ee0f104262
UX: Refactor position dialog #465 #5082
* Places: Use $nextTick for state updates
* Places: Refactor duplicate code
2025-06-30 16:29:56 +02:00
Michael Mayer
a30c04bab6 UX: Adjust config of places search autocomplete component #465 #5080
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-30 10:21:04 +02:00
Ömer Duran
056c6f3917
UX: Replace v-menu with v-autocomplete and add loading state to apply button #465 #5080
* Places:  Replace v-menu with v-autocomplete for better search experience
* Places: Add loading state for location info retrieval
2025-06-30 09:38:01 +02:00
Michael Mayer
10f15431ff Videos: Set timestamps to zero when remuxing containers to MP4 #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-30 09:35:26 +02:00
Michael Mayer
1709f708ed Viewer: Disable video looping when seeking manually #1307 #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-30 09:35:26 +02:00
Michael Mayer
4475a8d914 Develop: Upgrade base image from 250608-plucky to 250630-plucky
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-30 09:35:26 +02:00
Simon Rettberg
00d1cddf37
Metadata: Update list of unwanted descriptions (#5078)
Signed-off-by: Simon Rettberg <simon.rettberg@rz.uni-freiburg.de>
2025-06-29 17:15:01 +02:00
Michael Mayer
a39c1d3248 Download: Skip Playlist test in dl_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-29 17:13:26 +02:00
Michael Mayer
dec24ece73 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-29 17:09:08 +02:00
Michael Mayer
fd33e54c20 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-29 17:08:06 +02:00
Michael Mayer
af3357bfdc Metadata: Update list of stop words in pkg/txt
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-29 17:07:05 +02:00
Michael Mayer
761cf6a47e Metadata: Refactor position input and dialog components #465 #5043 #5069
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-27 15:35:49 +02:00
Michael Mayer
7e2d55ece4 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-27 15:33:44 +02:00
Ömer Duran
0e66db223c
UX: Improve GPS position input and dialog components #465 #5069
* Places: Remove the close button for design consistency #465
* Places: Enhance coordinate input in photo edit details #465
* Places: Refactor layout in location dialog #465
* Places: Improve layout and styling in location dialog #465
* Places: Delete coordinate input formatting in photo edit details #465
* Places: Create reusable coordinate input component
2025-06-27 12:38:42 +02:00
Keith Martin
22e865c66a
SQLite: Fix "too many SQL variables" error when flagging pictures as hidden #3742 #5074
* Backend: Refactor update statement to resolve too many sql variables (retro fit from gorm2)
* Backend: Refactor subquery to gorm1 compliance
2025-06-27 12:28:50 +02:00
graciousgrey
3679c11c34 Scans: Add scan detection for epson scanner #5703 2025-06-26 11:42:22 +02:00
graciousgey
55575623c5 Tests: Adapt acceptance test #4999 2025-06-26 11:39:15 +02:00
graciousgrey
40df1d71cf Translations: Update fr.json 2025-06-26 09:25:05 +02:00
Weblate
c2d981e4d1 Weblate: Update frontend translations 2025-06-26 09:10:26 +02:00
Ömer Duran
aadde256eb
Setup: Add Cloud-Init configuration for the PhotoPrismPi SD image #4414 #5068
This adds initial cloud-init configuration files for the automatic installation of PhotoPrism on a Raspberry Pi. The files include metadata, network configuration, and an in-depth user-data script that installs Docker, configures paths, sets services, and prepares the system for PhotoPrism with Traefik and MariaDB.
2025-06-25 14:44:39 +02:00
Michael Mayer
60cb5684c2 UX: Redirect to the collection page when albums are deleted #4994
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-25 13:20:42 +02:00
Michael Mayer
8cef088bba Places: Refactor location input and dialog styles #465 #5043
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-25 04:20:57 +02:00
Michael Mayer
7a2cb27c1f Places: Refactor search and reverse API endpoint validation #465 #5043
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-25 03:07:50 +02:00
Michael Mayer
033cfc4922 Places: Refactor search and reverse API endpoints #465 #5043
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-25 00:43:31 +02:00
Michael Mayer
bcbbbcd7b3 Backend: Add WebLocale formatting function to clean package #465 #5043
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-25 00:03:41 +02:00
Ömer Duran
baa5f2d9a0
UX: Add a map for selecting locations in the Edit dialog #465 #5043
* Frontend: Map Dialog first version
* Frontend: Simplify street address handling and remove reset location control in map dialog
* Frontend: Enhance map undo functionality
* Frontend: Refactor location info handling to use backend API for reverse geocoding
* Frontend: Improve coordinate input handling
* Frontend: Adjust layout in photo details
* Frontend: Add feature to clear coordinates
* Frontend: Update button alignment
* Frontend: Implement place search feature in map dialog
2025-06-24 23:22:16 +02:00
Ömer Duran
7d1c453960
Setup: Update DigitalOcean Docker configuration (#4978)
* Setup: Update Digital Ocean Docker Image

* Setup: update digital ocean docs

* Setup: Update Docker CE version in cloud README

* Setup: Update Traefik version to 3.4

* Setup: Update software versions in DigitalOcean README
2025-06-24 22:54:18 +02:00
Michael Mayer
4dc703c855 Frontend: Regenerate .json translation files #4994 #4999 #5067
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-24 21:44:32 +02:00
Weblate
58ffaf1bfa Weblate: Update frontend translations 2025-06-24 21:43:57 +02:00
Michael Mayer
d1c6efa2b6 Frontend: Regenerate .po translation files #4994 #4999
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-24 21:36:02 +02:00
Michael Mayer
595e528258 UX: Refactor album toolbar menu and add "danger" theme color #4994 #4999
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-24 21:34:51 +02:00
Ömer Duran
95cb881f56
Albums: Add "Delete Album" action to the album toolbar menu #4994 #4999
* Frontend: Add "Delete Album" option to album toolbar #4994
* Frontend: Replace dialog with confirmation dialog in toolbar #4994
* Frontend: Refine visibility condition for "Delete Album" option in toolbar #4994
2025-06-24 20:44:25 +02:00
graciousgey
702b83870f Tests: Add test #5018 2025-06-24 17:52:36 +02:00
Michael Mayer
e201e27842 Frontend: Update test deps and scripts in package.json #5014
This removes the "test-" prefix from vitest script targets.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-24 12:59:17 +02:00
Michael Mayer
a965c32188 Backend: Upgrade github.com/olekukonko/tablewriter from v0.0.5 to v1.0.7
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-24 12:48:38 +02:00
graciousgrey
982f864cc0 Translations: Update cs.json 2025-06-24 11:19:01 +02:00
Weblate
b054a1e09a Weblate: Update frontend translations 2025-06-24 11:01:20 +02:00
findnature
b3bdd5d8ce
Media: Replace sort.Slice with slices.Sort for natural ordering (#4981)
Signed-off-by: findnature <cricis@aliyun.com>
2025-06-23 15:38:55 +02:00
Michael Mayer
47f9a509b1 Backend: Update dependencies in go.mod and go.sum #5042
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-23 15:34:33 +02:00
graciousgrey
a49181f75d Tests: Skip unstable test #5014 2025-06-23 15:33:05 +02:00
Brandon Richardson
1d8fa4e3ea
Backend: Set content-type on metrics endpoints (#5042)
The prometheus text format requires metrics endpoints respond with the
content-type 'text/plain; version=0.0.4'. Without this, newer versions
of prometheus fail to scrape the metrics endpoint and report an error.
It's possible to work around this by setting the
'fallback_scrape_protocol' setting in the prometheus scrape target
configuration, but this revision sets the content type appropriately to
avoid this in the first place.
2025-06-23 15:32:01 +02:00
Michael Mayer
758d86f903 Frontend: Update test deps in package.json and license NOTICE #5014
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-20 16:39:38 +02:00
Ömer Duran
a82d657b6b
Frontend: Convert tests from mocha to vitest #5014
* Tests: convert all common tests from mocha to karma

* Tests: refactor Vuetify setup in tests

* Tests: update package-lock.json

* Tests: convert all model test to vitest 1/2

* Tests: convert all model test to vitest 2/2

* Tests: fix broken test

* Tests: time zone UTC

* Tests: Add playwright screenshots folder to gitignore

* Tests: Add timezone to vitest scripts

* Tests: Add Vitest scripts to Makefile

* Tests: delete unused timezone configs

* Tests: Update some tests

* Tests: Update vitest config

* Tests: Delete usesless try-catch
2025-06-20 16:28:26 +02:00
Ömer Duran
985e2febf4
Fix: timezone handling in sidebar component (#5015) 2025-06-20 01:22:39 +02:00
Michael Mayer
40be3cc290 Backend: Fix typo in inline function documentation #5059
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-20 01:19:49 +02:00
Michael Mayer
087594161e Frontend: Update *.json translation files #5061
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-19 20:13:38 +02:00
Weblate
a9d0f3e9a4 Weblate: Update frontend translations 2025-06-19 20:12:26 +02:00
Michael Mayer
44c85a8a46 Docs: Update license NOTICE files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-19 20:06:49 +02:00
Michael Mayer
55b8042c98 Auth: Update ACL grants and actions
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-19 20:04:33 +02:00
Michael Mayer
2596fe0252 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-19 18:37:35 +02:00
Michael Mayer
1e89fa5d32 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-19 18:37:07 +02:00
Michael Mayer
7d05ecab9a Frontend: Add .overflow-hidden style to css/layout.css #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-19 17:40:52 +02:00
graciousgrey
f7218f67e2 Classify: Improve rules.yml #5057 2025-06-19 09:14:02 +02:00
graciousgey
cdcfc69e05 Tests: Refactor acceptance tests 2025-06-17 20:20:48 +02:00
Michael Mayer
d57ee7b7ab Header: Add "Content-Language" const
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-12 02:30:48 +02:00
Michael Mayer
fd056913d8 Frontend: Improve user interface styles
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-12 00:32:58 +02:00
Michael Mayer
c8ce9ec772 Videos: Extract embedded metadata with ExifTool #4982 #4892 #5040
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-11 21:49:02 +02:00
Michael Mayer
6a65f86bf9 Frontend: Improve user interface styles
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-11 21:11:53 +02:00
Michael Mayer
42a22f1377 M2TS: Improve inline code docs #4982 #4892 #5040
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-11 19:26:43 +02:00
Michael Mayer
86fe4404ef M2TS: Extract embedded metadata with ExifTool #4982 #4892 #5040
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-11 19:22:20 +02:00
Michael Mayer
6fa0ab4734 Setup: Update inline docs in compose.yaml config examples #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-11 10:58:18 +02:00
Michael Mayer
7759aad68f Videos: Auto-install/update yt-dlp in the dev environment #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-11 10:54:09 +02:00
Michael Mayer
47a4d1ab0a Docs: Update license NOTICE files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-10 14:31:04 +02:00
Michael Mayer
38c8fec985 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-10 14:29:46 +02:00
Michael Mayer
e9a76efc3b Videos: Update yt-dlp when building new Docker images #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-10 14:27:03 +02:00
Michael Mayer
cf7aaa5059 Videos: Add "update-yt-dlp" init target to scripts/dist/Makefile #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-10 14:22:07 +02:00
Michael Mayer
dc265085a8 WebDAV: Add "/import/" path check to internal/service/heuristic.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-10 14:02:57 +02:00
Michael Mayer
03f5bb322d Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-10 14:01:47 +02:00
Michael Mayer
2e2ebab433 Videos: Improve downloading, remuxing, and transcoding #4982 #4892 #5040
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-06-09 15:31:23 +02:00
graciousgrey
a45d9d30b9 Update SPONSORS.md 2025-06-09 15:15:13 +02:00
graciousgrey
7a1929797c Translations: Update fr.po 2025-06-07 08:51:18 +02:00
Weblate
1ac9a8a3bf Weblate: Update frontend translations 2025-06-07 08:23:22 +02:00
graciousgrey
f98f2bcc8e Translations: Update hu.json and zh.json 2025-05-26 11:58:17 +02:00
Weblate
eda33e2032 Weblate: Update frontend translations 2025-05-26 11:46:53 +02:00
graciousgey
cf9258949a Tests: Adapt acceptance tests to be more stable 2025-05-25 11:26:56 +02:00
Michael Mayer
ae530fec1b CLI: Force overwrite of existing video and metadata downloads #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-25 07:03:35 +02:00
Michael Mayer
3bcc415c06 Frontend: Update package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-25 01:47:02 +02:00
Michael Mayer
72fdd05358 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-25 01:41:28 +02:00
Michael Mayer
798c77464e Develop: Upgrade base image from 250507-plucky to 250524-plucky #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-25 01:40:13 +02:00
Michael Mayer
69600fdbe3 Video Downloads: Update test video URL #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-25 01:33:59 +02:00
Michael Mayer
03dba1fe20 Video Downloads: Set --playlist-index and --embed-metadata flags #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-25 01:20:59 +02:00
graciousgrey
2499b13f51 Tests: Add unit tests #271 2025-05-21 13:16:11 +02:00
raystlin
c682a94a07 Updated vision.yml testdata
This version adds the new fields to the test configuration
2025-05-18 11:08:34 +00:00
raystlin
f28f3d1a07 Fixed format on model_external_test
make fmt-go was applied
2025-05-18 11:06:34 +00:00
graciousgey
af832247fc Tests: Update testcafe timeouts 2025-05-16 16:48:55 +02:00
Michael Mayer
a5aef038ef Batch Edit: Fix PhotoLng.Mixed flag in form/batch/photos.go #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-15 16:37:28 +02:00
graciousgey
fce886f077 Tests: Refactor page model for more stability 2025-05-15 08:57:50 +02:00
raystlin
7214479bc4 Merge remote-tracking branch 'upstream/develop' into feature/custom-tf-model-127 2025-05-14 21:08:35 +00:00
graciousgrey
876a421ad7 Frontend: Update ja.json 2025-05-14 14:18:44 +02:00
Weblate
8292f97469 Weblate: Update backend translations 2025-05-14 13:12:48 +02:00
Weblate
f5ee512a70 Weblate: Update frontend translations 2025-05-14 13:12:21 +02:00
graciousgrey
0ecc08750b Tests: Update test commands 2025-05-14 10:58:49 +02:00
Michael Mayer
4326523194 GitHub: Update PULL_REQUEST_TEMPLATE.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-13 14:36:55 +02:00
Michael Mayer
465245eb85 GitHub: Update PULL_REQUEST_TEMPLATE.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-13 14:30:55 +02:00
Ömer Duran
7ab90720ff
Tests: write Initial Tests for .vue Components (#5003)
* Tests: Add initial Vue component tests
* Tests: Update package scripts
2025-05-13 11:53:17 +02:00
Michael Mayer
b642be2c91 API: Update swagger.json endpoint documentation #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-13 11:34:23 +02:00
Michael Mayer
cfc8bac26f Batch Edit: Return -2 for mixed CameraID and LensID values #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-13 11:08:04 +02:00
Michael Mayer
e754af0e08 Batch Edit: Return -2 for mixed day, month, and year values #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-13 10:50:47 +02:00
Michael Mayer
bf37bf44c7 API: Update swagger.json endpoint documentation #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-13 10:24:17 +02:00
Michael Mayer
9a39adebae API: Refactor /batch/photos/edit endpoint to return "models" #271
The "photos" array in the response has been renamed to "models". This
data is now always returned, so using the "return" flag in the request
is no longer necessary.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-13 10:22:35 +02:00
Michael Mayer
bdaab4b412 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-13 10:09:27 +02:00
Michael Mayer
e89efc9d39 Clean: Add version assertions to version_test.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-13 10:06:07 +02:00
raystlin
05808241b9 Fix AI Faces test.
The test was broken because of the new parameters
2025-05-12 18:48:42 +00:00
raystlin
38956e0f4a Merge remote-tracking branch 'upstream/develop' into feature/custom-tf-model-127 2025-05-12 18:46:57 +00:00
Michael Mayer
699cff429c GitHub: Update PULL_REQUEST_TEMPLATE.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-10 12:05:48 +02:00
Michael Mayer
f6908837ee Vision Client: Allow a custom prompt to be included in requests
see https://github.com/photoprism/photoprism-vision/issues/11

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-09 18:59:28 +02:00
Michael Mayer
9c16bb11b8 GitHub: Update PULL_REQUEST_TEMPLATE.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-09 10:05:36 +02:00
graciousgrey
e02f543808 Frontend: Open thumb fromPhotos on the labels tab 2025-05-08 13:02:33 +02:00
Michael Mayer
0e74afa358 GitHub: Update PULL_REQUEST_TEMPLATE.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-08 05:31:58 +02:00
Michael Mayer
53d43f7933 GitHub: Update PULL_REQUEST_TEMPLATE.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-08 04:51:50 +02:00
Michael Mayer
0597269fc4 GitHub: Update PULL_REQUEST_TEMPLATE.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-08 04:49:23 +02:00
Michael Mayer
1554d52b00 Frontend: Update yaml dep in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-08 01:38:37 +02:00
Michael Mayer
3c09bb9475 Frontend: Update babel deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-08 01:35:59 +02:00
Michael Mayer
43238cf6e4 Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-08 01:22:18 +02:00
Michael Mayer
7958239f7e Vision Client: Add configured model version to request data #1090
also see https://github.com/photoprism/photoprism-vision/issues/1

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-08 01:19:13 +02:00
Michael Mayer
2eb731e721 Develop: Update GPU device count in compose.nvidia.yaml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-08 00:24:34 +02:00
Michael Mayer
ade2c5e269 Develop: Upgrade base image from 250505-plucky to 250507-plucky
The new image includes updated dependencies such as Go v1.24.3.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-08 00:22:22 +02:00
graciousgrey
2ddfa5c9a1 Tests: Add unit tests #4947 2025-05-07 15:00:09 +02:00
graciousgrey
1a794da1fe Tests: Add unit tests #4969 2025-05-07 12:03:50 +02:00
Michael Mayer
dd1f3b820f Frontend: Update fr.json and ja.json translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-06 17:01:32 +02:00
Cathie Integra
39e8b5b9ad
Weblate: Update frontend translations (#4993)
Co-authored-by: Weblate <noreply@weblate.org>
2025-05-06 17:00:31 +02:00
graciousgrey
cccb0ca00a Tests: Add unit tests 2025-05-06 16:52:02 +02:00
Michael Mayer
ade59eebf0 Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-06 16:23:41 +02:00
Michael Mayer
7b2a9a11c3 Backend: Update dependencies in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-06 16:23:22 +02:00
Michael Mayer
2e626b8221 Backend: Run fmt-go to format photos_test.go and selection_test.go #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-06 16:22:51 +02:00
Ömer Duran
4f04ffe133
Frontend: Integrate Vitest test framework #4990
- Includes fixtures and mocks system for API and models as well as npm scripts for running tests, watch mode, coverage and UI
- Adds test setup with JSDOM environment and utility function tests
- Converts marker model tests from Mocha/Chai to Vitest
2025-05-06 16:18:39 +02:00
Michael Mayer
b5d2d1c7fb Makefile: Remove "docker-" prefix from nvidia and intel targets
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-06 16:02:08 +02:00
Cathie Integra
d18be7e76c
Weblate: Update frontend translations (#4991)
Co-authored-by: Weblate <noreply@weblate.org>
2025-05-06 15:32:31 +02:00
Michael Mayer
2787059411 GitHub: Update question.md and PULL_REQUEST_TEMPLATE.md templates
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-06 15:07:59 +02:00
graciousgrey
5e4d258860 Tests: Add unit tests #271 2025-05-06 14:45:58 +02:00
graciousgrey
79b6a75703 API: Add security definitions to swagger annotations 2025-05-05 16:50:33 +02:00
Michael Mayer
723dee6620 Develop: Upgrade base image from 250502-plucky to 250505-plucky #4979
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 12:23:00 +02:00
Michael Mayer
cbcee62444 Dist: Update install-tensorflow.sh script #4979
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 11:57:54 +02:00
Michael Mayer
4349087272 Entity: Use Db() instead of UnscopedDb() in details_fixtures.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 11:17:11 +02:00
Michael Mayer
83717bda02 TensorFlow 2: Build AMD64 binaries for generic x86-64 march #4979
see https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 10:57:01 +02:00
Michael Mayer
333c54f3a2 TensorFlow 2: Build AMD64 binaries with "nocona" compatibility #4979
see https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 10:46:22 +02:00
Michael Mayer
80e6d02509 TensorFlow 2: Build AMD64 binaries with Prescott compatibility #4979
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 10:41:58 +02:00
Michael Mayer
4484b885d4 TensorFlow 2: Update docker/tensorflow/Makefile #4979
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 10:33:49 +02:00
Michael Mayer
2b788fd258 TensorFlow 2: Build AMD64 binaries with Pentium 4 compatibility #4979
see https://github.com/photoprism/photoprism/discussions/4979

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 10:32:32 +02:00
Michael Mayer
c4ddc4a119 API: Remove unused Filter property from batch request forms #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 09:25:52 +02:00
Michael Mayer
3d325015af Setup: Update nvidia/compose.yaml configuration example #4986
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 09:06:17 +02:00
Michael Mayer
f50bae84b1 Develop: Update compose.nvidia.yaml and compose.intel.yaml #4986
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 09:05:55 +02:00
Michael Mayer
a55b3ecc9c Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 08:57:39 +02:00
Michael Mayer
6bd86d6032 Develop: Update compose.nvidia.yaml configuration #4986
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 08:57:24 +02:00
Michael Mayer
ca843987f7 Setup: Update compose.yaml configuration examples #4986
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-05 07:40:21 +02:00
Michael Mayer
fdea09518c UX: Remove transition from "scroll to top" button for faster rendering
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-04 16:00:06 +02:00
Michael Mayer
b6d031a4ba API: Omit markers when serializing JSON search results #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-04 15:09:40 +02:00
Michael Mayer
3d730884ce Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-04 14:33:33 +02:00
Michael Mayer
b20f9d6e50 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-04 14:32:32 +02:00
Michael Mayer
5973aeca5f Backend: Update dependencies in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-04 14:31:09 +02:00
Michael Mayer
dd6e17e97e API: Rename /batch/photos endpoint to /batch/photos/edit #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-04 14:09:23 +02:00
Michael Mayer
b423b1980b API: Add /batch/photos endpoint to get metadata of selected photos #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-03 12:43:01 +02:00
graciousgrey
43ff8b2a8d Tests: Add unit tests 2025-05-03 10:25:58 +02:00
Michael Mayer
c80f703ecd UX: Maintain scroll position when refreshing search results #4985
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-03 10:05:53 +02:00
Michael Mayer
bd4b7b3ad3 API: Update swagger.json endpoint documentation
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-03 09:30:42 +02:00
Michael Mayer
6f3f1fd392 Backend: Update dependencies in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-03 09:29:41 +02:00
Michael Mayer
6b4a32a1b3 UX: Optimize generation of thumbnail image URL in photo.js #4985
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-03 09:25:55 +02:00
Michael Mayer
033a956e21 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-03 09:12:57 +02:00
graciousgey
a23058ce4b Tests: Refactor acceptance tests 2025-05-02 18:44:32 +02:00
graciousgrey
b61f3063d9 Tests: Add unit tests #4973 2025-05-02 18:39:40 +02:00
Michael Mayer
d530ab4f23 Frontend: Regenerate translation .po files #4980
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-02 14:32:33 +02:00
Michael Mayer
4677579f9a i18n: Change locale "ja_JP" to "ja", so it matches the filename #4980
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-02 14:30:37 +02:00
Michael Mayer
4a992dc350 CLI: Add image, vector, raw, pdf, and audio support to dl command #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-02 13:55:52 +02:00
Theresa Gresch
fb0c22fb4b
Merge pull request #4974 from photoprism/unit-test-stack-original-name
Tests: Add unit tests for photo stack determination and original file retrieval
2025-05-02 12:25:01 +02:00
Michael Mayer
607b285443 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-02 12:17:14 +02:00
Michael Mayer
de14b30570 Videos: Add "photoprism dl" CLI command to import from a URL #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-02 12:16:59 +02:00
Michael Mayer
06529c3854 Develop: Upgrade base image from 250426-plucky to 250502-plucky #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-02 10:06:18 +02:00
Michael Mayer
8faf3fc918 Import: Add ytdl package for downloading videos from URLs #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-02 10:04:34 +02:00
Michael Mayer
a7d927a83b Videos: Add install-yt-dlp.sh script #4982
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-05-02 09:57:52 +02:00
hardlydearly
060924c19a
Backend: Use slices.Contains to simplify code (#4975)
Signed-off-by: hardlydearly <799511800@qq.com>
2025-04-30 15:25:05 +02:00
graciousgrey
bb67dca507 Tests: Add unit tests and test fixtures 2025-04-30 14:07:04 +02:00
Ömer Duran
9526f1d4dc Tests: Add unit tests for photo stack determination and original file retrieval 2025-04-29 21:54:11 +03:00
graciousgey
8ce192ceba Tests: Refactor sharing test to be stable 2025-04-29 16:45:44 +02:00
Theresa Gresch
d0f7393ebe
Merge pull request #4972 from photoprism/cover-test-improvements
Tests: Enhance album cover selection logic in acceptance tests
2025-04-29 10:24:52 +02:00
Michael Mayer
fe3071ba18 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-29 08:56:32 +02:00
Michael Mayer
a64e2ea445 Sharing: Allow authenticated clients to share albums #4973
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-29 08:54:16 +02:00
Radon Rosborough
138cc3c458
Upload: Generate a more elegant random token #4970 #4971
* Upload: More elegant generateToken
* Add unit test
2025-04-29 08:01:44 +02:00
Ömer Duran
aeaa39969b Tests: Enhance album cover selection logic in acceptance tests 2025-04-29 01:46:53 +03:00
graciousgey
ba8d38a761 Tests: Refactor acceptance tests 2025-04-28 10:35:54 +02:00
Michael Mayer
05b68db22d Config: Update internal/api/swagger.json #4969
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-27 15:08:32 +02:00
Michael Mayer
3f2f0a7e67 Config: Allow FFmpeg bitrate limit to be disabled with -1 #4969
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-27 15:07:28 +02:00
Michael Mayer
eb4fc032ff Config: Add preset, quality, and device options for FFmpeg #4969
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-27 14:36:36 +02:00
raystlin
6565fb2d6f AI: Fixed unitialization problems
* vision_list command failed silently for models without meta.
* face model panicked for models without meta.
2025-04-27 10:41:53 +00:00
Michael Mayer
27ec7a1282 Videos: Add "va-driver-all" and "libva2" to Docker base images #4967
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-26 11:41:01 +02:00
Michael Mayer
9ab1772b64 Develop: Export SEMVER_MAJOR and SEMVER_MINOR in Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-26 11:25:01 +02:00
Michael Mayer
a3883c1cd4 Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-26 11:11:18 +02:00
Michael Mayer
591ec1fad7 Backend: Update dependencies in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-26 11:10:51 +02:00
Michael Mayer
a7ee4a6cff Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-26 11:10:29 +02:00
Michael Mayer
98f2cbd51b Develop: Export SEMVER_VERSION, BUILD_TAG and BUILD_ARCH in Makefile
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-26 10:59:26 +02:00
Michael Mayer
eb9c64772f Develop: Upgrade base image from 250418-plucky to 250426-plucky #4967
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-26 09:40:50 +02:00
Michael Mayer
8fbe03ee1b Videos: Update driver packages for Intel QSV and add "amd" target "#4967
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-26 09:09:26 +02:00
Michael Mayer
21ddba4595 Setup: Install optimized TensorFlow 2 version on first startup #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-25 11:05:21 +02:00
Michael Mayer
cbc415d32b CLI: Correct indentation of backup and restore command descriptions
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-25 08:34:43 +02:00
Michael Mayer
71a623b5e0 Docker: Increase TF_CPP_MIN_LOG_LEVEL from 2 (info) to 4 (error)
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-25 07:56:27 +02:00
Michael Mayer
eddb096adb Docker: Reduce MALLOC_ARENA_MAX from 4 to 2 for less memory consumption
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-25 07:52:49 +02:00
Michael Mayer
f73b703123 Videos: Increase transcoding bitrate limit default to 60 Mbps #1307
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-24 11:59:29 +02:00
Michael Mayer
9e39b2f81d Videos: Improve log message when file has already been transcoded #1307
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-24 11:25:15 +02:00
Michael Mayer
fed0cfff6a Videos: Stream AVC only if native format/codec is not supported #1307
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-24 11:18:10 +02:00
Michael Mayer
cc5a4a6fd8 NSFW: Remove "nsfw:" prefix from returned errors
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-24 08:49:00 +02:00
Michael Mayer
7c7f89b2ac Convert: Update commands after upgrading ImageMagick from v6 to v7 #4963
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-24 08:48:13 +02:00
Michael Mayer
2a2a55b9fa Docs: Update license NOTICE files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-24 07:24:01 +02:00
Michael Mayer
451c172a70 Docs: Update internal/api/swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-24 07:23:47 +02:00
Michael Mayer
5648469247 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-24 07:22:24 +02:00
Michael Mayer
c6e571aab1 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-24 07:22:14 +02:00
Michael Mayer
f2a89063c6 Metadata: Fix typo in LocationUTC() function #4622 #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-23 17:54:33 +02:00
Michael Mayer
e59fdded1b Metadata: Preserve UTC time when a location time zone is set #4622 #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-23 17:15:49 +02:00
Michael Mayer
56ba9f1ee5 Metadata: Use Local time for file modification timestamps #4622 #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-23 16:15:00 +02:00
Michael Mayer
5e77c6a3bb Metadata: Improve timezone parsing in /pkg/time/tz #4622 #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-23 15:35:43 +02:00
Michael Mayer
4c7ca93dcc Metadata: Improve handling of Local and UTC timezones #4622 #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-23 15:08:15 +02:00
Michael Mayer
947e7a0fb1 Metadata: Normalize timezone names from YAML sidecar files #4622 #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-23 13:39:22 +02:00
Michael Mayer
d96b8027bd Metadata: Ensure that time zone names are always normalized #4622 #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-23 13:29:48 +02:00
Michael Mayer
8e17a8780b Backend: Limit error message chars, not runes
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-23 13:25:55 +02:00
Michael Mayer
36afc4a215 Backend: Clip error messages when too long
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-23 13:22:52 +02:00
Michael Mayer
c4d4b91488 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-23 12:52:37 +02:00
Michael Mayer
b9dda9337a Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-23 12:52:21 +02:00
Michael Mayer
5cd2c25489 Metadata: Move timezone related functions to /pkg/time/tz #4622 #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-23 12:50:12 +02:00
Michael Mayer
598be273aa Metadata: Set time zone based on location #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-22 15:45:18 +02:00
Michael Mayer
2a9741e826 Metadata: Default to "Local" if no time zone is set #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-22 14:44:50 +02:00
Theresa Gresch
44a3a9dcba
Merge pull request #4944 from photoprism/test/album-cover-setting
Tests: Add test for setting album cover
2025-04-22 13:21:28 +02:00
Michael Mayer
da7af617f7 Docs: Update internal/api/swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-22 10:48:51 +02:00
Michael Mayer
4bd4d17c5c Docs: Update license NOTICE files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-22 10:48:32 +02:00
Michael Mayer
20036b5de0 Frontend: Update .po translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-22 10:48:03 +02:00
Michael Mayer
582fc5d359 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-22 10:46:47 +02:00
Michael Mayer
c9777b39ed Frontend: Upgrade maplibre-gl to v5.4.0 in package.json #4959
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-22 10:46:26 +02:00
Michael Mayer
3bf5e59c63 Places: Add raster planet and hillshading tiles to Default map #4959
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-22 10:42:54 +02:00
Michael Mayer
bb8d835034 Frontend: Update .po and .json translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-21 12:54:52 +02:00
Cathie Integra
f8563adbcc
Weblate: Update frontend translations (#4958)
Co-authored-by: Weblate <noreply@weblate.org>
2025-04-21 12:52:59 +02:00
Michael Mayer
e616ced26e Places: Remove "Buildings" map style (now included in Default)
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-21 12:52:10 +02:00
Michael Mayer
264a1d67f6 Places: Add "Buildings" map style
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-20 19:45:31 +02:00
Michael Mayer
7d56a454dc Viewer: Remove experimental flag checks for info sidebar #4930 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-19 18:50:11 +02:00
Michael Mayer
a86d64b828 Viewer: Remove experimental flag check for info sidebar #4930 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-19 18:49:12 +02:00
Michael Mayer
ddf5924917 Viewer: Ignore jpeg codec for non-image media types #4930 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-19 18:19:26 +02:00
Michael Mayer
f50d833a0e Viewer: Display additional metadata in the Info sidebar #4930 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-19 18:13:18 +02:00
Ömer Duran
91ebcfab33 Tests: Implement album cover setting functionality across multiple pages 2025-04-19 16:24:29 +02:00
Michael Mayer
27b72aa1e9 Search: Parse lat,lng string into float64 coordinates #4930 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-19 16:04:44 +02:00
Michael Mayer
e7bb9bfb56 Viewer: Add link to maplibre.org/maputnik/ in comments #4930 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-19 14:52:43 +02:00
Michael Mayer
bbac7b91f0 Viewer: Don't render sidebar map when Places is disabled #4930 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-19 14:46:02 +02:00
Michael Mayer
ecf8af193b Viewer: Refactor #4930 to load dynamic map in info sidebar #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-19 14:24:41 +02:00
Ömer Duran
ca1f5cf781 Tests: Fix album cover test using proper selectors 2025-04-19 11:46:16 +02:00
Ömer Duran
140dc7b23c
Viewer: Add Interactive Map to Sidebar Info (#4930)
* Backend: Clean up Unix socket file on shutdown

* Backend: Clean up Unix socket file on startup

* Backend: Clean up Unix socket file

* Refactor Unix socket cleanup in server startup process

* Viewer: Reorganize the sidebar to display additional metadata attributes based on file type #4812

* Viewer: Add map view to sidebar #4812

* Viewer: Improve sidebar metadata spacing. #4812

* Viewer: Optimize megapixels calculation #4812

* Viewer: Move styles to lightbox.css #4812

* Viewer: Removing click event from Lat Lng #4812

* Viewer: Adjust css for map

* Viewer: extract map component from sidebar info

* fix: restore actions array in sidebar info

* Viewer: Offline map feature removed from sidebar

* Viewer: Use TakenAtLocal for consistent sidebar date format

* Viewer: Add zoom controls to the map component

* Viewer: Add map attribution in sidebar with default collapsed state
2025-04-19 11:15:06 +02:00
Michael Mayer
f0629cb151 Frontend: Update dependencies in go.mod and go.sum #4952
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-19 11:05:58 +02:00
Michael Mayer
d60a4c5767 Frontend: Update timestamp formats #4952
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-19 11:02:20 +02:00
Ömer Duran
555936d939 Merge branch 'develop' into test/album-cover-setting 2025-04-19 10:20:28 +02:00
Michael Mayer
79ceeb1ada Settings: Apply custom time zone under App Passwords and Services #4952
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 17:14:01 +02:00
Michael Mayer
e811422c44 Config: Shorten time zone in timestamps #4952
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 16:41:13 +02:00
Michael Mayer
4a0f285a2c Config: Use configured timezone for logs, errors and mod dates #4952
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 16:06:15 +02:00
Michael Mayer
a746cc1779 Docker: Upgrade libheif to v1.19.7 in jammy base images
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 14:43:42 +02:00
Michael Mayer
ac8ee9e4dd Build: Change variable export in Makefiles for Make v4 compatibility
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 13:52:14 +02:00
Michael Mayer
9e521b244d Develop: Upgrade default base image from oracular to plucky
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 13:12:47 +02:00
Michael Mayer
eb228b0e45 Docker: Install libheif v1.19.5 in jammy base images
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 12:54:26 +02:00
Michael Mayer
b64ba76bc5 Scripts: Update install-libheif.sh and install-tensorflow.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 12:53:56 +02:00
Michael Mayer
bdf97fff58 Makefile: Add build-libheif build commands for Ubuntu 25.04 (Plucky)
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 11:55:19 +02:00
Michael Mayer
fa3d7d831d Dist: Update install-libheif.sh script and related Makefile targets
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 11:51:37 +02:00
Michael Mayer
da4e9d57c1 Develop: Add deploy image for Ubuntu 25.04 (Plucky Puffin)
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 11:24:11 +02:00
Michael Mayer
d7ea086c5d Develop: Add Docker base image files for Ubuntu 25.04 (Plucky Puffin)
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 11:18:17 +02:00
Michael Mayer
9e56672019 Frontend: Update dependencies in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 11:17:20 +02:00
Michael Mayer
7dad78eb91 Backend: Update Go dependencies in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 11:16:59 +02:00
Michael Mayer
d15c6e59fa Frontend: Update .json translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 11:07:46 +02:00
Weblate
1c086455e2 Weblate: Update frontend translations 2025-04-18 11:07:06 +02:00
Michael Mayer
9b78cc3406 Frontend: Update .po translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-18 10:58:32 +02:00
graciousgey
c83d5f2f17 Tests: Adapt acceptance tests 2025-04-17 18:07:09 +02:00
graciousgrey
53c853dae5 Tests: Add unit tests #4942 2025-04-17 15:40:42 +02:00
Michael Mayer
b6423e5090 UX: Add wide sidepanel style for batch edit dialog #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-17 15:13:45 +02:00
Michael Mayer
5877be38df Search: Improve generated search filter documentation #4947
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-17 12:51:09 +02:00
Michael Mayer
7da6a97d15 Search: Improve generated search filter documentation #4947
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-17 12:46:57 +02:00
Michael Mayer
2b66db8216 Search: Improve generated search filter documentation #4947
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-17 12:44:27 +02:00
Michael Mayer
46e4810391 Search: Improve generated search filter documentation #4947
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-17 12:40:46 +02:00
Michael Mayer
f7b80bf34d Search: Update generated search filter documentation #4947
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-17 12:12:02 +02:00
Michael Mayer
9c33235a83 Frontend: Update dependencies and package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-17 11:38:32 +02:00
Michael Mayer
04ac2a383e Search: Find pictures with a specific term in Title or Caption #4947
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-17 11:38:08 +02:00
Michael Mayer
dff52f8ca0 Frontend: Update vuetify from v3.8.1 to v3.8.2 in package.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 19:48:49 +02:00
Michael Mayer
23a1182d00 Settings: Ensure that defaults are used instead of empty values
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 19:28:05 +02:00
Michael Mayer
b3a38224af Settings: Change the initial maps style to "default"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 18:15:03 +02:00
Michael Mayer
1b519fbc33 Places: Change the Default map setting value to "default"
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 18:09:23 +02:00
Michael Mayer
49e84c4a7f Config: Apply configured default time zone to user settings #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 17:56:57 +02:00
Michael Mayer
557a25a6b5 Metadata: Change date_med_tz to datetime_med_tz #4812 #4946 #4930
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 17:39:08 +02:00
Michael Mayer
a440eb6bc7 Metadata: Update tests after changing Local timezone identifier #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 17:36:25 +02:00
Michael Mayer
5f32d75700 Metadata: Use "Local" as identifier for the local time zone #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 17:12:37 +02:00
Michael Mayer
dddfee3920 Frontend: Update .po translation files #4946
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 17:10:35 +02:00
Michael Mayer
e21bdc3b22 Frontend: Update translation .json files #4945
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 12:52:27 +02:00
Weblate
3f5e040a5a Weblate: Update frontend translations 2025-04-16 12:50:49 +02:00
Ömer Duran
4096583b1c Tests: Remove 'only' flag from album cover test 2025-04-16 10:50:15 +02:00
Ömer Duran
33afc04d86 Tests: Add test for setting album cover 2025-04-16 10:48:42 +02:00
raystlin
d082929dee Removed parameter Channels
It seems to be standarized, so it is now used as an additional check for
input signatures.
2025-04-16 08:19:58 +00:00
Michael Mayer
6ee74461ed API: Update swagger.json docs
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 10:10:15 +02:00
Michael Mayer
a446218933 Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 10:10:01 +02:00
Michael Mayer
35e0e112bd Frontend: Update translation .po and .json files #4942
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 10:09:22 +02:00
Michael Mayer
f28aaac518 Frontend: Update deps in package.json and package-lock.json #4942
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 10:08:47 +02:00
Michael Mayer
fbcd210578 UX: Add language selector to login page #4942
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 10:07:32 +02:00
Michael Mayer
fcd17f8859 Frontend: Update translation .json files #4941
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-16 10:07:32 +02:00
Weblate
af7c71e762 Weblate: Update frontend translations 2025-04-16 10:07:26 +02:00
Weblate
e1b9946448 Weblate: Update frontend translations 2025-04-16 08:12:47 +02:00
Michael Mayer
7f4f63775d Frontend: Update translation .po and .json files #4939
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-15 17:00:02 +02:00
Weblate
208ff18a5d Weblate: Update frontend translations 2025-04-15 16:57:55 +02:00
Michael Mayer
c22b118dd6 MediaFile: Use thumb.FileInfo() to determine image width and height
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-15 15:43:24 +02:00
Michael Mayer
96dbb5ccbc Config: Refactor command flags, reports, and client options
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-15 15:42:03 +02:00
Michael Mayer
2c47644ea8 Metadata: Add "local" as an alias for an unknown (local) time zone
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-15 15:39:04 +02:00
Michael Mayer
161b18e5e8 Backend: Update Go dependencies in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-15 15:35:36 +02:00
Michael Mayer
55394d4137 AI: Remove Hidden flag from "photoprism vision run" command #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-15 14:51:55 +02:00
raystlin
eca0bc5205 AI Test: Added path protection to tests
As we are decompressing, we have to check the paths before writing to
disk.
2025-04-14 19:32:42 +00:00
Michael Mayer
a89d386541 UX: Tweak video controls background in fullscreen viewer
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 19:08:39 +02:00
Michael Mayer
eb39662e36 UX: Darken video controls background in fullscreen viewer
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 18:58:24 +02:00
Michael Mayer
b2a36c24dc UX: Refactor notification styles in notify.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 18:46:02 +02:00
Michael Mayer
0b390f356f UX: Add role attributes to progress bars in templates/app.gohtml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 17:41:49 +02:00
Michael Mayer
61ceed0726 UX: Refactor notification styles in notify.css and notify.vue
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 17:41:05 +02:00
Michael Mayer
60e41b425b UX: Refactor notification teleport and transition in notify.vue
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 17:29:58 +02:00
Michael Mayer
41d9dd7c21 Frontend: Refactor setTokens() and updateTokens() in common/config.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 15:35:05 +02:00
Theresa Gresch
c3741cb912
Merge pull request #4934 from photoprism/keyboard-shortcut-tests
Tests: Add Keyboard Shortcuts
2025-04-14 12:20:25 +02:00
Michael Mayer
ac8db75a3f UX: Improve mobile notification styles in notify.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 10:31:02 +02:00
raystlin
8d9a16cef6 AI Test: Added resolution to external models
The definition of the models now contain the expected resolution. This
has improved the results for efficientnet-m.
2025-04-14 08:15:10 +00:00
Ömer Duran
65fcb25952 Merge branch 'develop' into keyboard-shortcut-tests 2025-04-14 10:11:51 +02:00
Ömer Duran
ab31f20508 Test: Move nav selectors to constructor 2025-04-14 10:11:25 +02:00
Michael Mayer
38155190c5 Import: Ignore archive sidecar files #4929
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 08:59:21 +02:00
Michael Mayer
66b7d83d7e Search: Reset view when there are no results or an error occurs #4935
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 08:46:31 +02:00
Michael Mayer
d4becb575f Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 07:46:30 +02:00
Michael Mayer
bc4f1f3080 API: Update swagger.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 07:45:56 +02:00
Michael Mayer
328938d268 Backend: Update dependencies in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 07:44:10 +02:00
Michael Mayer
f8bf1d45fc UX: Improve notification styles in notify.css and notify.vue
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-14 07:42:58 +02:00
raystlin
5521d06bc0 Added Interval parameter to PhotoInput
This parameter allows us to rescale the input of the models because some
of them need values between [0, 1] and other between [-1, 1].
2025-04-13 20:32:02 +00:00
raystlin
e55536e581 Merge remote-tracking branch 'upstream/develop' into feature/custom-tf-model-127 2025-04-13 15:27:50 +00:00
raystlin
457a47b36f AI: Added a test for external models
The tests has a envar check to avoid running it by default, as it
downloads the models and generates a lot of errors.
2025-04-13 14:54:42 +00:00
raystlin
ad94d03576 Fixed classify and nsfw tests
They were broken when the constructors changed to include metadata.
2025-04-13 14:53:34 +00:00
raystlin
d993eb2a85 AI: Added some intelligence to label loading.
Now when loading labels internal/ai/tensorflow package will try to look
for all the files that match the glob label*.txt and will return the
labels that match the expected number. Some models add a first label
called background, which is a bias.
Also, a new parameter has been added to models to allow a second path to
look for the label files. This path is set to nasnet asset on
internal/ai/vision.
2025-04-13 14:49:54 +00:00
Michael Mayer
f09aa7749b UX: Update tabindex attributes and remove focus workaround in notify.vue
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-13 13:44:25 +02:00
Michael Mayer
914476ffe7 Backend: Update dependencies in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-13 11:36:50 +02:00
Michael Mayer
41abde5db8 Frontend: Update dependencies in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-13 11:36:35 +02:00
Michael Mayer
916276e36a UX: Check if elements are already active before setting focus
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-13 11:35:10 +02:00
Michael Mayer
8189503a69 AI: Add additional vision service API configuration options #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-13 10:58:15 +02:00
Michael Mayer
e5916b98b9 UX: Remove .is-rtl styles from css/notify.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 20:08:42 +02:00
Michael Mayer
1d77c2306f UX: Remove unnecessary notification classes in notify.vue
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 20:03:28 +02:00
Michael Mayer
e6ec733303 UX: Improve notification styles
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 19:27:37 +02:00
Michael Mayer
6f3ad2dea3 UX: Replace v-snackbar component with div elements
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 19:03:01 +02:00
Michael Mayer
377c7ed1d5 Config: Change the order of options in settings.yml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 17:53:46 +02:00
Michael Mayer
128df65f54 Develop: Upgrade base image from 250407-oracular to 250412-oracular
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 15:30:37 +02:00
Michael Mayer
8068e471d1 Develop: Update Makefile and compose.nvidia.yaml
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 15:30:22 +02:00
Michael Mayer
494f75917c Develop: Update service configuration in compose.yaml files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 15:11:09 +02:00
Michael Mayer
52cc9b1cd3 Docker: Update install-s6.sh script
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 15:10:37 +02:00
Michael Mayer
06de8e2b66 Docker: Refactor service initialization and reduce startup log verbosity
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 14:06:39 +02:00
Michael Mayer
b03f06a1a2 Dist: Refactor install-s6.sh script
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 12:22:30 +02:00
Michael Mayer
1831261cfd Dist: Add script to install the latest nats-server binary
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 11:50:12 +02:00
Michael Mayer
43c794d242 AI: Add script to install the latest qdrant database binary #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-12 11:49:03 +02:00
Ömer Duran
7d39c51e31 Merge branch 'keyboard-shortcut-tests' of https://github.com/photoprism/photoprism into keyboard-shortcut-tests 2025-04-12 11:35:22 +02:00
Ömer Duran
d0a23491df Tests: Refactor lightbox archive and download shortcut tests 2025-04-12 11:33:25 +02:00
Ömer Duran
36c5b7012f Merge branch 'develop' into keyboard-shortcut-tests 2025-04-12 10:57:05 +02:00
Ömer Duran
26b552bb58 Tests: Remove 'only' from photo scroll test to ensure it runs with other tests 2025-04-12 10:55:45 +02:00
Ömer Duran
285c0f4543 Tests: Test scroll restoration and fix deprecation 2025-04-12 10:54:36 +02:00
Ömer Duran
6d6671c356 Tests: verify search not focused before ctrl+f 2025-04-12 10:27:21 +02:00
Ömer Duran
6088ebd617 Tests: Update selector for upload dialog visibility check 2025-04-12 10:22:04 +02:00
Ömer Duran
6c05e02077 Tests: Changed test messages for slideshow functionality 2025-04-12 10:20:03 +02:00
raystlin
0895a085a1 Migrated nsfw to the new model loading system.
nsfw/model.go and vision/model.go modified to make it work. Testing
remains undone.
2025-04-11 20:29:31 +00:00
raystlin
88508679b0 Modified classify to add custom models
Vision input parameters have also been changed to support the new
parameters needed for the models.
2025-04-11 20:01:36 +00:00
Michael Mayer
63fb46578a API: Remove unused "api/hooks" package
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-11 20:02:08 +02:00
Michael Mayer
07e22b0c14 API: Remove unused Webhook endpoint due to architecture change
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-11 19:39:39 +02:00
Michael Mayer
63d72ee867 AI: Refactor Webhook endpoint and improve related unit tests #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-11 19:22:54 +02:00
raystlin
8bc7121394 Added a comment to clarify
EnsureShape operation may seem unnecesary, but PredictCosts fails it it
is not added to the graph.
2025-04-11 16:57:27 +00:00
Michael Mayer
f2ffb0fdce AI: Add Webhook endpoint and refactor ACL for Vision API #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-11 18:41:54 +02:00
raystlin
7bcbaea492 Dynamically add a softmax layer to a loaded graph.
By inspecting existing models we saw that many times logits are returned
instead of probabilities. Photoprism uses probabilites to rank the
quality of the results, so we need to transform those logits. Our
approach is to add a new layer at runtime to the graph that performs the
softmax operation.
2025-04-11 14:32:17 +00:00
raystlin
d0f6d903e2 Added utilities to inspect tensorflow models.
These new functions allows us to inspect the saved models, get the tags
and try to guess the inputs and outputs.
2025-04-11 14:30:48 +00:00
Ömer Duran
7925ab205d Tests: Add acceptance tests for keyboard shortcuts
The following shortcuts are tested:
- Common page shortcuts: Search focus (Ctrl+F), Refresh (Ctrl+R), Upload dialog (Ctrl+U).
- Lightbox shortcuts: Info panel toggle (Ctrl+I), Mute/Unmute (Ctrl+M), Slideshow play/pause (Ctrl+S), Archive (Ctrl+A), Download (Ctrl+D), Edit (Ctrl+E), Fullscreen toggle (Ctrl+F), Like/Unlike (Ctrl+L).
- Expansion panel toggle (Shift+Ctrl+F) and focusing search fields on specific pages (People, Labels, Library Errors) (Ctrl+F).
2025-04-11 15:22:36 +02:00
Michael Mayer
35bfe0694b API: Disable gzip compression for /api/v1/dl endpoint #127 #1090
Required for compatibility with the Python HTTP client. In addition,
this commit refactors function names and adds tests.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-11 14:13:25 +02:00
Michael Mayer
bd634c828b AI: Shorten "face/embeddings" model type to just "face" #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-11 05:48:00 +02:00
Michael Mayer
720d83ef3a AI: Disable Vision API in demo mode #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-11 05:37:08 +02:00
Michael Mayer
c14be8f57e Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-11 05:20:08 +02:00
Michael Mayer
76757811cb Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-11 05:19:47 +02:00
Michael Mayer
f80acab4c2 AI: Add "photoprism vision run" command and vision worker #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-11 05:15:14 +02:00
Michael Mayer
5b8be2f5d4 AI: Add "photoprism vision" CLI subcommands #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-11 02:11:53 +02:00
Michael Mayer
6fcce84623 AI: Add photoprism-vision test service and caption API client #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-11 01:17:47 +02:00
Michael Mayer
068ee52301 AI: Improve code comments in vision package #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-10 22:08:49 +02:00
Michael Mayer
627f4f8d21 AI: Refactor API client in vision package #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-10 21:16:03 +02:00
Michael Mayer
0304ed37c3 AI: Set default vision API client timeout to one minute #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-10 21:07:57 +02:00
Michael Mayer
190be2a1b5 AI: Finalize facial embeddings, labels and nsfw API endpoints #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-10 20:28:26 +02:00
Michael Mayer
caf3ae1ab5 AI: Refactor use of face embeddings, labels, and nsfw models #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-10 16:49:34 +02:00
graciousgey
ecef34a8da Tests: Adapt acceptance tests 2025-04-10 11:27:49 +02:00
Michael Mayer
204ce2b100 Logs: Allow restart of logging after database provider reset #47 #4831
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-09 16:31:06 +02:00
Michael Mayer
eaea3a416d Logs: Stop logging errors when database connection is gone #47 #4831
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-09 12:50:44 +02:00
Michael Mayer
cf3b933e59 API: Refactor data URL encoding and decoding in pkg/media #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-09 10:58:48 +02:00
Michael Mayer
7f1041c434 Labels: Add image classification service client #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-08 04:14:18 +02:00
Michael Mayer
42897bde35 API: Add download package to allow temporary file downloads #127 #1090
This is necessary to provide external services with temporary access to
specific media files without giving them permanent access, a regular
download, or an access token.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-07 23:56:35 +02:00
Michael Mayer
0f76186663 AI: Reject API requests with content-type multipart/form-data #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-07 23:05:34 +02:00
Michael Mayer
d304509c0d AI: Add VisionApi, VisionUri, and VisionKey config options #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-07 20:30:07 +02:00
Michael Mayer
2a6b9fb237 AI: Add config option to specify the vision.yml settings file #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-07 13:18:03 +02:00
Michael Mayer
9d648f74dd AI: Add Code and Error to Vision API service response #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-07 12:51:44 +02:00
Michael Mayer
f3e066af45 AI: Add Vision API service endpoint for image classification #127 #1090
This is a proof of concept and still under development. The other
Vision API endpoints are stubs for testing and not yet functional.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-07 12:19:39 +02:00
Michael Mayer
907850cb80 Develop: Upgrade base image from 250402-oracular to 250407-oracular #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-07 11:36:51 +02:00
Michael Mayer
c6b6bfde70 CI: Exclude ARMv7 when building new Docker images and packages #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-07 11:36:16 +02:00
raystlin
ae735f6a1e Migrated arm64 Dockerfile to jammy
To support more gcc versions
2025-04-07 06:08:05 +02:00
raystlin
fd0baeb5a4 Modified comment on Dockerfile
Simply to add the llvm installation to the existing comment.
2025-04-07 06:08:05 +02:00
Michael Mayer
bfdb839d01 AI: Add TensorFlow utility package and improve model loading #127 #1090
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-07 05:26:45 +02:00
Michael Mayer
35e9294d87 AI: Add vision package and vision API endpoints #127 #1090
These changes allow to configure the computer vision models through an
optional vision.yml configuration file. Note that the API endpoints
are not yet functional and require further work.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 23:39:37 +02:00
Michael Mayer
b791896fc6 UX: Prevent buttons and menus from getting selected
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 15:04:25 +02:00
Michael Mayer
043f6c2569 Build: Downgrade TensorFlow from v2.18.0 to v1.15.2 in docker/armv7 #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 11:03:08 +02:00
Michael Mayer
332e57d59f AI: Update build target and install-tensorflow.sh for AVX512 #222 #4922
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 10:15:34 +02:00
Michael Mayer
a3456637cd AI: Detect AMX-AVX512 instructions in install-tensorflow.sh #222 #4922
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 10:01:22 +02:00
Michael Mayer
5650ea29b5 AI: Update libtensorflow-avx512 build target in Makefile #222 #4922
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 10:00:20 +02:00
Michael Mayer
c9e305808b AI: Add nano package to tensorflow Dockerfiles #222 #4922
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 09:41:26 +02:00
Michael Mayer
efe36603f8 AI: Add libtensorflow-avx512 to default targets in Makefile #222 #4922
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 09:39:21 +02:00
Michael Mayer
96fdd1a41a AI: Add libtensorflow build target for Intel AMX-AVX512 #222 #4922
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 09:37:49 +02:00
Michael Mayer
0b9233f44b AI: Build libtensorflow with --copt=-O2 instead of --copt=-O3 #222 #4922
This should optimize for fast execution as much as possible without
significantly increasing the binary size.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 09:25:20 +02:00
Michael Mayer
5a9e3a8645 AI: Update Makefile targets for tensorflow build images #222 #4922
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 09:14:06 +02:00
Michael Mayer
3900573a7c AI: Fix libtensorflow tar.gz path in create_archive.sh #222 #4922
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 09:09:03 +02:00
Michael Mayer
d9c260b865 AI: Use Docker build argument to specify TensorFlow version #222 #4922
This also ensures that the archives will be created in /build.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 09:05:06 +02:00
Michael Mayer
a97d66d6e4 AI: Update libtensorflow build targets in Makefiles #222 #4922
This normalizes the archive names and adds required compiler flags.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-06 08:35:06 +02:00
Michael Mayer
5256a7f276 Viewer: Add title and caption styles for collapsible sidebar #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 23:22:00 +02:00
Michael Mayer
eed7bfff73 Viewer: Refactor getViewport() function in component/lightbox.vue #4927
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 22:42:44 +02:00
Michael Mayer
d6c215c9c6 Viewer: Set max video width to 100% in lightbox.css #4927
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 22:42:18 +02:00
Michael Mayer
b6ca5a1717 Config: Add upload-limit flag to limit total upload size #4929 #4895
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 15:44:13 +02:00
Michael Mayer
1350eff0f5 UX: Improve action menu styles in css/controls.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 14:40:45 +02:00
Michael Mayer
bf66a9e19a Config: Update import-allow description in flags.go #4929 #4895
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 13:15:02 +02:00
Michael Mayer
5a1ca738f6 Config: Update options.go #4929 #4895
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 13:04:14 +02:00
Michael Mayer
63d6902605 Config: Update upload-allow description in flags.go #4929 #4895
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 12:53:55 +02:00
Michael Mayer
de89979e45 Upload: Add new config options to compose.yaml examples #4929 #4895
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 12:49:32 +02:00
Michael Mayer
fe424d8966 Upload: Reject files that exceed the originals limit #4929 #4895 #2049
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 12:43:51 +02:00
Michael Mayer
b0e42bebf1 Upload: Add support for uploading zip archives #4929 #4895
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 12:02:33 +02:00
Weblate
cf3b7f8d18 Weblate: Update frontend translations 2025-04-05 09:46:00 +02:00
Michael Mayer
83c30987eb Viewer: Improve $util.thumb() test in unit/common/util_test.js #4927
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 09:33:34 +02:00
Michael Mayer
1cf69e231f Viewer: Enhance thumbnail size selection for high aspect ratios #4927
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-05 09:31:28 +02:00
graciousgrey
6d776c8a97 Frontend: Tests set default timezone in karma.conf.js 2025-04-04 17:06:49 +02:00
Ömer Duran
974369966a UX: prevent duplicate folder selection in remote sync 2025-04-04 15:41:51 +02:00
Michael Mayer
cdc1866720 Viewer: Skip loading new image if no matching thumbnail size is set
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-04 13:02:04 +02:00
Michael Mayer
4915840035 Videos: Skip forward/back 10 seconds with right/left #1131 #3623 #4698
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-04 12:26:43 +02:00
raystlin
0ff942342f
AI: Improve TensorFlow for C build images and scripts (#4922)
* Fixed create_archive.sh

The previous version followed symlinks on doing the copy to a temporary
folder, so the resulting size was 3 times what it should be. Also
*.param files have been excluded from the final tar.gz file.

* Migrated tensorflow image to jammy

So as to build against an older version of glibc and support more OS
versions.

* Extend new create_archive.sh to all build types

The changes on the main create_archive.sh are now on all the other
versions.
2025-04-04 11:36:36 +02:00
Michael Mayer
990a0a40ba Frontend: Update line numbers in translation *.po files #1131 #4916
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-04 11:29:52 +02:00
Michael Mayer
405c9e7650 UX: Refactor shortcut event handling to use common/view.js #1131 #4916
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-04 11:28:50 +02:00
Michael Mayer
dc2370ebf3 Viewer: Add tooltips to metadata in info sidebar #4811 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-04 10:15:56 +02:00
Michael Mayer
439d683fdb Viewer: Update translation *.json files #4925
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-04 10:04:19 +02:00
Weblate
15e6ea0a4d Weblate: Update frontend translations 2025-04-04 10:03:38 +02:00
Michael Mayer
c9a8d8f89d Viewer: Shorten title of slideshow-toggle button #4811 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-04 10:01:26 +02:00
Michael Mayer
e9a6973d16 Viewer: Update translation *.json files #4811 #4812 #4924
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-04 09:58:58 +02:00
Weblate
8a537755a0 Weblate: Update frontend translations 2025-04-04 09:57:22 +02:00
Michael Mayer
ff47ff7366 UX: Add title to information sidebar close button #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-04 09:55:09 +02:00
Michael Mayer
53feb26fa9 Frontend: Update dependencies in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-04 09:49:49 +02:00
Michael Mayer
f8e32d260e Viewer: Rename sidebar-button to info-button ("Information") #4811 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-04 09:49:25 +02:00
Michael Mayer
bb60ea028e UX: Increase background opacity for error and warning notifications
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-03 15:54:55 +02:00
Michael Mayer
fb040de538 UX: Improve notification snackbar styles and theme colors
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-03 15:40:32 +02:00
Michael Mayer
e76bf0c4da Viewer: Fix copying coordinates to clipboard #4811 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-03 15:39:35 +02:00
Michael Mayer
db77ddce0f UX: Refactor notification snackbar component model and styles
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-03 14:45:35 +02:00
Michael Mayer
1ed65ba8f6 UX: Refactor action menu event handling #4811 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-03 13:17:16 +02:00
Michael Mayer
0fc7aa3767 Viewer: Darken info sidebar colors #4811 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-03 07:03:20 +02:00
Michael Mayer
f8d2cfd1f2 Viewer: Remove anchor attribute in lightbox/menu.vue #4811 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-03 06:58:27 +02:00
Michael Mayer
252784c029 Viewer: Improve info sidebar colors #4811 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-03 06:43:31 +02:00
Michael Mayer
e6fecc5020 Viewer: Prevent video controls from being selected #4811 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-03 06:22:26 +02:00
Michael Mayer
c973d4edd6 Viewer: Fix action menu in Firefox and improve input focus #4811 #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-03 06:12:47 +02:00
Michael Mayer
2dc1baf2e8 Viewer: Improve styles for and refactor collapsible sidebar #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-03 03:51:30 +02:00
Michael Mayer
b0e3ff1231 UX: Add transparent busy overlay style and improve keyboard shortcuts
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 20:53:57 +02:00
Michael Mayer
17154e33d2 Frontend: Rename PPhotoUploadDialog to PUploadDialog
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 20:16:10 +02:00
Michael Mayer
37d609c2bd UX: Remove Ctrl+H key shortcut in lightbox.vue #1131 #3623 #4916
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 19:23:17 +02:00
Michael Mayer
e78414ac1e Frontend: Update *.json translation file #4918
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 18:57:48 +02:00
Weblate
f3dddef6a4 Weblate: Update frontend translations 2025-04-02 18:57:03 +02:00
Michael Mayer
3d66556acf UX: Add keyboard shortcuts & improve focus management #1131 #3623 #4916
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 18:55:50 +02:00
Michael Mayer
433d726d75 SQLite: Update database initialization for entity unit tests #47 #4831
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 13:53:11 +02:00
Michael Mayer
6596474389 SQLite: Refactor database initialization for unit tests #47 #4831
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 13:44:40 +02:00
Michael Mayer
7b5f295a9b TensorFlow: Improve install-tensorflow.sh script to detect AVX-VNNI #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 13:20:47 +02:00
Michael Mayer
5ff21ad589 TensorFlow: Enable oneDNN optimizations in Dockerfiles #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 12:48:29 +02:00
Michael Mayer
8cd1de6b64 TensorFlow: Improve install-tensorflow.sh script #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 12:44:09 +02:00
Michael Mayer
f4fa80a8cf Develop: Add clean-build target to Makefile #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 11:52:44 +02:00
Michael Mayer
00e12b8bd8 Develop: Don't install AVX/AVX2 version of TensorFlow by default #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 11:50:55 +02:00
Michael Mayer
083c59550a AI: Upgrade Go language bindings for the TensorFlow C API #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 04:16:27 +02:00
Michael Mayer
b5c1c6b974 Develop: Upgrade base image from 250329-oracular to 250402-oracular #222
The new image includes TensorFlow v2.18.0 and Go v1.24.2.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 04:06:23 +02:00
Michael Mayer
0dd2639d97 SQLite: Use file storage instead of memory for unit tests #47 #4831
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 04:05:08 +02:00
Michael Mayer
e2d74220d5 TensorFlow: Update install-tensorflow.sh to default to v2.18.0 #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 03:40:39 +02:00
Michael Mayer
f0959c2796 Dockerfiles: Add TF_ENABLE_ONEDNN_OPTS variable for TensorFlow 2 #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-02 00:03:10 +02:00
Michael Mayer
6b26974ce7 TensorFlow: Upgrade build scripts to v2.18.0 #222
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 23:43:22 +02:00
Michael Mayer
a6b4378533 UX: Reduce flickering when refreshing search results #4917
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 21:04:17 +02:00
Michael Mayer
512f044ec6 UX: Refactor keyboard event handler in lightbox.vue #1131 #4916
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 19:56:45 +02:00
Michael Mayer
67c99fb322 UX: Support meta (Cmd) key as alternative to Ctrl for macOS #1131 #4916
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 19:44:00 +02:00
Michael Mayer
57d0869e65 Frontend: Add "focus-trap" and update dependencies in package.json #4916
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 19:12:36 +02:00
Michael Mayer
64f051ece3 Docs: Update README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 14:11:07 +02:00
Michael Mayer
eba878dea1 Frontend: Update *.json translation files #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 12:40:58 +02:00
Weblate
a2825be165 Weblate: Update frontend translations 2025-04-01 12:40:26 +02:00
Michael Mayer
8f8d901787 Viewer: Rename PSidebarMetadata to PSidebarInfo #4812
Also allows to test the sidebar when experimental features are enabled.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 12:39:39 +02:00
Michael Mayer
80f93b471a Frontend: Update *.po translation files #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 12:36:36 +02:00
Michael Mayer
36a359eb6f Viewer: Add a lightbox theme to use for the info sidebar #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 10:35:06 +02:00
Michael Mayer
0dc3e1c8a4 Viewer: Add map marker example to sidebar metadata #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 08:45:47 +02:00
Michael Mayer
17dbe15dc2 Viewer: Set viewPortWidth during initialization #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 02:47:29 +02:00
Michael Mayer
72435cd0e8 Viewer: Remove dataSource option and add getNumItems() instead #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 02:22:40 +02:00
Michael Mayer
a12323cf2e Viewer: Make sidebar title and caption read only #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 02:22:07 +02:00
Michael Mayer
ecbcb8f63c Frontend: Update *.json translation files #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 01:54:18 +02:00
Weblate
ebc013a204 Weblate: Update frontend translations 2025-04-01 01:53:45 +02:00
Michael Mayer
f861bbece8 Frontend: Update *.po translation files #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 01:51:30 +02:00
Michael Mayer
86113d1429 Viewer: Preserve slide data while Viewer is open #383
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 01:48:32 +02:00
Michael Mayer
9f8c8b4c10 Viewer: Show "Remove from Album" action only for regular albums #383
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 01:27:29 +02:00
Michael Mayer
1ec6562799 Viewer: Implement proof-of-concept for info sidebar with metadata #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-04-01 00:34:40 +02:00
Michael Mayer
b729f53d9d Docs: Update README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 22:45:06 +02:00
Michael Mayer
cd630536e2 Docs: Update README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 22:21:17 +02:00
Michael Mayer
cdbb4eefcc Viewer: Rename PActionLightbox to PLightboxMenu #4812
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 21:57:37 +02:00
Michael Mayer
b015abf85f Places: Update *.json translation files #4762
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 21:44:18 +02:00
Weblate
a9e6874fe0 Weblate: Update frontend translations 2025-03-31 21:42:27 +02:00
Michael Mayer
47a5412eeb Places: Update *.po translation files #4762
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 21:39:36 +02:00
Michael Mayer
70402ba46f Places: Update map title in /frontend/src/options/options.js #4762
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 21:39:29 +02:00
Weblate
d3c8af196d Weblate: Update frontend translations 2025-03-31 21:38:02 +02:00
Michael Mayer
955fd1d247 Places: Update *.po translation files #4762
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 21:33:45 +02:00
Michael Mayer
995da0f611 Places: Update map style options and terrain styles #4762
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 21:31:24 +02:00
Michael Mayer
9c79f54994 Viewer: Add TimeZone to thumbnail model data #4812 #4905
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 20:51:26 +02:00
Michael Mayer
5a3aa9db18 Frontend: Remove unused code from component/album/toolbar.vue
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 20:48:20 +02:00
Michael Mayer
e637034a8c Places: Improve map initialization and add satellite map style #4762
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 20:47:48 +02:00
Michael Mayer
62987fbbe1 Viewer: Improve thumb model and thumb size calculation #4812 #4905
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 19:20:48 +02:00
Michael Mayer
5dbbf340a0 Search: Fix opening randomly sorted results in Viewer #4905
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 13:59:50 +02:00
Michael Mayer
31ae58435e Frontend: Update dependencies in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 13:37:11 +02:00
Michael Mayer
1ff381d0b7 Viewer: Refactor "Remove from Album" menu action #383 #3758 #3974 #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 13:36:54 +02:00
Michael Mayer
16777de1a9 Viewer: Update *.json translation files #383 #3758 #3974 #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 13:32:43 +02:00
Michael Mayer
24adfcb9f2 Viewer: Update *.po translation files #383 #3758 #3974 #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 13:31:51 +02:00
Weblate
9e036d259f Weblate: Update frontend translations 2025-03-31 13:29:55 +02:00
Michael Mayer
df5695a220 Viewer: Add "Remove from Album" menu action #383 #3758 #3974 #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 13:28:41 +02:00
Michael Mayer
aa687ade0b AI: Add Qdrant vector database for test & development #1090 #1287 #4669
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-31 12:35:28 +02:00
Michael Mayer
422256122d UX: Check permissions before opening upload dialog #1131
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-30 19:13:03 +02:00
Michael Mayer
2ebac920f2 UX: Show keyboard shortcuts in action menus #1131
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-30 18:40:35 +02:00
Michael Mayer
b678bf384c Viewer: Update *.json translation files #383 #3758 #3974 #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-30 15:04:30 +02:00
Weblate
9a4773610a Weblate: Update frontend translations 2025-03-30 15:03:22 +02:00
Michael Mayer
d895affffa Frontend: Update dependencies in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-30 14:34:40 +02:00
Michael Mayer
1a207e3543 Viewer: Update translations in src/locales/*.po #383 #3758 #3974 #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-30 14:34:18 +02:00
Michael Mayer
7bc4417eff Viewer: Add "Set as Album Cover" menu action #383 #3758 #3974 #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-30 14:26:03 +02:00
Michael Mayer
7afffe1809 Setup: Improve compose.yaml inline documentation #4051
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-29 04:24:47 +01:00
Michael Mayer
4080901576 Develop: Upgrade base image from 250326 to 250329-oracular #47 #4831
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-29 03:40:42 +01:00
Michael Mayer
deeb8b987a PostgreSQL: Install "postgresql-client" package in Dockerfiles #47 #4831
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-29 02:25:37 +01:00
Michael Mayer
f142a9d52c Frontend: Update hls.js in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-28 23:47:00 +01:00
Michael Mayer
7bc9347909 Backend: Update deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-28 23:43:19 +01:00
Michael Mayer
c6176d0b1e UX: Update counters and covers in the background #4323
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-28 23:20:28 +01:00
Michael Mayer
cef91e442a Import: Preserve hidden .keep and .gitkeep files #4092
This prevents directories from being deleted when using the "move"
import option, which would otherwise delete hidden files and empty
directories.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-28 22:20:03 +01:00
Michael Mayer
45e0504dab Config: Read OIDC client secret from file #2302
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-28 21:29:14 +01:00
Michael Mayer
ad5baf2823 Config: Read admin and database password from file #2302
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-28 21:00:56 +01:00
Michael Mayer
a89f186f40 UX: Immediately return focus when displaying notification snackbar
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-28 19:44:01 +01:00
Michael Mayer
0951720512 UX: Do not close notification snackbar on content click anymore
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-28 19:20:00 +01:00
Michael Mayer
0d251a9d43 UX: Use arrow keys to navigate in edit dialog #3623
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-28 18:37:05 +01:00
Michael Mayer
e025f22553 UX: Refactor notification snackbar and loading bar components
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-28 18:32:20 +01:00
Michael Mayer
a76bbba2a6 FFmpeg: Fix Intel Quick Sync Video (QSV) hardware transcoding #4382
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-28 16:31:20 +01:00
graciousgey
a24b385560 Tests: Adapt page model to changes 2025-03-28 16:22:19 +01:00
Michael Mayer
2934319591 UX: Close notification snackbar on content click
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-28 10:00:57 +01:00
Michael Mayer
ca708c3f56 Codespell: Fix invalid inline comments and broken test assertions #4506
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-27 16:57:56 +01:00
Yaroslav Halchenko
15668ee7b5
CI: Add codespell config and fix typos (#4506)
More about codespell: https://github.com/codespell-project/codespell
2025-03-27 16:42:24 +01:00
Michael Mayer
47e740fd88 Metadata: Use "github.com/ugjka/go-tz/v2" instead of custom fork
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-27 16:34:47 +01:00
Michael Mayer
ae0b63eb50 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-27 15:37:49 +01:00
Michael Mayer
9de641eb66 Backend: Remove unnecessary usage of fmt.Sprintf() #3846
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-27 15:12:03 +01:00
graciousgrey
9aff925c94 Tests: Add unit tests #4895 2025-03-27 14:42:59 +01:00
Michael Mayer
02bc6b6bce Faces: Remove check that is always true in ai/face/detector.go #4457
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-27 14:34:00 +01:00
Michael Mayer
5fe3c34167 Config: Improve parsing of boolean environment variables #4372
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-27 13:35:47 +01:00
Michael Mayer
4ea2ab0ddb Frontend: Update *.json translation files #4900
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-27 10:50:38 +01:00
Michael Mayer
ed06bbda9d Frontend: Update src/locales/*.po translation files #4900
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-27 10:48:07 +01:00
Cathie Integra
7c70c247b9
Weblate: Update frontend translations (#4900)
Co-authored-by: Weblate <noreply@weblate.org>
2025-03-27 10:46:42 +01:00
Michael Mayer
0761be3258 Videos: Improve transcoding and indexing logs #4549
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-27 10:36:15 +01:00
Michael Mayer
4329b43b76 Backend: Improve error handling and logging #4491
These changes are based on a pull request submitted by @songzhibin97.
Thank you very much!

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-27 09:51:38 +01:00
Michael Mayer
8836f90251 WebDAV: Refactor service discovery heuristic to add custom headers #4608
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-27 03:31:48 +01:00
Esteve Fernandez
a36e8b19f8
WebDAV: Add depth header to service discovery request for Hetzner compatibility (#4608)
Signed-off-by: Esteve Fernandez <esteve@apache.org>
2025-03-27 03:07:21 +01:00
Jacob D
0d487b6490
Faces: Improve performance when manual tagging (#4691)
This PR implements a strategy to improve Optimize() performance by returning the correct number of modified rows in PurgeOrphanFaces and treating the result 0 as an error condition in MergeFaces. Logging around this has been improved in faces.go and faces_optimize.go.

Related Comments:
- https://github.com/photoprism/photoprism/issues/3124#issuecomment-2566025503
- https://github.com/photoprism/photoprism/pull/4691#issuecomment-2566164179
2025-03-27 01:40:31 +01:00
Michael Mayer
4ab9b14bcb Backend: Update github.com/bytedance/sonic in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 22:15:30 +01:00
Michael Mayer
fc0aac9877 Backend: Update indirect Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 22:11:57 +01:00
Michael Mayer
3ec92af160 Frontend: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 21:38:29 +01:00
Michael Mayer
7fe8ad9b35 Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 21:36:44 +01:00
Michael Mayer
58d55f820f Frontend: Reformat *.vue components with ESLint 9
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 21:24:47 +01:00
Michael Mayer
9927eb62eb Develop: Upgrade base image from 250317-oracular to 250326-oracular
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 21:23:03 +01:00
Michael Mayer
8b89c60418 Frontend: Reformat *.vue and *.js files with ESLint 9
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 21:08:50 +01:00
Michael Mayer
62eff7c4c3 Frontend: Upgrade ESLint from v8.57.0 to v9.23.0
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 21:07:45 +01:00
Michael Mayer
858130da9c Frontend: Update build deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 20:25:34 +01:00
Michael Mayer
a62d3d0e57 Frontend: Update "maplibre-gl" in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 20:20:39 +01:00
Michael Mayer
2df077df26 Frontend: Update dependencies in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 20:17:16 +01:00
Michael Mayer
4176303d6f Timezones: Upgrade gopkg.in/photoprism/go-tz.v2 from v2.1.3 to v2.2.0
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 20:11:43 +01:00
Michael Mayer
dce754182e Logs: Refactor message formatting in event package
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 12:58:51 +01:00
Michael Mayer
a2186f3fa4 Frontend: Update *.json translation files #4694
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 12:56:04 +01:00
Weblate
dc15a4aabe Weblate: Update frontend translations 2025-03-26 12:55:20 +01:00
Michael Mayer
b0eb7aacdd UX: Rename "Videos" to "Media" in navigation and add audio type #4694
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-26 12:53:15 +01:00
Weblate
6f08d7f5b9 Weblate: Update frontend translations 2025-03-26 11:55:07 +01:00
graciousgey
4996c2db0d Tests: Add acceptance tests 2025-03-26 09:19:18 +01:00
Michael Mayer
9e95c7e71c Upload: Delete invalid files, improve type checks and import logs #4895
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-25 11:58:59 +01:00
Michael Mayer
1f36d35d23 Upload: Report successful number of files in users_upload.go #4895
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-25 08:48:00 +01:00
Michael Mayer
3acd41027b Viewer: Update menu styles in css/lightbox.css #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-25 08:35:21 +01:00
Michael Mayer
ff5135c2a3 Viewer: Improve menu styles and refactor close event handler #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-25 08:07:40 +01:00
Michael Mayer
7de72bd99a Upload: Allow to limit the types of files users can upload #4895
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-25 06:32:01 +01:00
Michael Mayer
b771e86f8d Viewer: Replace me-1 and ms-1 padding classes with custom button styles
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-25 04:09:22 +01:00
Michael Mayer
b25209f114 Settings: Refactor list of supported user interface locales
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-25 03:45:49 +01:00
Michael Mayer
0a58484d6d Viewer: Improve menu styles and move close button to the left #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-25 03:18:15 +01:00
Michael Mayer
c702699f45 Viewer: Regenerate frontend translation json files #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-25 00:23:32 +01:00
Weblate
99653613ee Weblate: Update frontend translations 2025-03-25 00:22:50 +01:00
Michael Mayer
4acba7de18 Viewer: Update frontend translation files #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-25 00:20:21 +01:00
Michael Mayer
8765cf4d3f Viewer: Add a three-dot menu to perform additional actions #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-25 00:19:29 +01:00
Michael Mayer
c78b023675 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-24 23:11:21 +01:00
Michael Mayer
c9f0c5f475 Frontend: Regenerate src/locales/json/*.json #4893
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-24 21:22:20 +01:00
Weblate
33867d4d1f Weblate: Update frontend translations 2025-03-24 21:20:41 +01:00
Michael Mayer
6e07d42a1b UX: Reduce JS bundle size by dynamically loading MapLibre GL JS #4778
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-24 21:20:05 +01:00
Michael Mayer
67811d87fa Videos: Create fragmented MP4s when transcoding with FFmpeg #4892
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-24 20:47:57 +01:00
Michael Mayer
d9924010d4 UX: Reduce JS size by loading hls.light.min.js instead of hls.js #4778
hls.light.js is a smaller version of hls.js that does not include
support for alternate audio, subtitles, CMCD, EME (DRM), and variable
substitution.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-24 20:16:33 +01:00
Michael Mayer
0ddc179737 UX: Reduce JS bundle size by loading translation files on demand #4778
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-24 12:43:08 +01:00
Michael Mayer
a125219751
Update README.md 2025-03-24 07:43:30 +01:00
Michael Mayer
93b53214f6
Update README.md 2025-03-24 07:42:23 +01:00
Michael Mayer
50b0e8babf
Update README.md 2025-03-24 06:35:14 +01:00
Michael Mayer
06d6a370b7 Frontend: Update src/locales/translations.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-23 14:49:28 +01:00
Weblate
4890447787 Weblate: Update frontend translations 2025-03-23 14:49:03 +01:00
Michael Mayer
0bf2c5c580 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-23 14:44:11 +01:00
Michael Mayer
00359b1a4e Settings: Update labels in content.vue and regenerate translation files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-23 14:43:48 +01:00
Michael Mayer
c6225f7117 Setup: Update inline docs in Docker Compose config examples #4888 #4889
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-23 14:14:22 +01:00
Michael Mayer
173fa526e9 Config: Improve --prod docs in flags.go #4888 #4889
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-23 14:00:22 +01:00
Michael Mayer
555d5cdbbe Config: Improve --prod docs in flags.go #4888 #4889
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-23 13:57:50 +01:00
Michael Mayer
4ed7c6c242 Config: Update --prod and --log-level docs in flags.go #4888 #4889
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-23 13:54:59 +01:00
Michael Mayer
9a01ace34d Config: Update --prod flag documentation in flags.go #4888 #4889
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-23 13:48:38 +01:00
Michael Mayer
6e20ad6edb Dependencies: Update NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-23 13:14:49 +01:00
Michael Mayer
68d1bbb359 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-23 13:12:29 +01:00
Michael Mayer
c081155c4f Config: Improve log options documentation in flags.go #4888 #4889
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-23 13:11:55 +01:00
Michael Mayer
0b02c5d17c Database: Reduce log level for connection info to debug #4888 #4889
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-23 12:06:10 +01:00
Michael Mayer
cd577f5108
Update README.md 2025-03-23 11:10:17 +01:00
Michael Mayer
d3882edebc
Update README.md 2025-03-23 11:08:20 +01:00
Michael Mayer
cf8fbf5870
Update README.md 2025-03-23 10:25:23 +01:00
Michael Mayer
3b6efc1786
Update README.md 2025-03-22 12:35:37 +01:00
Michael Mayer
cd427c66be
Update README.md 2025-03-22 12:34:57 +01:00
Michael Mayer
9467dd89bf
Update README.md 2025-03-21 18:31:22 +01:00
Michael Mayer
57590c48bb
Docs: Update desktop and mobile screenshots in README.md 2025-03-21 05:44:29 +01:00
Michael Mayer
f4b3ed33a2 Dependencies: Update NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-20 22:11:23 +01:00
Michael Mayer
8af26827de Backend: Upgrade indirect Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-20 22:09:15 +01:00
Michael Mayer
b321c1f2c4 UX: Apply values returned by the server when changing content settings
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-20 12:56:07 +01:00
Michael Mayer
2bf60529cc UX: Block user interface while saving content and advanced settings
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-20 12:03:37 +01:00
Michael Mayer
e7df0c2125 Docs: Update config.yml section titles in config/report_sections.go
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-20 11:23:14 +01:00
Michael Mayer
f51969f0b7 Places: Prevent background flicker when route changes
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-20 08:52:32 +01:00
Michael Mayer
c7548e43e8 UX: Disable teleporting for snackbar notifications
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-20 08:29:07 +01:00
Michael Mayer
f3aa4e7e05 Frontend: Prevent replacing new auth data with restored values
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 16:51:41 +01:00
Michael Mayer
33577a1a2b Auth: Improve fallback for data stored under the previously used keys
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 16:46:26 +01:00
Michael Mayer
87ccc96181 Search: Allow searching for labels that only have an emoji as name #4761
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 16:14:30 +01:00
Michael Mayer
b2aee3a184 UX: Prevent notifications from blocking navigation
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 16:11:24 +01:00
Michael Mayer
86d5c13bce Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 15:11:01 +01:00
Michael Mayer
8b327b4ae9 Dependencies: Update NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 15:03:36 +01:00
Michael Mayer
60358da03a Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 15:01:45 +01:00
Michael Mayer
5abe0299e2 UX: Switch position of Upload and Download button in album action menu
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 14:59:34 +01:00
Michael Mayer
9d9bc43b03 Auth: Add fallback for tokens stored under the previously used key
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 14:51:51 +01:00
Michael Mayer
ba83fcedfb Albums: Prevent the same albums from being created twice #4849
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 12:00:30 +01:00
Michael Mayer
34f3d9eac1 Slugs: Use base32 encoding for slugs that don't contain text #4761
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 11:57:53 +01:00
Michael Mayer
f1d9e85a8f Sharing: Don't use the album UID twice in the redirect URL
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 11:52:46 +01:00
Michael Mayer
7489dbbed5 UX: Brighten "selected" color of Nordic theme in options/themes.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 11:51:19 +01:00
Michael Mayer
08b550143e UX: Increase background opacity of warning notifications in vuetify.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 11:50:33 +01:00
Michael Mayer
e621c0237a UX: Set contain styles for list and cards view results
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 11:49:49 +01:00
Michael Mayer
37a27b2957 UX: Use overlay when mobile navigation drawer is open
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 11:48:38 +01:00
Michael Mayer
5fa02a723a Frontend: Use canonical key for localStorage
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 11:46:15 +01:00
Michael Mayer
eee392cf08 UX: Scroll to the top instantly to avoid rendering issues
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-19 11:10:54 +01:00
Michael Mayer
4589c0de28 UX: Adjust .p-page__loading styles for cluster view im Places
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 18:12:26 +01:00
Michael Mayer
efe2fd502a Albums: Apply default sort order when uploading to a new album #405
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 16:48:00 +01:00
graciousgey
e09a166b64 Tests: Adapt acceptance tests to changes 2025-03-18 15:46:11 +01:00
graciousgrey
f4af470894 Tests: Add unit tests 2025-03-18 15:20:51 +01:00
graciousgrey
e7bed76656 Tests: Add unit tests 2025-03-18 14:49:49 +01:00
Michael Mayer
8c4bd1f3ed API: Add unit tests for DownloadName() and AlbumDownloadName() #4344
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 14:48:06 +01:00
Michael Mayer
56790b4183 Albums: Always update album contents when an album is updated
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 14:00:39 +01:00
Michael Mayer
dd18401d82 WebDAV: Add "failed" state for files that cannot be synchronized #4827
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 11:53:56 +01:00
rubyisrust
6dce52643c chore: make function comment match function name
Signed-off-by: rubyisrust <rustrover@icloud.com>
2025-03-18 10:00:49 +01:00
Michael Mayer
dfe8c2e14b Dependencies: Update NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 09:11:29 +01:00
Michael Mayer
231a046c6b Backend: Upgrade "github.com/golang/geo" in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 09:08:54 +01:00
Michael Mayer
28032d9d2b Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 09:08:54 +01:00
Michael Mayer
f9bb349bbb Frontend: Regenerate src/locales/translations.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 09:08:54 +01:00
Weblate
b288d02dc2 Weblate: Update frontend translations 2025-03-18 09:05:59 +01:00
Michael Mayer
042438eed0 Frontend: Regenerate *.po files in /src/locales
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 09:01:40 +01:00
Michael Mayer
57060844ba Auth: Improve user model and search in backend and frontend
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 09:00:50 +01:00
Michael Mayer
772a850e1a UX: Update categories available in feedback form
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 08:56:48 +01:00
Michael Mayer
6128bf4e47 Config: Require MariaDB v11.4 to use SSL for backups #4837
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 08:55:27 +01:00
Michael Mayer
8aa0cc95ea Config: Fix and improve database version detection #4837
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 08:38:18 +01:00
Michael Mayer
b7874a9880 UX: Improve input validation in feedback form
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 08:36:02 +01:00
Michael Mayer
9ab5ff91e4 UX: Add utility class to detect, request, and exit fullscreen mode #4839
This will also exit fullscreen mode in Places before unmount.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-18 06:28:04 +01:00
Michael Mayer
4ba17f36d1 Frontend: Regenerate src/locales/translations.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-17 19:29:30 +01:00
Weblate
76b8690b96 Weblate: Update backend translations 2025-03-17 19:28:17 +01:00
Weblate
b560f0deab Weblate: Update frontend translations 2025-03-17 19:28:00 +01:00
Michael Mayer
6d8c704979 Viewer: Exit fullscreen mode only if it was not previously enabled #4839
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-17 18:38:43 +01:00
Michael Mayer
1291944e11 Viewer: Improve full screen toggle and browser detection #4839
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-17 18:32:32 +01:00
Michael Mayer
f81a945e74 Albums: Add settings to set a default sort order for each type #405
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-17 17:53:33 +01:00
Michael Mayer
17c7765f6a Cards View: Don't use filename as title if showTitles is true #1164
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-17 16:56:29 +01:00
Michael Mayer
d0239ba209 UX: Improve quota calculation and checks in config and api #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-17 16:12:47 +01:00
Michael Mayer
3a5fc5c512 Backups: Remove empty lines from photoprism/backup/database.go #4837
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-17 13:26:49 +01:00
Michael Mayer
898224a4c1 Frontend: Regenerate *.po files in src/locales #577
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-17 13:25:33 +01:00
Michael Mayer
940194ab1c Backups: Detect server version to determine SSL support #4837
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-17 13:23:43 +01:00
Michael Mayer
9af3478f71 Albums: Reload pictures when the album sort order has changed #405
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-17 11:25:06 +01:00
Michael Mayer
8187182c4a Develop: Upgrade base image from 250310-oracular to 250317-oracular
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-17 11:10:11 +01:00
Michael Mayer
fc6513ad21 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-16 17:02:48 +01:00
Michael Mayer
5e8d7c1e01 Frontend: Regenerate *.po files in src/locales #577
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-16 17:02:38 +01:00
Weblate
32572ed38c Weblate: Update frontend translations 2025-03-16 17:00:44 +01:00
Michael Mayer
5887479f49 UX: Reorder UI settings in page/settings/general.vue #577
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-16 16:59:58 +01:00
Michael Mayer
cb24de4fc8 Frontend: Update tests/unit/model/photo_test.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-16 16:23:34 +01:00
Michael Mayer
328d51ee41 Albums: Add settings for downloading album archives #4344 #405
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-16 16:10:47 +01:00
Michael Mayer
23a66d52f9 UX: Remove unused td.meta-data button style in views.css #4727
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-16 14:36:55 +01:00
Michael Mayer
9178c37930 UX: Hide list view table header on very small screens #1164 #4727
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-16 13:23:03 +01:00
Michael Mayer
35b42a116d UX: Improve result selection in list view #1164 #4727
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-16 13:13:46 +01:00
Michael Mayer
cf428e3245 UX: Allow display of disk usage information in demo mode #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-15 18:46:40 +01:00
Michael Mayer
79e6ebaf4f UX: Update icon for PDF documents in search results #4600
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-15 16:31:18 +01:00
Michael Mayer
5b300d6764 UX: Update browse route handling in common/config.js #577
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-15 16:06:46 +01:00
Michael Mayer
5496cd06a3 UX: Allow guests to choose a start page as well #577
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-15 16:01:55 +01:00
Michael Mayer
4a6d3a9bd8 UX: Redirect users accessing /library/ to the default route #577
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-15 15:44:20 +01:00
Michael Mayer
6275539412 Frontend: Update src/locales/translations.json #577
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-15 14:52:36 +01:00
Michael Mayer
0350e5d572 UX: Add UI settings for selecting start page and time zone #577
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-15 14:51:44 +01:00
Weblate
32cbd1ade9 Weblate: Update frontend translations 2025-03-15 14:48:00 +01:00
Michael Mayer
aef8f4e8ce Frontend: Regenerate *.po files in src/locales
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-15 14:43:16 +01:00
graciousgey
599e3683c1 Tests: Add classes for testing 2025-03-15 13:39:37 +01:00
Weblate
8c551d2871 Weblate: Update frontend translations 2025-03-15 12:54:00 +01:00
Michael Mayer
faaf541979 Frontend: Regenerate *.po files in src/locales
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-15 12:49:06 +01:00
Michael Mayer
4c30f6fd2f Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-15 11:26:58 +01:00
Michael Mayer
ea90be0ce9 Settings: Update frontend/src/locales/translations.json #1164
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-15 11:26:48 +01:00
Weblate
867a2653ce Weblate: Update frontend translations 2025-03-15 11:24:12 +01:00
Michael Mayer
47f99ea2b6 Settings: Update frontend/src/locales/translations.json #1164
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 16:16:20 +01:00
Weblate
62c6578a16 Weblate: Update frontend translations 2025-03-14 16:15:11 +01:00
Michael Mayer
4537fc6129 Settings: Update frontend/src/locales/translations.json #1164
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 16:13:35 +01:00
Weblate
a5b41dbf84 Weblate: Update frontend translations 2025-03-14 16:13:07 +01:00
Michael Mayer
4af1ab6a76 UX: Update usage hint texts in Settings > Content #1164
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 16:09:42 +01:00
Michael Mayer
012f579305 Settings: Update frontend/src/locales/translations.json #1164
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 16:04:54 +01:00
Weblate
46475678ad Weblate: Update frontend translations 2025-03-14 16:03:57 +01:00
Michael Mayer
4357f8e732 UX: Make information shown on cards view configurable #1164
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 16:01:05 +01:00
Michael Mayer
72a8a9f801 Settings: Update icons for "Content" and "Disable ExifTool" #405 #4344
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 12:55:51 +01:00
Michael Mayer
88a7a31cbf Settings: Update frontend/src/locales/translations.json #405 #4344
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 12:38:55 +01:00
Weblate
0b65e8491b Weblate: Update frontend translations 2025-03-14 12:38:29 +01:00
Michael Mayer
994b30ad49 Settings: Update frontend/src/locales/translations.json #405 #4344
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 12:34:28 +01:00
Weblate
bf409c2c20 Weblate: Update frontend translations 2025-03-14 12:33:05 +01:00
Michael Mayer
8d049155ca Settings: Rename "Library" tab to "Content" and add redirect #405 #4344
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 12:30:04 +01:00
Michael Mayer
eae5d97a43 Frontend: Regenerate *.po files in src/locales
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 12:25:44 +01:00
Michael Mayer
a2b5bd8a14 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 12:11:09 +01:00
Michael Mayer
982e5ae1c8 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 12:10:50 +01:00
Michael Mayer
646beba018 Frontend: Regenerate *.po files in src/locales
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 12:10:30 +01:00
Michael Mayer
23c7d22d23 Frontend: Add additional link URLs to common/links.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 11:09:26 +01:00
Michael Mayer
86a7d21c6b Frontend: Add documentation link URLs to common/links.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 10:44:39 +01:00
Michael Mayer
2a9d9f1584 UX: Remove Settings from the action menu in component/photo/toolbar.vue
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-14 10:09:00 +01:00
NinaLua
b3ad0e5b92 refactor: using slices.Contains to simplify the code
Signed-off-by: NinaLua <iturf@sina.cn>
2025-03-14 10:06:09 +01:00
Michael Mayer
2440c5424d Frontend: Refactor album toolbar styles in toolbar.vue and pages.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-13 15:57:32 +01:00
Michael Mayer
262f2abc9e Frontend: Optimize page toolbar title styles in src/css/pages.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-13 12:21:06 +01:00
Michael Mayer
6020b3158c Frontend: Update locale dir tests in unit/common/config_test.js #4778
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-13 11:31:19 +01:00
Michael Mayer
e2054f3d62 Backend: Upgrade github.com/zitadel/oidc/v3 in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-13 11:08:41 +01:00
Michael Mayer
4cb60f156c Frontend: Add reusable <p-action-menu> component #4830 #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-13 10:25:52 +01:00
Michael Mayer
85c079caba Frontend: Replace PPhotoDeleteDialog with standard PConfirmDialog #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-13 08:27:33 +01:00
Michael Mayer
762a9978bc Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-13 08:11:35 +01:00
Michael Mayer
b90c946811 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-13 08:03:08 +01:00
Michael Mayer
c2f8a642d7 Frontend: Regenerate src/locales/translations.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-13 08:01:25 +01:00
Weblate
e2aa6362fb Weblate: Update frontend translations 2025-03-13 08:00:41 +01:00
Michael Mayer
ea8d2a1f5f Frontend: Rename component/confirm/action.vue to dialog.vue #4811
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-13 07:59:36 +01:00
Michael Mayer
e5c67a0563 UX: Increase font size of .v-table footer in css/vuetify.css
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-13 07:57:56 +01:00
Michael Mayer
a5f15a7116 Frontend: Apply locale settings only once during initialization #4778
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-13 07:38:46 +01:00
Weblate
088ef815ce Weblate: Update backend translations 2025-03-12 20:31:21 +01:00
Michael Mayer
b4e082f56b UX: Refactor toolbar inputs and buttons with a three-dot menu #4830
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-12 20:12:39 +01:00
Weblate
e9e0d3ff3f Weblate: Update frontend translations 2025-03-12 20:09:32 +01:00
Michael Mayer
376099a0d0 Frontend: Regenerate *.po files in src/locales
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-12 20:03:27 +01:00
graciousgrey
a3067a8887 Tests: Add unit tests 2025-03-12 16:34:28 +01:00
Michael Mayer
9936c21aeb Documents: Update search queries and filter documentation #4600
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-12 04:48:15 +01:00
Michael Mayer
f747211017 Library: Add support for indexing PDF documents #4600
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-12 04:26:04 +01:00
Weblate
a3914d6098 Weblate: Update frontend translations 2025-03-12 04:19:37 +01:00
Michael Mayer
5ad5f7447f Frontend: Regenerate *.po files in src/locales
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-12 04:03:10 +01:00
Michael Mayer
7f0717e9a0 Auth: Prevent login if additional accounts may not be created #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-12 01:08:16 +01:00
Michael Mayer
bfc6cb2351 Frontend: Update .map-background gradient in src/css/places.css #4762
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-12 00:36:02 +01:00
Michael Mayer
99eae989d0 Frontend: Update .map-background styles in src/css/places.css #4762
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-12 00:21:06 +01:00
Michael Mayer
eb489d420a Frontend: Simplify styles in src/css/places.css #4762
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-12 00:01:57 +01:00
Michael Mayer
56f1c06300 Places: Adjust brightness of small stars in 3D Earth view #4762
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 23:59:32 +01:00
Michael Mayer
bcea7ac078 Places: Increase brightness of small stars in 3D Earth view #4762
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 23:55:15 +01:00
Michael Mayer
eb9371d089 WebDAV: Skip download sync if storage is full or quota is exceeded #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 23:45:41 +01:00
Michael Mayer
c3d22c157c Places: Add night sky background with stars for 3D Earth view #4762
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 23:09:06 +01:00
Michael Mayer
bed5ed2760 Frontend: Regenerate src/locales/translations.json #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 21:00:43 +01:00
Weblate
70651b29b1 Weblate: Update frontend translations 2025-03-11 21:00:06 +01:00
Michael Mayer
de5072a73d Frontend: Improve error messages for exceeded storage size #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 20:57:11 +01:00
Weblate
bf5b70e8b9 Weblate: Update backend translations 2025-03-11 20:37:30 +01:00
Michael Mayer
a66d3278ab API: Prevent file imports/uploads if there is no free storage #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 20:35:07 +01:00
Michael Mayer
0e3c365cac UX: Improve lavender theme notification colors
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 19:40:22 +01:00
Michael Mayer
94a4d17f49 UX: Improve snackbar notification styles
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 19:22:59 +01:00
Michael Mayer
ea428f8f20 Frontend: Regenerate src/locales/translations.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 18:11:53 +01:00
Weblate
4ec95ca6ca Weblate: Update frontend translations 2025-03-11 18:11:19 +01:00
Weblate
3fa937f489 Weblate: Update backend translations 2025-03-11 18:10:28 +01:00
Michael Mayer
44fc11b537 UX: Improve alert and notification styles
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 18:06:24 +01:00
Michael Mayer
7a97b38cb3 UX: Specify files quota in GB instead of MB #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 18:04:10 +01:00
Michael Mayer
6eec12c8c9 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 18:00:27 +01:00
Michael Mayer
71c89ce407 CI: Upgrade TestCafe to v3.7.2 in scripts/dist/install-nodejs.sh
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 17:59:54 +01:00
Michael Mayer
2f2915451e Frontend: Regenerate *.po files in src/locales
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 17:59:05 +01:00
Michael Mayer
f0eb7828e3 Backend: Regenerate *.po files in /assets/locales
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 17:58:12 +01:00
Michael Mayer
08b3cabad6 UX: Improve data table and pagination styles
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-11 10:45:31 +01:00
graciousgrey
006ed32838 Tests: Add unit tests #4848 2025-03-10 19:03:59 +01:00
Michael Mayer
8f6880b034 UX: Show lens details after camera information in Cards results view
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-10 18:04:31 +01:00
Michael Mayer
c35567d1c7 Backend: Regenerate assets/locales/*/*.po files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-10 17:38:13 +01:00
Michael Mayer
114a51ccae UX: Enable disk usage information in development environment #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-10 17:36:39 +01:00
Michael Mayer
ed9a14b609 Search: Use component v-progress-circular for loading animation
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-10 17:35:48 +01:00
graciousgrey
ad3b00f009 Tests: Add unit tests #4266 2025-03-10 17:33:00 +01:00
Michael Mayer
de734148d2 UX: Improve camera information in Cards results view
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-10 16:31:04 +01:00
Michael Mayer
df09c78ee1 Videos: Add "codec" search filter and auto-enable nvidia encoder #4848
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-10 14:30:25 +01:00
Michael Mayer
587867a41a Backend: Regenerate assets/locales/*/*.po
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-10 13:16:09 +01:00
graciousgrey
6532054950 Frontend: Add show new faces button to no-result view 2025-03-10 13:11:13 +01:00
Michael Mayer
bf5c66b660 UX: Always show image size information in Cards results view
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-10 12:51:15 +01:00
Michael Mayer
478ba483d2 Develop: Upgrade base image from 250221-oracular to 250310-oracular
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-10 11:24:52 +01:00
Michael Mayer
d08eab37e9 Frontend: Regenerate src/locales/translations.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-10 11:23:06 +01:00
Weblate
368dc135e5 Weblate: Update frontend translations 2025-03-10 11:22:21 +01:00
Michael Mayer
5c4c7011e5 Backend: Update Go deps in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-10 11:20:39 +01:00
Michael Mayer
38a921d14a Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-10 11:20:04 +01:00
Weblate
f652159522 Weblate: Update frontend translations 2025-03-05 22:08:06 +01:00
Weblate
05a88780f7 Weblate: Update backend translations 2025-03-04 08:35:27 +01:00
Michael Mayer
b1de2b70f4 Frontend: Regenerate src/locales/translations.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-04 08:34:11 +01:00
Michael Mayer
8f914e293e Backend: Regenerate assets/locales/*/*.po #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-04 08:34:01 +01:00
Weblate
b3e6656893 Weblate: Update frontend translations 2025-03-04 08:32:17 +01:00
Michael Mayer
e298cb42b6 Backend: Regenerate assets/locales/messages.pot #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-04 08:30:35 +01:00
Michael Mayer
b1d9f24fc5 Config: Disable uploads and imports when storage is full #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-04 08:28:28 +01:00
graciousgey
580cfbe078 Tests: Improve acceptance test to be stable 2025-03-04 08:00:54 +01:00
Michael Mayer
ace90d95a4 Config: Refactor filesystem usage detection and add tests #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-03 21:05:08 +01:00
Michael Mayer
fbdd621111 Config: Fix total disk space calculation in config_usage.go #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-03 20:28:20 +01:00
Michael Mayer
2dba0fdeab Frontend: Regenerate src/locales/translations.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-03 20:12:57 +01:00
Michael Mayer
3d63ea3586 Frontend: Update deps in package.json and package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-03 20:12:30 +01:00
Weblate
062739ed77 Weblate: Update frontend translations 2025-03-03 20:11:24 +01:00
Michael Mayer
c2cc50b670 Config: Add option to show filesystem usage in sidebar navigation #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-03 20:05:56 +01:00
Michael Mayer
abfb19bd63 UX: Improve "Nordic" theme colors in frontend/src/options/themes.js
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-03 19:58:52 +01:00
graciousgrey
81c025442a Tests: Add acceptance tests 2025-03-03 18:56:28 +01:00
Michael Mayer
59bb5e0bdb UX: Add box-shadow to page navigation in css/pages.css #4830
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-03 13:44:20 +01:00
Michael Mayer
e1a9a68b29 FS: Add /pkg/fs/duf to determine mount points and disk usage #4266
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-03 11:24:30 +01:00
Michael Mayer
5c1b0ba96b Frontend: Regenerate src/locales/translations.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-02 19:15:21 +01:00
Weblate
219ccfe8dd Weblate: Update frontend translations 2025-03-02 19:13:05 +01:00
Michael Mayer
a146e2ed99 Frontend: Update src/locales/*.po files
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-02 19:11:32 +01:00
Michael Mayer
71a4376565 Frontend: Regenerate src/locales/translations.json #3168
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-02 14:28:04 +01:00
Weblate
a4d149c64c Weblate: Update frontend translations 2025-03-02 14:26:58 +01:00
Michael Mayer
c42f88ace0 UX: Dynamically set position of scroll-to-top button #4830
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-02 14:22:00 +01:00
Michael Mayer
e0e422e8f1 Frontend: Update deps in package-lock.json
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-02 13:49:29 +01:00
Michael Mayer
1574a4e16f UX: Make page tabs and toolbars sticky so they remain visible #4830
Signed-off-by: Michael Mayer <michael@photoprism.app>
2025-03-02 13:49:12 +01:00
3373 changed files with 411285 additions and 125901 deletions

2
.agents/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

8
.claude/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
*
!.gitignore
!CLAUDE.md
!rules
!rules/*.md
!agents
!agents/*.md
!settings.json

148
.claude/CLAUDE.md Normal file
View file

@ -0,0 +1,148 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. Detailed rules are in `.claude/rules/*.md` files organized by topic.
## Build Commands
Run `make help` to list all available targets. Key commands:
**Backend (Go):**
- `make build-go` — build the `photoprism` binary (develop mode)
- `make build-all` — build backend + frontend
- `go build ./...` — compile all Go packages
**Frontend (Vue 3):**
- `make build-js` — production build of the frontend
- `make watch-js` — watch mode for frontend development (Ctrl+C to stop)
**Dependencies:**
- `make dep` — install all dependencies (TensorFlow models, ONNX models, JS packages)
- `make dep-js` — install JS dependencies only (`npm ci`). The `photoprism/develop` image and the repo `Makefile` both set `NPM_CONFIG_IGNORE_SCRIPTS=true`, so install scripts are skipped automatically; when running npm directly in an env without that default, pass `--ignore-scripts`. Rebuild native addons with `npm rebuild --ignore-scripts=false <pkg>` — a bare `npm rebuild` no-ops wherever the env default is active.
**Docker dev environment:**
- `make docker-build` — build local Docker image
- `docker compose up` — start dev environment (app at http://localhost:2342/)
- `make terminal` — open shell in dev container
## Testing
**Run all tests:**
- `make test` — runs both JS and Go tests
- `make test-go` — all Go tests (slow, ~20 min)
- `make test-js` — frontend unit tests (Vitest)
- `make test-short` — short Go tests in parallel (~5 min)
**Run targeted Go tests:**
```bash
go test ./internal/api -run 'TestFunctionName' -count=1
go test ./internal/photoprism -run 'TestMediaFile_' -count=1
go test ./internal/entity/... -count=1 -tags="slow,develop"
```
**Run targeted JS tests:**
- `make vitest-watch` — Vitest in watch mode
- `make vitest-coverage` — Vitest with coverage report
**Reset test databases before running Go tests:**
- `make reset-testdb` — clears SQLite test DBs and MariaDB testdb
**Subset targets:** `make test-pkg`, `make test-api`, `make test-entity`, `make test-commands`, `make test-photoprism`, `make test-ai`
## Formatting & Linting
Available targets: `make fmt` (everything), `make fmt-go`, `make fmt-js`, `make fmt-swag` / `make swag` (Swagger), `make lint-go`, `make lint-js`. Detailed conventions live in `.claude/rules/go-code-style.md` and `.claude/rules/frontend-rules.md`.
When creating or editing shell scripts, run `shellcheck <file>` and resolve warnings. When editing Markdown files that contain tables, format them with `npx --yes markdown-table-formatter <filename>`.
## Schema Migrations
If a change touches database schema, check migrations:
```bash
go run cmd/photoprism/photoprism.go migrations ls
go run cmd/photoprism/photoprism.go migrations run
# or via Makefile:
make migrate
```
Migration files live in `internal/entity/migrate/`.
## Architecture Overview
PhotoPrism is a self-hosted photo management app. The backend is Go, the frontend is Vue 3 + Vuetify 3, and the database is MariaDB or SQLite (via GORM).
### Backend (`internal/`, `pkg/`, `cmd/`)
| Package | Purpose |
|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `internal/photoprism` | **Core application logic**: indexing originals, metadata extraction, thumbnail generation, import/stacking, converter orchestration (FFmpeg/ImageMagick/ExifTool). Entry point for workers and CLI. |
| `internal/entity` | **Database models** (GORM): Photo, File, Album, Label, Face, User, Session, etc. Contains fixtures for tests and migration helpers. |
| `internal/entity/query` | Database query helpers used by the API and core packages. |
| `internal/api` | **REST API handlers** (Gin): thin handlers that validate input, enforce ACL/auth, delegate to services. Annotated with Swagger comments. |
| `internal/server` | HTTP server setup, routing (Gin engine), WebDAV, static assets, middleware wiring. Routes are registered in `routes.go`. |
| `internal/config` | Application configuration: CLI flags, env vars, client config sent to the frontend. |
| `internal/workers` | Background workers: indexing scheduler, metadata sync, sharing, backup, vision jobs. |
| `internal/commands` | CLI command implementations (`github.com/urfave/cli/v2`). |
| `internal/auth` | Authentication: ACL (`auth/acl`), JWT (`auth/jwt`), OIDC (`auth/oidc`), session management. |
| `internal/form` | Request form/binding structs for the API layer. |
| `internal/meta` | Metadata extraction from EXIF, XMP, JSON sidecars. |
| `internal/ffmpeg` | FFmpeg/transcoding helpers. |
| `internal/thumb` | Thumbnail generation helpers. |
| `internal/ai` | AI/vision model integration (TensorFlow, ONNX). |
| `internal/service` | Services: maps geocoding, hub (membership), cluster, WebDAV client, CIDR helpers. |
| `internal/event` | Event bus for structured logging and audit events. |
| `pkg/` | Standalone, reusable packages: `fs`, `geo`, `media`, `txt`, `clean`, `rnd`, `i18n`, `http`, `time`, etc. No dependency on `internal/`. |
**Request flow:** HTTP request → Gin middleware (auth, rate limiting) → `internal/api` handler → `internal/photoprism` or `internal/entity` → response.
**Audit logging convention** (`event.AuditInfo/Warn/Err`): slices must follow the pattern **Who → What → Outcome**:
- Who: `ClientIP(c)` + actor context (`"session %s"`, `"user %s"`)
- What: resource constant + action segments
- Outcome: single token like `status.Succeeded`, `status.Failed`, `status.Denied`, `status.Error(err)`
### Frontend (`frontend/`)
Vue 3 app using the Options API and Vuetify 3.
| Directory | Purpose |
|---------------------------|-------------------------------------------------------------------------------------------------|
| `frontend/src/model/` | Client-side models mirroring API responses (Photo, Album, File, User, etc.) |
| `frontend/src/app/` | App bootstrap, routing (`routes.js`), and the `$session` reactive singleton |
| `frontend/src/page/` | Page-level components |
| `frontend/src/component/` | Reusable UI components |
| `frontend/src/common/` | Shared utilities, the API client (`$api`), and reactive singletons (`$config`, `$view`, `$log`) |
| `frontend/src/locales/` | i18n translation files |
| `frontend/tests/` | Vitest unit tests + TestCafe acceptance tests |
State management uses reactive singleton modules in `src/common/` and `src/app/`, not Vuex or Pinia. Frontend code-style, formatting, testing, translation, and Playwright rules live in `.claude/rules/frontend-rules.md`.
### API Conventions
- REST API v1 base path: `/api/v1/` (configured via `conf.BaseUri()`)
- Authentication: Bearer token (`Authorization` header) or `X-Auth-Token` header
- Pagination: `count`, `offset`, `limit` parameters (default 100, max 1000)
- After adding/changing API handlers, regenerate Swagger docs: `make fmt-go swag-fmt swag`
- New routes must be registered in `internal/server/routes.go`
### Config & Flags
Verify config option names before using them:
```bash
./photoprism --help
./photoprism show config-options
./photoprism show config-yaml
```
### Verify Before Propagating
Before promoting a claim from `CLAUDE.md`, `AGENTS.md`, a memory entry, or another spec into a new rule, spec, code comment, or commit message, verify it against the current code (grep imports, list directories, read the cited file). Stale documentation silently turns into stale rules and stale specs that future sessions will trust. When the claim names a package, function, file, or framework, the cost of one grep is much smaller than the cost of repeating an error across multiple files.
### Detailed Rules
Topic-specific conventions live under `.claude/rules/` and are loaded alongside this file:
- `code-comments.md` — shared JS/Go doc comment rules (length cap, what to omit); referenced by both style files.
- `go-code-style.md`, `go-testing.md` — Go style, package boundaries, test patterns, fixtures.
- `frontend-rules.md` — JS/Vue code style, formatting, dependencies, tests, Playwright, translations.
- `commit-and-docs-style.md` — commit-message format, GitHub issue templates, spec heading style.
- `safety-and-security.md` — Git/data safety, destructive commands, file I/O and archive-extraction policies, HTTP download helpers.
- `api-and-config.md`, `cluster-operations.md`, `import-index-download.md`, `build-and-runtime.md`, `sources-of-truth.md` — domain-specific guidance.

View file

@ -0,0 +1,41 @@
---
name: ui-tester
description: Drives the Playwright MCP browser to exercise UI flows, verify behavior in a real Chromium, and report findings concisely. Use for any task that needs to navigate pages, click through flows, fill forms, capture console errors, check network requests, or validate UI state. Returns a short verdict + evidence so the parent context isn't filled with raw snapshots and console logs.
tools: Bash, Read, Grep, Glob, WebFetch, ToolSearch, mcp__playwright__browser_navigate, mcp__playwright__browser_navigate_back, mcp__playwright__browser_snapshot, mcp__playwright__browser_take_screenshot, mcp__playwright__browser_click, mcp__playwright__browser_hover, mcp__playwright__browser_drag, mcp__playwright__browser_drop, mcp__playwright__browser_type, mcp__playwright__browser_fill_form, mcp__playwright__browser_select_option, mcp__playwright__browser_press_key, mcp__playwright__browser_file_upload, mcp__playwright__browser_handle_dialog, mcp__playwright__browser_wait_for, mcp__playwright__browser_console_messages, mcp__playwright__browser_network_requests, mcp__playwright__browser_evaluate, mcp__playwright__browser_run_code, mcp__playwright__browser_resize, mcp__playwright__browser_tabs, mcp__playwright__browser_close
---
You are a focused UI test driver. The parent agent has delegated browser-driven work to you so its context stays clean. Your output is the only thing it sees — make it short, structured, and decision-ready.
## Loading tool schemas
The Playwright MCP tools above appear in your toolset by name but their schemas are deferred. Before you can call any of them, run `ToolSearch` once with `select:<tool_names>` to load the schemas for the specific tools you need (e.g. `select:mcp__playwright__browser_navigate,mcp__playwright__browser_snapshot,mcp__playwright__browser_click`). Don't load all of them — just the handful this task actually needs.
## Browser environment
- The MCP server runs **one shared Chromium instance** with a **persistent profile**. Cookies and `localStorage` from earlier sessions persist. Assume state may already exist — log in fresh if a flow requires a known account.
- This profile is **separate** from the user's real Chrome. You won't see their personal logins or extensions.
- There is no parallelism — only you should be driving the browser during your run.
## Workflow
1. **Plan first.** Decide the minimum flow that proves or disproves the parent's question. Don't explore; execute.
2. **Run.** Navigate, interact, observe. Prefer `browser_snapshot` (accessibility tree) over `browser_take_screenshot` — it's much smaller and works for assertions. Reach for screenshots only when the parent explicitly wants visual evidence.
3. **Capture signals.** Pull `browser_console_messages` and, if relevant, `browser_network_requests` near the end of the flow — they're often the actual answer.
4. **Clean up before returning.** Call `browser_close` so the next subagent starts with no open tabs. The persistent profile keeps cookies, but tabs/state shouldn't leak across runs.
## Reporting format
Default to **under 300 words** unless the parent asked for more. Structure:
- **Verdict:** one sentence — pass / fail / partial, and what was tested.
- **Evidence:** 36 bullet points with the concrete observations (URLs visited, elements clicked, console errors verbatim, network failures with status codes). Quote error messages exactly; don't paraphrase.
- **Notes (optional):** anything the parent should know that wasn't asked for but matters (e.g. "noticed an unrelated 404 on `/api/foo`").
Don't paste full snapshots, full console logs, or screenshot data unless the parent specifically requested them. The parent does not need to see your tool-call play-by-play — just the conclusion and the evidence supporting it.
## What not to do
- Don't open new browsers, install Playwright, or modify the MCP server config.
- Don't edit application code unless the parent explicitly told you to. Your job is to test what's there.
- Don't run long-form Go/JS test suites (that's `make test` territory) — you're the manual-QA-in-a-browser agent, not a CI runner.
- Don't summarize what you just did at the end ("I navigated to X, then clicked Y, then..."). The verdict + evidence is the summary.

View file

@ -0,0 +1,42 @@
## API & Config Changes
- Respect precedence: `options.yml` overrides CLI/env values, which override defaults.
- Adding a new option: update `internal/config/options.go` (yaml/flag tags), register in `internal/config/flags.go`, expose a getter, surface it in `*config.Report()`, and write generated values back to `options.yml`. Use `CliTestContext` in `internal/config/test.go` to exercise new flags.
- Adding a `customize.FeatureSettings` flag: a new field defaults to `true` via reflection (`features_default.go`) and is operator-disableable through `PHOTOPRISM_DISABLE_FEATURES` — no new CLI option needed. It cascades: update the full-struct literals in `internal/config/customize/{acl,scope}_test.go` and `internal/config/client_config_test.go` (the longest field name re-aligns every literal via gofmt), and `testdata/settings.yml` self-updates via `TestSettings_Save`. If the flag is only meaningful for accounts/roles, gate it per-session in `customize.Settings.ApplyACL` / `ApplyScope` (e.g. `Account`/`AppPasswords` require `ResourcePassword`/`ActionUpdate`); that shapes the Web UI client config only — enforce server-side behavior on the global flag via a `Config.DisableX()` helper.
- Identify an app-password credential by its session, not its token: `(*entity.Session).IsApplication()` (auth provider `application`) covers every grant that mints one (`password`/`session`/`cli`). The token format and grant type vary, so don't gate on `rnd.IsAppPassword` or `GrantType`.
- For `options.yml` writes, prefer config-owned persistence helpers: `Config.SaveOptionsPatch(...)` for generic merges, `Config.SaveClusterOptionsUpdate(...)` for cluster-managed metadata.
- Use `pkg/fs.ConfigFilePath` for config filenames so existing `.yml` files stay valid and new installs can adopt `.yaml` transparently.
- Use the public accessors on `*config.Config` (e.g. `JWKSUrl()`, `SetJWKSUrl()`) instead of mutating `Config.Options()` directly; reserve raw option tweaks for test fixtures.
- New metadata sources (e.g. `SrcOllama`, `SrcOpenAI`) must be defined in both `internal/entity/src.go` and the frontend lookup tables (`frontend/src/common/util.js`).
- Config init order: load `options.yml` (`c.initSettings()`), run `EarlyExt().InitEarly(c)`, connect/register the DB, then `Ext().Init(c)`.
- Favor explicit CLI flags: check `c.cliCtx.IsSet("<flag>")` before overriding user-supplied values.
- Database helpers: reuse `conf.Db()` / `conf.Database*()`, avoid GORM `WithContext`, quote MySQL identifiers, and reject unsupported drivers early.
## Handler Conventions
- Reuse limiter stacks (`limiter.Auth`, `limiter.Login`) and `limiter.AbortJSON` for 429s. Lean on `api.ClientIP`, `header.BearerToken`, and `Abort*` helpers.
- Compare secrets with constant-time checks; set `Cache-Control: no-store` on sensitive responses.
- Register routes in `internal/server/routes.go`. New list endpoints default `count=100` (max 1000) and `offset≥0`; document parameters explicitly.
- Set portal mode via `PHOTOPRISM_NODE_ROLE=portal` plus `PHOTOPRISM_JOIN_TOKEN` when needed.
## API Shape Checklist
When renaming or adding fields:
- Field casing: **TitleCase** (`UUID`, `Name`, `SiteUrl`) for fields backed by a DB entity (mirror the entity/model), **camelCase** (`storageNamespace`, `redirectUri`) for generated/artificial payloads (client config, session, action/RPC bodies). A filtered/computed entity projection stays TitleCase; an action payload stays camelCase but MAY TitleCase its single entity-identity field (e.g. `UUID`). See `specs/common/field-casing.md`.
- Update DTOs in `internal/service/cluster/response.go` and any mappers.
- Update handlers and regenerate Swagger: `make fmt-go swag-fmt swag`.
- Update tests (search/replace old field names) and examples in `specs/`.
- Quick grep: `rg -n 'oldField|newField' -S` across code, tests, and specs.
## Testing Helpers
- Isolate config paths with `t.TempDir()`; reuse `NewConfig`, `CliTestContext`, and `NewApiTest()` harnesses.
- Authenticate via `AuthenticateAdmin`, `AuthenticateUser`, or `OAuthToken`. Toggle auth with `conf.SetAuthMode(config.AuthModePasswd)`.
- Prefer OAuth client tokens over non-admin fixtures for negative permission checks.
## Roles & ACL
- Map roles via the shared tables: users through `acl.ParseRole(s)` / `acl.UserRoles[...]`, clients through `acl.ClientRoles[...]`.
- Treat `RoleAliasNone` ("none") and an empty string as `RoleNone`; default unknown client roles to `RoleClient`.
- Build CLI role help from the registered role map (never hand-maintained literals) so each edition lists exactly the roles it accepts: `commands.UserRoleUsageFor(<map>)` / `Roles.CliUsageString()`, passing CE `acl.UserRoles` or an edition's own static `auth.UserRoles` (reference the edition map directly, not the runtime-reassigned `acl.UserRoles`, to avoid the init-order trap; Portal's map includes `cluster_admin`). For federatable / cluster-instance contexts (LDAP, OIDC group→role, cluster grants) use `acl.ClusterInstanceRolesCliUsageString()` — it excludes `cluster_admin`/`visitor`. `pkg/txt.JoinOr` renders the "a, b, or c" style.
- For JWT/client scope checks, use the shared helpers (`acl.ScopePermits` / `acl.ScopeAttrPermits`).

View file

@ -0,0 +1,46 @@
## Agent Runtime (Host vs Container)
Agents MAY run either inside the Development Environment container (recommended) or on the host.
### Detecting the Environment
- **Inside container if** `/.dockerenv` exists (authoritative signal).
- Path hint: when the project path is `/go/src/github.com/photoprism/photoprism` *and* `/.dockerenv` is absent, assume you are on the host with a bind mount.
### Host Mode
- Build local dev image (once): `make docker-build`
- Start services: `docker compose up` (add `-d` for background)
- Follow live app logs: `docker compose logs -f --tail=100 photoprism`
- Execute a single command in the app container: `docker compose exec photoprism <command>`
- Run as non-root to avoid root-owned files: `docker compose exec -u "$(id -u):$(id -g)" photoprism <command>`
- Open a terminal session: `make terminal`
- Stop everything: `docker compose --profile=all down --remove-orphans` (`make down`)
### Container Mode
- Install deps: `make dep`
- Build frontend/backend: `make build-js` and `make build-go`
- Watch frontend changes: `make watch-js`
- Start PhotoPrism server: `./photoprism start`
- HTTP: http://localhost:2342/
- HTTPS: https://app.localssl.dev/ (via Traefik, if running)
- Admin Login: Default credentials are `admin` / `photoprism`; check `compose.yaml` for `PHOTOPRISM_ADMIN_USER` and `PHOTOPRISM_ADMIN_PASSWORD` if they differ.
- Do not use the Docker CLI inside the container; starting/stopping services requires host Docker access.
### Operating Systems & Architectures
- Guides and command examples assume Linux/Unix shell on 64-bit AMD64 or ARM64.
- For Windows-specifics, see the Developer Guide FAQ: https://docs.photoprism.app/developer-guide/faq/#can-your-development-environment-be-used-under-windows
### CLI Binary Names
The CLI name is `photoprism` in production and public docs. Other binary names (`photoprism-plus`, `photoprism-pro`, `photoprism-portal`) are only used in development builds for side-by-side comparisons.
## Container Image Builds
- **Pin the dev `Dockerfile` `FROM` to a dated `photoprism/develop` tag, never the floating codename.** Use `photoprism/develop:<YYMMDD>-<codename>` (e.g. `photoprism/develop:260520-resolute`), not `photoprism/develop:resolute` / `:latest` / `:ubuntu`. The dated tag pins to a known-good build so a drive-by `docker pull` doesn't silently swap in a fresh base mid-session, and bumping the date in a commit gives developers + reviewers a visible signal that a new base image is available. The `buildx-multi.sh` script publishes both `:<codename>` and `:<YYMMDD>-<codename>` on every build — the dated one is the durable pointer. When you bump the base image, also update `Dockerfile`, the host `compose.yaml` (if it references the tag explicitly), and any docs that quote the current dev image.
- **Never mix Debian and Ubuntu `apt` repositories in the same image:**
- Don't add a Debian source to an Ubuntu base (or vice versa) to install a single missing package — the transitive deps drift, apt's solver pulls newer libraries from the foreign distro, and other build steps in the same `RUN` (e.g. `install-libheif.sh` running `apt-get install libavcodec-dev`) silently link against the wrong soname.
- Symptoms surface much later as `dlopen: libfoo.so.N: cannot open shared object file` at image runtime, with the binary referencing a soname that exists only in the foreign distro.
- If a package isn't available in the host distro's repos, prefer (a) a same-distro PPA / backports source, (b) a vendor-supplied .deb (e.g. Google Chrome from `dl.google.com`), or (c) a from-source build pinned to a known version.

View file

@ -0,0 +1,41 @@
## Cluster Operations
- Keep bootstrap decoupled: avoid importing `internal/service/cluster/node/*` from `internal/config` or the cluster root; nodes talk to the Portal over HTTP(S) using constants from `internal/service/cluster/const.go`.
- Bootstrap refreshes node OAuth credentials on 401/403 (rotate secret + retry, info-level log). If the secret file can't be written, the rotated value stays cached in memory so the current process continues.
- Portal validation accepts HTTP advertise URLs only for loopback or cluster-internal domains (`*.svc`, `*.cluster.local`, `*.internal`); everything else must use HTTPS.
- Theme endpoint: `GET /api/v1/cluster/theme` streams a zip from `conf.ThemePath()`; reinstall only when `app.js` is missing and always use the header helpers in `pkg/http/header`.
- Registration flow: send `rotate=true` only for MySQL/MariaDB nodes without credentials; treat 401/403/404 as terminal; include `ClientID` + `ClientSecret` when renaming an existing node; persist only newly generated secrets or DB settings.
### Registry & DTOs
- Use the client-backed registry (`NewClientRegistryWithConfig`) — the file-backed version is legacy.
- Nodes are keyed by UUID v7 (`/api/v1/cluster/nodes/{uuid}`); registry interface is UUID-first (`Get`, `FindByNodeUUID`, `FindByClientID`, `RotateSecret`, `DeleteAllByUUID`). CLI lookups resolve `uuid → ClientID → name`.
- DTOs normalize `Database.{Name,User,Driver,RotatedAt}`; `ClientSecret` is exposed only during creation/rotation. `nodes rm --all-ids` cleans duplicate client rows. `ClientData` no longer stores `NodeUUID`.
- Admin responses may include `AdvertiseUrl`/`Database`; client/user sessions stay redacted.
- Registry files live under `conf.PortalConfigPath()/nodes/` (mode 0600).
### Provisioner & DSN
- Database/user names use UUID-based HMACs (`<prefix>d<hmac11>`, `<prefix>u<hmac11>`; prefix defaults to `cluster_`).
- `BuildDSN` accepts a `driver` but falls back to MySQL format with a warning when unsupported. For Postgres, extend `BuildDSN` and `provisioner.DatabaseDriver` handling, add validations, and return `driver=postgres` consistently in API and CLI output.
### Sessions & Redaction
- Admin session (full view): `AuthenticateAdmin(app, router)`.
- User session: create a non-admin test user (role=guest), set a password, then `AuthenticateUser`.
- Client session (redacted internal fields; `SiteUrl` visible):
```go
s, _ := entity.AddClientSession("test-client", conf.SessionMaxAge(), "cluster", authn.GrantClientCredentials, nil)
token := s.AuthToken()
r := AuthenticatedRequest(app, http.MethodGet, "/api/v1/cluster/nodes", token)
```
- Admins see `AdvertiseUrl` and `Database`; client/user sessions don't. `SiteUrl` is safe for all roles. Client config includes `storageNamespace` (SHA-256 of `SiteUrl`) for browser storage scoping.
### Preflight Checklist
- `go build ./...`
- `make fmt-go swag-fmt swag`
- `go test ./internal/service/cluster/registry -count=1`
- `go test ./internal/api -run 'Cluster' -count=1`
- `go test ./internal/commands -run 'ClusterRegister|ClusterNodesRotate' -count=1`
- Tooling: `make swag` may fetch modules — confirm network access before running.

View file

@ -0,0 +1,12 @@
## JS/Go Code Comment Rules
A doc comment is **required** for every function (including unexported helpers), as well as for every non-trivial Vue `methods:` / `computed:` / watcher:
- Keep comments **compact** and default to one line for "what" in the format `// Name does X.`. Skip trivial getters (`isOpen: () => this.open`).
- Add 1-2 follow-up lines (`// …`) **only** if the "why" is non-obvious: a hidden invariant, a workaround that would otherwise be undone by a future cleanup, a contract a reader can't infer from the code. If readers can infer the "why" from the function body or a nearby line, then omit it.
- Multi-paragraph explanations belong in `specs/`, package `README.md` files, or GitHub issues — never in the source itself.
Doc comments for packages and exported identifiers must be complete sentences that begin with the name of the thing being described and end with a period. For short examples in comments, indent code instead of using backticks.
Use US English spelling in all code comments (`parameterized`, `behavior`, `color`, `serialize`, `normalize`, `optimize`, …) — not the British `-ised`/`-our`/`-re` variants.
> **Don't include in code comments:** Issue / PR numbers, "previously…" history, alternatives considered, what the function used to do, references to old commits, names of subsequent reviewers, or any narrative that names the change rather than the steady-state behavior. That context belongs in commit messages, specs, or handover notes.

View file

@ -0,0 +1,57 @@
## Commit Messages
Use concise, imperative subjects with a one-word prefix indicating the scope or topic:
- `Config: Add tests for "darktable-cli" path detection`
If the commit relates to specific issues or pull requests, reference their IDs in the message:
- `Docker: Use two stage build to reduce image size #123 #5632`
Commit messages must not exceed 80 characters in length.
Do not add `Co-Authored-By: Claude …` trailers (or any other AI-authorship trailer) to commit messages.
## GitHub Issues
Issue titles MUST be concise, use the imperative mood, and start with a single capitalized prefix followed by a colon and a space, e.g. `Search: Add filter for RAW image formats`.
Issue descriptions MUST begin with a one-sentence **User Story** in the format: `**As a <role>, I want <goal>, so that <outcome>.**`
Use level-3 Markdown headings for sections within issue descriptions, for example `### Acceptance Criteria`.
Follow the User Story with a clear summary of the expected behavior, rationale, technical considerations, and constraints.
Descriptions MUST conclude with a checklist of **Acceptance Criteria**:
- Use GitHub checklist formatting: `- [ ]`
- Criteria MUST be clear, testable, and unambiguous.
- Each item MUST use one of the following requirement-level keywords:
- `MUST` — required for the issue to be considered complete
- `SHOULD` — strongly recommended but not strictly required
- `MAY` — optional enhancement
- Keep the checklist current: once the work for a criterion is implemented **and verified**, mark it done (`- [x]`).
- Leave items that are unverified, not yet implemented, or skipped optional (`MAY`) enhancements unchecked.
- An issue is complete only when every `MUST` is checked; never tick a box on the strength of a plan alone or an unrun test.
- When referencing an issue from a commit that fulfills some of its criteria, update the matching boxes first.
> Agents MUST create, edit, close, reopen, relabel, or otherwise modify GitHub issues only when explicitly requested by the user.
The repo's issue templates use the new GitHub `type:` property (`Bug`, `Feature`) instead of `bug`/`idea` labels. `gh issue create` does not yet accept a `--type` flag, so when filing issues programmatically use `--label` only and tell the user to set the issue type via the web UI.
## Specifications & Documentation
- Document headings use a **Chicago-style title case**, with additional code- and path-aware normalization rules (see below). Always spell the product name as `PhotoPrism`.
- When writing CLI examples or scripts, place option flags before positional arguments unless the command requires a different order.
- Use RFC 3339 UTC timestamps in request and response examples, and valid ID, UID and UUID examples in docs and tests.
- Technical specifications in the nested `specs/` subrepository may not be present in every clone or environment. Do not add `Makefile` targets in the main project that depend on `specs/` paths.
- Auto-generated configuration and command references live under `specs/generated/`. Agents MUST NOT read, analyze, or modify anything in this directory.
- Nested Git repositories may appear to be ignored; if so, change directories before staging or committing updates.
- **Never reference `specs/` paths from public artifacts** — issue bodies, PR descriptions, package READMEs (`frontend/README.md`, `internal/*/README.md`, etc.), top-level `CODEMAP.md`/`GLOSSARY.md`, code comments outside `specs/`. External readers see a 404 and the private subrepo's existence is leaked. Hints in `AGENTS.md` and `CLAUDE.md` files are the documented exception. Quick check: `grep -n "specs/" <file>` should return no matches before saving any public-facing file.
> **Title Case** rules (Chicago-style headline capitalization, with code- and path-aware normalization):
> - Capitalize the first word, the first word after a colon, dash, or end punctuation, and all major words, including the second part of a hyphenated major word.
> - Lowercase only articles, short conjunctions, and short prepositions of three letters or fewer when they are not in one of those positions.
> - Preserve known acronyms (for example, API, CLI, HTTP, JSON) and slash-separated acronym groups (for example, CSV/TSV) as uppercase.
> - Preserve RFC 2119 / RFC 8174 normative keywords (MUST, SHOULD, MAY, SHALL, REQUIRED, RECOMMENDED, OPTIONAL) as uppercase when used in their normative sense.
> - Preserve inline code spans (`` `foo` ``), file paths (e.g. `docs/foo-bar.md`), and slash commands (e.g. `/grill-me`) verbatim; do not recase their contents.
> - Use `&` instead of `And`/`Or` in headings.
> Refresh the `**Last Updated:**` date at the top of documents whenever you make changes to their contents, using the format `January 20, 2026` (without time); leave it as-is for simple formatting or whitespace-only edits.

View file

@ -0,0 +1,77 @@
## Frontend Code Style & Test Coverage
- **Comments:** Follow the code comment rules in `code-comments.md`.
- **Tests:** Test new JS functions (including helpers) and new Vue components whenever practical; update existing tests when behavior changes. When a unit test is impractical (DOM-heavy flows, third-party widget integration), the doc comment is still mandatory — it's the minimum bar.
- **State:** Shared state lives in reactive singleton modules under `src/common/` and `src/app/` (e.g., `app/session.js`, `common/config.js`, `common/clipboard.js`, `common/log.js`) that export a `reactive()` / `ref()` object directly; components access them via `import` or via the globally-installed `$config` / `$session` plugins. Do not introduce Vuex, Pinia, or new ad-hoc stores — extend an existing singleton or add a new one alongside its peers in `common/` or `app/`.
- **Vue/Vuetify:** Use the Options API in Vue components (consistent with the rest of the codebase); do not introduce Composition API or `<script setup>`.
- **TypeScript:** Do not introduce TypeScript. The frontend is a pure JS + Vue SFC codebase: no `.ts` files, no `tsconfig.json`, no `<script lang="ts">` blocks. JSDoc type annotations in comments are fine; full TS migrations are out of scope.
## Frontend Formatting
- ESLint + Prettier own formatting. After edits run `make fmt-js` (or `npm run fmt` inside `frontend/`) and `make lint-js` to verify; `frontend/eslint.config.mjs` is the flat-config source of truth.
- The dev container preinstalls `eslint` and `prettier` on the global `PATH` at the same version `frontend/package.json` pins (`eslint --version` should match the `eslint` entry in `frontend/package.json`). Invoke them directly (e.g. `eslint --fix tests/`) from `frontend/` — no need for `npx`, which adds a spawn step and an extra resolution layer.
- Prettier reflow is **not** part of `make fmt-js` / `eslint --fix` — the `prettier/prettier` rule is set to `"off"` so intentional newlines (multi-line method chains, vertical predicate lists) are preserved. Run `prettier --write <file>` explicitly when a full reflow is wanted; do not run it blanket across `src/` or `tests/`.
- Prettier uses `printWidth: 160`, double quotes, semicolons, `trailingComma: "es5"`, and `proseWrap: "never"` (see `frontend/.prettierrc.json`). Do not hand-wrap long lines — let Prettier decide. CSS/SCSS use `tabWidth: 4`.
- The repo-root `.editorconfig` covers indentation and newline style; don't override it locally.
- Vue SFC block order is `<template>``<script>``<style>`; keep it consistent with existing components.
## Frontend Dependencies & Pins
- `frontend/README.md` is the canonical doc for pin rationale, the `overrides` layer, ESM-only upgrade blockers, and the orphan-audit pattern — read it before bumping any non-caret pin or adding/removing a top-level dep.
- **Pins are intentional.** When a version has no caret (e.g., `"axios": "1.16.1"`, `"vuetify": "3.12.2"`), check `frontend/README.md` and `git log -p -S "<pkg>" -- frontend/package.json` for the reason before changing it.
- npm is a workspace; run `npm install --ignore-scripts --no-audit --no-fund --no-update-notifier` from the **repo root** (not `frontend/`) so the root `package-lock.json` updates. After dep changes also run `make audit`, `make build-js`, `make test-js`, and `make notice`.
- Before adding a new dep or removing one as "unused", run `rg -nF "<pkg>" frontend ...` plus `npm ls <pkg> --all` to confirm there's no transitive consumer or peer-dep. Recent precedents: `postcss-url`, `@vitejs/plugin-react`, `cheerio`, `@testing-library/react`, `vite-tsconfig-paths` (all true orphans removed once consumer left).
## Frontend Linting & Test Entry Points
- Follow the lint/format scripts in `frontend/package.json`; all added JS, Vue, and tests must conform.
- Unit tests (Vitest): `make test-js`, `make vitest-watch`, `make vitest-coverage`. Acceptance: `acceptance-*` targets in the root `Makefile`.
- **Always invoke Vitest through the npm/make wrapper, never bare `npx vitest run`.** `frontend/package.json`'s `test` script wraps the call in `cross-env TZ=UTC BUILD_ENV=development NODE_ENV=development BABEL_ENV=test`. Without those env vars ~50 component tests (Vuetify renders, chip-selector, login, location-input, batch-edit, people-tab, lightbox `toggleSidebar`, etc.) and TZ-sensitive date tests fail spuriously — the failures look real but only reproduce in the unwrapped invocation. Do not compare a "failed N, passed M" report from bare `npx vitest run` against a `make test-js` baseline. For ad-hoc filtering on a single file, mirror the env explicitly: `(cd frontend && TZ=UTC BUILD_ENV=development NODE_ENV=development BABEL_ENV=test npx vitest run <path>)`.
- One-off TestCafe (single case by `testID`):
```bash
make storage/acceptance
make acceptance-sqlite-restart
make wait-2
(cd frontend && npm run testcafe -- "chrome --headless=new --use-gl=angle --use-angle=swiftshader --disable-features=LocalNetworkAccessChecks" --config-file ./testcaferc.json --test-meta mode=public,type=short,testID=components-001 "tests/acceptance")
make acceptance-sqlite-stop
```
Always return to repo root before `make acceptance-sqlite-stop`.
## Frontend Test Gotchas
- Hidden-route UI checks under `/library/hidden` or `/portal/hidden` require both `files.file_error` and `photos.photo_quality = -1`; `file_error` alone will not surface the row.
## Playwright MCP Usage
- Endpoint `http://localhost:2342/`; logins at `/library/login` (CE/Plus/Pro) and `/portal/login` (Portal). Use local compose admin credentials; if login fails, inspect the active compose env.
- Viewports: desktop `1280x900`; mobile uses the mobile Playwright server at `375x667`. Close the browser tab after scripted interactions.
- Prefer waits over sleeps; click only visible/enabled elements; use role/label/text selectors (not XPath).
- Screenshots: small and reproducible — JPEG, visible viewport, deterministic `.local/screenshots/<case>/<step>__<viewport>.jpg` names, no large inline screenshots.
- If `npx` fetches an MCP server at runtime, add `--yes` or preinstall to avoid prompts.
- Delegate to the `ui-tester` subagent for any flow with more than ~2 browser steps (login + navigate + assert, multi-step forms, regression sweeps). Brief it with the URL, credentials, exact steps, and the verdict format you want back; ask for a short report so raw snapshots and console dumps stay out of the parent context. Drive Playwright MCP inline only for one-shot checks (single navigate, single screenshot).
## Frontend Focus Management
- Dialogs must follow the shared pattern in `frontend/src/common/README.md`: expose `ref="dialog"` on `<v-dialog>`, call `$view.enter/leave` in `@after-enter` / `@after-leave`, and avoid positive `tabindex`.
- Persistent dialogs (`persistent` prop) must handle Escape via `@keydown.esc.exact` to suppress Vuetify's rejection animation; keep other shortcuts on `@keyup` so inner inputs can cancel first.
- Global shortcuts go through `onShortCut(ev)` in `common/view.js`, which only forwards Escape and `ctrl`/`meta` combos — don't rely on it for arbitrary keys.
- When a dialog opens nested menus (e.g., combobox suggestions), confirm they work with the global trap; see the README for troubleshooting.
## Frontend Translations
- Never hardcode locale strings in templates or scripts — every user-visible string MUST go through `$gettext` / `T` so it appears in `frontend/src/locales/translations.pot`.
- **Exception — standardized technical identifiers stay untranslated.** Render protocol/acronym/identifier field labels and option values as literal strings, not via `$gettext`: e.g. `Client ID`, `Client Credentials`, `OIDC`, `UUID`, `Node UUID`. Translating them adds catalog noise and risks ambiguous renderings (e.g. "Client" → German "Kunde"). Common English field names like `Site URL` or `Advertise URL` stay translated.
- **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
- HTML entrypoints live in `assets/templates/`: `index.gohtml`, `app.gohtml`, `app.js.gohtml`, `splash.gohtml`. `assets/static/js/browser-check.js` runs capability checks before the main bundle; keep it loaded before the bundle script in `app.js.gohtml` and don't add `defer`/`async` to the bundle tag unless you reintroduce a guarded loader.
- OIDC login completion bridges through `assets/templates/auth.gohtml`, writing the session into namespaced browser storage — must stay aligned with `frontend/src/common/session.js`, `frontend/src/common/storage.js`, and the login-form toggle in `frontend/src/page/auth/login.vue`.
- When touching session bootstrap, verify `session.js` resolves `storageNamespace` from the real client-config shape (`window.__CONFIG__` / `config.values`), not just mocks. Add a focused test that would fail if restore fell back to `pp:root:`.
- The loader partial is reused in `pro/`, `plus/`, and `portal/assets/templates/index.gohtml`; verify they still include it whenever `app.js.gohtml` or bundle loading changes.
- Splash styles: `frontend/src/css/splash.css` — add new splash elements there for cross-edition consistency.
- Browser baseline: Safari 13 / iOS 13 or current Chrome, Edge, Firefox.

View file

@ -0,0 +1,31 @@
## Go Code Style
- **Comments:** Follow the code comment rules in `code-comments.md`.
- **Packages:** Every Go package must contain a `<package>.go` file in its root (e.g. `internal/auth/jwt/jwt.go`) with the standard license header and a short package description comment.
- **Format:** Go is formatted by `gofmt` with tabs. Do not hand-format indentation. After edits run `make fmt-go` (gofmt + goimports).
- **Linting:** Run `make lint-go` (`golangci-lint`) after Go changes; prefer `golangci-lint run ./internal/<pkg>/...` for focused edits.
## Package Boundaries
- Code in `pkg/*` MUST NOT import from `internal/*`. If you need config/entity/DB access, put new code under `internal/` instead.
## GORM Field Naming
When adding struct fields with uppercase abbreviations (e.g. `LabelNSFW`, `UserID`, `URLHash`), set an explicit `gorm:"column:<name>"` tag so column names stay consistent (`label_nsfw`, `user_id`, `url_hash` instead of split-letter variants).
## Filesystem Permissions & io/fs Aliasing
- Always use shared permission variables from `pkg/fs` when creating files/directories:
- Directories: `fs.ModeDir` (0o755 with umask)
- Regular files: `fs.ModeFile` (0o644 with umask)
- Config files: `fs.ModeConfigFile` (default 0o664)
- Secrets/tokens: `fs.ModeSecretFile` (default 0o600)
- Backups: `fs.ModeBackupFile` (default 0o600)
- Do not pass stdlib `io/fs` flags to functions expecting permission bits. When importing the stdlib package, alias it to avoid collisions: `iofs "io/fs"` or `gofs "io/fs"`.
- Prefer `filepath.Join` for filesystem paths; reserve `path.Join` for URL paths. For slash-based logical paths stored in DB/config/API payloads (e.g. folder album paths), normalize with `clean.SlashPath(...)` instead of ad-hoc `strings.ReplaceAll(..., "\\", "/")` + trim logic.
## Logging
- Use the shared logger (`event.Log`) via the package-level `log` variable (see `internal/auth/jwt/logger.go`) instead of direct `fmt.Print*` or ad-hoc loggers.
- Terminology: in human-readable log text, prefer canonical runtime terms (`instance`, `service`) and reserve `node` for contract-bound names (`/cluster/nodes`, `Node*`, `PHOTOPRISM_NODE_*`).
- Audit outcomes: import `github.com/photoprism/photoprism/pkg/log/status` and end every `event.Audit*` slice with a single outcome token such as `status.Succeeded`, `status.Failed`, `status.Denied`. When a sanitized error string should be the outcome, call `status.Error(err)` instead of manually passing `clean.Error(err)`.

View file

@ -0,0 +1,49 @@
## Go Test Coverage
- Every new Go function (including unexported helpers) must have focused coverage in a sibling `*_test.go`. Refactors count: each new helper needs its own `Test<Name>` with at least a Success and an error/InvalidRequest case — don't rely on the old test covering the new path.
- Before reporting a change done, grep your diff for `^func ` additions and confirm each has a matching `Test*`. Swagger or route regeneration is not a substitute — Swagger documents shape, tests prove behavior.
## Go Testing Patterns
- Tests live next to sources (`<file>_test.go`); group cases with `t.Run(...)` using **PascalCase** names (`Success`, `InvalidRequest`). Consecutive subtests inside the same `Test*` function are written without blank lines between them so the cases read as a compact table; reserve blank lines for separating distinct setup blocks.
- Do not run multiple test commands in parallel — suites share fixtures, temp assets, and DB state.
- Keep Go scratch work inside `internal/...` (Go refuses `internal/` imports from `/tmp`).
- Prefer focused runs: `go test ./internal/<pkg> -run <Name> -count=1`. Avoid `./...` unless needed; heavy packages (`internal/entity`, `internal/photoprism`) take 30120s on first run.
### Fast, Focused Test Recipes
- FS + archives (fast): `go test ./pkg/fs -run 'Copy|Move|Unzip' -count=1`
- Media helpers (fast): `go test ./pkg/media/... -count=1`
- Thumbnails (libvips, moderate): `go test ./internal/thumb/... -count=1`
- FFmpeg builders (moderate): `go test ./internal/ffmpeg -run 'Remux|Transcode|Extract' -count=1`
### Test Config Helpers
- Default to `config.NewMinimalTestConfig(t.TempDir())` for FS/config scaffolding, or `config.NewMinimalTestConfigWithDb("<name>", t.TempDir())` for a fresh SQLite schema.
- Reserve `config.TestConfig()` for tests that truly need the fully seeded fixture snapshot (runs `InitializeTestData()`, wipes `storage/testdata`).
- Config helpers auto-discover `assets/`; don't set `PHOTOPRISM_ASSETS_PATH` in `init()`. Hub traffic is disabled by default; re-enable with `PHOTOPRISM_TEST_HUB=test`.
### Fixtures
- `NewTestConfig("<pkg>")` runs `InitializeTestData()`; for custom configs call `c.InitializeTestData()` (and optionally `c.AssertTestData(t)`).
- `PhotoFixtures.Get()` etc. return value copies — re-query via `entity.FindPhoto(fixture)` when you need the DB row.
- New persistent IDs: `rnd.GenerateUID(entity.PhotoUID|FileUID|LabelUID|ClientUID|…)`; node UUIDs use `rnd.UUIDv7()` and `node.uuid` is required in responses.
- Use `entity.Values` (not raw `map[string]interface{}`) for DB updates. Reuse shared `Example*` constants for illustrative credentials (see `internal/service/cluster/examples.go`).
### CLI Testing Gotchas
- `urfave/cli` calls `os.Exit` on `cli.Exit(...)`; use `RunWithTestContext` (in `internal/commands/commands_test.go`) or invoke `cmd.Action(ctx)` directly and check `err.(cli.ExitCoder).ExitCode()`.
- Non-interactive: set `PHOTOPRISM_CLI=noninteractive` and/or pass `--yes`.
- SQLite DSN from `NewTestConfig("<pkg>")` is a per-suite path like `.<pkg>.db` — don't assert empty.
- Reuse shared flag helpers (`DryRunFlag(...)`, `YesFlag()`) for new CLI flags.
### FFmpeg & Hardware Gating
- Gate GPU/HW encoder integrations with `PHOTOPRISM_FFMPEG_ENCODER`; CI skips them by default.
- Negative paths (missing ffmpeg, unwritable dest) must stay fast and always run. Prefer command-string assertions when hardware is unavailable.
### API/CLI Test Pitfalls
- Register `CreateSession(router)` once per test router — duplicates panic.
- Don't invoke `start` or emit signals in unit tests; some commands defer `conf.Shutdown()` and close the DB.
- MariaDB iteration: `mariadb -D photoprism` for ad-hoc SQL without rebuilding Go.

View file

@ -0,0 +1,26 @@
## Import/Index
- ImportWorker may skip files if an identical one already exists (duplicate detection). Use unique copies or assert DB rows after ensuring a non-duplicate destination.
- Mixed roots: keep `SamplesPath()/ImportPath()/OriginalsPath()` consistent so `RelatedFiles` and `AllowExt` behave as expected.
- `IndexOptions*` helpers require a `*config.Config`; pass the active config (or `config.NewMinimalTestConfig(t.TempDir())` in unit tests) so face/label/NSFW scheduling matches the current run.
- Folder albums use path-first lookup/update (`album_path`) to avoid slug collisions for emoji child paths.
- Label/label-search logic should reuse `entity.FindLabels(...)`, `entity.FindLabelIDs(...)`, and `entity.LabelSlugs(...)` for homophone-aware exact-name matching — avoid ad-hoc slug SQL in search code.
- Vision worker scheduling is controlled via `VisionSchedule` / `VisionFilter` and `Run` in `vision.yml`. Use `vision.FilterModels` and `entity.Photo.ShouldGenerateLabels/Caption` to decide when work is required before loading media files.
## Download CLI Workbench (yt-dlp, remux, importer)
**Code anchors:** CLI flags/examples in `internal/commands/download.go`; core impl in `internal/commands/download_impl.go`; yt-dlp helpers in `internal/photoprism/dl/*` (`options.go`, `info.go`, `file.go`, `meta.go`); importer entry in `internal/photoprism/get/import.go`; import options in `internal/photoprism/import_options.go`.
**Fast test runs:**
- yt-dlp package: `go test ./internal/photoprism/dl -run 'Options|Created|PostprocessorArgs' -count=1`
- CLI command: `go test ./internal/commands -run 'DownloadImpl|HelpFlags' -count=1`
**FFmpeg-less tests:** set `c.Options().FFmpegBin = "/bin/false"` and `c.Settings().Index.Convert = false` to avoid ffmpeg dependencies when not validating remux.
**Stubbing yt-dlp (no network):** use a shell script that prints minimal JSON for `--dump-single-json` and creates a file + prints its path when `--print` is requested. Harness env vars: `YTDLP_ARGS_LOG` (append final args for assertion), `YTDLP_OUTPUT_FILE` (absolute file path to create for `--print`), `YTDLP_DUMMY_CONTENT` (file contents to avoid importer duplicate detection between tests).
**Remux policy:**
- Pipe method: PhotoPrism remux (ffmpeg) always embeds title/description/created.
- File method: yt-dlp writes files; we pass `--postprocessor-args 'ffmpeg:-metadata creation_time=<RFC3339>'` so imports get `Created` even without local remux.
- Default policy `auto`; use `always` for the most complete metadata.
- CLI defaults: `photoprism dl` defaults to `--method pipe` and `--impersonate firefox`; pass `-i none` to disable impersonation.

View file

@ -0,0 +1,32 @@
## Safety & Data
- If `git status` shows unexpected changes, assume a human might be editing; ask before using reset commands like `git checkout` or `git reset`.
- Do not run `git config` (global or repo-level); changing Git configuration is prohibited for agents. Nested subrepos (e.g. `specs/`) may lack a configured committer identity — pass `-c user.email=… -c user.name=…` to the specific `git commit` invocation rather than configuring the repo.
- Do not run destructive commands against production data. Prefer ephemeral volumes and test fixtures for acceptance tests. The destructive CLI commands `photoprism reset`, `users reset`, `auth reset`, and `audit reset` require explicit `--yes`; never invoke them in examples or scripts without a backup warning.
- Never commit secrets, local configurations, or cache files. Use environment variables or a local `.env`. Ensure `.env`, `.config`, `.local`, `.codex`, and `.gocache` are in `.gitignore` and `.dockerignore`.
- Prefer existing caches, workers, and batching strategies in code and `Makefile`. Consider memory/CPU impact of changes; only suggest benchmarks or profiling when justified.
- Regenerate `NOTICE` files with `make notice` when dependencies change (e.g. `go.mod`, `go.sum`, `package-lock.json`). Do not edit `NOTICE` or `frontend/NOTICE` manually.
> If anything in this file conflicts with the `Makefile` or Sources of Truth, **ask** for clarification before proceeding.
## File I/O — Overwrite Policy (force semantics)
- Default is safety-first: callers must not overwrite non-empty destination files unless they opt-in with `force=true`. Replacing empty destinations is allowed without `force`.
- Open destinations with `O_WRONLY|O_CREATE|O_TRUNC` to avoid trailing bytes when overwriting; use `O_EXCL` when callers must detect collisions.
- Where this lives: `internal/photoprism/mediafile.go` (`MediaFile.Copy/Move`), `pkg/fs/copy.go`, `pkg/fs/move.go`.
- When to set `force=true`: explicit "replace" actions or admin tools where the user confirmed overwrite. Not for import/index flows — Originals must not be clobbered.
## Archive Extraction — Security Checklist
- Validate ZIP entry names with a safe join; reject absolute paths (e.g. `/etc/passwd`), Windows drive/volume paths (`C:\\…` or `C:/…`), and any entry that escapes the target directory after cleaning (`..` traversal).
- ZIP entry names use slash semantics, not host OS semantics: validate in ZIP-name space with `path.Clean` / `path.IsAbs`, reject backslashes (`\`), and use `path.Base` for hidden-name checks. Convert to OS paths only at write time via `filepath.FromSlash(...)`. Enforce destination containment with `filepath.Rel(...)` — not string-prefix checks.
- Enforce per-file and total size budgets to prevent resource exhaustion. Skip OS metadata directories (e.g. `__MACOSX`) and reject suspicious names.
- Where this lives: `pkg/fs/zip.go` (`Unzip`, `UnzipFile`, `safeJoin`).
## HTTP Download — Security Checklist
- Use the shared safe HTTP helper: `pkg/http/safe``safe.Download(destPath, url, *safe.Options)`. Default policy: only `http/https`, enforced timeouts and max size, writes to a `0600` temp file then renames.
- SSRF protection (mandatory unless explicitly needed for tests): set `AllowPrivate=false` to block private/loopback/multicast/link-local ranges. All redirect targets are validated and the final connected peer IP is also checked. Prefer an image-focused `Accept` header for image downloads.
- Avatars and small images: use `internal/thumb/avatar.SafeDownload` (15 s timeout, 10 MiB, `AllowPrivate=false`).
- Tests using `httptest.Server` on 127.0.0.1 must pass `AllowPrivate=true` explicitly.
- Keep per-resource size budgets small; rely on `io.LimitReader` + `Content-Length` prechecks.

View file

@ -0,0 +1,16 @@
## Sources of Truth
- Makefile targets (always prefer existing targets): see the `Makefile`
- Developer Guide Setup: https://docs.photoprism.app/developer-guide/setup/
- Developer Guide Tests: https://docs.photoprism.app/developer-guide/tests/
- Contributing: `CONTRIBUTING.md`
- Security: `SECURITY.md`
- REST API: https://docs.photoprism.dev/ (Swagger), https://docs.photoprism.app/developer-guide/api/ (Docs)
- Code Maps: `CODEMAP.md` (Backend/Go), `frontend/CODEMAP.md` (Frontend/JS)
- Terminology Glossary: `GLOSSARY.md` (single source for term definitions across specs/docs)
- Package-level `README.md` files under `internal/`, `pkg/`, `frontend/`, and `frontend/src/` for detailed package documentation.
- Frontend dependency pin rationale, override layer, and orphan-audit pattern: `frontend/README.md` (check before bumping any non-caret pin or adding/removing a top-level dep).
> Quick Tip: to inspect GitHub issue details without leaving the terminal, run `curl -s https://api.github.com/repos/photoprism/photoprism/issues/<id>`; if `gh` is set up, you MAY also run `gh issue view <id> -R photoprism/photoprism`.
> Frontend test sequences (Vitest / TestCafe / Playwright), hidden-route UI gotchas, and acceptance-test flow live in `frontend-rules.md`.

19
.claude/settings.json Normal file
View file

@ -0,0 +1,19 @@
{
"permissions": {
"additionalDirectories": ["/go", "/tmp", "/home"],
"allow": [
"Bash(make:*)",
"Bash(go:*)",
"Bash(npx --yes markdown-table-formatter:*)",
"Read",
"Write",
"Edit",
"Grep",
"Glob",
"WebSearch",
"mcp__playwright__*"
],
"defaultMode": "acceptEdits"
},
"awaySummaryEnabled": false
}

9
.codespellrc Normal file
View file

@ -0,0 +1,9 @@
[codespell]
# Ref: https://github.com/codespell-project/codespell#using-a-config-file
skip = .git*,*.svg,go.sum,package-lock.json,*.css,.codespellrc,locales,stopwords.*,shortwords.*,countries.*,keywords.json,smallwords.*
check-hidden = true
# ACRONYMS and generally mixed case/Capitalized words
# Also ignore some German
ignore-regex = ^(SMethod=shal|biuld: build)$|https://\S+|\b([A-Z][a-zA-Z]+|ist auf)\b|"(datin|alis|hel)"|\bfixe == false\b
# common variables or other tricky cases
ignore-words-list = renderd,nd,folde,crate,ue,fo,ist,alo,mot,te,admiraal

View file

@ -1,38 +1,76 @@
# Local build files and directories
# Local build files and directories:
/photos/*
/frontend/node_modules/*
/node_modules
/assets/docs
/assets/static/build/*
/assets/facenet
/assets/nasnet
/assets/nsfw
/storage
/build
/frontend/node_modules/
/node_modules/
/assets/docs/
/assets/static/build/
/assets/facenet/
/assets/nasnet/
/assets/nsfw/
/assets/efficientnet/
/assets/imagenet/
/assets/resnet/
/assets/vision/
/assets/models/
/storage/
/build/
/setup/Makefile
/photoprism
/photoprism-*
/coverage.*
/frontend/tests/acceptance/screenshots
/frontend/tests/acceptance/screenshots/
/frontend/tests/screenshots/
/frontend/tests/*.html
/frontend/tests/*.log
/frontend/tests_output/
/frontend/coverage/
/test/
/specs/
/docs/
/bin/
# Custom config, database, log, and temporary files
/tmp/
.env
# Docker configuration files:
.dockerignore
*.log
*.jsonl
*.db
*.db-journal
Dockerfile
docker-compose*
compose.yaml
compose.*.yaml
*.override.yml
*.override.yaml
*.tmp.yml
*.tmp.yaml
# Automatically generated files, e.g. by editors and operating systems
# Customization, database, log, and temporary files:
*.socket
*.lock
*.sock
*.pid
*.log
*.jsonl
*.db
*.db-journal
*.sqlite
*.override.yml
*.tmp.yml
*.override.yaml
*.tmp.yaml
*.out
*.test
*.exe
*.exe~
*.dll
*.so
*.dylib
*.tmp
*.img
*.img.xz
*.img.gz
/*.zip
/coverage.*
__pycache__
venv
.venv
.env*
.tmp
.nv
.eslintcache
.gocache
.gitconfig
.DS_Store
.DS_Store?
._*
@ -42,10 +80,20 @@ ehthumbs.db
Thumbs.db
.heartbeat
.idea
.glide
.codex
.claude
.config
.local
*~
.goutputstream*
.c9revisions
.settings
.swp
.tmp
.glide
/tmp/
/internal/tmp/
*.override.md
/AGENTS_*
/REPOS.md
join_token
client_secret

20
.editorconfig Normal file
View file

@ -0,0 +1,20 @@
# Top-most EditorConfig file, https://editorconfig.org
root = true
# Use Unix-style newlines with a newline ending every file.
[*]
end_of_line = lf
insert_final_newline = false
# Set rules by file type.
[*.json]
indent_style = space
indent_size = 2
[*.{js,yaml,yml,md,txt}]
charset = utf-8
indent_style = space
indent_size = 2
[Makefile]
indent_style = tab

41
.env.example Normal file
View file

@ -0,0 +1,41 @@
## Build & Test Environment Overrides
##
## Copy this file to ".env" in the same directory as compose.yaml and uncomment
## the variables you want to customize.
# Isolates container names, named volumes, and the auto-prefixed default network
# across parallel checkouts of this repo. To run multiple environments side-by-
# side, set this together with COMPOSE_NETWORK_NAME below.
# COMPOSE_PROJECT_NAME=photoprism
# Bridge-network name. Override together with COMPOSE_PROJECT_NAME to run
# multiple parallel dev environments without colliding on the shared network.
# COMPOSE_NETWORK_NAME=photoprism
# Optional services to start by default. Comma-separated list of profile names
# read by Docker Compose itself (so no --profile flag is required).
# COMPOSE_PROFILES=postgres
# In-container working directory and bind mount target for the repo checkout.
# Override when the host clone lives outside the default GOPATH layout; the
# value is reused for the Dockerfile WORKDIR (build arg), working_dir, the
# source bind mount, and every PhotoPrism path env var so they stay in sync.
# WORKING_DIR=/go/src/github.com/photoprism/photoprism
# Network interfaces to which Traefik and other services bind on the host.
# Defaults expose Traefik on every interface (so *.localssl.dev is reachable
# from the LAN) and keep direct service ports on loopback only.
# TRAEFIK_BIND_HOST=0.0.0.0
# SERVICES_BIND_HOST=127.0.0.1
# Host ports for Traefik's HTTP and HTTPS entrypoints.
# TRAEFIK_HTTP_PORT=80
# TRAEFIK_HTTPS_PORT=443
# Public base URL used in share links, OIDC & PWA URIs.
# PHOTOPRISM_SITE_URL=https://app.localssl.dev/
# Ports to which MariaDB and PostgreSQL should bind. PostgreSQL only starts
# when the "postgres" (or "all") profile is enabled via COMPOSE_PROFILES.
# MARIADB_PORT=4001
# POSTGRES_PORT=4002

View file

@ -1,26 +1,31 @@
---
name: Bug Report
name: Bug Report 🐞
about: Report a new and clearly identified bug that must be fixed directly in the application
title: 'SHORT DESCRIPTION OF THE PROBLEM YOU ARE REPORTING'
labels: bug
title: 'Bug: Edit the title before submitting'
type: Bug
assignees: ''
---
PLEASE PROCEED ONLY IF YOU ARE ABSOLUTELY SURE THAT THIS IS NOT A TECHNICAL SUPPORT INCIDENT AND/OR POSSIBLY A PROBLEM WITH SOME OTHER SOFTWARE YOU ARE USING. VISIT <https://www.photoprism.app/kb/getting-support> TO LEARN MORE ABOUT OUR SUPPORT OPTIONS. THANK YOU FOR YOUR CAREFUL CONSIDERATION!
<details>
PLEASE PROCEED ONLY IF YOU ARE SURE THAT THIS IS NOT A TECHNICAL SUPPORT INCIDENT AND/OR POSSIBLY A PROBLEM WITH SOME OTHER SOFTWARE YOU ARE USING:
---------------------------------------------------------------------------
1. Thoroughly review our [Getting Started](https://docs.photoprism.app/getting-started/) and [User Guides](https://docs.photoprism.app/user-guide/).
2. Work through the [Troubleshooting Checklists](https://docs.photoprism.app/getting-started/troubleshooting/) we provide.
3. Do not report [known issues](https://docs.photoprism.app/known-issues/) or [missing features](https://github.com/photoprism/photoprism/issues) as bugs.
4. Use [GitHub Discussions](https://github.com/photoprism/photoprism/discussions) for community help, and visit our [Support Guide](https://www.photoprism.app/kb/getting-support/) to learn more about support options.
#### 1. What is not working as documented?
THANK YOU! 💎
</details>
Be as specific as possible and explain which part of the software is not [working as documented](https://docs.photoprism.app/), e.g. "image not found" or "wrong thumbnail" would not be detailed enough.
**Be as specific as possible and explain which part of the software is not [working as documented](https://docs.photoprism.app/), e.g. "image not found" or "wrong thumbnail" would not be detailed enough.**
Links to the related documentation on [docs.photoprism.app](https://docs.photoprism.app/):
- ...
*Please never report [known issues](https://docs.photoprism.app/known-issues/) or [missing features](https://github.com/photoprism/photoprism/issues) as bugs, and do not submit bug reports for the purpose of getting [technical support](https://www.photoprism.app/kb/getting-support) or because you have not received a response in our [public community forums](https://github.com/photoprism/photoprism/discussions). Thank you very much!*
*Please never report [known issues](https://docs.photoprism.app/known-issues/) or [missing features](https://github.com/photoprism/photoprism/issues) as bugs, and do not submit bug reports for the purpose of getting [technical support](https://www.photoprism.app/kb/getting-support/) or because you have not received a response in our [public community forums](https://github.com/photoprism/photoprism/discussions). Thank you very much!*
#### 2. How can we reproduce it?
### 1. How can we reproduce it?
Steps to reproduce the behavior:
@ -31,23 +36,23 @@ Steps to reproduce the behavior:
When reporting an import, indexing, or performance issue, please include the number and type of pictures in your library, as well as any configuration options you have changed, such as for thumbnail quality.
#### 3. What behavior do you expect?
### 2. What behavior do you expect?
Give us a clear and concise description of what you expect.
#### 4. What could be the cause of your problem?
### 3. What could be the cause of your problem?
Always try to determine the cause of your problem using the checklists at <https://docs.photoprism.app/getting-started/troubleshooting/> before submitting a bug report.
#### 5. Can you provide us with example files for testing, error logs, or screenshots?
### 4. Can you provide us with example files for testing, error logs, or screenshots?
Please include sample files or screenshots that help to reproduce your problem. You can also email files or share a download link, see <https://www.photoprism.app/contact> for details.
Please include sample files or screenshots that help to reproduce your problem. You can also email files or share a download link, see <https://www.photoprism.app/contact/> for details.
Visit <https://docs.photoprism.app/getting-started/troubleshooting/browsers/> to learn how to diagnose frontend issues.
**Important: If it is an import, indexing or metadata issue, we require sample files and logs from you.** Otherwise, we will not be able to process your report. If it is an import problem specifically, please always provide us with an archive of the files before you imported them so we can reproduce the behavior.
**Important: Attach or link to files that help us reproduce the problem. Import and indexing issues require sample files and logs.** Otherwise, we will not be able to process your report. If it is an import problem specifically, please always provide us with an archive of the files before you imported them so we can reproduce the behavior.
#### 6. Which software versions do you use?
### 5. Which software versions do you use?
(a) PhotoPrism Architecture & Build Number: AMD64, ARM64, ARMv7,...
@ -63,7 +68,7 @@ You can find the version/build number of the app in *Settings* by scrolling to t
*Always provide database and operating system details if it is a backend, import, or indexing issue. Should it be a frontend issue, at a minimum we require you to provide web browser and operating system details. When reporting a performance problem, we ask that you provide us with complete information about your environment, as there may be more than one cause.*
#### 7. On what kind of device is PhotoPrism installed?
### 6. On what kind of device is PhotoPrism installed?
This is especially important if you are reporting a performance, import, or indexing issue. You can skip this if you're reporting a problem you found in our public demo, or if it's a completely unrelated issue, such as incorrect page layout.
@ -77,9 +82,9 @@ This is especially important if you are reporting a performance, import, or inde
*Always provide device, memory, and storage details if you have a backend, performance, import, or indexing issue.*
#### 8. Do you use a Reverse Proxy, Firewall, VPN, or CDN?
### 7. Do you use a Reverse Proxy, Firewall, VPN, or CDN?
If yes, please specify type and version. You can skip this if you are reporting a completely unrelated issue.
Describe your network setup. If applicable, include details about your NGINX or other reverse proxy configuration.
*Always provide this information when you have a reliability, performance, or frontend problem, such as failed uploads, connection errors, broken thumbnails, or video playback issues.*

87
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View file

@ -0,0 +1,87 @@
name: Bug Report 🐞
description: Report a new and clearly identified bug that must be fixed directly in the application.
title: "Bug: Edit the title before submitting"
type: Bug
assignees: []
body:
- type: markdown
attributes:
value: |
Please proceed only if you are sure that this is not a technical support incident and/or a problem with some other software you are using:
1. Thoroughly review our [Getting Started](https://docs.photoprism.app/getting-started/) and [User Guides](https://docs.photoprism.app/user-guide/).
2. Work through the [Troubleshooting Checklists](https://docs.photoprism.app/getting-started/troubleshooting/) we provide.
3. Do not report [known issues](https://docs.photoprism.app/known-issues/) or [missing features](https://github.com/photoprism/photoprism/issues) as bugs.
4. Use [GitHub Discussions](https://github.com/photoprism/photoprism/discussions) for community help, and visit our [Support Guide](https://www.photoprism.app/kb/getting-support/) to learn more about support options.
- type: textarea
id: documented-behavior
attributes:
label: What is not working as documented?
description: Be specific and include links to the relevant documentation when possible.
placeholder: Describe the incorrect behavior and link to the related documentation on https://docs.photoprism.app/.
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: How can we reproduce it?
description: Provide numbered steps so we can reproduce the behavior reliably.
placeholder: |
1. Go to ...
2. Click ...
3. Scroll to ...
4. Expected vs. actual result
validations:
required: true
- type: checkboxes
id: prerequisites
attributes:
label: Have you verified that no similar reports exist?
description: Confirm that you read the relevant documentation, this is not a support request, and that no similar reports already exist.
options:
- label: This is a new bug that has not yet been reported or documented
required: true
- type: textarea
id: expected-behavior
attributes:
label: What behavior do you expect?
description: Share the correct outcome you expected to see.
validations:
required: true
- type: textarea
id: possible-cause
attributes:
label: What could be the cause?
description: Summarize any investigation you have already completed and the potential root cause.
- type: textarea
id: software-versions
attributes:
label: Which software versions do you use?
description: Include all relevant software versions so we can reproduce the environment.
value: |
- PhotoPrism Edition & Version (Build):
- Database Type & Version(s):
- Operating System(s):
- Browser Type & Version(s):
- Ad Blockers, Antivirus, and Plugins:
validations:
required: true
- type: textarea
id: installation-device
attributes:
label: On what device is PhotoPrism installed?
description: Provide hardware details, especially for performance, import, or indexing issues.
value: |
- CPU/Device Type(s):
- Physical Memory & Swap in GB:
- Storage (HDD/SSD/RAID, USB, Network):
- type: textarea
id: networking-setup
attributes:
label: Do you use a reverse proxy, firewall, VPN, or CDN?
description: Describe your network setup. If applicable, include details about your NGINX or other reverse proxy configuration.
placeholder: Describe proxies, VPNs, CDNs, or firewall software involved. Include versions and configuration snippets when helpful.
- type: upload
id: supporting-material
attributes:
label: Logs, Sample Files, or Screenshots
description: Attach or link to files that help us reproduce the problem. Import and indexing issues require sample files and logs.

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Ask a Question in GitHub Discussions
url: https://github.com/photoprism/photoprism/discussions
about: Use Discussions for general questions, community support, and troubleshooting help.
- name: Read Our Support Guide
url: https://www.photoprism.app/kb/getting-support/
about: Learn about official support options and how to get assistance with PhotoPrism.

View file

@ -1,33 +1,57 @@
---
name: Feature Request
about: Suggest a new feature or enhancement
title: 'Category: Short Description (PLEASE CHANGE)'
labels: idea
title: 'Feature: Edit the title before submitting'
type: Feature
assignees: ''
---
PLEASE ONLY PROCEED IF YOU ARE ABSOLUTELY SURE THAT THIS IS NOT A TECHNICAL SUPPORT INCIDENT AND/OR A PROBLEM WITH OTHER SOFTWARE YOU ARE USING. PLEASE ALSO CHECK OUR PUBLIC ROADMAP AND TRY TO FIND EXISTING FEATURE REQUESTS FIRST:
<details>
PLEASE PROCEED ONLY IF YOU ARE SURE THAT THIS IS NOT A TECHNICAL SUPPORT INCIDENT AND/OR POSSIBLY A PROBLEM WITH SOME OTHER SOFTWARE YOU ARE USING. CHECK OUR PUBLIC ROADMAP AND TRY TO FIND EXISTING FEATURE REQUESTS FIRST:
- <https://link.photoprism.app/roadmap>
- <https://github.com/photoprism/photoprism/issues>
VISIT <https://www.photoprism.app/kb/getting-support> TO LEARN MORE ABOUT OUR SUPPORT OPTIONS. THANK YOU FOR YOUR CAREFUL CONSIDERATION!
- https://link.photoprism.app/roadmap
- https://github.com/photoprism/photoprism/issues
===============================================================================
THANK YOU! 💎
</details>
**Describe what problem this solves and why this would be valuable to many users**
**As a <role>, I want <goal>, so that <outcome>.**
All issue descriptions MUST begin with a one-sentence user story in the format shown above:
- Issue titles MUST be concise, use the imperative mood, and start with a single capitalized prefix followed by a colon and a space, e.g. `Search: Add filter for RAW image formats`.
- Follow the user story with information about the problem the feature solves, the alternatives you considered, and any other relevant details.
- Use level-3 Markdown headings to separate sections like `### Background`, `### Additional Context`, `### Open Questions`, and `### Acceptance Criteria`.
### Background
**What problem does this solve, and why would it be valuable to many users?**
A clear and concise description of what the problem is and why it is important to solve it.
**Describe the solution you'd like**
**What solution do you propose?**
A clear and concise description of what you suggest to happen.
**Describe alternatives you've considered**
**Which alternatives or workarounds have you considered?**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
### Additional Context
Add any other context or screenshots about the feature request here.
- Add any other context or screenshots about the feature request here.
### Open Questions
- [ ] <question> — options A/B/C and implications.
- [ ] <question> — potential ambiguity or conflict to clarify.
### Acceptance Criteria
- [ ] <component> MUST <expected behavior>
- [ ] <component> SHOULD <expected behavior>
- [ ] <component> MAY <expected behavior>
### References
- Add links to [external documentation](https://www.example.com/), references, or examples.

View file

@ -0,0 +1,73 @@
name: Feature Request
description: Suggest a new feature or enhancement.
title: "Feature: Edit the title before submitting"
type: Feature
assignees: []
body:
- type: markdown
attributes:
value: |
Before submitting a new request, please check our GitHub roadmap and issues for similar requests:
- https://link.photoprism.app/roadmap
- https://github.com/photoprism/photoprism/issues
- type: textarea
id: user-story
attributes:
label: User Story
description: |
Feature requests MUST begin with a one sentence user story.
**As a <role>, I want <goal>, so that <outcome>.**
placeholder: "**As a <role>, I want <goal>, so that <outcome>.**"
value: "**As a <role>, I want <goal>, so that <outcome>.**"
validations:
required: true
- type: textarea
id: problem-statement
attributes:
label: What problem does this solve, and why would it be valuable to many users?
description: Explain the underlying problem and why it is important to solve it.
placeholder: Describe the problem, why it is important, and who is affected.
validations:
required: true
- type: textarea
id: proposed-solution
attributes:
label: What solution do you propose?
description: Provide a clear and concise description of the feature or enhancement you propose.
placeholder: Outline the proposed solution or experience from the user's perspective.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Which alternatives or workarounds have you considered?
description: Describe alternative solutions, workarounds, or related features you evaluated.
placeholder: Mention any alternative solutions, workarounds, or related features you evaluated.
- type: checkboxes
id: prerequisites
attributes:
label: Have you verified that no similar issues exist?
options:
- label: This is not a support request, and I verified that no similar issues exist
required: true
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context or screenshots about the feature request here.
placeholder: Add any other context or screenshots that help explain the request.
- type: textarea
id: acceptance-criteria
attributes:
label: Acceptance Criteria
description: Use checklist items and RFC 2119 keywords such as MUST, SHOULD, and MAY to define the expected behavior.
placeholder: |
- [ ] <component> MUST <expected behavior>.
- [ ] <component> SHOULD <expected behavior>.
- [ ] <component> MAY <expected behavior>.
value: |
- [ ] <component> MUST <expected behavior>.
- [ ] <component> SHOULD <expected behavior>.
- [ ] <component> MAY <expected behavior>.
validations:
required: true

View file

@ -1,18 +0,0 @@
---
name: Question
about: You have a general question or need assistance
title: 'STOP! DO NOT PROCEED, USE GITHUB DISCUSSIONS INSTEAD - THANK YOU'
labels: technical-support
assignees: ''
---
FOR GENERAL QUESTIONS, TECHNICAL SUPPORT, AND TO GET TO KNOW OTHER COMMUNITY MEMBERS:
<https://github.com/photoprism/photoprism/discussions>
OUR TROUBLESHOOTING CHECKLISTS HELP YOU QUICKLY DIAGNOSE AND FIX COMMON PROBLEMS:
<https://docs.photoprism.app/getting-started/troubleshooting/>
DO NOT PROCEED, THANK YOU!

View file

@ -1,33 +1,34 @@
<!--
Thank you for your interest in contributing!
Because we want to create the best possible product for our users, we have a set of criteria to ensure that all submissions are acceptable, see https://docs.photoprism.app/developer-guide/pull-requests/ for details.
(1) Please provide a concise description of your pull request.
- What does it implement / fix / improve? Why?
- Are the changes related to an existing issue?
(2) After you submit your first pull request, you will be asked to accept our CLA, see https://www.photoprism.app/cla.
(3) Finally, please confirm that the following criteria are met by replacing "[ ]" with "[x]" (also possible at a later time).
-->
Acceptance Criteria:
- [ ] Features and enhancements must be fully implemented so that they can be released at any time without additional work
- [ ] Automated unit and/or acceptance tests are mandatory to ensure the changes work as expected and to reduce repetitive manual work
- [ ] Frontend components must be responsive to work and look properly on phones, tablets, and desktop computers; you must have tested them on all major browsers and different devices
- [ ] Documentation and translation updates should be provided if needed
- [ ] In case you submit database-related changes, they must be tested and compatible with SQLite 3 and MariaDB 10.5.12+
### Description
<!--
We appreciate your interest in contributing! Please provide a brief description of your changes so that we know what is included in this pull request, and confirm that it meets the acceptance criteria:
Since reviewing, testing and finally merging pull requests requires significant resources on our side, this can take several months if it's not just a small fix, especially if extensive testing is required to prevent bugs from getting into our stable version.
We thank you for your patience! :)
What does it aim to implement, fix or improve? Why?
-->
These changes implement/fix/improve...
#### Related Issues
- Links to issues that this PR fixes, implements, or is otherwise related to...
### Acceptance Criteria
<!-- You may add additional criteria and/or remove criteria that do not apply, e.g. because your PR does not include frontend changes: -->
- [ ] New features or enhancements are fully implemented and do not break existing functionality, so that they can be released at any time without requiring additional work
- [ ] Automated unit and/or acceptance tests are included to ensure that changes work as expected and to reduce repetitive manual work
- [ ] Documentation has been / will be updated, especially as it relates to new configuration options or potentially disruptive changes
- [ ] The user interface has been tested on Chrome, Safari, and Firefox and is fully responsive for use on phones, tablets, and desktop computers
- [ ] Database-related changes have been successfully tested with SQLite 3 and MariaDB 10.5.12+
<!--
Contribution Agreement:
After submitting your first pull request, you will be asked to confirm our contribution agreement. This allows us to safely use your Contribution in all our projects without risking unexpected legal disputes or having to repeatedly ask for permission.
The agreement is solely for our protection and that of our users. It does not grant us exclusive rights to your code.
PhotoPrism UG ("PhotoPrism", "we" or "us") hereby confirms to you that, to the fullest extent permitted by applicable law, this Contribution is provided "AS IS" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OR CONDITIONS OF NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. You have no obligation to provide support, maintenance, or other services for your Contribution.
Thank you very much! 🌈💎✨
-->

86
.github/copilot-instructions.md vendored Normal file
View file

@ -0,0 +1,86 @@
# Instructions for GitHub Copilot
## Purpose
- Provide Copilot with the single sources of truth for building, testing, and contributing to PhotoPrism.
- Improve PR reviews and code suggestions by aligning them with our documented workflows and style.
## Single Sources of Truth (SOT)
- Makefile targets (always prefer existing targets): https://github.com/photoprism/photoprism/blob/develop/Makefile
- Developer Guide Setup: https://docs.photoprism.app/developer-guide/setup/
- Developer Guide Tests: https://docs.photoprism.app/developer-guide/tests/
- Contributing: https://github.com/photoprism/photoprism/blob/develop/CONTRIBUTING.md
- Security: https://github.com/photoprism/photoprism/blob/develop/SECURITY.md
- REST API (Swagger): https://docs.photoprism.dev/
- REST API Guide: https://docs.photoprism.app/developer-guide/api/
- Agents reference for tools/commands: https://github.com/photoprism/photoprism/blob/develop/AGENTS.md
## Build & Run (local dev; use Makefile first)
- Show tasks: `make help`
- Build local image: `make docker-build`
- Start dev env: `docker compose up` (add `-d` for detached)
- Logs: `docker compose logs -f --tail=100 photoprism`
- Open app: http://localhost:2342/ (HTTP) / https://app.localssl.dev/ (TLS via Traefik when enabled)
- From the dev container:
- Install deps: `make dep`
- Build frontend: `make build-js` (or `cd frontend && npm run build`)
- Build backend: `make build-go`
- Watch frontend: `make watch-js` (stop with Ctrl+C)
- Run server binary: `./photoprism start`
## Tests & Lint
- Full tests: `make test`
- Frontend tests (Vitest): `make test-js` (watch: `make vitest-watch`, coverage: `make vitest-coverage`)
- Backend tests: `make test-go`
- Formatting:
- Go: `go fmt`, `goimports` (see `make fmt`, `make fmt-go`)
- JS/Vue: use scripts in `frontend/package.json` (ESLint + Prettier)
## Project Structure & Languages
- Backend: Go (`internal/`, `pkg/`, `cmd/`) + MariaDB/SQLite
- Frontend: Vue 3 + Vuetify 3 (`frontend/`)
- Docker/compose for dev/CI; Traefik used for local TLS in dev profile when enabled.
## Code Review Instructions (for Copilot)
- Respect SOT above; do not invent flags, env vars, or Compose options. If a command/env var is not in the docs/Makefile/CLI help, say “not documented” and suggest checking the SOT.
- Prefer minimal, surgical diffs. Propose changes as concrete patches and reference the relevant Makefile target or doc section.
- Before suggesting refactors, check tests and build tasks exist and can pass with the change. If tests are missing, suggest specific Vitest/Go test snippets.
- Security: never suggest committing secrets; prefer env vars and `.env` in dev only. Point to SECURITY.md for disclosures.
- Data safety: never run or recommend destructive CLI operations in examples without explicit backups and `--yes`. Avoid `photoprism reset`, `photoprism users reset`, `photoprism auth reset`, or `photoprism audit reset` in PR comments unless the change is specifically about those commands; if unavoidable, add bold warnings and backup steps.
- Database/schema: if a change touches persistence, check for migrations and mention `photoprism migrate` / `migrations` commands.
- API changes: align with the REST API docs/spec; include curl examples only if they match current endpoints and auth notes.
- UX/i18n: keep UI strings concise, translatable, and consistent; avoid hard-coded language constructs; prefer existing patterns/components.
## Style & Patterns
- Go: idiomatic Go, clear error handling, small functions, packages with focused responsibilities. Keep public surface minimal. Add/adjust unit tests.
- Vue/JS: options API, store patterns as in existing code, avoid breaking translations. Keep ESLint/Prettier clean.
- Config & flags: suggest `photoprism --help`, `photoprism show config-options` or `photoprism show config-yaml` to verify names before using them.
## Performance & Reliability
- Prefer using existing caches, workers, and batching strategies referenced in code and Makefile. Consider memory/CPU impact; suggest benchmarks or profiling only when justified.
## When Unsure
- Ask for the exact Makefile target or doc link you need, then proceed. Defer to SOT if any conflict arises.
## References To Help Copilot Answer Questions
- Show supported formats/filters: run `photoprism show file-formats` and `photoprism show search-filters` (use results rather than guessing).
- For CI/dev containers, assume Linux/Unix shell by default; link Windows specifics in Developer Guide FAQ.
## Output Expectations
- Prefer short, actionable comments with code blocks that pass tests locally: `make test-js` (frontend) / `make test-go` (backend)
- If a suggestion requires additional context (e.g., DB access, external service), call it out explicitly.
## Safety Checklist Before Proposing a CLI Command
- Include a dry-run or non-destructive variant if possible.
- Recommend creating/using backups before any reset/migrate.

View file

@ -0,0 +1,13 @@
---
applyTo:
- "internal/**"
- "pkg/**"
- "cmd/**"
---
For backend changes:
- Maintain Go style; keep functions small, errors wrapped with context.
- Add/update unit tests; ensure `make test-go` passes.
- Touching schema? Mention migrations and verify with `photoprism migrations ls`/`migrate`.
- For CLI/config, confirm flags/envs via `photoprism --help` / `photoprism show config-options` before suggesting.

View file

@ -0,0 +1,12 @@
---
applyTo:
- "frontend/**"
---
For frontend changes:
- Keep Vue 3 idioms; prefer options API and existing components.
- Run `make build-js` and `make test-js`; fix ESLint/Prettier before proposing changes.
- Avoid introducing global state; follow existing store patterns.
- Keep strings translatable; dont hardcode locales.
- For performance, avoid unnecessary reactivity and re-renders; justify new deps.

63
.gitignore vendored
View file

@ -18,38 +18,65 @@
*.dll
*.so
*.dylib
*.tmp
*.img
*.img.xz
*.img.gz
/*.zip
/coverage.*
__pycache__
venv
.venv
.env
.env*
!.env.example
.tmp
.nv
.eslintcache
.gocache
.gitconfig
.system
/pro/
/portal/
/plus/
/tmp/
/internal/tmp/
/test/
*-lock.json
/node_modules
/frontend/node_modules/*
!/package-lock.json
/node_modules/
/frontend/node_modules/
/frontend/tests/*.html
/frontend/tests/*.log
/frontend/tests/screenshots
/frontend/tests/screenshots/
/frontend/src/locales/*.mo
/frontend/tests_output
/frontend/tests_output/
frontend/coverage/
**/__screenshots__/
/.playwright-mcp/
/photoprism
/photoprism-*
/photos/originals/*
/photos/import/*
/storage/*
/build/*
/assets/docs
/assets/facenet
/assets/nasnet
/assets/nsfw
/storage/
/build/
/setup/Makefile
/assets/docs/
/assets/facenet/
/assets/nasnet/
/assets/nsfw/
/assets/static/build/
/pro
/plus
/assets/static/maps/
/assets/*net
/assets/vision/
/specs/
/docs/
/bin/
*.override.md
/AGENTS_*
/REPOS.md
/TODO.md
join_token
client_secret
# Files created automatically by editors and/or operating systems:
.DS_Store
@ -60,8 +87,16 @@ frontend/coverage/
ehthumbs.db
Thumbs.db
.heartbeat
.idea
.glide
.idea
.codex
.config
.local
*.local.json
*.local.yaml
.project
.vscode
*.tmproj
*~
.goutputstream*
.c9revisions

74
.golangci.yml Normal file
View file

@ -0,0 +1,74 @@
version: "2"
linters:
default: standard
# Extra linters that are usually worth the cost even on a big codebase.
enable:
- revive
- gosec
- gocritic # good generic bug/quality suggestions
- misspell # catch obvious spelling mistakes in identifiers/comments
# Linters that tend to fight with established code style or structure:
disable:
- funlen
- gocyclo
- wsl
- lll # don't enforce a strict max line length
- mnd # don't go after every "magic number"
- depguard # only useful once you define strict dependency rules
- gomodguard
- ineffassign
- errcheck
settings:
revive:
# Only enable the revive rules you actually care about.
rules:
- name: blank-imports
- name: error-strings
- name: error-return
- name: error-naming
- name: exported
- name: if-return
- name: var-naming
severity: warning
disabled: false
exclude: [""]
arguments:
- ["ID", "Id", "id", "UID", "Uid", "uid", "URI", "Uri", "uri", "URL", "Url", "url"] # AllowList
- [] # DenyList
- - skip-initialism-name-checks: true
upper-case-const: true
skip-package-name-checks: true
- name: var-declaration
- name: increment-decrement
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
misspell:
# Correct spellings using locale preferences for US or UK.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
# Default is to use a neutral variety of English.
locale: US
# Typos to ignore.
# Should be in lower case.
# Default: []
ignore-rules:
- nolint
- gosec
# Extra word corrections.
# `typo` and `correction` should only contain letters.
# The words are case-insensitive.
# Default: []
extra-words:
- typo: "Photoprism"
correction: "PhotoPrism"
# Mode of the analysis:
# - default: checks all the file content.
# - restricted: checks only comments.
# Default: ""
mode: restricted

View file

@ -24,7 +24,7 @@ debug = false
displayName = "John Doe"
sn = "Doe"
uidnumber = 5003
primarygroup = 5501
primarygroup = 5502
loginShell = "/bin/sh"
otherGroups = [5505,5506,5507,5508]
userPrincipalName = "jdoe@example.com"
@ -239,6 +239,48 @@ debug = false
action = "search"
object = "*"
[[users]]
name = "mona"
givenname = "Mona"
objectClass = "manager"
displayName = "Mona Man"
sn = "Man"
userPrincipalName = "mona@example.com"
mail = "mona@example.com"
uidnumber = 5011
primarygroup = 5511
loginShell = "/bin/bash"
otherGroups = [5505]
passsha256 = "4314c1fe282face45336b1422a3285c5ff31a39c8e24425615fa53a43b718493" # photoprism
[[users.customattributes]]
photoprismRoleManager = ["true"]
photoprismNoLogin = ["false"]
photoprismWebdav = ["true"]
[[users.capabilities]]
action = "search"
object = "*"
[[users]]
name = "laura"
givenname = "Laura"
objectClass = "admin"
displayName = "Laura Scope"
sn = "Doe"
userPrincipalName = "laura@example.com"
mail = "laura@example.com"
uidnumber = 5001
primarygroup = 5501
loginShell = "/bin/bash"
otherGroups = [5501, 5508]
passsha256 = "4314c1fe282face45336b1422a3285c5ff31a39c8e24425615fa53a43b718493" # photoprism
[[users.customattributes]]
photoprismRoleAdmin = ["true"]
photoprismNoLogin = ["false"]
photoprismWebdav = ["true"]
[[users.capabilities]]
action = "search"
object = "*"
[[users]]
name = "max"
givenname = "Max"
@ -298,4 +340,8 @@ debug = false
[[groups]]
name = "PhotoPrism-viewer"
gidnumber = 5510
gidnumber = 5510
[[groups]]
name = "PhotoPrism-manager"
gidnumber = 5511

View file

@ -2,4 +2,4 @@
user=root
password=photoprism
host=mariadb
port=4001
skip-ssl=true

24
.prettierignore Normal file
View file

@ -0,0 +1,24 @@
coverage/
node_modules/
screenshots/
acceptance/
build/
dist/
bin/
tests/upload-files/
.tmp
.gocache
.var
*.html
*.md
.*
# JS / Vue / configs — ESLint owns formatting (see frontend/eslint.config.mjs).
# Prettier on these collapses intentional multi-line method chains and
# predicate lists; we deliberately moved them off Prettier's autofix path.
# Vue templates are formatted by eslint-plugin-vue's flat/recommended preset
# (vue/html-indent, vue/html-quotes, vue/max-attributes-per-line, etc.).
**/*.js
**/*.mjs
**/*.cjs
**/*.vue

335
.qdrant.yaml Normal file
View file

@ -0,0 +1,335 @@
log_level: INFO
# Logging configuration
# Qdrant logs to stdout. You may configure to also write logs to a file on disk.
# Be aware that this file may grow indefinitely.
# logger:
# # Logging format, supports `text` and `json`
# format: text
# on_disk:
# enabled: true
# log_file: path/to/log/file.log
# log_level: INFO
# # Logging format, supports `text` and `json`
# format: text
storage:
# Where to store all the data
storage_path: ./storage
# Where to store snapshots
snapshots_path: ./snapshots
snapshots_config:
# "local" or "s3" - where to store snapshots
snapshots_storage: local
# s3_config:
# bucket: ""
# region: ""
# access_key: ""
# secret_key: ""
# Where to store temporary files
# If null, temporary snapshots are stored in: storage/snapshots_temp/
temp_path: null
# If true - point payloads will not be stored in memory.
# It will be read from the disk every time it is requested.
# This setting saves RAM by (slightly) increasing the response time.
# Note: those payload values that are involved in filtering and are indexed - remain in RAM.
#
# Default: true
on_disk_payload: true
# Maximum number of concurrent updates to shard replicas
# If `null` - maximum concurrency is used.
update_concurrency: null
# Write-ahead-log related configuration
wal:
# Size of a single WAL segment
wal_capacity_mb: 32
# Number of WAL segments to create ahead of actual data requirement
wal_segments_ahead: 0
# Normal node - receives all updates and answers all queries
node_type: "Normal"
# Listener node - receives all updates, but does not answer search/read queries
# Useful for setting up a dedicated backup node
# node_type: "Listener"
performance:
# Number of parallel threads used for search operations. If 0 - auto selection.
max_search_threads: 0
# Max number of threads (jobs) for running optimizations across all collections, each thread runs one job.
# If 0 - have no limit and choose dynamically to saturate CPU.
# Note: each optimization job will also use `max_indexing_threads` threads by itself for index building.
max_optimization_threads: 0
# CPU budget, how many CPUs (threads) to allocate for an optimization job.
# If 0 - auto selection, keep 1 or more CPUs unallocated depending on CPU size
# If negative - subtract this number of CPUs from the available CPUs.
# If positive - use this exact number of CPUs.
optimizer_cpu_budget: 0
# Prevent DDoS of too many concurrent updates in distributed mode.
# One external update usually triggers multiple internal updates, which breaks internal
# timings. For example, the health check timing and consensus timing.
# If null - auto selection.
update_rate_limit: null
# Limit for number of incoming automatic shard transfers per collection on this node, does not affect user-requested transfers.
# The same value should be used on all nodes in a cluster.
# Default is to allow 1 transfer.
# If null - allow unlimited transfers.
#incoming_shard_transfers_limit: 1
# Limit for number of outgoing automatic shard transfers per collection on this node, does not affect user-requested transfers.
# The same value should be used on all nodes in a cluster.
# Default is to allow 1 transfer.
# If null - allow unlimited transfers.
#outgoing_shard_transfers_limit: 1
# Enable async scorer which uses io_uring when rescoring.
# Only supported on Linux, must be enabled in your kernel.
# See: <https://qdrant.tech/articles/io_uring/#and-what-about-qdrant>
#async_scorer: false
optimizers:
# The minimal fraction of deleted vectors in a segment, required to perform segment optimization
deleted_threshold: 0.2
# The minimal number of vectors in a segment, required to perform segment optimization
vacuum_min_vector_number: 1000
# Target amount of segments optimizer will try to keep.
# Real amount of segments may vary depending on multiple parameters:
# - Amount of stored points
# - Current write RPS
#
# It is recommended to select default number of segments as a factor of the number of search threads,
# so that each segment would be handled evenly by one of the threads.
# If `default_segment_number = 0`, will be automatically selected by the number of available CPUs
default_segment_number: 0
# Do not create segments larger this size (in KiloBytes).
# Large segments might require disproportionately long indexation times,
# therefore it makes sense to limit the size of segments.
#
# If indexation speed have more priority for your - make this parameter lower.
# If search speed is more important - make this parameter higher.
# Note: 1Kb = 1 vector of size 256
# If not set, will be automatically selected considering the number of available CPUs.
max_segment_size_kb: null
# Maximum size (in KiloBytes) of vectors to store in-memory per segment.
# Segments larger than this threshold will be stored as read-only memmapped file.
# To enable memmap storage, lower the threshold
# Note: 1Kb = 1 vector of size 256
# To explicitly disable mmap optimization, set to `0`.
# If not set, will be disabled by default.
memmap_threshold_kb: null
# Maximum size (in KiloBytes) of vectors allowed for plain index.
# Default value based on https://github.com/google-research/google-research/blob/master/scann/docs/algorithms.md
# Note: 1Kb = 1 vector of size 256
# To explicitly disable vector indexing, set to `0`.
# If not set, the default value will be used.
indexing_threshold_kb: 20000
# Interval between forced flushes.
flush_interval_sec: 5
# Max number of threads (jobs) for running optimizations per shard.
# Note: each optimization job will also use `max_indexing_threads` threads by itself for index building.
# If null - have no limit and choose dynamically to saturate CPU.
# If 0 - no optimization threads, optimizations will be disabled.
max_optimization_threads: null
# This section has the same options as 'optimizers' above. All values specified here will overwrite the collections
# optimizers configs regardless of the config above and the options specified at collection creation.
#optimizers_overwrite:
# deleted_threshold: 0.2
# vacuum_min_vector_number: 1000
# default_segment_number: 0
# max_segment_size_kb: null
# memmap_threshold_kb: null
# indexing_threshold_kb: 20000
# flush_interval_sec: 5
# max_optimization_threads: null
# Default parameters of HNSW Index. Could be overridden for each collection or named vector individually
hnsw_index:
# Number of edges per node in the index graph. Larger the value - more accurate the search, more space required.
m: 16
# Number of neighbours to consider during the index building. Larger the value - more accurate the search, more time required to build index.
ef_construct: 100
# Minimal size (in KiloBytes) of vectors for additional payload-based indexing.
# If payload chunk is smaller than `full_scan_threshold_kb` additional indexing won't be used -
# in this case full-scan search should be preferred by query planner and additional indexing is not required.
# Note: 1Kb = 1 vector of size 256
full_scan_threshold_kb: 10000
# Number of parallel threads used for background index building.
# If 0 - automatically select.
# Best to keep between 8 and 16 to prevent likelihood of building broken/inefficient HNSW graphs.
# On small CPUs, less threads are used.
max_indexing_threads: 0
# Store HNSW index on disk. If set to false, index will be stored in RAM. Default: false
on_disk: false
# Custom M param for hnsw graph built for payload index. If not set, default M will be used.
payload_m: null
# Default shard transfer method to use if none is defined.
# If null - don't have a shard transfer preference, choose automatically.
# If stream_records, snapshot or wal_delta - prefer this specific method.
# More info: https://qdrant.tech/documentation/guides/distributed_deployment/#shard-transfer-method
shard_transfer_method: null
# Default parameters for collections
collection:
# Number of replicas of each shard that network tries to maintain
replication_factor: 1
# How many replicas should apply the operation for us to consider it successful
write_consistency_factor: 1
# Default parameters for vectors.
vectors:
# Whether vectors should be stored in memory or on disk.
on_disk: null
# shard_number_per_node: 1
# Default quantization configuration.
# More info: https://qdrant.tech/documentation/guides/quantization
quantization: null
# Default strict mode parameters for newly created collections.
strict_mode:
# Whether strict mode is enabled for a collection or not.
enabled: false
# Max allowed `limit` parameter for all APIs that don't have their own max limit.
max_query_limit: null
# Max allowed `timeout` parameter.
max_timeout: null
# Allow usage of unindexed fields in retrieval based (eg. search) filters.
unindexed_filtering_retrieve: null
# Allow usage of unindexed fields in filtered updates (eg. delete by payload).
unindexed_filtering_update: null
# Max HNSW value allowed in search parameters.
search_max_hnsw_ef: null
# Whether exact search is allowed or not.
search_allow_exact: null
# Max oversampling value allowed in search.
search_max_oversampling: null
service:
# Maximum size of POST data in a single request in megabytes
max_request_size_mb: 32
# Number of parallel workers used for serving the api. If 0 - equal to the number of available cores.
# If missing - Same as storage.max_search_threads
max_workers: 0
# Host to bind the service on
host: 0.0.0.0
# HTTP(S) port to bind the service on
http_port: 6333
# gRPC port to bind the service on.
# If `null` - gRPC is disabled. Default: null
# Comment to disable gRPC:
grpc_port: 6334
# Enable CORS headers in REST API.
# If enabled, browsers would be allowed to query REST endpoints regardless of query origin.
# More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
# Default: true
enable_cors: true
# Enable HTTPS for the REST and gRPC API
enable_tls: false
# Check user HTTPS client certificate against CA file specified in tls config
verify_https_client_certificate: false
# Set an api-key.
# If set, all requests must include a header with the api-key.
# example header: `api-key: <API-KEY>`
#
# If you enable this you should also enable TLS.
# (Either above or via an external service like nginx.)
# Sending an api-key over an unencrypted channel is insecure.
#
# Uncomment to enable.
# api_key: your_secret_api_key_here
# Set an api-key for read-only operations.
# If set, all requests must include a header with the api-key.
# example header: `api-key: <API-KEY>`
#
# If you enable this you should also enable TLS.
# (Either above or via an external service like nginx.)
# Sending an api-key over an unencrypted channel is insecure.
#
# Uncomment to enable.
# read_only_api_key: your_secret_read_only_api_key_here
# Uncomment to enable JWT Role Based Access Control (RBAC).
# If enabled, you can generate JWT tokens with fine-grained rules for access control.
# Use generated token instead of API key.
#
# jwt_rbac: true
# Hardware reporting adds information to the API responses with a
# hint on how many resources were used to execute the request.
#
# Uncomment to enable.
# hardware_reporting: true
cluster:
# Use `enabled: true` to run Qdrant in distributed deployment mode
enabled: false
# Configuration of the inter-cluster communication
p2p:
# Port for internal communication between peers
port: 6335
# Use TLS for communication between peers
enable_tls: false
# Configuration related to distributed consensus algorithm
consensus:
# How frequently peers should ping each other.
# Setting this parameter to lower value will allow consensus
# to detect disconnected nodes earlier, but too frequent
# tick period may create significant network and CPU overhead.
# We encourage you NOT to change this parameter unless you know what you are doing.
tick_period_ms: 100
# Compact consensus operations once we have this amount of applied
# operations. Allows peers to join quickly with a consensus snapshot without
# replaying a huge amount of operations.
# If 0 - disable compaction
compact_wal_entries: 128
# Set to true to prevent service from sending usage statistics to the developers.
# Read more: https://qdrant.tech/documentation/guides/telemetry
telemetry_disabled: true

3
.rsyncignore Normal file
View file

@ -0,0 +1,3 @@
.*
*.db
__*

17
.telemetry Normal file
View file

@ -0,0 +1,17 @@
# Privacy defaults: opt out of third-party telemetry, analytics, update checks,
# and other non-essential network calls. Uses plain KEY=VALUE lines so this
# file can be referenced by Docker Compose via env_file: and sourced from
# shells, in addition to being included by the Makefile.
DO_NOT_TRACK=true
DISABLE_AUTOUPDATER=1
DISABLE_TELEMETRY=1
DISABLE_ERROR_REPORTING=1
DISABLE_FEEDBACK_COMMAND=1
NO_UPDATE_NOTIFIER=true
NPM_CONFIG_UPDATE_NOTIFIER=false
NPM_CONFIG_AUDIT=false
NPM_CONFIG_FUND=false
GH_TELEMETRY=false
CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY=1
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1

173
AGENTS.md Normal file
View file

@ -0,0 +1,173 @@
# PhotoPrism Repository Guidelines
**Last Updated:** May 5, 2026
## Purpose
Entry point for agents and humans.
## Sources of Truth
- Makefile: https://github.com/photoprism/photoprism/blob/develop/Makefile
- Setup guide: https://docs.photoprism.app/developer-guide/setup/
- Test guide: https://docs.photoprism.app/developer-guide/tests/
- Contributing: https://github.com/photoprism/photoprism/blob/develop/CONTRIBUTING.md
- Security: https://github.com/photoprism/photoprism/blob/develop/SECURITY.md
- REST API: https://docs.photoprism.dev/ and https://docs.photoprism.app/developer-guide/api/
- Code maps: [`CODEMAP.md`](CODEMAP.md), [`frontend/CODEMAP.md`](frontend/CODEMAP.md)
- Package docs: `README.md` files under `internal/`, `pkg/`, `frontend/`, and `frontend/src/`
- Frontend dependency pins, override layer, and orphan-audit pattern: [`frontend/README.md`](frontend/README.md) (read before bumping any non-caret pin or adding/removing a top-level dep)
- AI/Vision docs: [`internal/ai/face/README.md`](internal/ai/face/README.md), [`internal/ai/vision/README.md`](internal/ai/vision/README.md), [`internal/ai/vision/openai/README.md`](internal/ai/vision/openai/README.md), [`internal/ai/vision/ollama/README.md`](internal/ai/vision/ollama/README.md)
- Glossary: [`GLOSSARY.md`](GLOSSARY.md)
- When dependencies change, regenerate `NOTICE` files with `make notice`; do not edit `NOTICE` or `frontend/NOTICE` manually.
## Subtree Guides
- [`internal/AGENTS.md`](internal/AGENTS.md): internal Go rules.
- [`internal/api/AGENTS.md`](internal/api/AGENTS.md): API rules.
- [`internal/config/AGENTS.md`](internal/config/AGENTS.md): config rules.
- [`internal/commands/AGENTS.md`](internal/commands/AGENTS.md): CLI rules.
- [`internal/photoprism/AGENTS.md`](internal/photoprism/AGENTS.md): import and index rules.
- [`internal/service/cluster/AGENTS.md`](internal/service/cluster/AGENTS.md): cluster rules.
- [`frontend/AGENTS.md`](frontend/AGENTS.md): frontend rules.
- [`pkg/AGENTS.md`](pkg/AGENTS.md): `pkg/*` security and test rules.
Optional nested repositories such as `plus/`, `pro/`, `portal/`, and `specs/` may contain their own `AGENTS.md` files. When present, treat those files as additional directory-local guidance.
## Local Agent Progress
- Use `.agents/TODO.md` for actionable tasks and `.agents/DONE.md` for completed work.
- These files are local workflow aids and may not exist in every workspace.
## Style Notes
### Commit Messages
- Use concise imperative subjects with a one-word prefix, for example `Config: Add tests for "darktable-cli" path detection`.
- Append issue or PR IDs when relevant.
- Commit messages must not exceed 80 characters.
### GitHub Issues
- Titles MUST be concise, imperative, and start with one capitalized prefix plus `: `, for example `Search: Add filter for RAW image formats`.
- Descriptions MUST begin with a one-sentence bold user story: `**As a <role>, I want <goal>, so that <outcome>.**`
- Use level-3 Markdown headings for sections within issue descriptions, for example `### Acceptance Criteria`.
- Follow with behavior, rationale, technical considerations, and constraints.
- End with `- [ ]` checklist items for the acceptance criteria, each using `MUST`, `SHOULD`, or `MAY`.
- Keep the checklist current: once the work for a criterion is implemented **and verified**, mark it done (`- [x]`).
- Leave items that are unverified, not yet implemented, or skipped optional (`MAY`) enhancements unchecked.
- An issue is complete only when every `MUST` is checked; never tick a box on the strength of a plan alone or an unrun test.
- When referencing an issue from a commit that fulfills some of its criteria, update the matching boxes first.
- Agents MUST create, edit, close, reopen, relabel, or otherwise modify GitHub issues only when explicitly requested by the user.
### Specifications & Documentation
- Markdown headings use a Chicago-style title case, with additional code- and path-aware normalization rules (see *Title Case rules* below). Always spell the product name as `PhotoPrism`.
- Put option flags before positional arguments unless the command requires another order.
- Use RFC 3339 UTC timestamps and valid ID, UID, and UUID examples in docs and tests.
- The nested `specs/` repository may be absent. Do not add main-repo `Makefile` targets that depend on it; when present, you may run its tools manually.
- Testing guides live at `specs/dev/backend-testing.md` and `specs/dev/frontend-testing.md`.
- Do not read, analyze, or modify `specs/generated/`; refer humans to `specs/generated/README.md` when regeneration is needed.
- Refresh `**Last Updated:**` when you change document contents, but leave it unchanged for whitespace-only or formatting-only edits.
- Nested Git repositories may appear ignored; change into them before staging or committing updates.
Title Case rules (Chicago-style, with code- and path-aware normalization):
- Capitalize the first word, the first word after a colon, dash, or end punctuation, and all major words, including the second part of a hyphenated major word.
- Lowercase only articles, short conjunctions, and short prepositions of three letters or fewer when they are not in one of those positions.
- Preserve known acronyms (for example, API, CLI, HTTP, JSON) and slash-separated acronym groups (for example, CSV/TSV) as uppercase.
- Preserve RFC 2119 / RFC 8174 normative keywords (MUST, SHOULD, MAY, SHALL, REQUIRED, RECOMMENDED, OPTIONAL) as uppercase when used in their normative sense.
- Preserve inline code spans (`` `foo` ``), file paths (e.g. `docs/foo-bar.md`), and slash commands (e.g. `/grill-me`) verbatim; do not recase their contents.
- Use `&` instead of `And`/`Or` in headings.
## Safety & Data
- If `git status` shows unexpected changes, assume a human may be editing; ask before using reset-style commands.
- Do not run `git config` at either the global or repository level.
- Do not run destructive commands against production data; prefer ephemeral volumes and test fixtures for acceptance tests.
- Never commit secrets, local configurations, or cache files; use environment variables or a local `.env`.
- Ensure `.env`, `.config`, `.local`, `.codex`, and `.gocache` are ignored in `.gitignore` and `.dockerignore`.
- Prefer existing caches, workers, and batching strategies already referenced by the code and `Makefile`.
- Consider CPU and memory impact; only suggest profiling or benchmarks when justified.
- If anything here conflicts with the `Makefile` or the sources of truth, ask for clarification before proceeding.
## Project Layout & Shared Rules
- Backend: Go in `internal/`, `pkg/`, and `cmd/`, backed by MariaDB or SQLite.
- Frontend: Vue 3 plus Vuetify 3 under `frontend/`.
- Local dev and CI use Docker Compose; Traefik provides local TLS via `*.localssl.dev`.
- Code in `pkg/*` must not import from `internal/*`. If you need config, entity, or DB access, add code under `internal/`.
- Shared Go rules:
- After Go edits, run `make fmt-go` and keep `gofmt` tab indentation.
- Every added/modified Go function, including unexported helpers, must have focused test coverage in the corresponding `*_test.go` files; update existing tests or add new ones as needed.
- Every Go package must contain a root `<package>.go` file with the standard license header and a short package description comment.
- Use `pkg/fs` permission constants: `fs.ModeDir`, `fs.ModeFile`, `fs.ModeConfigFile`, `fs.ModeSecretFile`, and `fs.ModeBackupFile`.
- When importing the stdlib `io/fs`, alias it to avoid collisions, for example `iofs "io/fs"` or `gofs "io/fs"`.
- Do not pass stdlib `io/fs` mode flags where permission bits are expected.
- Prefer `filepath.Join` for filesystem paths and `path.Join` only for URL paths.
- Normalize slash-based logical paths stored in DB, config, or API payloads with `clean.SlashPath(...)`.
- Shared JS/Vue rules:
- Added/modified JavaScript functions, including helpers, should be tested whenever practical; update existing tests or add new ones as needed.
- Added/modified Vue components should have component-test coverage, and existing component tests should be updated as needed when behavior changes.
- When adding a metadata source such as `SrcOllama` or `SrcOpenAI`, update both `internal/entity/src.go` and `frontend/src/common/util.js` so backend and UI stay aligned.
### JS/Go Code Comments
A doc comment is **required** for every function (including unexported helpers), as well as for every non-trivial Vue `methods:` / `computed:` / watcher:
- Keep comments **compact** and default to one line for "what" in the format `// Name does X.`. Skip trivial getters (`isOpen: () => this.open`).
- Add 1-2 follow-up lines (`// …`) **only** if the "why" is non-obvious: a hidden invariant, a workaround that would otherwise be undone by a future cleanup, a contract a reader can't infer from the code. If readers can infer the "why" from the function body or a nearby line, then omit it.
- Multi-paragraph explanations belong in `specs/`, package `README.md` files, or GitHub issues — never in the source itself.
Doc comments for packages and exported identifiers must be complete sentences that begin with the name of the thing being described and end with a period. For short examples in comments, indent code instead of using backticks.
Use US English spelling in all code comments (`parameterized`, `behavior`, `color`, `serialize`, `normalize`, `optimize`, …) — not the British `-ised`/`-our`/`-re` variants.
> **Don't include in code comments:** Issue / PR numbers, "previously…" history, alternatives considered, what the function used to do, references to old commits, names of subsequent reviewers, or any narrative that names the change rather than the steady-state behavior. That context belongs in commit messages, specs, or handover notes.
## Agent Runtime
- Detect container mode by checking for `/.dockerenv`.
- If the repo path is `/go/src/github.com/photoprism/photoprism` and `/.dockerenv` is absent, treat the environment as host mode with a bind mount and prefer host-side Docker commands.
- Bash check: `[ -f "/.dockerenv" ] && echo container || echo host`
- Node.js check: `require("fs").existsSync("/.dockerenv")`
- Inside the container, prefer `npm exec --yes <agent> -- --help` or `npx <agent> ...`; if a global npm install is unavoidable, install it only inside the container.
- The `photoprism/develop` base image and the repo `Makefile` both set `NPM_CONFIG_IGNORE_SCRIPTS=true`, so `npm ci`/`npm install` via `make` targets skip install scripts out of the box. When running npm directly in an environment that does not set or inherit that default, pass `--ignore-scripts` explicitly to mitigate supply-chain attacks. Rebuild native addons with `npm rebuild --ignore-scripts=false <pkg>` — a bare `npm rebuild` is a silent no-op wherever the env default is active.
- On the host, use the vendor-recommended install method and run from the repository root so agent discovery sees this file.
## Build, Format & Test
- Run `make help` to see supported targets.
- Host mode:
- `make docker-build`
- `docker compose up` or `docker compose up -d`
- `docker compose logs -f --tail=100 photoprism`
- `docker compose exec photoprism ./photoprism help`
- `docker compose exec -u "$(id -u):$(id -g)" photoprism <command>` to avoid root-owned files
- `make terminal`
- `docker compose --profile=all down --remove-orphans` or `make down`
- Container mode:
- `make dep`
- `make build-js` and `make build-go`
- `make watch-js` or `cd frontend && npm run watch`
- `./photoprism start`
- Local URLs: `http://localhost:2342/` and, with Traefik, `https://app.localssl.dev/`
- Local compose defaults to `admin` / `photoprism`; inspect `compose.yaml` if they differ.
- Do not use the Docker CLI inside the container; manage Compose from the host instead.
- The public CLI name is always `photoprism`; development-only side-by-side binaries may use edition-specific names.
- Our command examples assume a Linux or Unix shell on 64-bit AMD64 or ARM64; see the Developer Guide FAQ for Windows-specific notes.
Formatting and test entry points:
- Full suite: `make test`, `make lint`
- Go-specific lint, format, and package-test rules live in [`internal/AGENTS.md`](internal/AGENTS.md).
- Frontend lint, Vitest, acceptance, and Playwright rules live in [`frontend/AGENTS.md`](frontend/AGENTS.md).
- Go tests live next to their sources; use PascalCase `t.Run(...)` names for related subtests. Keep consecutive subtests inside the same `Test*` function back-to-back without blank lines so the cases read as a compact table; reserve blank lines for separating distinct setup blocks.
- Do not run multiple test commands in parallel; suites share fixtures, assets, and database state.
- Prefer focused test runs such as `go test ./path/to/pkg -run Name -count=1` while iterating.
- Use `mariadb -D photoprism` inside the dev shell when you need to inspect MariaDB state directly.
- Run `shellcheck <file>` on edited shell scripts, or use the corresponding `make` target.
### Container Image Builds
- **Never mix Debian and Ubuntu `apt` repositories in the same image:**
- Don't add a Debian source to an Ubuntu base (or vice versa) to install a single missing package — the transitive deps drift, apt's solver pulls newer libraries from the foreign distro, and other build steps in the same `RUN` (e.g. `install-libheif.sh` running `apt-get install libavcodec-dev`) silently link against the wrong soname.
- Symptoms surface much later as `dlopen: libfoo.so.N: cannot open shared object file` at image runtime, with the binary referencing a soname that exists only in the foreign distro.
- If a package isn't available in the host distro's repos, prefer (a) a same-distro PPA / backports source, (b) a vendor-supplied .deb (e.g. Google Chrome from `dl.google.com`), or (c) a from-source build pinned to a known version.

299
CODEMAP.md Normal file
View file

@ -0,0 +1,299 @@
PhotoPrism — Backend CODEMAP
**Last Updated:** May 5, 2026
Purpose
- Give agents and contributors a fast, reliable map of where things live and how they fit together, so you can add features, fix bugs, and write tests without spelunking.
- Sources of truth: prefer Makefile targets and the Developer Guide linked in AGENTS.md.
Quick Start
- Inside dev container (recommended):
- Install deps: `make dep`
- Build backend: `make build-go`
- Lint Go (golangci-lint): `make lint-go` (uses `.golangci.yml`; prints findings without failing) or run both stacks with `make lint`
- Run server: `./photoprism start`
- Open: http://localhost:2342/ or https://app.localssl.dev/ (Traefik required)
- On host (manages Docker):
- Build image: `make docker-build`
- Start services: `docker compose up -d`
- Logs: `docker compose logs -f --tail=100 photoprism`
Executables & Entry Points
- CLI app (binary name across docs/images is `photoprism`):
- Main: `cmd/photoprism/photoprism.go`
- Commands registry: `internal/commands/commands.go` (array `commands.PhotoPrism`)
- Catalog helpers: `internal/commands/catalog` (DTOs and builders to enumerate commands/flags; Markdown renderer)
- Web server:
- Startup: `internal/commands/start.go``server.Start` (starts HTTP(S), workers, session cleanup)
- HTTP server: `internal/server/start.go` (compression, security, healthz, readiness, TLS/AutoTLS/unix socket)
- Routes: `internal/server/routes.go` (registers all v1 API groups + UI, WebDAV, sharing, .well-known)
- API group: `APIv1 = router.Group(conf.BaseUri("/api/v1"), Api(conf))`
High-Level Package Map (Go)
- `internal/api` — Gin handlers and Swagger annotations; only glue, no business logic
- `internal/commands` — CLI command definitions and orchestration (`start`, `index`, `import`, `migrate`, etc.); `commands.go` wires them into the app and subpackages like `catalog` emit CLI documentation.
- `internal/server` — HTTP server, middleware, routing, static/ui/webdav
- `internal/config` — configuration, flags/env/options, client config, DB init/migrate
- `internal/entity` — GORM v1 models, queries, search helpers, migrations
- Label lookup helpers now live in `internal/entity/label*.go`; reuse `FindLabels(...)`, `FindLabelIDs(...)`, and `LabelSlugs(...)` for homophone-aware exact-name/slug resolution instead of duplicating slug SQL in callers.
- `internal/photoprism` — core domain logic (indexing, import, faces, thumbnails, cleanup)
- `internal/ai/vision` — multi-engine computer vision pipeline (models, adapters, schema). Adapter docs: [`internal/ai/vision/openai/README.md`](internal/ai/vision/openai/README.md) and [`internal/ai/vision/ollama/README.md`](internal/ai/vision/ollama/README.md).
- `internal/workers` — background schedulers (index, vision, sync, meta, backup)
- `internal/auth` — ACL, sessions, OIDC
- `internal/service` — cluster/portal, maps, hub, webdav
- WebDAV client docs: `internal/service/webdav/README.md`
- Key WebDAV client behavior:
- Recursive directory discovery prefers `PROPFIND Depth: infinity` and falls back to iterative `Depth: 1` traversal for incompatible servers.
- Hidden dotfiles and entries inside hidden dot-directories are excluded from listings and fallback traversal because they often represent lock files, partial uploads, or provider metadata.
- Service timeouts apply to control operations (`Files`, `Directories`, `Mkdir`, `Delete`), while `Upload` and `Download` avoid total request deadlines and instead use connection-level safeguards.
- `internal/event` — logging, pub/sub, audit; canonical outcome tokens live in `pkg/log/status` (use helpers like `status.Error(err)` when the sanitized message should be the outcome). Docs: `internal/event/README.md`.
- `internal/ffmpeg`, `internal/thumb`, `internal/meta`, `internal/form`, `internal/mutex` — media, thumbs, metadata, forms, coordination. Docs: `internal/ffmpeg/README.md`, `internal/meta/README.md`.
- `pkg/*` — reusable utilities (must never import from `internal/*`), e.g. `pkg/clean`, `pkg/enum`, `pkg/fs`, `pkg/txt`, `pkg/http/header`
Templates & Static Assets
- Entry HTML lives in `assets/templates/index.gohtml`, which includes the splash markup from `app.gohtml` and the SPA loader from `app.js.gohtml`.
- OIDC login completion for the SPA is bridged through `assets/templates/auth.gohtml`, which clears legacy/namespaced session keys and writes the session into the preferred namespaced browser store selected by the login UI toggle in `frontend/src/page/auth/login.vue`.
- The browser check logic resides in `assets/static/js/browser-check.js` and is included via `app.js.gohtml`; it performs capability checks (Promise, fetch, AbortController, `script.noModule`, etc.) before the main bundle runs.
- Update this file (and the partial) in lockstep with `pro/assets/templates/index.gohtml`, `plus/assets/templates/index.gohtml`, and `portal/assets/templates/index.gohtml`, because those editions import the same partial.
- Keep the script tag order unchanged so the browser check executes before the main bundle.
- `splash.gohtml` renders the loading screen text while the bundle loads; styles are in `frontend/src/css/splash.css`.
- When adjusting browser support messaging, update both the loader partial and splash styles so the warning message stays consistent across editions.
- Service worker routes live in `internal/server/routes_webapp.go`. Handlers for `sw.js`, `sw-scope-cleanup.js`, and Workbox runtime files (`/workbox-:hash`) are defined there so service workers run under both the site root and a base URI; remember Gins `:hash` parameter excludes the `.js` suffix, so the handler/test matches the full filename manually.
HTTP API
- Handlers live in `internal/api/*.go` and are registered in `internal/server/routes.go`.
- Annotate new endpoints in handler files; generate docs with: `make fmt-go swag-fmt && make swag`.
- Do not edit `internal/api/swagger.json` by hand.
- Swagger notes:
- Use full `/api/v1/...` in every `@Router` annotation (match the group prefix).
- Annotate only public handlers; skip internal helpers to avoid stray generic paths.
- `make swag-json` runs a stabilization step (`swaggerfix`) removing duplicated enums for `time.Duration`; API uses integer nanoseconds for durations.
- `/api/v1/metrics` (see `internal/api/metrics.go`) exposes Prometheus metrics, including cached filesystem/account usage derived from `config.Usage()`, registered user/guest totals, and portal cluster node counts when `NodeRole=portal`; the handler returns the standard Prometheus exposition content type (`text/plain; version=0.0.4`).
- Common groups in `routes.go`: sessions, OAuth/OIDC, config, users, services, thumbnails, video, downloads/zip, index/import, photos/files/labels/subjects/faces, batch ops, cluster, technical (metrics, status, echo).
- Hidden search behavior (used by the hidden route under the configured frontend URI, default `/library/hidden` for CE/Plus/Pro and `/portal/hidden` for Portal) is implemented in `internal/entity/search/photos.go`:
- `frm.Hidden` enforces `photos.photo_quality = -1` and `photos.deleted_at IS NULL`.
- Non-hidden searches exclude errored files by default (`files.file_error = ''`) unless `frm.Error` is explicitly set.
- Search DTOs in `internal/entity/search/photos_results.go` expose `FileError` (`files.file_error`) so clients can render hidden reasons without loading full file details first.
Configuration & Flags
- Options struct: `internal/config/options.go` with `yaml:"…"` (for `defaults.yml`/`options.yml`), `json:"…"` (clients/API), and `flag:"…"` (CLI flags/env) tags.
- For secrets/internals: `json:"-"` disables JSON processing to prevent values from being exposed through the API (see `internal/api/config_options.go`).
- If needed: `yaml:"-"` disables YAML processing; `flag:"-"` prevents `ApplyCliContext()` from assigning CLI values (flags/env variables) to a field, without affecting the flags in `internal/config/flags.go`.
- Annotations may include edition tags like `tags:"plus,pro"` to control visibility (see `internal/config/options_report.go` logic).
- Global flags/env: `internal/config/flags.go` (`EnvVars(...)`)
- Available flags/env: `internal/config/cli_flags_report.go` + `internal/config/report_sections.go` → surfaced by `photoprism show config-options --md/--json`
- YAML options mapping: `internal/config/options_report.go` + `internal/config/report_sections.go` → surfaced by `photoprism show config-yaml --md/--json`
- Report current values: `internal/config/report.go` → surfaced by `photoprism show config` (alias `photoprism config --md`).
- CLI commands catalog: `internal/commands/show_commands.go` → surfaced by `photoprism show commands` (Markdown by default; `--json` alternative; `--nested` optional tree; `--all` includes hidden commands/flags; nested `help` subcommands omitted).
- Precedence: `defaults.yml` < CLI/env < `options.yml` (global options rule). See Agent Tips in `AGENTS.md`.
- Config-owned persistence helpers:
- `Config.SaveOptionsPatch(...)` in `internal/config/config.go` for generic `options.yml` merge/write/reload.
- `Config.SaveClusterOptionsUpdate(...)` in `internal/config/config_cluster.go` for cluster metadata updates (`ClusterUUID`, `NodeUUID`, `NodeClientID`, DB fields, etc.).
- Getters are grouped by topic, e.g. DB in `internal/config/config_db.go`, server in `config_server.go`, TLS in `config_tls.go`, etc.
- Client Config (read-only)
- Endpoint: GET `/api/v1/config` (see `internal/api/api_client_config.go`).
- CDN behavior: Requests carrying CDN headers are rejected with `404` to prevent intermediary cache mix-ups between public and session-specific config payloads.
- Assembly: Built from `internal/config/client_config.go` (not a direct serialization of Options) plus extension values registered via `config.Register` in `internal/config/extensions.go`.
- Updates: Back-end calls `UpdateClientConfig()` to publish "config.updated" over websockets after changes (see `internal/api/config_options.go` and `internal/api/config_settings.go`).
- ACL/mode aware: Values are filtered by user/session and may differ for public vs. authenticated users.
- Dont expose secrets: Treat it as client-visible; avoid sensitive data. To add fields, extend client values via `config.Register` rather than exposing Options directly.
- Refresh cadence: The web UI (nonmobile) also polls for updates every 10 minutes via `$config.update()` in `frontend/src/app.js`, complementing the websocket push.
- OIDC Groups (Pro-Only)
- Config options (tagged `pro`, flags hidden in CE): `oidc-group-claim` (default `groups`), `oidc-group` (required membership list), `oidc-group-role` (mapping `GROUP=ROLE`).
- Parsing/helpers: `internal/auth/oidc/groups.go` normalizes IDs, detects Entra `_claim_names` overage, maps groups→roles, and enforces required membership in `internal/api/oidc_redirect.go`.
- Overage: if `_claim_names.groups` is present and no groups are returned, login fails when required groups are configured; Graph fetch is not implemented yet.
Database & Migrations
- Driver: GORM v1 (`github.com/jinzhu/gorm`). No `WithContext`. Use `db.Raw(stmt).Scan(&nop)` for raw SQL.
- Entities and helpers: `internal/entity/*.go` and subpackages (`query`, `search`, `sortby`).
- Migrations engine: `internal/entity/migrate/*` — run via `config.MigrateDb()`; CLI: `photoprism migrate` / `photoprism migrations`.
- DB init/migrate flow: `internal/config/config_db.go` chooses driver/DSN, sets `gorm:table_options`, then `entity.InitDb(migrate.Opt(...))`.
AuthN/Z & Sessions
- Session model and cache: `internal/entity/auth_session*` and `internal/auth/session/*` (cleanup worker).
- `internal/entity/auth_session_jwt.go` builds transient sessions from portal-issued JWTs; used by `internal/api/api_auth_jwt.go` when nodes authenticate portal requests.
- ACL: `internal/auth/acl/*` — roles, grants, scopes; use constants; avoid logging secrets, compare tokens constanttime; for scope checks use `acl.ScopePermits` / `ScopeAttrPermits` instead of rolling your own parsing.
- OIDC: `internal/auth/oidc/*`.
Media Processing
- Thumbnails: `internal/thumb/*` and helpers in `internal/photoprism/mediafile_thumbs.go`.
- Metadata: `internal/meta/*`.
- FFmpeg integration: `internal/ffmpeg/*`.
- HEIF tooling: distribution binaries live under `scripts/dist/install-libheif.sh`; regenerate archives with `make build-libheif-*` (wraps `scripts/dist/build-libheif.sh` for each supported distro/arch) before publishing to `dl.photoprism.app/dist/libheif/`.
- Folder album consistency:
- `internal/entity/folder.go` keeps `FindFolder(...)` unscoped for create/index conflict handling, so a soft-deleted row cannot cause repeated insert/fail/not-found loops.
- `internal/photoprism/index.go` runs `entity.ReconcileOriginalsFolderAlbums(...)` only on forced rescans, after the file walk, so regular indexing stays lightweight while complete rescans repair stale/missing folder albums.
Background Workers
- Scheduler and workers: `internal/workers/*.go` (index, vision, meta, sync, backup, share); started from `internal/commands/start.go`.
- Auto indexer: `internal/workers/auto/*`.
Cluster / Portal
- Node types: `internal/service/cluster/const.go` (`cluster.RoleInstance`, `cluster.RolePortal`, `cluster.RoleService`).
- Node bootstrap & registration: `internal/service/cluster/node/*` (HTTP to Portal; do not import Portal internals).
- Registration now retries once on 401/403 by rotating the node client secret with the join token and persists the new credentials (falling back to in-memory storage if the secrets directory is read-only).
- Theme sync logs explicitly when refresh/rotation occurs so operators can trace credential churn in standard log levels.
- Registry/provisioner: `internal/service/cluster/registry/*`, `internal/service/cluster/provisioner/*`.
- Theme endpoint (server): GET `/api/v1/cluster/theme`; client/CLI installs theme only if missing or no `app.js`.
- Portal-only extensions: `portal/internal/portal` (Portal defaults, flags, provisioning options, `/i/*` proxy router).
Logging & Events
- Logger and event hub: `internal/event/*`; `event.Log` is the shared logger.
- HTTP headers/constants: `pkg/http/header/*` — always prefer these in handlers and tests.
Server Startup Flow (happy path)
1) `photoprism start` (CLI) → `internal/commands/start.go`
2) Config init, DB init/migrate, session cleanup worker
3) `internal/server/start.go` builds Gin engine, middleware, API group, templates
4) `internal/server/routes.go` registers UI, WebDAV, sharing, wellknown, and all `/api/v1/*` routes
5) Workers and autoindex start; health endpoints `/livez`, `/readyz` available
Common HowTos
- Add a CLI command
- Create `internal/commands/<name>.go` with a `*cli.Command`
- Add it to `PhotoPrism` in `internal/commands/commands.go`
- Tests: prefer `RunWithTestContext` from `internal/commands/commands_test.go` to avoid `os.Exit`
- Add a REST endpoint
- Create handler in `internal/api/<area>.go` with Swagger annotations
- Register it in `internal/server/routes.go`
- Use helpers: `api.ClientIP(c)`, `header.BearerToken(c)`, `Abort*` functions
- Validate pagination bounds (default `count=100`, max `1000`, `offset>=0`) for list endpoints
- Run `make fmt-go swag-fmt && make swag`; keep docs accurate
- Tests: `go test ./internal/api -run <Name>` and focused helpers (`NewApiTest()`, `PerformRequest*`)
- Add a config option
- Add field with tags to `internal/config/options.go`
- Register CLI flag/env in `internal/config/flags.go` via `EnvVars(...)`
- Expose a getter (e.g., in `config_server.go` or topic file)
- Append to `rows` in `*config.Report()` after the same option as in `options.go`
- If value must persist, write back to `options.yml` and reload into memory (prefer `Config.SaveOptionsPatch(...)` and related config-owned helpers over ad-hoc YAML logic).
- When you need the path to defaults/options/settings files, call `pkg/fs.ConfigFilePath` so `.yml` and `.yaml` stay interchangeable.
- Tests: cover CLI/env/file precedence (see `internal/config/test.go` helpers)
- Touch the DB schema
- Use GORM auto-migration, or add a custom migration in `internal/entity/migrate/<dialect>/...` and run `go generate` or `make generate` (runs `go generate` for all packages)
- Bump/review version gates in `migrate.Version` usage via `config_db.go`
- Tests: run against SQLite by default; for MySQL cases, gate appropriately
Testing
- Full suite: `make test` (frontend + backend). Backend only: `make test-go`.
- Focused packages: `go test ./internal/<pkg> -run <Name>`.
- CLI tests: `PHOTOPRISM_CLI=noninteractive` or pass `--yes` to avoid prompts; use `RunWithTestContext` to prevent `os.Exit`.
- SQLite DSN in tests is persuite (not empty). Clean up files if you capture the DSN.
- Frontend unit tests via Vitest are separate; see `frontend/CODEMAP.md`.
- Config helpers automatically disable Hub service calls for tests (`hub.ApplyTestConfig()`).
- Test configs auto-discover the repo `assets/` folder, so avoid adding per-package `PHOTOPRISM_ASSETS_PATH` shims unless you have an unusual layout.
Security & Hot Spots (Where to Look)
- Zip extraction (path traversal prevention): `pkg/fs/zip.go`
- Uses `safeJoin` to reject absolute/volume paths and `..` traversal; enforces per-file and total size limits.
- Tests: `pkg/fs/zip_extra_test.go` cover abs/volume/.. cases and limits.
- Force-aware Copy/Move and truncation-safe writes:
- App helpers: `internal/photoprism/mediafile.go` (`MediaFile.Copy/Move` with `force`).
- Utils: `pkg/fs/copy.go`, `pkg/fs/move.go` (use `O_TRUNC` to avoid trailing bytes).
- FFmpeg command builders and encoders:
- Core: `internal/ffmpeg/transcode_cmd.go`, `internal/ffmpeg/remux.go`.
- Encoders (string builders only): `internal/ffmpeg/{apple,intel,nvidia,vaapi,v4l}/avc.go`.
- Tests guard HW runs with `PHOTOPRISM_FFMPEG_ENCODER`; otherwise assert command strings and negative paths.
- libvips thumbnails:
- Pipeline: `internal/thumb/vips.go` (VipsInit, VipsRotate, export params).
- Sizes & names: `internal/thumb/sizes.go`, `internal/thumb/names.go`, `internal/thumb/filter.go`; face/marker crop helpers live in `internal/thumb/crop` (e.g., `ParseThumb`, `IsCroppedThumb`).
- Safe HTTP downloader:
- Shared utility: `pkg/http/safe` (`Download`, `Options`).
- Protections: scheme allowlist (http/https), preDNS + perredirect hostname/IP validation, final peer IP check, size and timeout enforcement, temp file `0600` + rename.
- Avatars: wrapper `internal/thumb/avatar.SafeDownload` applies stricter defaults (15s, 10MiB, `AllowPrivate=false`, imagefocused `Accept`).
- Tests: `go test ./pkg/http/safe -count=1` (includes redirect SSRF cases); avatars: `go test ./internal/thumb/avatar -count=1`.
- CDN guards for credential flows:
- Auth/session and OAuth/OIDC endpoints reject CDN-marked requests.
- Cluster bootstrap endpoint `POST /api/v1/cluster/nodes/register` also rejects CDN-marked requests to avoid caching responses that may contain bootstrap secrets.
Performance & Limits
- Prefer existing caches/workers/batching as per Makefile and code.
- When adding list endpoints, default `count=100` (max `1000`); set `Cache-Control: no-store` for secrets.
Conventions & Rules of Thumb
- Respect package boundaries: code in `pkg/*` must not import `internal/*`.
- Prefer constants/helpers from `pkg/http/header` over string literals.
- Never log secrets; compare tokens constanttime.
- Dont import Portal internals from cluster instance/service bootstraps; use HTTP.
- Prefer small, hermetic unit tests; isolate filesystem paths with `t.TempDir()` and env like `PHOTOPRISM_STORAGE_PATH`.
- Cluster nodes: identify by UUID v7 (internally stored as `NodeUUID`; exposed as `UUID` in API/CLI). The OAuth client ID (`NodeClientID`, exposed as `ClientID`) is for OAuth only. Registry lookups and CLI commands accept UUID, ClientID, or DNS-label name (priority in that order).
Filesystem Permissions & io/fs Aliasing
- Use `github.com/photoprism/photoprism/pkg/fs` permission variables when creating files/dirs:
- `fs.ModeDir` (0o755 with umask), `fs.ModeFile` (0o644 with umask), `fs.ModeConfigFile` (0o664), `fs.ModeSecretFile` (0o600), `fs.ModeBackupFile` (0o600).
- Do not use stdlib `io/fs` mode bits as permission arguments. When importing stdlib `io/fs`, alias it (`iofs`/`gofs`) to avoid `fs.*` collisions with our package.
- Prefer `filepath.Join` for filesystem paths across platforms; use `path.Join` for URLs only.
Cluster Registry & Provisioner Cheatsheet
- UUIDfirst everywhere: API paths `{uuid}`, Registry `Get/Delete/RotateSecret` by UUID; explicit `FindByClientID` exists for OAuth.
- Node/DTO fields: `uuid` required; `clientId` optional; database metadata includes `driver`.
- Provisioner naming (no slugs):
- database: `cluster_d<hmac11>`
- username: `cluster_u<hmac11>`
HMAC is base32 of ClusterUUID+NodeUUID; drivers currently `mysql|mariadb`.
- DSN builder: `BuildDSN(driver, host, port, user, pass, name)`; warns and falls back to MySQL format for unsupported drivers.
- Go tests live beside sources: for `path/to/pkg/<file>.go`, add tests in `path/to/pkg/<file>_test.go` (create if missing). For the same function, group related cases as `t.Run(...)` sub-tests (table-driven where helpful) and name each subtest string in PascalCase.
- Public API and internal registry DTOs use normalized field names:
- `Database` (not `db`) with `Name`, `User`, `Driver`, `RotatedAt`.
- Node-level rotation timestamps use `RotatedAt`.
- Registration returns `Secrets.ClientSecret`; the CLI persists it under config `NodeClientSecret`.
- Admin responses may include `AdvertiseUrl` and `Database`; non-admin responses are redacted by default.
- Cluster CLI highlights:
- `photoprism cluster register` supports `--site-url` and `--advertise-url`. Both values are always forwarded to the Portal regardless of whether they differ.
- Automatic MariaDB credential rotation logic lives in `config.ShouldAutoRotateDatabase()` and is shared by both the CLI and node bootstrap.
Frequently Touched Files (by topic)
- CLI wiring: `cmd/photoprism/photoprism.go`, `internal/commands/commands.go`
- Server: `internal/server/start.go`, `internal/server/routes.go`, middleware in `internal/server/*.go`
- API handlers: `internal/api/*.go` (plus `docs.go` for package docs)
- Config: `internal/config/*` (`flags.go`, `config_db.go`, `config_server.go`, `options.go`)
- Entities & queries: `internal/entity/*.go`, `internal/entity/query/*`
- Migrations: `internal/entity/migrate/*`
- Workers: `internal/workers/*`
- Cluster: `internal/service/cluster/*`
- Theme support: `internal/service/cluster/theme/version.go` exposes `DetectVersion`, used by bootstrap, CLI, and API handlers to compare portal vs node theme revisions (prefers `fs.VersionTxtFile`, falls back to `app.js` mtime).
- Registration sanitizes `AppName`, `AppVersion`, and `Theme` with `clean.TypeUnicode`; defaults for app metadata come from `config.About()` / `config.Version()`. `cluster.RegisterResponse` now includes a `Theme` hint when the portal has a newer bundle so nodes can decide whether to download immediately.
- Headers: `pkg/http/header/*`
Downloads (CLI) & yt-dlp helpers
- CLI command & core:
- `internal/commands/download.go` (flags, defaults, examples)
- `internal/commands/download_impl.go` (testable implementation used by CLI)
- yt-dlp wrappers:
- `internal/photoprism/dl/options.go` (arg wiring; `FFmpegPostArgs` hook for `--postprocessor-args`)
- `internal/photoprism/dl/info.go` (metadata discovery)
- `internal/photoprism/dl/file.go` (file method with `--output`/`--print`)
- `internal/photoprism/dl/meta.go` (`CreatedFromInfo` fallback; `RemuxOptionsFromInfo`)
- Importer:
- `internal/photoprism/get/import.go` (work pool)
- `internal/photoprism/import_options.go` (`ImportOptionsMove/Copy`)
- Testing hints:
- Fast loops: `go test ./internal/photoprism/dl -run 'Options|Created|PostprocessorArgs' -count=1`
- CLI only: `go test ./internal/commands -run 'DownloadImpl|HelpFlags' -count=1`
- Disable ffmpeg when not needed: set `FFmpegBin = "/bin/false"`, `Settings.Index.Convert=false` in tests.
- Stub yt-dlp: shell script that prints JSON for `--dump-single-json`, creates a file and prints path for `--print`.
- Avoid importer dedup: vary file bytes (e.g., `YTDLP_DUMMY_CONTENT`) or dest.
Useful Make Targets (selection)
- `make help` — list targets
- `make dep` — install Go/JS deps in container
- `make build-go` — build backend
- `make test-go` — backend tests (SQLite)
- `make swag` — generate Swagger JSON in `internal/api/swagger.json`
- `make fmt-go swag-fmt` — format Go code and Swagger annotations
See Also
- AGENTS.md (repository rules and tips for agents)
- Developer Guide (Setup/Tests/API) — links in AGENTS.md → Sources of Truth
Go Internal Import Rule
- Keep temporary Go helpers inside `internal/...`; the Go toolchain blocks importing `internal/` packages from directories such as `/tmp`, so use a disposable path like `internal/tmp/` when you need scratch space.
Fast Test Recipes
- Filesystem + archives (fast): `go test ./pkg/fs -run 'Copy|Move|Unzip' -count=1`
- Media helpers (fast): `go test ./pkg/media/... -count=1`
- Thumbnails (libvips, moderate): `go test ./internal/thumb/... -count=1`
- FFmpeg command builders (moderate): `go test ./internal/ffmpeg -run 'Remux|Transcode|Extract' -count=1`

View file

@ -1,8 +1,8 @@
# PhotoPrism® Code of Conduct
**By using the software and services we provide, you agree to our [Terms of Service](https://www.photoprism.app/terms), including our [Privacy Policy](https://www.photoprism.app/privacy) and the following Code of Conduct. It explains the "dos and donts" when interacting with our team and other community members.**
**By using the software and services we provide, you agree to our [Terms of Service](https://www.photoprism.app/terms/), including our [Privacy Policy](https://www.photoprism.app/privacy/) and the following Code of Conduct. It explains the "dos and donts" when interacting with our team and other community members.**
*This Code of Conduct was last updated on May 6, 2024. A German translation is available at [photoprism.app/de/code-of-conduct](https://www.photoprism.app/de/code-of-conduct).*
*This Code of Conduct was last updated on May 30, 2026. A German translation is available at [photoprism.app/de/code-of-conduct](https://www.photoprism.app/de/code-of-conduct/).*
## Rules
@ -30,16 +30,12 @@ We have found that many of the issues that new users get upset about when they r
## Reporting
We encourage all community members to resolve problems on their own whenever possible. Serious and persistent violations, such as disrespectful, abusive, harassing, or otherwise unacceptable behavior, [may be reported](https://www.photoprism.app/contact) to us.
We encourage all community members to resolve problems on their own whenever possible. Serious and persistent violations, such as disrespectful, abusive, harassing, or otherwise unacceptable behavior, [may be reported](https://www.photoprism.app/contact/) to us.
## Enforcement
Our community standards will be enforced as necessary to protect everyone's well-being and to ensure that our discussion forums, chat rooms, and other infrastructure can be used as intended.
Our community standards will be enforced as necessary to protect everyone's well-being and ensure our discussion forums, chat rooms, and other infrastructure, such as GitHub, can be used as intended.
Initial warnings may be issued in the form of a [snarky comment](https://www.urbandictionary.com/define.php?term=snarky), especially if you seem reckless or [surprisingly harsh](https://github.com/photoprism/photoprism/issues/281#issuecomment-1207233135). In serious cases, we will provide a link to this Code of Conduct to avoid misunderstandings. We also reserve the right to delete rants, personal attacks, spam, and unsolicited advertising from our community forums.
In cases where violations may be unintentional and improvement seems possible, we aim to issue warnings before taking further action.
Getting a simple **\*plonk\***[^1] in response finally signals that we have lost hope and you're being ignored according to **Rule &#35;3**. This old tradition from Usenet days is as time-saving as it is clear. It is not meant in a disrespectful way.
In addition, we may use technical measures to temporarily or permanently restrict your access to our infrastructure, including forums and chats.
[^1]: \*plonk\* including variants such as "Plonk." stands for the metaphorical sound of a user hitting the bottom of the kill file. It was first used in [Usenet forums](https://en.everybodywiki.com/Plonk_(Usenet)), a worldwide distributed discussion system and precursor to the Web.
In serious cases, we may use technical measures to restrict your access to our infrastructure, including GitHub, forums, and chats, either temporarily or permanently. We also reserve the right to delete rants, personal attacks, spam, and unsolicited advertisements. If you believe we made a mistake, you may [email us](https://www.photoprism.app/contact/) to request an appeal.

View file

@ -4,9 +4,9 @@ We welcome contributions of any kind, including blog posts, tutorials, testing,
## Join the Community ##
Follow us on [Mastodon](https://floss.social/@photoprism), [Bluesky](https://bsky.app/profile/photoprism.app), or join the [Community Chat](https://link.photoprism.app/chat) to get regular updates, connect with other users, and discuss your ideas. Our [Code of Conduct](https://www.photoprism.app/code-of-conduct) explains the "dos and donts" when interacting with other community members.
Follow us on [Mastodon](https://floss.social/@photoprism), [Bluesky](https://bsky.app/profile/photoprism.app), or join the [Community Chat](https://link.photoprism.app/chat) to get regular updates, connect with other users, and discuss your ideas. Our [Code of Conduct](https://www.photoprism.app/code-of-conduct/) explains the "dos and donts" when interacting with other community members.
As a [contributor](https://docs.photoprism.app/developer-guide/), you are also welcome to [contact us directly](https://www.photoprism.app/contact) if you have something on your mind that you don't want to discuss publicly. Please note, however, that due to the high volume of emails we receive, our team may be unable to get back to you immediately. We do our best to respond within five business days or less.
As a [contributor](https://docs.photoprism.app/developer-guide/), you are also welcome to [contact us directly](https://www.photoprism.app/contact/) if you have something on your mind that you don't want to discuss publicly. Please note, however, that due to the high volume of emails we receive, our team may be unable to get back to you immediately. We do our best to respond within five business days or less.
## Not a Developer? No Problem ##
@ -36,20 +36,22 @@ We kindly ask you not to report bugs via GitHub Issues **unless you are certain
- When reporting a problem, always include the software versions you are using and other information about your environment such as [browser, browser plugins](https://docs.photoprism.app/getting-started/troubleshooting/browsers/), operating system, [storage type](https://docs.photoprism.app/getting-started/troubleshooting/performance/#storage), [memory size](https://docs.photoprism.app/getting-started/troubleshooting/performance/#memory), and [processor](https://docs.photoprism.app/getting-started/troubleshooting/performance/#server-cpu)
- Note that all issue **subscribers receive an email notification** from GitHub whenever a new comment is added, so these should only be used for sharing important information and not for discussions, questions or expressing personal opinions
- [Contact us](https://www.photoprism.app/contact) or [a community member](https://link.photoprism.app/discussions) if you need help, it could be a local configuration problem, or a misunderstanding in how the software works
- [Contact us](https://www.photoprism.app/contact/) or [a community member](https://link.photoprism.app/discussions) if you need help, it could be a local configuration problem, or a misunderstanding in how the software works
- This gives our team the opportunity to [improve the docs](https://docs.photoprism.app/getting-started/troubleshooting/) and provide best-in-class support to you, instead of handling unclear/duplicate bug reports or triggering a flood of notifications by responding to comments
## Submitting Pull Requests ##
Follow our [step-by-step guide](https://docs.photoprism.app/developer-guide/pull-requests) to learn how to submit new features, bug fixes, and documentation enhancements.
You are welcome to use AI tools for research, drafting, or other supporting tasks. However, we do not accept fully AI-generated pull requests at this time. Every contribution must be carefully reviewed, tested, and understood by a human contributor who can discuss the implementation details and maintain the change afterward.
Pull requests solving ["help wanted"](https://github.com/photoprism/photoprism/labels/help%20wanted) issues are the easiest to merge and the most helpful to us, as they allow us to spend more time on core functionality and other issues that are difficult for external contributors to work on. If you are new to this project, anything labeled ["easy"](https://github.com/photoprism/photoprism/labels/easy) may be a good first contribution.
**Be aware that reviewing, testing and finally merging pull requests requires significant resources on our side. It can therefore take several months if it is not just a small fix, especially if extensive testing is needed to prevent bugs from getting into our stable version.**
## Contributor License Agreement (CLA) ##
After you submit your first pull request, you will be asked to accept our Contributor License Agreement (CLA). Visit [photoprism.app/cla](https://www.photoprism.app/cla) and [photoprism.app/oss/faq](https://www.photoprism.app/oss/faq#cla) to learn more.
After you submit your first pull request, you will be asked to accept our Contributor License Agreement (CLA). Visit [photoprism.app/cla](https://www.photoprism.app/cla/) and [photoprism.app/oss/faq](https://www.photoprism.app/oss/faq/#cla) to learn more.
## Thank You to All Current and Past Sponsors 💎 ##
@ -74,4 +76,4 @@ Because many of these apps and tools were originally developed for internal use
----
*PhotoPrism® is a [registered trademark](https://www.photoprism.app/trademark). By using the software and services we provide, you agree to our [Terms of Service](https://www.photoprism.app/terms), [Privacy Policy](https://www.photoprism.app/privacy), and [Code of Conduct](https://www.photoprism.app/code-of-conduct). Docs are [available](https://link.photoprism.app/github-docs) under the [CC BY-NC-SA 4.0 License](https://creativecommons.org/licenses/by-nc-sa/4.0/); [additional terms](https://github.com/photoprism/photoprism/blob/develop/assets/README.md) may apply.*
*PhotoPrism® is a [registered trademark](https://www.photoprism.app/trademark/). By using the software and services we provide, you agree to our [Terms of Service](https://www.photoprism.app/terms/), [Privacy Policy](https://www.photoprism.app/privacy/), and [Code of Conduct](https://www.photoprism.app/code-of-conduct/). Docs are [available](https://link.photoprism.app/github-docs) under the [CC BY-NC-SA 4.0 License](https://creativecommons.org/licenses/by-nc-sa/4.0/); [additional terms](https://github.com/photoprism/photoprism/blob/develop/assets/README.md) may apply.*

View file

@ -1,7 +1,12 @@
# Ubuntu 24.10 (Oracular Oriole)
FROM photoprism/develop:250221-oracular
# Ubuntu 26.04 LTS (Resolute Raccoon)
FROM photoprism/develop:260709-resolute
# Harden npm usage by default (applies to npm ci / install in dev container)
ENV NPM_CONFIG_IGNORE_SCRIPTS=true
## Alternative Environments:
# FROM photoprism/develop:questing # Ubuntu 25.10 (Questing Quokka)
# FROM photoprism/develop:plucky # Ubuntu 25.04 (Plucky Puffin)
# FROM photoprism/develop:armv7 # ARMv7 (32bit)
# FROM photoprism/develop:oracular # Ubuntu 24.10 (Oracular Oriole)
# FROM photoprism/develop:noble # Ubuntu 24.04 LTS (Noble Numbat)
@ -13,9 +18,21 @@ FROM photoprism/develop:250221-oracular
# FROM photoprism/develop:bullseye # Debian 11 (Bullseye)
# FROM photoprism/develop:buster # Debian 10 (Buster)
# Set default working directory.
WORKDIR "/go/src/github.com/photoprism/photoprism"
# Set default working directory. Override WORKING_DIR (e.g. via compose build
# args populated from .env) to match a custom host-side clone layout; the value
# must stay aligned with compose's working_dir and the source bind mount target.
ARG WORKING_DIR=/go/src/github.com/photoprism/photoprism
WORKDIR "${WORKING_DIR}"
# Copy source to image.
COPY . .
COPY --chown=root:root /scripts/dist/ /scripts/
# Update scripts in image.
COPY --chown=root:root ./scripts/dist/ /scripts/
# Re-install the dev "mariadb" client config so a custom MARIADB_PORT in .env
# is honored even when the base image was built before the port=<n> line was
# removed (no-op once the next dated base image picks up the new .my.cnf).
COPY --chown=root:root --chmod=644 ./.my.cnf /etc/my.cnf
RUN sudo /scripts/install-yt-dlp.sh

View file

@ -1,3 +1,3 @@
custom: "https://www.photoprism.app/editions#compare"
custom: "https://www.photoprism.app/editions/#compare"
github: photoprism
patreon: photoprism

38
GLOSSARY.md Normal file
View file

@ -0,0 +1,38 @@
## PhotoPrism — Glossary
**Last Updated:** February 23, 2026
### Purpose & Scope
- This is the single source of truth for terminology used across PhotoPrism documentation.
- Define terms once here and reference this file instead of redefining the same terms in multiple documents.
- Keep technical/API contract names unchanged where required, even when user-facing wording differs.
### Canonical Terms
- **admin** — user or client with elevated authorization scopes/roles.
- **AdvertiseUrl** — internal/service URL that cluster peers use to reach an instance or service.
- **app** — intentional identifier in names/examples (for example `app.js`, `app.kubernetes.io/*`, `photoprism-app`); not the preferred generic runtime role term.
- **client** — OAuth/API client identity and credentials (`ClientID`, `ClientSecret`), and broadly a caller of an API.
- **cluster domain** — DNS domain used to derive cluster defaults (for example portal/instance URLs).
- **cluster UUID** — stable cluster identifier used by provisioning and cluster metadata.
- **instance** — PhotoPrism runtime with role `instance` (a cluster member serving UI/API/media features).
- **Join Token** — bootstrap bearer token used for initial registration (`/api/v1/cluster/nodes/register`).
- **node** — technical identifier used in API/config contracts (for example `/api/v1/cluster/nodes`, `NodeName`, `PHOTOPRISM_NODE_*`, `config/node/...` paths).
- **portal** — PhotoPrism runtime with role `portal`, providing cluster control-plane APIs and routing.
- **service** — PhotoPrism runtime with role `service` (non-instance cluster member focused on service workloads).
- **SiteUrl** — canonical public URL/origin for an instance.
- **tenant** — shared-domain routing ownership label used in path-based URLs such as `/i/<tenant>/...`; typically maps to a registered instance name.
### Writing Rules
- Use **instance**/**instances** for cluster runtime behavior and role language.
- Use **tenant**/**tenants** for shared-domain path ownership and routing semantics.
- Keep **node** where a field name, endpoint, flag/env var, config path, or code contract explicitly requires it.
- Keep **app** only where it is an intentional identifier/example.
- When a term appears ambiguous, link or refer back to this glossary.
### Change Management
- Update this file first when introducing, renaming, or clarifying core terminology.
- When terminology changes, update dependent docs to match these definitions.

View file

@ -625,7 +625,7 @@ corporate design, product and service names, and any other brand features
and elements, whether registered or unregistered („Brand Assets“) — are
proprietary assets owned exclusively by PhotoPrism UG („PhotoPrism“). We
reserve the right to object to any use or misuse in any jurisdiction
worldwide. Visit <https://www.photoprism.app/trademark> to learn more.
worldwide. Visit <https://www.photoprism.app/trademark/> to learn more.
(b) Contributors, licensees, business partners, and other third parties
may never claim ownership of PhotoPrism's Brand Assets or brands confusingly

556
Makefile
View file

@ -1,23 +1,31 @@
# Copyright © 2018 - 2025 PhotoPrism UG. All rights reserved.
# Copyright © 2018 - 2026 PhotoPrism UG. All rights reserved.
#
# Questions? Email us at hello@photoprism.app or visit our website to learn
# more about our team, products and services: https://www.photoprism.app/
export GO111MODULE=on
export NPM_CONFIG_IGNORE_SCRIPTS ?= true
ifneq (,$(wildcard .telemetry))
include .telemetry
export $(shell sed -n 's/^[[:space:]]*\([A-Z_][A-Z0-9_]*\)=.*/\1/p' .telemetry)
endif
-include .semver
-include .env
export
# Binary file names.
BINARY_NAME=photoprism
GOIMPORTS=goimports
# Build version.
SEMVER_MAJOR ?= 0
# Build version string.
SEMVER_MAJOR ?= 1
export SEMVER_MAJOR
SEMVER_MINOR ?= $(shell date -u +%y%m)
export SEMVER_MINOR
SEMVER_PATCH ?= $(shell date -u +%d)
SEMVER_VERSION ?= $(SEMVER_MAJOR).$(SEMVER_MINOR).$(SEMVER_PATCH)
export SEMVER_VERSION
# Build parameters.
BUILD_PATH ?= $(shell realpath "./build")
@ -25,9 +33,13 @@ BUILD_DATE ?= $(shell date -u +%y%m%d)
REPORT_DATE ?= $(shell date -u +%Y-%m-%d)
BUILD_VERSION ?= $(shell git describe --always)
BUILD_TAG ?= $(BUILD_DATE)-$(BUILD_VERSION)
export BUILD_TAG
BUILD_OS ?= $(shell uname -s)
BUILD_ARCH ?= $(shell scripts/dist/arch.sh)
BUILD_ARCH ?= $(shell ./scripts/dist/arch.sh)
export BUILD_ARCH
JS_BUILD_PATH ?= $(shell realpath "./assets/static/build")
TF_VERSION ?= 2.18.0
WORKING_DIR ?= /go/src/github.com/photoprism/photoprism
# Install parameters.
INSTALL_PATH ?= $(BUILD_PATH)/photoprism-ce_$(BUILD_TAG)-$(shell echo $(BUILD_OS) | tr '[:upper:]' '[:lower:]')-$(BUILD_ARCH)
@ -59,48 +71,74 @@ endif
# Declare "make" targets.
all: dep build-js
dep: dep-tensorflow dep-js
dep: dep-tensorflow dep-onnx dep-js
biuld: build
build: build-go
watch: watch-js
build-all: build-go build-js
pull: docker-pull
test: test-js test-go
test-go: reset-sqlite run-test-go
test-pkg: reset-sqlite run-test-pkg
test-api: reset-sqlite run-test-api
test-entity: reset-sqlite run-test-entity
test-commands: reset-sqlite run-test-commands
test-photoprism: reset-sqlite run-test-photoprism
test-short: reset-sqlite run-test-short
test-go: run-test-go
test-hub: run-test-hub
test-pkg: run-test-pkg
test-ai: run-test-ai
test-api: run-test-api
test-video: run-test-video
test-entity: run-test-entity
test-commands: run-test-commands
test-photoprism: run-test-photoprism
test-short: run-test-short
test-mariadb: reset-acceptance run-test-mariadb
acceptance-run-chromium: storage/acceptance acceptance-auth-sqlite-restart wait acceptance-auth acceptance-auth-sqlite-stop acceptance-sqlite-restart wait-2 acceptance acceptance-sqlite-stop
acceptance-run-chromium-short: storage/acceptance acceptance-auth-sqlite-restart wait acceptance-auth-short acceptance-auth-sqlite-stop acceptance-sqlite-restart wait-2 acceptance-short acceptance-sqlite-stop
acceptance-auth-run-chromium: storage/acceptance acceptance-auth-sqlite-restart wait acceptance-auth acceptance-auth-sqlite-stop
acceptance-public-run-chromium: storage/acceptance acceptance-sqlite-restart wait acceptance acceptance-sqlite-stop
wait:
sleep 20
wait-2:
acceptance-run-chromium: storage/acceptance acceptance-sqlite-restart-1 wait-1 acceptance-api acceptance-sqlite-stop-1 acceptance-auth-sqlite-restart wait-2 acceptance-auth acceptance-auth-sqlite-stop acceptance-sqlite-restart-3 wait-3 acceptance acceptance-sqlite-stop-3
acceptance-run-chromium-short: storage/acceptance acceptance-auth-sqlite-restart wait-1 acceptance-auth-short acceptance-auth-sqlite-stop acceptance-sqlite-restart-2 wait-2 acceptance-short acceptance-sqlite-stop-2
acceptance-auth-run-chromium: storage/acceptance acceptance-auth-sqlite-restart wait-1 acceptance-auth acceptance-auth-sqlite-stop
acceptance-public-run-chromium: storage/acceptance acceptance-sqlite-restart-1 wait-1 acceptance acceptance-sqlite-stop-1
acceptance-api-run-chromium: storage/acceptance acceptance-sqlite-restart-1 wait-1 acceptance-api acceptance-sqlite-stop-1
help: list
list:
@awk '/^[[:alnum:]]+[^[:space:]]+:/ {printf "%s",substr($$1,1,length($$1)-1); if (match($$0,/#/)) {desc=substr($$0,RSTART+1); sub(/^[[:space:]]+/,"",desc); printf " - %s\n",desc} else printf "\n" }' "$(firstword $(MAKEFILE_LIST))"
wait-%:
sleep 20
show-rev:
@git rev-parse HEAD
show-build:
@echo "$(BUILD_TAG)"
tag-release:
scripts/tag-release.sh $(EDITION) $(TAG_ARGS)
test-all: test acceptance-run-chromium
fmt: fmt-js fmt-go swag-fmt
fmt: fmt-js fmt-go fmt-swag
format: format-tables fmt-go fmt-swag
format-tables: # Format Markdown tables in README.md, AGENTS.md, and CODEMAP.md files.
@set -eu; \
tmp="$$(mktemp)"; \
trap 'rm -f "$$tmp"' EXIT INT TERM; \
find "$(CURDIR)" -maxdepth 1 -type f \( -name 'README.md' -o -name 'AGENTS.md' -o -name 'CODEMAP.md' \) -print0 >> "$$tmp"; \
for dir in internal pkg docker setup; do \
if [ -d "$$dir" ]; then \
find "$$dir" -type f \( -name 'README.md' -o -name 'AGENTS.md' -o -name 'CODEMAP.md' \) -print0 >> "$$tmp"; \
fi; \
done; \
if [ ! -s "$$tmp" ]; then \
echo "No markdown files found for table formatting."; \
exit 0; \
fi; \
xargs -0 npx --yes markdown-table-formatter < "$$tmp"
clean-local: clean-local-config clean-local-cache
upgrade: dep-upgrade-js dep-upgrade
devtools: install-go dep-npm
.SILENT: help;
logs:
$(DOCKER_COMPOSE) logs -f
help:
@echo "For build instructions, visit <https://docs.photoprism.app/developer-guide/>."
down: docker-down
docker-down:
$(DOCKER_COMPOSE) --profile=all down --remove-orphans
docs: swag
swag: swag-json
swag-json:
@echo "Generating ./internal/api/swagger.json..."
swag init --ot json --parseDependency --parseDepth 1 --dir internal/api -g api.go -o ./internal/api
@echo "Fixing unstable time.Duration enums in swagger.json..."
@GO111MODULE=on go run scripts/tools/swaggerfix/main.go internal/api/swagger.json || { echo "swaggerfix failed"; exit 1; }
swag-yaml:
@echo "Generating ./internal/api/swagger.yaml..."
swag init --ot yaml --parseDependency --parseDepth 1 --dir internal/api -g api.go -o ./internal/api
@ -127,18 +165,24 @@ notice:
fix-permissions:
$(info Updating filesystem permissions...)
@if [ $(UID) != 0 ]; then\
echo "Running \"chown --preserve-root -Rcf $(UID):$(GID) /go /photoprism /opt/photoprism /tmp/photoprism\". Please wait."; \
sudo chown --preserve-root -Rcf $(UID):$(GID) /go /photoprism /opt/photoprism /tmp/photoprism || true;\
echo "Running \"chmod --preserve-root -Rcf u+rwX /go/src/github.com/photoprism/* /photoprism /opt/photoprism /tmp/photoprism\". Please wait.";\
sudo chmod --preserve-root -Rcf u+rwX /go/src/github.com/photoprism/photoprism/* /photoprism /opt/photoprism /tmp/photoprism || true;\
echo "Running \"chown --preserve-root -Rcf $(UID):$(GID) /go $(WORKING_DIR) /photoprism /opt/photoprism /tmp/photoprism\". Please wait."; \
sudo chown --preserve-root -Rcf $(UID):$(GID) /go $(WORKING_DIR) /photoprism /opt/photoprism /tmp/photoprism || true;\
echo "Running \"chmod --preserve-root -Rcf u+rwX $(WORKING_DIR)/* /photoprism /opt/photoprism /tmp/photoprism\". Please wait.";\
sudo chmod --preserve-root -Rcf u+rwX $(WORKING_DIR)/* /photoprism /opt/photoprism /tmp/photoprism || true;\
echo "Done."; \
else\
echo "Running as root. Nothing to do."; \
fi
gettext-merge:
./scripts/gettext-merge.sh
gettext-extract:
./scripts/gettext-extract.sh
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)
@ -146,10 +190,12 @@ clean:
[ ! -d "frontend/node_modules" ] || rm -rf frontend/node_modules
[ ! -d "$(BUILD_PATH)" ] || rm -rf --preserve-root $(BUILD_PATH)
[ ! -d "$(JS_BUILD_PATH)" ] || rm -rf --preserve-root $(JS_BUILD_PATH)
clean-build:
[ ! -d "$(BUILD_PATH)" ] || rm -rf --preserve-root $(BUILD_PATH)
tar.gz:
$(info Creating tar.gz archives from the directories in "$(BUILD_PATH)"...)
find "$(BUILD_PATH)" -maxdepth 1 -mindepth 1 -type d -name "photoprism*" -exec tar --exclude='.[^/]*' -C {} -czf {}.tar.gz . \;
pkg: pkg-amd64 pkg-arm64 pkg-armv7
pkg: pkg-amd64 pkg-arm64
pkg-amd64:
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" photoprism/develop:jammy make all install tar.gz
pkg-arm64:
@ -161,6 +207,7 @@ install:
@[ ! -d "$(DESTDIR)" ] || (echo "ERROR: Install path '$(DESTDIR)' already exists!"; exit 1)
mkdir --mode=$(INSTALL_MODE) -p $(DESTDIR)
env TMPDIR="$(BUILD_PATH)" ./scripts/dist/install-tensorflow.sh $(DESTDIR)
env TMPDIR="$(BUILD_PATH)" ./scripts/dist/install-onnx.sh $(DESTDIR)
rm -rf --preserve-root $(DESTDIR)/include
(cd $(DESTDIR) && mkdir -p bin lib assets)
./scripts/build.sh prod "$(DESTDIR)/bin/$(BINARY_NAME)"
@ -176,9 +223,11 @@ install-go:
go build -v ./...
install-tensorflow:
sudo scripts/dist/install-tensorflow.sh
install-onnx:
sudo scripts/dist/install-onnx.sh
install-darktable:
sudo scripts/dist/install-darktable.sh
acceptance-sqlite-restart:
acceptance-sqlite-restart-%: acceptance-sqlite-stop-%
cp -f storage/acceptance/backup.db storage/acceptance/index.db
cp -f storage/acceptance/config-sqlite/settingsBackup.yml storage/acceptance/config-sqlite/settings.yml
rm -rf storage/acceptance/sidecar/2020
@ -188,15 +237,15 @@ acceptance-sqlite-restart:
rm -rf storage/acceptance/originals/2011
rm -rf storage/acceptance/originals/2013
rm -rf storage/acceptance/originals/2017
./photoprism --auth-mode="public" -c "./storage/acceptance/config-sqlite" --test start -d
acceptance-sqlite-stop:
./photoprism --auth-mode="public" -c "./storage/acceptance/config-sqlite" --test stop
acceptance-auth-sqlite-restart:
./photoprism --auth-mode="public" -c "./storage/acceptance/config-sqlite" start -d
acceptance-sqlite-stop-%:
./photoprism --auth-mode="public" -c "./storage/acceptance/config-sqlite" stop
acceptance-auth-sqlite-restart: acceptance-auth-sqlite-stop
cp -f storage/acceptance/backup.db storage/acceptance/index.db
cp -f storage/acceptance/config-sqlite/settingsBackup.yml storage/acceptance/config-sqlite/settings.yml
./photoprism --auth-mode="password" -c "./storage/acceptance/config-sqlite" --test start -d
./photoprism --auth-mode="password" -c "./storage/acceptance/config-sqlite" start -d
acceptance-auth-sqlite-stop:
./photoprism --auth-mode="password" -c "./storage/acceptance/config-sqlite" --test stop
./photoprism --auth-mode="password" -c "./storage/acceptance/config-sqlite" stop
start:
./photoprism start -d
stop:
@ -205,6 +254,8 @@ terminal:
$(DOCKER_COMPOSE) exec -u $(UID) photoprism bash
mariadb:
$(DOCKER_COMPOSE) exec mariadb mariadb -uroot -pphotoprism photoprism
mariadb-init:
mariadb < scripts/sql/mariadb-init.sql
root: root-terminal
root-terminal:
$(DOCKER_COMPOSE) exec -u root photoprism bash
@ -228,20 +279,136 @@ clean-local-config:
rm -f $(BUILD_PATH)/config/*
dep-list:
go list -u -m -json all | go-mod-outdated -direct
dep-list-all:
go list -u -m -json all | go-mod-outdated
vuln: audit
audit: audit-frontend audit-backend
audit-frontend: npm-audit
audit-backend: dep-vuln
dep-audit: dep-vuln
dep-vuln:
@echo "Checking Go production dependencies for security vulnerabilities..."
go run golang.org/x/vuln/cmd/govulncheck@latest ./pkg/... ./internal/...
dep-vuln-verbose:
@echo "Conducting verbose security vulnerability checks on Go dependencies..."
go run golang.org/x/vuln/cmd/govulncheck@latest -show verbose -show traces ./pkg/... ./internal/...
dep-vuln-test:
@echo "Checking Go production & test dependencies for security vulnerabilities..."
go run golang.org/x/vuln/cmd/govulncheck@latest -test ./pkg/... ./internal/...
npm: dep-npm npm-version
npm-version:
@echo "📦 Installed npm $$(npm --version)."
dep-npm:
sudo npm install -g npm
dep-js:
(cd frontend && npm ci --no-update-notifier --no-audit)
@echo "Installing NPM package manager..."
@if command -v sudo >/dev/null 2>&1; then \
sudo npm install -g --location=global --ignore-scripts --no-audit --no-fund --no-update-notifier "npm@latest"; \
else \
npm install -g --location=global --ignore-scripts --no-audit --no-fund --no-update-notifier "npm@latest"; \
fi
dep-js: npm-ci
npm-ci:
$(info Clean install of NPM dependencies...)
npm ci --ignore-scripts --no-audit --no-fund --no-update-notifier
npm-install:
$(info Installing NPM dependencies...)
npm install --save --ignore-scripts --no-audit --no-fund --no-update-notifier
npm-update:
$(info Updating NPM dependencies in package.json and package-lock.json...)
npm update --save --package-lock --ignore-scripts --no-audit --no-fund --no-update-notifier
npm-audit:
npm audit --ignore-scripts --no-fund --no-update-notifier
tools: gh claude codex
codex: dep-codex codex-version codex-skills
codex-version:
@echo "🤖 Installed $$(codex --version)."
dep-codex:
@echo "Installing Codex CLI..."
@[ -n "$(CODEX_HOME)" ] && [ "$(CODEX_HOME)" != "/" ] && install -d -m 700 -- "$(CODEX_HOME)" || true
@if command -v sudo >/dev/null 2>&1; then \
sudo npm install -g --location=global --ignore-scripts --no-audit --no-fund --no-update-notifier "@openai/codex@latest"; \
else \
npm install -g --location=global --ignore-scripts --no-audit --no-fund --no-update-notifier "@openai/codex@latest"; \
fi
skills: agents-skills claude-skills
agents-skills: codex-skills
codex-skills:
@if [ -d "specs/.agents/skills" ]; then \
echo "Linking Codex skills from specs/.agents/skills..."; \
install -d -m 755 -- ".agents/skills"; \
for src in specs/.agents/skills/*/; do \
[ -d "$$src" ] || continue; \
name=$$(basename "$$src"); \
link=".agents/skills/$$name"; \
target="../../specs/.agents/skills/$$name"; \
if [ -L "$$link" ] || [ ! -e "$$link" ]; then \
ln -sfn "$$target" "$$link"; \
else \
echo "WARNING: $$link exists and is not a symlink, skipping"; \
fi; \
done; \
else \
echo "No specs/.agents/skills directory found, skipping."; \
fi
gh: dep-gh gh-version
gh-version:
@echo "🐙 Installed $$(gh --version | head -n 1)."
dep-gh:
@echo "Installing GitHub CLI..."
@if command -v apt-get >/dev/null 2>&1; then \
./scripts/dist/install-gh.sh; \
elif command -v dnf >/dev/null 2>&1; then \
if command -v sudo >/dev/null 2>&1; then \
sudo dnf install -y gh; \
else \
dnf install -y gh; \
fi; \
elif command -v brew >/dev/null 2>&1; then \
brew install gh; \
else \
echo "ERROR: Could not install gh automatically. See https://cli.github.com/"; \
exit 1; \
fi
claude: claude-skills
@[ -n "$(HOME)" ] && [ "$(HOME)" != "/" ] && install -d -m 755 -- "$(HOME)/.local/bin" || true
@[ -n "$(CLAUDE_CONFIG_DIR)" ] && [ "$(CLAUDE_CONFIG_DIR)" != "/" ] && install -d -m 755 -- "$(CLAUDE_CONFIG_DIR)" || true
@if command -v claude >/dev/null 2>&1; then \
echo "Updating Claude Code..."; \
claude update; \
else \
echo "Installing Claude Code..."; \
curl -fsSL https://claude.ai/install.sh | bash; \
fi
claude-skills:
@if [ -d "specs/.claude/skills" ]; then \
echo "Linking Claude Code skills from specs/.claude/skills..."; \
install -d -m 755 -- ".claude/skills"; \
for src in specs/.claude/skills/*/; do \
[ -d "$$src" ] || continue; \
name=$$(basename "$$src"); \
link=".claude/skills/$$name"; \
target="../../specs/.claude/skills/$$name"; \
if [ -L "$$link" ] || [ ! -e "$$link" ]; then \
ln -sfn "$$target" "$$link"; \
else \
echo "WARNING: $$link exists and is not a symlink, skipping"; \
fi; \
done; \
else \
echo "No specs/.claude/skills directory found, skipping."; \
fi
dep-go:
go build -v ./...
dep-upgrade:
go get -u -t ./...
dep-upgrade-js:
(cd frontend && npm update --legacy-peer-deps)
frontend-update:
make -C frontend update
dep-upgrade-js: frontend-update
dep-tensorflow:
scripts/download-facenet.sh
scripts/download-nasnet.sh
scripts/download-nsfw.sh
dep-onnx:
scripts/download-scrfd.sh
dep-acceptance: storage/acceptance
storage/acceptance:
[ -f "./storage/acceptance/index.db" ] || (cd storage && rm -rf acceptance && wget -c https://dl.photoprism.app/qa/acceptance.tar.gz -O - | tar -xz)
@ -253,6 +420,7 @@ zip-nsfw:
(cd assets && zip -r nsfw.zip nsfw -x "*/.*" -x "*/version.txt")
build-js:
(cd frontend && env BUILD_ENV=production NODE_ENV=production npm run build)
(cd frontend && node scripts/precompress.js)
build-go: build-develop
build-develop:
rm -f $(BINARY_NAME)
@ -271,59 +439,94 @@ build-static:
scripts/build.sh static $(BINARY_NAME)
build-libheif: build-libheif-amd64 build-libheif-arm64 build-libheif-armv7
build-libheif-amd64:
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:oracular ./scripts/dist/build-libheif.sh v1.19.5
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:noble ./scripts/dist/build-libheif.sh v1.19.5
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:jammy ./scripts/dist/build-libheif.sh v1.19.5
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:bookworm ./scripts/dist/build-libheif.sh v1.19.5
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:resolute ./scripts/dist/build-libheif.sh v1.23.1
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:questing ./scripts/dist/build-libheif.sh v1.23.1
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:plucky ./scripts/dist/build-libheif.sh v1.23.1
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:noble ./scripts/dist/build-libheif.sh v1.23.1
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:jammy ./scripts/dist/build-libheif.sh v1.23.1
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:bookworm ./scripts/dist/build-libheif.sh v1.23.1
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:trixie ./scripts/dist/build-libheif.sh v1.23.1
build-libheif-arm64:
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:oracular ./scripts/dist/build-libheif.sh v1.19.5
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:noble ./scripts/dist/build-libheif.sh v1.19.5
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:jammy ./scripts/dist/build-libheif.sh v1.19.5
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:bookworm ./scripts/dist/build-libheif.sh v1.19.5
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:resolute ./scripts/dist/build-libheif.sh v1.23.1
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:questing ./scripts/dist/build-libheif.sh v1.23.1
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:plucky ./scripts/dist/build-libheif.sh v1.23.1
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:noble ./scripts/dist/build-libheif.sh v1.23.1
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:jammy ./scripts/dist/build-libheif.sh v1.23.1
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:bookworm ./scripts/dist/build-libheif.sh v1.23.1
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:trixie ./scripts/dist/build-libheif.sh v1.23.1
build-libheif-armv7:
docker run --rm -u $(UID) --platform=arm --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm -e SYSTEM_ARCH=arm photoprism/develop:armv7 ./scripts/dist/build-libheif.sh v1.19.5
docker run --rm -u $(UID) --platform=arm --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm -e SYSTEM_ARCH=arm photoprism/develop:jammy ./scripts/dist/build-libheif.sh v1.19.5
docker run --rm -u $(UID) --platform=arm --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm -e SYSTEM_ARCH=arm photoprism/develop:armv7 ./scripts/dist/build-libheif.sh v1.23.1
build-libheif-latest: build-libheif-amd64-latest build-libheif-arm64-latest build-libheif-armv7-latest
build-libheif-amd64-latest:
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:oracular ./scripts/dist/build-libheif.sh
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:resolute ./scripts/dist/build-libheif.sh
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:questing ./scripts/dist/build-libheif.sh
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:plucky ./scripts/dist/build-libheif.sh
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:noble ./scripts/dist/build-libheif.sh
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:jammy ./scripts/dist/build-libheif.sh
build-libheif-arm64-latest:
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:oracular ./scripts/dist/build-libheif.sh
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:resolute ./scripts/dist/build-libheif.sh
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:questing ./scripts/dist/build-libheif.sh
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:plucky ./scripts/dist/build-libheif.sh
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:noble ./scripts/dist/build-libheif.sh
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:jammy ./scripts/dist/build-libheif.sh
build-libheif-armv7-latest:
docker run --rm -u $(UID) --platform=arm --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm -e SYSTEM_ARCH=arm photoprism/develop:armv7 ./scripts/dist/build-libheif.sh
docker run --rm -u $(UID) --platform=arm --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm -e SYSTEM_ARCH=arm photoprism/develop:jammy ./scripts/dist/build-libheif.sh
build-tensorflow:
docker build -t photoprism/tensorflow:build docker/tensorflow
docker run -ti photoprism/tensorflow:build bash
build-tensorflow-arm64:
docker build -t photoprism/tensorflow:arm64 docker/tensorflow/arm64
docker run -ti photoprism/tensorflow:arm64 bash
build-libheif-deb: build-libheif-deb-amd64 build-libheif-deb-arm64
build-libheif-deb-amd64:
docker run --rm -u $(UID) --platform=amd64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/develop:resolute ./scripts/dist/build-libheif-deb.sh v1.23.1
build-libheif-deb-arm64:
docker run --rm -u $(UID) --platform=arm64 --pull=always -v ".:/go/src/github.com/photoprism/photoprism" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/develop:resolute ./scripts/dist/build-libheif-deb.sh v1.23.1
build-tensorflow: docker-tensorflow-amd64
docker-tensorflow: docker-tensorflow-amd64
docker-tensorflow-amd64:
docker build --pull --no-cache -t photoprism/tensorflow:latest -t photoprism/tensorflow:amd64 -t photoprism/tensorflow:$(TF_VERSION)-amd64 --build-arg TF_VERSION=$(TF_VERSION) docker/tensorflow
terminal-tensorflow: terminal-tensorflow-amd64
terminal-tensorflow-amd64:
mkdir -p ./build
docker run --rm --pull missing -ti --platform=amd64 -v "./build:/build" -e BUILD_ARCH=amd64 -e SYSTEM_ARCH=amd64 photoprism/tensorflow:amd64 bash
build-tensorflow-arm64: docker-tensorflow-arm64
docker-tensorflow-arm64:
docker build --pull --no-cache -t photoprism/tensorflow:arm64 -t photoprism/tensorflow:$(TF_VERSION)-arm64 --build-arg TF_VERSION=$(TF_VERSION) docker/tensorflow/arm64
terminal-tensorflow-arm64:
mkdir -p ./build
docker run --rm --pull missing -ti --platform=arm64 -v "./build:/build" -e BUILD_ARCH=arm64 -e SYSTEM_ARCH=arm64 photoprism/tensorflow:arm64 bash
build-setup: build-setup-nas-raspberry-pi
build-setup-nas-raspberry-pi:
./scripts/setup/nas/raspberry-pi/build.sh
watch-js:
(cd frontend && node scripts/precompress.js --clean)
(cd frontend && env BUILD_ENV=development NODE_ENV=production npm run watch)
test-js:
$(info Running JS unit tests...)
(cd frontend && env TZ=UTC BUILD_ENV=development NODE_ENV=development BABEL_ENV=test npm run test)
(cd frontend && npm run test)
acceptance:
$(info Running public-mode tests in Chrome...)
(cd frontend && npm run testcafe -- "chrome --headless=new" --test-grep "^(Multi-Window)\:*" --test-meta mode=public --config-file ./testcaferc.json --experimental-multiple-windows "tests/acceptance" && npm run testcafe -- "chrome --headless=new" --test-grep "^(Common|Core)\:*" --test-meta mode=public --config-file ./testcaferc.json "tests/acceptance")
(cd frontend && find ./tests/acceptance -type f -name "*.js" | xargs -i perl -0777 -ne 'while(/(?:mode: \"auth[^,]*\,)|(Multi-Window\:[A-Za-z 0-9\-_]*)/g){print "$$1\n" if ($$1);}' {} | xargs -I testname bash -c 'npm run testcafe -- "chrome --headless=new --use-gl=angle --use-angle=swiftshader --disable-features=LocalNetworkAccessChecks" --experimental-multiple-windows --test-meta mode=public --config-file ./.testcaferc.cjs --test "testname" "tests/acceptance"')
(cd frontend && npm run testcafe -- "chrome --headless=new --use-gl=angle --use-angle=swiftshader --disable-features=LocalNetworkAccessChecks" --test-grep "^(Common|Core)\:*" --test-meta mode=public --config-file ./.testcaferc.cjs "tests/acceptance")
acceptance-short:
$(info Running JS acceptance tests in Chrome...)
(cd frontend && npm run testcafe -- "chrome --headless=new" --test-grep "^(Multi-Window)\:*" --test-meta mode=public --config-file ./testcaferc.json --experimental-multiple-windows "tests/acceptance" && npm run testcafe -- "chrome --headless=new" --test-grep "^(Common|Core)\:*" --test-meta mode=public,type=short --config-file ./testcaferc.json "tests/acceptance")
acceptance-firefox:
$(info Running JS acceptance tests in Firefox...)
(cd frontend && npm run testcafe -- firefox:headless --test-grep "^(Common|Core)\:*" --test-meta mode=public --config-file ./testcaferc.json --disable-native-automation "tests/acceptance")
(cd frontend && find ./tests/acceptance -type f -name "*.js" | xargs -i perl -0777 -ne 'while(/(?:mode: \"auth[^,]*\,)|(Multi-Window\:[A-Za-z 0-9\-_]*)/g){print "$$1\n" if ($$1);}' {} | xargs -I testname bash -c 'npm run testcafe -- "chrome --headless=new --use-gl=angle --use-angle=swiftshader --disable-features=LocalNetworkAccessChecks" --experimental-multiple-windows --test-meta mode=public,type=short --config-file ./.testcaferc.cjs --test "testname" "tests/acceptance"')
(cd frontend && npm run testcafe -- "chrome --headless=new --use-gl=angle --use-angle=swiftshader --disable-features=LocalNetworkAccessChecks" --test-grep "^(Common|Core)\:*" --test-meta mode=public,type=short --config-file ./.testcaferc.cjs "tests/acceptance")
acceptance-auth:
$(info Running JS acceptance-auth tests in Chrome...)
(cd frontend && npm run testcafe -- "chrome --headless=new" --test-grep "^(Multi-Window)\:*" --test-meta mode=auth --config-file ./testcaferc.json --experimental-multiple-windows "tests/acceptance" && npm run testcafe -- "chrome --headless=new" --test-grep "^(Common|Core)\:*" --test-meta mode=auth --config-file ./testcaferc.json "tests/acceptance")
(cd frontend && find ./tests/acceptance -type f -name "*.js" | xargs -i perl -0777 -ne 'while(/(?:mode: \"public[^,]*\,)|(Multi-Window\:[A-Za-z 0-9\-_]*)/g){print "$$1\n" if ($$1);}' {} | xargs -I testname bash -c 'npm run testcafe -- "chrome --headless=new --use-gl=angle --use-angle=swiftshader --disable-features=LocalNetworkAccessChecks" --experimental-multiple-windows --test-meta mode=auth --config-file ./.testcaferc.cjs --test "testname" "tests/acceptance"')
(cd frontend && npm run testcafe -- "chrome --headless=new --use-gl=angle --use-angle=swiftshader --disable-features=LocalNetworkAccessChecks" --test-grep "^(Common|Core)\:*" --test-meta mode=auth --config-file ./.testcaferc.cjs "tests/acceptance")
acceptance-auth-short:
$(info Running JS acceptance-auth tests in Chrome...)
(cd frontend && npm run testcafe -- "chrome --headless=new" --test-grep "^(Multi-Window)\:*" --test-meta mode=auth --config-file ./testcaferc.json --experimental-multiple-windows "tests/acceptance" && npm run testcafe -- "chrome --headless=new" --test-grep "^(Common|Core)\:*" --test-meta mode=auth,type=short --config-file ./testcaferc.json "tests/acceptance")
acceptance-auth-firefox:
$(info Running JS acceptance-auth tests in Firefox...)
(cd frontend && npm run testcafe -- firefox:headless --test-grep "^(Common|Core)\:*" --test-meta mode=auth --config-file ./testcaferc.json --disable-native-automation "tests/acceptance")
(cd frontend && find ./tests/acceptance -type f -name "*.js" | xargs -i perl -0777 -ne 'while(/(?:mode: \"public[^,]*\,)|(Multi-Window\:[A-Za-z 0-9\-_]*)/g){print "$$1\n" if ($$1);}' {} | xargs -I testname bash -c 'npm run testcafe -- "chrome --headless=new --use-gl=angle --use-angle=swiftshader --disable-features=LocalNetworkAccessChecks" --experimental-multiple-windows --test-meta mode=auth,type=short --config-file ./.testcaferc.cjs --test "testname" "tests/acceptance"')
(cd frontend && npm run testcafe -- "chrome --headless=new --use-gl=angle --use-angle=swiftshader --disable-features=LocalNetworkAccessChecks" --test-grep "^(Common|Core)\:*" --test-meta mode=auth,type=short --config-file ./.testcaferc.cjs "tests/acceptance")
acceptance-api:
$(info Running JS acceptance-api tests in Chrome...)
(cd frontend && npm run testcafe -- "chrome --headless=new --use-gl=angle --use-angle=swiftshader --disable-features=LocalNetworkAccessChecks" --test-meta mode=api --config-file ./.testcaferc.cjs "tests/acceptance")
vitest-watch:
$(info Running Vitest unit tests in watch mode...)
(cd frontend && npm run test-watch)
vitest-coverage:
$(info Running Vitest unit tests with coverage...)
(cd frontend && npm run test-coverage)
vitest-component:
$(info Running Vitest component tests...)
(cd frontend && npm run test-component)
reset-mariadb:
$(info Resetting photoprism database...)
mysql < scripts/sql/reset-photoprism.sql
@ -336,27 +539,36 @@ reset-mariadb-local:
reset-mariadb-acceptance:
$(info Resetting acceptance database...)
mysql < scripts/sql/reset-acceptance.sql
reset-mariadb-all: reset-mariadb-testdb reset-mariadb-local reset-mariadb-acceptance reset-mariadb-photoprism
reset-mariadb-all: reset-mariadb-testdb reset-mariadb-local reset-mariadb-acceptance
reset-testdb: reset-sqlite reset-mariadb-testdb
reset-acceptance: reset-mariadb-acceptance
reset-sqlite:
$(info Removing test database files...)
find ./internal -type f -name ".test.*" -delete
find ./internal -type f \( -iname '.*.db' -o -iname '.*.db-journal' -o -iname '.test.*' \) -delete
run-test-short:
$(info Running short Go tests in parallel mode...)
$(GOTEST) -parallel 2 -count 1 -cpu 2 -short -timeout 5m ./pkg/... ./internal/...
$(GOTEST) -parallel 2 -count 1 -cpu 2 -short -timeout 5m ./pkg/... ./internal/... ./.../internal/...
run-test-go:
$(info Running all Go tests...)
$(GOTEST) -parallel 1 -count 1 -cpu 1 -tags="slow,develop" -timeout 20m ./pkg/... ./internal/...
$(GOTEST) -parallel 1 -count 1 -cpu 1 -tags="slow,develop" -timeout 20m ./pkg/... ./internal/... ./.../internal/...
run-test-hub:
$(info Running all Go tests with hub requests...)
env PHOTOPRISM_TEST_HUB="true" $(GOTEST) -parallel 1 -count 1 -cpu 1 -tags="slow,develop,debug" -timeout 20m ./pkg/... ./internal/...
run-test-mariadb:
$(info Running all Go tests on MariaDB...)
PHOTOPRISM_TEST_DRIVER="mysql" PHOTOPRISM_TEST_DSN="root:photoprism@tcp(mariadb:4001)/acceptance?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true" $(GOTEST) -parallel 1 -count 1 -cpu 1 -tags="slow,develop" -timeout 20m ./pkg/... ./internal/...
PHOTOPRISM_TEST_DRIVER="mysql" PHOTOPRISM_TEST_DSN="root:photoprism@tcp(mariadb:$${MARIADB_PORT:-4001})/acceptance?charset=utf8mb4,utf8&collation=utf8mb4_unicode_ci&parseTime=true" $(GOTEST) -parallel 1 -count 1 -cpu 1 -tags="slow,develop" -timeout 20m ./pkg/... ./internal/...
run-test-pkg:
$(info Running all Go tests in "/pkg"...)
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./pkg/...
run-test-ai:
$(info Running all AI tests...)
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./internal/ai/...
run-test-api:
$(info Running all API tests...)
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./internal/api/...
run-test-video:
$(info Running all video tests...)
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./internal/ffmpeg/... ./internal/photoprism/dl/... ./pkg/media/...
run-test-entity:
$(info Running all Entity tests...)
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./internal/entity/...
@ -368,49 +580,88 @@ run-test-photoprism:
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./internal/photoprism/...
test-parallel:
$(info Running all Go tests in parallel mode...)
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./pkg/... ./internal/...
$(GOTEST) -parallel 2 -count 1 -cpu 2 -tags="slow,develop" -timeout 20m ./pkg/... ./internal/... ./.../internal/...
test-verbose:
$(info Running all Go tests in verbose mode...)
$(GOTEST) -parallel 1 -count 1 -cpu 1 -tags="slow,develop" -timeout 20m -v ./pkg/... ./internal/...
$(GOTEST) -parallel 1 -count 1 -cpu 1 -tags="slow,develop" -timeout 20m -v ./pkg/... ./internal/... ./.../internal/...
test-race:
$(info Running all Go tests with race detection in verbose mode...)
$(GOTEST) -tags="slow,develop" -race -timeout 60m -v ./pkg/... ./internal/...
$(GOTEST) -tags="slow,develop" -race -timeout 60m -v ./pkg/... ./internal/... ./.../internal/...
test-coverage:
$(info Running all Go tests with code coverage report...)
go test -parallel 1 -count 1 -cpu 1 -failfast -tags="slow,develop" -timeout 30m -coverprofile coverage.txt -covermode atomic ./pkg/... ./internal/...
go test -parallel 1 -count 1 -cpu 1 -failfast -tags="slow,develop" -timeout 30m -coverprofile coverage.txt -covermode atomic ./pkg/... ./internal/... ./.../internal/...
go tool cover -html=coverage.txt -o coverage.html
go tool cover -func coverage.txt | grep total:
git-pull:
@echo "Pulling changes from remote repositories..."; \
if [ -d .git ]; then \
echo "Updating photoprism"; \
git pull --ff-only || echo "Warning: git pull failed in root"; \
else \
echo "Skipping: current directory is not a Git repo"; \
fi; \
for d in */ ; do \
[ -d "$$d" ] || continue; \
[ -d "$$d/.git" ] || continue; \
echo "Updating photoprism/$$d"; \
git -C "$$d" pull --ff-only || echo "Warning: git pull failed in $$d"; \
done;
docker-pull:
$(DOCKER_COMPOSE) --profile=all pull --ignore-pull-failures
$(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
docker-local-up:
$(DOCKER_COMPOSE) -f compose.local.yaml up --force-recreate
docker-local-down:
$(DOCKER_COMPOSE) -f compose.local.yaml down -V
nvidia: nvidia-up
nvidia-build:
$(DOCKER_COMPOSE) --profile=qdrant -f compose.nvidia.yaml pull --ignore-pull-failures
$(DOCKER_COMPOSE) --profile=qdrant -f compose.nvidia.yaml build
nvidia-up:
$(DOCKER_COMPOSE) --profile=qdrant -f compose.nvidia.yaml pull --ignore-pull-failures
$(DOCKER_COMPOSE) --profile=qdrant -f compose.nvidia.yaml up --remove-orphans
nvidia-down:
$(DOCKER_COMPOSE) --profile=qdrant -f compose.nvidia.yaml down --remove-orphans
intel: intel-up
intel-build:
$(DOCKER_COMPOSE) -f compose.intel.yaml pull --ignore-pull-failures
$(DOCKER_COMPOSE) -f compose.intel.yaml build
intel-up:
$(DOCKER_COMPOSE) -f compose.intel.yaml pull --ignore-pull-failures
$(DOCKER_COMPOSE) -f compose.intel.yaml up --remove-orphans
intel-down:
$(DOCKER_COMPOSE) -f compose.intel.yaml down --remove-orphans
develop: docker-develop
docker-develop: docker-develop-latest
docker-develop-all: docker-develop-latest docker-develop-other
docker-develop-latest: docker-develop-ubuntu
docker-develop-debian: docker-develop-bookworm docker-develop-bookworm-slim
docker-develop-ubuntu: docker-develop-oracular docker-develop-oracular-slim
docker-develop-ubuntu: docker-develop-resolute docker-develop-resolute-slim
docker-develop-legacy: docker-develop-jammy docker-develop-jammy-slim
docker-develop-other: docker-develop-debian docker-develop-bullseye docker-develop-bullseye-slim docker-develop-buster
docker-develop-bookworm:
docker pull --platform=amd64 debian:bookworm-slim
docker pull --platform=arm64 debian:bookworm-slim
docker pull --platform=arm debian:bookworm-slim
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64,linux/arm bookworm /bookworm "-t photoprism/develop:debian"
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 bookworm /bookworm "-t photoprism/develop:debian"
docker-develop-bookworm-slim:
docker pull --platform=amd64 debian:bookworm-slim
docker pull --platform=arm64 debian:bookworm-slim
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 bookworm-slim /bookworm-slim
docker-develop-trixie:
docker pull --platform=amd64 debian:trixie-slim
docker pull --platform=arm64 debian:trixie-slim
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 trixie /trixie
docker-develop-trixie-slim:
docker pull --platform=amd64 debian:trixie-slim
docker pull --platform=arm64 debian:trixie-slim
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 trixie-slim /trixie-slim
docker-develop-bullseye:
docker pull --platform=amd64 golang:1-bullseye
docker pull --platform=arm64 golang:1-bullseye
docker pull --platform=arm golang:1-bullseye
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64,linux/arm bullseye /bullseye
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 bullseye /bullseye
docker-develop-bullseye-slim:
docker pull --platform=amd64 debian:bullseye-slim
docker pull --platform=arm64 debian:bullseye-slim
@ -430,8 +681,7 @@ docker-develop-impish:
docker-develop-jammy:
docker pull --platform=amd64 ubuntu:jammy
docker pull --platform=arm64 ubuntu:jammy
docker pull --platform=arm ubuntu:jammy
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64,linux/arm jammy /jammy
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 jammy /jammy
docker-develop-jammy-slim:
docker pull --platform=amd64 ubuntu:jammy
docker pull --platform=arm64 ubuntu:jammy
@ -463,11 +713,35 @@ docker-develop-noble-slim:
docker-develop-oracular:
docker pull --platform=amd64 ubuntu:oracular
docker pull --platform=arm64 ubuntu:oracular
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 oracular /oracular "-t photoprism/develop:latest -t photoprism/develop:ubuntu"
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 oracular /oracular
docker-develop-oracular-slim:
docker pull --platform=amd64 ubuntu:oracular
docker pull --platform=arm64 ubuntu:oracular
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 oracular-slim /oracular-slim
docker-develop-plucky:
docker pull --platform=amd64 ubuntu:plucky
docker pull --platform=arm64 ubuntu:plucky
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 plucky /plucky
docker-develop-plucky-slim:
docker pull --platform=amd64 ubuntu:plucky
docker pull --platform=arm64 ubuntu:plucky
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 plucky-slim /plucky-slim
docker-develop-questing:
docker pull --platform=amd64 ubuntu:questing
docker pull --platform=arm64 ubuntu:questing
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 questing /questing
docker-develop-questing-slim:
docker pull --platform=amd64 ubuntu:questing
docker pull --platform=arm64 ubuntu:questing
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 questing-slim /questing-slim
docker-develop-resolute:
docker pull --platform=amd64 ubuntu:resolute
docker pull --platform=arm64 ubuntu:resolute
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 resolute /resolute "-t photoprism/develop:latest -t photoprism/develop:ubuntu"
docker-develop-resolute-slim:
docker pull --platform=amd64 ubuntu:resolute
docker pull --platform=arm64 ubuntu:resolute
scripts/docker/buildx-multi.sh develop linux/amd64,linux/arm64 resolute-slim /resolute-slim
unstable: docker-unstable
docker-unstable: docker-unstable-mantic
docker-unstable-jammy:
@ -485,10 +759,10 @@ docker-unstable-mantic:
preview: docker-preview-ce
docker-preview: docker-preview-ce
docker-preview-all: docker-preview-latest docker-preview-other
docker-preview-ce: docker-preview-oracular
docker-preview-ce: docker-preview-resolute
docker-preview-latest: docker-preview-ubuntu
docker-preview-debian: docker-preview-bookworm
docker-preview-ubuntu: docker-preview-oracular
docker-preview-ubuntu: docker-preview-resolute
docker-preview-other: docker-preview-debian docker-preview-bullseye
docker-preview-arm: docker-preview-arm64 docker-preview-armv7
docker-preview-bookworm:
@ -553,12 +827,30 @@ docker-preview-oracular:
docker pull --platform=arm64 photoprism/develop:oracular
docker pull --platform=arm64 photoprism/develop:oracular-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 preview-ce /oracular
docker-preview-plucky:
docker pull --platform=amd64 photoprism/develop:plucky
docker pull --platform=amd64 photoprism/develop:plucky-slim
docker pull --platform=arm64 photoprism/develop:plucky
docker pull --platform=arm64 photoprism/develop:plucky-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 preview-ce /plucky
docker-preview-questing:
docker pull --platform=amd64 photoprism/develop:questing
docker pull --platform=amd64 photoprism/develop:questing-slim
docker pull --platform=arm64 photoprism/develop:questing
docker pull --platform=arm64 photoprism/develop:questing-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 preview-questing /questing
docker-preview-resolute:
docker pull --platform=amd64 photoprism/develop:resolute
docker pull --platform=amd64 photoprism/develop:resolute-slim
docker pull --platform=arm64 photoprism/develop:resolute
docker pull --platform=arm64 photoprism/develop:resolute-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 preview-ce /resolute
release: docker-release
docker-release: docker-release-latest
docker-release-all: docker-release-latest docker-release-other
docker-release-latest: docker-release-ubuntu
docker-release-debian: docker-release-bookworm
docker-release-ubuntu: docker-release-oracular
docker-release-ubuntu: docker-release-resolute
docker-release-other: docker-release-debian docker-release-bullseye
docker-release-arm: docker-release-arm64 docker-release-armv7
docker-release-bookworm:
@ -623,6 +915,28 @@ docker-release-oracular:
docker pull --platform=arm64 photoprism/develop:oracular
docker pull --platform=arm64 photoprism/develop:oracular-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 ce /oracular
docker-release-plucky:
docker pull --platform=amd64 photoprism/develop:plucky
docker pull --platform=amd64 photoprism/develop:plucky-slim
docker pull --platform=arm64 photoprism/develop:plucky
docker pull --platform=arm64 photoprism/develop:plucky-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 ce /plucky
docker-release-questing:
docker pull --platform=amd64 photoprism/develop:questing
docker pull --platform=amd64 photoprism/develop:questing-slim
docker pull --platform=arm64 photoprism/develop:questing
docker pull --platform=arm64 photoprism/develop:questing-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 ce-questing /questing
docker-release-resolute:
docker pull --platform=amd64 photoprism/develop:resolute
docker pull --platform=amd64 photoprism/develop:resolute-slim
docker pull --platform=arm64 photoprism/develop:resolute
docker pull --platform=arm64 photoprism/develop:resolute-slim
scripts/docker/buildx-multi.sh photoprism linux/amd64,linux/arm64 ce /resolute
start-traefik:
$(DOCKER_COMPOSE) up -d --wait traefik
stop-traefik:
$(DOCKER_COMPOSE) down traefik
start-local:
$(DOCKER_COMPOSE) -f compose.local.yaml up -d --wait
stop-local:
@ -665,12 +979,20 @@ terminal-preview:
$(DOCKER_COMPOSE) -f compose.preview.yaml exec photoprism-preview bash
logs-preview:
$(DOCKER_COMPOSE) -f compose.preview.yaml logs -f photoprism-preview
docker-local: docker-local-oracular
docker-local-all: docker-local-oracular docker-local-noble docker-local-mantic docker-local-lunar docker-local-jammy docker-local-bookworm docker-local-bullseye docker-local-buster
docker-local: docker-local-resolute
docker-local-up:
$(DOCKER_COMPOSE) -f compose.local.yaml up --force-recreate
docker-local-down:
$(DOCKER_COMPOSE) -f compose.local.yaml down --remove-orphans
docker-local-all: docker-local-resolute docker-local-questing docker-local-plucky docker-local-oracular docker-local-noble docker-local-mantic docker-local-lunar docker-local-jammy docker-local-bookworm docker-local-bullseye docker-local-buster
docker-local-bookworm:
docker pull photoprism/develop:bookworm
docker pull photoprism/develop:bookworm-slim
scripts/docker/build.sh photoprism ce-bookworm /bookworm "-t photoprism/photoprism:local"
docker-local-trixie:
docker pull photoprism/develop:trixie
docker pull debian:trixie-slim
scripts/docker/build.sh photoprism ce-trixie /trixie "-t photoprism/photoprism:local"
docker-local-bullseye:
docker pull photoprism/develop:bullseye
docker pull photoprism/develop:bullseye-slim
@ -703,12 +1025,27 @@ docker-local-oracular:
docker pull photoprism/develop:oracular
docker pull ubuntu:oracular
scripts/docker/build.sh photoprism ce-oracular /oracular "-t photoprism/photoprism:local"
docker-local-questing:
docker pull photoprism/develop:questing
docker pull ubuntu:questing
scripts/docker/build.sh photoprism ce-questing /questing "-t photoprism/photoprism:local"
docker-local-plucky:
docker pull photoprism/develop:plucky
docker pull ubuntu:plucky
scripts/docker/build.sh photoprism ce-plucky /plucky "-t photoprism/photoprism:local"
docker-local-resolute:
docker pull photoprism/develop:resolute
docker pull ubuntu:resolute
scripts/docker/build.sh photoprism ce-resolute /resolute "-t photoprism/photoprism:local"
local-develop: docker-local-develop
docker-local-develop: docker-local-develop-oracular
docker-local-develop-all: docker-local-develop-oracular docker-local-develop-noble docker-local-develop-mantic docker-local-develop-lunar docker-local-develop-jammy docker-local-develop-bookworm docker-local-develop-bullseye docker-local-develop-buster docker-local-develop-impish
docker-local-develop: docker-local-develop-resolute
docker-local-develop-all: docker-local-develop-resolute docker-local-develop-questing docker-local-develop-oracular docker-local-develop-noble docker-local-develop-mantic docker-local-develop-lunar docker-local-develop-jammy docker-local-develop-bookworm docker-local-develop-bullseye docker-local-develop-buster docker-local-develop-impish
docker-local-develop-bookworm:
docker pull debian:bookworm-slim
scripts/docker/build.sh develop bookworm /bookworm
docker-local-develop-trixie:
docker pull debian:trixie-slim
scripts/docker/build.sh develop trixie /trixie
docker-local-develop-bullseye:
docker pull golang:1-bullseye
scripts/docker/build.sh develop bullseye /bullseye
@ -733,12 +1070,18 @@ docker-local-develop-noble:
docker-local-develop-oracular:
docker pull ubuntu:oracular
scripts/docker/build.sh develop oracular /oracular
docker-local-develop-questing:
docker pull ubuntu:questing
scripts/docker/build.sh develop questing /questing
docker-local-develop-plucky:
docker pull ubuntu:plucky
scripts/docker/build.sh develop plucky /plucky
docker-local-develop-resolute:
docker pull ubuntu:resolute
scripts/docker/build.sh develop resolute /resolute
docker-ddns:
docker pull golang:alpine
scripts/docker/buildx-multi.sh ddns linux/amd64,linux/arm64 $(BUILD_DATE)
docker-goproxy:
docker pull golang:alpine
scripts/docker/buildx-multi.sh goproxy linux/amd64,linux/arm64 $(BUILD_DATE)
demo: docker-demo
docker-demo: docker-demo-latest
docker-demo-all: docker-demo-latest docker-demo-debian
@ -773,14 +1116,23 @@ docker-dummy-oidc:
packer-digitalocean:
$(info Buildinng DigitalOcean marketplace image...)
(cd ./setup/docker/cloud && packer build digitalocean.json)
lint: lint-js lint-go check-api-request-limits
lint-js:
(cd frontend && npm run lint)
$(info Linting JS code...)
$(MAKE) -C frontend lint
lint-go:
$(info Linting Go code...)
golangci-lint run --issues-exit-code 0 ./pkg/... ./internal/... ./.../internal/...
check-api-request-limits:
$(info Checking API request-body limits...)
bash ./scripts/check-api-request-limits.sh
fmt-js:
(cd frontend && npm run fmt)
fmt-go:
go fmt ./pkg/... ./internal/... ./cmd/...
go fmt ./pkg/... ./internal/... ./cmd/... ./.../internal/...
gofmt -w -s pkg internal cmd
goimports -w -local "github.com/photoprism" pkg internal cmd
fmt-swag: swag-fmt
tidy:
go mod tidy
users:

3153
NOTICE

File diff suppressed because it is too large Load diff

View file

@ -8,11 +8,9 @@ PhotoPrism: Browse Your Life in Pictures
[![Bluesky Social](https://dl.photoprism.app/img/badges/badge-bluesky.svg)](https://bsky.app/profile/photoprism.app)
[![Mastodon](https://dl.photoprism.app/img/badges/badge-floss-social.svg)](https://floss.social/@photoprism)
PhotoPrism® is an AI-Powered Photos App for the [Decentralized Web](https://en.wikipedia.org/wiki/Decentralized_web).
It makes use of the latest technologies to tag and find pictures automatically without getting in your way.
You can run it at home, on a private server, or in the cloud.
PhotoPrism® is an AI-powered, privacy-first app for browsing, organizing, and sharing photos and videos. It helps tag, search, and rediscover media without getting in your way, whether self-hosted or in the cloud.
![](https://dl.photoprism.app/img/ui/search-cards-view.jpg)
![](https://dl.photoprism.app/img/ui/2025/desktop-search.jpg)
To get a first impression, you are welcome to play with our [public demo](https://try.photoprism.app/). Please be careful not to upload any private, unlawful or offensive pictures.
@ -20,23 +18,21 @@ To get a first impression, you are welcome to play with our [public demo](https:
**Our mission is to provide the most user- and privacy-friendly solution to keep your pictures organized and accessible.** That's why PhotoPrism was built from the ground up to run wherever you need it, without compromising freedom, privacy, or functionality:
* Browse [all your photos](https://docs.photoprism.app/user-guide/organize/browse/) and [videos](https://try.photoprism.app/library/videos) without worrying about [RAW conversion, duplicates or video formats](https://docs.photoprism.app/user-guide/settings/library/)
* Easily find specific pictures using [powerful search filters](https://try.photoprism.app/library/browse?view=cards&q=flower%20color%3Ared)
* Recognizes [the faces of your family and friends](https://try.photoprism.app/library/people)
* [Automatic classification](https://try.photoprism.app/library/labels) of pictures based on their content and location
* [Play Live Photos](https://try.photoprism.app/library/live) by hovering over them in [albums](https://try.photoprism.app/library/albums) and [search results](https://try.photoprism.app/library/browse?view=cards&q=type%3Alive)
* Since the [User Interface](https://try.photoprism.app/) is a [Progressive Web App](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps),
it provides a native app-like experience, and you can conveniently install it on the home screen of all major operating systems and mobile devices
* Includes four high-resolution [World Maps](https://try.photoprism.app/library/places) to bring back the memories of your favorite trips
* Metadata is extracted and merged from Exif, XMP, and other sources such as Google Photos
* Many more image properties like [Colors](https://try.photoprism.app/library/browse?view=cards&q=color:red), [Chroma](https://try.photoprism.app/library/browse?view=cards&q=mono%3Atrue), and [Quality](https://try.photoprism.app/library/review) can be searched as well
* Use [PhotoSync](https://link.photoprism.app/photosync) to securely backup iOS and Android phones in the background
* WebDAV clients such as Microsoft's Windows Explorer and Apple's Finder [can connect directly](https://docs.photoprism.app/user-guide/sync/webdav/) to PhotoPrism, allowing you to open, edit, and delete files from your computer as if they were local
<img align="right" height="270" src="https://dl.photoprism.app/img/ui/2025/iphone-crocus-540px.png">
Being completely [**self-funded and independent**](https://link.photoprism.app/membership), we can promise you that we will [never sell your data](https://www.photoprism.app/privacy) and that we will [always be transparent](https://www.photoprism.app/terms) about our software and services. Your data will never be shared with Google, Amazon, Microsoft or Apple unless you intentionally upload files to one of their services. 🔒
* Browse [all your pictures](https://docs.photoprism.app/user-guide/organize/browse/) without worrying about [RAW images](https://www.photoprism.app/kb/file-formats/) or [video formats](https://docs.photoprism.app/user-guide/organize/video/)
* Whether you're using a phone, tablet, or desktop computer, our [intuitive PWA](https://try.photoprism.app/) provides a native app-like experience and can be [easily installed](https://docs.photoprism.app/user-guide/pwa/) on your home screen
* Quickly find specific photos and videos with [powerful search filters](https://docs.photoprism.app/user-guide/search/filters/) that can be combined and are available for [many different properties](https://docs.photoprism.app/user-guide/search/filters/#filter-reference), including [labels](https://try.photoprism.app/library/labels), [location](https://try.photoprism.app/library/places?q=s2:47a85a63f764), [resolution](https://try.photoprism.app/library/browse?view=cards&q=mp:4), [color](https://try.photoprism.app/library/browse?view=cards&q=color:red), [chroma](https://try.photoprism.app/library/browse?view=cards&q=mono%3Atrue), and [quality](https://try.photoprism.app/library/review)
* [Automatically labels your pictures](https://try.photoprism.app/library/labels) based on content and location, and recognizes the faces of [your family and friends](https://try.photoprism.app/library/people/new)
* [Live Photos](https://try.photoprism.app/library/live) start playing when you [hover over them](https://try.photoprism.app/library/browse?view=cards&q=type%3Alive) and when viewing a slideshow
* Six high-resolution [World Maps](https://try.photoprism.app/library/places) and our [privacy-preserving geocoding service](https://docs.photoprism.app/getting-started/#maps-places) help bring back memories of your favorite trips and let you explore the world
* Metadata can be extracted and merged from Exif, XMP, and other sources like Google Photos
* [Use compatible apps](https://docs.photoprism.app/user-guide/native-apps/) like [PhotoSync](https://link.photoprism.app/photosync) to back up iOS and Android phones in the background
* WebDAV clients such as [Microsoft's Windows Explorer](https://docs.photoprism.app/user-guide/sync/webdav/#__tabbed_1_2) and [Apple's Finder](https://docs.photoprism.app/user-guide/sync/webdav/#connect-to-a-webdav-server) can [connect directly to PhotoPrism](https://docs.photoprism.app/user-guide/sync/webdav/), allowing you to open, edit, and delete files from your computer as if they were local
Being completely [**self-funded and independent**](https://link.photoprism.app/membership), we can promise you that we will [never sell your data](https://www.photoprism.app/privacy/) and that we will [always be transparent](https://www.photoprism.app/terms/) about our software and services. Your data will never be shared with Google, Amazon, Microsoft or Apple unless you intentionally upload files to one of their services. 🔒
## Getting Started ##
<img align="right" width="25%" src="https://www.photoprism.app/user/pages/01.home/03._screenshots/iphone-maps-hybrid-540px.png">
Step-by-step [installation instructions](https://docs.photoprism.app/getting-started/) for our self-hosted [community edition](https://link.photoprism.app/personal-editions) can be found on [docs.photoprism.app](https://docs.photoprism.app/getting-started/) - all you need is a Web browser and [Docker](https://docs.docker.com/get-docker/) to run the server. It is available for Mac, Linux, and Windows.
@ -47,18 +43,18 @@ See our [Getting Started FAQ](https://docs.photoprism.app/getting-started/faq/#h
## Support Our Mission 💎 ##
**PhotoPrism is 100% self-funded and independent.** Your [continued support](https://link.photoprism.app/membership) helps us [provide more features to the public](https://www.photoprism.app/oss/faq#what-functionality-is-generally-available), release [regular updates](https://docs.photoprism.app/release-notes/), and remain independent!
**PhotoPrism is 100% self-funded and independent.** Your [continued support](https://link.photoprism.app/membership) helps us [provide more features to the public](https://www.photoprism.app/oss/faq/#what-functionality-is-generally-available), release [regular updates](https://docs.photoprism.app/release-notes/), and remain independent!
Our members [enjoy additional features](https://www.photoprism.app/kb/personal), including access to [interactive world maps](https://try.photoprism.app/library/places), and can join our private chat room to [connect with our team](https://www.photoprism.app/about/team). We currently have the following membership options:
Our members [enjoy additional features](https://www.photoprism.app/kb/personal/), including access to [interactive world maps](https://try.photoprism.app/library/places), and can join our private chat room to [connect with our team](https://www.photoprism.app/about/team/). We currently have the following membership options:
- You can [sign up directly on our website](https://link.photoprism.app/membership) and pay with credit card or SEPA through Stripe, so you don't need to [link an external account](https://www.photoprism.app/kb/activation) and can easily upgrade or downgrade at any time
- You can [sign up directly on our website](https://link.photoprism.app/membership) and pay with credit card or SEPA through Stripe, so you don't need to [link an external account](https://www.photoprism.app/kb/activation/) and can easily upgrade or downgrade at any time
- Alternatively, [Patreon](https://link.photoprism.app/patreon) also supports PayPal, additional currencies, and lets you choose between monthly and annual billing for all tiers
If you currently support us through [GitHub Sponsors](https://link.photoprism.app/sponsor), you can also [register on our website](https://my.photoprism.app/register) and use the *Activate GitHub Sponsors Membership* button to link your account. For details on this and how to [link your Patreon account](https://www.patreon.com/pledges), see our [Activation Guide](https://www.photoprism.app/kb/activation).
If you currently support us through [GitHub Sponsors](https://link.photoprism.app/sponsor), you can also [register on our website](https://my.photoprism.app/register) and use the *Activate GitHub Sponsors Membership* button to link your account. For details on this and how to [link your Patreon account](https://www.patreon.com/pledges), see our [Activation Guide](https://www.photoprism.app/kb/activation/).
You are [welcome to contact us](https://www.photoprism.app/contact) for change requests, membership questions, and business partnerships.
You are [welcome to contact us](https://www.photoprism.app/contact/) for change requests, membership questions, and business partnerships.
[View Membership FAQ ](https://www.photoprism.app/kb/membership)[Sign Up ](https://link.photoprism.app/membership)
[View Membership FAQ ](https://www.photoprism.app/membership/faq/)[Sign Up ](https://link.photoprism.app/membership)
### Why Your Support Matters ###
@ -79,26 +75,32 @@ Common problems can be quickly diagnosed and solved using our [Troubleshooting C
## Upcoming Features and Enhancements ##
<a href="https://github.com/orgs/photoprism/projects/5"><img align="right" height="240" src="https://dl.photoprism.app/img/ui/2025/upcoming-features-240px.png"></a>
Our [Project Roadmap](https://link.photoprism.app/roadmap) shows what tasks are in progress and what features will be implemented next. You are invited to give ideas you like a thumbs-up, so we know what's most popular.
Be aware that we have a zero-bug policy and do our best to help users when they need support or have other questions. This comes at a price though, as we can't give exact release dates for new features. Our team receives many more requests than can be implemented, so we want to emphasize that we are in no way obligated to implement the features, enhancements, or other changes you request. We do, however, appreciate your feedback and carefully consider all requests.
**Because sustained funding is key to quickly releasing new features, we encourage you to support our mission by [signing up as a sponsor](https://link.photoprism.app/sponsor) or purchasing a [commercial license](https://www.photoprism.app/teams). Ultimately, that's what's best for the product and the community.**
**Because sustained funding is key to quickly releasing new features, we encourage you to support our mission by [signing up for a personal membership](https://link.photoprism.app/membership) or [purchasing a commercial license](https://www.photoprism.app/teams/#compare).**
[Become a Member ](https://link.photoprism.app/membership)
## GitHub Issues ⚠️ ##
We kindly ask you not to report bugs via GitHub Issues **unless you are certain to have found a fully reproducible and previously unreported issue** that must be fixed directly in the app. Thank you for your careful consideration!
- When browsing issues, please note that **our team and all issue subscribers receive an email notification** from GitHub whenever a new comment is added, so these should only be used for sharing important information and not for [discussions, questions](https://github.com/photoprism/photoprism/discussions), or [expressing personal opinions](https://www.photoprism.app/code-of-conduct)
- In order for us to investigate [new bug reports](https://www.photoprism.app/kb/reporting-bugs), they must include **a complete list of steps to reproduce the problem**, the software versions used and information about the environment in which the problem occurred, such as [browser type, browser version, browser plug-ins](https://docs.photoprism.app/getting-started/troubleshooting/browsers/), operating system, [storage type](https://docs.photoprism.app/getting-started/troubleshooting/performance/#storage), [processor type](https://docs.photoprism.app/getting-started/troubleshooting/performance/#server-cpu), and [memory size](https://docs.photoprism.app/getting-started/troubleshooting/performance/#memory)
- [Contact us](https://www.photoprism.app/contact) or [a community member](https://link.photoprism.app/discussions) if you need help, it could be a local configuration problem, or a misunderstanding in how the software works
- When browsing issues, please note that **our team and all issue subscribers receive an email notification** from GitHub whenever a new comment is added, so these should only be used for sharing important information and not for [discussions, questions](https://github.com/photoprism/photoprism/discussions), or [expressing personal opinions](https://www.photoprism.app/code-of-conduct/)
- In order for us to investigate [new bug reports](https://www.photoprism.app/kb/reporting-bugs/), they must include **a complete list of steps to reproduce the problem**, the software versions used and information about the environment in which the problem occurred, such as [browser type, browser version, browser plug-ins](https://docs.photoprism.app/getting-started/troubleshooting/browsers/), operating system, [storage type](https://docs.photoprism.app/getting-started/troubleshooting/performance/#storage), [processor type](https://docs.photoprism.app/getting-started/troubleshooting/performance/#server-cpu), and [memory size](https://docs.photoprism.app/getting-started/troubleshooting/performance/#memory)
- [Contact us](https://www.photoprism.app/contact/) or [a community member](https://link.photoprism.app/discussions) if you need help, it could be a local configuration problem, or a misunderstanding in how the software works
- This gives us the opportunity to [improve our documentation](https://docs.photoprism.app/getting-started/troubleshooting/) and provide best-in-class support instead of dealing with unclear/duplicate bug reports or triggering a flood of notifications by replying to comments
## Connect with the Community ##
Follow us on [Mastodon](https://floss.social/@photoprism), [Bluesky](https://bsky.app/profile/photoprism.app), or join the [Community Chat](https://link.photoprism.app/chat) to get regular updates, connect with other users, and discuss your ideas. Our [Code of Conduct](https://www.photoprism.app/code-of-conduct) explains the "dos and donts" when interacting with other community members.
<a href="https://link.photoprism.app/chat"><img align="right" width="144" height="144" src="https://dl.photoprism.app/img/brands/element-logo.svg"></a>
As a [contributor](CONTRIBUTING.md), you are also welcome to [contact us directly](https://www.photoprism.app/contact) if you have something on your mind that you don't want to discuss publicly. Please note, however, that due to the high volume of emails we receive, our team may be unable to get back to you immediately. We do our best to respond within five business days or less.
Follow us on [Mastodon](https://floss.social/@photoprism), [Bluesky](https://bsky.app/profile/photoprism.app), or join the [Community Chat](https://link.photoprism.app/chat) to get regular updates, connect with other users, and discuss your ideas. Our [Code of Conduct](https://www.photoprism.app/code-of-conduct/) explains the "dos and donts" when interacting with other community members.
As a [contributor](CONTRIBUTING.md), you are also welcome to [contact us directly](https://www.photoprism.app/contact/) if you have something on your mind that you don't want to discuss publicly. Please note, however, that due to the high volume of emails we receive, our team may be unable to get back to you immediately. We do our best to respond within five business days or less.
## Every Contribution Makes a Difference ##
@ -106,4 +108,4 @@ We welcome [contributions](CONTRIBUTING.md) of any kind, including blog posts, t
----
*PhotoPrism® is a [registered trademark](https://www.photoprism.app/trademark). By using the software and services we provide, you agree to our [Terms of Service](https://www.photoprism.app/terms), [Privacy Policy](https://www.photoprism.app/privacy), and [Code of Conduct](https://www.photoprism.app/code-of-conduct). Docs are [available](https://link.photoprism.app/github-docs) under the [CC BY-NC-SA 4.0 License](https://creativecommons.org/licenses/by-nc-sa/4.0/); [additional terms](https://github.com/photoprism/photoprism/blob/develop/assets/README.md) may apply.*
*PhotoPrism® is a [registered trademark](https://www.photoprism.app/trademark/). By using the software and services we provide, you agree to our [Terms of Service](https://www.photoprism.app/terms/), [Privacy Policy](https://www.photoprism.app/privacy/), and [Code of Conduct](https://www.photoprism.app/code-of-conduct/). Docs are [available](https://link.photoprism.app/github-docs) under the [CC BY-NC-SA 4.0 License](https://creativecommons.org/licenses/by-nc-sa/4.0/); [additional terms](https://github.com/photoprism/photoprism/blob/develop/assets/README.md) may apply.*

View file

@ -1,10 +1,10 @@
# Thank You to All Current and Past Sponsors 💎 #
Your [continued support](https://link.photoprism.app/membership) helps us [provide more features to the public](https://www.photoprism.app/oss/faq#what-functionality-is-generally-available), release [regular updates](https://docs.photoprism.app/release-notes/), and remain independent! 💜
Your [continued support](https://link.photoprism.app/membership) helps us [provide more features to the public](https://www.photoprism.app/oss/faq/#what-functionality-is-generally-available), release [regular updates](https://docs.photoprism.app/release-notes/), and remain independent! 💜
You are [welcome to contact us](https://www.photoprism.app/contact) for change requests, membership questions, and business partnerships.
You are [welcome to contact us](https://www.photoprism.app/contact/) for change requests, membership questions, and business partnerships.
[View Membership FAQ ](https://www.photoprism.app/kb/membership)[Contact Us ](https://www.photoprism.app/contact)
[View Membership FAQ ](https://www.photoprism.app/membership/faq/)[Contact Us ](https://www.photoprism.app/contact/)
## Platinum Sponsors ##
@ -24,12 +24,16 @@ You are [welcome to contact us](https://www.photoprism.app/contact) for change r
[**Patrick Kvaksrud**](https://github.com/Kvaksrud) (October 2023)
**Alexander Burke** (November 2023)
[**Lars Kusch**](https://github.com/LarsK1) (December 2023)
**Joseph Hobbs** (November 2024)
**[Andreas Krizek](https://github.com/Cosmic314)** (January 2025)
**[Jason Grim](https://github.com/jgrim)** (June 2025)
## Gold Sponsors ##
[**Simen Eriksen**](https://github.com/dennorske) (GitHub Sponsors, December 2019)
@ -86,6 +90,10 @@ You are [welcome to contact us](https://www.photoprism.app/contact) for change r
[**Kevin "BentoFox" Gelking**](https://github.com/KevinGelking) (Patreon, December 2024)
[**Lukaz**](https://github.com/lukazvprecisn) (Patreon, May 2025)
[**Philipp Marmet**](https://github.com/fujexo) (October 2025)
## Infrastructure Sponsors ##
Our project infrastructure is provided by the following companies:

View file

@ -1,4 +1,6 @@
examples
README.md
Thumbs.db
docs
.*
.*
_*

View file

@ -1,4 +1,4 @@
# Backend Translations
## Backend Translations
PhotoPrism uses [gettext](https://en.wikipedia.org/wiki/Gettext) for localizing frontend and backend.
It's one of the most widely adopted standards for translating user interfaces.
@ -15,6 +15,9 @@ It's source code can be obtained on [GitHub](https://github.com/vslavik/poedit).
Only asynchronous notifications and certain API responses need translation to provide a
consistent user experience.
Asynchronous notifications and user-facing API error responses are additionally rendered by the web
frontend in each user's current UI language (using the message identifier); the `default.po` translation
here serves as a fallback and for non-browser consumers such as the CLI.
Technical log messages should be in English to avoid ambiguities and (even slightly) wrong translations.
`default.po` files in subdirectories contain localized messages for each
@ -29,7 +32,7 @@ the language. Now you can start translating.
When done, create a new directory (using the locale as name) and save your translation there as `default.po`.
The POT file `/assets/locales/messages.pot` will be automatically updated when
running `go generate` in `/internal/i18n` or `make generate` in the main project directory.
running `go generate` in `/pkg/i18n` or `make generate` in the main project directory.
Note that this will only work when you have gettext installed on your system.
We recommend using our latest development image as described in the Developer Guide.

View file

@ -2,403 +2,433 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: none\n"
"Language: af\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Iets het verkeerd geloop, probeer weer"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Kan dit nie doen nie"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Veranderinge kon nie gestoor word nie"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Kan nie verwyder word nie"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s bestaan reeds"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Nie gevind"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Lêer nie gevind nie"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Lêer te groot"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Ongesteun"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Ongesteunde tipe"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Ongesteunde formaat"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Oorspronklike omslag is leeg"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Seleksie nie gevind nie"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entiteit nie gevind nie"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Rekening nie gevind nie"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Verbruiker nie gevind nie"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Merker nie gevind nie"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kamera nie gevind nie"
#: messages.go:130
msgid "Lens not found"
msgstr "Lens nie gevind nie"
#: messages.go:131
msgid "Album not found"
msgstr "Album nie gevind nie"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Onderwerp nie gevind nie"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Persoon nie gevind nie"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Gesig nie gevind nie"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Nie beskikbaar in publieke modus nie"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Nie beskikbaar in leesalleen modus nie"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Teken asseblief in op jou rekening"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Toegang geweier"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Betaling vereis"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Oplegging mag aanstoot gee"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Oplegging misluk"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Geen items gekies nie"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Kon nie lêer skep nie. Gaan asseblief toestemmings na"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Kon nie vouer skep nie. Gaan asseblief toestemmings na"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Kon nie konnekteer nie, probeer asseblief weer"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Tik verifikasiekode"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Ongeldige verifikasiekode, probeer asseblief weer"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Ongeldige wagwoord, probeer asseblief weer"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Eienskap gedeaktiveer"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Geen merker geselekteer"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Geen albums geselekteer nie"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Geen lêers beskikbaar vir aflaai nie"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Kon nie zip-lêer skep nie"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Ongeldige magtiging"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Ongeldige skakel"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Ongeldige naam"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Besig, probeer asseblief later weer"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Die opwek tydperk is %s, maar moet 1 uur of minder wees"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Jou rekening kon nie gekoppel word nie"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Te veel versoeke"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Onvoldoende berging"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kwota oorskry"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registrasie gedeaktiveer"
#: messages.go:164
msgid "Verified email required"
msgstr "Geverifieerde e-pos vereis"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Veranderinge suksesvol gestoor"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album geskep"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album gestoor"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s uitgevee"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Albuminhoud gekloon"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Lêer verwyder uit stapel"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Lêer uitgevee"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Seleksie bygevoeg na %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Een inskrywing bygevoeg na %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d inskrywings by %s gevoeg"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Een inskrywing verwyder uit %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d inskrywings verwyder uit %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Rekening geskep"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Rekening gestoor"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Rekening uitgevee"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Stellings gestoor"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Wagwoord verander"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Invoer voltooi in %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Invoer gekanselleer"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "inhoudsopgawe voltooi in %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indekseer van oorspronklikes …"
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indekseer lêers in %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indeksering gekanselleer"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "%d lêers en %d foto's verwyder"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Skuif lêers van %s af"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Kopieer lêers van %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Merkers uitgevee"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Merkers gestoor"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Onderwerp gestoor"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Onderwerp uitgevee"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Persoon gestoor"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Persoon uitgevee"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Lêer opgelaai"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d lêers opgelaai in %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Verwerk oplegging..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Oplegging geprosesseer"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Seleksie goedgekeur"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Seleksie geargiveer"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Seleksie herstel"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Seleksie gemerk as privaat"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albums uitgevee"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip geskep in %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Permanent uitgevee"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s geherstel"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Suksesvol geverifieer"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Suksesvol geaktiveer"
#~ msgid "Storage is full"
#~ msgstr "Berging is vol"
#~ msgid "Invalid request"
#~ msgstr "Ongeldige versoek"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: none\n"
"Language: ar\n"
"MIME-Version: 1.0\n"
@ -13,392 +13,423 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "حدث خطأ ما حاول مرة أخرى"
msgstr "حدث خطأ ما، حاول مرة أخرى"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "غير قادر على فعل ذلك"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "لا يمكن حفظ التغييرات"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "لا يمكن حذفه"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s موجود بالفعل"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "لم يتم العثور على"
msgstr "لم يتم العثور"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "لم يتم العثور على الملف"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "الملف كبير جدًا"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "غير مدعوم"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "نوع غير معتمد"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "صيغة غير مدعومة"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "مجلد النسخ الأصلية فارغ"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "الاختيار غير موجود"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "الكيان غير موجود"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "الحساب غير موجود"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "المستخدم غير موجود"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "التصنيف غير موجود"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "لم يتم العثور على الكاميرا"
#: messages.go:130
msgid "Lens not found"
msgstr "لم يتم العثور على العدسة"
#: messages.go:131
msgid "Album not found"
msgstr "الألبوم غير موجود"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "الموضوع غير موجود"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "لم يتم العثور على الشخص"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "الوجه غير موجود"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "غير متاح في الوضع العام"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "غير متوفر في وضع القراءة فقط"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "يرجى تسجيل الدخول إلى حسابك"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "طلب الاذن مرفوض"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "الدفع مطلوب"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "تحميل قد يكون مسيئا"
msgstr "المحتوى المرفوع قد يكون مسيئا"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "التحميل فشل"
msgstr "فشل التحميل"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "لم يتم تحديد الاختيار"
msgstr "لم يتم اختيار المحتوى"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "فشل إنشاء الملف ، يرجى التحقق من الأذونات"
msgstr "فشل إنشاء الملف ، يرجى التحقق من الصلاحيات"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "فشل إنشاء المجلد ، يرجى التحقق من الأذونات"
msgstr "لم يتم إنشاء المجلد ، يرجى التحقق من الصلاحيات"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "تعذر الاتصال ، يرجى المحاولة مرة أخرى"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "أدخل رمز التحقق"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "رمز التحقق غير صالح، يرجى المحاولة مرة أخرى"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "كلمة السر غير مطابقة، برجاء حاول مرة أخرى"
msgstr "كلمة السر غير مطابقة، يرجى المحاولة مرة أخرى"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "الخاصية معطلة"
msgstr "الخاصية غير مفعلة"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "لم يتم تحديد تسميات"
msgstr "لم يتم تحديد المعرفات"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "لم يتم تحديد ألبومات"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "لا توجد ملفات متاحة للتنزيل"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "فشل إنشاء ملف مضغوط"
msgstr "فشل في إنشاء ملف مضغوط"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "بيانات الاعتماد غير صالحة"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "ارتباط غير صالح"
msgstr "رابط غير صالح"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "اسم غير صحيح"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "مشغول ، يرجى المحاولة مرة أخرى في وقت لاحق"
msgstr "مشغول، يرجى المحاولة مرة أخرى في وقت لاحق"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "فترة التنبيه هي %s ، لكن يجب أن تكون ساعة واحدة أو أقل"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "لا يمكن ربط حسابك"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "طلبات كثيرة جدا"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "مساحة تخزين غير كافية"
#: messages.go:162
msgid "Quota exceeded"
msgstr "تم تجاوز المساحة المخصصة"
#: messages.go:163
msgid "Registration disabled"
msgstr "تم تعطيل التسجيل"
#: messages.go:164
msgid "Verified email required"
msgstr "البريد الإلكتروني الموثق مطلوب"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "تم حفظ التغييرات بنجاح"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "تم إنشاء الألبوم"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "تم حفظ الألبوم"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "تم حذف الألبوم %s"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "تم نسخ محتويات الألبوم"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "تمت إزالة الملف من المكدس"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "تم حذف الملف"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "تمت إضافة التحديد إلى %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "تمت إضافة إدخال واحد إلى %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "تمت إضافة %d مدخلات إلى %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "تمت إزالة إدخال واحد من %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "تمت إزالة %d مدخلات من %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "تم إنشاء الحساب"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "تم حفظ الحساب"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "تم حذف الحساب"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "تم حفظ الإعدادات"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "تم تغيير كلمة السر"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "اكتمل الاستيراد في %d ثانية"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "تم إلغاء الاستيراد"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "اكتملت الفهرسة في %d ثانية"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "تتم فهرسة الصور الأصلية ..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "فهرسة الملفات في %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "تم إلغاء الفهرسة"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "تمت إزالة %d ملفات و %d صورة"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "نقل الملفات من %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "نسخ ملفات من %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "تم حذف التصنيفات"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "تم حفظ التصنيف"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "تم حفظ الموضوع"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "تم حذف الموضوع"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "حفظ الشخص"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "تم حذف الشخص"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "تم تحميل الملف"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "تم تحميل %d ملف في %d ثانية"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "جارٍ معالجة التحميل ..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "تمت معالجة التحميل"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "تمت الموافقة على الاختيار"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "تمت أرشفة الاختيار"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "تمت استعادة التحديد"
msgstr "تم استعادة المحتوى المحدد"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "تم تحديد الاختيار على أنه خاص"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "تم حذف الألبومات"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "إنشاء الملف المضغوط خلال %d ثوانٍ"
msgstr "تم إنشاء الملف المضغوط خلال %d ثوانٍ"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "تم الحذف بشكل نهائي"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "تمت استعادة %s"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "تم التحقق بنجاح"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "تم التنشيط بنجاح"
msgstr "تم التفعيل بنجاح"
#~ msgid "Storage is full"
#~ msgstr "التخزين ممتلئ"
#~ msgid "Invalid request"
#~ msgstr "طلب غير صالح"

View file

@ -2,10 +2,9 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: none\n"
"Language: be\n"
"MIME-Version: 1.0\n"
@ -13,389 +12,420 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Нешта пайшло не так, паўтарыце спробу"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Немагчыма зрабіць гэта"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Не ўдалося захаваць змены"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Немагчыма выдаліць"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s ужо існуе"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Не знойдзена"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Файл не знойдзены"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Файл занадта вялікі"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Не падтрымліваецца"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Тып не падтрымліваецца"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Фармат не падтрымліваецца"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Тэчка арыгіналаў пустая"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Выбар не знойдзены"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Аб'ект не знойдзены"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Уліковы запіс не знойдзены"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Карыстальнік не знойдзены"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Тэг не знойдзены"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Камера не знойдзена"
#: messages.go:130
msgid "Lens not found"
msgstr "Аб'ектыў не знойдзены"
#: messages.go:131
msgid "Album not found"
msgstr "Альбом не знойдзены"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Тэма не знойдзена"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Чалавек не знойдзены"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Твар не знойдзены"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Недаступна ў публічным рэжыме"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Недаступна ў рэжыме толькі для чытання"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Калі ласка, увайдзіце ў свой уліковы запіс"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "У доступе адмоўлена"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Патрабуецца аплата"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Запампоўка можа быць абразлівай"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Памылка загрузкі"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Элементы не выбраны"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Не ўдалося стварыць файл, праверце дазволы"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Не атрымалася стварыць папку, праверце дазволы"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Немагчыма падключыцца, паспрабуйце яшчэ раз"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Увядзіце праверачны код"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Няправільны код спраўджання, паўтарыце спробу"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Няправільны пароль, паспрабуйце яшчэ раз"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Функцыя адключана"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Меткі не выбраны"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Альбомы не выбраны"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Няма даступных файлаў для спампоўкі"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Не ўдалося стварыць zip-файл"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Няправільныя ўліковыя даныя"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Няправільная спасылка"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Няправільнае імя"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Заняты, паўтарыце спробу пазней"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Інтэрвал абуджэння складае %s, але павінен быць не больш за 1 гадзіну"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Ваш уліковы запіс не можа быць падключаны"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Занадта шмат запытаў"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Недастаткова месца для захоўвання"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Квота перавышана"
#: messages.go:163
msgid "Registration disabled"
msgstr "Рэгістрацыя адключана"
#: messages.go:164
msgid "Verified email required"
msgstr "Патрабуецца правераны адрас электроннай пошты"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Змены паспяхова захаваны"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Альбом створаны"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Альбом захаваны"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Альбом %s выдалены"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Змест альбома кланаваны"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Файл выдалены са стэка"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Файл выдалены"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Выбар дададзены ў %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Адзін запіс дададзены ў %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d запісы дададзены ў %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Адзін запіс выдалены з %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "Запісы %d выдалены з %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Уліковы запіс створаны"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Уліковы запіс захаваны"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Уліковы запіс выдалены"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Налады захаваны"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Пароль зменены"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Імпарт завершаны праз %d с"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Імпарт адменены"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Індэксацыя завершана ў %d с"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Індэксаванне арыгіналаў..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Індэксацыя файлаў у %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Індэксацыя адменена"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Выдалена %d файлаў і %d фота"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Перамяшчэнне файлаў з %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Капіраванне файлаў з %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Меткі выдалены"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Цэтлік захаваны"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Тэма захавана"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Тэма выдалена"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Чалавек выратаваны"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Асоба выдалена"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Файл запампаваны"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d файлы, загружаныя ў %d с"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Апрацоўка запампоўкі..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Загрузка апрацавана"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Выбар ухвалены"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Выбранае заархівавана"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Выбар адноўлены"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Выбар пазначаны як прыватны"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Альбомы выдалены"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip створаны ў %d с"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Выдалены назаўсёды"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s быў адноўлены"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Паспяхова праверана"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Паспяхова актывавана"
#~ msgid "Storage is full"
#~ msgstr "Сховішча запоўнена"

View file

@ -2,403 +2,433 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: none\n"
"Language: bg\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Нещо се е объркало, опитайте отново"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Не можете да го направите"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Промените не могат да бъдат запазени"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Не може да бъде изтрит"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s вече съществува"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Не е намерен"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Файлът не е намерен"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Твърде голям файл"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Не се поддържа"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Неподдържан тип"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Неподдържан формат"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Папката с оригинали е празна"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Изборът не е намерен"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Субектът не е намерен"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Акаунтът не е намерен"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Потребителят не е намерен"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Етикетът не е намерен"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Камерата не е открита"
#: messages.go:130
msgid "Lens not found"
msgstr "Обективът не е открит"
#: messages.go:131
msgid "Album not found"
msgstr "Албумът не е намерен"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Темата не е намерена"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Лицето не е намерено"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Лицето не е намерено"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Не е наличен в публичен режим"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Не е наличен в режим само за четене"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Моля, влезте в профила си"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Достъп отказан"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Изисква се плащане"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Качването може да е обидно"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Файловете не успяха да се качат"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Няма избрани елементи"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Неуспешно създаване на файл, моля, проверете разрешенията"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Неуспешно създаване на папка, моля, проверете разрешенията"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Не може да се свърже, опитайте отново"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Въведете код за верификация"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Невалиден код за потвърждение, моля опитайте отново"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Невалидна парола, моля, опитайте отново"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Функцията е деактивирана"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Няма избрани етикети"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Няма избрани албуми"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Няма налични файлове за изтегляне"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Неуспешно създаване на zip файл"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Невалидни креденции"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Невалидна връзка"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Невалидно име"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Заето, моля, опитайте отново по-късно"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Интервалът на събуждане е %s, но трябва да е 1 час или по-малко"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Вашият акаунт не може да бъде свързан"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Твърде много заявки"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Недостатъчно място за съхранение"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Превишаване на квотата"
#: messages.go:163
msgid "Registration disabled"
msgstr "Регистрацията е деактивирана"
#: messages.go:164
msgid "Verified email required"
msgstr "Необходим е потвърден имейл адрес"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Промените са успешно записани"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Създаден албум"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Запазен албум"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Албум %s изтрит"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Съдържанието на албума беше клонирано"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Премахване на файла от стека"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Изтрит файл"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Добавяне на селекция към %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Добавяне на един запис към %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d добавени записи към %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Отстранен е един запис от %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d премахнати записи от %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Създаден акаунт"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Акаунтът запазен"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Изтрит акаунт"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Запазени настройки"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Паролата е променена"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Импортът е завършен за %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Вносът е отменен"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Индексирането е завършено за %d сек"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Индексиране на оригинали..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Индексиране на файлове в %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Отменено индексиране"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Премахнати са %d файлове и %d снимки"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Преместване на файлове от %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Копиране на файлове от %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Изтрити етикети"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Запазен етикет"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Тема: запазени"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Изтрит предмет"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Запазено лице"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Изтрито лице"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Качен файл"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d файлове, качени за %d сек"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Обработка на качването..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Качването е обработено"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Одобрена селекция"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Архивирана селекция"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Възстановена селекция"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Селекция, отбелязана като частна"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Изтрити албуми"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip създаден за %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Постоянно изтрити"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s е възстановена"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Успешно потвърдено"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Успешно активиран"
#~ msgid "Storage is full"
#~ msgstr "Съхранението е пълно"
#~ msgid "Invalid request"
#~ msgstr "Невалидна заявка"

View file

@ -2,403 +2,434 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: none\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "S'ha produït un error, torna-ho a provar"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Incapaç de fer-ho"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "No s'han pogut desar els canvis"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "No s'ha pogut suprimir"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s El nom ja existeix"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "No trobat"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "No s'ha trobat el fitxer"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Fitxer massa gran"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Sense suport"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Tipus no compatible"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Format no compatible"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "La carpeta d'originals està buida"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "No s'ha trobat la selecció"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "No s'ha trobat l'entitat"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Compte no trobat"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Usuari no trobat"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "No s'ha trobat l'etiqueta"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "No s'ha trobat la càmera"
#: messages.go:130
msgid "Lens not found"
msgstr "Lent no trobada"
#: messages.go:131
msgid "Album not found"
msgstr "No s'ha trobat l'àlbum"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "No s'ha trobat el tema"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Persona no trobada"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "No s'ha trobat la cara"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "No disponible en mode públic"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "No disponible en mode només de lectura"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Si us plau, inicieu sessió al vostre compte"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Permís denegat"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Pagament requerit"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "La càrrega pot ser ofensiva"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "La càrrega ha fallat"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "No s'ha seleccionat cap element"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "No s'ha pogut crear el fitxer, comproveu els permisos"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "No s'ha pogut crear la carpeta, comproveu els permisos"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "No s'ha pogut connectar, torna-ho a provar"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Introduïu el codi de verificació"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Codi de verificació no vàlid, torneu-ho a provar"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "La contrasenya no és vàlida, torneu-ho a provar"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Funció desactivada"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "No s'ha seleccionat cap etiqueta"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "No s'ha seleccionat cap àlbum"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "No hi ha fitxers disponibles per a la baixada"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "No s'ha pogut crear el fitxer zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Credencials incorrectes"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Enllaç no vàlid"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Nom no vàlid"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Ocupat, torna-ho a provar més tard"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "L'interval d'activació és %s, però ha de ser d'1 h o menys"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "No s'ha pogut connectar el vostre compte"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Massa peticions"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Emmagatzematge insuficient"
#: messages.go:162
msgid "Quota exceeded"
msgstr "S'ha superat la quota"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registre desactivat"
#: messages.go:164
msgid "Verified email required"
msgstr "Cal un correu electrònic verificat"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Els canvis s'han desat correctament"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Àlbum creat"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Àlbum desat"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "S'ha suprimit l'àlbum %s"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Contingut de l'àlbum clonat"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "S'ha eliminat el fitxer de la pila"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "S'ha suprimit el fitxer"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "S'ha afegit una selecció a %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "S'ha afegit una entrada a %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d entrades afegides a %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "S'ha eliminat una entrada de %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "S'han eliminat %d entrades de %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Compte creat"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Compte desat"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Compte suprimit"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Configuració desada"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Sha canviat la contrasenya"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Importació completada en %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Importació cancel·lada"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexació completada en %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "S'estan indexant els originals..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indexant fitxers a %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "S'ha cancel·lat la indexació"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "S'han eliminat %d fitxers i %d fotos"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "S'estan movent fitxers de %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "S'estan copiant fitxers de %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "S'han suprimit les etiquetes"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "S'ha desat l'etiqueta"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Assumpte desat"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "S'ha suprimit el tema"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Persona salvada"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "S'ha suprimit la persona"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Fitxer penjat"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d fitxers penjats en %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "S'està processant la càrrega..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "S'ha processat la càrrega"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Selecció aprovada"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Selecció arxivada"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "S'ha restaurat la selecció"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "La selecció s'ha marcat com a privada"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Àlbums suprimits"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip creat en %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Esborrat permanentment"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s s'ha restaurat"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Verificat correctament"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "S'ha activat correctament"
#~ msgid "Storage is full"
#~ msgstr "L'emmagatzematge està ple"
#~ msgid "Invalid request"
#~ msgstr "La sol·licitud no és vàlida"

View file

@ -2,10 +2,9 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: Czech <https://translate.photoprism.app/projects/photoprism/"
"backend/cs/>\n"
"Language: cs\n"
@ -13,393 +12,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Něco se pokazilo, zkuste to znovu"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Nelze to udělat"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Změny nemohly být uloženy"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Nemohlo být vymazáno"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s již existuje"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Nenalezeno"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Soubor nenalezen"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Příliš velký soubor"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Nepodporováno"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Nepodporovaný typ"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Nepodporovaný formát"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Složka Originály je prázdná"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Výběr nenalezen"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Subjekt nebyl nalezen"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Účet nenalezen"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Uživatel nenalezen"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Štítek nenalezen"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Fotoaparát nebyl nalezen"
#: messages.go:130
msgid "Lens not found"
msgstr "Objektiv nebyl nalezen"
#: messages.go:131
msgid "Album not found"
msgstr "Album nenalezeno"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Předmět nebyl nalezen"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Osoba nebyla nalezena"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Obličej nebyl nalezen"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Není k dispozici ve veřejném módu"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Není k dispozici v režimu pouze pro čtení"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Přihlaste se ke svému účtu"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Přístup zamítnut"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Požadovaná platba"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Nahrané soubory by mohly být urážlivé"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Nahrávání selhalo"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Nebyly vybrány žádné položky"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Vytváření souboru selhalo, zkontrolujte prosím oprávnění"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Vytváření složky selhalo, zkontrolujte prosím oprávnění"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Nemohlo být připojeno, zkuste to prosím znovu"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Vložte ověřovací kód"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Neplatný ověřovací kód, zkuste to prosím znovu"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Neplatné heslo, zkuste to prosím znovu"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Funkce deaktivovaná"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Nebyly vybrány žádné štítky"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Nebyla vybrána žádná alba"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Žádné soubory ke stažení k dispozici"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Nebylo možné vytvořit soubor ZIP"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Neplatné údaje"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Neplatný odkaz"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Neplatný jméno"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Zaneprázdněn, zkuste to prosím později"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Interval buzení je %s, ale musí být 1h nebo kratší"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Váš účet se nepodařilo připojit"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Příliš mnoho požadavků"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Nedostatečné skladování"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Překročení kvóty"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registrace je deaktivována"
#: messages.go:164
msgid "Verified email required"
msgstr "Je nutné zadat ověřenou e-mailovou adresu"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Změny byly úspěšně uloženy"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album vytvořeno"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album uloženo"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s vymazáno"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Obsah alba naklonován"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Soubor odstraněn ze stohu"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Soubor vymazán"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Výběr přidán do %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Jeden záznam přidán do %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d záznamů přidáno do %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Jeden záznam odstraněn z %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d záznamů odstraněno z %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Účet vytvořen"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Účet uložen"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Účet vymazán"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Nastavení uloženo"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Heslo změněno"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Import dokončen za %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Import zrušen"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexování dokončeno za %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indexování originálů..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indexování souborů v %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indexování zrušeno"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Odstraněno %d souborů a %d fotografií"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Přesouvání souborů z %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Kopírování souborů z %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Štítky vymazány"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Štítek uložen"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Předmět uložen"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Předmět smazán"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Uložená osoba"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Vymazaná osoba"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Soubor odeslán"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d souborů nahráno za %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Zpracování nahrávání..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Nahrávání bylo zpracováno"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Výběr potvrzen"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Výběr archivován"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Výběr obnoven"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Výběr označen jako Soukromý"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Alba vymazána"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "ZIP vytvořen za %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Trvale smazáno"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s bylo obnoveno"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Úspěšně ověřeno"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Úspěšně aktivováno"
#~ msgid "Storage is full"
#~ msgstr "Úložiště je plné"
#~ msgid "Invalid request"
#~ msgstr "Neplatný požadavek"

View file

@ -2,10 +2,9 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: Danish <https://translate.photoprism.app/projects/photoprism/"
"backend/da/>\n"
"Language: da\n"
@ -13,393 +12,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Der gik noget galt, prøv igen"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Det kan ikke lade sig gøre"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Ændringer kunne ikke gemmes"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Kunne ikke slettes"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s findes allerede"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Ikke fundet"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Fil ikke fundet"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Filen er for stor"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Ikke understøttet"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Ikke-understøttet type"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Ikke understøttet format"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Mappen Originaler er tom"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Valg ikke fundet"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Enhed ikke fundet"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Konto ikke fundet"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Bruger ikke fundet"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Etiket ikke fundet"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kameraet blev ikke fundet"
#: messages.go:130
msgid "Lens not found"
msgstr "Objektiv ikke fundet"
#: messages.go:131
msgid "Album not found"
msgstr "Album ikke fundet"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Emne ikke fundet"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Person ikke fundet"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Ansigt ikke fundet"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Ikke tilgængelig i offentlig tilstand"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Ikke tilgængelig i skrivebeskyttet tilstand"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Log ind på din konto"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Tilladelse nægtet"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Betaling påkrævet"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Upload kan være stødende"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Upload mislykkedes"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Ingen emner valgt"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Oprettelse af fil mislykkedes, tjek venligst tilladelser"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Oprettelse af mappe mislykkedes, tjek venligst tilladelser"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Kunne ikke oprette forbindelse, prøv venligst igen"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Indtast verifikations kode"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Ugyldig bekræftelseskode. Prøv venligst igen"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Ugyldig adgangskode, prøv venligst igen"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Funktion deaktiveret"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Ingen etiketter valgt"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Ingen album valgt"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Ingen filer til rådighed til download"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Det lykkedes ikke at oprette zip-fil"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Ugyldige legitimationsoplysninger"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Ugyldigt link"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Ugyldigt navn"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Optaget, prøv venligst igen senere"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Vækningsintervallet er %s, men skal være 1 time eller mindre"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Der kunne ikke oprettes forbindelse til din konto"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "For mange anmodninger"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Utilstrækkelig opbevaring"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kvote overskredet"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registrering er deaktiveret"
#: messages.go:164
msgid "Verified email required"
msgstr "Der kræves en bekræftet e-mailadresse"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Ændringer gemt med succes"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album oprettet"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album gemt"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s slettet"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Albumindhold klonet"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Fil fjernet fra stakken"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Fil slettet"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Valg tilføjet til %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "En post tilføjet til %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d poster tilføjet til %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "En post fjernet fra %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d poster fjernet fra %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Konto oprettet"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Gemte konto"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Konto slettet"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Indstillinger gemt"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Adgangskode ændret"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Import afsluttet efter %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Import annulleret"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indeksering afsluttet efter %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indeksering af originaler..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indeksering af filer i %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indeksering annulleret"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Fjernede %d filer og %d fotos"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Flytter filer fra %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Kopierer filer fra %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Etiketter slettet"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Etikette gemt"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Emne gemt"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Emne slettet"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Person gemt"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Person slettet"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Fil uploadet"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d filer uploadet på %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Behandling af upload..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Upload er blevet behandlet"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Udvælgelse godkendt"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Udvælgelse arkiveret"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Udvalgte gendannet"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Udvalgte er markeret som privat"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albums slettet"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip filen blev lavet på %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Permanent slettet"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s er blevet genoprettet"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Verifikation lykkedes"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Aktivering lykkedes"
#~ msgid "Storage is full"
#~ msgstr "Lageret er fyldt op"
#~ msgid "Invalid request"
#~ msgstr "Ugyldig anmodning"

View file

@ -2,10 +2,9 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: German <https://translate.photoprism.app/projects/photoprism/"
"backend/de/>\n"
"Language: de\n"
@ -13,394 +12,425 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
"X-Poedit-Basepath: .\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Etwas ist schief gelaufen, versuche es noch einmal"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Dies ist nicht möglich"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Fehler beim Speichern der Daten"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Konnte nicht gelöscht werden"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s existiert bereits"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Nicht gefunden"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Datei konnte nicht gefunden werden"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Datei zu groß"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Wird nicht unterstützt"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Typ wird nicht unterstützt"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Nicht unterstütztes Format"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Originals-Verzeichnis ist leer"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Auswahl nicht gefunden"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Keine Daten gefunden"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Unbekannter Account"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Nutzer nicht gefunden"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Kategorie nicht gefunden"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kamera nicht gefunden"
#: messages.go:130
msgid "Lens not found"
msgstr "Objektiv nicht gefunden"
#: messages.go:131
msgid "Album not found"
msgstr "Album nicht gefunden"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Unbekanntes Motiv"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Unbekannte Person"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Unbekanntes Gesicht"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Im öffentlichen Modus nicht verfügbar"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Im Nur-Lese-Modus nicht verfügbar"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Bitte melde dich an"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Erlaubnis verweigert"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Zahlung erforderlich"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Inhalt könnte anstößig sein und wurde abgelehnt"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Upload fehlgeschlagen"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Nichts ausgewählt"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Datei konnte nicht erstellt werden"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Ordner konnte nicht erstellt werden"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Verbindung fehlgeschlagen"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Verifizierungscode eingeben"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Ungültiger Verifizierungscode, bitte erneut versuchen"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Ungültiges Passwort"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Funktion deaktiviert"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Keine Kategorien ausgewählt"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Keine Alben ausgewählt"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Keine Dateien zum Download verfügbar"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Zip-Datei konnte nicht erstellt werden"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Ungültige Zugangsdaten"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Ungültiger Link"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Ungültiger Name"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Beschäftigt, bitte später erneut versuchen"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Worker-Intervall ist %s, muss aber 1h oder weniger betragen"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Das Konto konnte nicht verbunden werden"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Zu viele Anfragen"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Zu wenig Speicherplatz"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Maximale Anzahl erreicht"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registrierung deaktiviert"
#: messages.go:164
msgid "Verified email required"
msgstr "Eine verifizierte E-Mail-Adresse ist erforderlich"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Änderungen erfolgreich gespeichert"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album erstellt"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album gespeichert"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s gelöscht"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Album-Einträge kopiert"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Datei aus Stapel entfernt"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Datei gelöscht"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Auswahl zu %s hinzugefügt"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Ein Eintrag zu %s hinzugefügt"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d Einträge zu %s hinzugefügt"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Ein Eintrag aus %s entfernt"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d Einträge aus %s entfernt"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Konto hinzugefügt"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Konto gespeichert"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Konto gelöscht"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Einstellungen gespeichert"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Passwort geändert"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Import in %d s abgeschlossen"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Import abgebrochen"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexierung in %d s abgeschlossen"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indexiere Dateien…"
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indexiere Dateien in %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indexierung abgebrochen"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "%d Dateien und %d Bilder wurden entfernt"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Verschiebe Dateien von %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Kopiere Dateien von %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Kategorien gelöscht"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Kategorie gespeichert"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Motiv gespeichert"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Motiv gelöscht"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Person gespeichert"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Person gelöscht"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Datei hochgeladen"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d Dateien hochgeladen in %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Verarbeitung des Uploads..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Der Upload wurde verarbeitet"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Auswahl übernommen"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Auswahl archiviert"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Auswahl wiederhergestellt"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Auswahl als privat markiert"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Alben gelöscht"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip-Datei erstellt in %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Endgültig gelöscht"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s wurde wiederhergestellt"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Erfolgreich verifiziert"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Erfolgreich aktiviert"
#~ msgid "Storage is full"
#~ msgstr "Der Speicher ist voll"
#~ msgid "Invalid request"
#~ msgstr "Ungültige Anfrage"

View file

@ -2,402 +2,432 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: none\n"
"Language: el\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Κάτι πήγε στραβά, δοκιμάστε ξανά"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Αυτό δεν είναι εφικτό"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Οι αλλαγές δεν μπόρεσαν να αποθηκευτούν"
msgstr "Οι αλλαγές δεν ήταν δυνατό να αποθηκευτούν"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Δεν μπόρεσε να διαγραφεί"
msgstr "Δεν ήταν εφικτή η διαγραφή"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s υπάρχει ήδη"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Δεν βρέθηκε"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Το αρχείο δεν βρέθηκε"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Πολύ μεγάλο αρχείο"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Ανυποστήρικτος"
msgstr "Δεν υποστηρίζεται"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Μη υποστηριζόμενος τύπος"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Μη υποστηριζόμενη μορφή"
msgstr "Μη υποστηριζόμενος μορφότυπος"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Ο φάκελος Πρωτότυπα είναι άδειος"
msgstr "Ο φάκελος πρωτότυπων είναι άδειος"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Η επιλογή δεν βρέθηκε"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Η οντότητα δεν βρέθηκε"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Ο λογαριασμός δεν βρέθηκε"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Ο χρήστης δεν βρέθηκε"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Η ετικέτα δεν βρέθηκε"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Δεν εντοπίστηκε η κάμερα"
#: messages.go:130
msgid "Lens not found"
msgstr "Δεν βρέθηκε ο φακός"
#: messages.go:131
msgid "Album not found"
msgstr "Η Συλλογή δεν βρέθηκε"
msgstr "Το άλμπουμ δεν βρέθηκε"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Το Θέμα δεν βρέθηκε"
msgstr "Το θέμα δεν βρέθηκε"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Το Άτομο δεν βρέθηκε"
msgstr "Το άτομο δεν βρέθηκε"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Το Πρόσωπο δεν βρέθηκε"
msgstr "Το πρόσωπο δεν βρέθηκε"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Μη διαθέσιμο κατά τη δημόσια λειτουργία"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "μη διαθέσιμο στην κατάσταση \"μόνο για ανάγνωση\""
msgstr "Μη διαθέσιμο στην κατάσταση \"μόνο ανάγνωση\""
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Παρακαλούμε συνδεθείτε και δοκιμάστε ξανά"
msgstr "Συνδεθείτε στο λογαριασμό σας"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Το Άτομο διαγράφηκε"
msgstr "Δέν δόθηκε άδεια"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Απαιτείται πληρωμή"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Η φόρτωση μπορεί να είναι προσβλητική"
msgstr "Το ανέβασμα μπορεί να είναι προσβλητικό"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Αποτυχία αποστολής"
msgstr "Αποτυχία ανεβάσματος"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Δεν έχουν επιλεγεί αντικείμενα"
msgstr "Δεν έχουν επιλεγεί στοιχεία"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Απέτυχε η δημιουργία αρχείου, παρακαλούμε ελέγξτε τα δικαιώματα"
msgstr "Απέτυχε η δημιουργία αρχείου, ελέγξτε τα δικαιώματα"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Απέτυχε η δημιουργία φακέλου, παρακαλούμε ελέγξτε τα δικαιώματα"
msgstr "Απέτυχε η δημιουργία φακέλου, ελέγξτε τα δικαιώματα"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Δεν ήταν δυνατή η σύνδεση, παρακαλώ δοκιμάστε ξανά"
msgstr "Δεν ήταν δυνατή η σύνδεση, δοκιμάστε ξανά"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "βάλτε κωδικό επιβεβαίωσης"
msgstr "Εισάγετε τον κωδικό επαλήθευσης"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Μη έγκυρος κωδικός επαλήθευσης, δοκιμάστε ξανά"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Μη έγκυρος κωδικός πρόσβασης, παρακαλώ δοκιμάστε ξανά"
msgstr "Μη έγκυρος κωδικός πρόσβασης, δοκιμάστε ξανά"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Λειτουργία απενεργοποιημένη"
msgstr "Απενεργοποιημένη λειτουργία"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Δεν έχουν επιλεγεί ετικέτες"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Δεν έχουν επιλεγεί συλλογές"
msgstr "Δεν έχουν επιλεγεί άλμπουμ"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Δεν υπάρχουν διαθέσιμα αρχεία για λήψη"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Απέτυχε η δημιουργία αρχείου zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Μη έγκυρα διαπιστευτήρια"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Μη έγκυρος σύνδεσμος"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Μη έγκυρο όνομα"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Απασχολημένος, προσπαθήστε ξανά αργότερα"
msgstr "Το σύστημα είναι απασχολημένο, προσπαθήστε ξανά αργότερα"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Το διάστημα αφύπνισης είναι %s, αλλά πρέπει να είναι 1 ώρα ή λιγότερο"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Ο λογαριασμός σας δεν μπόρεσε να συνδεθεί"
msgstr "Ο λογαριασμός σας δεν ήταν δυνατό να συνδεθεί"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Πάρα πολλά αιτήματα"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Ανεπαρκής χώρος"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Υπέρβαση ορίου"
#: messages.go:163
msgid "Registration disabled"
msgstr "Η εγγραφή έχει απενεργοποιηθεί"
#: messages.go:164
msgid "Verified email required"
msgstr "Απαιτείται επαληθευμένη διεύθυνση ηλεκτρονικού ταχυδρομείου"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Οι αλλαγές αποθηκεύτηκαν επιτυχώς"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Η Συλλογή δημιουργήθηκε"
msgstr "Το άλμπουμ δημιουργήθηκε"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Η Συλλογή αποθηκεύθηκε"
msgstr "Το άλμπουμ αποθηκεύθηκε"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Η Συλλογή %s διαγράφηκε"
msgstr "Το άλμπουμ %s διαγράφηκε"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Τα περιεχόμενα της Συλλογής αντιγράφηκαν"
msgstr "Τα περιεχόμενα του άλμπουμ αντιγράφηκαν"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Αφαίρεση αρχείου από τη στοίβα"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Το αρχείο διαγράφηκε"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Η επιλογή προστέθηκε στο %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Μία εγγραφή προστέθηκε στο %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d καταχωρήσεις προστέθηκαν στο %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Μία καταχώρηση αφαιρέθηκε από %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d καταχωρήσεις αφαιρέθηκαν από %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Ο Λογαριασμός δημιουργήθηκε"
msgstr "Ο λογαριασμός δημιουργήθηκε"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Ο Λογαριασμός αποθηκεύθηκε"
msgstr "Ο λογαριασμός αποθηκεύτηκε"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Ο Λογαριασμός διαγράφηκε"
msgstr "Ο λογαριασμός διαγράφηκε"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Οι ρυθμίσεις αποθηκεύτηκαν"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Ο κωδικός πρόσβασης άλλαξε"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Η εισαγωγή ολοκληρώθηκε σε %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Η εισαγωγή ακυρώθηκε"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Η δημιουργία ευρετηρίου σε %d s"
msgstr "Η ευρετηρίαση ολοκληρώθηκε σε %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Δημιουργία ευρετηρίου για τα πρωτότυπα..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Δημιουργία ευρετηρίου αρχείων σε %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Η δημιουργία ευρετηρίου ακυρώθηκε"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Αφαίρεση %d αρχείων και %d φωτογραφιών"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Μετακίνηση αρχείων από %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Αντιγραφή αρχείων από %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Οι Ετικέτες διαγράφηκαν"
msgstr "Οι ετικέτες διαγράφηκαν"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Η Ετικέτα αποθηκεύτηκε"
msgstr "Η ετικέτα αποθηκεύτηκε"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Το Θέμα αποθηκεύθηκε"
msgstr "Το θέμα αποθηκεύθηκε"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Το Θέμα διαγράφηκε"
msgstr "Το θέμα διαγράφηκε"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Το Άτομο αποθηκεύθηκε"
msgstr "Το άτομο αποθηκεύτηκε"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Το Άτομο διαγράφηκε"
msgstr "Το άτομο διαγράφηκε"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Το αρχείο διαγράφηκε"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d αρχεία μεταφορτώθηκαν σε %d s"
msgstr "%d αρχεία ανεβάστηκαν σε %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Επεξεργασία μεταφόρτωσης..."
msgstr "Επεξεργασία ανεβάσματος..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Η φόρτωση έχει ολοκληρωθεί"
msgstr "Το ανέβασμα έχει ολοκληρωθεί"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Η επιλογή εγκρίθηκε"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Η επιλογή αρχειοθετήθηκε"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Η επιλογή αποκαταστάθηκε"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Η επιλογή χαρακτηρίστηκε ως ιδιωτική"
msgstr "Η επιλογή μαρκαρίστηκε ως ιδιωτική"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Οι Συλλογές διαγράφηκαν"
msgstr "Διαγραμμένα άλμπουμ"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Το αρχείο συμπίεσης δημιουργήθηκε σε %d s"
msgstr "Το αρχείο zip δημιουργήθηκε σε %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Διαγράφηκε μόνιμα"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s έχει αποκατασταθεί"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Επαληθεύτηκε με επιτυχία"
msgstr "Επιτυχής επαλήθευση"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Ενεργοποιήθηκε με επιτυχία"
msgstr "Επιτυχής ενεργοποίηση"
#~ msgid "Storage is full"
#~ msgstr "Ο αποθηκευτικός χώρος είναι γεμάτος"
#~ msgid "Invalid request"
#~ msgstr "Μη έγκυρο αίτημα"

View file

@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: 2022-10-31 16:44+0100\n"
"Last-Translator: Michael Mayer <michael@photoprism.org>\n"
"Language-Team: \n"
@ -13,387 +13,415 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.3\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr ""
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr ""
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr ""
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr ""
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr ""
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr ""
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr ""
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr ""
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr ""
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr ""
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr ""
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr ""
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr ""
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr ""
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr ""
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr ""
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr ""
#: messages.go:118
msgid "Album not found"
msgstr ""
#: messages.go:119
msgid "Subject not found"
msgstr ""
#: messages.go:120
msgid "Person not found"
msgstr ""
#: messages.go:121
msgid "Face not found"
msgstr ""
#: messages.go:122
msgid "Not available in public mode"
msgstr ""
#: messages.go:123
msgid "Not available in read-only mode"
msgstr ""
#: messages.go:124
msgid "Please log in to your account"
msgstr ""
#: messages.go:125
msgid "Permission denied"
msgstr ""
#: messages.go:126
msgid "Upload might be offensive"
msgstr ""
#: messages.go:127
msgid "Upload failed"
msgstr ""
#: messages.go:128
msgid "No items selected"
msgstr ""
#: messages.go:129
msgid "Failed creating file, please check permissions"
msgid "Camera not found"
msgstr ""
#: messages.go:130
msgid "Failed creating folder, please check permissions"
msgid "Lens not found"
msgstr ""
#: messages.go:131
msgid "Could not connect, please try again"
msgid "Album not found"
msgstr ""
#: messages.go:132
msgid "Enter verification code"
msgid "Subject not found"
msgstr ""
#: messages.go:133
msgid "Invalid verification code, please try again"
msgid "Person not found"
msgstr ""
#: messages.go:134
msgid "Invalid password, please try again"
msgid "Face not found"
msgstr ""
#: messages.go:135
msgid "Feature disabled"
msgid "Not available in public mode"
msgstr ""
#: messages.go:136
msgid "No labels selected"
msgid "Not available in read-only mode"
msgstr ""
#: messages.go:137
msgid "No albums selected"
msgid "Please log in to your account"
msgstr ""
#: messages.go:138
msgid "No files available for download"
msgid "Permission denied"
msgstr ""
#: messages.go:139
msgid "Failed to create zip file"
msgid "Payment required"
msgstr ""
#: messages.go:140
msgid "Invalid credentials"
msgid "Upload might be offensive"
msgstr ""
#: messages.go:141
msgid "Invalid link"
msgid "Upload failed"
msgstr ""
#: messages.go:142
msgid "Invalid name"
msgid "No items selected"
msgstr ""
#: messages.go:143
msgid "Busy, please try again later"
msgid "Failed creating file, please check permissions"
msgstr ""
#: messages.go:144
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgid "Failed creating folder, please check permissions"
msgstr ""
#: messages.go:145
msgid "Your account could not be connected"
msgid "Could not connect, please try again"
msgstr ""
#: messages.go:146
msgid "Too many requests"
msgid "Enter verification code"
msgstr ""
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr ""
#: messages.go:148
msgid "Invalid password, please try again"
msgstr ""
#: messages.go:149
msgid "Changes successfully saved"
msgid "Feature disabled"
msgstr ""
#: messages.go:150
msgid "Album created"
msgid "No labels selected"
msgstr ""
#: messages.go:151
msgid "Album saved"
msgid "No albums selected"
msgstr ""
#: messages.go:152
#, c-format
msgid "Album %s deleted"
msgid "No files available for download"
msgstr ""
#: messages.go:153
msgid "Album contents cloned"
msgid "Failed to create zip file"
msgstr ""
#: messages.go:154
msgid "File removed from stack"
msgid "Invalid credentials"
msgstr ""
#: messages.go:155
msgid "File deleted"
msgid "Invalid link"
msgstr ""
#: messages.go:156
#, c-format
msgid "Selection added to %s"
msgid "Invalid name"
msgstr ""
#: messages.go:157
#, c-format
msgid "One entry added to %s"
msgid "Busy, please try again later"
msgstr ""
#: messages.go:158
#, c-format
msgid "%d entries added to %s"
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr ""
#: messages.go:159
#, c-format
msgid "One entry removed from %s"
msgid "Your account could not be connected"
msgstr ""
#: messages.go:160
#, c-format
msgid "%d entries removed from %s"
msgid "Too many requests"
msgstr ""
#: messages.go:161
msgid "Account created"
msgid "Insufficient storage"
msgstr ""
#: messages.go:162
msgid "Account saved"
msgid "Quota exceeded"
msgstr ""
#: messages.go:163
msgid "Account deleted"
msgid "Registration disabled"
msgstr ""
#: messages.go:164
msgid "Settings saved"
msgstr ""
#: messages.go:165
msgid "Password changed"
msgstr ""
#: messages.go:166
#, c-format
msgid "Import completed in %d s"
msgid "Verified email required"
msgstr ""
#: messages.go:167
msgid "Import canceled"
msgid "Changes successfully saved"
msgstr ""
#: messages.go:168
#, c-format
msgid "Indexing completed in %d s"
msgid "Album created"
msgstr ""
#: messages.go:169
msgid "Indexing originals..."
msgid "Album saved"
msgstr ""
#: messages.go:170
#, c-format
msgid "Indexing files in %s"
msgid "Album %s deleted"
msgstr ""
#: messages.go:171
msgid "Indexing canceled"
msgid "Album contents cloned"
msgstr ""
#: messages.go:172
#, c-format
msgid "Removed %d files and %d photos"
msgid "File removed from stack"
msgstr ""
#: messages.go:173
#, c-format
msgid "Moving files from %s"
msgid "File deleted"
msgstr ""
#: messages.go:174
#, c-format
msgid "Copying files from %s"
msgid "Selection added to %s"
msgstr ""
#: messages.go:175
msgid "Labels deleted"
#, c-format
msgid "One entry added to %s"
msgstr ""
#: messages.go:176
msgid "Label saved"
#, c-format
msgid "%d entries added to %s"
msgstr ""
#: messages.go:177
msgid "Subject saved"
#, c-format
msgid "One entry removed from %s"
msgstr ""
#: messages.go:178
msgid "Subject deleted"
#, c-format
msgid "%d entries removed from %s"
msgstr ""
#: messages.go:179
msgid "Person saved"
msgid "Account created"
msgstr ""
#: messages.go:180
msgid "Person deleted"
msgid "Account saved"
msgstr ""
#: messages.go:181
msgid "File uploaded"
msgid "Account deleted"
msgstr ""
#: messages.go:182
#, c-format
msgid "%d files uploaded in %d s"
msgid "Settings saved"
msgstr ""
#: messages.go:183
msgid "Processing upload..."
msgid "Password changed"
msgstr ""
#: messages.go:184
msgid "Upload has been processed"
#, c-format
msgid "Import completed in %d s"
msgstr ""
#: messages.go:185
msgid "Selection approved"
msgid "Import canceled"
msgstr ""
#: messages.go:186
msgid "Selection archived"
#, c-format
msgid "Indexing completed in %d s"
msgstr ""
#: messages.go:187
msgid "Selection restored"
msgid "Indexing originals..."
msgstr ""
#: messages.go:188
msgid "Selection marked as private"
#, c-format
msgid "Indexing files in %s"
msgstr ""
#: messages.go:189
msgid "Albums deleted"
msgid "Indexing canceled"
msgstr ""
#: messages.go:190
#, c-format
msgid "Zip created in %d s"
msgid "Removed %d files and %d photos"
msgstr ""
#: messages.go:191
msgid "Permanently deleted"
#, c-format
msgid "Moving files from %s"
msgstr ""
#: messages.go:192
#, c-format
msgid "%s has been restored"
msgid "Copying files from %s"
msgstr ""
#: messages.go:193
msgid "Successfully verified"
msgid "Labels deleted"
msgstr ""
#: messages.go:194
msgid "Label saved"
msgstr ""
#: messages.go:195
msgid "Subject saved"
msgstr ""
#: messages.go:196
msgid "Subject deleted"
msgstr ""
#: messages.go:197
msgid "Person saved"
msgstr ""
#: messages.go:198
msgid "Person deleted"
msgstr ""
#: messages.go:199
msgid "File uploaded"
msgstr ""
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr ""
#: messages.go:201
msgid "Processing upload..."
msgstr ""
#: messages.go:202
msgid "Upload has been processed"
msgstr ""
#: messages.go:203
msgid "Selection approved"
msgstr ""
#: messages.go:204
msgid "Selection archived"
msgstr ""
#: messages.go:205
msgid "Selection restored"
msgstr ""
#: messages.go:206
msgid "Selection marked as private"
msgstr ""
#: messages.go:207
msgid "Albums deleted"
msgstr ""
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr ""
#: messages.go:209
msgid "Permanently deleted"
msgstr ""
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr ""
#: messages.go:211
msgid "Successfully verified"
msgstr ""
#: messages.go:212
msgid "Successfully activated"
msgstr ""

View file

@ -2,10 +2,9 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: Spanish <https://translate.photoprism.app/projects/photoprism/"
"backend/es/>\n"
"Language: es\n"
@ -13,393 +12,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Algo ha ido mal, inténtalo de nuevo"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Incapaz de hacerlo"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "No se pudieron guardar los cambios"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "No se pudo borrar"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s ya existe"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "No encontrado"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "No se encuentra el archivo"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Archivo demasiado grande"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "No compatible"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Tipo no admitido"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Formato no admitido"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "La carpeta de originales está vacía"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Selección no encontrada"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entidad no encontrada"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Cuenta no encontrada"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Usuario no encontrado"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Etiqueta no encontrada"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "No se encuentra la cámara"
#: messages.go:130
msgid "Lens not found"
msgstr "No se ha encontrado la lente"
#: messages.go:131
msgid "Album not found"
msgstr "Álbum no encontrado"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Asunto no encontrado"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Persona no encontrada"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Cara no encontrada"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "No disponible en modo público"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "No está disponible en modo de sólo lectura"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Por favor inicie sesión"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Permiso denegado"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Pago requerido"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "El archivo subido puede ser ofensivo"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Carga fallida"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Ningún elemento seleccionado"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Fallo al crear el archivo, por favor, compruebe los permisos"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Fallo al crear la carpeta, por favor, compruebe los permisos"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "No se pudo conectar, por favor vuelva a intentarlo"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Ingrese el código de verificación"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Código de verificación no válido, inténtalo de nuevo"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Contraseña inválida, por favor vuelva a intentarlo"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Característica desactivada"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Ninguna etiqueta seleccionada"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Ningún álbum seleccionado"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Ningún archivo disponible para descargar"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Fallo al crear el archivo zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Credenciales no válidas"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Enlace inválido"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Nombre inválido"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Ocupado, por favor vuelva a intentarlo más tarde"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "El intervalo de activación es %s, pero debe ser 1h o menos"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Su cuenta no pudo ser conectada"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Demasiadas peticiones"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Almacenamiento insuficiente"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Cuota superada"
#: messages.go:163
msgid "Registration disabled"
msgstr "El registro está desactivado"
#: messages.go:164
msgid "Verified email required"
msgstr "Se requiere una dirección de correo electrónico verificada"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Cambios guardados con éxito"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Álbum creado"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Álbum guardado"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Álbum %s borrado"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Contenidos del álbum clonados"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Archivo eliminado de la pila"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Archivo eliminado"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Selección añadida a %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Una entrada añadida a %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d entradas añadidas a %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Una entrada eliminada de %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d entradas eliminadas de %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Cuenta creada"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Cuenta guardada"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Cuenta borrada"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Ajustes guardados"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Contraseña cambiada"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Importación completada en %d"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Importación cancelada"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexación completada em %d"
msgstr "Indexación completada en %d"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indexando originales..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indexando archivos en %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indexación cancelada"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Eliminados %d archivos y %d fotos"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Moviendo achivos desde %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Copiando archivos desde %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Etiquetas borradas"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Etiqueta guardada"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Asunto guardado"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Sujeto eliminado"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Persona salvada"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Persona eliminada"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Archivo cargado"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d archivos subidos en %d"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Procesando la carga..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "La carga ha sido procesada"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Selección aprobada"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Selección archivada"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Selección restaurada"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Selección marcada como privada"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Álbumes borrados"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip creado en %d"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Eliminado permanentemente"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s ha sido restaurado"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Verificado con éxito"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Activado exitosamente"
#~ msgid "Storage is full"
#~ msgstr "El almacén está lleno"
#~ msgid "Invalid request"
#~ msgstr "Petición no válida"

View file

@ -2,403 +2,433 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: none\n"
"Language: et\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Midagi läks valesti, proovige uuesti"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Seda ei ole võimalik teha"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Muudatuste salvestamine ebaõnnestus"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Kustutamine ebaõnnestus"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s on juba olemas"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Ei leitud"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Faili ei leitud"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Fail on liiga suur"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Toetamata"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Toetamata tüüp"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Mittetoetatud formaat"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Originaalide kaust on tühi"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Valikut ei leitud"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Olemit ei leitud"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Kontot ei leitud"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Kasutajat ei leitud"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Silti ei leitud"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kaamerat ei leitud"
#: messages.go:130
msgid "Lens not found"
msgstr "Objektiivi ei leitud"
#: messages.go:131
msgid "Album not found"
msgstr "Albumit ei leitud"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Teemat ei leitud"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Isikut ei leitud"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Nägu ei leitud"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Pole avalikus režiimis saadaval"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Pole kirjutuskaitstud režiimis saadaval"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Palun logi oma kontole sisse"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Õigused puuduvad"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Nõutav makse"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Fail võib olla solvav"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Üleslaadimine ebaõnnestus"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Midagi pole valitud"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Faili loomine ebaõnnestus, kontrolli õiguseid"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Kausta loomine ebaõnnestus, kontrolli õiguseid"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Ühendumine ebaõnnestus, palun proovi uuesti"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Sisesta kontrollkood"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Vale kinnituskood, proovige uuesti"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Vale parool, palun proovi uuesti"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Funktsioon välja lülitatud"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Ühtegi silti pole valitud"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Ühtegi albumit pole valitud"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Ühtegi faili ei ole allalaadimiseks saadaval"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "ZIP-faili loomine ebaõnnestus"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Kehtetud ligipääsuandmed"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Vigane link"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Vigane nimi"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Hõivatud, palun proovi hiljem uuesti"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Ärkamisintervall on %s, kuid peab olema 1 tund või vähem"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Konto ühendamine ebaõnnestus"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Liiga palju taotlusi"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Ebapiisav ladustamine"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kvoot ületatud"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registreerimine on keelatud"
#: messages.go:164
msgid "Verified email required"
msgstr "Nõutav on kinnitatud e-posti aadress"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Muudatused edukalt salvestatud"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album lisatud"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album salvestatud"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s kustutatud"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Albumi sisu kloonitud"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Fail virnast eemaldatud"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Fail kustutatud"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Valik lisatud albumisse %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Üks kirje lisatud albumisse %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d kirjet lisatud albumisse %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Üks kirje eemaldatud albumist %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d kirjet eemaldatud albumist %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Konto loodud"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Konto salvestatud"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Konto kustutatud"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Seaded salvestatud"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Parool muudetud"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Import tehtud %d sekundiga"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Import tühistatud"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indekseerimine lõpetatud %d sekundiga"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Originaalide indekseerimine..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Failide indekseerimine: %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indekseerimine tühistatud"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Eemaldatud %d faili ja %d fotot"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Failide liigutamine asukohast %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Failide kopeerimine asukohast %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Sildid kustutatud"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Silt salvestatud"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Teema salvestatud"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Teema kustutatud"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Isik salvestatud"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Isik kustutatud"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "File üles laaditud"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d faili üles laaditud %d sekundiga"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Üleslaaditud faili töötlemine..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Üleslaaditud fail on töödeldud"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Valik heaks kiidetud"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Valik arhiveeritud"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Valik taastatud"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Valik privaatseks märgitud"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albumid kustutatud"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "ZIP-fail loodud %d sekundiga"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Lõplikult kustutatud"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s on taastatud"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Edukalt kinnitatud"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Edukalt aktiveeritud"
#~ msgid "Storage is full"
#~ msgstr "Ladu on täis"
#~ msgid "Invalid request"
#~ msgstr "Vigane päring"

View file

@ -2,399 +2,429 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: none\n"
"Language: eu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Arazoren bat izan da. Saiatu berriro"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Hori egin ezinik"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Ezin izan dira aldaketak gorde"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Ezin izan da ezabatu"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s dagoeneko existitzen da"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Ez da aurkitu"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Fitxategia ez da aurkitu"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Fitxategi handiegia"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Onartu gabe"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Onartu gabeko mota"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Onartu gabeko formatua"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Jatorrizkoen karpeta hutsik dago"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Ez da hautapena aurkitu"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Ez da aurkitu entitatea"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Ez da kontua aurkitu"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Ez da erabiltzailea aurkitu"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Ez da etiketa aurkitu"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kamera ez da aurkitu"
#: messages.go:130
msgid "Lens not found"
msgstr "Lentila ez da aurkitu"
#: messages.go:131
msgid "Album not found"
msgstr "Ez da aurkitu albuma"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Ez da aurkitu gaia"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Pertsona ez da aurkitu"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Aurpegia ez da aurkitu"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Ez dago eskuragarri modu publikoan"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Ez dago erabilgarri irakurtzeko soilik moduan"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Mesedez, hasi saioa zure kontuan"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Baimena ukatu egin da"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Ordainketa beharrezkoa da"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Kargatzea iraingarria izan daiteke"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Ezin izan da kargatu"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Ez da elementurik hautatu"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Ezin izan da fitxategia sortzean. Egiaztatu baimenak"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Ezin izan da karpeta sortzean. Egiaztatu baimenak"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Ezin izan da konektatu. Saiatu berriro"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Sartu egiaztapen-kodea"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Egiaztapen-kode baliogabea. Saiatu berriro"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Pasahitz baliogabea, saiatu berriro"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Eginbidea desgaituta dago"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Ez da etiketarik hautatu"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Ez dago albumik hautatu"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Ez dago fitxategirik deskargatzeko erabilgarri"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Ezin izan da zip fitxategia sortu"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Kredentzialak baliogabeak"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Esteka baliogabea"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Izen baliogabea"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Lanpetuta, saiatu berriro geroago"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Esnatzeko tartea %s da, baina ordu 1 edo gutxiagokoa izan behar du"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Ezin izan da zure kontua konektatu"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Eskaera gehiegi"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Biltegiratze nahikoa ez"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kuota gainditu da"
#: messages.go:163
msgid "Registration disabled"
msgstr "Erregistroa desgaituta dago"
#: messages.go:164
msgid "Verified email required"
msgstr "Egiaztatutako posta elektronikoa beharrezkoa da"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Aldaketak ongi gorde dira"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Sortu da albuma"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Albuma gorde da"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "%s albuma ezabatu da"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Albumen edukia klonatu da"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Fitxategia pilatik kendu da"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Fitxategia ezabatu da"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Aukeraketa gehitu da %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Sarrera bat gehitu da %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d sarrerak gehitu dira %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Sarrera bat kendu da %s-tik"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d sarrerak kendu dira %s-tik"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Kontua sortu da"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Kontua gorde da"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Kontua ezabatu da"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Ezarpenak gorde dira"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Pasahitza aldatu da"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Inportazioa %d s-an amaitu da"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Inportazioa bertan behera utzi da"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexatzea %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Jatorrizkoak indexatzen..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Fitxategiak indexatzen %s-n"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indexazioa bertan behera utzi da"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "%d fitxategiak eta %d argazkiak kendu dira"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Fitxategiak mugitzen %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "%s fitxategiak kopiatzen"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Etiketak ezabatu dira"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Etiketa gorde da"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Gaia gorde da"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Gaia ezabatu da"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Pertsona gordeta"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Pertsona ezabatu da"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Kargatu da fitxategia"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d fitxategiak %d s-etan kargatu dira"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Kargaketa prozesatzen..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Kargatzea prozesatu da"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Hautaketa onartu da"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Hautaketa artxibatuta dago"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Hautaketa leheneratu da"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Hautapena pribatu gisa markatu da"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albumak ezabatu dira"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip sortu zen %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Betiko ezabatu da"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s leheneratu da"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Behar bezala egiaztatu da"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Behar bezala aktibatu da"
#~ msgid "Storage is full"
#~ msgstr "Biltegia beteta dago"

View file

@ -2,403 +2,434 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: none\n"
"Language: fa\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n==0 || n==1);\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "یه چیزی اشتباه شد دوباره تلاش کن"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "قادر به انجام آن نیست"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "تغییرات را نمی توان ذخیره کرد"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "نمی توان حذف کرد"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s از قبل وجود دارد"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "پیدا نشد"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "فایل پیدا نشد"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "فایل خیلی بزرگ است"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "پشتیبانی نمی شود"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "نوع پشتیبانی نشده"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "قالب پشتیبانی نشده"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "پوشه اصلی خالی است"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "انتخاب پیدا نشد"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "موجودیت پیدا نشد"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "حساب کاربری پیدا نشد"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "کاربر پیدا نشد"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "برچسب پیدا نشد"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "دوربین پیدا نشد"
#: messages.go:130
msgid "Lens not found"
msgstr "لنز یافت نشد"
#: messages.go:131
msgid "Album not found"
msgstr "آلبوم پیدا نشد"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "موضوع پیدا نشد"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "فرد پیدا نشد"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "صورت پیدا نشد"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "در حالت عمومی در دسترس نیست"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "در حالت فقط خواندنی در دسترس نیست"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "لطفا وارد شوید و دوباره امتحان کنید"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "فرد حذف شد"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "پرداخت لازم است"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "آپلود ممکن است توهین آمیز باشد"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "آپلود انجام نشد"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "هیچ موردی انتخاب نشده است"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "فایل ایجاد نشد، لطفا مجوزها را بررسی کنید"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "پوشه ایجاد نشد، لطفا مجوزها را بررسی کنید"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "اتصال برقرار نشد، لطفاً دوباره امتحان کنید"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "کد تایید را وارد کنید"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "کد تأیید نامعتبر است، لطفاً دوباره امتحان کنید"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "رمز عبور نامعتبر است، لطفا دوباره امتحان کنید"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "ویژگی غیرفعال است"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "هیچ برچسبی انتخاب نشده است"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "هیچ آلبومی انتخاب نشده است"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "هیچ فایلی برای دانلود موجود نیست"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "فایل فشرده ایجاد نشد"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "گواهی نامه نامعتبر"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "لینک نامعتبر"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "نام نامعتبر"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "مشغول است، لطفاً بعداً دوباره امتحان کنید"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "فاصله بیداری %s است، اما باید 1 ساعت یا کمتر باشد"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "حساب شما متصل نشد"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "درخواست های خیلی زیاد"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "ذخیره سازی ناکافی"
#: messages.go:162
msgid "Quota exceeded"
msgstr "از سهمیه فراتر رفت"
#: messages.go:163
msgid "Registration disabled"
msgstr "ثبت نام غیرفعال شد"
#: messages.go:164
msgid "Verified email required"
msgstr "ایمیل تایید شده الزامی است"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "تغییرات با موفقیت ذخیره شد"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "آلبوم ایجاد شد"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "آلبوم ذخیره شد"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "آلبوم %s حذف شد"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "محتویات آلبوم کلون شد"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "فایل از پشته حذف شد"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "فایل حذف شد"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "مورد انتخابی به %s اضافه شد"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "یک مورد به %s اضافه شد"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d مورد به %s اضافه شد"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "یک مورد از %s حذف شد"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d مورد از %s حذف شد"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "حساب کاربری ایجاد شد"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "حساب کاربری ذخیره شد"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "حساب کاربری حذف شد"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "تنظیمات ذخیره شد"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "رمزعبور تغییر کرد"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "وارد کردن در %d ثانیه تکمیل شد"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "وارد کردن لغو شد"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "نمایه سازی در %d ثانیه تکمیل شد"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "نمایه سازی نسخه های اصلی ..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "نمایه سازی فایل ها در %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "نمایه سازی لغو شد"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "%d فایل و %d عکس حذف شد"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "انتقال فایل ها از %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "کپی کردن فایل ها از %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "برچسب ها حذف شدند"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "برچسب ذخیره شد"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "موضوع ذخیره شد"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "موضوع حذف شد"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "فرد ذخیره شد"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "فرد حذف شد"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "فایل حذف شد"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d فایل در %d ثانیه آپلود شد"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "در حال پردازش آپلود..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "%s بازیابی شده است"
msgstr "بارگذاری پردازش شده است"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "مورد انتخابی تایید شد"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "مورد انتخابی بایگانی شد"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "مورد انتخابی بازیابی شد"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "مورد انتخابی به‌عنوان خصوصی علامت‌گذاری شد"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "آلبوم حذف شد"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "فایل فشرده در %d ثانیه ایجاد شد"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "برای همیشه حذف شد"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s بازیابی شده است"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "با موفقیت تأیید شد"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "با موفقیت فعال شد"
#~ msgid "Storage is full"
#~ msgstr "فضای ذخیره سازی پر است"
#~ msgid "Invalid request"
#~ msgstr "درخواست نامعتبر است"

View file

@ -2,403 +2,433 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: none\n"
"Language: fi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Jokin meni pieleen, yritä uudelleen"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Se ei onnistu"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Muutoksia ei voitu tallentaa"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Ei voitu poistaa"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s on jo olemassa"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Ei löytynyt"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Tiedostoa ei löydy"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Tiedosto liian suuri"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Ei tuettu"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Tyyppiä ei tueta"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Ei tuettu muoto"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Originaalit-kansio on tyhjä"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Valintaa ei löydy"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entiteettiä ei löydy"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Tiliä ei löydy"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Käyttäjää ei löydy"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Tarraa ei löydy"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kameraa ei löydy"
#: messages.go:130
msgid "Lens not found"
msgstr "Objektiivia ei löydy"
#: messages.go:131
msgid "Album not found"
msgstr "Albumia ei löydy"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Aihetta ei löydy"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Henkilöä ei löydy"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Kasvoja ei löydy"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Ei käytettävissä julkisessa tilassa"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Ei käytettävissä vain luku-tilassa"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Kirjaudu sisään tilillesi"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Lupa evätty"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Vaadittu maksu"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Upload saattaa olla loukkaava"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Lataus epäonnistui"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Kohdetta ei ole valittu"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Tiedoston luominen epäonnistui, tarkista käyttöoikeudet"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Kansion luominen epäonnistui, tarkista käyttöoikeudet"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Yhteyttä ei saatu muodostettua, yritä uudelleen"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "syötä vahvistus koodi"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Virheellinen vahvistuskoodi, yritä uudelleen"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Väärä salasana, yritä uudelleen"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Ominaisuus poistettu käytöstä"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Ei valittuja tarroja"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Ei valittuja albumeita"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Tiedostoja ei ole ladattavissa"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Zip-tiedoston luominen epäonnistui"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Virheelliset valtakirjat"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Virheellinen linkki"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Virheellinen nimi"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Varattu, yritä myöhemmin uudelleen"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Heräämisväli on %s, mutta sen on oltava enintään 1h"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Tiliäsi ei voitu yhdistää"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Liian monta pyyntöä"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Riittämätön varastointi"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kiintiö ylitetty"
#: messages.go:163
msgid "Registration disabled"
msgstr "Rekisteröityminen on poistettu käytöstä"
#: messages.go:164
msgid "Verified email required"
msgstr "Vaaditaan vahvistettu sähköpostiosoite"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Muutokset tallennettu onnistuneesti"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Albumi luotu"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Albumi tallennettu"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Albumi %s poistettu"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Albumin sisältö kloonattu"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Tiedosto poistettu pinosta"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Tiedosto poistettu"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Valinta lisätty %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Yksi merkintä lisätty kohtaan %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d merkintöjä lisätty %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Yksi merkintä poistettu kohdasta %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d merkinnät poistettu %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Tili luotu"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Tallennettu tili"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Tili poistettu"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Asetukset tallennettu"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Salasana vaihdettu"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Tuonti valmis %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Tuonti peruutettu"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indeksointi valmis %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Alkuperäiskappaleiden indeksointi..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Tiedostojen indeksointi osoitteessa %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indeksointi peruutettu"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Poistettiin %d tiedostoa ja %d valokuvaa"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Tiedostojen siirtäminen %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Tiedostojen kopiointi %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Tunnisteet poistettu"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Tarra tallennettu"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Aihe tallennettu"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Aihe poistettu"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Tallennettu henkilö"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Henkilö poistettu"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Ladattu tiedosto"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d tiedostoa ladattu %d s aikana"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Käsittelen latausta..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Lataus on käsitelty"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Valinta hyväksytty"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Valinta arkistoitu"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Valinta palautettu"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Valinta merkitty yksityiseksi"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albumit poistettu"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip luotu %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Poistettu pysyvästi"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s on palautettu"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Vahvistettu onnistuneesti"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Aktivointi onnistui"
#~ msgid "Storage is full"
#~ msgstr "Varasto on täynnä"
#~ msgid "Invalid request"
#~ msgstr "Virheellinen pyyntö"

View file

@ -2,10 +2,9 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: French <https://translate.photoprism.app/projects/photoprism/"
"backend/fr/>\n"
"Language: fr\n"
@ -13,393 +12,428 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Quelque chose s'est mal passé, réessayez"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Impossible de faire cela"
msgstr "Impossible d'effectuer cela"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Les modifications n'ont pas pu être sauvegardées"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "N'a pas pu être supprimé"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s existe déjà"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Non trouvé"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Fichier non trouvé"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Fichier trop volumineux"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Non pris en charge"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Type non pris en charge"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Format non supporté"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Le dossier des originaux est vide"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Sélection non trouvée"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entité non trouvée"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Compte non trouvé"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Utilisateur non trouvé"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Étiquette non trouvée"
#: messages.go:118
msgid "Album not found"
msgstr "Album introuvable"
#: messages.go:129
msgid "Camera not found"
msgstr "Caméra non trouvée"
#: messages.go:119
#: messages.go:130
msgid "Lens not found"
msgstr "Objectif non trouvé"
#: messages.go:131
msgid "Album not found"
msgstr "Album non trouvé"
#: messages.go:132
msgid "Subject not found"
msgstr "Sujet non trouvé"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Personne non trouvée"
#: messages.go:121
#: messages.go:134
#, fuzzy
msgid "Face not found"
msgstr "Visage non trouvé"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Non disponible en mode public"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Non disponible en mode lecture seule"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Veuillez vous connecter avec votre compte"
msgstr "Veuillez vous connecter à votre compte"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Permission refusée"
msgstr "Autorisation refusée"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Paiement requis"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Le contenu chargé peut être choquant"
msgstr "Le contenu chargé pourrait être de nature offensante"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Échec du chargement"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Aucun élément sélectionné"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "La création du fichier a échoué, veuillez vérifier les permissions"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Échec de la création du dossier, veuillez vérifier les permissions"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Échec lors de la connexion, veuillez réessayer"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Entrer le code de vérification"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Code de vérification invalide, veuillez réessayer"
msgstr "Code de vérification incorrect, veuillez réessayer"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Mot de passe invalide, veuillez réessayer"
msgstr "Mot de passe incorrect, veuillez réessayer"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Fonctionnalité désactivée"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Aucune étiquette sélectionnée"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Aucun album sélectionné"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Aucun fichier disponible au téléchargement"
msgstr "Aucun fichier à télécharger"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Échec de la création du fichier zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Les informations d'identification sont invalides"
msgstr "Les informations d'identification ne sont pas valables"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Lien invalide"
msgstr "Lien incorrect"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Nom invalide"
msgstr "Nom incorrect"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Occupé, veuillez réessayer plus tard"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "L'intervalle de réveil est %s, mais doit être inférieur ou égal à 1h"
msgstr ""
"L'intervalle entre les tâches est de %s, mais il doit être inférieur ou égal "
"à 1 h"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Votre compte n'a pas pu être connecté"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Trop de demandes"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Espace de stockage insuffisant"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Quota dépassé"
#: messages.go:163
#, fuzzy
msgid "Registration disabled"
msgstr "Inscription désactivée"
#: messages.go:164
msgid "Verified email required"
msgstr "Adresse de courriel vérifiée requise"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Les modifications ont bien été enregistrées"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album créé"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album sauvegardé"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s supprimé"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Le contenu de l'album a été copié"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Le fichier a été retiré du groupe"
msgstr "Le fichier a été retiré de la pile"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Fichier supprimé"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Sélection ajoutée à %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Une entrée a été ajoutée à %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d entrées ont été ajoutées à %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Une entrée a été supprimée de %s"
msgstr "Une entrée a été supprimée dans %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d entrées ont été supprimées de %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Compte créé"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Compte sauvegardé"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Compte supprimé"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Paramètres sauvegardés"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Mot de passe modifié"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Importation terminée en %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Importation annulée"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexation terminée en %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indexage des originaux…"
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indexation des fichiers de %s"
msgstr "Indexation des fichiers en %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indexation annulée"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Suppression de %d fichiers et %d photos"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Déplacement de fichiers depuis %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Copie de fichiers depuis %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Étiquettes supprimées"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Étiquettes sauvegardées"
msgstr "Étiquette sauvegardée"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Sujet sauvegardé"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Sujet supprimé"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Personne sauvegardée"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Personne supprimée"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Fichier téléchargé"
msgstr "Fichier chargé"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d fichiers chargés en %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Traitement du téléchargement..."
msgstr "Chargement en cours…"
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Le téléchargement a été traité"
msgstr "Le chargement a été effectué"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Sélection approuvée"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Sélection archivée"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Sélection restaurée"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Sélection marquée comme privée"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albums supprimés"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Archive zip créée en %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Supprimé définitivement"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s a été restauré"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Vérifié avec succès"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Activation réussie"
#~ msgid "Storage is full"
#~ msgstr "L'espace de stockage est plein"
#~ msgid "Invalid request"
#~ msgstr "Requête invalide"

View file

@ -7,10 +7,9 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-09 06:08+0000\n"
"PO-Revision-Date: 2024-09-03 12:37+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: none\n"
"Language: ga\n"
"MIME-Version: 1.0\n"
@ -18,389 +17,420 @@ msgstr ""
"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"
"X-Generator: Weblate 5.7.1\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Chuaigh rud éigin mícheart, bain triail eile as"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Ní féidir é sin a dhéanamh"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Níorbh fhéidir na hathruithe a shábháil"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Níorbh fhéidir a scriosadh"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s ann cheana"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Ní bhfuarthas"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Comhad gan aimsiú"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Comhad ró-mhór"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Gan tacaíocht"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Cineál nach dtacaítear leis"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Formáid nach dtacaítear léi"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Tá fillteán bunghnéithe folamh"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Níor aimsíodh an rogha"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Aonán gan aimsiú"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Cuntas gan aimsiú"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Úsáideoir gan aimsiú"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Níor aimsíodh an lipéad"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Níor aimsíodh an ceamara"
#: messages.go:130
msgid "Lens not found"
msgstr "Níor aimsíodh an lionsa"
#: messages.go:131
msgid "Album not found"
msgstr "Albam gan aimsiú"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Ní bhfuarthas an t-ábhar"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Ní bhfuarthas an duine"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Aghaidh gan aimsiú"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Níl sé ar fáil i mód poiblí"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Níl sé ar fáil i mód inléite amháin"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Logáil isteach i do chuntas le do thoil"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Cead diúltaithe"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Íocaíocht ag teastáil"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "D'fhéadfadh uaslódáil a bheith maslach"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Theip ar an uaslódáil"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Níl aon mhír roghnaithe"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Theip ar chruthú an chomhaid, seiceáil na ceadanna"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Theip ar chruthú fillteán, seiceáil na ceadanna"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Níorbh fhéidir ceangal a dhéanamh, bain triail eile as"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Cuir isteach cód fíorúcháin"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Cód fíoraithe neamhbhailí, bain triail eile as"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Pasfhocal neamhbhailí, bain triail eile as"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Gné díchumasaithe"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Níor roghnaíodh aon lipéid"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Níor roghnaíodh aon albam"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Níl aon chomhaid ar fáil le híoslódáil"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Theip ar chruthú an chomhaid zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Dintiúir neamhbhailí"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Nasc neamhbhailí"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Ainm neamhbhailí"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Gnóthach, bain triail eile as ar ball"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Is é %s an t-eatramh múscail, ach caithfidh sé a bheith 1h nó níos lú"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Níorbh fhéidir do chuntas a nascadh"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "An iomarca iarratas"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Stóráil neamhleor"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Sáraíodh an cuóta"
#: messages.go:163
msgid "Registration disabled"
msgstr "Clárú díchumasaithe"
#: messages.go:164
msgid "Verified email required"
msgstr "Ríomhphost fíoraithe ag teastáil"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Sábháladh na hathruithe"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Albam cruthaithe"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Sábháilte albam"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Albam %s scriosta"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Clónáilte ábhar albam"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Baineadh an comhad den chruach"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Scriosadh an comhad"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Cuireadh an rogha le %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Cuireadh iontráil amháin le %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d iontráil curtha le %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Baineadh iontráil amháin de %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d iontráil bainte de %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Cuntas cruthaithe"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Cuntas sábháilte"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Scriosadh an cuntas"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Socruithe sábháilte"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Athraíodh an pasfhocal"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Iompórtáil críochnaithe i %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Cealaíodh an iompórtáil"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Innéacsú curtha i gcrích in %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Buntéacs á innéacsú..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Comhaid á innéacsú in %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Innéacsú cealaithe"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Baineadh %d comhaid agus %d grianghraif"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Comhaid á mbogadh ó %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Comhaid á gcóipeáil ó %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Scriosadh na lipéid"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Lipéad sábháilte"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Ábhar sábháilte"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Scriosadh an t-ábhar"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Sábháladh an duine"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Scriosadh an duine"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Comhad uaslódáilte"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d comhaid uaslódáilte i %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Uaslódáil á phróiseáil..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Próiseáladh an t-uaslódáil"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Faomhadh an roghnúcháin"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Roghnaithe sa chartlann"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Athchóiríodh an roghnúchán"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Roghnú marcáilte mar phríobháideach"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albaim scriosta"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip cruthaithe i %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Scriosta go buan"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s athchóirithe"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "D'éirigh leis a fhíorú"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Cuireadh i ngníomh go rathúil"
#~ msgid "Storage is full"
#~ msgstr "Tá an stóráil iomlán"

View file

@ -2,10 +2,9 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: Hebrew <https://translate.photoprism.app/projects/photoprism/"
"backend/he/>\n"
"Language: he\n"
@ -14,393 +13,424 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && "
"n % 10 == 0) ? 2 : 3));\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "קרתה תקלה נסה שוב"
msgstr "משהו השתבש נא לנסות שוב"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "לא מסוגל לעשות את זה"
msgstr "לא ניתן לבצע זאת"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "לא ניתן לשמור שינויים"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "לא ניתן למחיקה"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s כבר קיים"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "לא נמצא"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "הקובץ לא נמצא"
msgstr "קובץ לא נמצא"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "קובץ גדול מדי"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "אינו נתמך"
msgstr "לא נתמך"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "סוג לא נתמך"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "פורמט לא נתמך"
msgstr "תסדיר לא נתמך"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "תיקיית המקור ריקה"
msgstr "תיקיית מקור ריקה"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "הבחירה לא נמצאה"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "הישות לא נמצאה"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "החשבון לא נמצא"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "המשתמש לא נמצא"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "התווית לא נמצאה"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "לא נמצאה מצלמה"
#: messages.go:130
msgid "Lens not found"
msgstr "לא נמצא עדשה"
#: messages.go:131
msgid "Album not found"
msgstr "האלבום לא נמצא"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "הנושא לא נמצא"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "אדם לא נמצא"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "הפנים לא נמצאו"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "לא זמין במצב ציבורי"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "לא זמין במצב קריאה בלבד"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "אנא היכנס לחשבון שלך"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "גישה נדחתה"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "נדרש תשלום"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "ההעלאה עשויה להיות פוגענית"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "העלאה נכשלה"
msgstr "העלאה כשלה"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "לא נבחרו פריטים"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "יצירת הקובץ נכשלה, אנא בדוק את ההרשאות"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "יצירת התיקיה נכשלה, אנא בדוק את ההרשאות"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "לא ניתן היה להתחבר, נסה שוב"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "הכנס קוד אימות"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "קוד אימות לא חוקי, אנא נסה שוב"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "סיסמה לא תקינה, נסה שוב"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "התכונה מושבתת"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "לא נבחרו תוויות"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "לא נבחרו אלבומים"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "אין קבצים זמינים להורדה"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "יצירת קובץ ה-zip נכשלה"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "אישורים לא תקינים"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "קישור לא תקין"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "מספר לא תקף"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "עסוק, אנא נסה שוב מאוחר יותר"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "מרווח ההשכמה הוא %s, אך חייב להיות שעה אחת או פחות"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "לא ניתן היה לחבר את החשבון שלך"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "יותר מדי בקשות"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "אחסון לא מספיק"
#: messages.go:162
msgid "Quota exceeded"
msgstr "חריגה מהמכסה"
#: messages.go:163
msgid "Registration disabled"
msgstr "ההרשמה אינה פעילה"
#: messages.go:164
msgid "Verified email required"
msgstr "נדרש כתובת דוא\"ל מאומתת"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "השינויים נשמרו בהצלחה"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "האלבום נוצר"
msgstr "אלבום נוצר"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "האלבום נשמר"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "האלבום %s נמחק"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "תוכן האלבום שוכפל"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "הקובץ הוסר מהאיחוד"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "הקובץ נמחק"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "הבחירה נוספה ל-%s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "רשומה אחת נוספה ל-%s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d רשומות נוספו ל-%s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "רשומה אחת הוסרה מ-%s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d רשומות הוסרו מ-%s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "החשבון נוצר"
msgstr "חשבון נוצר"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "החשבון נשמר"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "החשבון נמחק"
msgstr "חשבון נמחק"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "ההגדרות נשמרו"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "סיסמא שונתה"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "הייבוא הושלם ב-%d שניות"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "הייבוא בוטל"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "האינדוקס הושלם ב-%d שניות"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "מאנדקס קבצי מקור..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "מאנדקס קבצים תוך %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "יצירת האינדקס בוטלה"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "הוסרו %d קבצים ו-%d תמונות"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "מעביר קבצים מ-%s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "מעתיק קבצים מ-%s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "תוויות נמחקו"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "התווית נשמרה"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "הנושא נשמר"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "הנושא נמחק"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "אדם נשמר"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "אדם נמחק"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "הקובץ הועלה"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d קבצים הועלו תוך %d שניות"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "מעבד העלאה..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "ההעלאה עובדה"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "הבחירה אושרה"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "הבחירה הועברה לארכיון"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "הבחירה שוחזרה"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "הבחירה סומנה כפרטית"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "אלבומים נמחקו"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "ה-ZIP נוצר תוך %d שניות"
msgstr "קובץ Zip נוצר תוך %d שניות"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "נמחק לצמיתות"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s שוחזר"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "אומת בהצלחה"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "הופעל בהצלחה"
#~ msgid "Storage is full"
#~ msgstr "האחסון מלא"
#~ msgid "Invalid request"
#~ msgstr "בקשה לא תקינה"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: Hindi <https://translate.photoprism.app/projects/photoprism/"
"backend/hi/>\n"
"Language: hi\n"
@ -13,393 +13,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n==0 || n==1);\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "कुछ गलत हुआ है, दोबारा कोशिश करें"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "ऐसा करने में असमर्थ"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "परिवर्तन सहेजा नहीं जा सका"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "हटाया नहीं जा सका"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s पहले से मौजूद है"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "नहीं मिला"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "फाइल नहीं मिली"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "बहुत बड़ी फाइल"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "असमर्थित"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "असमर्थित प्रकार"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "असमर्थित प्रारूप"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "मूल फ़ोल्डर खाली है"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "चयन नहीं मिला"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "इकाई नहीं मिली"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "खता नहीं मिला"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "उपयोगकर्ता नहीं मिला"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "लेबल नहीं मिला"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "कैमरा नहीं मिला"
#: messages.go:130
msgid "Lens not found"
msgstr "लेंस नहीं मिला"
#: messages.go:131
msgid "Album not found"
msgstr "एल्बम नहीं मिला"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "विषय नहीं मिला"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "व्यक्ति नहीं मिला"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "चेहरा नहीं मिला"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "सार्वजनिक मोड में उपलब्ध नहीं है"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "रीड ओनली मोड में उपलब्ध नहीं है"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "कृपया अपने खाते लॉग इन करें"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "अनुमति नहीं मिली"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "भुगतान आवश्यक"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "अपलोड आपत्तिजनक हो सकता है"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "अपलोड विफल"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "कोई आइटम नहीं चुना गया"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "फ़ाइल बनाने में विफल, कृपया अनुमतियों की जाँच करें"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "फ़ोल्डर बनाने में विफल, कृपया अनुमतियों की जाँच करें"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "कनेक्ट नहीं हो सका, कृपया पुनः प्रयास करें"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "सत्यापन कोड दर्ज करें"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "सत्यापन कोड अमान्य है, कृपया पुनः प्रयास करें"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "अमान्य पासवर्ड, कृपया पुनः प्रयास करें"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "सुविधा अक्षम है"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "कोई लेबल नहीं चुना गया"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "कोई एल्बम नहीं चुना गया"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "डाउनलोड के लिए कोई फाइल उपलब्ध नहीं है"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "ज़िप फ़ाइल बनाने में विफल"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "अवैध प्रत्यय पत्र"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "अमान्य लिंक"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "अमान्य नाम"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "व्यस्त, कृपया बाद में पुन: प्रयास करें"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "वेकअप अंतराल %s है, लेकिन 1h या उससे कम होना चाहिए"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "आपका खाता कनेक्ट नहीं किया जा सका"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "बहुत अधिक अनुरोध"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "अपर्याप्त भंडारण"
#: messages.go:162
msgid "Quota exceeded"
msgstr "कोटा पूरा हो गया"
#: messages.go:163
msgid "Registration disabled"
msgstr "पंजीकरण अक्षम"
#: messages.go:164
msgid "Verified email required"
msgstr "ईमेल सत्यापन आवश्यक है"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "परिवर्तन सफलतापूर्वक सहेजे गए"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "एल्बम बनाया गया"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "एल्बम सहेजा गया"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "एल्बम %s हटाया गया"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "एल्बम सामग्री को क्लोन किया गया"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "स्टैक से फ़ाइल को निकाला गया"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "फ़ाइल हटा दी गई"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "चयन %s में जोड़ा गया"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "एक प्रविष्टि %s में जोड़ी गई"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d प्रविष्टियों को %s में जोड़ा गया"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "%s से एक प्रविष्टि को हटाया गया"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d प्रविष्टियों को %s से हटा दिया गया"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "खाता बन गया"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "खाता सहेजा गया"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "खाता हटाया गया"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "सेटिंग्स को सहेजा गया"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "पासवर्ड बदला गया"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "%d s में आयात पूरा हुआ"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "आयात रद्द कर दिया गया"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "%d s में अनुक्रमण पूरा हुआ"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "अनुक्रमण मूल ..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "%s में फाइलों को अनुक्रमित करना"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "अनुक्रमण रद्द किया गया"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "%d फ़ाइलों और %d फ़ोटो को हटा दिया गया"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "%s से फाइल चल रही है"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "%s से फाइल कॉपी कर रहा है"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "लेबल हटा दिए गए"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "लेबल सहेजा गया"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "विषय सहेजा गया"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "विषय हटा दिया गया"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "व्यक्ति बचाया"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "व्यक्ति हटाया गया"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "फ़ाइल अपलोड की गई"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d फाइलों को %d में अपलोड किया गया"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "अपलोड संसाधित किया जा रहा है..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "अपलोड संसाधित हो गया है"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "चयन को संग्रहीत किया गया"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "चयन को संग्रहीत किया गया"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "चयन बहाल"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "चयन निजी के रूप में चिह्नित"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "एल्बम हटाए गए"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "%d s में बनाया गया ज़िप"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "स्थायी रूप से हटा दिया गया"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s बहाल कर दिया गया है"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "सफलतापूर्वक सत्यापित"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "सफलतापूर्वक सक्रिय किया गया"
#~ msgid "Storage is full"
#~ msgstr "स्टोरेज भर गया है"
#~ msgid "Invalid request"
#~ msgstr "अमान्य अनुरोध"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: none\n"
"Language: hr\n"
"MIME-Version: 1.0\n"
@ -13,393 +13,424 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Nešto nije u redu, pokušajte ponovno"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Nesposoban to učiniti"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Promjene se nisu mogle spremiti"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Nije moguće izbrisati"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s već postoji"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Nije pronađeno"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Datoteka nije pronađena"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Datoteka je prevelika"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Nepodržano"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Nepodržana vrsta"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Nepodržani format"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Originalna mapa je prazna"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Odabir nije pronađen"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entitet nije pronađen"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "račun nije pronađen"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Korisnik nije pronađen"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Oznaka nije pronađena"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kamera nije pronađena"
#: messages.go:130
msgid "Lens not found"
msgstr "Leća nije pronađena"
#: messages.go:131
msgid "Album not found"
msgstr "Album nije pronađen"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Predmet nije pronađen"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Osoba nije pronađena"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Lice nije pronađeno"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Nije dostupno u javnom načinu"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "nije dostupno u načinu samo za čitanje"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Molimo prijavite se i pokušajte ponovno"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Osoba je izbrisana"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Potrebno je plaćanje"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Prijenos bi mogao biti uvredljiv"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Prijenos nije uspio"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Nema odabranih stavki"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Izrada datoteke nije uspjela, provjerite dopuštenja"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Izrada mape nije uspjela, provjerite dopuštenja"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Povezivanje nije uspjelo, pokušajte ponovno"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Unesite kontrolni kod"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Nevažeći kontrolni kod, pokušajte ponovno"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Nevažeća lozinka, pokušajte ponovo"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Značajka je onemogućena"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Nije odabrana nijedna oznaka"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Nije odabran nijedan album"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Nema dostupnih datoteka za preuzimanje"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Izrada zip datoteke nije uspjela"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Nevažeće vjerodajnice"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Nevažeća veza"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Nevažeći naziv"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Zauzeto, pokušajte ponovo kasnije"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Interval buđenja je %s, ali mora biti 1 sat ili manje"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Vaš račun nije bilo moguće povezati"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Previše zahtjeva"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Nedovoljno prostora za pohranu"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kvota premašena"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registracija onemogućena"
#: messages.go:164
msgid "Verified email required"
msgstr "Potrebna je potvrđena e-pošta"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Promjene su uspješno spremljene"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album stvoren"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album je spremljen"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s je izbrisan"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Sadržaj albuma je kloniran"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Datoteka je uklonjena iz hrpe"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Datoteka je izbrisana"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Odabir je dodan u %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Jedan unos dodan u %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d unosi dodani u %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Jedan unos uklonjen iz %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d unosi uklonjeni iz %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Račun kreiran"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Račun spremljen"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Račun je izbrisan"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Postavke spremljene"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Lozinka je promijenjena"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Uvoz dovršen za %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Uvoz je otkazan"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indeksiranje dovršeno za %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indeksiranje originala..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indeksiranje datoteka u %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indeksiranje je otkazano"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Uklonjene %d datoteke i %d fotografije"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Premještanje datoteka iz %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Kopiranje datoteka s %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Oznake su izbrisane"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Oznaka je spremljena"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Predmet je spremljen"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Predmet je izbrisan"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Osoba je spremljena"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Osoba je izbrisana"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Datoteka je izbrisana"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d datoteke prenesene u %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Obrada prijenosa..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Prijenos bi mogao biti uvredljiv"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Odabir odobren"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Odabir je arhiviran"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Odabir je vraćen"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Odabir je označen kao privatan"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albumi su izbrisani"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip stvoren u %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Trajno izbrisano"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "Odabir je vraćen"
msgstr "%s je vraćen"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Uspješno potvrđeno"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Uspješno aktiviran"
#~ msgid "Storage is full"
#~ msgstr "Pohrana je puna"
#~ msgid "Invalid request"
#~ msgstr "Neispravan zahtjev"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: Hungarian <https://translate.photoprism.app/projects/"
"photoprism/backend/hu/>\n"
"Language: hu\n"
@ -13,393 +13,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Valami rosszul ment, próbálja újra"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Erre képtelen"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Módosításokat nem sikerült menteni"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Nem sikerült törölni"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s már létezik"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Nem található"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Fájl nem található"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Túl nagy fájl"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Nem támogatott"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Nem támogatott típus"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Nem támogatott formátum"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Az Originals mappa üres"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Kiválasztás nem található"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entitás nem található"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Fiók nem található"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Felhasználó nem található"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Címke nem található"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "A kamera nem található"
#: messages.go:130
msgid "Lens not found"
msgstr "A lencse nem található"
#: messages.go:131
msgid "Album not found"
msgstr "Album nem található"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Tárgy nem található"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Személy nem található"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Arc nem található"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Nyilvános módban nem elérhető"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Nem elérhető olvasói módban"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Kérjük, jelentkezzen be fiókjába"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Engedély megtagadva"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Fizetés szükséges"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "A feltöltött fájl sértő lehet"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Feltöltés sikertelen"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Nincsenek kiválasztva elemek"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Sikertelen fájl létrehozás. Kérjük, ellenőrizze a jogosultságokat"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Sikertelen mappa létrehozás. Kérjük, ellenőrizze a jogosultságokat"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Nem sikerült csatlakozni, próbálja újra"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Adja meg a megerősítő kódot"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Érvénytelen ellenőrző kód. Kérjük, próbálja újra"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Érvénytelen jelszó, próbálkozzon újra"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Funkció letiltva"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Nincsenek kiválasztva címkék"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Nincsenek kiválasztott albumok"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Nincsenek letölthető fájlok"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Nem sikerült létrehozni a zip fájlt"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Érvénytelen belépési adatok"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Érvénytelen hivatkozás"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Érvénytelen név"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Túl magas terhelés, próbálkozzon újra később"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Az ébresztési intervallum a %s, de legfeljebb 1 óra lehet."
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "A fiókját nem lehetett csatlakoztatni"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Túl sok kérés"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Elégtelen tárolás"
#: messages.go:162
msgid "Quota exceeded"
msgstr "A kvóta túllépése"
#: messages.go:163
msgid "Registration disabled"
msgstr "Regisztráció letiltva"
#: messages.go:164
msgid "Verified email required"
msgstr "Ellenőrzött e-mail cím szükséges"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Módosítások sikeresen mentve"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album létrehozva"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album mentve"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "%s album törölve"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Album tartalma klónozva"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Fájl eltávolítva a halomból"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Fájl törölve"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Választék hozzáadva a következőhöz: %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Egy bejegyzés hozzáadva a következőhöz: %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d bejegyzés hozzáadva a következőhöz: %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Egy bejegyzés eltávolítva innen: %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d bejegyzés eltávolítva innen: %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Fiók létrehozva"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Fiók mentve"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Fiók törölve"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Beállítások elmentve"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Jelszó megváltoztatva"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Importálás %d másodperc alatt befejeződött"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Importálás megszakítva"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexelés %d másodperc alatt befejeződött"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Eredeti dokumentumok indexelése..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Fájlok indexelése itt: %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indexelés megszakítva"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "%d fájl és %d fénykép eltávolítva"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Fájlok áthelyezése innen: %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Fájlok másolása innen: %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Címkék törölve"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Címkék mentve"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Tárgy mentve"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Tárgy törölve"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Személy mentve"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Személy törölve"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Fájl feltöltve"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d fájl feltöltve %d másodperc alatt"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Feltöltött fájlok feldolgozása..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Feltöltött fájlok feldolgozva"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "A kijelölés jóváhagyva"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "A kijelölés archiválva"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "A kijelölés visszaállítva"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "A kijelölés privátként megjelölve"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albumok törölve"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "A tömörített fájl létrejött %d másodperc alatt"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Véglegesen törölve"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s visszaállítva"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Sikeresen ellenőrizve"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Sikeres aktiválás"
#~ msgid "Storage is full"
#~ msgstr "A tároló megtelt"
#~ msgid "Invalid request"
#~ msgstr "Érvénytelen kérés"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: Indonesian <https://translate.photoprism.app/projects/"
"photoprism/backend/id/>\n"
"Language: id\n"
@ -13,393 +13,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Ada yang salah, coba lagi"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Tidak dapat melakukan itu"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Perubahan tidak dapat disimpan"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Tidak dapat dihapus"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s sudah ada"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Tidak ditemukan"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Berkas tidak ditemukan"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Berkas terlalu besar"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Tidak didukung"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Jenis tidak didukung"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Format yang tidak didukung"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Folder asli kosong"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Pilihan tidak ditemukan"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entitas tidak ditemukan"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Akun tidak ditemukan"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Pengguna tidak ditemukan"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Label tidak ditemukan"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kamera tidak ditemukan"
#: messages.go:130
msgid "Lens not found"
msgstr "Lensa tidak ditemukan"
#: messages.go:131
msgid "Album not found"
msgstr "Album tidak ditemukan"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Subjek tidak ditemukan"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Orang tidak ditemukan"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Wajah tidak ditemukan"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Tidak tersedia dalam mode publik"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Tidak tersedia dalam mode hanya-baca"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Silakan masuk ke akun Anda"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Izin ditolak"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Diperlukan pembayaran"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Unggahan mungkin menyinggung"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Unggahan gagal"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Tidak ada item yang dipilih"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Gagal membuat file, silakan periksa izin"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Gagal membuat folder, harap periksa izin"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Tidak dapat terhubung, silakan coba lagi"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Masukkan kode verifikasi"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Kode verifikasi tidak valid, silakan coba lagi"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Kata sandi salah, silakan coba lagi"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Fitur dinonaktifkan"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Tidak ada label yang dipilih"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Tidak ada album yang dipilih"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Tidak ada file yang tersedia untuk diunduh"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Gagal membuat file zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Kredensial tidak valid"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Tautan tidak valid"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Nama tidak valid"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Sibuk, silakan coba lagi nanti"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Interval wakeup adalah %s, tetapi harus 1 jam atau kurang"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Akun Anda tidak dapat terhubung"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Terlalu banyak permintaan"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Penyimpanan yang tidak memadai"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kuota terlampaui"
#: messages.go:163
msgid "Registration disabled"
msgstr "Pendaftaran dinonaktifkan"
#: messages.go:164
msgid "Verified email required"
msgstr "Email terverifikasi diperlukan."
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Perubahan berhasil disimpan"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album dibuat"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album disimpan"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s dihapus"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Konten album dikloning"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "File dihapus dari tumpukan"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Berkas dihapus"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Pilihan ditambahkan ke %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Satu entri ditambahkan ke %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d entri ditambahkan ke %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Satu entri dihapus dari %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d entri dihapus dari %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Akun dibuat"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Akun disimpan"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Akun dihapus"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Pengaturan disimpan"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Kata sandi diubah"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Impor selesai dalam %d detik"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Impor dibatalkan"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Pengindeksan selesai dalam %d detik"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Mengindeks dokumen asli..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Mengindeks file dalam %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Pengindeksan dibatalkan"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Menghapus %d file dan %d foto"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Memindahkan file dari %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Menyalin file dari %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Label dihapus"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Label disimpan"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Subjek disimpan"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Subjek dihapus"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Orang disimpan"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Orang dihapus"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "File diunggah"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d file diupload di %d detik"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Memproses unggahan..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Unggahan telah diproses"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Pilihan disetujui"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Pilihan diarsipkan"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Pilihan dipulihkan"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Pilihan ditandai sebagai pribadi"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Koleksi album dihapus"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip dibuat dalam %d detik"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Dihapus permanen"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s telah dipulihkan"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Berhasil diverifikasi"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Berhasil diaktifkan"
#~ msgid "Storage is full"
#~ msgstr "Penyimpanan penuh"
#~ msgid "Invalid request"
#~ msgstr "Permintaan tidak valid"

View file

@ -2,9 +2,9 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-09 06:08+0000\n"
"PO-Revision-Date: 2025-02-15 18:02+0000\n"
"Last-Translator: Andrea Risso <andry.riss@gmail.com>\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"
"Language-Team: Italian <https://translate.photoprism.app/projects/photoprism/"
"backend/it/>\n"
"Language: it\n"
@ -12,393 +12,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.9.2\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Qualcosa è andato storto, riprova"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Impossibile farlo"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Le modifiche non possono essere salvate"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Impossibile eliminare"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s esiste già"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Non trovato"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "File non trovato"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "File troppo grande"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Non supportato"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Formato non supportato"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Formato non supportato"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "La cartella degli originali è vuota"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Selezione non trovata"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entità non trovata"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Account non trovato"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Utente non trovato"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Etichetta non trovata"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Fotocamera non trovata"
#: messages.go:130
msgid "Lens not found"
msgstr "Obiettivo non trovato"
#: messages.go:131
msgid "Album not found"
msgstr "Album non trovato"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Soggetto non trovato"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Persona non trovata"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Faccia non trovata"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Non disponibile in modalità pubblica"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Non disponibile in modalità di sola lettura"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Accedere al proprio account"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Permesso negato"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Pagamento obbligatorio"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "L'upload potrebbe essere offensivo"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Upload fallito"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Nessun elemento selezionato"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Impossibile creare il file, si prega di controllare i permessi"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Impossibile creare la cartella, si prega di controllare i permessi"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Impossibile connettersi, si prega di riprovare"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Inserisci codice di verifca"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Codice di verifica errato, prova di nuovo"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Password non valida, si prega di riprovare"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Funzionalità disabilitata"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Nessuna etichetta selezionata"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Nessun album selezionato"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Nessun file è disponibile per il download"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Impossibile creare il file zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Credenziali non valide"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Link non valido"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Nome non valido"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Occupato, si prega di riprovare più tardi"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "L'intervallo di risveglio è %s, ma deve essere pari o inferiore a 1h"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Non è stato possibile collegare l'account"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Troppe richieste"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Stoccaggio insufficiente"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Quota superata"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registrazione disabilitata"
#: messages.go:164
msgid "Verified email required"
msgstr "È necessario un indirizzo e-mail verificato"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Modifiche salvate con successo"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album creato"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album salvato"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s eliminato"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "I contenuti dell'album sono stati duplicati"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "File rimosso dallo stack"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "File eliminato"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Selezione aggiunta a %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Un elemento aggiunto a %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d elementi aggiunti a %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Un elemento rimosso da %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d elementi rimossi da %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Account creato"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Account salvato"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Account eliminato"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Impostazioni salvate"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Password cambiata"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Importazione completata in %d secondi"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Importazione cancellata"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indicizzazione completata in %d secondi"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indicizzando gli originali..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indicizzazione dei file in %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indicizzazione cancellata"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Rimossi %d file e %d foto"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Spostamento dei file da %s in corso"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Copia dei file da %s in corso"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Etichette eliminate"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Etichetta salvata"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Soggetto salvato"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Soggetto cancellato"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Persona salvata"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Persona cancellata"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "File caricato"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d file caricati in %d secondi"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Elaborazione del caricamento..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Il caricamento è stato elaborato"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Selezione approvata"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Selezione archiviata"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Selezione ripristinata"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Selezione impostata come privata"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Album eliminati"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip creato in %d secondi"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Eliminato permanentemente"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s è stato ripristinato"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Verifica avvenuta con successo"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Attivazione avvenuta con successo"
#~ msgid "Storage is full"
#~ msgstr "La memoria è piena"
#~ msgid "Invalid request"
#~ msgstr "Richiesta non valida"

View file

@ -2,404 +2,434 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: Japanese <https://translate.photoprism.app/projects/"
"photoprism/backend/ja/>\n"
"Language: ja_JP\n"
"Language: ja\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "問題が発生しました。もう一度やり直してください"
msgstr "何かが間違っています。もう一度やり直してください"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "実行できませんでした"
msgstr "その操作はできません"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "変更を保存できませんでした"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "削除できませんでした"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s は既に存在します"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "見つかりませんでした"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "ファイルが見つかりませんでした"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "ファイルサイズが大きすぎます"
msgstr "ファイルが大きすぎます"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "サポートされていません"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "サポートされていないタイプ"
msgstr "サポートされていない形式です"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "非対応のフォーマットです"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Originalsフォルダーが空です"
msgstr "Originals フォルダーは空です"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "選択した項目は存在しません"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "エンティティが見つかりません"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "アカウント存在しません"
msgstr "アカウント存在しません"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "ユーザ存在しません"
msgstr "ユーザーが存在しません"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "ラベル存在しません"
msgstr "ラベル存在しません"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "カメラが見つかりません"
#: messages.go:130
msgid "Lens not found"
msgstr "レンズが見つからない"
#: messages.go:131
msgid "Album not found"
msgstr "アルバムは存在しません"
msgstr "アルバム存在しません"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "件名が見つかりません"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "人が見つかりません"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "顔を検出できませんでした"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "公開モードでは利用できません"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "読み込み専用モードでは利用できません"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "アカウントにログインしてください"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "アクセス拒否"
msgstr "アクセス拒否されました"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "要支払い"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "アップロードされた項目に過激なものが含まれている可能性があります"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "アップロード失敗"
msgstr "アップロード失敗しました"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "項目が選択されていません"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "ファイルの作成に失敗しました権限を確認してください"
msgstr "ファイルの作成に失敗しました権限を確認してください"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "フォルダの作成に失敗しました権限を確認してください"
msgstr "フォルダの作成に失敗しました権限を確認してください"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "接続できませんでした、再度試してみてください"
msgstr "接続できませんでした。もう一度お試しください"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "認証コードを入力してください"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "認証コードが無効です。もう一度お試しください"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "不正なパスワードです、再度試してみてください"
msgstr "不正なパスワードです。もう一度お試しください"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "機能が無効になりました"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "ラベルが選択されていません"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "アルバムが選択されていません"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "ダウンロードできるファイルはありません"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "zip ファイルの作成に失敗しました"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "不正な認証情報"
msgstr "正しくない認証情報です"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "不正なリンク"
msgstr "正しくないリンクです"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "無効なバケット名"
msgstr "無効な名前です"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "混雑しています、後で再試行してください"
msgstr "他の処理中です。後で再試行してください"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "ウェイクアップ間隔は%sであるが、1h以下でなければならない"
msgstr "ウェイクアップ間隔は %s ですが、1時間以内で指定する必要があります"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "お客様のアカウントに接続できませんでした"
msgstr "アカウントに接続できませんでした"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "リクエストが多すぎます"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "ストレージが不足しています"
#: messages.go:162
msgid "Quota exceeded"
msgstr "ノルマ超過"
#: messages.go:163
msgid "Registration disabled"
msgstr "登録が無効になっている"
#: messages.go:164
msgid "Verified email required"
msgstr "確認済みのメールアドレスが必要だ"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "変更が正常に保存されました"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "アルバムを作成しました"
msgstr "アルバムが作成されました"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "アルバムを保存しました"
msgstr "アルバムが保存されました"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "アルバム %s を削除しました"
msgstr "アルバム %s が削除されました"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "アルバムの内容が複製されました"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "スタックからファイルが削除されました"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "ファイルが削除されました"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "選択した項目が %s に追加されました"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "1 件の項目が %s に追加されました"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d 件の項目が %s に追加されました"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "1 件の項目が %s から削除されました"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d 件の項目が %s から削除されました"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "アカウントが作成されました"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "アカウントが保存されました"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "アカウントが削除されました"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "設定が保存されました"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "パスワードが変更されました"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "インポートが %d 秒で完了しました"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "インポートが取り消されました"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "インデックスが %d 秒で完了しました"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "オリジナルの項目をインデックスしています..."
msgstr "originals をインデックスしています..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "%s 内のファイルをインデックスしています"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "インデックスが取り消されました"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "%d 件のファイルと %d 件の写真が削除されました"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "%s からファイルを移動しています"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "%s からファイルをコピーしています"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "ラベルが削除されました"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "ラベルが保存されました"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "保存対象"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "件名 削除"
msgstr "件名を削除しました"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "保存された人"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "削除された人"
msgstr "人を削除しました"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "アップロードされたファイル"
msgstr "ファイルがアップロードされました"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d 件のファイルを %d 秒でアップロードしました"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "アップロードの処理..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "アップロードが処理されました"
msgstr "アップロードが完了しました"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "選択した項目が承認されました"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "選択した項目がアーカイブされました"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "選択した項目が復元されました"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "選択した項目をプライベートにしました"
msgstr "選択した項目がプライベートに設定されました"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "アルバムが削除されました"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "%d 秒で zip ファイルを作成しました"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "永久に削除"
msgstr "完全に削除されました"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s が復元されました"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "検証に成功しました"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "正常に有効化されました"
#~ msgid "Storage is full"
#~ msgstr "ストレージは満杯だ"
#~ msgid "Invalid request"
#~ msgstr "不正なリクエスト"

View file

@ -2,10 +2,9 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: Korean <https://translate.photoprism.app/projects/photoprism/"
"backend/ko/>\n"
"Language: ko\n"
@ -13,393 +12,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "문제가 발생했습니다. 다시 시도하세요."
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "그렇게 할 수 없습니다."
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "변경 사항을 저장할 수 없음"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "삭제할 수 없음"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s가 이미 존재함"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "찾을 수 없음"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "파일을 찾을 수 없음"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "파일이 너무 큽니다"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "지원되지 않음"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "지원되지 않는 유형"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "지원되지 않는 형식"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "원본 폴더가 비어 있습니다"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "선택 항목을 찾을 수 없음"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "항목을 찾을 수 없음"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "계정을 찾을 수 없음"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "사용자를 찾을 수 없음"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "라벨을 찾을 수 없음"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "카메라를 찾을 수 없습니다"
#: messages.go:130
msgid "Lens not found"
msgstr "렌즈를 찾을 수 없습니다"
#: messages.go:131
msgid "Album not found"
msgstr "앨범을 찾을 수 없음"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "제목을 찾을 수 없음"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "사람을 찾을 수 없음"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "얼굴을 찾을 수 없음"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "공개 모드에서는 사용할 수 없음"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "읽기 전용 모드에서는 사용할 수 없음"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "귀하의 계정에 로그인하십시오"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "권한이 없음"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "결제 필요"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "업로드가 불쾌할 수 있습니다"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "업로드 실패"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "선택된 항목이 없습니다"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "파일 생성에 실패했습니다. 권한을 확인하세요"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "폴더를 만들지 못했습니다. 권한을 확인하세요"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "연결할 수 없습니다. 다시 시도해 주세요"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "인증코드를 입력하세요"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "잘못된 인증 코드입니다. 다시 시도해 주세요."
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "비밀번호가 잘못되었습니다. 다시 시도해 주세요"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "기능 비활성화됨"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "선택한 라벨이 없습니다"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "앨범이 선택되지 않았습니다"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "다운로드할 수 있는 파일이 없습니다"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "zip 파일 생성 실패"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "잘못된 자격 증명"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "유효하지 않은 링크입니다"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "잘못된 이름"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "바쁘니 나중에 다시 시도해 주세요"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "깨우기 간격은 %s이지만 1시간 이하여야 합니다"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "계정을 연결할 수 없습니다"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "너무 많은 요청"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "저장 공간 부족"
#: messages.go:162
msgid "Quota exceeded"
msgstr "할당량 초과"
#: messages.go:163
msgid "Registration disabled"
msgstr "등록이 비활성화되었습니다."
#: messages.go:164
msgid "Verified email required"
msgstr "인증된 이메일 주소가 필요합니다"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "변경사항이 성공적으로 저장되었습니다"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "앨범 생성됨"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "앨범 저장됨"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "앨범 %s이(가) 삭제됨"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "복제된 앨범 콘텐츠"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "스택에서 제거된 파일"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "파일이 삭제됨"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "선택 항목이 %s에 추가됨"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "%s에 항목 1개 추가됨"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d 항목이 %s에 추가됨"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "%s에서 항목 1개 삭제됨"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d 항목이 %s에서 제거됨"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "계정 생성됨"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "계정이 저장됨"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "계정 삭제됨"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "설정 저장됨"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "비밀번호 변경됨"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "%d초 후에 가져오기 완료"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "가져오기 취소됨"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "%d초 후에 인덱싱 완료"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "원본 색인 생성 중..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "%s에서 파일 색인 생성"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "인덱싱 취소됨"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "파일 %d개와 사진 %d개를 삭제했습니다"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "%s에서 파일 이동"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "%s에서 파일 복사"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "라벨 삭제됨"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "라벨이 저장되었습니다"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "주제가 저장됨"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "제목 삭제됨"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "사람이 저장됨"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "삭제된 사람"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "업로드된 파일 1개"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d개의 파일이 %d초에 업로드됨"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "업로드 처리 중..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "업로드가 처리되었습니다"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "선택 항목 승인됨"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "선택 항목 보관됨"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "선택 항목 복원됨"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "비공개로 표시된 선택"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "앨범 삭제됨"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "%d초에 생성된 우편번호"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "영구 삭제됨"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s이(가) 복원되었습니다"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "성공적으로 확인되었습니다"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "성공적으로 활성화되었습니다"
#~ msgid "Storage is full"
#~ msgstr "저장 공간이 가득 찼습니다."
#~ msgid "Invalid request"
#~ msgstr "잘못된 요청"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: Kurdish <https://translate.photoprism.app/projects/photoprism/"
"backend/ku/>\n"
"Language: ku\n"
@ -13,393 +13,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Tiştek xelet derket, dîsa biceribîne"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Nikarin vê yekê bikin"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "گۆڕانکاریەکان پاشەکەوت نەکراوە"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "نەتوانرا بسڕێتەوە"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s پێشتر هەیە"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "نەدۆزرایەوە"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "دۆسیەکە نەدۆزرایەوە"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Pelê pir mezin e"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Piştgirî nekirin"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Cureyê ne piştgirî"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Format nayê destek kirin"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Peldanka orjînal vala ye"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "هەڵبژاردەکان نەدۆزرایەوە"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "هیچ ئەلبومێکی نەدۆزیوەتەوە"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "هەژمارەکە نەدۆزرایەوە"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "بەکارهێنەرەکە نەدۆزرایەوە"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "پێناسەکە نەدۆزرایەوە"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kamera nehat dîtin"
#: messages.go:130
msgid "Lens not found"
msgstr "Lens nehat dîtin"
#: messages.go:131
msgid "Album not found"
msgstr "ئەلبومەکە نەدۆزرایەوە"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "ناونیشان"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "هیچ ئەلبومێکی نەدۆزیوەتەوە"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "نەدۆزرایەوە"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "بەردەست نیە بۆ دۆخی گشتی"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "بەردەست نییە لە دۆخی تەنها-خوێندنەوە"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "تکایە تێپەڕبە پاشان هەوڵبدەرەوە"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "ئەلبومەکان سڕانەوە"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Pêdivî bi dravdanê heye"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "بارکردن لەوانەیە سووکایەتی بێت"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "بارکردنەکە سەرکەوتوو نەبوو"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "هیچ ئایتمێک دەستنیشان نەکراوە"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "شکست لە دروستکردنی پەڕگە، تکایە مۆڵەتەکان بپشکنە"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "شکست لە دروستکردنی بوخچە، تکایە مۆڵەتەکان بپشکنە"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "نەیتوانی پەیوەندی بگرێت، تکایە دووبارە هەوڵ بدەوە"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Koda verastkirinê binivîse"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Koda verastkirinê nederbasdar e, ji kerema xwe dîsa biceribîne"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "تێپەرەوشە هەڵەیە، تکایە جارێکی تر هەوڵبدەوە"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "تایبەتمەندی ناچالاک کراوە"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "هیج لە پێناسەکان هەڵنەبژێردراوە"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "هیج لە ئەلبومەکان هەڵنەبژێردراوە"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "هیچ پەڕگەیەک ئامادە نیە بۆ داگرتن"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "دروستکردنی فایلی زیپ سەرکەوتوو نەبوو"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "زانیارییەکان نادروستە"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "بەستەرەکە نادروستە"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "بەروارێکی نادروست"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "تێپەرەوشە هەڵەیە، تکایە جارێکی تر هەوڵبدەوە"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Navbera hişyarbûnê %s ye, lê divê 1h an kêmtir be"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Hesabê te nehat girêdan"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Pir daxwazî"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Depo ne bes e"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kota derbas kir"
#: messages.go:163
msgid "Registration disabled"
msgstr "Qeydkirin neçalak e"
#: messages.go:164
msgid "Verified email required"
msgstr "E-nameya piştrastkirî pêwîst e"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "گۆڕانکاریەکان سەرکەوتوانە پاشەکەوتکرا"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "ئەلبومەکە دروستکرا"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "ئەلبومەکە پاشەکەوتکرا"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "ئەلبومی %s سڕایەوە"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "ناوەڕۆکەکانی ئەلبومەکە هاووێنە کرا"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "دۆسیەکە کۆژاوەتەوە لە کەڵەکەکە"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "پەڕگە سڕایەوە"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "دەستنیشان کراو زیادکرایە %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "یەک تێکراو زیاد کرایە %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d تێکراو زیاد کرایە %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "یەک تێکراو لابرا لە %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d تێکراو لابرا لە %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "هەژمارەکە دروستکرا"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "هەژمارەکە پاشەکەوتکرا"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "هەژمارەکە سڕایەوە"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "ڕێکخستنەکان پاشەکەوتکرا"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "تێپەڕەوشە گۆڕدرا"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "هاوردن تەواو بوو بە %d چرکە"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "هاوردن هەڵوەشێنرایەوە"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "نیشانە کردن تەواو بوو بە %d چرکە"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "نیشانەکردنی ڕەسەنەکان..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "نیشانەکردنی پەڕگەکان لە %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "نیشانەکردن هەڵوەشێنرایەوە"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "لابردنی %d پەڕگە و %d وێنە"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "گواستنەوەی پەڕگە لە %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "کۆپی کردنی پەڕگە لە%s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "پێناسەکان سڕانەوە"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "پێناسەکە پاشەکەوتکرا"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "ناونیشان"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "ناونیشان"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "ڕێکخستنەکان پاشەکەوتکراو"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "ئەلبومەکان سڕانەوە"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "پەڕگە سڕایەوە"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d پەڕگە بارکرە بە %d چرکە"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Pêvajoya barkirinê..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "بارکردن لەوانەیە سووکایەتی بێت"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "دەستنیشان کراو پەسەند کرا"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "هەڵبژاردەکە ئەرشیفکرا"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "هەڵبژاردەکە دووبارەکۆگاکرایەوە"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "دەستنیشانکراوەکان کران بە تایبەتی"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "ئەلبومەکان سڕایەوە"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "زیپ بە %d چرکە دروستکرا"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "بە هەمیشەیی سڕاوەتەوە"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "هەڵبژاردەکە دووبارەکۆگاکرایەوە"
msgstr "%s دووبارە کۆگاکرایەوە"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Bi serketî verast kirin"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Bi serketî hate aktîfkirin"
#~ msgid "Storage is full"
#~ msgstr "Storage tije ye"
#~ msgid "Invalid request"
#~ msgstr "داواکاری نادروست"

View file

@ -2,10 +2,9 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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"
"Language-Team: none\n"
"Language: lt\n"
"MIME-Version: 1.0\n"
@ -14,393 +13,424 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n % 10 == 1 && (n % 100 < 11 || n % 100 > "
"19)) ? 0 : ((n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19)) ? "
"1 : 2);\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Kažkas nepavyko, bandykite dar kartą"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Nepavyksta to padaryti"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Pakeitimų nepavyko išsaugoti"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Negalima ištrinti"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s jau egzistuoja"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Nerasta"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Failo rasti nepavyko"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Per didelis failas"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Nepalaikoma"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Nepalaikomas tipas"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Nepalaikomas formatas"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Originalų aplankas tuščias"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Pasirinkimas nerastas"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Subjektas nerastas"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Paskyra nerasta"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Vartotojas nerastas"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Etiketė nerasta"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kameros nerasta"
#: messages.go:130
msgid "Lens not found"
msgstr "Objektyvas nerastas"
#: messages.go:131
msgid "Album not found"
msgstr "Albumas nerastas"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Tema nerasta"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Asmuo nerastas"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Veidas nerastas"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Negalima naudoti viešuoju režimu"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Negalima naudoti tik skaitymo režimu"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Prisijunkite prie savo paskyros"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Priėjimas neimanomas"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Reikalingas mokėjimas"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Įkėlimas gali būti įžeidžiantis"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Įkelti nepavyko"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Nėra pasirinktų elementų"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Nepavyko sukurti failo, patikrinkite leidimus"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Nepavyko sukurti aplanko, patikrinkite leidimus"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Nepavyko prisijungti, bandykite dar kartą"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Įveskite patvirtinimo kodą"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Neteisingas patvirtinimo kodas, bandykite dar kartą"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Netinkamas slaptažodis, bandykite dar kartą"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Funkcija išjungta"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Nėra pasirinktų etikečių"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Nėra pasirinktų albumų"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Nėra parsisiunčiamų failų"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Nepavyko sukurti zip failo"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Neteisingi įgaliojimai"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Netinkama nuoroda"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Netinkamas pavadinimas"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Užimta, bandykite vėliau"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Budinimo intervalas yra %s, bet turi būti ne ilgesnis kaip 1 val"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Nepavyko prisijungti prie jūsų paskyros"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Per daug prašymų"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Nepakankama saugykla"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Viršyta kvota"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registracija išjungta"
#: messages.go:164
msgid "Verified email required"
msgstr "Reikalingas patvirtintas el. pašto adresas"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Pakeitimai sėkmingai išsaugoti"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Sukurtas albumas"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Išsaugotas albumas"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Albumas %s pašalintas"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Klonuotas albumo turinys"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Failas pašalintas iš kamino"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Ištrintas failas"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Pasirinkimas pridėtas prie %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Vienas įrašas pridėtas prie %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d įrašai, įtraukti į %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Vienas įrašas pašalintas iš %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d įrašai pašalinti iš %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Sukurta paskyra"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Išsaugota paskyra"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Ištrinta paskyra"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Nustatymai išsaugoti"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Slaptažodis pakeistas"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Importas baigtas per %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Importas atšauktas"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indeksavimas baigtas per %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Originalų indeksavimas..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Failų indeksavimas %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indeksavimas atšauktas"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Pašalinti %d failai ir %d nuotraukos"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Failų perkėlimas iš %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Failų kopijavimas iš %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Ištrintos etiketės"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Išsaugota etiketė"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Tema - išsaugotas"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Išbrauktas objektas"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Išsaugotas asmuo"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Išbrauktas asmuo"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Įkeltas failas"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d failai įkelti per %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Įkėlimo apdorojimas..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Įkėlimas apdorotas"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Patvirtinta atranka"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Atranka archyvuota"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Atkurta atranka"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Atranka pažymėta kaip privati"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Ištrinti albumai"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip sukurta %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Visam laikui ištrintas"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s buvo atkurta"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Sėkmingai patvirtinta"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Sėkmingai suaktyvinta"
#~ msgid "Storage is full"
#~ msgstr "Saugykla užpildyta"
#~ msgid "Invalid request"
#~ msgstr "Neleistina užklausa"

View file

@ -0,0 +1,434 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\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-"
"translate@weblate.org>\n"
"Language-Team: none\n"
"Language: lv\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n % 10 == 0 || n % 100 >= 11 && n % 100 <= "
"19) ? 0 : ((n % 10 == 1 && n % 100 != 11) ? 1 : 2);\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Kaut kas nogāja greizi, mēģiniet vēlreiz"
#: messages.go:113
msgid "Unable to do that"
msgstr "To nevar izdarīt"
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Izmaiņas nevarēja saglabāt"
#: messages.go:115
msgid "Could not be deleted"
msgstr "Nevarēja izdzēst"
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s jau pastāv"
#: messages.go:117
msgid "Not found"
msgstr "Nav atrasts"
#: messages.go:118
msgid "File not found"
msgstr "Fails nav atrasts"
#: messages.go:119
msgid "File too large"
msgstr "Fails ir pārāk liels"
#: messages.go:120
msgid "Unsupported"
msgstr "Neatbalstīts"
#: messages.go:121
msgid "Unsupported type"
msgstr "Neatbalstīts tips"
#: messages.go:122
msgid "Unsupported format"
msgstr "Neatbalstīts formāts"
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Oriģinālu mape ir tukša"
#: messages.go:124
msgid "Selection not found"
msgstr "Izvēle nav atrasta"
#: messages.go:125
msgid "Entity not found"
msgstr "Vienība nav atrasta"
#: messages.go:126
msgid "Account not found"
msgstr "Konts nav atrasts"
#: messages.go:127
msgid "User not found"
msgstr "Lietotājs nav atrasts"
#: messages.go:128
msgid "Label not found"
msgstr "Birka nav atrasta"
#: messages.go:129
msgid "Camera not found"
msgstr "Kamera nav atrasta"
#: messages.go:130
msgid "Lens not found"
msgstr "Objektīvs nav atrasts"
#: messages.go:131
msgid "Album not found"
msgstr "Albums nav atrasts"
#: messages.go:132
msgid "Subject not found"
msgstr "Tēma nav atrasta"
#: messages.go:133
msgid "Person not found"
msgstr "Persona nav atrasta"
#: messages.go:134
msgid "Face not found"
msgstr "Seja nav atrasta"
#: messages.go:135
msgid "Not available in public mode"
msgstr "Nav pieejams publiskajā režīmā"
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Nav pieejams lasīšanas režīmā"
#: messages.go:137
msgid "Please log in to your account"
msgstr "Lūdzu, piesakieties savā kontā"
#: messages.go:138
msgid "Permission denied"
msgstr "Atļauja liegta"
#: messages.go:139
msgid "Payment required"
msgstr "Nepieciešams maksājums"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Augšupielāde varētu būt aizskaroša"
#: messages.go:141
msgid "Upload failed"
msgstr "Augšupielāde neizdevās"
#: messages.go:142
msgid "No items selected"
msgstr "Nav izvēlēts neviens ieraksts"
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Neizdevās izveidot failu, lūdzu, pārbaudiet atļaujas"
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Neizdevās izveidot mapi, lūdzu, pārbaudiet atļaujas"
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Nevarēja izveidot savienojumu, lūdzu, mēģiniet vēlreiz"
#: messages.go:146
msgid "Enter verification code"
msgstr "Ievadiet verifikācijas kodu"
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Nederīgs verifikācijas kods, lūdzu, mēģiniet vēlreiz"
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Nederīga parole, lūdzu, mēģiniet vēlreiz"
#: messages.go:149
msgid "Feature disabled"
msgstr "Funkcionalitāte ir izslēgta"
#: messages.go:150
msgid "No labels selected"
msgstr "Nav atlasītas nevienas birkas"
#: messages.go:151
msgid "No albums selected"
msgstr "Nav atlasīts neviens albums"
#: messages.go:152
msgid "No files available for download"
msgstr "Nav lejupielādei pieejamu failu"
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Neizdevās izveidot zip failu"
#: messages.go:154
msgid "Invalid credentials"
msgstr "Nederīgs lietotājvārds vai parole"
#: messages.go:155
msgid "Invalid link"
msgstr "Nederīga saite"
#: messages.go:156
msgid "Invalid name"
msgstr "Nederīgs nosaukums"
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Aizņemts, lūdzu, mēģiniet vēlreiz vēlāk"
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Pamošanās intervāls ir %s, bet tam jābūt 1 h vai mazākam"
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Jūsu kontu nevarēja savienot"
#: messages.go:160
msgid "Too many requests"
msgstr "Pārāk daudz pieprasījumu"
#: messages.go:161
msgid "Insufficient storage"
msgstr "Nepietiek brīvas vietas"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kvota pārsniegta"
#: messages.go:163
msgid "Registration disabled"
msgstr "Reģistrācija atspējota"
#: messages.go:164
msgid "Verified email required"
msgstr "Nepieciešama verificēta e-pasta adrese"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Izmaiņas veiksmīgi saglabātas"
#: messages.go:168
msgid "Album created"
msgstr "Albums izveidots"
#: messages.go:169
msgid "Album saved"
msgstr "Albums saglabāts"
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Albums %s ir dzēsts"
#: messages.go:171
msgid "Album contents cloned"
msgstr "Albuma saturs ir dublēts"
#: messages.go:172
msgid "File removed from stack"
msgstr "Fails izņemts no saraksta"
#: messages.go:173
msgid "File deleted"
msgstr "Fails izdzēsts"
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Atlasījums pievienots %s"
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Viens ieraksts pievienots %s"
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d ieraksti pievienoti %s"
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Viens ieraksts noņemts no %s"
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d ieraksti noņemti no %s"
#: messages.go:179
msgid "Account created"
msgstr "Konts izveidots"
#: messages.go:180
msgid "Account saved"
msgstr "Konts saglabāts"
#: messages.go:181
msgid "Account deleted"
msgstr "Konts ir dzēsts"
#: messages.go:182
msgid "Settings saved"
msgstr "Iestatījumi saglabāti"
#: messages.go:183
msgid "Password changed"
msgstr "Parole nomainīta"
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Importēšana pabeigta %d s laikā"
#: messages.go:185
msgid "Import canceled"
msgstr "Importēšana atcelta"
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indeksēšana pabeigta %d s laikā"
#: messages.go:187
msgid "Indexing originals..."
msgstr "Notiek oriģinālu indeksēšana..."
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Notiek failu indeksēšana %s"
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indeksēšana atcelta"
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Noņemti %d faili un %d fotoattēli"
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Failu pārvietošana no %s"
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Failu kopēšana no %s"
#: messages.go:193
msgid "Labels deleted"
msgstr "Birkas ir dzēstas"
#: messages.go:194
msgid "Label saved"
msgstr "Birka saglabāta"
#: messages.go:195
msgid "Subject saved"
msgstr "Tēma saglabāta"
#: messages.go:196
msgid "Subject deleted"
msgstr "Tēma dzēsta"
#: messages.go:197
msgid "Person saved"
msgstr "Persona saglabāta"
#: messages.go:198
msgid "Person deleted"
msgstr "Persona dzēsta"
#: messages.go:199
msgid "File uploaded"
msgstr "Fails augšupielādēts"
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d faili augšupielādēti %d sekundēs"
#: messages.go:201
msgid "Processing upload..."
msgstr "Notiek augšupielādes apstrāde..."
#: messages.go:202
msgid "Upload has been processed"
msgstr "Augšupielāde ir apstrādāta"
#: messages.go:203
msgid "Selection approved"
msgstr "Atlase apstiprināta"
#: messages.go:204
msgid "Selection archived"
msgstr "Atlase arhivēta"
#: messages.go:205
msgid "Selection restored"
msgstr "Atlase atjaunota"
#: messages.go:206
msgid "Selection marked as private"
msgstr "Izvēle atzīmēta kā privāta"
#: messages.go:207
msgid "Albums deleted"
msgstr "Albumi ir dzēsti"
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "ZIP fails izveidots %d sekundēs"
#: messages.go:209
msgid "Permanently deleted"
msgstr "Neatgriezeniski dzēsts"
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s ir atjaunots"
#: messages.go:211
msgid "Successfully verified"
msgstr "Veiksmīgi verificēts"
#: messages.go:212
msgid "Successfully activated"
msgstr "Veiksmīgi aktivizēts"

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-09 06:08+0000\n"
"POT-Creation-Date: 2026-06-27 09:13+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,387 +17,415 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr ""
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr ""
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr ""
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr ""
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr ""
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr ""
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr ""
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr ""
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr ""
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr ""
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr ""
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr ""
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr ""
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr ""
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr ""
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr ""
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr ""
#: messages.go:118
msgid "Album not found"
msgstr ""
#: messages.go:119
msgid "Subject not found"
msgstr ""
#: messages.go:120
msgid "Person not found"
msgstr ""
#: messages.go:121
msgid "Face not found"
msgstr ""
#: messages.go:122
msgid "Not available in public mode"
msgstr ""
#: messages.go:123
msgid "Not available in read-only mode"
msgstr ""
#: messages.go:124
msgid "Please log in to your account"
msgstr ""
#: messages.go:125
msgid "Permission denied"
msgstr ""
#: messages.go:126
msgid "Upload might be offensive"
msgstr ""
#: messages.go:127
msgid "Upload failed"
msgstr ""
#: messages.go:128
msgid "No items selected"
msgstr ""
#: messages.go:129
msgid "Failed creating file, please check permissions"
msgid "Camera not found"
msgstr ""
#: messages.go:130
msgid "Failed creating folder, please check permissions"
msgid "Lens not found"
msgstr ""
#: messages.go:131
msgid "Could not connect, please try again"
msgid "Album not found"
msgstr ""
#: messages.go:132
msgid "Enter verification code"
msgid "Subject not found"
msgstr ""
#: messages.go:133
msgid "Invalid verification code, please try again"
msgid "Person not found"
msgstr ""
#: messages.go:134
msgid "Invalid password, please try again"
msgid "Face not found"
msgstr ""
#: messages.go:135
msgid "Feature disabled"
msgid "Not available in public mode"
msgstr ""
#: messages.go:136
msgid "No labels selected"
msgid "Not available in read-only mode"
msgstr ""
#: messages.go:137
msgid "No albums selected"
msgid "Please log in to your account"
msgstr ""
#: messages.go:138
msgid "No files available for download"
msgid "Permission denied"
msgstr ""
#: messages.go:139
msgid "Failed to create zip file"
msgid "Payment required"
msgstr ""
#: messages.go:140
msgid "Invalid credentials"
msgid "Upload might be offensive"
msgstr ""
#: messages.go:141
msgid "Invalid link"
msgid "Upload failed"
msgstr ""
#: messages.go:142
msgid "Invalid name"
msgid "No items selected"
msgstr ""
#: messages.go:143
msgid "Busy, please try again later"
msgid "Failed creating file, please check permissions"
msgstr ""
#: messages.go:144
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgid "Failed creating folder, please check permissions"
msgstr ""
#: messages.go:145
msgid "Your account could not be connected"
msgid "Could not connect, please try again"
msgstr ""
#: messages.go:146
msgid "Too many requests"
msgid "Enter verification code"
msgstr ""
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr ""
#: messages.go:148
msgid "Invalid password, please try again"
msgstr ""
#: messages.go:149
msgid "Changes successfully saved"
msgid "Feature disabled"
msgstr ""
#: messages.go:150
msgid "Album created"
msgid "No labels selected"
msgstr ""
#: messages.go:151
msgid "Album saved"
msgid "No albums selected"
msgstr ""
#: messages.go:152
#, c-format
msgid "Album %s deleted"
msgid "No files available for download"
msgstr ""
#: messages.go:153
msgid "Album contents cloned"
msgid "Failed to create zip file"
msgstr ""
#: messages.go:154
msgid "File removed from stack"
msgid "Invalid credentials"
msgstr ""
#: messages.go:155
msgid "File deleted"
msgid "Invalid link"
msgstr ""
#: messages.go:156
#, c-format
msgid "Selection added to %s"
msgid "Invalid name"
msgstr ""
#: messages.go:157
#, c-format
msgid "One entry added to %s"
msgid "Busy, please try again later"
msgstr ""
#: messages.go:158
#, c-format
msgid "%d entries added to %s"
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr ""
#: messages.go:159
#, c-format
msgid "One entry removed from %s"
msgid "Your account could not be connected"
msgstr ""
#: messages.go:160
#, c-format
msgid "%d entries removed from %s"
msgid "Too many requests"
msgstr ""
#: messages.go:161
msgid "Account created"
msgid "Insufficient storage"
msgstr ""
#: messages.go:162
msgid "Account saved"
msgid "Quota exceeded"
msgstr ""
#: messages.go:163
msgid "Account deleted"
msgid "Registration disabled"
msgstr ""
#: messages.go:164
msgid "Settings saved"
msgstr ""
#: messages.go:165
msgid "Password changed"
msgstr ""
#: messages.go:166
#, c-format
msgid "Import completed in %d s"
msgid "Verified email required"
msgstr ""
#: messages.go:167
msgid "Import canceled"
msgid "Changes successfully saved"
msgstr ""
#: messages.go:168
#, c-format
msgid "Indexing completed in %d s"
msgid "Album created"
msgstr ""
#: messages.go:169
msgid "Indexing originals..."
msgid "Album saved"
msgstr ""
#: messages.go:170
#, c-format
msgid "Indexing files in %s"
msgid "Album %s deleted"
msgstr ""
#: messages.go:171
msgid "Indexing canceled"
msgid "Album contents cloned"
msgstr ""
#: messages.go:172
#, c-format
msgid "Removed %d files and %d photos"
msgid "File removed from stack"
msgstr ""
#: messages.go:173
#, c-format
msgid "Moving files from %s"
msgid "File deleted"
msgstr ""
#: messages.go:174
#, c-format
msgid "Copying files from %s"
msgid "Selection added to %s"
msgstr ""
#: messages.go:175
msgid "Labels deleted"
#, c-format
msgid "One entry added to %s"
msgstr ""
#: messages.go:176
msgid "Label saved"
#, c-format
msgid "%d entries added to %s"
msgstr ""
#: messages.go:177
msgid "Subject saved"
#, c-format
msgid "One entry removed from %s"
msgstr ""
#: messages.go:178
msgid "Subject deleted"
#, c-format
msgid "%d entries removed from %s"
msgstr ""
#: messages.go:179
msgid "Person saved"
msgid "Account created"
msgstr ""
#: messages.go:180
msgid "Person deleted"
msgid "Account saved"
msgstr ""
#: messages.go:181
msgid "File uploaded"
msgid "Account deleted"
msgstr ""
#: messages.go:182
#, c-format
msgid "%d files uploaded in %d s"
msgid "Settings saved"
msgstr ""
#: messages.go:183
msgid "Processing upload..."
msgid "Password changed"
msgstr ""
#: messages.go:184
msgid "Upload has been processed"
#, c-format
msgid "Import completed in %d s"
msgstr ""
#: messages.go:185
msgid "Selection approved"
msgid "Import canceled"
msgstr ""
#: messages.go:186
msgid "Selection archived"
#, c-format
msgid "Indexing completed in %d s"
msgstr ""
#: messages.go:187
msgid "Selection restored"
msgid "Indexing originals..."
msgstr ""
#: messages.go:188
msgid "Selection marked as private"
#, c-format
msgid "Indexing files in %s"
msgstr ""
#: messages.go:189
msgid "Albums deleted"
msgid "Indexing canceled"
msgstr ""
#: messages.go:190
#, c-format
msgid "Zip created in %d s"
msgid "Removed %d files and %d photos"
msgstr ""
#: messages.go:191
msgid "Permanently deleted"
#, c-format
msgid "Moving files from %s"
msgstr ""
#: messages.go:192
#, c-format
msgid "%s has been restored"
msgid "Copying files from %s"
msgstr ""
#: messages.go:193
msgid "Successfully verified"
msgid "Labels deleted"
msgstr ""
#: messages.go:194
msgid "Label saved"
msgstr ""
#: messages.go:195
msgid "Subject saved"
msgstr ""
#: messages.go:196
msgid "Subject deleted"
msgstr ""
#: messages.go:197
msgid "Person saved"
msgstr ""
#: messages.go:198
msgid "Person deleted"
msgstr ""
#: messages.go:199
msgid "File uploaded"
msgstr ""
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr ""
#: messages.go:201
msgid "Processing upload..."
msgstr ""
#: messages.go:202
msgid "Upload has been processed"
msgstr ""
#: messages.go:203
msgid "Selection approved"
msgstr ""
#: messages.go:204
msgid "Selection archived"
msgstr ""
#: messages.go:205
msgid "Selection restored"
msgstr ""
#: messages.go:206
msgid "Selection marked as private"
msgstr ""
#: messages.go:207
msgid "Albums deleted"
msgstr ""
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr ""
#: messages.go:209
msgid "Permanently deleted"
msgstr ""
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr ""
#: messages.go:211
msgid "Successfully verified"
msgstr ""
#: messages.go:212
msgid "Successfully activated"
msgstr ""

View file

@ -2,399 +2,430 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: none\n"
"Language: ms\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Kesilapan telah berlaku, cuba lagi"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Tidak mampu berbuat demikian"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Perubahan tidak dapat disimpan"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Tidak dapat dipadamkan"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s sudah wujud"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Tidak ditemui"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Fail tidak dijumpai"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Fail terlalu besar"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Tidak disokong"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Jenis tidak disokong"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Format yang tidak disokong"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Folder asal kosong"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Pilihan tidak ditemui"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entiti tidak ditemui"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "akaun tidak dijumpai"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Pengguna tidak dijumpai"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Label tidak ditemui"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kamera tidak ditemui"
#: messages.go:130
msgid "Lens not found"
msgstr "Lensa tidak ditemui"
#: messages.go:131
msgid "Album not found"
msgstr "Album tidak ditemui"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Subjek tidak ditemui"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Orang tidak ditemui"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Wajah tidak ditemui"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Tidak tersedia dalam mod awam"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Tidak tersedia dalam mod baca sahaja"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Sila log masuk ke akaun anda"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Kebenaran ditolak"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Bayaran diperlukan"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Muat naik mungkin menyinggung perasaan"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Muat naik gagal"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Tiada item dipilih"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Gagal membuat fail, sila semak kebenaran"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Gagal membuat folder, sila semak kebenaran"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Tidak dapat menyambung, sila cuba lagi"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Masukkan kod pengesahan"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Kod pengesahan tidak sah, sila cuba lagi"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Kata laluan tidak sah, sila cuba lagi"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Ciri dilumpuhkan"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Tiada label dipilih"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Tiada album dipilih"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Tiada fail tersedia untuk dimuat turun"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Gagal membuat fail zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Bukti kelayakan tidak sah"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Pautan tidak sah"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Nama tidak sah"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Sibuk, sila cuba lagi nanti"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Selang bangun ialah %s, tetapi mestilah 1j atau kurang"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Akaun anda tidak dapat disambungkan"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Terlalu banyak permintaan"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Storan tidak mencukupi"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kuota melebihi"
#: messages.go:163
msgid "Registration disabled"
msgstr "Pendaftaran dilumpuhkan"
#: messages.go:164
msgid "Verified email required"
msgstr "E-mel yang disahkan diperlukan"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Perubahan berjaya disimpan"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album dibuat"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album disimpan"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s dipadamkan"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Kandungan album diklon"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Fail dialih keluar daripada timbunan"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Fail dipadamkan"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Pilihan ditambahkan pada %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Satu entri ditambahkan pada %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "Entri %d ditambahkan pada %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Satu entri dialih keluar daripada %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d entri dialih keluar daripada %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Akaun dibuat"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Akaun disimpan"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Akaun dipadamkan"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Tetapan Disimpan"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Kata laluan ditukar"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Import selesai dalam %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Import dibatalkan"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Pengindeksan selesai dalam %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Mengindeks asal..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Mengindeks fail dalam %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Pengindeksan dibatalkan"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Mengalih keluar fail %d dan foto %d."
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Memindahkan fail dari %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Menyalin fail daripada %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Label dipadamkan"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Label disimpan"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Subjek disimpan"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Subjek dipadamkan"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Orang yang diselamatkan"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Orang dipadamkan"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Fail dimuat naik"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "Fail %d dimuat naik dalam %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Memproses muat naik..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Muat naik telah diproses"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Pemilihan diluluskan"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Pemilihan diarkibkan"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Pemilihan dipulihkan"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Pilihan ditandakan sebagai peribadi"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Album dipadamkan"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip dibuat dalam %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Dipadamkan secara kekal"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s telah dipulihkan"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Berjaya disahkan"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Berjaya diaktifkan"
#~ msgid "Storage is full"
#~ msgstr "Storan penuh"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: Norwegian Bokmål <https://translate.photoprism.app/projects/"
"photoprism/backend/nb_NO/>\n"
"Language: nb\n"
@ -13,393 +13,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Noe gikk galt, prøv igjen"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Ikke i stand til å gjøre det"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Kan ikke lagre endringer"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Kan ikke slettes"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s eksisterer allerede"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Ikke funnet"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Fil ikke funnet"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Filen er for stor"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Ustøttet"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Ikke støttet type"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Ikke støttet format"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Originaler-mappen er tom"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Finner ikke utvalg"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Enheten ble ikke funnet"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Konto ikke funnet"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Bruker ikke funnet"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Merkelapp ikke funnet"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kameraet ble ikke funnet"
#: messages.go:130
msgid "Lens not found"
msgstr "Objektivet ble ikke funnet"
#: messages.go:131
msgid "Album not found"
msgstr "Album ikke funnet"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Emnet ble ikke funnet"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Person ikke funnet"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Ansikt ikke funnet"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Ikke tilgjengelig i offentlig modus"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "ikke tilgjengelig i skrivebeskyttet modus"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Logg inn på kontoen din"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Ingen tilgang"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Betaling kreves"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Opplastingen kan være støtende"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Opplasting mislyktes"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Ingen elementer valgt"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Kunne ikke opprette fil, vennligst sjekk tillatelser"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Kunne ikke opprette mappe, vennligst sjekk tillatelser"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Kunne ikke koble til, vennligst prøv igjen"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Angi verifikasjonskode"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Ugyldig bekreftelseskode. Prøv igjen"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Ugyldig passord, vennligst prøv igjen"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Tjeneste deaktivert"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Ingen merkelapper valgt"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Ingen albumer valgt"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Ingen filer tilgjengelig for nedlasting"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Kunne ikke opprette zip-arkiv"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Ugyldige innloggingsdetaljer"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Ugyldig lenke"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Ugyldig navn"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Opptatt. Prøv igjen senere"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Oppvåkningsintervallet er %s, men må være 1 time eller mindre"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Kontoen din kunne ikke kobles til"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "For mange forespørsler"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Utilstrekkelig lagringsplass"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kvote overskredet"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registrering deaktivert"
#: messages.go:164
msgid "Verified email required"
msgstr "Bekreftet e-post kreves"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Endringene ble lagret"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album opprettet"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album lagret"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s slettet"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Albuminnhold duplisert"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Fil fjernet fra samling"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Fil slettet"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Utvalg lagt til %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "En oppføring lagt til %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d oppføringer lagt til %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "En oppføring fjernet fra %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d oppføringer fjernet fra %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Konto opprettet"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Konto lagret"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Konto slettet"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Innstillinger lagret"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Passord endret"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Import fullført på %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Import avbrutt"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indeksering fullført på %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indekserer originaler…"
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indekserer filer i %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indeksering avbrutt"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Fjernet %d filer og %d foto"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Flytter filer fra %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Kopierer filer fra %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Merkelapper slettet"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Merkelapper lagret"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Emnet er lagret"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Emnet er slettet"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Person reddet"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Person slettet"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Fil lastet opp"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d filer lastet opp på %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Behandler opplasting..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Opplastingen er behandlet"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Utvalg godkjent"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Utvalg arkivert"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Utvalg gjenopprettet"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Utvalg markert som privat"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Album slettet"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip opprettet på %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Permanent slettet"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s har blitt gjenopprettet"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Vellykket verifisert"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Vellykket aktivert"
#~ msgid "Storage is full"
#~ msgstr "Lageret er fullt"
#~ msgid "Invalid request"
#~ msgstr "Ugyldig forespørsel"

View file

@ -1,10 +1,11 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: ci@photoprism.app\n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2025-02-25 12:18+0000\n"
"Last-Translator: Jurre de Jongh <jurre.de.jongh@topicus.nl>\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-"
"translate@weblate.org>\n"
"Language-Team: Dutch <https://translate.photoprism.app/projects/photoprism/"
"backend/nl/>\n"
"Language: nl\n"
@ -12,393 +13,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.9.2\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Er ging iets mis, probeer het opnieuw"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Dat kan niet"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Wijzigingen kunnen niet worden opgeslagen"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Kan niet verwijderd worden"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s bestaat al"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Niet gevonden"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Bestand niet gevonden"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Bestand te groot"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Niet ondersteund"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Niet-ondersteund type"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Niet ondersteund formaat"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "De map Originelen is leeg"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Selectie niet gevonden"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entiteit niet gevonden"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Account niet gevonden"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Gebruiker niet gevonden"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Label niet gevonden"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Camera niet gevonden"
#: messages.go:130
msgid "Lens not found"
msgstr "Lens niet gevonden"
#: messages.go:131
msgid "Album not found"
msgstr "Album niet gevonden"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Onderwerp niet gevonden"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Persoon niet gevonden"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Gezicht niet gevonden"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Niet beschikbaar in publieke modus"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Niet beschikbaar in alleen-lezen modus"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Log in op je account"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Toegang geweigerd"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Betaling vereist"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Upload kan aanstootgevend zijn"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Uploaden mislukt"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Geen items geselecteerd"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Bestand aanmaken mislukt, controleer alstublieft de rechten"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Folder aanmaken mislukt, controleer alstublieft de rechten"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Kan niet verbinden, probeer alstublieft opnieuw"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Verificatiecode invoeren"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Ongeldige verificatiecode. Probeer het opnieuw"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Fout wachtwoord, probeer alstublieft opnieuw"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Functie uitgeschakeld"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Geen labels geselecteerd"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Geen albums geselecteerd"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Geen bestanden beschikbaar om te downloaden"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Maken van zip-bestand is mislukt"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Ongeldige inloggegevens"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Ongeldige link"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Ongeldige mapnaam"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Bezet, probeer het later nog eens"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Het wekinterval is %s, maar moet 1 uur of minder zijn"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Uw account kon niet worden aangesloten"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Te veel verzoeken"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Onvoldoende opslag"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Quota overschreden"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registratie uitgeschakeld"
#: messages.go:164
msgid "Verified email required"
msgstr "Geverifieerd e-mailadres vereist"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Wijzigingen succesvol opgeslagen"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album aangemaakt"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album opgeslagen"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s verwijderd"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Albuminhoud gekopieerd"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Bestand uit stapel verwijderd"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Bestand verwijderd"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Selectie toegevoegd aan %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Eén item toegevoegd aan %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d items toegevoegd aan %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Eén item verwijderd uit %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d items verwijderd uit %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Account aangemaakt"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Account opgeslagen"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Account verwijderd"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Instellingen opgeslagen"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Wachtwoord gewijzigd"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Importeren voltooid in %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Importeren geannuleerd"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexeren voltooid in %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Originelen indexeren…"
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Bestanden indexeren in %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indexeren geannuleerd"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "%d bestanden en %d fotos verwijderd"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Bestanden verplaatsen uit %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Bestanden kopiëren uit %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Labels verwijderd"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Labels opgeslagen"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Onderwerp opgeslagen"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Onderwerp verwijderd"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Persoon gered"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Persoon verwijderd"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Bestand geüpload"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d bestanden geüpload in %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Verwerking upload..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Upload is verwerkt"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Selectie goedgekeurd"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Selectie gearchiveerd"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Selectie hersteld"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Selectie gemarkeerd als privé"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albums verwijderd"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip gemaakt in %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Permanent verwijderd"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s is hersteld"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Met succes geverifieerd"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Met succes geactiveerd"
#~ msgid "Storage is full"
#~ msgstr "Opslag is vol"
#~ msgid "Invalid request"
#~ msgstr "Ongeldige aanvraag"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: Polish <https://translate.photoprism.app/projects/photoprism/"
"backend/pl/>\n"
"Language: pl\n"
@ -14,395 +14,426 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Coś poszło nie tak, spróbuj jeszcze raz"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Nie da się tego zrobić"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Nie można zapisać zmian"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Nie można usunąć"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s już istnieje"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Nie znaleziono"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Plik nie został znaleziony"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Plik jest zbyt duży"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Nieobsługiwane"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Nieobsługiwany typ"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Nieobsługiwany format"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Folder oryginałów jest pusty"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Nie znaleziono wyboru"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Nie znaleziono podmiotu"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Konto nie znalezione"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Użytkownik nie znaleziony"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Etykieta nie została odnaleziona"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Nie znaleziono kamery"
#: messages.go:130
msgid "Lens not found"
msgstr "Nie znaleziono obiektywu"
#: messages.go:131
msgid "Album not found"
msgstr "Album nie został znaleziony"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Temat nie został znaleziony"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Osoba nie została znaleziona"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Twarz nie została znaleziona"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Niedostępne w trybie publicznym"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Niedostępne w trybie tylko do odczytu"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Proszę zalogować się na swoje konto"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Brak uprawnień"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Wymagana płatność"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Przesyłane dane mogą być obraźliwe"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Przesyłanie nie powiodło się"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Nie wybrano żadnych elementów"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Nie można utworzyć pliku, sprawdź uprawnienia"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Nie można utworzyć folderu, sprawdź uprawnienia"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Nie można się połączyć, spróbuj ponownie"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Wprowadź kod weryfikacyjny"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Nieprawidłowy kod weryfikacyjny. Spróbuj ponownie"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Nieprawidłowe hasło, spróbuj ponownie"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Funkcja wyłączona"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Nie wybrano etykiet"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Nie wybrano albumów"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Brak plików do pobrania"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Nie udało się utworzyć pliku zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Nieprawidłowe dane logowania"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Nieprawidłowy link"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Nieprawidłowa nazwa"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Zajęty, spróbuj ponownie później"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr ""
"Interwał wybudzenia %s jest nieprawidłowy, powinien być równy lub mniejszy "
"niż 1 godzina"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Twoje konto nie może być podłączone"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Zbyt wiele żądań"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Niewystarczająca pamięć"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Przekroczony limit"
#: messages.go:163
msgid "Registration disabled"
msgstr "Rejestracja wyłączona"
#: messages.go:164
msgid "Verified email required"
msgstr "Wymagany zweryfikowany adres e-mail"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Zmiany zostały pomyślnie zapisane"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album został utworzony"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album został zapisany"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s został usunięty"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Album został sklonowany"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Plik został rozgrupowany"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Plik został usunięty"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Wybór dodany do %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Dodano jeden wpis do %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d wpisy dodane do %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Usunięto jeden wpis z %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d wpisy usunięte z %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Konto utworzone"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Konto zapisane"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Konto usunięte"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Ustawienia zapisane"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Hasło zostało zmienione"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Import zakończony w %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Import został anulowany"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indeksowanie zakończone w %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indeksowanie oryginałów…"
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indeksowanie plików w %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indeksowanie anulowane"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Usunięto %d plików i %d zdjęć"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Przenoszenie plików z %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Kopiowanie plików z %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Usunięto etykiety"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Etykieta zapisana"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Przedmiot zapisany"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Przedmiot usunięty"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Osoba zapisana"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Osoba usunięta"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Przesłany plik"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d plików przesłano w %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Przetwarzanie uploadu..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Przesyłanie zostało przetworzone"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Wybór zatwierdzony"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Wybór zarchiwizowany"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Wybór został przywrócony"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Wybór oznaczony jako prywatny"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albumy zostały usunięte"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip utworzony w %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Trwale usunięty"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s zostało przywrócone"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Pomyślnie zweryfikowano"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Pomyślnie aktywowano"
#~ msgid "Storage is full"
#~ msgstr "Pamięć jest pełna"
#~ msgid "Invalid request"
#~ msgstr "Niepoprawne żądanie"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: Portuguese <https://translate.photoprism.app/projects/"
"photoprism/backend/pt/>\n"
"Language: pt\n"
@ -13,393 +13,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Algo correu mal, tente novamente"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Incapaz de fazer isso"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "As mudanças não foram salvas"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Não foi possível excluir"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s já existe"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Não encontrado"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Arquivo não encontrado"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Arquivo muito grande"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Não compatível"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Tipo não suportado"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Formato sem suporte"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "A pasta dos originais está vazia"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Seleção não encontrada"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entidade não encontrada"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Conta não encontrada"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Usuário não encontrado"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Etiqueta não encontrada"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Não foi encontrada nenhuma câmara"
#: messages.go:130
msgid "Lens not found"
msgstr "Lente não encontrada"
#: messages.go:131
msgid "Album not found"
msgstr "Álbum não encontrado"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Assunto não encontrado"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Pessoa não encontrada"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Rosto não encontrado"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Indisponível em modo público"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Não disponível no modo somente leitura"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Faça o login em sua conta"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Permissão negada"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Pagamento obrigatório"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Envio pode ser ofensivo"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Envio falhou"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Sem itens selecionados"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Falha ao criar arquivo, por favor cheque as permissões"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Falha ao criar pasta, por favor cheque as permissões"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Não foi possível conectar, por favor tente novamente"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Digite o código de verificação"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Código de verificação inválido, tente novamente"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Senha inválida, por favor tente novamente"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Recurso Desativado"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Sem etiquetas selecionadas"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Sem álbuns selecionados"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Sem arquivos disponíveis para baixar"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Falha ao criar arquivo zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Credenciais inválidas"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Link inválido"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Nome inválido"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Em uso, por favor tente novamente mais tarde"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "O intervalo de despertar é %s, mas deve ser de 1h ou menos"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Sua conta não pôde ser conectada"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Demasiados pedidos"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Armazenamento insuficiente"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Quota excedida"
#: messages.go:163
msgid "Registration disabled"
msgstr "Cadastro desativado"
#: messages.go:164
msgid "Verified email required"
msgstr "É necessário um e-mail verificado."
#: messages.go:167
msgid "Changes successfully saved"
msgstr "As mudanças foram salvas com sucesso"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Álbum criado"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Álbum salvo"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Álbum %s excluído"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Conteúdo do álbum copiado"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Arquivo removido da pilha"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Arquivo excluído"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Seleção adicionada a %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Uma entrada adicionada a %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d entradas adicionadas a %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Uma entrada removida de %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d entradas removidas de %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Conta criada"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Conta salva"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Conta excluída"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Configurações salvas"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Senha alterada"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Importação completa em %d"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Importação cancelada"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexação completa em %d"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indexando originais..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indexando arquivos em %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indexação cancelada"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Removidos %d arquivos e %d fotos"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Movendo arquivos de %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Copiando arquivos de %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Etiquetas excluídas"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Etiqueta salva"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Assunto salvo"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Assunto eliminado"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Pessoa salva"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Pessoa apagada"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Arquivo carregado"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d arquivos enviados em %d"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "A processar carregamento..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "O Upload foi processado"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Seleção aprovada"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Seleção arquivada"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Seleção restaurada"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Seleção marcada como privada"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Álbuns excluídos"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip criado em %d"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Permanentemente excluídas"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s foi restaurado"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Verificado com sucesso"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Ativado com sucesso"
#~ msgid "Storage is full"
#~ msgstr "O armazenamento está cheio"
#~ msgid "Invalid request"
#~ msgstr "Solicitação inválida"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: Portuguese (Brazil) <https://translate.photoprism.app/"
"projects/photoprism/backend/pt_BR/>\n"
"Language: pt_BR\n"
@ -13,393 +13,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Algo deu errado, tente novamente"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Incapaz de fazer isso"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "As mudanças não foram salvas"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Não foi possível excluir"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s já existe"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Não encontrado"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Arquivo não encontrado"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Arquivo muito grande"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Não compatível"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Tipo não suportado"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Formato sem suporte"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "A pasta dos originais está vazia"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Seleção não encontrada"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entidade não encontrada"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Conta não encontrada"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Usuário não encontrado"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Etiqueta não encontrada"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Câmera não encontrada"
#: messages.go:130
msgid "Lens not found"
msgstr "Lente não encontrada"
#: messages.go:131
msgid "Album not found"
msgstr "Álbum não encontrado"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Assunto não encontrado"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Pessoa não encontrada"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Rosto não encontrado"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Indisponível em modo público"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Não disponível no modo somente leitura"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Faça o login em sua conta"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Permissão negada"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Pagamento obrigatório"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Envio pode ser ofensivo"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Envio falhou"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Sem itens selecionados"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Falha ao criar arquivo, por favor cheque as permissões"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Falha ao criar pasta, por favor cheque as permissões"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Não foi possível conectar, por favor tente novamente"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Digite o código de verificação"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Código de verificação inválido, tente novamente"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Senha inválida, por favor tente novamente"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Recurso Desativado"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Sem etiquetas selecionadas"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Sem álbuns selecionados"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Sem arquivos disponíveis para baixar"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Falha ao criar arquivo zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Credenciais inválidas"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Link inválido"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Nome inválido"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Ocupado, por favor tente mais tarde"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "O intervalo de despertar é %s, mas deve ser de 1h ou menos"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Sua conta não pôde ser conectada"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Muitas solicitações"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Armazenamento insuficiente"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Cota excedida"
#: messages.go:163
msgid "Registration disabled"
msgstr "Cadastro desativado"
#: messages.go:164
msgid "Verified email required"
msgstr "É necessário um e-mail verificado."
#: messages.go:167
msgid "Changes successfully saved"
msgstr "As mudanças foram salvas com sucesso"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Álbum criado"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Álbum salvo"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Álbum %s excluído"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Conteúdo do álbum copiado"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Arquivo removido da pilha"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Arquivo excluído"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Seleção adicionada a %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Uma entrada adicionada a %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d entradas adicionadas a %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Uma entrada removida de %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d entradas removidas de %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Conta criada"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Conta salva"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Conta excluída"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Configurações salvas"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Senha alterada"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Importação completa em %d"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Importação cancelada"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexação completa em %d"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indexando originais..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indexando arquivos em %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indexação cancelada"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Removidos %d arquivos e %d fotos"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Movendo arquivos de %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Copiando arquivos de %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Etiquetas excluídas"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Etiqueta salva"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Assunto salvo"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Assunto eliminado"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Pessoa salva"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Pessoa apagada"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Arquivo carregado"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d arquivos enviados em %d"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Processamento de upload..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "O Upload foi processado"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Seleção aprovada"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Seleção arquivada"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Seleção restaurada"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Seleção marcada como privada"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Álbuns excluídos"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip criado em %d"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Permanentemente excluídas"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s foi restaurado"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Verificado com sucesso"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Ativado com sucesso"
#~ msgid "Storage is full"
#~ msgstr "O armazenamento está cheio"
#~ msgid "Invalid request"
#~ msgstr "Solicitação inválida"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: Romanian <https://translate.photoprism.app/projects/"
"photoprism/backend/ro/>\n"
"Language: ro\n"
@ -14,393 +14,424 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < "
"20)) ? 1 : 2;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Ceva nu a mers bine, încercați din nou"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Nu se poate face asta"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Modificările nu au putut fi salvate"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Nu a putut fi șters"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s deja există"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Nu a fost găsit"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Fișier nedescoperit"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Fișier prea mare"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Neacceptat"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Tip neacceptat"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Format neacceptat"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Dosarul Originals este gol"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Selecția nu a fost găsită"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entitatea nu a fost găsită"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Contul nu a fost găsit"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Utilizatorul nu a fost găsit"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Eticheta nu a fost găsită"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Nu s-a găsit camera"
#: messages.go:130
msgid "Lens not found"
msgstr "Obiectivul nu a fost găsit"
#: messages.go:131
msgid "Album not found"
msgstr "Album nedescoperit"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Subiectul nu a fost găsit"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Persoana nu a fost găsită"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Fața nu a fost găsită"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Nu este disponibil în modul public"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Nu este disponibil în modul doar pentru citire"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Vă rugăm să vă conectați la contul dvs"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Permisiune refuzată"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Plata necesară"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Încărcarea poate fi ofensatoare"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Încărcarea a eșuat"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Niciun element selectat"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Nu a reușit să creeze fișierul, vă rugăm să verificați permisiunile"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Nu s-a reușit crearea dosarului, vă rugăm să verificați permisiunile"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Nu s-a putut conecta, vă rugăm să încercați din nou"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Introduceți codul de verificare"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Cod de verificare nevalid, încercați din nou"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Parolă invalidă, vă rugăm să încercați din nou"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Caracteristică dezactivată"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Nu sunt selectate etichete"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Nu sunt selectate albume"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Nu există fișiere disponibile pentru descărcare"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Nu a reușit să creeze fișierul zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Acreditări nevalabile"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Legătură invalidă"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Nume invalid"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Ocupat, vă rugăm să încercați din nou mai târziu"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Intervalul de trezire este %s, dar trebuie să fie de 1h sau mai puțin"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Contul dvs. nu a putut fi conectat"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Prea multe cereri"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Depozitare insuficientă"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Cota depășită"
#: messages.go:163
msgid "Registration disabled"
msgstr "Înregistrare dezactivată"
#: messages.go:164
msgid "Verified email required"
msgstr "Adresă de e-mail verificată necesară"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Modificări salvate cu succes"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album creat"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album salvat"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s șters"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Conținutul albumului a fost clonat"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Fișier eliminat din stivă"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Fișier șters"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Selecție adăugată la %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "O intrare adăugată la %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d intrări adăugate la %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "O intrare eliminată din %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d intrări eliminate din %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Cont creat"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Cont salvat"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Cont șters"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Setări salvate"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Parola a fost schimbată"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Import finalizat în %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Importul a fost anulat"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexare finalizată în %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indexarea originalelor..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indexarea fișierelor în %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indexare anulată"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Sau eliminat %d fișiere și %d fotografii"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Mutarea fișierelor din %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Copierea fișierelor din %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Etichete șterse"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Etichetă salvată"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Subiect salvat"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Subiect eliminat"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Persoană salvată"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Persoană eliminată"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Fișier încărcat"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d fișiere încărcate în %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Procesarea încărcării..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Încărcarea a fost procesată"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Selecție aprobată"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Selecție arhivată"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Selecție restabilită"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Selecție marcată ca fiind privată"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albume șterse"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Fișierul Zip creat în %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Șterse definitiv"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s a fost restaurat"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Verificat cu succes"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Activat cu succes"
#~ msgid "Storage is full"
#~ msgstr "Spațiul de stocare este plin"
#~ msgid "Invalid request"
#~ msgstr "Cerere invalidă"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: Russian <https://translate.photoprism.app/projects/photoprism/"
"backend/ru/>\n"
"Language: ru\n"
@ -14,393 +14,424 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Что-то пошло не так, попробуйте еще раз"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Невозможно сделать это"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Изменения не будут сохранены"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Не будет удалено"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s уже существует"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Не найдено"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Файл не найден"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Слишком большой файл"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Не поддерживается"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Неподдерживаемый тип"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Неподдерживаемый формат"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Папка оригиналов пуста"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Выделение не найдено"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Сущность не найдена"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Учетная запись не найдена"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Пользователь не найден"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Метка не найдена"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Камера не найдена"
#: messages.go:130
msgid "Lens not found"
msgstr "Объектив не найден"
#: messages.go:131
msgid "Album not found"
msgstr "Альбом не найден"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Объект не найден"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Человек не найден"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Лицо не найдено"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Не доступно в публичном режиме"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Недоступно в режиме только для чтения"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Пожалуйста, войдите в свой аккаунт"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Доступ запрещен"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Требуется оплата"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Загрузка может быть оскорбительной"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Загрузка не удалась"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Нет выделенных элементов"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Не удалось создать файл, проверьте права доступа"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Не удалось создать папку, проверьте права доступа"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Нет соединения, попробуйте еще раз"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "введите код подтверждения"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Неверный код подтверждения. Повторите попытку."
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Неверный пароль, пожалуйста попробуйте еще раз"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Данная возможность отключена"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Нет выделенных меток"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Нет выделенных альбомов"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Нет файлов, доступных для скачивания"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Не удалось создать zip-файл"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Неверные учетные данные"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Неверная ссылка"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Неприемлемое имя"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Занят, повторите попытку позже"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Интервал пробуждения составляет %s, но должен быть 1 час или меньше"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Ваш аккаунт не удалось подключить"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Слишком много запросов"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Недостаточно места для хранения"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Квота превышена"
#: messages.go:163
msgid "Registration disabled"
msgstr "Регистрация отключена"
#: messages.go:164
msgid "Verified email required"
msgstr "Требуется подтверждение адреса электронной почты."
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Изменения сохранены"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Альбом создан"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "\\альбом сохранен"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Альбом %s удален"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Содержимое альбома скоприровано"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Файл удален из очереди"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Файл удалён"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Выделение добавлено к %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Один элемент добавлен к %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d элементов добавлено к %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Один элемент удален из %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d элементов удалено из %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Учетная запись создана"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Учетная запись сохранена"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Учетная запись удалена"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Настройки сохранены"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Пароль изменен"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Импортирование завершено за %d c"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Импортирование отменено"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Индексирование завершено за %d с"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Индексирование Оригиналов..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Индексирование файлов в %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Индексирование отменено"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Удаление %d файлов и %d фотографий"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Перемещение файлов из %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Копирование файлов из %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Метки удалены"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Метки сохранены"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Тема сохранена"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Тема удалена"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Человек спасен"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Лицо удалено"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Файл загружен"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d файлов загружено за %d с"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Обработка загрузки..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Загрузка была обработана"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Утвержденный выбор"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Выбранное помещено в архив"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Выбранное восстановлено"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Выбранное помечено как приватное"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Альбом удален"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip архив создан за %d с"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Постоянно удаляется"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s был восстановлен"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Успешно проверено"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Успешно активировано"
#~ msgid "Storage is full"
#~ msgstr "Хранилище заполнено"
#~ msgid "Invalid request"
#~ msgstr "Неправильный запрос"

View file

@ -2,9 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-09 06:08+0000\n"
"PO-Revision-Date: 2024-11-05 09:00+0000\n"
"Last-Translator: Jozef Gaal <preklady@mayday.sk>\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-"
"translate@weblate.org>\n"
"Language-Team: Slovak <https://translate.photoprism.app/projects/photoprism/"
"backend/sk/>\n"
"Language: sk\n"
@ -12,393 +13,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Weblate 5.8.2\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Niečo sa pokazilo, skúste to znova"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Nemožno to urobiť"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Zmeny sa neuložili"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Nepodarilo sa odstrániť"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s už existuje"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Nenájdené"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Súbor nenájdený"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Príliš veľký súbor"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Nepodporované"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Nepodporovaný typ"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Nepodporovaný formát"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Priečinok Originály je prázdny"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Výber nenájdený"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Subjekt nenájdený"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Účet nenájdený"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Užívateľ nenájdený"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Štítok nenájdený"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Fotoaparát nebol nájdený"
#: messages.go:130
msgid "Lens not found"
msgstr "Objektív nebol nájdený"
#: messages.go:131
msgid "Album not found"
msgstr "Album nenájdený"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Predmet nenájdený"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Osoba nenájdená"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Tvár nenájdená"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Nedostupné vo verejnom móde"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "nedostupné v móde len pre čítanie"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Prosím prihláste sa a skúste znova"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Osoba odstránená"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Požadovaná platba"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Nahrané súbory môžu byť urážlivé"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Odovzdávanie zlyhalo"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Neboli vybraté žiadne položky"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Vytváranie súboru zlyhalo, prosím skontrolujte oprávnenia"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Vytváranie zložky zlyhalo, prosím skontrolujte oprávnenia"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Nebolo možné sa pripojiť, skúste to znova"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Zadajte overovací kód"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Neplatný overovací kód, skúste to znova"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Nesprávne heslo, skúste to znova"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Funkcia vypnutá"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Neboli vybraté žiadne štítky"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Neboli vybraté žiadne albumy"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Žiadne súbory na stiahnutie k dispozícií"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Nebolo možné vytvoriť súbor ZIP"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Neplatné údaje"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Neplatný odkaz"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Neplatné meno"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Systém zaneprázdnený, prosím skúste znovu neskôr"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Interval prebúdzania je %s, ale musí byť najviac 1 h"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Vaše konto sa nepodarilo pripojiť"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Príliš veľa požiadaviek"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Nedostatočné skladovanie"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Prekročenie kvóty"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registrácia zakázaná"
#: messages.go:164
msgid "Verified email required"
msgstr "Vyžaduje sa overený e-mail"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Zmeny úspešne uložené"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album vytvorený"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album uložený"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s vymazaný"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Obsah albumu prekopírovaný"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Súbor odstránený zo stohu"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Súbor odstránený"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Výber pridaný do %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Jeden záznam pridaný do %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d záznamov pridaných do %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Jeden záznam odstránený z %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d záznamov odstránených z %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Účet vytvorený"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Účet uložený"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Účet odstránený"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Nastavenia uložené"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Heslo zmenené"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Import hotový za %d sekúnd"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Import zrušený"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexovanie hotové za %d sekúnd"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indexovanie originálov..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indexovanie súborov v %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indexovanie zrušené"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Bolo odstránených %d súborov a %d fotiek"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Presúvanie súborov z %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Kopírovanie súborov z %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Štítky odstránené"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Štítok uložený"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Predmet uložený"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Predmet odstránený"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Osoba uložená"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Osoba odstránená"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Súbor odstránený"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d súborov nahraných za %d sekúnd"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Spracovanie nahrávania..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Nahrané súbory môžu byť urážlivé"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Označenie schválené"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Označenie archivované"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Označenie obnovené"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Označenie označené ako súkromné"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albumy odstránené"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Súbor ZIP vytvorený za %d sekúnd"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Trvalo odstránené"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s bolo obnovené"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Úspešne overené"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Úspešne aktivované"
#~ msgid "Storage is full"
#~ msgstr "Úložisko je plné"
#~ msgid "Invalid request"
#~ msgstr "Neplatná požiadavka"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: none\n"
"Language: sl\n"
"MIME-Version: 1.0\n"
@ -13,393 +13,424 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || "
"n%100==4 ? 2 : 3;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Nekaj je šlo narobe, poskusite znova"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Tega ni mogoče storiti"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Sprememb ni bilo mogoče shraniti"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Ni bilo mogoče izbrisati"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s že obstaja"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Ga ni mogoče najti"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Datoteka ni najdena"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Prevelika datoteka"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Nepodprto"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Nepodprta vrsta"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Nepodprt format"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Mapa Originali je prazna"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Izbor ni najden"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entiteta ni bila najdena"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Račun ni najden"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Uporabnik ne obstaja"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Oznaka ni bila najdena"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kamera ni bila najdena"
#: messages.go:130
msgid "Lens not found"
msgstr "Objektiv ni bil najden"
#: messages.go:131
msgid "Album not found"
msgstr "Album ni najden"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Zadeva ni bila najdena"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Oseba ni bila najdena"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Obraza ni mogoče najti"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Ni na voljo v javnem načinu"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Ni na voljo v načinu samo za branje"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Prijavite se v svoj račun"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Dovoljenje Zavrnjeno"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Zahtevano plačilo"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Nalaganje je lahko žaljivo"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Nalaganje neuspešno"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Ni izbranih elementov"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Neuspešno ustvarjanje datoteke, preverite dovoljenja"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Neuspešno ustvarjanje mape, preverite dovoljenja"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Ne morem vzpostaviti povezave, poskusite znova"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "vnesi potrditveno kodo"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Neveljavna koda za preverjanje, poskusite znova"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Nepravilno geslo, poskusite znova"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Funkcija je onemogočena"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Ni izbranih nalepk"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Ni izbranih albumov"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Za prenos ni na voljo nobenih datotek"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Ni uspelo ustvariti datoteke zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Neveljavne poverilnice"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Neveljavna povezava"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Neveljavno ime"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Zaseden, poskusite znova pozneje"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Interval prebujanja je %s, vendar mora biti 1h ali manj"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Vašega računa ni bilo mogoče povezati"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Preveč zahtev"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Nezadostno skladiščenje"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kvota je presežena"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registracija onemogočena"
#: messages.go:164
msgid "Verified email required"
msgstr "Zahtevan je potrjen e-poštni naslov"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Spremembe so bile uspešno shranjene"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Ustvarjen album"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Shranjen album"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s izbrisano"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Vsebina albuma klonirana"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Datoteka odstranjena iz sklada"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Izbrisana datoteka"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Izbor dodan v %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "En vnos dodan v %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d vnosi dodani v %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "En vnos odstranjen iz %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d vnosi odstranjeni iz %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Ustvarjen račun"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Shranjen račun"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Račun je izbrisan"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Nastavitve shranjene"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Geslo spremenjeno"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Uvoz se zaključi v %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Uvoz preklican"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indeksiranje je končano v %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indeksiranje izvirnikov..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indeksiranje datotek v %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indeksiranje preklicano"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Odstranjene %d datoteke in %d fotografije"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Premikanje datotek iz %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Kopiranje datotek iz %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Etikete izbrisane"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Shranjena nalepka"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Zadeva je shranjena"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Predmet izbrisanih"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Rešena oseba"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Izbrisana oseba"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Prenesena datoteka"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d datoteke, naložene v %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Obdelava nalaganja..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Prenos je bil obdelan"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Odobren izbor"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Arhiviran izbor"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Obnovljen izbor"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Izbor označen kot zasebni"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Izbrisani albumi"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip, ustvarjen v %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Trajno izbrisano"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s je bil obnovljen"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Uspešno preverjeno"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Uspešno aktiviran"
#~ msgid "Storage is full"
#~ msgstr "Shramba je polna"
#~ msgid "Invalid request"
#~ msgstr "Neveljavna zahteva"

View file

@ -2,9 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-09 06:08+0000\n"
"PO-Revision-Date: 2024-07-30 06:22+0000\n"
"Last-Translator: Cotignac <jan-eric@myhrgren.se>\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-"
"translate@weblate.org>\n"
"Language-Team: Swedish <https://translate.photoprism.app/projects/photoprism/"
"backend/sv/>\n"
"Language: sv\n"
@ -12,393 +13,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Något gick fel, försök igen"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Det går inte att göra"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Ändringarna kunde inte sparas"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Kunde inte raderas"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s finns redan"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Hittades inte"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Filen kunde inte hittas"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Filen är för stor"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Stöds ej"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Denna typ stöds ej"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Format som inte stöds"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Mappen med originalen är tom"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Urvalet kunde inte hittas"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Entitet kunde inte hittas"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Kontot kunde inte hittas"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Användaren kunde inte hittas"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Etikett saknas"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kameran hittades inte"
#: messages.go:130
msgid "Lens not found"
msgstr "Linsen hittades inte"
#: messages.go:131
msgid "Album not found"
msgstr "Albumet finns inte"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Ämnet finns inte"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Personen kunde inte hittas"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Ansiktet kunde inte hittas"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Inte tillgängligt i offentligt läge"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Inte tillgänglig i skrivskyddsläge"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Logga in på ditt konto"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Åtkomst nekades"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Betalning krävs"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Uppladdning kan vara stötande"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Uppladdning misslyckades"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Inga objekt har valts"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Det gick inte att skapa en fil, kontrollera behörigheter"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Det gick inte att skapa en mapp, kontrollera behörigheter"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Kunde inte ansluta, försök igen"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Ange verifieringskod"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Ogiltig verifieringskod, försök igen"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Felaktigt lösenord, försök igen"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Funktionen är inaktiverad"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Inga etiketter har valts"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Inga album har valts"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Inga filer finns tillgängliga för nedladdning"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Misslyckades med att skapa en zip-fil"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Ogiltiga autentiseringsuppgifter"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Ogiltig länk"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Felaktigt namn"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Upptagen, försök igen senare"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Uppvakningsintervallet är %s, men måste vara 1 timme eller mindre"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Ditt konto kunde inte anslutas"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "För många förfrågningar"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Otillräcklig lagring"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kvoten överskriden"
#: messages.go:163
msgid "Registration disabled"
msgstr "Registrering inaktiverad"
#: messages.go:164
msgid "Verified email required"
msgstr "Verifierad e-postadress krävs"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Ändringarna har sparats"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Album skapat"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Album sparat"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s raderat"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Innehållet i albumet kopieras"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Filen tas bort från stapeln"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Fil raderad"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Urval tillagt i %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "En post tillagd i %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d poster tillagda till %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "En post borttagen från %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d poster raderade från %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Kontot har skapats"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Kontot sparat"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Kontot raderat"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Inställningarna har sparats"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Lösenordet har ändrats"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Importen slutfördes på %d s"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Importen avbruten"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Indexering slutförd på %d s"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Indexering av original..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Indexering av filer i %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Indexering avbruten"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Tog bort %d filer och %d bilder"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Flyttar filer från %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Kopierar filer från %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Etiketter raderade"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Etikett sparad"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Ämne sparat"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Ämne raderat"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Person sparad"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Person raderad"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Uppladdad fil"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d filer uppladdade på %d s"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Behandling av uppladdning..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Uppladdningen har behandlats"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Urvalet är godkänt"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Urval arkiverat"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Urvalet har återställts"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Urval markerat som privat"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Album raderade"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip skapad på %d s"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Permanent borttagen"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s har återställts"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Verifierad"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Lyckades aktiverad"
#~ msgid "Storage is full"
#~ msgstr "Lagringsutrymmet är fullt"
#~ msgid "Invalid request"
#~ msgstr "Ogiltig begäran"

View file

@ -2,403 +2,434 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: none\n"
"Language: th\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "เกิดข้อผิดพลาด โปรดลองอีกครั้ง"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "ไม่สามารถทำเช่นนั้นได้"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "ไม่สามารถบันทึกการเปลี่ยนแปลง"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "ไม่สามารถลบได้"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s มีอยู่แล้ว"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "ไม่พบ"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "ไม่พบไฟล์"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "ไฟล์ใหญ่เกินไป"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "ไม่รองรับ"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "ประเภทที่ไม่รองรับ"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "รูปแบบที่ไม่สนับสนุน"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "โฟลเดอร์ต้นฉบับว่างเปล่า"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "ไม่พบสิ่งที่เลือก"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "ไม่พบเอนทิตี"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "ไม่พบบัญชี"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "ไม่พบผู้ใช้"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "ไม่พบป้ายกำกับ"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "ไม่พบกล้อง"
#: messages.go:130
msgid "Lens not found"
msgstr "ไม่พบเลนส์"
#: messages.go:131
msgid "Album not found"
msgstr "ไม่พบอัลบั้ม"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "ไม่พบหัวเรื่อง"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "ไม่พบบุคคล"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "ไม่พบใบหน้า"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "ไม่พร้อมใช้งานในโหมดสาธารณะ"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "ไม่พร้อมใช้งานในโหมดอ่านอย่างเดียว"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "กรุณาเข้าสู่ระบบบัญชีของคุณ"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "ปฏิเสธการอนุญาต"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "ต้องชำระเงิน"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "การอัปโหลดอาจไม่เหมาะสม"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "การอัพโหลดล้มเหลว"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "ไม่มีรายการที่เลือก"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "สร้างไฟล์ไม่สำเร็จ โปรดตรวจสอบสิทธิ์"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "สร้างโฟลเดอร์ไม่สำเร็จ โปรดตรวจสอบสิทธิ์"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "ไม่สามารถเชื่อมต่อได้ โปรดลองอีกครั้ง"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "ระบุรหัสยืนยืน"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "รหัสยืนยันไม่ถูกต้อง โปรดลองอีกครั้ง"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "รหัสผ่านไม่ถูกต้อง โปรดลองอีกครั้ง"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "คุณลักษณะถูกปิดใช้งาน"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "ไม่ได้เลือกป้ายกำกับ"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "ไม่ได้เลือกอัลบั้ม"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "ไม่มีไฟล์สำหรับดาวน์โหลด"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "สร้างไฟล์ zip ไม่สำเร็จ"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "ข้อมูลประจำตัวที่ไม่ถูกต้อง"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "ลิงก์ไม่ถูกต้อง"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "ชื่อไม่ถูกต้อง"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "ไม่ว่าง โปรดลองอีกครั้งในภายหลัง"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "ช่วงเวลาปลุกคือ %s แต่ต้องเป็น 1 ชั่วโมงหรือน้อยกว่า"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "ไม่สามารถเชื่อมต่อบัญชีของคุณได้"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "คำขอมากเกินไป"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "พื้นที่เก็บข้อมูลไม่เพียงพอ"
#: messages.go:162
msgid "Quota exceeded"
msgstr "เกินโควตา"
#: messages.go:163
msgid "Registration disabled"
msgstr "การลงทะเบียนถูกปิดใช้งาน"
#: messages.go:164
msgid "Verified email required"
msgstr "ต้องยืนยันอีเมล"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "บันทึกการเปลี่ยนแปลงเรียบร้อยแล้ว"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "สร้างอัลบั้มแล้ว"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "บันทึกอัลบั้มแล้ว"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "ลบอัลบั้ม %s แล้ว"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "โคลนเนื้อหาในอัลบั้ม"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "ไฟล์ถูกลบออกจากสแต็ค"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "ลบไฟล์แล้ว"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "เพิ่มการเลือกใน %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "เพิ่มหนึ่งรายการใน %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d รายการที่เพิ่มใน %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "ลบหนึ่งรายการจาก %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "รายการ %d ถูกลบออกจาก %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "สร้างบัญชีแล้ว"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "บันทึกบัญชีแล้ว"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "ลบบัญชีแล้ว"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "การตั้งค่าที่บันทึกไว้"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "เปลี่ยนรหัสผ่านแล้ว"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "การนำเข้าเสร็จสมบูรณ์ใน %d วินาที"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "ยกเลิกการนำเข้าแล้ว"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "การสร้างดัชนีเสร็จสิ้นใน %d วินาที"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "กำลังจัดทำดัชนีต้นฉบับ..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "การทำดัชนีไฟล์ใน %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "ยกเลิกการทำดัชนีแล้ว"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "ลบไฟล์ %d และภาพถ่าย %d"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "การย้ายไฟล์จาก %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "การคัดลอกไฟล์จาก %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "ลบป้ายกำกับแล้ว"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "บันทึกป้ายกำกับแล้ว"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "บันทึกหัวเรื่องแล้ว"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "ลบหัวเรื่องแล้ว"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "บุคคลที่บันทึกไว้"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "ลบบุคคลแล้ว"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "อัปโหลดไฟล์แล้ว"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "ไฟล์ %d ที่อัปโหลดใน %d วินาที"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "กำลังประมวลผลการอัปโหลด..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "อัปโหลดได้รับการดำเนินการ"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "การเลือกได้รับการอนุมัติ"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "เก็บถาวรการเลือกแล้ว"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "คืนค่าการเลือกแล้ว"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "การเลือกถูกทำเครื่องหมายเป็นส่วนตัว"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "ลบอัลบั้มแล้ว"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip สร้างใน %d วินาที"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "ลบอย่างถาวร"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s ได้รับการกู้คืนแล้ว"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "ตรวจสอบเรียบร้อยแล้ว"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "เปิดใช้งานสำเร็จแล้ว"
#~ msgid "Storage is full"
#~ msgstr "พื้นที่เก็บข้อมูลเต็มแล้ว"
#~ msgid "Invalid request"
#~ msgstr "คำขอไม่ถูกต้อง"

View file

@ -2,402 +2,434 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-09 06:08+0000\n"
"PO-Revision-Date: 2024-12-24 19:02+0000\n"
"Last-Translator: Omer Duran <me@omerduran.dev>\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-"
"translate@weblate.org>\n"
"Language-Team: none\n"
"Language: tr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.8.4\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Bir şeyler ters gitti, tekrar deneyin"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Bunu yapmak mümkün değil"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Değişiklikler kaydedilemedi"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Silinemedi"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s Zaten var"
msgstr "%s zaten var"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Bulunamadı"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Dosya bulunamadı"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Dosya çok büyük"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Desteklenmiyor"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Desteklenmeyen tür"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Desteklenmeyen format"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Orijinaller klasörü boş"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Seçim bulunamadı"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Varlık bulunamadı"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Hesap bulunamadı"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Kullanıcı bulunamadı"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Etiket bulunamadı"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Kamera bulunamadı."
#: messages.go:130
msgid "Lens not found"
msgstr "Lens bulunamadı."
#: messages.go:131
msgid "Album not found"
msgstr "Albüm bulunamadı"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Özne bulunamadı"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Kişi bulunamadı"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Yüz bulunamadı"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Genel modda mevcut değil"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Salt okunur modda kullanılamaz"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Lütfen hesabınıza giriş yapın"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "İzin reddedildi"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Ödeme gerekli"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Yükleme rahatsız edici olabilir"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Yükleme başarısız"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Seçili öğe yok"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Dosya oluşturulamadı, lütfen izinleri kontrol edin"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Klasör oluşturulamadı, lütfen izinleri kontrol edin"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Bağlanılamadı, lütfen tekrar deneyin"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Doğrulama kodunu giriniz"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Geçersiz doğrulama kodu, lütfen tekrar deneyin"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Geçersiz şifre, lütfen tekrar deneyin"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Özellik devre dışı"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Seçili etiket yok"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Seçili albüm yok"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "İndirilebilecek dosya yok"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Zip dosyası oluşturulamadı"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Geçersiz kimlik bilgileri"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Geçersiz link"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Geçersiz isim"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Meşgul, lütfen daha sonra tekrar deneyin"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Uyandırma aralığı %s'dır, ancak 1 saat veya daha az olmalıdır"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Hesabınız bağlanamadı"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Çok fazla talep var"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Yetersiz depolama"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Kota aşıldı"
#: messages.go:163
msgid "Registration disabled"
msgstr "Kayıt devre dışı bırakıldı"
#: messages.go:164
msgid "Verified email required"
msgstr "Doğrulanmış e-posta adresi gereklidir."
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Değişiklikler başarıyla kaydedildi"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Albüm oluşturuldu"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Albüm kaydedildi"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Albüm %s silindi"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Albüm içeriği klonlandı"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Dosya yığından kaldırıldı"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Silinmiş dosya"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Seçim %s'a eklendi"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Bir giriş %s'a eklendi"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d girişleri %s'e eklendi"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Bir giriş %s'dan kaldırıldı"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d girişleri %s'den kaldırıldı"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Hesap eklendi"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Hesap kaydedildi"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Hesap silindi"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Ayarlar kaydedildi"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Şifre Değiştirildi"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "İçe aktarma %d s içinde tamamlandı"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "İthalat iptal edildi"
msgstr "İçe aktarma iptal edildi"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "İndeksleme %d s içinde tamamlandı"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Orijinalleri dizinliyor..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "%s dosya yüklendi"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "İndeksleme iptal edildi"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "%d dosya ve %d fotoğraf kaldırıldı"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Dosyaları %s'dan taşıma"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Dosyaları %s'dan kopyalama"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Etiketler silindi"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Etiket kaydedildi"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Konu kaydedildi"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Konu silindi"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Kurtarılan kişi"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Kişi silindi"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Dosya yüklendi"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d dosyalar %d s içinde yüklendi"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Yükleme işlemi..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Yükleme işlemi tamamlandı"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Seçim onaylandı"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Seçim arşivlendi"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Seçim geri yüklendi"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Özel olarak işaretlenmiş seçim"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Albümler silindi"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip %d s içinde oluşturuldu"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Kalıcı olarak silindi"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s geri yüklendi"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Başarıyla doğrulandı"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Başarıyla etkinleştirildi"
#~ msgid "Storage is full"
#~ msgstr "Depolama alanı dolu"
#~ msgid "Invalid request"
#~ msgstr "Geçersiz istek"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: none\n"
"Language: uk\n"
"MIME-Version: 1.0\n"
@ -13,394 +13,425 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Щось пішло не так, спробуйте ще раз"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Неможливо це зробити"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Зміни не можливо зберегти"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Не можливо видалити"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s вже існує"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Не знайдено"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Файл не знайдено"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Файл занадто великий"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Не підтримується"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Непідтримуваний тип"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Непідтримуваний формат"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Папка з оригіналами порожня"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Вибір не знайдено"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Об'єкт не знайдено"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Обліковий запис не знайдено"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Користувача не знайдено"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Мітку не знайдено"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Камеру не знайдено"
#: messages.go:130
msgid "Lens not found"
msgstr "Об'єктив не знайдено"
#: messages.go:131
msgid "Album not found"
msgstr "Альбом не знайдено"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Тема не знайдена"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Особистість не знайдена"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Обличчя не знайдено"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Недоступно в публічному режимі"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "не доступно в режимі \"тільки читання\""
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Будь ласка, увійдіть до свого облікового запису"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "В доступі відмовлено"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Потрібна оплата"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Завантаження може бути образливим"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Помилка вивантаження"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Нічого не вибрано"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Помилка створення файла, перевірте дозволи"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Не вдалося створити папку, перевірте права доступу"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Не можливо підключитися, спробуйте знову"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Введіть код верифікації"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Невірний код верифікації, спробуйте знову"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "Невірний пароль, спробуйте знову"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Функцію вимкнено"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Мітки не вибрано"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Альбоми не вибрано"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Немає доступних файлів для завантаження"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Не вдалося створити zip-файл"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Недійсні облікові дані"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Невірне посилання"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Невірне ім'я"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Зайнято, спробуйте пізніше"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr ""
"Інтервал пробудження становить %s, але має становити 1 годину або менше"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Ваш обліковий запис не вдалося підключити"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "Занадто багато запитів"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Недостатнє зберігання"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Перевищено квоту"
#: messages.go:163
msgid "Registration disabled"
msgstr "Реєстрацію вимкнено"
#: messages.go:164
msgid "Verified email required"
msgstr "Потрібна підтверджена електронна адреса"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Зміни успішно збережено"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Альбом створено"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Альбом збережено"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Альбом %s видалено"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Вміст альбому клоновано"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Файл видалено з стеку"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Файл видалено"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Вибір додано до %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Один запис додано до %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d записів додано до %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Один запис видалено з %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d записів видалено з %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Обліковий запис створено"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Обліковий запис збережено"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Обліковий запис видалено"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Налаштування збережено"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "Пароль змінено"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Імпортування тривало %d с"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Імпортування скасовано"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Індексування тривало %d с"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Індексуємо оригінали..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Індексуємо файли в %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Індексування скасовано"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Видалено %d файлів та %d фотографій"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Переносимо файли з %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Копіюємо файли з %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Мітки видалено"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Мітку збережено"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Тема збережена"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Тема видалена"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Людина збережена"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Людина видалена"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "Файл завантажено"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "%d файлів вивантажено за %d с"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Обробка завантаження..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Завантаження оброблено"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Вибір затверджено"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Вибране заархівовано"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Вибране відновлено"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Вибіране позначено як приватне"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Альбом видалено"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip створено за %d с"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Остаточно видалено"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s було відновлено"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Верифікація успішна"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Активація успішна"
#~ msgid "Storage is full"
#~ msgstr "Сховище заповнене"
#~ msgid "Invalid request"
#~ msgstr "Невірний запит"

View file

@ -2,399 +2,430 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: none\n"
"Language: vi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "Đã xảy ra lỗi, hãy thử lại"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "Không thể làm điều đó"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "Không thể lưu các thay đổi"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "Không thể xóa được"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s đã tồn tại"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "Không tìm thấy"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "Không tìm thấy tập tin"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "Tệp quá lớn"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "Không được hỗ trợ"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "Loại không được hỗ trợ"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "Định dạng không được hỗ trợ"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "Thư mục gốc trống"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "Không tìm thấy lựa chọn"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "Không tìm thấy thực thể"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "Tài khoản không được tìm thấy"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "Không tìm thấy người dùng"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "Không tìm thấy nhãn"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "Không tìm thấy máy ảnh"
#: messages.go:130
msgid "Lens not found"
msgstr "Không tìm thấy ống kính"
#: messages.go:131
msgid "Album not found"
msgstr "Không tìm thấy album"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "Không tìm thấy chủ đề"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "Không tìm thấy người"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "Không tìm thấy khuôn mặt"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "Không khả dụng ở chế độ công khai"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "Không khả dụng ở chế độ chỉ đọc"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "Xin hãy đăng nhập vào tài khoản của bạn"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "Quyền bị từ chối"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "Yêu cầu thanh toán"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "Tải lên có thể gây khó chịu"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "Tải lên không thành công"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "Không có mục nào được chọn"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "Không tạo được tệp, vui lòng kiểm tra quyền"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "Không tạo được thư mục, vui lòng kiểm tra quyền"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "Không thể kết nối, vui lòng thử lại"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "Nhập mã xác nhận"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "Mã xác minh không hợp lệ, vui lòng thử lại"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "mật mã không hợp lệ, vui lòng thử lại"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "Tính năng bị tắt"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "Không có nhãn nào được chọn"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "Không có album nào được chọn"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "Không có tập tin nào để tải xuống"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "Không tạo được tệp zip"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "Thông tin không hợp lệ"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "Liên kết không hợp lệ"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "Tên không hợp lệ"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "Đang bận, vui lòng thử lại sau"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "Khoảng thời gian đánh thức là %s nhưng phải từ 1 giờ trở xuống"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "Tài khoản của bạn không thể kết nối được"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "quá nhiều yêu cầu"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "Không đủ dung lượng lưu trữ"
#: messages.go:162
msgid "Quota exceeded"
msgstr "Vượt quá hạn ngạch"
#: messages.go:163
msgid "Registration disabled"
msgstr "Đăng ký bị vô hiệu hóa"
#: messages.go:164
msgid "Verified email required"
msgstr "Cần có email đã được xác minh."
#: messages.go:167
msgid "Changes successfully saved"
msgstr "Đã lưu thay đổi thành công"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "Đã tạo album"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "Đã lưu album"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "Album %s đã bị xóa"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "Nội dung album được sao chép"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "Đã xóa tệp khỏi ngăn xếp"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "Đã xóa tệp"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "Đã thêm lựa chọn vào %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "Đã thêm một mục vào %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "Các mục %d được thêm vào %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "Đã xóa một mục khỏi %s"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "Các mục %d đã bị xóa khỏi %s"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "Tài khoản đã được tạo"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "Đã lưu tài khoản"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "Tài khoản đã bị xóa"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "Đã lưu cài đặt"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "mật khẩu đã được thay đổi"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "Quá trình nhập hoàn tất sau %d giây"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "Đã hủy nhập"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "Việc lập chỉ mục hoàn tất sau %d giây"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "Lập chỉ mục bản gốc..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "Lập chỉ mục các tệp trong %s"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "Đã hủy lập chỉ mục"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "Đã xóa tệp %d và ảnh %d"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "Di chuyển tệp từ %s"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "Sao chép tập tin từ %s"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "Đã xóa nhãn"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "Đã lưu nhãn"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "Đã lưu chủ đề"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "Chủ đề đã bị xóa"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "Người đã được cứu"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "Người đã bị xóa"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "File đã được tải lên"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "Các tệp %d được tải lên trong %d giây"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "Đang xử lý tải lên..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "Tải lên đã được xử lý"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "Lựa chọn đã được phê duyệt"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "Đã lưu trữ lựa chọn"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "Đã khôi phục lựa chọn"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "Lựa chọn được đánh dấu là riêng tư"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "Album đã bị xóa"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip được tạo trong %d giây"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "Đã xóa vĩnh viễn"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s đã được khôi phục"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "Đã xác minh thành công"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "Đã kích hoạt thành công"
#~ msgid "Storage is full"
#~ msgstr "Lưu trữ đã đầy"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: Chinese (Simplified) <https://translate.photoprism.app/"
"projects/photoprism/backend/zh_Hans/>\n"
"Language: zh\n"
@ -13,393 +13,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "出错了,再试一次"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "无法做到这一点"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "无法保存变更"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "无法删除"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s 已存在"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "未找到"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "未找到文件"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "文件过大"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "不支持"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "不支持的类型"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "不支持的格式"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "原件文件夹是空的"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "未找到所选内容"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "未找到实体"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "未找到账户"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "未找到用户"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "未找到标签"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "未找到摄像头"
#: messages.go:130
msgid "Lens not found"
msgstr "未找到镜头"
#: messages.go:131
msgid "Album not found"
msgstr "未找到相册"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "未找到主题"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "未找到人物"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "未找到面孔"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "在公开模式下不可用"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "在只读模式下不可用"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "请登录你的账户"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "没有权限"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "需要付款"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "上传内容可能具有冒犯性"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "上传失败"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "未选择任何项目"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "创建文件失败,请检查权限"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "创建目录失败,请检查权限"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "无法连接,请重试"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "输入验证码"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "验证码无效,请重试"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "无效密码,请重试"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "功能已禁用"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "未选择标签"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "未选择相册"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "没有可供下载的文件"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "创建压缩文件失败"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "无效凭证"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "无效链接"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "无效名称"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "忙碌中,请稍后重试"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "唤醒间隔为 %s但必须小于等于 1 小时"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "你的账户无法连接"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "请求太多"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "存储不足"
#: messages.go:162
msgid "Quota exceeded"
msgstr "超出配额"
#: messages.go:163
msgid "Registration disabled"
msgstr "注册已禁用"
#: messages.go:164
msgid "Verified email required"
msgstr "需要已验证的电子邮件地址"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "更改成功保存"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "相册已创建"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "相册已保存"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "相册 %s 已删除"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "相册内容已复制"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "文件已从堆中移除"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "文件已删除"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "所选项目已加入 %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "条目已添加到 %s"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d 个条目已添加到 %s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "条目已从 %s 移除"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d 个条目已从 %s 移除"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "账户已创建"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "账户已保存"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "账户已删除"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "设置已保存"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "密码已更改"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "导入成功,耗时 %d 秒"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "导入已取消"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "索引成功,耗时 %d 秒"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "索引源文件..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "索引 %s 中的文件"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "索引已取消"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "移除了 %d 个文件和 %d 张照片"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "正在从 %s 中移动文件"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "正在从 %s 中复制文件"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "标签已移除"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "标签已保存"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "主题已保存"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "主题已删除"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "人物已保存"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "人物已删除"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "已上传文件"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "已上传 %d 个文件,耗时 %d 秒"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "处理上传..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "上传已被处理"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "所选项已批准"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "所选项已归档"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "所选项已恢复"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "所选项已设为私有"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "相册已删除"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip 文件创建成功,耗时 %d 秒"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "已永久删除"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s 已恢复"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "验证成功"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "已成功激活"
#~ msgid "Storage is full"
#~ msgstr "存储空间已满"
#~ msgid "Invalid request"
#~ msgstr "无效请求"

View file

@ -2,10 +2,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-08 13:45+0000\n"
"PO-Revision-Date: 2024-07-05 09:24+0000\n"
"Last-Translator: Weblate Translation Memory <noreply-mt-weblate-translation-"
"memory@weblate.org>\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-"
"translate@weblate.org>\n"
"Language-Team: Chinese (Traditional) <https://translate.photoprism.app/"
"projects/photoprism/backend/zh_Hant/>\n"
"Language: zh_TW\n"
@ -13,393 +13,424 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.5.5\n"
"X-Generator: Weblate 2026.5\n"
#: messages.go:101
#: messages.go:112
msgid "Something went wrong, try again"
msgstr "出错了,再试一次"
#: messages.go:102
#: messages.go:113
msgid "Unable to do that"
msgstr "无法做到这一点"
#: messages.go:103
#: messages.go:114
msgid "Changes could not be saved"
msgstr "無法儲存更改項目"
#: messages.go:104
#: messages.go:115
msgid "Could not be deleted"
msgstr "無法刪除"
#: messages.go:105
#: messages.go:116
#, c-format
msgid "%s already exists"
msgstr "%s 已存在"
#: messages.go:106
#: messages.go:117
msgid "Not found"
msgstr "未找到"
#: messages.go:107
#: messages.go:118
msgid "File not found"
msgstr "未找到檔案"
#: messages.go:108
#: messages.go:119
msgid "File too large"
msgstr "文件過大"
#: messages.go:109
#: messages.go:120
msgid "Unsupported"
msgstr "不支援"
#: messages.go:110
#: messages.go:121
msgid "Unsupported type"
msgstr "不支援的類型"
#: messages.go:111
#: messages.go:122
msgid "Unsupported format"
msgstr "不支持的格式"
#: messages.go:112
#: messages.go:123
msgid "Originals folder is empty"
msgstr "原稿文件夾是空的"
#: messages.go:113
#: messages.go:124
msgid "Selection not found"
msgstr "未找到選取項目"
#: messages.go:114
#: messages.go:125
msgid "Entity not found"
msgstr "未找到實體"
#: messages.go:115
#: messages.go:126
msgid "Account not found"
msgstr "未找到帳號"
#: messages.go:116
#: messages.go:127
msgid "User not found"
msgstr "未找到使用者"
#: messages.go:117
#: messages.go:128
msgid "Label not found"
msgstr "未找到標籤"
#: messages.go:118
#: messages.go:129
msgid "Camera not found"
msgstr "未找到攝影機"
#: messages.go:130
msgid "Lens not found"
msgstr "未找到鏡頭"
#: messages.go:131
msgid "Album not found"
msgstr "未找到相簿"
#: messages.go:119
#: messages.go:132
msgid "Subject not found"
msgstr "未找到主體"
#: messages.go:120
#: messages.go:133
msgid "Person not found"
msgstr "找不到人"
#: messages.go:121
#: messages.go:134
msgid "Face not found"
msgstr "找不到面貌"
#: messages.go:122
#: messages.go:135
msgid "Not available in public mode"
msgstr "不適用於公開模式"
#: messages.go:123
#: messages.go:136
msgid "Not available in read-only mode"
msgstr "不適用於唯讀模式"
#: messages.go:124
#: messages.go:137
msgid "Please log in to your account"
msgstr "請登入您的帳戶"
#: messages.go:125
#: messages.go:138
msgid "Permission denied"
msgstr "權限遭拒"
#: messages.go:126
#: messages.go:139
msgid "Payment required"
msgstr "需要付款"
#: messages.go:140
msgid "Upload might be offensive"
msgstr "所上傳檔案可能會冒犯其他人"
#: messages.go:127
#: messages.go:141
msgid "Upload failed"
msgstr "上傳失敗"
#: messages.go:128
#: messages.go:142
msgid "No items selected"
msgstr "未選取任何項目"
#: messages.go:129
#: messages.go:143
msgid "Failed creating file, please check permissions"
msgstr "建立文件失敗,請檢查權限"
#: messages.go:130
#: messages.go:144
msgid "Failed creating folder, please check permissions"
msgstr "建立目錄失敗,請檢查權限"
#: messages.go:131
#: messages.go:145
msgid "Could not connect, please try again"
msgstr "無法連線,請重試"
#: messages.go:132
#: messages.go:146
msgid "Enter verification code"
msgstr "輸入驗證碼"
#: messages.go:133
#: messages.go:147
msgid "Invalid verification code, please try again"
msgstr "驗證碼無效,請重試"
#: messages.go:134
#: messages.go:148
msgid "Invalid password, please try again"
msgstr "密碼無效,請重試"
#: messages.go:135
#: messages.go:149
msgid "Feature disabled"
msgstr "功能未開啟"
#: messages.go:136
#: messages.go:150
msgid "No labels selected"
msgstr "未選擇標籤"
#: messages.go:137
#: messages.go:151
msgid "No albums selected"
msgstr "未選取相簿"
#: messages.go:138
#: messages.go:152
msgid "No files available for download"
msgstr "没有可以下載的檔案"
#: messages.go:139
#: messages.go:153
msgid "Failed to create zip file"
msgstr "建立 zip 檔失敗"
#: messages.go:140
#: messages.go:154
msgid "Invalid credentials"
msgstr "認證無效"
#: messages.go:141
#: messages.go:155
msgid "Invalid link"
msgstr "超連結無效"
#: messages.go:142
#: messages.go:156
msgid "Invalid name"
msgstr "無效名稱"
#: messages.go:143
#: messages.go:157
msgid "Busy, please try again later"
msgstr "忙碌中,請稍候再試"
#: messages.go:144
#: messages.go:158
#, c-format
msgid "The wakeup interval is %s, but must be 1h or less"
msgstr "喚醒間隔為 %s但必須少於1 小時"
#: messages.go:145
#: messages.go:159
msgid "Your account could not be connected"
msgstr "您的賬戶無法連接"
#: messages.go:146
#: messages.go:160
msgid "Too many requests"
msgstr "请求太多"
#: messages.go:149
#: messages.go:161
msgid "Insufficient storage"
msgstr "儲存空間不足"
#: messages.go:162
msgid "Quota exceeded"
msgstr "超過配額"
#: messages.go:163
msgid "Registration disabled"
msgstr "註冊已停用"
#: messages.go:164
msgid "Verified email required"
msgstr "需要已驗證的電子郵件地址"
#: messages.go:167
msgid "Changes successfully saved"
msgstr "成功儲存變更"
#: messages.go:150
#: messages.go:168
msgid "Album created"
msgstr "相簿已建立"
#: messages.go:151
#: messages.go:169
msgid "Album saved"
msgstr "相簿已儲存"
#: messages.go:152
#: messages.go:170
#, c-format
msgid "Album %s deleted"
msgstr "相簿 %s 已刪除"
#: messages.go:153
#: messages.go:171
msgid "Album contents cloned"
msgstr "相簿内容已被複製"
#: messages.go:154
#: messages.go:172
msgid "File removed from stack"
msgstr "檔案已從堆疊中移除"
#: messages.go:155
#: messages.go:173
msgid "File deleted"
msgstr "檔案已刪除"
#: messages.go:156
#: messages.go:174
#, c-format
msgid "Selection added to %s"
msgstr "選取項目已加入 %s"
#: messages.go:157
#: messages.go:175
#, c-format
msgid "One entry added to %s"
msgstr "已在 %s 增加一個項目"
#: messages.go:158
#: messages.go:176
#, c-format
msgid "%d entries added to %s"
msgstr "%d個項目已加入%s"
#: messages.go:159
#: messages.go:177
#, c-format
msgid "One entry removed from %s"
msgstr "已從 %s 移除一個項目"
#: messages.go:160
#: messages.go:178
#, c-format
msgid "%d entries removed from %s"
msgstr "%d 個項目已從 %s 移除"
#: messages.go:161
#: messages.go:179
msgid "Account created"
msgstr "帳號已建立"
#: messages.go:162
#: messages.go:180
msgid "Account saved"
msgstr "帳號已儲存"
#: messages.go:163
#: messages.go:181
msgid "Account deleted"
msgstr "帳號已刪除"
#: messages.go:164
#: messages.go:182
msgid "Settings saved"
msgstr "設定已儲存"
#: messages.go:165
#: messages.go:183
msgid "Password changed"
msgstr "密碼已更改"
#: messages.go:166
#: messages.go:184
#, c-format
msgid "Import completed in %d s"
msgstr "匯入成功, 共用 %d 秒"
#: messages.go:167
#: messages.go:185
msgid "Import canceled"
msgstr "匯入取消"
#: messages.go:168
#: messages.go:186
#, c-format
msgid "Indexing completed in %d s"
msgstr "索引建立成功, 共用 %d 秒"
#: messages.go:169
#: messages.go:187
msgid "Indexing originals..."
msgstr "索引原始檔案..."
#: messages.go:170
#: messages.go:188
#, c-format
msgid "Indexing files in %s"
msgstr "建立 %s 中的檔案索引"
#: messages.go:171
#: messages.go:189
msgid "Indexing canceled"
msgstr "建立索引取消"
#: messages.go:172
#: messages.go:190
#, c-format
msgid "Removed %d files and %d photos"
msgstr "刪除了 %d 個檔案和 %d 張照片"
#: messages.go:173
#: messages.go:191
#, c-format
msgid "Moving files from %s"
msgstr "正在從 %s 中移動檔案"
#: messages.go:174
#: messages.go:192
#, c-format
msgid "Copying files from %s"
msgstr "正在從 %s 中複製檔案"
#: messages.go:175
#: messages.go:193
msgid "Labels deleted"
msgstr "已刪除標籤"
#: messages.go:176
#: messages.go:194
msgid "Label saved"
msgstr "標籤已儲存"
#: messages.go:177
#: messages.go:195
msgid "Subject saved"
msgstr "主題已儲存"
#: messages.go:178
#: messages.go:196
msgid "Subject deleted"
msgstr "主題已刪除"
#: messages.go:179
#: messages.go:197
msgid "Person saved"
msgstr "人物已儲存"
#: messages.go:180
#: messages.go:198
msgid "Person deleted"
msgstr "人物已刪除"
#: messages.go:181
#: messages.go:199
msgid "File uploaded"
msgstr "檔案上傳成功"
#: messages.go:182
#: messages.go:200
#, c-format
msgid "%d files uploaded in %d s"
msgstr "已上傳 %d 個檔案, 共用 %d 秒"
#: messages.go:183
#: messages.go:201
msgid "Processing upload..."
msgstr "正在處理上傳..."
#: messages.go:184
#: messages.go:202
msgid "Upload has been processed"
msgstr "上傳已處理完畢"
#: messages.go:185
#: messages.go:203
msgid "Selection approved"
msgstr "選取項目已認可"
#: messages.go:186
#: messages.go:204
msgid "Selection archived"
msgstr "選取項目已封存"
#: messages.go:187
#: messages.go:205
msgid "Selection restored"
msgstr "選取項目已被復原"
#: messages.go:188
#: messages.go:206
msgid "Selection marked as private"
msgstr "選取項目已設為私人"
#: messages.go:189
#: messages.go:207
msgid "Albums deleted"
msgstr "相簿已刪除"
#: messages.go:190
#: messages.go:208
#, c-format
msgid "Zip created in %d s"
msgstr "Zip檔建立成功, 共用 %d 秒"
#: messages.go:191
#: messages.go:209
msgid "Permanently deleted"
msgstr "永久刪除"
#: messages.go:192
#: messages.go:210
#, c-format
msgid "%s has been restored"
msgstr "%s 已被回復"
#: messages.go:193
#: messages.go:211
msgid "Successfully verified"
msgstr "驗證成功"
#: messages.go:194
#: messages.go:212
msgid "Successfully activated"
msgstr "激活成功"
#~ msgid "Storage is full"
#~ msgstr "儲存空間已滿"
#~ msgid "Invalid request"
#~ msgstr "無效請求"

2
assets/models/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*
!.gitignore

122
assets/profiles/icc/NOTICE Normal file
View file

@ -0,0 +1,122 @@
================================================================================
================================================================================
Third-Party ICC Profiles for PhotoPrism
--------------------------------------------------------------------------------
The following 3rd-party ICC profiles 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: 2025-11-23
--------------------------------------------------------------------------------
Files: a98.icc (compatibleWithAdobeRGB1998.icc)
Source: OpenICC "compatibleWithAdobeRGB1998.icc" via Debian icc-profiles-free
URL: https://salsa.debian.org/debian/icc-profiles-free/-/blob/a7a3c11b8a6d3bc2937447183b87dc89de9d2388/icc-profiles-openicc/default_profiles/base/compatibleWithAdobeRGB1998.icc
License: zlib/libpng
Checksum (md5): 826a1e13374e3dc34f9872f31ec028c8
The zlib/libpng License
Copyright (c) Graeme Gill <graeme@argyllcms.com>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
The provided ICC Profiles in the package are called DATA in the following
statement:
NO WARRANTY
BECAUSE THE DATA IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE DATA, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE DATA "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE DATA IS WITH YOU. SHOULD THE
DATA PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE DATA AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE DATA (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE DATA TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
--------------------------------------------------------------------------------
Files: adobecompat-v2.icc, adobecompat-v4.icc, applecompat-v2.icc, applecompat-v4.icc, cgats001compat-v2-micro.icc, colormatchcompat-v2.icc, colormatchcompat-v4.icc, dci-p3-v4.icc, displayp3-v2-magic.icc, displayp3-v2-micro.icc, displayp3-v4.icc, displayp3compat-v2-magic.icc, displayp3compat-v2-micro.icc, displayp3compat-v4.icc, prophoto-v2-magic.icc, prophoto-v2-micro.icc, prophoto-v4.icc, rec2020-g24-v4.icc, rec2020-v2-magic.icc, rec2020-v2-micro.icc, rec2020-v4.icc, rec2020compat-v2-magic.icc, rec2020compat-v2-micro.icc, rec2020compat-v4.icc, rec601ntsc-v2-magic.icc, rec601ntsc-v2-micro.icc, rec601ntsc-v4.icc, rec601pal-v2-magic.icc, rec601pal-v2-micro.icc, rec601pal-v4.icc, rec709-v2-magic.icc, rec709-v2-micro.icc, rec709-v4.icc, scrgb-v2.icc, sgrey-v2-magic.icc, sgrey-v2-micro.icc, sgrey-v2-nano.icc, sgrey-v4.icc, srgb-v2-magic.icc, srgb-v2-micro.icc, srgb-v2-nano.icc, srgb-v4.icc, widegamutcompat-v2.icc, widegamutcompat-v4.icc
Source: Compact-ICC-Profiles via Debian icc-profiles-free
URL: https://salsa.debian.org/debian/icc-profiles-free/-/tree/a7a3c11b8a6d3bc2937447183b87dc89de9d2388/Compact-ICC-Profiles/profiles
License: CC0-1.0 (Public Domain Dedication)
Checksums (md5):
adobecompat-v2.icc 08220aa4b4e4259ec3c446a35197d89b
adobecompat-v4.icc fbf912760a8d14e496ff389c29c3132d
applecompat-v2.icc 21453c734d9364abceacc7ab837019ec
applecompat-v4.icc fc399558e27a0d53748820cff2a98a2b
cgats001compat-v2-micro.icc 56a85233ee08fa7527875be36cf426d6
colormatchcompat-v2.icc 9f2a755b4b3069f46f4eaef11e24926d
colormatchcompat-v4.icc 9e119efb0abaa31e955f8a30eeabc58c
dci-p3-v4.icc bdedf9e7ad0b93ed8f85f8c3ebdc4223
displayp3-v2-magic.icc 6748fcfd56d38770a02c023bbd6d0529
displayp3-v2-micro.icc 2615293123ddc4366af3da39455c3d7a
displayp3-v4.icc 32dc35d6a113b86cbc31bd1281e3baed
displayp3compat-v2-magic.icc 05fb82a702e27438ecec47a2f120cdcd
displayp3compat-v2-micro.icc 2ef6c295ac5d05760c1a4cf1668951a3
displayp3compat-v4.icc c34c90451326b183916f05b3ae41d920
prophoto-v2-magic.icc 15a31d407cf35662fbe4513f6204bfdf
prophoto-v2-micro.icc 445c1a3f3f1a20aab68e76838d3ed334
prophoto-v4.icc 8f4523255234753cd2d3111d8f09b184
rec2020-g24-v4.icc 3c7afbfff612d10a10775c167d36b51e
rec2020-v2-magic.icc 3b5846fb69faa53ebdfd29061f17b0e3
rec2020-v2-micro.icc 13d1e96875c35f7d5ebaf0f6a3d16357
rec2020-v4.icc 297c644758a979abe62349ca1ff416d5
rec2020compat-v2-magic.icc 9aa85534e81c275bc0627badf157580a
rec2020compat-v2-micro.icc fa39fc95daece7dcaff18e7265082368
rec2020compat-v4.icc 66839229639bb55bc443b490fe302364
rec601ntsc-v2-magic.icc 53ee12707ac87a8e3b3452af4a325e29
rec601ntsc-v2-micro.icc af05afec2146917a67445ac6cb5ca61d
rec601ntsc-v4.icc cc57dd6fa3d6f08e43e0f70b5376c00a
rec601pal-v2-magic.icc f706fd528cedcd1c88dac50073112f94
rec601pal-v2-micro.icc d193e01949eb5347b0d16d2b3ccdabcf
rec601pal-v4.icc dd7cd61d6ee14a521c9fb5afa2803e8e
rec709-v2-magic.icc 47f09046656a2f0d66117a9c1b15e137
rec709-v2-micro.icc f91edc9f3ff1390c842bd9e8759688b0
rec709-v4.icc 0339e2a70940aefd9237311889d065e6
scrgb-v2.icc a841263101bdf48fb9b81486f5451f2d
sgrey-v2-magic.icc ef6221686b517e4665480639202dacd5
sgrey-v2-micro.icc ca08451dba57ca1e910330cda37515ad
sgrey-v2-nano.icc 57d72e3f6437d65c618ebcdb1f6fa1bd
sgrey-v4.icc b93b1e31e75243ea08fbdab9e82f7cbe
srgb-v2-magic.icc 5967f401f9a54913a283942710cef93c
srgb-v2-micro.icc e8de3a5b44d70610306b0a20225701d1
srgb-v2-nano.icc e060a57b7a057f7f0bdb859b68db60e9
srgb-v4.icc 3c6a277ddee033ad090ba22b8323dcaf
widegamutcompat-v2.icc 63c0165987ee94c8c7f2c68749e0418d
widegamutcompat-v4.icc 4ccb168ae2f7daa51d3cef7df6fa6f16
--------------------------------------------------------------------------------

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