Compare commits

..

402 Commits

Author SHA1 Message Date
Zack Pollard
61c4b27b94 refactor: rename background service to legacy 2025-08-06 11:06:15 +01:00
Jason Rasmussen
a5760129f0 fix: custom-url ssr (#20704) 2025-08-05 23:29:01 +02:00
Gaurav Yadav
d430b869ac fix: shared link custom URL photo access authentication (#20534) 2025-08-05 23:22:19 +02:00
Brandon Wees
4179c8a17d fix(mobile): filter people that have less than 3 faces (#20705) 2025-08-05 21:16:13 +00:00
Zack Pollard
0a9cbf01d2 feat: ack sync reset (#20703) 2025-08-05 20:30:19 +00:00
Alex
9567a2a560 fix: delete local asset show twice (#20700)
* chore: better button width

* fix: delete local action show twice
2025-08-05 19:18:57 +00:00
renovate[bot]
58dd6f094c chore(deps): update dependency @types/bcrypt to v6 (#20669)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 19:58:08 +02:00
Zack Pollard
02381343ff fix: album asset sync must sync new assets in a shared album (#20655) 2025-08-05 17:53:51 +01:00
Mert
09a5963eee fix(mobile): catch thumbnail cache miss (#20694)
catch error
2025-08-05 11:32:06 -05:00
Alex
a573a23c83 fix: empty custom header prevent logging in (#20693) 2025-08-05 16:14:21 +00:00
Brandon Wees
7118dca559 feat(mobile): album shared user editing (#20671)
* feat(mobile): album shared user editing

* fix: album leaving

* i18n and options button

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-08-05 15:31:58 +00:00
Brandon Wees
13d43e193e feat(mobile): use custom headers when connecting in widget (#20666)
* feat(mobile): use custom headers when connecting in widget

* delete log in android widget

* chore: code review changes
2025-08-05 10:29:27 -05:00
Brandon Wees
7a7843467c feat(mobile): remove from album in asset viewer bar (#20672)
* feat: remove from album in asset viewer bar

* chore: move button to bottom bar instead of bottom sheet

* move back to bottom sheet

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-08-05 15:20:55 +00:00
Mert
9e6fee4064 fix(mobile): use cached thumbnail in full size image provider (#20637) 2025-08-05 10:20:25 -04:00
shenlong
9680f1290d fix: exclude assets that haven't been hashed yet from uploads (#20684)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-08-05 08:35:25 -05:00
renovate[bot]
ce2ea98926 fix(deps): update typescript-projects (#20396)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-08-05 12:45:47 +00:00
renovate[bot]
5c76cc34e1 chore(deps): update node.js to v22.18.0 (#20662)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 11:01:15 +00:00
renovate[bot]
eb2f4c866e chore(deps): update dependency eslint-plugin-unicorn to v60 (#20677)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-08-05 10:58:13 +00:00
renovate[bot]
2a370087e8 chore(deps): update dependency @types/node to ^22.17.0 (#20657)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 11:56:53 +01:00
renovate[bot]
272c8a5812 chore(deps): update grafana/grafana docker tag to v12.1.0 (#20661)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 11:56:05 +01:00
renovate[bot]
08fe549ed8 chore(deps): update base-image to v202507291116 (major) (#20668)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 11:54:37 +01:00
renovate[bot]
ae15efdf2a chore(deps): update dependency pigeon to v26 (#20678)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-08-05 10:52:03 +00:00
renovate[bot]
8e003f95db chore(deps): update github/codeql-action action to v3.29.5 (#20656)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-05 11:44:50 +01:00
Brandon Wees
3e92e837f1 feat(mobile): create shared link for albums (#20652)
* feat(mobile): create shared link for albums

* translation

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-08-05 01:51:45 +00:00
Brandon Wees
081307ced2 fix: expand sheet when album search is focused (#20651)
* fix: expand sheet when album search is focused

* convert GeneralBottomSheet to ConsumerStatefulWidget

* fix: cleaning up

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-08-04 20:35:57 -05:00
Michael
a91bb399f0 feat: add server.versionCheck permission (#20555)
* add server.versionCheck permission

* getVersionCheck is no admin-route
2025-08-04 17:39:05 -05:00
Brandon Wees
42b78c59b5 fix(mobile): disable memory lane when memories are disabled (#20642)
* fix(mobile): disable memory lane when memories are disabled

* Update main_timeline.page.dart

* fix: formatting

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-08-04 22:34:28 +00:00
Brandon Wees
750d21aeba fix(mobile): use storageIndicator setting for beta timeline (#20639)
* fix: use storageIndicator setting for beta timeline

* fix: reactively update the storage indicator icons when setting is changed

* Update drift_trash.page.dart

* override to bool for storageIndicator
2025-08-04 17:25:58 -05:00
Paweł Wojtaszko
990d9ba9a8 fix: adjust margin and gap for trailing elements in control app bar (#20645) 2025-08-04 17:24:19 -05:00
Brandon Wees
4d0c9172e5 fix: not clearing local data when logging out while sync is running (#20646) 2025-08-04 17:14:26 -05:00
Brandon Wees
094e3a2757 fix(mobile): cleanly handle logout when no host is set (#20521)
* fix: cleanly handle logging out when no host is set on API

* move conditional to auth_api repo
2025-08-05 03:11:58 +05:30
Zack Pollard
278668b8c5 fix: improvements to sync and upload when resuming app (#20524)
- App will now kick off hashing after local sync if the lifecycle is in resumed or active state
- We now wait for hashing to complete before we kick off the upload process
2025-08-05 03:11:44 +05:30
cford256
10141504a2 fix: exif rating rounding (#20457)
* fix_Exlif_Metadata_Rating_Rounding_to_Interger

Rounding Exlif Rating Interger
Images support having numbers other than integers for the rating metadata in EXLIF. The database expects it to be an integer though. Trying to upload an image that has a rating other than an integer results in it failing to parse the image and defaulting to showing a corrupted file icon. 

Rather than changing the database type, I would like to round the rating to the nearest integer so that Immich works with images that have a rating like this in their metadata.

* Changing Metadata validateRange to always round.

* Update server/src/services/metadata.service.ts

Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>

---------

Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
2025-08-04 14:29:51 -05:00
Brandon Wees
67736c8fce fix(mobile): fetch serverConfig before building shared link (#20638)
fix(mobile): fetch serverConfig before trying to pull externalDomain for new shared link
2025-08-04 14:28:43 -05:00
Paweł Wojtaszko
b56a272f64 fix: adjust search bar padding and visibility based on input state (#20598) 2025-08-04 17:46:46 +00:00
shenlong
5901c2e963 fix: hide navigation bar in search page during multi-selection (#20616)
fix: hide navigation bar in search page during multiselect

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-08-04 12:39:40 -05:00
Alex
be85832b20 fix: add assets to album (#20626)
* fix: add assets to album

* always navigate back to the albums view from album page
2025-08-04 12:25:11 -05:00
bo0tzz
c8f9a72d3e feat: close likely duplicates (#20556)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-08-04 18:15:15 +02:00
Alexandre Garnier
3d633a81c4 fix(mobile): use right translation function for pluralized ICU message format (#20404) 2025-08-04 11:53:11 +05:30
shenlong
4efbf36d82 chore: log asset name on hash failures (#20608) 2025-08-04 06:07:50 +00:00
Alden Bansemer
e2c3c39597 chore: tweak photo sphere fov and zoom speed constants (#20595) 2025-08-04 01:07:11 -05:00
github-actions
007ba1d9ef chore: version v1.137.3 2025-08-01 14:52:24 +00:00
Daniel Dietzler
4d5cd1a6b5 fix: migration if media location is set (#20532) 2025-08-01 14:49:51 +00:00
shenlong
8108f50c4e fix: guard IS_FAVORITE column with SDK check (#20511)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-08-01 05:39:59 -05:00
Alex
1b8354ed36 chore: post release tasks (#20497) 2025-08-01 05:38:52 -05:00
github-actions
9242afb4b0 chore: version v1.137.2 2025-08-01 02:45:16 +00:00
Alex
c5f14adff0 feat: drag to select beta timeline (#20456) 2025-07-31 21:29:01 -05:00
Alex
1378f22368 fix: add to album render empty app bar (#20480)
* fix: add to album render empty app bar

* set current album
2025-07-31 21:28:33 -05:00
Alex
4bd465e752 feat: change grid size with gesture (#20455) 2025-07-31 21:02:28 -05:00
github-actions
a07531be3b chore: version v1.137.1 2025-07-31 23:05:34 +00:00
Daniel Dietzler
3cdc6844a1 fix: automatic media location migration without internal assets (#20489) 2025-07-31 22:58:35 +00:00
github-actions
c3263e50fc chore: version v1.137.0 2025-07-31 20:19:26 +00:00
Alex
7391ea6ff9 chore: large file size grid view styling (#20472)
* chore: large file grid styles

* chore: large file grid styles
2025-07-31 12:52:19 -04:00
Daniel Dietzler
f972b8d514 fix: modal race conditions (#20460) 2025-07-31 07:28:45 -05:00
Jason Rasmussen
6b50d958f4 fix: incorrect next/previous action after folder view refresh (#20447) 2025-07-30 14:50:52 -05:00
Alex
27c456eb75 fix: people navigation (#20450) 2025-07-30 14:47:47 -05:00
Brandon Wees
e7d051db3c feat: drift edit time and date action (#20377)
* feat: drift edit time and date action

* feat: add edit button on asset viewer bottom sheet

* update localDateTime column in addition to createdAt to keep consistency

* fix: dont update local dateTime

Server calcs this anyway and it will be synced when the change is applied. We don't use localDateTime on mobile so there is no reason to update this value

* fix: padding around edit icon in ListTile

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>

* chore: format

* fix: hide date edit control when asset does not have a remote

* fix: pull timezones correctly from image

---------

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
2025-07-30 14:40:13 -05:00
Peter Ombodi
86d31d7d29 fix(download): handle completed downloads and refresh albums (#20241)
* fix(download): handle completed downloads and refresh albums

* fix(download): remove use of outdated AlbumService

---------

Co-authored-by: Peter Ombodi <peter.ombodi@gmail.com>
2025-07-30 14:33:55 -05:00
shenlong
f416342eff fix: clear local file cache before upload (#20448)
* clear local file cache before upload

* clear cache during hashing

* fix test

* add button to clear cache manually

* add button to clear cache manually

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-30 14:32:38 -05:00
Cédric
d73335ecbc docs: add config example for Authelia (#20223) 2025-07-30 19:13:19 +00:00
shenlong
641a3baadd fix(mobile): add partial index based on library ID to remote assets (#20214)
* feat: add libraryId to SyncAssetV1

* add partial index

# Conflicts:
#	mobile/drift_schemas/main/drift_schema_v5.json
#	mobile/lib/infrastructure/repositories/db.repository.dart
#	mobile/lib/infrastructure/repositories/db.repository.steps.dart
#	mobile/test/drift/main/generated/schema_v5.dart

* chore: make build

* rebase

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-30 23:59:00 +05:30
shenlong
f85d8add01 fix: json encoding failure during live photo download (#20444)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-30 12:48:18 -05:00
Weblate (bot)
c278b7ad17 chore(web): update translations (#20105)
Co-authored-by: AbuKareem Tuffaha <abukareem.tuffaha@gmail.com>
Co-authored-by: Adam Uchmanowicz <auchmanowicz@gmail.com>
Co-authored-by: AgentTricky <andreweditz26@gmail.com>
Co-authored-by: Alexandre Garnier <zigarn@users.noreply.hosted.weblate.org>
Co-authored-by: Alvin <ekzistadismo@gmail.com>
Co-authored-by: Andreas Johansen <andreas@josern.com>
Co-authored-by: Bartłomiej <20731216+Jarsey45@users.noreply.github.com>
Co-authored-by: Bartłomiej <bartek.yt01@gmail.com>
Co-authored-by: Benjamin Graf <benjamin@eende.net>
Co-authored-by: CanbiZ <mickey.leskowitz@gmail.com>
Co-authored-by: Cezar Olteanu <lecezar2014@gmail.com>
Co-authored-by: Christoph Auer <Christoph.Auer@pilsheim.de>
Co-authored-by: Dag Stuan <D.Stuan@gmail.com>
Co-authored-by: Davide Ciaccia <davideccia@gmail.com>
Co-authored-by: Davide Vegliante <davidevegliante@gmail.com>
Co-authored-by: Dennis Premoli <dennis.premoli@gmail.com>
Co-authored-by: DevServs <bonov@mail.ru>
Co-authored-by: Dmitry Banny <dj.icecore@gmail.com>
Co-authored-by: Felipe Silva <dorsal-cobweb-life@duck.com>
Co-authored-by: Fjuro <fjuro@alius.cz>
Co-authored-by: Florian Ostertag <florian.kuepper@gmail.com>
Co-authored-by: Hurricane-32 <rodrigorimo@hotmail.com>
Co-authored-by: Indrek Haav <indrek.haav@hotmail.com>
Co-authored-by: Javier Villanueva García <jvg2203@gmail.com>
Co-authored-by: John Molkavitch <jblum66@gmail.com>
Co-authored-by: Jordy H <jordy@hoebergen.net>
Co-authored-by: Jozef Gaal <preklady@mayday.sk>
Co-authored-by: Kasper Honoré <kasper@honore-stens.dk>
Co-authored-by: Lauritz Tieste <lauritz6000000@gmail.com>
Co-authored-by: Leo Bottaro <github@leobottaro.com>
Co-authored-by: MaBeniu <marius.beniusis@teliacompany.com>
Co-authored-by: Mateo Varela <matevarela32@gmail.com>
Co-authored-by: Matjaž T <matjaz@moj-svet.si>
Co-authored-by: Mikkel Dupont Olesen <m-do2009@hotmail.com>
Co-authored-by: Musab Ustun <musabyusufustun@outlook.com>
Co-authored-by: Mārtiņš Bruņenieks <martinsb@gmail.com>
Co-authored-by: Nick Huang <nick80322@gmail.com>
Co-authored-by: Nico Kaiser <nico@kaiser.me>
Co-authored-by: Nicolò <nicveronese@gmail.com>
Co-authored-by: Nikolina Babok <nikolinababok83@gmail.com>
Co-authored-by: Pavel Miniutka <pavel.miniutka@gmail.com>
Co-authored-by: Petri Hämäläinen <petri.hamalainen@mailbox.org>
Co-authored-by: Phantom0174 <darrenhsiou@gmail.com>
Co-authored-by: R J <robindanoskarjohansson@gmail.com>
Co-authored-by: Raman Venmarathoor <ramanvemman@gmail.com>
Co-authored-by: Santiago <santiwever@hotmail.com>
Co-authored-by: Saschl <sascharudolf46@gmail.com>
Co-authored-by: Sergey Katsubo <skatsubo@gmail.com>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Sylvain Pichon <service@spichon.fr>
Co-authored-by: Tajbir Prottoy <tajbirprottoy@gmail.com>
Co-authored-by: Tanishq Sindhu <hisar.champion@gmail.com>
Co-authored-by: Tijs-B <tijs.bergmans@telenet.be>
Co-authored-by: Tony Ronaldo Matute <tonyronaldomatute@gmail.com>
Co-authored-by: User 123456789 <user123456789@users.noreply.hosted.weblate.org>
Co-authored-by: Vegard Fladby <vegard@fladby.org>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: Zvonimir <zzrakic@protonmail.com>
Co-authored-by: adri1m64 <adrien.melle@laposte.net>
Co-authored-by: chamdim <chamdim@protonmail.com>
Co-authored-by: eav5jhl0 <eav5jhl0@users.noreply.hosted.weblate.org>
Co-authored-by: grgergo <gergo_g@proton.me>
Co-authored-by: johnwoo_nl <pb@lunenburg-productions.nl>
Co-authored-by: manosrh <manosrh@gmail.com>
Co-authored-by: maxius65 <max.dewispelaere@hotmail.com>
Co-authored-by: neketos851 <kokgp554t@mozmail.com>
Co-authored-by: over adm <1ron3gg@gmail.com>
Co-authored-by: pyccl <changcongliang@163.com>
Co-authored-by: syyhs668 <812741539@qq.com>
Co-authored-by: thehijacker <thehijacker@gmail.com>
Co-authored-by: traptegies <lars.reuss@gmx.de>
Co-authored-by: tsloms <t.slomski@outlook.de>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
2025-07-30 18:16:47 +01:00
Alex
10e9c278ee feat: network requirement option for upload (#20302)
* wifi toggle

* feat: network requirement option for upload

* chore: put back holding queue previous config numbers

* options

* backup option page

* pr feedback
2025-07-30 22:13:20 +05:30
bo0tzz
47a025f39f chore: also run docs build on oapi changes (#20440) 2025-07-30 13:30:21 -03:00
Jason Rasmussen
749f999f2a feat: better endpoint descriptions (#20439) 2025-07-30 13:29:36 -03:00
Jason Rasmussen
d5a01c0310 fix(web): timeline time bucket issue (#20438) 2025-07-30 11:21:02 -05:00
Brandon Wees
097e132fba fix: user profile images not working in beta timeline (#20203)
* fix user icons in album view

* revert updateUsersV1 change

* fix: UserDto merge issues

* fix: update user entity

* revert what I thought were merge issues

turns out drift cant figure out when it needs to gen a file...

* fix removed line

* handle defaults for older servers

* feat: checkpoint migrations

* fix: use parenthesis instead of brackets

* Update 1753800911775-ProfileImageCheckpointRemoval.ts

* fix: sync stream updateUsersV1
2025-07-30 11:09:28 -05:00
shenlong
da5deffd03 fix: exclude assets from excluded albumbs on main timeline (#20425)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-30 10:16:23 -05:00
shenlong
9f20522df5 chore: add isFavorite to PlatformAsset in duplicate check (#20427)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-30 08:44:19 -05:00
Ben
baadf9db20 fix(web): timeline date group width (#19964)
Fix the calculation for the date group width, so there's never a scenario where photos will be hidden. On mobile devices, photos in the second row can sometimes have a top of <100px, which throws off the calculation of the date group width.
2025-07-30 08:39:19 -04:00
xCJPECKOVERx
4ea4ee40af fix(web): Search chip key value heights don't match (#20312)
- add flex items-stretch to stretch chip key height to match value height
2025-07-30 08:31:16 -04:00
renovate[bot]
d8a6552811 chore(deps): update ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0 docker digest to 32324a2 (#20381)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-30 08:29:37 -04:00
renovate[bot]
444133a72b chore(deps): update ghcr.io/immich-app/postgres:14-vectorchord0.3.0 docker digest to 0e763a2 (#20380)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-30 10:36:50 +00:00
Alex
29f16c6a47 feat: people page/sheet/detail (#20309) 2025-07-30 03:07:53 +00:00
shenlong
268b411a6f fix: sync is_favorite from native (#20412)
* feat: sync is_favorite from native

* handle favorite during upload

* Update mobile/ios/Runner/Sync/MessagesImpl.swift

Co-authored-by: Alex <alex.tran1502@gmail.com>

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-29 21:57:04 -05:00
Brandon Wees
07ed060c32 feat: 3-2-1 backup onboarding card (#20374)
* feat: 3-2-1 backup onboarding card

* chore: format i18n

* fix: lint

* Update onboarding-backup.svelte

* fix: e2e onboarding test
2025-07-29 21:55:21 -05:00
Jason Rasmussen
2f5d543ad9 fix: tweak error docs (#20417) 2025-07-29 21:33:24 +00:00
Jason Rasmussen
9b65cd4d7b feat!: remove typeorm (#20366)
feat: remove typeorm
2025-07-29 17:28:02 -04:00
Brandon Wees
290e325c5c feat: drift description editor (#20383)
* feat: drift description editor

* chore: use focus node

* chore: code review fixes

* chore: move description update to action.service

* refactor

* refactor

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-29 21:17:33 +00:00
Jason Rasmussen
58521c9efb feat: change default media location to /data (#20367)
* feat!: change default media location to /data

* feat: dynamically detect media location
2025-07-29 16:58:50 -04:00
Andrew Marshall
4cae15f28d feat: support config via systemd credentials (#20406)
feat: Support config via Systemd Credentials

See https://systemd.io/CREDENTIALS/. This is used as a fallback, so will
only be used if the `$*_FILE` var is empty. This could also be used to
implicitly use Docker Secrets by settings
`CREDENTIALS_DIRECTORY=/run/secrets` rather than setting individual
`$_*FILE` environment variables.
2025-07-29 16:43:11 -04:00
shenlong
e6ec019852 fix: show missing local assets only in timeline with partner sharing (#20298)
fix: show missing local assets in timeline with partner sharing

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-29 10:05:04 -05:00
Brandon Wees
3b5e00131b fix: android widget periodic updates (#20389)
* fix: android widget updates

* ensure periodic work is queued when we receive an update

This will not "reset the clock" on the periodic work since we are using         ExistingPeriodicWorkPolicy.UPDATE. This is needed since existing widgets have already been asked to queue their workers. If those periodic workers were overwritten by a widget update request from the app, there is no way to queue them again. onReceive gets run when the app requests a widget update so the periodic workers will get queued again.
2025-07-29 08:59:10 -05:00
Zack Pollard
a0fa7318ed fix: handle cleanup of new backups alongside old backups (#20402) 2025-07-29 13:28:10 +01:00
Zack Pollard
2a005629a0 chore: bump minimum eslint-config-prettier version due to MAL-2025-6022 (#20400) 2025-07-29 11:23:52 +00:00
renovate[bot]
59a50b8697 chore(deps): update github-actions (#20384)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-29 12:07:14 +01:00
renovate[bot]
90eac40e02 chore(deps): update terraform cloudflare to v4.52.1 (#20387)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-29 12:06:52 +01:00
Andreas Petersson
ad6f7f8089 docs: add immich_ml_balancer to community projects (#20399) 2025-07-29 12:02:37 +01:00
renovate[bot]
056b262cba chore(deps): update dependency @types/node to ^22.16.5 (#20385)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-29 11:48:26 +02:00
renovate[bot]
cfae134ecf fix(deps): update typescript-projects (#20388)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-07-29 09:47:30 +00:00
Jason Rasmussen
fbbb6af27a chore: update open-api (#20376) 2025-07-28 19:56:22 -05:00
Brandon Wees
1804a8fe58 fix: openapi spec (#20378) 2025-07-28 23:46:34 +00:00
Alwin Lohrie
ae1d60e259 feat: find large files utility (#18040)
feat: large asset utility

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2025-07-28 18:48:39 -04:00
Jason Rasmussen
7d759edfcc chore: add permission metadata to open-api document (#20373) 2025-07-28 18:40:34 -04:00
shenlong
34974b036c fix: handle back gesture in multi selection mode (#20356)
* fix: handle back gesture in multi selection mode

# Conflicts:
#	mobile/lib/presentation/widgets/timeline/timeline.widget.dart

* remove null-aware element because Isar

* chore: set sqlite busy_timeout to 500ms (#20358)

fix: add busy_timeout pragma

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-28 19:22:50 +00:00
shenlong
e52b9d15b5 chore: bump dart sdk to 3.8 (#20355)
* chore: bump dart sdk to 3.8

* chore: make build

* make pigeon

* chore: format files

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-28 14:04:03 -05:00
Jed-Giblin
9b3718120b feat: shared links custom URL (#19999)
* feat: custom url for shared links

* feat: use a separate route and query param

---------

Co-authored-by: Jason Rasmussen <jason@rasm.me>
2025-07-28 14:16:55 -04:00
Jason Rasmussen
16b14b390f fix: file samples (#20364) 2025-07-28 13:30:49 -04:00
Jason Rasmussen
7e7b8da128 fix: debug source maps (#20363) 2025-07-28 12:41:22 -04:00
Dag Stuan
66ea75072d feat(web): auto fit bounds for map modal (#20345) 2025-07-28 17:36:37 +01:00
Sergey Katsubo
d34670bae6 feat(server): include reason in null reverse geocoding logs (#20347)
* Clarify in log why reverse geocoding may return nothing

* Decrease log level for empty reverse geocoding response from warn to log

* Use a named constant for 25km

* Mention fallback to countries in the message

* Improve natural earth log message

* Decrease log level for empty reverse geocoding response from natural earth countries
2025-07-28 08:51:00 -05:00
shenlong
1e1c2ea627 fix: backup indicator in beta app bar (#20354)
fix: beta - app bar backup indicator

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-28 08:50:50 -05:00
Sergey Katsubo
c7fcb23a23 chore(docs): add links to custom scan interval from other sections in external library doc (#20353) 2025-07-28 13:42:59 +01:00
shenlong
708e42d8a3 fix: change translation key for archive action button (#20336)
* chore: change translation key for archive action button

* chore: await navigation before emitting event

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-27 17:43:23 +00:00
Alex
d15f67da5d feat: scroll to top & view in timeline (#20274)
* feat: scroll to top & view in timeline

* use EventStream

* refactor: event invocation and listerner

* fix: correct parent routing
2025-07-27 21:48:32 +05:30
Matthew Momjian
6becf409da feat(docs): reorganize DB queries, add tags (#20303)
* reorganize

* fix checksum
2025-07-27 10:03:58 -05:00
xCJPECKOVERx
ee4ae40d61 fix(web): Album picker recent albums don't match sidebar (#20313)
- update album picker recent albums to show most recent 'updatedAt' instead of 'createdAt'. Matches sidebar.
2025-07-27 10:03:39 -05:00
Matthew Momjian
ebd644eedd fix(docs): update SQL queries with schema changes (#20297)
* sql queries with table changes

* fix linting
2025-07-26 17:38:12 -05:00
shenlong
7c36cbaf0f fix: error on navigating back from backup selection page (#20299)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-26 13:58:27 -05:00
Alex
3a5d82f790 chore: delete action button (#20261) 2025-07-26 13:51:18 -05:00
Alex
b14c768208 fix: share to app upload (#20271) 2025-07-26 11:42:24 -05:00
Alex
07cb2fb04e fix: remainder backup count (#20270) 2025-07-26 09:02:26 -05:00
Alexandre Garnier
9bbad45990 fix(mobile): remove unused translation and pluralize existing one for map photos count (#20282) 2025-07-26 09:00:35 -05:00
shenlong
e85655d34c fix: no hero animation after tab change (#20285)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-26 08:59:26 -05:00
shenlong
d0576697c3 chore: upgrade flutter to 3.32.8 (#20287)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-26 08:58:48 -05:00
Yaros
f9847bee51 fix(mobile): places search not working in beta version (#20284)
fix(mobile): places search not working
2025-07-26 17:00:57 +05:30
beposec
f2141de5bb fix(mobile): Fix a typo in SyncStreamService Logging (#20283)
Fix typo in logging
2025-07-26 11:29:42 +00:00
Alexandre Garnier
cb344cb014 fix(mobile): distinguish backup settings title from 'backup_controller_page_backup' translation entry (#20237)
Different translation in some languages like in French ('Sauvegarde' for title, otherwise 'Sauvegardé')
2025-07-25 18:07:59 -05:00
Jason Rasmussen
c6b25ef111 feat: automatically detect media location changes (#20256) 2025-07-25 15:25:36 -04:00
Jason Rasmussen
0fdeac0417 feat!: more permissions (#20250)
feat: more api key permissions
2025-07-25 15:25:23 -04:00
Jason Rasmussen
153bb70f6e feat(web): api key permission search (#20248) 2025-07-25 13:39:48 -04:00
Brandon Wees
da80b69062 fix(mobile): beta search page improvements (#20247)
search page improvements
2025-07-25 12:24:19 -05:00
Brandon Wees
f9292c9c96 fix(mobile): deep links when using the beta timeline (#20111)
* fix: deep links when using the beta timeline

* Update remote_asset.repository.dart

* Update mobile/lib/domain/services/asset.service.dart

Co-authored-by: Alex <alex.tran1502@gmail.com>

* return optional from album get

* do not include trashed assets in album asset count

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>

* formatting

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
2025-07-25 17:02:49 +00:00
Zack Pollard
2e0ee6ec05 feat: don't wait for network on app startup (#20232) 2025-07-25 11:19:50 -05:00
Zack Pollard
7f2e4f85f8 fix: lookup the primary key constraint name before dropping it (#20221) 2025-07-25 16:51:22 +01:00
Brandon Wees
c63f805cb4 fix: word wrapping on action buttons (#20231) 2025-07-25 15:10:01 +00:00
Alex
03a13828e1 chore: refactor upload service (#20130)
* chore: refactor upload service

* fix: cancel upload queue on logout (#20131)

* fix: cancel upload on logout

* fix: test

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>

---------

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-25 10:09:32 -05:00
Jeremy Fleischman
e5ee1c8db6 chore: add missing 'make pigeon' instruction (#20202)
* chore: fix typo 'make_build' -> 'make build'

* chore: add missing 'make pigeon' instruction

Turns out I was getting bit by forgetting to run `make pigeon`, which
also generates files. Perhaps it would be better to make it part of
`make build`?

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-25 15:05:40 +00:00
Daimolean
25e2d37490 fix(server): use UserMetadataKey enum instead of string (#20209)
* fix(server): use UserMetadataKey enum instead of string

* fix: mobile
2025-07-25 11:04:28 -04:00
Alex
ed5759fe07 fix: character width calculation (#20201) 2025-07-25 09:56:25 -05:00
Daniel Dietzler
edefed56ae fix: optional number inputs (#20218) 2025-07-25 09:06:12 -04:00
shenlong
13281f8531 docs: more make commands and add mobile checks to pr-checklist (#20211)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-25 13:24:08 +01:00
Zack Pollard
b48406bd20 fix: android backup album migration losing selection (#20220) 2025-07-25 12:57:31 +01:00
Brandon Wees
06c78dfa91 feat: add to album on new beta timeline (#20119)
* feat: add to album on new beta timeline

* handle add album button

* tune

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-25 01:10:33 -05:00
Jeremy Fleischman
de67d22bc0 fix: add missing awaits when changing client certificate (#20189)
I ran into this while testing out
<https://github.com/immich-app/immich/pull/19830>. When I add, change,
or remove a client certificate under Immich's advanced settings, the
change wouldn't take effect until some mysterious point in the future.
For example:

1. Add a client certificate. It doesn't get used.
2. Remove certificate. *Now* the client certificate from step 1) is used.
3. Restart application. Now no client certificate is used.

This all boils down to some missing `await`s. The user would change the
cert, and we'd start asynchronously saving it to the store, and while
the save is still happening, [`HttpSSLOptions` pulls the "old" value out of
`SSLClientCertStoreVal`](https://github.com/immich-app/immich/blob/v1.136.0/mobile/lib/utils/http_ssl_options.dart#L30).

With the appropriate `await`s, this behaves much more sanely.
2025-07-25 00:28:33 -05:00
shenlong
b4780e89af fix: add beta toggle in landscape mode (#20187)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-25 00:28:21 -05:00
shenlong
ad65e9011a chore: bump line length to 120 (#20191) 2025-07-25 02:37:22 +00:00
Zack Pollard
977c9b96ba fix: geodata_places pkey migration failing for certain upgrade paths (#20177) 2025-07-24 22:50:36 +01:00
John Stef
aa2828ab33 fix(mobile): hide video thumbnail when video is ready (#19328) 2025-07-24 22:38:08 +01:00
Daimolean
a36840d7cc fix(web): multi-select in ascending asset order (#19461) 2025-07-24 22:37:44 +01:00
Pablo Lluch
e34f46fa0d fix: send correct includeArchived parameter to API when showing markers in map (#20117)
Co-authored-by: Pablo Lluch <pablo.lluch@gmail.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-07-24 22:34:06 +02:00
Alex
6170a3843c chore: remove build flavor Android (#20161) 2025-07-24 14:55:49 -05:00
shenlong
563e2ab503 fix: update trash action i18n keys (#20164)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-24 14:55:35 -05:00
shenlong
79157e1043 fix: fallback auto grouping to day grouping (#20156)
fallback auto grouping to day grouping

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-24 19:28:40 +00:00
shenlong
02688a2a03 fix: override SSL options inside isolates (#20142)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-24 14:26:00 -05:00
Brandon Wees
3b9bfceef0 fix: album deleted toast message (#20121)
* fix: album deleted toast message

* Update mobile/lib/presentation/pages/drift_remote_album.page.dart

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>

* Fix lint

---------

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
2025-07-24 14:09:17 -05:00
github-actions
089085fcdb chore: version v1.136.0 2025-07-24 14:24:38 +00:00
Jason Rasmussen
fc68cf4f32 chore: remove migration (#20129) 2025-07-24 14:11:53 +00:00
Alex
0051a9bba5 fix(web): Revert prevent flashing white background in dark mode on page load/reload (#19934) (#20122)
Revert "fix(web): prevent flashing white background in dark mode on page load/reload (#19934)"

This reverts commit 32f23b8d38.
2025-07-24 09:45:38 +02:00
Daniel Dietzler
f27bdf7523 chore: migrate to UI modal manager (#20116) 2025-07-23 17:27:09 -04:00
Daniel Dietzler
c1c9f30ea4 chore: migrate to immich/ui confirm modal (#20114) 2025-07-23 22:56:56 +02:00
Jason Rasmussen
bc8cb9b671 fix: default route permission (#20113) 2025-07-23 16:56:38 -04:00
Jason Rasmussen
a675922172 fix: unset prewarn param (#20109) 2025-07-23 16:52:59 -04:00
Jason Rasmussen
2bead445bd docs: remove outdated note (#20110) 2025-07-23 16:00:19 -04:00
Daniel Dietzler
0e1c8c2b80 fix: ML recognition distance UI form validation (#20107) 2025-07-23 19:12:06 +02:00
Alex
0174de19dd feat: export database option (#20098) 2025-07-23 14:40:16 +00:00
Alex
1a35a01149 feat: drift manual upload (#20101) 2025-07-23 09:20:52 -05:00
shenlong
08122d6871 fix: show only local assets from albums selected for backup (#20050)
* show only local assets from albums selected for backup

# Conflicts:
#	mobile/lib/infrastructure/repositories/db.repository.drift.dart

* ignore backup selection

* fix: backup album ownerId

* fix: backup album ownerId

* only show local only assets that are selected for backup

* add index on visibility and backup selection

* fix: video not playing in search view

* remove safe area from bottom bar

* refactor stack count with a CTE and local asset with a SELECT

* fix lint

* remove redundant COALESCE

* remove stack count from main timeline query

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-23 09:13:15 -05:00
Jason Rasmussen
92384c28de feat: sync auth user (#20067) 2025-07-23 09:59:33 -04:00
Jason Rasmussen
ab597155fa fix: immich-dev live reload (#20104) 2025-07-23 09:59:21 -04:00
Weblate (bot)
1d9cc4ca5f chore(web): update translations (#20082)
Co-authored-by: Alberto Serluca <alberto.ser11@gmail.com>
Co-authored-by: DevServs <bonov@mail.ru>
Co-authored-by: Florian Ostertag <florian.kuepper@gmail.com>
Co-authored-by: Gilbert <thengilbert@gmail.com>
Co-authored-by: Indrek Haav <indrek.haav@hotmail.com>
Co-authored-by: Jozef Gaal <preklady@mayday.sk>
Co-authored-by: KecskeTech <teonyitas@gmail.com>
Co-authored-by: Kuno Claes <kuno@icodes.dev>
Co-authored-by: MSDNicrosoft <wang3311835119@hotmail.com>
Co-authored-by: Matjaž T <matjaz@moj-svet.si>
Co-authored-by: Mārtiņš Bruņenieks <martinsb@gmail.com>
Co-authored-by: Vegard Fladby <vegard@fladby.org>
Co-authored-by: adri1m64 <adrien.melle@laposte.net>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
2025-07-23 14:38:29 +01:00
shenlong
05d26dc683 fix: remove safe area from bottom bar (#20102)
* remove safe area from bottom bar

* fix: video not playing in search view

* stop foreground / background back on migration

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-23 08:23:49 -05:00
renovate[bot]
c91382625c fix(deps): update typescript-projects (#20103)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-07-23 13:26:28 +01:00
Alex
c7853fbe9d chore: refactor download group (#20099) 2025-07-23 04:21:58 +00:00
xCJPECKOVERx
1a70896113 feat(web): Remove from Stack (#19703)
* - add component
- update server's StackCreateDto for merge parameter
- Update stackRepo to only merge stacks when merge=true (default)
- update web action handlers to show stack changes

* - make open-api

* lint & format

* - Add proper icon to 'remove from stack'
- change web unstack icon to image-off-outline

* - cleanup

* - format & lint

* - make open-api: StackCreateDto merge optional

* initial addition of new endpoint

* remove stack endpoint

* - fix up remove stack endpoint
- open-api

* - Undo stackCreate merge parameter

* - open-api typescript

* open-api dart

* Tests:
- add tests
- update assetStub.imageFrom2015 to have required stack attributes to include it with tests

* update event name

* Fix event name in test

* remove asset_update check

* - merge stack.removeAsset params into one object
- refactor asset existence check (no need for asset fetch)
- fix tests

* Don't return updated stack

* Create specialized stack id & primary asset fetch for asset removal checks

* Correct new permission names

* make sql

* - fix open-api

* - cleanup
2025-07-22 22:17:06 -04:00
Alex
1011cdb376 chore: handle requeue upload when target albums changed (#20089)
* chore: handle requeue upload when target albums changed

* chore: remove debug
2025-07-22 17:11:06 -05:00
Sebastian Di Luzio
f1cac122ed fix: more inclusive language (#20092) 2025-07-22 21:29:36 +00:00
Brandon Wees
3c7f0a2900 chore(mobile): use hides instead of changing the namespace (#20090) 2025-07-22 16:02:52 -05:00
Brandon Wees
277e39ac98 fix(mobile): sync icon rotation direction (#20088)
spin the sync icon the right direction
2025-07-23 01:31:18 +05:30
renovate[bot]
b3061f1e4f fix(deps): update typescript-projects (#20086)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-07-22 19:18:29 +01:00
renovate[bot]
250548dea6 fix(deps): update typescript-projects (#19939)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-07-22 17:42:07 +00:00
Daimolean
ac44f6d1e0 feat(mobile): asset face sync (#20022)
* feat(mobile): asset face sync

* fix: lint

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-22 17:17:52 +00:00
shenlong
ab61bcfcc8 fix: reduce asset_viewer reloads (#20083)
* fix: reduce asset_viewer reloads

* limit the result of watch asset to one

* fix null reference in map thumbnail

* bump hash file limit to 256

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-22 11:58:34 -05:00
Alex
aa344a3989 feat: delete actions (#20034)
* chore: show delete local

* pr feedback

* restore and perm delete action
2025-07-22 16:36:00 +00:00
Brandon Wees
2efca67217 feat(mobile): beta sync stats page (#19950)
* show beta sync stats

* show status next to jobs

* use drift devtools reset database impl

* dcm fixes

* fix: hash count

* styling

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-22 16:24:32 +00:00
Alex
97daf42fd5 chore: don't show beta switcher if connect to server below 1.136 (#20084) 2025-07-22 10:24:00 -05:00
renovate[bot]
5548033cae chore(deps): update dependency @types/multer to v2 (#20069)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 11:00:28 +01:00
renovate[bot]
637eba6e08 chore(deps): update node.js to v22.17.1 (#20066)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 09:59:16 +00:00
renovate[bot]
f16457d2f9 chore(deps): update redis:6.2-alpine docker digest to 7fe72c4 (#20065)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 10:57:58 +01:00
Weblate (bot)
7b41c6348c chore(web): update translations (#20076)
Co-authored-by: Zack Pollard <zack@futo.org>
2025-07-22 09:49:18 +00:00
renovate[bot]
bd92f6b12d chore(deps): update dependency dotenv to v17 (#20073)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 09:31:01 +00:00
Daimolean
496b0c7076 fix(server): missing integer type (#20075) 2025-07-22 09:29:14 +00:00
renovate[bot]
166452640d chore(deps): update dependency @types/node to ^22.16.4 (#20068)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-22 10:28:15 +01:00
Weblate (bot)
30f6dc3a6e chore(web): update translations (#19228)
Co-authored-by: 1024mb <1024mb@users.noreply.hosted.weblate.org>
Co-authored-by: Abel Márquez Mora <abeelmarquez@gmail.com>
Co-authored-by: Adupa Vasista <adupavasista@gmail.com>
Co-authored-by: AgentTricky <andreweditz26@gmail.com>
Co-authored-by: Ahmed Khaleel Shihab <ahmed91shihab@gmail.com>
Co-authored-by: Ahmed Shihab <blugrana2@gmail.com>
Co-authored-by: Alberto Serluca <alberto.ser11@gmail.com>
Co-authored-by: Alex <weblate.attire524@passmail.net>
Co-authored-by: Andreas Johansen <andreas@josern.com>
Co-authored-by: Antonio Vazquez <antoniovavazquez@gmail.com>
Co-authored-by: Apurbo Islam <apurboislam2809@gmail.com>
Co-authored-by: Bahadır Hamza Öztürk <bahadirhamza2@gmail.com>
Co-authored-by: Barend van der Walt <barendjohannes.vdwalt@gmail.com>
Co-authored-by: Bernardo <bernaamg@gmail.com>
Co-authored-by: Bezruchenko Simon <worcposj44@gmail.com>
Co-authored-by: Bora Atıcı <boratici.acc@gmail.com>
Co-authored-by: Carina Chenot <carina.chenot@gmail.com>
Co-authored-by: Christian Glockner <christian@glcknr.eu>
Co-authored-by: Claudiu Hanza <claudiu.hanza@gmail.com>
Co-authored-by: Cristality_ <jovarasz@gmail.com>
Co-authored-by: DarkWolf DarkINFINITE <ddarkinfinite@gmail.com>
Co-authored-by: Davide Ciaccia <davideccia@gmail.com>
Co-authored-by: Denis Pacquier <denis.pacquier@gmail.com>
Co-authored-by: DevServs <bonov@mail.ru>
Co-authored-by: Etienne de Villiers <etiennefdevilliers@proton.me>
Co-authored-by: Filip Polak <rabbitxones@gmail.com>
Co-authored-by: Fjuro <fjuro@alius.cz>
Co-authored-by: Fjuro <git@alius.cz>
Co-authored-by: Florian Ostertag <florian.kuepper@gmail.com>
Co-authored-by: G M <gauravmmh2@gmail.com>
Co-authored-by: Gerry <ger_26_6@hotmail.com>
Co-authored-by: Girom Kenji Respicio Pacho <pachogiromkenji@gmail.com>
Co-authored-by: Gyubin Lee <support@pcor.me>
Co-authored-by: Hazret <tncytrk@live.com>
Co-authored-by: Hoi <Hoihoi@users.noreply.hosted.weblate.org>
Co-authored-by: Hurricane-32 <rodrigorimo@hotmail.com>
Co-authored-by: Indrek Haav <indrek.haav@hotmail.com>
Co-authored-by: Ivan Dimitrov <idimitrov08@gmail.com>
Co-authored-by: JPar99 <github.wad969@passmail.com>
Co-authored-by: Janat Taerakul <janat.taerakul@gmail.com>
Co-authored-by: Janat Taerakul <ppppp5541@gmail.com>
Co-authored-by: Jozef Gaal <preklady@mayday.sk>
Co-authored-by: JustRensio <debouwer741@gmail.com>
Co-authored-by: Lenny Angst <lenny@familie-angst.ch>
Co-authored-by: Leo Bottaro <github@leobottaro.com>
Co-authored-by: Lucas Correia <github.freehand702@passmail.net>
Co-authored-by: Luis Peregrina <luis.a.peregrina@gmail.com>
Co-authored-by: MSDNicrosoft <wang3311835119@hotmail.com>
Co-authored-by: MaBeniu <marius.beniusis@teliacompany.com>
Co-authored-by: Marc Portabella Navarro <portabella.marc@gmail.com>
Co-authored-by: Martin <me@mart-e.be>
Co-authored-by: Mateo Varela <matevarela32@gmail.com>
Co-authored-by: Matjaž T <matjaz@moj-svet.si>
Co-authored-by: Matteo Marchi <marchimatteo@gmail.com>
Co-authored-by: Mehedi Hasan <asmaparvin019@gmail.com>
Co-authored-by: Mohammed Al Otaibi <mopes.03.belle@icloud.com>
Co-authored-by: Molnar Eduard <edimolnar@posteo.ro>
Co-authored-by: Máté Molnár <matmolni@gmail.com>
Co-authored-by: Mārtiņš Bruņenieks <martinsb@gmail.com>
Co-authored-by: Niko Savola <niko.savola@aalto.fi>
Co-authored-by: OffsetMonkey538 <offsetmonkey538@gmail.com>
Co-authored-by: P <eisregner@gmail.com>
Co-authored-by: Pavel Miniutka <pavel.miniutka@gmail.com>
Co-authored-by: Petri Hämäläinen <petri.hamalainen@mailbox.org>
Co-authored-by: Revc Nix <revc.nix@gmail.com>
Co-authored-by: Robert <robert.bezem@gmail.com>
Co-authored-by: Runskrift <anders@rimfrost.nu>
Co-authored-by: SGT <gabriel.sgt@gmail.com>
Co-authored-by: Sachin Kekarjawalekar <kekarjawalekarsachin1@gmail.com>
Co-authored-by: Sai varun <saivarunkollurufb@gmail.com>
Co-authored-by: Santiago <santiwever@hotmail.com>
Co-authored-by: Sergey Katsubo <skatsubo@gmail.com>
Co-authored-by: Sergi Font <sfont@tuta.io>
Co-authored-by: Shawn <xiaxinx@gmail.com>
Co-authored-by: Sylvain Pichon <service@spichon.fr>
Co-authored-by: Taiki M <vexingly-many-mace@duck.com>
Co-authored-by: Theodor Onarheim <thbo@startmail.com>
Co-authored-by: Tijs-B <tijs.bergmans@telenet.be>
Co-authored-by: Tomas Veselis <tomkex@gmail.com>
Co-authored-by: Tony Ronaldo Matute <tonyronaldomatute@gmail.com>
Co-authored-by: Topaz Barziv <mail@topazbarziv.com>
Co-authored-by: User 123456789 <user123456789@users.noreply.hosted.weblate.org>
Co-authored-by: Valter Vicente <vallovic@gmail.com>
Co-authored-by: Vegard Fladby <vegard@fladby.org>
Co-authored-by: Xo <xocodokie@users.noreply.hosted.weblate.org>
Co-authored-by: Yago Raña Gayoso <yago.rana.gayoso@gmail.com>
Co-authored-by: adri1m64 <adrien.melle@laposte.net>
Co-authored-by: adriadam10 <adriadam10@gmail.com>
Co-authored-by: amirulashraf3861 <amirulashrafidros@gmail.com>
Co-authored-by: anton garcias <isaga.percompartir@gmail.com>
Co-authored-by: ardtas <ardtas@users.noreply.hosted.weblate.org>
Co-authored-by: bacardicoke <bacardicoke@gmail.com>
Co-authored-by: catelixor <catelixor+weblate@proton.me>
Co-authored-by: dark&white <darkwhite@users.noreply.hosted.weblate.org>
Co-authored-by: eSascha <kitaigorod49@yahoo.com>
Co-authored-by: eav5jhl0 <eav5jhl0@users.noreply.hosted.weblate.org>
Co-authored-by: evensure <j.evenschor@gmail.com>
Co-authored-by: jicetus <jicetus@users.noreply.hosted.weblate.org>
Co-authored-by: juanCoder64 <jgama12569@gmail.com>
Co-authored-by: lumppu <saukkolanerkki@gmail.com>
Co-authored-by: mastoduy <mastoduy@gmail.com>
Co-authored-by: miiyuh <itsazripp2@gmail.com>
Co-authored-by: no <weblate@rosenheim.dk>
Co-authored-by: sarga <devilcyber33@gmail.com>
Co-authored-by: slick-daddy <gokalpselamet@gmail.com>
Co-authored-by: st7105 <st7105@gmail.com>
Co-authored-by: waclaw66 <waclaw66@seznam.cz>
Co-authored-by: wickdj <wickdj@gmail.com>
Co-authored-by: Вячеслав Лукьяненко <madeinchuguev@gmail.com>
Co-authored-by: Оргил Пүрэвдорж <orgyldinio@proton.me>
2025-07-22 10:27:32 +01:00
Alex
02c423b326 chore: graceful(not) disposal(be gong) Isar (#20062) 2025-07-21 22:44:39 -05:00
Zack Pollard
df318ac641 feat: asset face sync (#20048)
* chore: remove thumbnailPath from person sync dto

* feat: asset face sync
2025-07-21 21:31:45 -04:00
bo0tzz
826eaedae6 feat: play live photos on hover (#19962) 2025-07-21 16:59:42 -05:00
Alex
737e768212 feat: drift partners (#20051)
* feat: drift toggle partner in timeline

* partners operation

* fix: lint
2025-07-21 16:58:53 -05:00
Brandon Wees
99e5b33969 feat: add favorites support to android widget (#20061) 2025-07-21 16:51:16 -05:00
shenlong
7ea8783593 chore: do not render drift migration auto gen files (#20060)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-21 16:48:22 -05:00
Alex
4d27f187ea feat: new upload (cont) (#20029)
* new upload button

* wip

* pr feedback

* fix: updateAll override album selection value

* feat: status box

* feat: handle upload resume

* re-enable websocket event

* fix: update state condition and upload status

* Better backup detail page

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-21 15:30:51 -05:00
shenlong
1dc62fce5f fix: remove foreign constraint on stack.primaryAssetId (#20052)
* fix: remove foreign constraint in stack.primaryAssetId

* fix migration

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-21 15:20:41 -05:00
shenlong
5fc4393e7a feat: migrate backup albums to sqlite (#20049)
* do not migrate again on app start

* migrate backup albums over to sqlite

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-21 12:56:49 -05:00
Alex
dee6d072fb fix: memory jarring hero animation (#20030)
* fix: memory jarring hero animation

* remove other hero
2025-07-20 13:56:53 -05:00
Mert
261818ddd9 refactor(mobile): download button in new timeline (#20010)
* download button

* minor improvements
2025-07-19 12:34:17 +03:00
Alex
fafb88d31c feat(mobile): new upload (#18726) 2025-07-19 04:58:53 +00:00
Min Idzelis
f929dc0816 fix: devcontainer layout (#20021) 2025-07-18 19:07:49 -04:00
Min Idzelis
9e94f52b05 chore: dockerfile layout changes (#19673)
Dockerfile layout changes

Fix up web path

feat: update server env vars for layout
2025-07-18 17:56:26 -04:00
Alex
5d244c6fec chore: finish drift locked page (#20013)
* feat: overlay mechanism

* handle merged asset local id extraction

* locked view asset viewer actions

* pr feedback
2025-07-18 18:16:22 +00:00
megumin
dcfe8d5ade fix: send filename when viewing the original file (#20005)
* feat: add fileName to downloadOriginal response

* test: add fileName to ImmichFileResponse for downloadOriginal

* lint: use single quotes for fileName string in test
2025-07-18 11:55:24 -05:00
shenlong
635f5de186 chore: change dcm constraint to include 1.30.0 (#20017)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-18 11:54:35 -05:00
Brandon Wees
9719965caf fix: invalid android manifest (#20015)
fix extra > in android manifest
2025-07-18 11:54:15 -05:00
Min Idzelis
f33e1ad94c feat: relocate scripts, PATH update (#20002)
Relocate scripts, and PATH updates
2025-07-18 11:19:06 -04:00
Min Idzelis
576f681b5c feat: remove dep on cwd for workers (#20012) 2025-07-18 10:57:49 -04:00
Jason Rasmussen
493d85b021 feat!: absolute file paths (#19995)
feat: absolute file paths
2025-07-18 10:57:29 -04:00
Brandon Wees
f32d4f15b6 feat(mobile): android widgets (#19310)
* wip

* wip widgets

* more wip changes

* latest changes

* working random widget

* cleanup

* add configurable widget

* add memory widget and cleanup of codebase

* album name handling

* add deeplinks

* finish minor refactoring and add some polish :)

* fix single shot type on random widget

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>

* switch to ExposedDropdownMenuBox for random configure activity

* handle empty album and no connection edge cases

* android project cleanup

* fix proguard and gson issues

* fix deletion handling

* fix proguard stripping for widget model classes/enums

* change random configuration activity close to a checkmark on right side

---------

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
2025-07-18 09:37:07 -05:00
Daimolean
7bae49ebd5 feat(mobile): people sync (#19777)
* feat(mobile): drift people sync

* merge main

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-18 14:21:39 +00:00
Alex
2e63b9d951 chore: add sync indicator and better album state management (#20004)
* album list rerendering

* sync indicator

* sync indicator

* fix: lint
2025-07-18 13:39:28 +00:00
Alex
137f0d48c0 chore: styling for asset_viewer bottom sheet (#20006)
bottom sheet styling
2025-07-18 08:36:29 -05:00
renovate[bot]
53acf08263 fix(deps): update dependency multer to v2.0.2 [security] (#20003)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-18 12:08:57 +02:00
shenlong
f32cd74232 feat: show stacks in asset viewer (#19935)
* feat: show stacks in asset viewer

* fix: global key issue and flash on stack asset change

* feat(mobile): stack and unstack action (#19941)

* feat(mobile): stack and unstack action

* add custom model

* use stackId from ActionSource

* Update mobile/lib/providers/infrastructure/action.provider.dart

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>

---------

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>

* fix: lint

* fix: bad merge

* fix: test

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
Co-authored-by: Daimolean <92239625+wuzihao051119@users.noreply.github.com>
Co-authored-by: wuzihao051119 <wuzihao051119@outlook.com>
2025-07-18 04:31:04 +00:00
Alex
546f841b2c chore: migration continue button (#20000)
* feat: add toggle to switch between Isar and Sqlite

* reset sqlite on beta

* start sync on app open in new timeline

* fix lint

* migrate hashes when new timeline is selected

* migrate hashes immediately after beta is enabled

* show loading indicator in change timeline page

* some stylings

* fix some styling issue

* release resources on isolate close

* replace route and styling

* handle migration back to old timeline

* check if a provider is mounted before calling dispose on it

* styling

* styling and button

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-17 15:58:55 -05:00
Daimolean
8491fe459d feat(mobile): drift search page (#19811)
* feat(mobile): drift search page

* migrate to drift page

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-17 15:25:25 -05:00
shenlong
2046dcc5b4 fix: mobile storage status check (#19986)
* fix: _shouldUseLocalAsset check

* show storage indicators in local album view

* update local thumb provider to work with remote asset

* update checks

* do not show upload button when selection is only merged assets

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-17 17:13:21 +00:00
Brandon Wees
03ff425664 chore(mobile): update casting to new asset viewer (#19994)
* update casting to new asset viewer

* handle websocket

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-17 17:08:32 +00:00
Mert
055b930066 refactor(mobile): share action button in new timeline (#19967)
* share asset button

* include source

* move to repository

* formatting
2025-07-17 11:41:30 -05:00
shenlong
531515daf9 feat: add toggle to switch between Isar and Sqlite (#19953) 2025-07-17 11:12:29 -05:00
Min Idzelis
b256c51b6b docs: update devcontainer docs (#19237) 2025-07-17 14:49:55 +00:00
Lucas Correia
238dc7c085 chore: adjust setting subtitle to less clumsy expression (#19970) 2025-07-17 15:40:49 +02:00
bo0tzz
184c7390a1 chore: also redirect docs/ with trailing slash (#19965)
Cause I keep running into that lol
2025-07-16 21:14:58 -05:00
Mert
649221176c refactor(mobile): delete local button in new timeline (#19961)
* delete local action button

* include source

* move prompt

* batch
2025-07-16 16:25:41 -05:00
renovate[bot]
eae2471ab5 chore(deps): update base-image to v202507162011 (major) (#19983)
chore(deps): update base-image to v202507162011

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-16 16:22:33 -05:00
shenlong
bfceed15da feat: add license page to app bar dialog (#19971)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-16 09:36:17 -05:00
bo0tzz
d9891f759e chore: use upstream setup-dcm action (#19963) 2025-07-16 09:35:36 -05:00
evan314159
32f23b8d38 fix(web): prevent flashing white background in dark mode on page load/reload (#19934)
* prevent flashing white background in dark mode on page load/reload, tested with Safari and Chrome on macOS

* integrate into existing FOUC-prevention

---------

Co-authored-by: Evan <evan@MacBook-Pro.local>
2025-07-16 14:34:45 +00:00
Brandon Wees
743b6644e9 feat(widgets): iOS widget improvements (#19893)
* improvements to error handling, ability to select "Favorites" as a virtual album, fix widgets not showing image when tinting homescreen

* dont include isFavorite all the time

* remove check for if the album exists

this will never run because we default to Album.NONE and its impossible to distinguish between no album selected and album DNE (we dont know what the store ID is, only what iOS gives)
2025-07-15 21:17:24 -05:00
Alex
34620e1e9a feat: album edit (#19936) 2025-07-15 20:37:44 -05:00
Jason Rasmussen
bcb968e3d1 refactor: job names (#19949) 2025-07-15 18:39:00 -04:00
Jason Rasmussen
e73abe0762 refactor: enum casing (#19946) 2025-07-15 14:50:13 -04:00
Jason Rasmussen
920d7de349 refactor: event names (#19945) 2025-07-15 13:41:19 -04:00
Jason Rasmussen
351701c4d6 refactor: validate enum (#19943) 2025-07-15 17:14:57 +00:00
Min Idzelis
68f249bc03 feat: improve geodata import speed (#19906)
chore(deps): update dependency vite to v7 (#19657)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-07-15 16:23:41 +00:00
renovate[bot]
eca54871d0 chore(deps): update docker.io/valkey/valkey:8-bookworm docker digest to facc1d2 (#19932)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-15 15:43:36 +00:00
renovate[bot]
b359eea124 chore(deps): update prom/prometheus docker digest to 63805eb (#19933)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-15 16:43:14 +01:00
renovate[bot]
c18f167e29 chore(deps): update immich-app/devtools action to v0.1.1 (#19938)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-15 16:42:49 +01:00
Daimolean
ba262fbaa8 feat(mobile): drift place page (#19914)
* feat(mobile): drift place page

* merge main

* feat(mobile): drift place detail page (#19915)

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-15 15:10:12 +00:00
Alex
59e7754bdc feat: websocket background sync (#19888)
* feat: websocket background sync

* batch websocket

* pr feedback
2025-07-15 09:38:28 -05:00
Daimolean
0acbf1199a feat(mobile): drift user metadata sync (#19894)
* feat(mobile): drift user metadata sync

* change text to jsonb

* update primary key

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-15 09:17:35 -05:00
Hamish
daea57f7d2 feat(web): better coordinate parsing (#19832)
feat: better coordinate parsing
2025-07-15 08:32:43 -05:00
renovate[bot]
82c3165247 fix(deps): update typescript-projects (#19808)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-07-14 22:30:39 +00:00
bo0tzz
3a854d77ac fix: use IMMICH_HOST env var in ML healthcheck (#19844)
Fixes #19843
2025-07-14 18:08:29 -04:00
Lukas
ccd0c35ca1 fix(web): adjust button size in person side panel (#19924)
* fix(web): adjust button size in person side panel

* round edit button
2025-07-14 18:05:34 -04:00
Lukas
5f10a4cae7 fix(web): allow renaming person without merging (#19923)
* fix(web): allow renaming person without merging

* improve return type
2025-07-14 14:24:32 -05:00
shenlong
9abb95d34a feat: handle live photos on new asset viewer (#19926)
sync and handle livePhotoVideoId in asset viewer

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-14 14:23:24 -05:00
Jason Rasmussen
805ec3e351 chore: asset sync FKs (#19927) 2025-07-14 10:57:25 -05:00
Sergey Katsubo
a97ba4862f fix(docs): Nightly Tasks Settings (#19907)
* Document new Nightly Tasks Settings

* Add a link to the settings

* List jobs that are configured in their own System Settings sections
2025-07-14 10:24:34 -04:00
Jason Rasmussen
c699df002a feat: rename schema (#19891) 2025-07-14 10:13:06 -04:00
shenlong
33c29e4305 chore: pass flavor to vscode flutter codelens (#19919) 2025-07-14 07:32:29 -05:00
Dominik Vogel
b0098d6d23 Update external-library.md (#19901) 2025-07-12 19:50:51 +00:00
renovate[bot]
04aab6ecce chore(deps): update dependency vite to v7 (#19657)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-07-11 23:32:35 +02:00
Jason Rasmussen
47c0dc0d7e feat: nightly tasks (#19879) 2025-07-11 17:32:10 -04:00
Daniel Dietzler
df581cc0d5 feat: UserMetadata sync (#19882)
* feat: UserMetadata sync

* refactor: sync table filters (#19887)
2025-07-11 18:19:53 +00:00
Jason Rasmussen
9e48ae3052 feat: naming strategy (#19848)
* feat: naming strategy

* feat: detect renames
2025-07-11 11:35:10 -04:00
shenlong
1d19d308e2 chore: update flutter to 3.32.6 (#19878)
* chore: update flutter to 3.32.6

* fix lint

* fix asset viewer scroll physics

* test: change init order for map test

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-11 10:34:49 -05:00
Alex
de4217cefc feat: action buttons in more view (#19867)
* feat: action buttons in more view

* pr feedback
2025-07-11 10:34:38 -05:00
Jason Rasmussen
617a2f146d fix: startup log level (#19885) 2025-07-11 11:22:38 -04:00
Alex
2b07d7ac63 feat: remove from album action button (#19884)
* feat: remove from album action

* feat: remove from album action
2025-07-11 10:06:53 -05:00
Jason Rasmussen
1cc5ca14ca feat: allow unordered migrations in dev (#19881) 2025-07-11 10:58:34 -04:00
shenlong
a625921e8f refactor: timeline repo queries (#19871)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-11 14:57:46 +00:00
Zach McGaughey
a17bba3328 fix: allow insecure connections in iOS WidgetExtension (#19863)
Allow insecure connections in WidgetExtension
2025-07-11 08:46:17 -05:00
Jason Rasmussen
4b3a4725c6 feat: pending sync reset flag (#19861) 2025-07-11 09:38:02 -04:00
shenlong
34f0f6c813 chore: rename new migration to execute last (#19872)
chore: rename new migration to change execution order

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-11 08:41:06 -04:00
Min Idzelis
906d14c172 chore: missing @types dependency for geojson (#19870) 2025-07-11 13:42:25 +02:00
Alex
d087f7c870 chore: beta flavor build (#19862)
* chore: beta flavor build

* make file

* beta flavor

* add build flavor to GHA

* add build flavor to GHA
2025-07-10 21:42:29 -05:00
Min Idzelis
de345a9524 chore: makefile split setup tasks (#19739)
Makefile split setup tasks
2025-07-10 21:35:39 -04:00
Min Idzelis
badd7ea2a9 chore: more missing deps (#19868) 2025-07-11 00:56:04 +02:00
shenlong
7d8f56b483 chore: hero animations (#19860)
* remove herocontrollerscope

* handle heroOffset in new timeline

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-10 20:25:18 +00:00
shenlong
70b73145f1 fix: ensure buffer loaded before opening asset viewer (#19864)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-10 20:21:50 +00:00
Brandon Wees
d178c52ba6 fix: cold start deep link logic (#19859) 2025-07-10 14:27:42 -05:00
SGT
55fe67dd20 fix(server): clear activity when asset is removed from album (#19019) 2025-07-10 19:37:56 +02:00
Jason Rasmussen
ed4c7817e7 feat: AssetUploadReadyV1 event (#19858) 2025-07-10 13:30:10 -04:00
Zack Pollard
39c95f1280 refactor: rename geodata pk constraint to match runtime constraint name (#19856) 2025-07-10 17:18:51 +00:00
Daimolean
4ddd3764b4 feat(mobile): hide storage indicator outside main timeline (#19835)
* feat(mobile): hide storage indicator outside main timeline

* fix: lint

* set default as false

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-10 11:59:52 -05:00
Alex
68db17028b feat: new create album page (#19731)
* feat: new create album page

* finished create album flow

* refactor into stateful widgets

* refactor

* focus fix

* lint

* default sort

* pr feedback
2025-07-10 11:59:15 -05:00
immich-tofu[bot]
1f50a0075e chore: modify .github/workflows/org-checks.yml 2025-07-10 15:59:44 +00:00
Zack Pollard
b19884d01e feat(server): people sync (#19854)
* chore: fix missing usage of deleteType for syncMemoriesV1

* chore: add src path for proper absolute imports in jetbrains

* feat: people sync
2025-07-10 11:32:42 -04:00
Alex
feff1899ee feat: expanded sliver app bar (#19827)
* use mutex

* feat: cool app bar

* animation

* adapt to more pages

* animation

* better animation

* fix: asset count

* Revert "fix: asset count"

This reverts commit 673a5b264b.

* fix: asset count

* fix: shaky animation on Android

* tunning

* offset SizedBox to fix scroll jump on multiselect

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-10 10:13:46 -05:00
Sergey Katsubo
977d6452f6 fix(docs): library and folders minor adjustments (#19642) 2025-07-10 14:31:06 +00:00
Léopold Koprivnik
f778adea92 feat: adds option to search only for untagged assets (#19730)
Co-authored-by: SkwalExe <skwal@skwal.net>
2025-07-10 16:28:20 +02:00
Min Idzelis
818bdde317 chore: update base images (#19741)
Update base images
2025-07-09 19:22:01 -04:00
Mert
fd48a33686 refactor(mobile): image thumbnails (#19821)
* image thumbnail refactor

* minor const-ification in new thumbnail tile

* underscore helper classes

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-07-09 14:16:09 -05:00
Brandon Wees
a918481c0b feat(mobile): cache latest ios widget entry for fallback (#19824)
* cache the last image an ios widget fetched and use if a fetch fails in a future timeline build

* code review fixes

* downgrade pbx for flutter

* use cache in snapshots
2025-07-09 13:59:54 -05:00
renovate[bot]
a201665b7e chore(deps): update base-image to v202507091427 (major) (#19840)
chore(deps): update base-image to v202507091427

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-09 12:52:11 -05:00
Brandon Wees
2a222fcfba chore(docs): roadmap updates (#19841) 2025-07-09 16:54:00 +01:00
immich-tofu[bot]
d902e7f87d chore: modify .github/workflows/org-checks.yml 2025-07-09 15:23:30 +00:00
shenlong
6278fe43c0 fix: run reload within a mutex (#19826)
* fix: run reload within a mutex

* change total assets before emitting the reload event

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-07-09 10:15:37 -05:00
shenlong
dfe6d27bbd feat: sqlite video player (#19792)
* feat: video player

* use remote asset id in local query

* fix: error from pre-caching beyond total assets

* fix: flipped local videos

* incorrect aspect ratio on iOS

* ignore other storage id during equals check

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-09 09:34:25 -05:00
Jason Rasmussen
51ab7498e9 feat: create table with constraints (#19828) 2025-07-09 09:13:14 -04:00
Hamish
4db76ddcf0 feat(web): update icons (#19831)
* fix: update password icon in user settings

* feat: add icons to more modals
2025-07-09 02:12:16 +00:00
Brandon Wees
d03eb87058 fix(mobile): deeplinking to asset view while viewer is already open (#19812)
* initial attempt at new guard

* do not resolve the route when replaced

* Update gallery_guard.dart comment

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-08 10:50:59 -05:00
Daimolean
a556de67b0 feat(mobile): drift local albums page (#19817)
* feat(mobile): drift local albums page

* fix: lint

* refactor: use AsyncValue

* fix: lint

* local album thumbnail

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-08 15:37:57 +00:00
Daimolean
e703685d8d feat(mobile): drift partner detail page (#19815)
* feat(mobile): drift partner detail page

* fix: lint
2025-07-08 10:31:07 -05:00
Daimolean
172388c455 feat(mobile): drift recently taken page (#19814)
* feat(mobile): drift recently taken page

* fix: lint

* refactor(mobile): timeline queries (#19818)

refactor: remote assets query to take single user id

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>

---------

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-08 13:54:29 +00:00
Jason Rasmussen
df4a27e8a7 feat: sql-tools overrides (#19796) 2025-07-08 08:17:40 -04:00
renovate[bot]
1f9813a28e chore(deps): update github/codeql-action action to v3.29.2 (#19806)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 12:26:07 +01:00
renovate[bot]
bbfff45058 chore(deps): update redis:6.2-alpine docker digest to 03fd052 (#19804)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 12:18:58 +02:00
Alex
87dd09d103 feat: selection mode timeline (#19734)
* feat: new page

* force multi-selection state

* fix: provider scoping

* Return selected assets

* lint

* lint

* simplify provider scope and drop drilling

* selection styling
2025-07-08 10:11:37 +05:30
Alex
dd94ad17aa fix: scrubber scroll error when page is not long enough (#19809) 2025-07-07 23:30:47 -05:00
renovate[bot]
a87c2e82cd fix(deps): update typescript-projects (#19666)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2025-07-07 20:29:58 +00:00
bo0tzz
a11ab4c3f7 chore: tidy up DCM analysis workflow (#19797) 2025-07-07 15:11:44 -05:00
Daimolean
ebf2f9fd7b feat(mobile): drift library page (#19789)
* feat(mobile): drift library page

* merge main & fix sliver padding

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-07-07 15:11:16 -05:00
Daimolean
683af67344 feat(mobile): drift video page (#19784)
* feat(mobile): drift video page

* filter motional parts

* remove status indicator join

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-07-07 18:51:49 +00:00
Daimolean
d149d6fa3f feat(mobile): drift favorite page (#19783)
* feat(mobile): drift favorite page

* remove status indicator join
2025-07-07 12:57:08 -05:00
Alex
8c5269c002 chore: lock DCM version in GHA (#19795) 2025-07-07 17:56:54 +00:00
Daimolean
cf91d9bdfc feat(mobile): drift locked folder page (#19746)
* feat(mobile): drift locked folder page

* feat: include local indicator

* remove join in bucket

* remove status indicator join

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-07-07 04:29:33 +00:00
Daimolean
5579554532 feat(mobile): drift trash page (#19745)
* feat(mobile): drift trash page

* feat: include local indicator

* remove join in bucket

* remove indicator join

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-07-07 04:05:40 +00:00
Damiano Ferrari
7e35e6985e chore: Use a contrasted color for text avatar (#19756) 2025-07-06 22:59:48 -05:00
Daimolean
56756baea2 feat(mobile): drift archive page (#19740)
* feat(mobile): drift archive page

* fix: lint

* feat: include local indicator

* remove join in bucket

* remove showing local indicator in bucket

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
Co-authored-by: alex <alex@localhost-live.localdomain>
2025-07-07 03:51:58 +00:00
matthieu-db
d5923241b5 fix: add quiet zone to QR code (#19771)
Add quiet zone to QR code

This is needed for the QR code to be readable by many QR readers. It is also a requirement for it to be a valid QR code.
2025-07-06 22:06:36 -05:00
Daimolean
cc471806fe feat(mobile): stack sync (#19735)
* feat(mobile): stack sync

* fix: lint

* Update mobile/lib/infrastructure/repositories/sync_api.repository.dart

Co-authored-by: Alex <alex.tran1502@gmail.com>

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-06 22:01:09 -05:00
Daniel Dietzler
4ce9bce414 feat: oauth role claim (#19758) 2025-07-06 18:45:32 -04:00
OffsetMonkey538
2f5d75ce21 docs: fix typo of webp listed under jpeg (#19743) 2025-07-05 15:52:22 +00:00
Daimolean
fb384fe90b fix(web): viewing asset lock (#19499)
* fix(web): viewing asset lock

* fix: lint

* make mutex stateless

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-07-05 02:52:39 +00:00
shenlong
73733370a2 feat: adds bottom sheet map and actions (#19726)
* reduce timeline rebuilds

* feat: adds bottom sheet map and actions (#19692)

* adds bottom sheet map and actions

* PR feedbacks

* only reload the asset viewer if asset is changed

* styling tweak

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>

* rename singleton and remove event prefix

* adds bottom sheet map and actions

* PR feedbacks

* refactor: use provider for viewer state

* feat: adds top and bottom app bar

* add safe area to bottom app bar

* change app and bottom bar color

* viewer - always have black background

* use the full width for the bottom sheet on landscape as well

* constraint the bottom sheet to not expand all the way

* add padding for location details in landscape

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-04 14:08:06 -05:00
Alex
4a2cf28882 feat: memories in new timeline (#19720)
* feat: memories sliver

* memories lane

* display and show memory

* fix: get correct memories

* naming

* pr feedback

* use equalsValue for visibility

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-04 13:49:15 -05:00
shenlong
181efb9010 refactor: reduce timeline rebuilds (#19704)
* reduce timeline rebuilds

* feat: adds bottom sheet map and actions (#19692)

* adds bottom sheet map and actions

* PR feedbacks

* only reload the asset viewer if asset is changed

* styling tweak

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>

* rename singleton and remove event prefix

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-04 10:30:34 -05:00
renovate[bot]
b00d44a00c fix(deps): update machine-learning (#19647) 2025-07-03 20:28:34 +00:00
Jason Rasmussen
6044663e26 refactor: sql-tools (#19717) 2025-07-03 10:59:17 -04:00
aviv926
484529e61e feat(server): add immich and postgres version to the database backup name (#19603) 2025-07-03 10:35:24 +01:00
Alex
445f9174ea feat: memories sync (#19644)
* feat: memories sync

* Update mobile/lib/infrastructure/repositories/sync_stream.repository.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update mobile/lib/infrastructure/repositories/sync_stream.repository.dart

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* show sync information

* tests and pr feedback

* pr feedback

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-02 19:18:37 +00:00
shenlong
7855974a29 feat(mobile): sqlite asset viewer (#19552)
* add full image provider and refactor thumb providers

* photo_view updates

* wip: asset-viewer

* fix controller dispose on page change

* wip: bottom sheet

* fix interactions

* more bottomsheet changes

* generate schema

* PR feedback

* refactor asset viewer

* never rotate and fix background on page change

* use photoview as the loading builder

* precache after delay

* claude: optimizing rebuild of image provider

* claude: optimizing image decoding and caching

* use proper cache for new full size image providers

* chore: load local HEIC fullsize for iOS

* make controller callbacks nullable

* remove imageprovider cache

* do not handle drag gestures when zoomed

* use loadOriginal setting for HEIC / larger images

* preload assets outside timer

* never use same controllers in photo-view gallery

* fix: cannot scroll down once swipe with bottom sheet

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-02 18:24:37 +00:00
Daimolean
ec603a008c feat(mobile): unarchive and unfavorite action (#19678) 2025-07-02 12:27:30 -05:00
shenlong
14276f41d8 fix: handle null bucket name during android sync (#19685)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-02 12:26:42 -05:00
Daimolean
a644cabab6 feat(mobile): trash and delete action (#19681)
* feat(mobile): trash and delete action

* fix lint
2025-07-02 12:26:07 -05:00
Daimolean
b8e67d0ef9 fix(mobile): filter deleted assets (#19683) 2025-07-02 12:25:14 -05:00
Min Idzelis
ca78bc91b6 feat: fully qualified path in error msg (#19674)
* feat: fully qualified path in error msg

* import style
2025-07-02 09:31:20 -04:00
shenlong
f2f3db3a79 refactor: action provider (#19677)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-01 23:08:52 -05:00
Jason Rasmussen
c435bdb5d3 refactor: sql-tools readers (#19672) 2025-07-01 22:57:17 -04:00
Min Idzelis
15da0d5a71 fix: email button (#19675) 2025-07-01 22:48:41 -04:00
Min Idzelis
090d87f82e chore: dev environment improvements and dependency updates (#19676) 2025-07-01 22:47:59 -04:00
Alex
25efba8fe6 chore: remove share link success prompt (#19671) 2025-07-01 16:55:17 +00:00
Daimolean
83afd49f5c feat(mobile): edit location action (#19645)
* change dto from integer to double

* feat(mobile): edit location action

* patch openapi

* refactor in provider

* fix lint

* chore: not showing success prompt if dimissed

* i18n

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-07-01 16:52:11 +00:00
Ramon Smits
639ede78c2 docs: document DB_STORAGE_TYPE environment variable (#19609)
Co-authored-by: Zack Pollard <github@zackpollard.uk>
2025-07-01 16:13:24 +00:00
shenlong
15be3437bf fix: timeline service uninitialised across routes (#19544) 2025-07-01 10:23:20 -05:00
Daimolean
f59b0bab5a refactor(mobile): action provider (#19669)
* refactor action provider

* fix lint
2025-07-01 10:18:23 -05:00
Alex
fa418d778b feat: lock folder action (#19634)
* feat: lock folder action

* refactor
2025-07-01 14:03:45 +00:00
bo0tzz
e0c4b8df6f chore: remove runner deps install step (#19527)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-07-01 14:18:14 +01:00
Min Idzelis
7f9689b4bc feat: bin for cli (#19648) 2025-07-01 08:00:41 -04:00
seifer44
e6f8bfdf5e chore(docs): add instruction for trusting self-signed certificates with Immich and an OAuth server (#18624) 2025-07-01 11:21:57 +00:00
Min Idzelis
8ccca04e27 fix(web): improve request cancellation handling in service worker cache (#19217) 2025-07-01 11:53:04 +01:00
Daniel Dietzler
53f80393bf chore: upgrade to cron v4 (#19664) 2025-07-01 12:47:04 +02:00
renovate[bot]
e5e857edc3 chore(deps): update prom/prometheus docker digest to 7a34573 (#19646)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-01 11:33:39 +01:00
renovate[bot]
590f96246d chore(deps): update github-actions (#19654)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-01 11:33:01 +01:00
renovate[bot]
38d73f2bc6 chore(deps): update dependency @types/node to ^22.15.33 (#19653)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-01 11:32:11 +01:00
renovate[bot]
96e3b96d57 fix(deps): update dependency nestjs-otel to v7 (#19662)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-01 11:02:46 +01:00
renovate[bot]
36b018e355 fix(deps): update typescript-projects (#18898)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-07-01 10:00:35 +00:00
renovate[bot]
214ca50406 chore(deps): update node.js to v22.17.0 (#19656)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-01 10:59:31 +01:00
renovate[bot]
29b3981609 fix(deps): update dependency nestjs-kysely to v3 (#19660)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-01 10:27:20 +01:00
Mert
a068a41c06 fix(server): prevent duplicate geodata temp table (#18580)
drop tmp table, create gist index first
2025-06-30 23:28:30 -04:00
bo0tzz
3c6e9e1191 feat: use request host as default SSR domain (#19485)
fix: hostname and domain confusion

chore: e2e test
2025-06-30 23:24:44 -04:00
Min Idzelis
db0415bbcc chore: undeclared versions/updates (#19649) 2025-06-30 23:23:41 -04:00
shenlong
a5c431fbf5 refactor: animate bottom sheet (#19655)
* refactor: animate bottom sheet

* rebase on main

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-06-30 22:23:38 -05:00
Min Idzelis
a3d588f6bd feat: makefile improvements (#19650) 2025-06-30 21:40:42 -05:00
shenlong
21f500191a refactor: actions provider (#19651)
* refactor: actions provider

* chore: rename error and stack

* remove empty checks

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-07-01 08:10:25 +05:30
shenlong
5011636d95 refactor: header - bulk select icon (#19652)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-06-30 21:33:37 -05:00
Alex
3f330c6476 feat: drift album page (#19564)
* feat: drift album page

* feat: page renderred

* feat: asset count

* refactor: use statefulwidget

* refactor: private widgets

* refactor: service layer

* refactor: import

* feat: get owner name

* pr feedback

* pr feedback

* pr feedback

* pr feedback
2025-07-01 07:54:50 +05:30
Daimolean
bb8755021d revert: timeout (#19639) 2025-06-30 17:02:50 -05:00
Jason Rasmussen
93f9e118ad refactor: timeline tests (#19641) 2025-06-30 17:43:45 -04:00
Jason Rasmussen
58ca1402ed feat: sync partner stacks (#19635) 2025-06-30 16:41:06 -04:00
Daimolean
32a7087883 feat(mobile): archive action (#19630)
* feat(mobile): archive action

* fix: lint

* Update i18n/en.json

Co-authored-by: Alex <alex.tran1502@gmail.com>

* fix: lint

* fix: lint

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-06-30 14:38:15 -05:00
Daimolean
53020852ec fix(web): modal race condition (#19625)
* fix(web): modal race condition

* fix: translation

* fix: translation
2025-06-30 14:33:47 -05:00
Jason Rasmussen
181a7e115f feat: sync stacks (#19629) 2025-06-30 14:26:41 -05:00
Alex
095ace8687 feat: shared link action (#19610) 2025-06-30 17:32:18 +00:00
Alex
4c3fcdc745 feat: favorite action (#19623) 2025-06-30 12:21:09 -05:00
Alex
fa5f30d9ca fix: timeline service mismatch state (#19612) 2025-06-30 12:20:13 -05:00
Jason Rasmussen
e60bc3c304 refactor: database types (#19624) 2025-06-30 13:19:16 -04:00
Jason Rasmussen
09cbc5d3f4 refactor: change password repository lookup (#19584) 2025-06-27 16:52:04 -04:00
Jason Rasmussen
a2a9797fab refactor: auth medium tests (#19583) 2025-06-27 15:35:19 -04:00
Matthew Momjian
3d35e65f27 fix(docs): add DB_USERNAME when needed (#19578)
add DB_USERNAME when needed
2025-06-27 13:54:27 -04:00
Jason Rasmussen
df76735f4a refactor: sync repository (#19581) 2025-06-27 13:47:06 -04:00
Jason Rasmussen
6feca56da8 feat: sync memories (#19579) 2025-06-27 12:20:13 -04:00
Alex
97aabe466e feat: action buttons place holder (#19561)
* feat: action buttons place holder

* lint

* Update base_action_button.widget.dart

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>

---------

Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
2025-06-27 13:33:46 +00:00
shenlong
72a53f43c8 feat: use sqlite timeline user provider (#19577)
use sqlite timeline user provider

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-06-27 08:29:27 -05:00
Jason Rasmussen
30b4f334d8 feat: upload manager (#19565) 2025-06-27 09:13:43 -04:00
Jason Rasmussen
6c6a32c63e refactor: memory medium tests (#19568) 2025-06-26 19:52:10 -04:00
Jason Rasmussen
6fed223405 fix: array-max-length (#19562) 2025-06-26 19:41:48 +00:00
Jason Rasmussen
3105094a3d refactor: medium tests (#19537) 2025-06-26 15:32:06 -04:00
Jason Rasmussen
b96c95beda refactor(server): sync service (#19559) 2025-06-26 17:24:57 +00:00
Daimolean
926ff075a3 fix(web): absolute path match in external library (#19551) 2025-06-26 10:46:34 -05:00
Min Idzelis
934649c8df feat(server): check additional exif date tags (#19216)
* feat(server): check additional exif date tags

- Add support for UTC date tags (GPSDateTime, DateTimeUTC, GPSDateStamp, SonyDateTime2)
- This matches tags that exiftool-vendored uses for tzSource in extractTzOffsetFromUTCOffset()

* Review comments

* nit

* review comments

* lots of tests for exif datetime

* missed

* format

* format again

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-06-26 10:18:40 -05:00
Brandon Wees
a43159f4ba fix(mobile): skip widget updates if on android (#19553)
* fix: skip widget updates if on android

* remove dead line
2025-06-26 10:07:22 -05:00
shenlong
ea3a14ed25 feat(mobile): add album asset sync (#19522)
* feat(mobile): add album asset sync

* add SyncAlbumToAssetDeleteV1 to openapi-spec

* update delete queries to use where in statements

* clear remote album when clear remote data

* fix: bad merge

* fix: bad merge

* fix: _SyncAckV1 return type

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: wuzihao051119 <wuzihao051119@outlook.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2025-06-26 08:50:39 -05:00
shenlong
24a4cba953 fix: enable photo manager custom filter by default (#19520)
enable photo manager custom filter by default

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-06-25 21:28:17 -05:00
shenlong
fda22c83b9 fix: sync stream album assets type order (#19540)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-06-25 20:42:56 -05:00
Matthew Momjian
2a8019726c feat(deployment): add shm_size for PG (#19472) 2025-06-25 20:38:37 +01:00
renovate[bot]
5f76cdddc7 chore(deps): update ghcr.io/astral-sh/uv:latest docker digest to 9653efd (#19530)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-25 20:37:53 +01:00
bo0tzz
48be10e48b fix: don't exclude .github folder from make install-all (#19534)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2025-06-25 20:37:40 +01:00
bo0tzz
6c11ef62e8 fix: don't use @master action version (#19526) 2025-06-25 17:55:17 +00:00
shenlong
65dce58aa4 refactor(mobile): do not skip iCloud albums during local sync (#19231)
do not skip cloud albums during local sync

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-06-25 16:46:31 +00:00
Brandon Wees
64cc7239fe feat(mobile): ios widget deeplink to asset in app (#19510)
* feat: ios widget deeplinks to asset in app

* fix: casing

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
2025-06-25 11:37:25 -05:00
renovate[bot]
5f89c2d111 chore(deps): pin actions/cache action to 5a3ec84 (#19529)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-25 16:21:49 +00:00
Daimolean
4621ec5ea2 fix(web): load day group in asset viewer (#19523)
* fix(web): load day group in asset viewer

* fix: lint
2025-06-25 11:18:11 -05:00
Jason Rasmussen
881a96cdf9 feat: add album asset sync (#19503)
wip: fix album asset exif and some other refactorings

feat: add album assets sync

feat: album to assets relation sync

Co-authored-by: Zack Pollard <zackpollard@ymail.com>
2025-06-25 16:10:31 +00:00
Alex
b001ba44f5 feat: generic control bottom app bar (#19524)
* feat: sliver appbar

* feat: snapping segment

* Date label font size

* lint

* fix: scrollController reinitialize multiple times

* feat: tab navigation

* chore: refactor to private widget

* feat: new control bottom app bar

* bad merge

* feat: sliver control bottom app bar
2025-06-25 16:08:02 +00:00
Zack Pollard
afb444c92c fix: only pass in is_main flag to mobile build for zizmor (#19525) 2025-06-25 17:53:08 +02:00
Zack Pollard
027c4a8b34 ci: much faster mobile builds (#19490) 2025-06-25 10:40:53 -05:00
Jason Rasmussen
eca9b56847 feat(server): person delete (#19511)
feat(api): person delete
2025-06-25 11:12:36 -04:00
shenlong
5b0575b956 refactor: DCM - const border radius, constructor & switch expressions (#19515)
* enable border radius, switch exp, const constructor

* regenerate provider

* more formatting

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
2025-06-25 13:06:24 +05:30
Alex
05064f87f0 feat: sliver appbar and snap scrubbing (#19446) 2025-06-24 20:02:46 -05:00
Alex
522cdbac99 feat: sliver timeline selection optimization (#19504) 2025-06-24 19:34:30 -05:00
renovate[bot]
9240bbc6ff chore(deps): update github-actions (#19045)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 22:54:05 +02:00
1967 changed files with 168221 additions and 63215 deletions

View File

@@ -11,8 +11,8 @@ services:
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
- server_node_modules:/workspaces/immich/server/node_modules
- web_node_modules:/workspaces/immich/web/node_modules
- ${UPLOAD_LOCATION}/photos:/workspaces/immich/server/upload
- ${UPLOAD_LOCATION}/photos/upload:/workspaces/immich/server/upload/upload
- ${UPLOAD_LOCATION}/photos:/data
- ${UPLOAD_LOCATION}/photos/upload:/data/upload
- /etc/localtime:/etc/localtime:ro
database:

View File

@@ -73,10 +73,8 @@ install_dependencies() {
log "Installing dependencies"
(
cd "${IMMICH_WORKSPACE}" || exit 1
run_cmd make ci-server
run_cmd make ci-sdk
run_cmd make build-sdk
run_cmd make ci-web
export CI=1 FROZEN=1 OFFLINE=1
run_cmd make setup-web-dev setup-server-dev
)
log ""
}

View File

@@ -13,8 +13,8 @@ services:
- open_api_node_modules:/workspaces/immich/open-api/typescript-sdk/node_modules
- server_node_modules:/workspaces/immich/server/node_modules
- web_node_modules:/workspaces/immich/web/node_modules
- ${UPLOAD_LOCATION:-upload1-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/workspaces/immich/server/upload
- ${UPLOAD_LOCATION:-upload2-devcontainer-volume}${UPLOAD_LOCATION:+/photos/upload}:/workspaces/immich/server/upload/upload
- ${UPLOAD_LOCATION:-upload1-devcontainer-volume}${UPLOAD_LOCATION:+/photos}:/data
- ${UPLOAD_LOCATION:-upload2-devcontainer-volume}${UPLOAD_LOCATION:+/photos/upload}:/data/upload
- /etc/localtime:/etc/localtime:ro
immich-web:
@@ -22,7 +22,7 @@ services:
immich-machine-learning:
env_file: !reset []
database:
env_file: !reset []
environment: !override
@@ -31,7 +31,7 @@ services:
POSTGRES_DB: ${DB_DATABASE_NAME-immich}
POSTGRES_INITDB_ARGS: '--data-checksums'
POSTGRES_HOST_AUTH_METHOD: md5
volumes:
volumes:
- ${UPLOAD_LOCATION:-postgres-devcontainer-volume}${UPLOAD_LOCATION:+/postgres}:/var/lib/postgresql/data
redis:

View File

@@ -1,37 +1,41 @@
.vscode/
.github/
.git/
.env*
*.log
*.tmp
*.temp
**/Dockerfile
**/node_modules/
**/.pnpm-store/
**/dist/
**/coverage/
**/build/
design/
docker/
!docker/scripts
docs/
!docs/package.json
!docs/package-lock.json
e2e/
!e2e/package.json
!e2e/package-lock.json
fastlane/
machine-learning/
misc/
mobile/
cli/coverage/
cli/dist/
cli/node_modules/
open-api/typescript-sdk/build/
open-api/typescript-sdk/node_modules/
!open-api/typescript-sdk/package.json
!open-api/typescript-sdk/package-lock.json
server/coverage/
server/node_modules/
server/upload/
server/src/queries
server/dist/
server/www/
web/node_modules/
web/coverage/
web/.svelte-kit
web/build/
web/.env

6
.gitattributes vendored
View File

@@ -12,6 +12,12 @@ mobile/lib/**/*.drift.dart linguist-generated=true
mobile/drift_schemas/main/drift_schema_*.json -diff -merge
mobile/drift_schemas/main/drift_schema_*.json linguist-generated=true
mobile/lib/infrastructure/repositories/db.repository.steps.dart -diff -merge
mobile/lib/infrastructure/repositories/db.repository.steps.dart linguist-generated=true
mobile/test/drift/main/generated/** -diff -merge
mobile/test/drift/main/generated/** linguist-generated=true
open-api/typescript-sdk/fetch-client.ts -diff -merge
open-api/typescript-sdk/fetch-client.ts linguist-generated=true

2
.github/.nvmrc vendored
View File

@@ -1 +1 @@
22.16.0
22.18.0

4
.github/.prettierignore vendored Normal file
View File

@@ -0,0 +1,4 @@
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

6
.github/package-lock.json generated vendored
View File

@@ -9,9 +9,9 @@
}
},
"node_modules/prettier": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"dev": true,
"license": "MIT",
"bin": {

View File

@@ -58,7 +58,7 @@ jobs:
contents: read
# Skip when PR from a fork
if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' && needs.pre-job.outputs.should_run == 'true' }}
runs-on: macos-14
runs-on: mich
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@@ -66,24 +66,40 @@ jobs:
ref: ${{ inputs.ref || github.sha }}
persist-credentials: false
- name: Create the Keystore
env:
KEY_JKS: ${{ secrets.KEY_JKS }}
working-directory: ./mobile
run: printf "%s" $KEY_JKS | base64 -d > android/key.jks
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: 'zulu'
java-version: '17'
cache: 'gradle'
- name: Restore Gradle Cache
id: cache-gradle-restore
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
~/.android/sdk
mobile/android/.gradle
mobile/.dart_tool
key: build-mobile-gradle-${{ runner.os }}-main
- name: Setup Flutter SDK
uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0
uses: subosito/flutter-action@fd55f4c5af5b953cc57a2be44cb082c8f6635e8e # v2.21.0
with:
channel: 'stable'
flutter-version-file: ./mobile/pubspec.yaml
cache: true
- name: Create the Keystore
env:
KEY_JKS: ${{ secrets.KEY_JKS }}
working-directory: ./mobile
run: echo $KEY_JKS | base64 -d > android/key.jks
- name: Setup Android SDK
uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3.2.2
with:
packages: ''
- name: Get Packages
working-directory: ./mobile
@@ -103,12 +119,30 @@ jobs:
ALIAS: ${{ secrets.ALIAS }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }}
IS_MAIN: ${{ github.ref == 'refs/heads/main' }}
run: |
flutter build apk --release
flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64
if [[ $IS_MAIN == 'true' ]]; then
flutter build apk --release
flutter build apk --release --split-per-abi --target-platform android-arm,android-arm64,android-x64
else
flutter build apk --debug --split-per-abi --target-platform android-arm64
fi
- name: Publish Android Artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: release-apk-signed
path: mobile/build/app/outputs/flutter-apk/*.apk
- name: Save Gradle Cache
id: cache-gradle-save
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4
if: github.ref == 'refs/heads/main'
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
~/.android/sdk
mobile/android/.gradle
mobile/.dart_tool
key: ${{ steps.cache-gradle-restore.outputs.cache-primary-key }}

View File

@@ -33,22 +33,21 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './cli/.nvmrc'
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Prepare SDK
run: pnpm install --frozen-lockfile
run: npm ci --prefix ../open-api/typescript-sdk/
- name: Build SDK
run: pnpm --dir ../open-api/typescript-sdk/ build
- run: pnpm build
- run: pnpm publish
run: npm run build --prefix ../open-api/typescript-sdk/
- run: npm ci
- run: npm run build
- run: npm publish
if: ${{ github.event_name == 'release' }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -71,7 +70,7 @@ jobs:
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Login to GitHub Container Registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
@@ -100,7 +99,7 @@ jobs:
type=raw,value=latest,enable=${{ github.event_name == 'release' }}
- name: Build and push image
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
file: cli/Dockerfile
platforms: linux/amd64,linux/arm64

96
.github/workflows/close-duplicates.yml vendored Normal file
View File

@@ -0,0 +1,96 @@
on:
issues:
types: [opened]
discussion:
types: [created]
name: Close likely duplicates
permissions: {}
jobs:
get_body:
runs-on: ubuntu-latest
env:
EVENT: ${{ toJSON(github.event) }}
outputs:
body: ${{ steps.get_body.outputs.body }}
steps:
- id: get_body
run: |
BODY=$(echo """$EVENT""" | jq -r '.issue // .discussion | .body' | base64 -w 0)
echo "body=$BODY" >> $GITHUB_OUTPUT
get_checkbox_json:
runs-on: ubuntu-latest
needs: get_body
container:
image: yshavit/mdq:0.7.2
outputs:
json: ${{ steps.get_checkbox.outputs.json }}
steps:
- id: get_checkbox
env:
BODY: ${{ needs.get_body.outputs.body }}
run: |
JSON=$(echo "$BODY" | base64 -d | /mdq --output json '# I have searched | - [?] Yes')
echo "json=$JSON" >> $GITHUB_OUTPUT
close_and_comment:
runs-on: ubuntu-latest
needs: get_checkbox_json
if: ${{ !fromJSON(needs.get_checkbox_json.outputs.json).items[0].list[0].checked }}
permissions:
issues: write
discussions: write
steps:
- name: Close issue
if: ${{ github.event_name == 'issues' }}
env:
GH_TOKEN: ${{ github.token }}
NODE_ID: ${{ github.event.issue.node_id }}
run: |
gh api graphql \
-f issueId="$NODE_ID" \
-f body="This issue has automatically been closed as it is likely a duplicate. We get a lot of duplicate threads each day, which is why we ask you in the template to confirm that you searched for duplicates before opening one." \
-f query='
mutation CommentAndCloseIssue($issueId: ID!, $body: String!) {
addComment(input: {
subjectId: $issueId,
body: $body
}) {
__typename
}
closeIssue(input: {
issueId: $issueId,
stateReason: DUPLICATE
}) {
__typename
}
}'
- name: Close discussion
if: ${{ github.event_name == 'discussion' && github.event.discussion.category.name == 'Feature Request' }}
env:
GH_TOKEN: ${{ github.token }}
NODE_ID: ${{ github.event.discussion.node_id }}
run: |
gh api graphql \
-f discussionId="$NODE_ID" \
-f body="This discussion has automatically been closed as it is likely a duplicate. We get a lot of duplicate threads each day, which is why we ask you in the template to confirm that you searched for duplicates before opening one." \
-f query='
mutation CommentAndCloseDiscussion($discussionId: ID!, $body: String!) {
addDiscussionComment(input: {
discussionId: $discussionId,
body: $body
}) {
__typename
}
closeDiscussion(input: {
discussionId: $discussionId,
reason: DUPLICATE
}) {
__typename
}
}'

View File

@@ -50,7 +50,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -63,7 +63,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/autobuild@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -76,6 +76,6 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
with:
category: '/language:${{matrix.language}}'

View File

@@ -131,7 +131,7 @@ jobs:
tag-suffix: '-rocm'
platforms: linux/amd64
runner-mapping: '{"linux/amd64": "mich"}'
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@094bfb927b8cd75b343abaac27b3241be0fccfe9 # multi-runner-build-workflow-0.1.0
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@129aeda75a450666ce96e8bc8126652e717917a7 # multi-runner-build-workflow-0.1.1
permissions:
contents: read
actions: read
@@ -154,7 +154,7 @@ jobs:
name: Build and Push Server
needs: pre-job
if: ${{ needs.pre-job.outputs.should_run_server == 'true' }}
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@094bfb927b8cd75b343abaac27b3241be0fccfe9 # multi-runner-build-workflow-0.1.0
uses: immich-app/devtools/.github/workflows/multi-runner-build.yml@129aeda75a450666ce96e8bc8126652e717917a7 # multi-runner-build-workflow-0.1.1
permissions:
contents: read
actions: read
@@ -177,7 +177,7 @@ jobs:
runs-on: ubuntu-latest
if: always()
steps:
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
- uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4
with:
needs: ${{ toJSON(needs) }}
@@ -188,6 +188,6 @@ jobs:
runs-on: ubuntu-latest
if: always()
steps:
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
- uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4
with:
needs: ${{ toJSON(needs) }}

View File

@@ -18,7 +18,7 @@ jobs:
permissions:
contents: read
outputs:
should_run: ${{ steps.found_paths.outputs.docs == 'true' || steps.should_force.outputs.should_force == 'true' }}
should_run: ${{ steps.found_paths.outputs.docs == 'true' || steps.found_paths.outputs.open-api == 'true' || steps.should_force.outputs.should_force == 'true' }}
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@@ -32,6 +32,8 @@ jobs:
- 'docs/**'
workflow:
- '.github/workflows/docs-build.yml'
open-api:
- 'open-api/immich-openapi-specs.json'
- name: Check if we should force jobs to run
id: should_force
run: echo "should_force=${{ steps.found_paths.outputs.workflow == 'true' || github.event_name == 'release' || github.ref_name == 'main' }}" >> "$GITHUB_OUTPUT"

View File

@@ -28,14 +28,12 @@ jobs:
token: ${{ steps.generate-token.outputs.token }}
persist-credentials: true
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './server/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Fix formatting
run: make install-all && make format-all

13
.github/workflows/org-checks.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
name: Org Checks
on:
pull_request_review:
pull_request:
jobs:
check-approvals:
name: Check for Team/Admin Review
uses: immich-app/devtools/.github/workflows/required-approval.yml@main
permissions:
pull-requests: read
contents: read

View File

@@ -14,7 +14,7 @@ jobs:
pull-requests: write
steps:
- name: Require PR to have a changelog label
uses: mheap/github-action-required-labels@fb29a14a076b0f74099f6198f77750e8fc236016 # v5.5.0
uses: mheap/github-action-required-labels@8afbe8ae6ab7647d0c9f0cfa7c2f939650d22509 # v5.5.1
with:
mode: exactly
count: 1

View File

@@ -100,7 +100,7 @@ jobs:
name: release-apk-signed
- name: Create draft release
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2
with:
draft: true
tag_name: ${{ env.IMMICH_VERSION }}

View File

@@ -20,20 +20,18 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './open-api/typescript-sdk/.nvmrc'
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Install deps
run: pnpm install --frozen-lockfile
run: npm ci
- name: Build
run: pnpm build
run: npm run build
- name: Publish
run: pnpm publish
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -42,6 +42,9 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
defaults:
run:
working-directory: ./mobile
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@@ -49,34 +52,29 @@ jobs:
persist-credentials: false
- name: Setup Flutter SDK
uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0
uses: subosito/flutter-action@fd55f4c5af5b953cc57a2be44cb082c8f6635e8e # v2.21.0
with:
channel: 'stable'
flutter-version-file: ./mobile/pubspec.yaml
- name: Install dependencies
run: dart pub get
working-directory: ./mobile
- name: Install DCM
run: |
sudo apt-get update
wget -qO- https://dcm.dev/pgp-key.public | sudo gpg --dearmor -o /usr/share/keyrings/dcm.gpg
echo 'deb [signed-by=/usr/share/keyrings/dcm.gpg arch=amd64] https://dcm.dev/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list
sudo apt-get update
sudo apt-get install dcm
uses: CQLabs/setup-dcm@8697ae0790c0852e964a6ef1d768d62a6675481a # v2.0.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
version: auto
working-directory: ./mobile
- name: Generate translation file
run: make translation
working-directory: ./mobile
- name: Run Build Runner
run: make build
working-directory: ./mobile
- name: Generate platform API
run: make pigeon
working-directory: ./mobile
- name: Find file changes
uses: tj-actions/verify-changed-files@a1c6acee9df209257a246f2cc6ae8cb6581c1edf # v20.0.4
@@ -92,25 +90,22 @@ jobs:
env:
CHANGED_FILES: ${{ steps.verify-changed-files.outputs.changed_files }}
run: |
echo "ERROR: Generated files not up to date! Run make_build inside the mobile directory"
echo "ERROR: Generated files not up to date! Run 'make build' and 'make pigeon' inside the mobile directory"
echo "Changed files: ${CHANGED_FILES}"
exit 1
- name: Run dart analyze
run: dart analyze --fatal-infos
working-directory: ./mobile
- name: Run dart format
run: dart format lib/ --set-exit-if-changed
working-directory: ./mobile
run: make format
- name: Run dart custom_lint
run: dart run custom_lint
working-directory: ./mobile
# TODO: Use https://github.com/CQLabs/dcm-action
- name: Run DCM
run: dcm analyze lib
working-directory: ./mobile
run: dcm analyze lib --fatal-style --fatal-warnings
zizmor:
name: zizmor
@@ -134,7 +129,7 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
with:
sarif_file: results.sarif
category: zizmor

View File

@@ -80,32 +80,30 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './server/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Run pnpm install
run: pnpm install --frozen-lockfile
- name: Run npm install
run: npm ci
- name: Run linter
run: pnpm lint
run: npm run lint
if: ${{ !cancelled() }}
- name: Run formatter
run: pnpm format
run: npm run format
if: ${{ !cancelled() }}
- name: Run tsc
run: pnpm check
run: npm run check
if: ${{ !cancelled() }}
- name: Run small tests & coverage
run: pnpm test
run: npm test
if: ${{ !cancelled() }}
cli-unit-tests:
@@ -125,36 +123,34 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './cli/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Setup typescript-sdk
run: pnpm install --frozen-lockfile && pnpm build
run: npm ci && npm run build
working-directory: ./open-api/typescript-sdk
- name: Install deps
run: pnpm install --frozen-lockfile
run: npm ci
- name: Run linter
run: pnpm lint
run: npm run lint
if: ${{ !cancelled() }}
- name: Run formatter
run: pnpm format
run: npm run format
if: ${{ !cancelled() }}
- name: Run tsc
run: pnpm check
run: npm run check
if: ${{ !cancelled() }}
- name: Run unit tests & coverage
run: pnpm test
run: npm run test
if: ${{ !cancelled() }}
cli-unit-tests-win:
@@ -174,29 +170,27 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './cli/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Setup typescript-sdk
run: pnpm install --frozen-lockfile && pnpm build
run: npm ci && npm run build
working-directory: ./open-api/typescript-sdk
- name: Install deps
run: pnpm install --frozen-lockfile
run: npm ci
# Skip linter & formatter in Windows test.
- name: Run tsc
run: pnpm check
run: npm run check
if: ${{ !cancelled() }}
- name: Run unit tests & coverage
run: pnpm test
run: npm run test
if: ${{ !cancelled() }}
web-lint:
@@ -216,32 +210,30 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './web/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Run setup typescript-sdk
run: pnpm install --frozen-lockfile && pnpm build
run: npm ci && npm run build
working-directory: ./open-api/typescript-sdk
- name: Run pnpm install
run: pnpm install --frozen-lockfile
- name: Run npm install
run: npm ci
- name: Run linter
run: pnpm lint:p
run: npm run lint:p
if: ${{ !cancelled() }}
- name: Run formatter
run: pnpm format
run: npm run format
if: ${{ !cancelled() }}
- name: Run svelte checks
run: pnpm check:svelte
run: npm run check:svelte
if: ${{ !cancelled() }}
web-unit-tests:
@@ -261,28 +253,26 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './web/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Run setup typescript-sdk
run: pnpm install --frozen-lockfile && pnpm build
run: npm ci && npm run build
working-directory: ./open-api/typescript-sdk
- name: Run pnpm install
run: pnpm install --frozen-lockfile
- name: Run npm install
run: npm ci
- name: Run tsc
run: pnpm run check:typescript
run: npm run check:typescript
if: ${{ !cancelled() }}
- name: Run unit tests & coverage
run: pnpm run test
run: npm run test
if: ${{ !cancelled() }}
i18n-tests:
@@ -298,20 +288,18 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './web/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Install dependencies
run: pnpm install --frozen-lockfile
run: npm --prefix=web ci
- name: Format
run: pnpm --dir=web format:i18n
run: npm --prefix=web run format:i18n
- name: Find file changes
uses: tj-actions/verify-changed-files@a1c6acee9df209257a246f2cc6ae8cb6581c1edf # v20.0.4
@@ -346,34 +334,32 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './e2e/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Run setup typescript-sdk
run: pnpm install --frozen-lockfile && pnpm run build
run: npm ci && npm run build
working-directory: ./open-api/typescript-sdk
if: ${{ !cancelled() }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
run: npm ci
if: ${{ !cancelled() }}
- name: Run linter
run: pnpm lint
run: npm run lint
if: ${{ !cancelled() }}
- name: Run formatter
run: pnpm format
run: npm run format
if: ${{ !cancelled() }}
- name: Run tsc
run: pnpm check
run: npm run check
if: ${{ !cancelled() }}
server-medium-tests:
@@ -393,20 +379,18 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './server/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Run pnpm install
run: pnpm install --frozen-lockfile
- name: Run npm install
run: npm ci
- name: Run medium tests
run: pnpm test:medium
run: npm run test:medium
if: ${{ !cancelled() }}
e2e-tests-server-cli:
@@ -430,27 +414,25 @@ jobs:
persist-credentials: false
submodules: 'recursive'
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './e2e/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Run setup typescript-sdk
run: pnpm install --frozen-lockfile && pnpm build
run: npm ci && npm run build
working-directory: ./open-api/typescript-sdk
if: ${{ !cancelled() }}
- name: Run setup cli
run: pnpm install --frozen-lockfile && pnpm build
run: npm ci && npm run build
working-directory: ./cli
if: ${{ !cancelled() }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
run: npm ci
if: ${{ !cancelled() }}
- name: Docker build
@@ -458,7 +440,7 @@ jobs:
if: ${{ !cancelled() }}
- name: Run e2e tests (api & cli)
run: pnpm test
run: npm run test
if: ${{ !cancelled() }}
e2e-tests-web:
@@ -482,22 +464,20 @@ jobs:
persist-credentials: false
submodules: 'recursive'
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './e2e/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Run setup typescript-sdk
run: pnpm install --frozen-lockfile && pnpm build
run: npm ci && npm run build
working-directory: ./open-api/typescript-sdk
if: ${{ !cancelled() }}
- name: Install dependencies
run: pnpm install --frozen-lockfile
run: npm ci
if: ${{ !cancelled() }}
- name: Install Playwright Browsers
@@ -519,7 +499,7 @@ jobs:
runs-on: ubuntu-latest
if: always()
steps:
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
- uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4
with:
needs: ${{ toJSON(needs) }}
@@ -536,7 +516,7 @@ jobs:
persist-credentials: false
- name: Setup Flutter SDK
uses: subosito/flutter-action@e938fdf56512cc96ef2f93601a5a40bde3801046 # v2.19.0
uses: subosito/flutter-action@fd55f4c5af5b953cc57a2be44cb082c8f6635e8e # v2.21.0
with:
channel: 'stable'
flutter-version-file: ./mobile/pubspec.yaml
@@ -604,20 +584,18 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './.github/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Run pnpm install
run: pnpm install --frozen-lockfile
- name: Run npm install
run: npm ci
- name: Run formatter
run: pnpm format
run: npm run format
if: ${{ !cancelled() }}
shellcheck:
@@ -631,7 +609,7 @@ jobs:
persist-credentials: false
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0
with:
ignore_paths: >-
**/open-api/**
@@ -649,20 +627,18 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './server/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Install server dependencies
run: pnpm install --frozen-lockfile
run: npm --prefix=server ci
- name: Build the app
run: pnpm --dir=server build
run: npm --prefix=server run build
- name: Run API generation
run: make open-api
@@ -692,7 +668,7 @@ jobs:
contents: read
services:
postgres:
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3@sha256:ec713143dca1a426eba2e03707c319e2ec3cc9d304ef767f777f8e297dee820c
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
@@ -714,30 +690,28 @@ jobs:
with:
persist-credentials: false
- name: Setup pnpm
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version-file: './server/.nvmrc'
cache: 'pnpm'
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Install server dependencies
run: pnpm install --frozen-lockfile
run: npm ci
- name: Build the app
run: pnpm build
run: npm run build
- name: Run existing migrations
run: pnpm migrations:run
run: npm run migrations:run
- name: Test pnpm schema:reset command works
run: pnpm schema:reset
- name: Test npm run schema:reset command works
run: npm run schema:reset
- name: Generate new migrations
continue-on-error: true
run: pnpm migrations:generate src/TestMigration
run: npm run migrations:generate src/TestMigration
- name: Find file changes
uses: tj-actions/verify-changed-files@a1c6acee9df209257a246f2cc6ae8cb6581c1edf # v20.0.4
@@ -756,7 +730,7 @@ jobs:
exit 1
- name: Run SQL generation
run: pnpm sync:sql
run: npm run sync:sql
env:
DB_URL: postgres://postgres:postgres@localhost:5432/immich

View File

@@ -38,7 +38,7 @@ jobs:
exit 1
fi
- name: Find Pull Request
uses: juliangruber/find-pull-request-action@48b6133aa6c826f267ebd33aa2d29470f9d9e7d0 # v1.9.0
uses: juliangruber/find-pull-request-action@952b3bb1ddb2dcc0aa3479e98bb1c2d1a922f096 # v1.10.0
id: find-pr
with:
branch: chore/translations
@@ -52,6 +52,6 @@ jobs:
permissions: {}
if: always()
steps:
- uses: immich-app/devtools/actions/success-check@6b81b1572e466f7f48ba3c823159ce3f4a4d66a6 # success-check-action-0.0.3
- uses: immich-app/devtools/actions/success-check@68f10eb389bb02a3cf9d1156111964c549eb421b # 0.0.4
with:
needs: ${{ toJSON(needs) }}

1
.gitignore vendored
View File

@@ -24,3 +24,4 @@ mobile/android/fastlane/report.xml
mobile/ios/fastlane/report.xml
vite.config.js.timestamp-*
.pnpm-store

4
.vscode/launch.json vendored
View File

@@ -7,7 +7,7 @@
"restart": true,
"port": 9231,
"name": "Immich API Server",
"remoteRoot": "/usr/src/app",
"remoteRoot": "/usr/src/app/server",
"localRoot": "${workspaceFolder}/server"
},
{
@@ -16,7 +16,7 @@
"restart": true,
"port": 9230,
"name": "Immich Workers",
"remoteRoot": "/usr/src/app",
"remoteRoot": "/usr/src/app/server",
"localRoot": "${workspaceFolder}/server"
}
]

View File

@@ -1,27 +1,33 @@
dev:
docker compose -f ./docker/docker-compose.dev.yml up --remove-orphans || make dev-down
@trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --remove-orphans
dev-down:
docker compose -f ./docker/docker-compose.dev.yml down --remove-orphans
dev-update:
docker compose -f ./docker/docker-compose.dev.yml up --build -V --remove-orphans
@trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --build -V --remove-orphans
dev-scale:
docker compose -f ./docker/docker-compose.dev.yml up --build -V --scale immich-server=3 --remove-orphans
@trap 'make dev-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.dev.yml up --build -V --scale immich-server=3 --remove-orphans
.PHONY: e2e
e2e:
docker compose -f ./e2e/docker-compose.yml up --build -V --remove-orphans
@trap 'make e2e-down' EXIT; COMPOSE_BAKE=true docker compose -f ./e2e/docker-compose.yml up --build -V --remove-orphans
e2e-update:
@trap 'make e2e-down' EXIT; COMPOSE_BAKE=true docker compose -f ./e2e/docker-compose.yml up --build -V --remove-orphans
e2e-down:
docker compose -f ./e2e/docker-compose.yml down --remove-orphans
prod:
docker compose -f ./docker/docker-compose.prod.yml up --build -V --remove-orphans
@trap 'make prod-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.prod.yml up --build -V --remove-orphans
prod-down:
docker compose -f ./docker/docker-compose.prod.yml down --remove-orphans
prod-scale:
docker compose -f ./docker/docker-compose.prod.yml up --build -V --scale immich-server=3 --scale immich-microservices=3 --remove-orphans
@trap 'make prod-down' EXIT; COMPOSE_BAKE=true docker compose -f ./docker/docker-compose.prod.yml up --build -V --scale immich-server=3 --scale immich-microservices=3 --remove-orphans
.PHONY: open-api
open-api:
@@ -34,7 +40,7 @@ open-api-typescript:
cd ./open-api && bash ./bin/generate-open-api.sh typescript
sql:
pnpm --dir server run sync:sql
npm --prefix server run sync:sql
attach-server:
docker exec -it docker_immich-server_1 sh
@@ -45,30 +51,30 @@ renovate:
MODULES = e2e server web cli sdk docs .github
audit-%:
pnpm --dir $(subst sdk,open-api/typescript-sdk,$*) audit fix
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) audit fix
install-%:
pnpm --dir $(subst sdk,open-api/typescript-sdk,$*) i
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) i
ci-%:
pnpm --dir $(subst sdk,open-api/typescript-sdk,$*) install --frozen-lockfile
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) ci
build-cli: build-sdk
build-web: build-sdk
build-%: install-%
pnpm --dir $(subst sdk,open-api/typescript-sdk,$*) build
npm --prefix $(subst sdk,open-api/typescript-sdk,$*) run build
format-%:
pnpm --dir $* format:fix
npm --prefix $* run format:fix
lint-%:
pnpm --dir $* lint:fix
npm --prefix $* run lint:fix
check-%:
pnpm --dir $* check
npm --prefix $* run check
check-web:
pnpm --dir web check:typescript
pnpm --dir web check:svelte
npm --prefix web run check:typescript
npm --prefix web run check:svelte
test-%:
pnpm --dir $* test
npm --prefix $* run test
test-e2e:
docker compose -f ./e2e/docker-compose.yml build
pnpm --dir e2e test
pnpm --dir e2e test:web
npm --prefix e2e run test
npm --prefix e2e run test:web
test-medium:
docker run \
--rm \
@@ -78,12 +84,12 @@ test-medium:
-v ./server/tsconfig.json:/usr/src/app/tsconfig.json \
-e NODE_ENV=development \
immich-server:latest \
-c "pnpm install --frozen-lockfile && pnpm test:medium -- --run"
-c "npm ci && npm run test:medium -- --run"
test-medium-dev:
docker exec -it immich_server /bin/sh -c "pnpm test:medium"
docker exec -it immich_server /bin/sh -c "npm run test:medium"
build-all: $(foreach M,$(filter-out e2e .github,$(MODULES)),build-$M) ;
install-all: $(foreach M,$(filter-out .github,$(MODULES)),install-$M) ;
install-all: $(foreach M,$(MODULES),install-$M) ;
ci-all: $(foreach M,$(filter-out .github,$(MODULES)),ci-$M) ;
check-all: $(foreach M,$(filter-out sdk cli docs .github,$(MODULES)),check-$M) ;
lint-all: $(foreach M,$(filter-out sdk docs .github,$(MODULES)),lint-$M) ;
@@ -93,9 +99,12 @@ hygiene-all: lint-all format-all check-all sql audit-all;
test-all: $(foreach M,$(filter-out sdk docs .github,$(MODULES)),test-$M) ;
clean:
find . -name "node_modules" -type d -prune -exec rm -rf '{}' +
find . -name "node_modules" -type d -prune -exec rm -rf {} +
find . -name "dist" -type d -prune -exec rm -rf '{}' +
find . -name "build" -type d -prune -exec rm -rf '{}' +
find . -name "svelte-kit" -type d -prune -exec rm -rf '{}' +
docker compose -f ./docker/docker-compose.dev.yml rm -v -f || true
docker compose -f ./e2e/docker-compose.yml rm -v -f || true
command -v docker >/dev/null 2>&1 && docker compose -f ./docker/docker-compose.dev.yml rm -v -f || true
command -v docker >/dev/null 2>&1 && docker compose -f ./e2e/docker-compose.yml rm -v -f || true
setup-server-dev: install-server
setup-web-dev: install-sdk build-sdk install-web

View File

@@ -9,6 +9,7 @@ upload/**
.prettierignore
.prettierrc
Dockerfile
package-lock.json
tsconfig.json
vite.config.ts
vitest.config.ts

View File

@@ -1 +1 @@
22.16.0
22.18.0

View File

@@ -2,17 +2,17 @@ FROM node:22.16.0-alpine3.20@sha256:2289fb1fba0f4633b08ec47b94a89c7e20b829fc5679
WORKDIR /usr/src/open-api/typescript-sdk
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
RUN pnpm install --frozen-lockfile
RUN npm ci
COPY open-api/typescript-sdk/ ./
RUN pnpm build
RUN npm run build
WORKDIR /usr/src/app
COPY cli/package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY cli/package.json cli/package-lock.json ./
RUN npm ci
COPY cli .
RUN pnpm build
RUN npm run build
WORKDIR /import

View File

@@ -6,8 +6,8 @@ Please see the [Immich CLI documentation](https://immich.app/docs/features/comma
Before building the CLI, you must build the immich server and the open-api client. To build the server run the following in the server folder:
$ pnpm install
$ pnpm build
$ npm install
$ npm run build
Then, to build the open-api client run the following in the open-api folder:
@@ -15,8 +15,8 @@ Then, to build the open-api client run the following in the open-api folder:
To run the Immich CLI from source, run the following in the cli folder:
$ pnpm install
$ pnpm build
$ npm install
$ npm run build
$ ts-node .
You'll need ts-node, the easiest way to install it is to use npm:
@@ -25,6 +25,6 @@ You'll need ts-node, the easiest way to install it is to use npm:
You can also build and install the CLI using
$ pnpm build
$ pnpm install -g .
$ npm run build
$ npm install -g .
****

2
cli/bin/immich Executable file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/env node
import '../dist/index.js';

4600
cli/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,11 @@
{
"name": "@immich/cli",
"version": "2.2.72",
"version": "2.2.77",
"description": "Command Line Interface (CLI) for Immich",
"type": "module",
"exports": "./dist/index.js",
"bin": {
"immich": "dist/index.js"
"immich": "./bin/immich"
},
"license": "GNU Affero General Public License version 3",
"keywords": [
@@ -15,28 +15,28 @@
"devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.8.0",
"@immich/sdk": "workspace:^",
"@immich/sdk": "file:../open-api/typescript-sdk",
"@types/byte-size": "^8.1.0",
"@types/cli-progress": "^3.11.0",
"@types/lodash-es": "^4.17.12",
"@types/micromatch": "^4.0.9",
"@types/mock-fs": "^4.13.1",
"@types/node": "^22.15.32",
"@types/node": "^22.17.0",
"@vitest/coverage-v8": "^3.0.0",
"byte-size": "^9.0.0",
"cli-progress": "^3.12.0",
"commander": "^12.0.0",
"eslint": "^9.14.0",
"eslint-config-prettier": "^10.0.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^59.0.0",
"eslint-plugin-unicorn": "^60.0.0",
"globals": "^16.0.0",
"mock-fs": "^5.2.0",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^4.0.0",
"typescript": "^5.3.3",
"typescript-eslint": "^8.28.0",
"vite": "^6.0.0",
"vite": "^7.0.0",
"vite-tsconfig-paths": "^5.0.0",
"vitest": "^3.0.0",
"vitest-fetch-mock": "^0.4.0",
@@ -69,6 +69,6 @@
"micromatch": "^4.0.8"
},
"volta": {
"node": "22.16.0"
"node": "22.18.0"
}
}

View File

@@ -2,37 +2,37 @@
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.52.0"
constraints = "4.52.0"
version = "4.52.1"
constraints = "4.52.1"
hashes = [
"h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=",
"h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=",
"h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=",
"h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=",
"h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=",
"h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=",
"h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=",
"h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=",
"h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=",
"h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=",
"h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=",
"h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=",
"h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=",
"h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=",
"zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0",
"zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8",
"zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238",
"zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f",
"zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f",
"zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8",
"zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9",
"zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060",
"h1:2lHvafwGbLdmc9lYkuJFw3nsInaQjRpjX/JfIRKmq/M=",
"h1:596JomwjrtUrOSreq9NNCS+rj70+jOV+0pfja5MXiTI=",
"h1:7mBOA5TVAIt3qAwPXKCtE0RSYeqij9v30mnksuBbpEg=",
"h1:ELVgzh4kHKBCYdL+2A8JjWS0E1snLUN3Mmz3Vo6qSfw=",
"h1:FGGM5yLFf72g3kSXM3LAN64Gf/AkXr5WCmhixgnP+l4=",
"h1:JupkJbQALcIVoMhHImrLeLDsQR1ET7VJLGC7ONxjqGU=",
"h1:KsaE4JNq+1uV1nJsuTcYar/8lyY6zKS5UBEpfYg3wvc=",
"h1:NHZ5RJIzQDLhie/ykl3uI6UPfNQR9Lu5Ti7JPR6X904=",
"h1:NfAuMbn6LQPLDtJhbzO1MX9JMIGLMa8K6CpekvtsuX8=",
"h1:e+vNKokamDsp/kJvFr2pRudzwEz2r49iZ/oSggw+1LY=",
"h1:jnb4VdfNZ79I3yj7Q8x+JmOT+FxbfjjRfrF0dL0yCW8=",
"h1:kmF//O539d7NuHU7qIxDj7Wz4eJmLKFiI5glwQivldU=",
"h1:s6XriaKwOgV4jvKAGPXkrxhhOQxpNU5dceZwi9Z/1k8=",
"h1:wt3WBEBAeSGTlC9OlnTlAALxRiK4SQgLy0KgBIS7qzs=",
"zh:2fb95e1d3229b9b6c704e1a413c7481c60f139780d9641f657b6eb9b633b90f2",
"zh:379c7680983383862236e9e6e720c3114195c40526172188e88d0ffcf50dfe2e",
"zh:55533beb6cfc02d22ffda8cba8027bc2c841bb172cd637ed0d28323d41395f8f",
"zh:5abd70760e4eb1f37a1c307cbd2989ea7c9ba0afb93818c67c1d363a31f75703",
"zh:699f1c8cd66129176fe659ebf0e6337632a8967a28d2630b6ae5948665c0c2ae",
"zh:69c15acd73c451e89de6477059cda2f3ec200b48ae4b9ff3646c4d389fd3205e",
"zh:6e02b687de21b844f8266dff99e93e7c61fc8eb688f4bbb23803caceb251839e",
"zh:7a51d17b87ed87b7bebf2ad9fc7c3a74f16a1b44eee92c779c08eb89258c0496",
"zh:88ad84436837b0f55302f22748505972634e87400d6902260fd6b7ba1610f937",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6",
"zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb",
"zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b",
"zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380",
"zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7",
"zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672",
"zh:8d46c3d9f4f7ad20ac6ef01daa63f4e30a2d16dcb1bb5c7c7ee3dc6be38e9ca1",
"zh:913d64e72a4929dae1d4793e2004f4f9a58b138ea337d9d94fa35cafbf06550a",
"zh:c8d93cf86e2e49f6cec665cfe78b82c144cce15a8b2e30f343385fadd1251849",
"zh:cc4f69397d9bc34a528a5609a024c3a48f54f21616c0008792dd417297add955",
"zh:df99cdb8b064aad35ffea77e645cf6541d0b1b2ebc51b6d26c42031de60ab69e",
]
}

View File

@@ -5,7 +5,7 @@ terraform {
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "4.52.0"
version = "4.52.1"
}
}
}

View File

@@ -2,37 +2,37 @@
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/cloudflare/cloudflare" {
version = "4.52.0"
constraints = "4.52.0"
version = "4.52.1"
constraints = "4.52.1"
hashes = [
"h1:2BEJyXJtYC4B4nda/WCYUmuJYDaYk88F8t1pwPzr0iQ=",
"h1:4IASk5SESeWKQ7JU0+M7KApuF5mZyklvwMXPBabim3c=",
"h1:5ImZxxALSnWfH/4EXw/wFirSmk5Tr0ACmcysy51AafE=",
"h1:6TJ3dxLSin4ZKBJLsZDn95H2ZYnGm8S7GGHvvXuuMQU=",
"h1:IzTUjg9kQ4N3qizP9CjYLeHwjsuGgtxwXvfUQWyOLcA=",
"h1:NTaOQfYINA0YTG/V1/9+SYtgX1it63+cBugj4WK4FWc=",
"h1:PXH48LuJn329sCfMXprdMDk51EZaWFyajVvS03qhQLs=",
"h1:Pi5M+GeoMSN2eJ6QnIeXjBf19O+rby/74CfB2ocpv20=",
"h1:ShXZ2ZjBvm3thfoPPzPT8+OhyismnydQVkUAfI8X12w=",
"h1:WQ9hu0Wge2msBbODfottCSKgu8oKUrw4Opz+fDPVVHk=",
"h1:Z5yXML2DE0uH9UU+M0ut9JMQAORcwVZz1CxBHzeBmao=",
"h1:jqI2qKknpleS3JDSplyGYHMu0u9K/tor1ZOjFwDgEMk=",
"h1:kgfutDh14Q5nw4eg6qGFamFxIiY8Ae0FPKRBLDOzpcI=",
"h1:zCAO7GZmfYhWb+i6TfqlqhMeDyPZWGio2IzEzAh3YTs=",
"zh:19be1a91c982b902c42aba47766860dfa5dc151eed1e95fd39ca642229381ef0",
"zh:1de451c4d1ecf7efbe67b6dace3426ba810711afdd644b0f1b870364c8ae91f8",
"zh:352b4a2120173298622e669258744554339d959ac3a95607b117a48ee4a83238",
"zh:3c6f1346d9154afbd2d558fabb4b0150fc8d559aa961254144fe1bc17fe6032f",
"zh:4c4c92d53fb535b1e0eff26f222bbd627b97d3b4c891ec9c321268676d06152f",
"zh:53276f68006c9ceb7cdb10a6ccf91a5c1eadd1407a28edb5741e84e88d7e29e8",
"zh:7925a97773948171a63d4f65bb81ee92fd6d07a447e36012977313293a5435c9",
"zh:7dfb0a4496cfe032437386d0a2cd9229a1956e9c30bd920923c141b0f0440060",
"h1:2lHvafwGbLdmc9lYkuJFw3nsInaQjRpjX/JfIRKmq/M=",
"h1:596JomwjrtUrOSreq9NNCS+rj70+jOV+0pfja5MXiTI=",
"h1:7mBOA5TVAIt3qAwPXKCtE0RSYeqij9v30mnksuBbpEg=",
"h1:ELVgzh4kHKBCYdL+2A8JjWS0E1snLUN3Mmz3Vo6qSfw=",
"h1:FGGM5yLFf72g3kSXM3LAN64Gf/AkXr5WCmhixgnP+l4=",
"h1:JupkJbQALcIVoMhHImrLeLDsQR1ET7VJLGC7ONxjqGU=",
"h1:KsaE4JNq+1uV1nJsuTcYar/8lyY6zKS5UBEpfYg3wvc=",
"h1:NHZ5RJIzQDLhie/ykl3uI6UPfNQR9Lu5Ti7JPR6X904=",
"h1:NfAuMbn6LQPLDtJhbzO1MX9JMIGLMa8K6CpekvtsuX8=",
"h1:e+vNKokamDsp/kJvFr2pRudzwEz2r49iZ/oSggw+1LY=",
"h1:jnb4VdfNZ79I3yj7Q8x+JmOT+FxbfjjRfrF0dL0yCW8=",
"h1:kmF//O539d7NuHU7qIxDj7Wz4eJmLKFiI5glwQivldU=",
"h1:s6XriaKwOgV4jvKAGPXkrxhhOQxpNU5dceZwi9Z/1k8=",
"h1:wt3WBEBAeSGTlC9OlnTlAALxRiK4SQgLy0KgBIS7qzs=",
"zh:2fb95e1d3229b9b6c704e1a413c7481c60f139780d9641f657b6eb9b633b90f2",
"zh:379c7680983383862236e9e6e720c3114195c40526172188e88d0ffcf50dfe2e",
"zh:55533beb6cfc02d22ffda8cba8027bc2c841bb172cd637ed0d28323d41395f8f",
"zh:5abd70760e4eb1f37a1c307cbd2989ea7c9ba0afb93818c67c1d363a31f75703",
"zh:699f1c8cd66129176fe659ebf0e6337632a8967a28d2630b6ae5948665c0c2ae",
"zh:69c15acd73c451e89de6477059cda2f3ec200b48ae4b9ff3646c4d389fd3205e",
"zh:6e02b687de21b844f8266dff99e93e7c61fc8eb688f4bbb23803caceb251839e",
"zh:7a51d17b87ed87b7bebf2ad9fc7c3a74f16a1b44eee92c779c08eb89258c0496",
"zh:88ad84436837b0f55302f22748505972634e87400d6902260fd6b7ba1610f937",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:8d4aa79f0a414bb4163d771063c70cd991c8fac6c766e685bac2ee12903c5bd6",
"zh:a67540c13565616a7e7e51ee9366e88b0dc60046e1d75c72680e150bd02725bb",
"zh:a936383a4767f5393f38f622e92bf2d0c03fe04b69c284951f27345766c7b31b",
"zh:d4887d73c466ff036eecf50ad6404ba38fd82ea4855296b1846d244b0f13c380",
"zh:e9093c8bd5b6cd99c81666e315197791781b8f93afa14fc2e0f732d1bb2a44b7",
"zh:efd3b3f1ec59a37f635aa1d4efcf178734c2fcf8ddb0d56ea690bec342da8672",
"zh:8d46c3d9f4f7ad20ac6ef01daa63f4e30a2d16dcb1bb5c7c7ee3dc6be38e9ca1",
"zh:913d64e72a4929dae1d4793e2004f4f9a58b138ea337d9d94fa35cafbf06550a",
"zh:c8d93cf86e2e49f6cec665cfe78b82c144cce15a8b2e30f343385fadd1251849",
"zh:cc4f69397d9bc34a528a5609a024c3a48f54f21616c0008792dd417297add955",
"zh:df99cdb8b064aad35ffea77e645cf6541d0b1b2ebc51b6d26c42031de60ab69e",
]
}

View File

@@ -5,7 +5,7 @@ terraform {
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "4.52.0"
version = "4.52.1"
}
}
}

View File

@@ -16,7 +16,7 @@ name: immich-dev
services:
immich-server:
container_name: immich_server
command: ['/usr/src/app/bin/immich-dev']
command: ['immich-dev']
image: immich-server-dev:latest
# extends:
# file: hwaccel.transcoding.yml
@@ -27,11 +27,11 @@ services:
target: dev
restart: unless-stopped
volumes:
- ../server:/usr/src/app
- ../open-api:/usr/src/open-api
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
- ${UPLOAD_LOCATION}/photos/upload:/usr/src/app/upload/upload
- /usr/src/app/node_modules
- ../server:/usr/src/app/server
- ../open-api:/usr/src/app/open-api
- ${UPLOAD_LOCATION}/photos:/data
- ${UPLOAD_LOCATION}/photos/upload:/data/upload
- /usr/src/app/server/node_modules
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
@@ -69,19 +69,20 @@ services:
# Needed for rootless docker setup, see https://github.com/moby/moby/issues/45919
# user: 0:0
build:
context: ../web
command: ['/usr/src/app/bin/immich-web']
context: ../
dockerfile: web/Dockerfile
command: ['immich-web']
env_file:
- .env
ports:
- 3000:3000
- 24678:24678
volumes:
- ../web:/usr/src/app
- ../i18n:/usr/src/i18n
- ../open-api/:/usr/src/open-api/
- ../web:/usr/src/app/web
- ../i18n:/usr/src/app/i18n
- ../open-api/:/usr/src/app/open-api/
# - ../../ui:/usr/ui
- /usr/src/app/node_modules
- /usr/src/app/web/node_modules
ulimits:
nofile:
soft: 1048576
@@ -116,13 +117,13 @@ services:
redis:
container_name: immich_redis
image: docker.io/valkey/valkey:8-bookworm@sha256:fec42f399876eb6faf9e008570597741c87ff7662a54185593e74b09ce83d177
image: docker.io/valkey/valkey:8-bookworm@sha256:facc1d2c3462975c34e10fccb167bfa92b0e0dbd992fc282c29a61c3243afb11
healthcheck:
test: redis-cli ping || exit 1
database:
container_name: immich_postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:5f6a838e4e44c8e0e019d0ebfe3ee8952b69afc2809b2c25f7b0119641978e91
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
env_file:
- .env
environment:
@@ -134,6 +135,7 @@ services:
- ${UPLOAD_LOCATION}/postgres:/var/lib/postgresql/data
ports:
- 5432:5432
shm_size: 128mb
# set IMMICH_TELEMETRY_INCLUDE=all in .env to enable metrics
# immich-prometheus:
# container_name: immich_prometheus

View File

@@ -20,7 +20,7 @@ services:
context: ../
dockerfile: server/Dockerfile
volumes:
- ${UPLOAD_LOCATION}/photos:/usr/src/app/upload
- ${UPLOAD_LOCATION}/photos:/data
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
@@ -56,14 +56,14 @@ services:
redis:
container_name: immich_redis
image: docker.io/valkey/valkey:8-bookworm@sha256:fec42f399876eb6faf9e008570597741c87ff7662a54185593e74b09ce83d177
image: docker.io/valkey/valkey:8-bookworm@sha256:facc1d2c3462975c34e10fccb167bfa92b0e0dbd992fc282c29a61c3243afb11
healthcheck:
test: redis-cli ping || exit 1
restart: always
database:
container_name: immich_postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:5f6a838e4e44c8e0e019d0ebfe3ee8952b69afc2809b2c25f7b0119641978e91
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
env_file:
- .env
environment:
@@ -75,6 +75,7 @@ services:
- ${UPLOAD_LOCATION}/postgres:/var/lib/postgresql/data
ports:
- 5432:5432
shm_size: 128mb
restart: always
# set IMMICH_TELEMETRY_INCLUDE=all in .env to enable metrics
@@ -82,7 +83,7 @@ services:
container_name: immich_prometheus
ports:
- 9090:9090
image: prom/prometheus@sha256:9abc6cf6aea7710d163dbb28d8eeb7dc5baef01e38fa4cd146a406dd9f07f70d
image: prom/prometheus@sha256:63805ebb8d2b3920190daf1cb14a60871b16fd38bed42b857a3182bc621f4996
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
@@ -94,7 +95,7 @@ services:
command: ['./run.sh', '-disable-reporting']
ports:
- 3000:3000
image: grafana/grafana:12.0.2-ubuntu@sha256:0512d81cdeaaff0e370a9aa66027b465d1f1f04379c3a9c801a905fabbdbc7a5
image: grafana/grafana:12.1.0-ubuntu@sha256:397aa30dd1af16cb6c5c9879498e467973a7f87eacf949f6d5a29407a3843809
volumes:
- grafana-data:/var/lib/grafana

View File

@@ -18,7 +18,7 @@ services:
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
volumes:
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
@@ -49,14 +49,14 @@ services:
redis:
container_name: immich_redis
image: docker.io/valkey/valkey:8-bookworm@sha256:fec42f399876eb6faf9e008570597741c87ff7662a54185593e74b09ce83d177
image: docker.io/valkey/valkey:8-bookworm@sha256:facc1d2c3462975c34e10fccb167bfa92b0e0dbd992fc282c29a61c3243afb11
healthcheck:
test: redis-cli ping || exit 1
restart: always
database:
container_name: immich_postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:5f6a838e4e44c8e0e019d0ebfe3ee8952b69afc2809b2c25f7b0119641978e91
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
@@ -67,6 +67,7 @@ services:
volumes:
# Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
shm_size: 128mb
restart: always
volumes:

View File

@@ -1 +1 @@
22.16.0
22.18.0

View File

@@ -180,7 +180,7 @@ services:
...
volumes:
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
+ - originals:/usr/src/app/originals
...
@@ -490,7 +490,7 @@ You can also scan the Postgres database file structure for errors:
<details>
<summary>Scan for file structure errors</summary>
```bash
docker exec -it immich_postgres pg_amcheck --username=postgres --heapallindexed --parent-check --rootdescend --progress --all --install-missing
docker exec -it immich_postgres pg_amcheck --username=<DB_USERNAME> --heapallindexed --parent-check --rootdescend --progress --all --install-missing
```
A normal result will end something like this and return with an exit code of `0`:

View File

@@ -57,7 +57,7 @@ Then please follow the steps in the following section for restoring the database
<TabItem value="Linux system" label="Linux system" default>
```bash title='Backup'
docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgres | gzip > "/path/to/backup/dump.sql.gz"
docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=<DB_USERNAME> | gzip > "/path/to/backup/dump.sql.gz"
```
```bash title='Restore'
@@ -79,7 +79,7 @@ docker compose up -d # Start remainder of Immich apps
<TabItem value="Windows system (PowerShell)" label="Windows system (PowerShell)">
```powershell title='Backup'
[System.IO.File]::WriteAllLines("C:\absolute\path\to\backup\dump.sql", (docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgres))
[System.IO.File]::WriteAllLines("C:\absolute\path\to\backup\dump.sql", (docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=<DB_USERNAME>))
```
```powershell title='Restore'
@@ -150,12 +150,10 @@ for more info read the [release notes](https://github.com/immich-app/immich/rele
- Preview images (small thumbnails and large previews) for each asset and thumbnails for recognized faces.
- Stored in `UPLOAD_LOCATION/thumbs/<userID>`.
- **Encoded Assets:**
- Videos that have been re-encoded from the original for wider compatibility. The original is not removed.
- Stored in `UPLOAD_LOCATION/encoded-video/<userID>`.
- **Postgres**
- The Immich database containing all the information to allow the system to function properly.
**Note:** This folder will only appear to users who have made the changes mentioned in [v1.102.0](https://github.com/immich-app/immich/discussions/8930) (an optional, non-mandatory change) or who started with this version.
- Stored in `DB_DATA_LOCATION`.
@@ -201,7 +199,6 @@ When you turn off the storage template engine, it will leave the assets in `UPLO
- Temporarily located in `UPLOAD_LOCATION/upload/<userID>`.
- Transferred to `UPLOAD_LOCATION/library/<userID>` upon successful upload.
- **Postgres**
- The Immich database containing all the information to allow the system to function properly.
**Note:** This folder will only appear to users who have made the changes mentioned in [v1.102.0](https://github.com/immich-app/immich/discussions/8930) (an optional, non-mandatory change) or who started with this version.
- Stored in `DB_DATA_LOCATION`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -46,6 +46,12 @@ services:
When a new asset is uploaded it kicks off a series of jobs, which include metadata extraction, thumbnail generation, machine learning tasks, and storage template migration, if enabled. To view the status of a job navigate to the Administration -> Jobs page.
Additionally, some jobs run on a schedule, which is every night at midnight. This schedule, with the exception of [External Libraries](/docs/features/libraries) scanning, cannot be changed.
<img src={require('./img/admin-jobs.webp').default} width="60%" title="Admin jobs" />
Additionally, some jobs (such as memories generation) run on a schedule, which is every night at midnight by default. To change when they run or enable/disable a job navigate to System Settings -> [Nightly Tasks Settings](https://my.immich.app/admin/system-settings?isOpen=nightly-tasks).
<img src={require('./img/admin-nightly-tasks.webp').default} width="60%" title="Admin nightly tasks" />
:::note
Some jobs ([External Libraries](/docs/features/libraries) scanning, Database Dump) are configured in their own sections in System Settings.
:::

View File

@@ -20,7 +20,6 @@ Immich supports 3rd party authentication via [OpenID Connect][oidc] (OIDC), an i
Before enabling OAuth in Immich, a new client application needs to be configured in the 3rd-party authentication server. While the specifics of this setup vary from provider to provider, the general approach should be the same.
1. Create a new (Client) Application
1. The **Provider** type should be `OpenID Connect` or `OAuth2`
2. The **Client type** should be `Confidential`
3. The **Application** type should be `Web`
@@ -29,7 +28,6 @@ Before enabling OAuth in Immich, a new client application needs to be configured
2. Configure Redirect URIs/Origins
The **Sign-in redirect URIs** should include:
- `app.immich:///oauth-callback` - for logging in with OAuth from the [Mobile App](/docs/features/mobile-app.mdx)
- `http://DOMAIN:PORT/auth/login` - for logging in with OAuth from the Web Client
- `http://DOMAIN:PORT/user-settings` - for manually linking OAuth in the Web Client
@@ -37,21 +35,17 @@ Before enabling OAuth in Immich, a new client application needs to be configured
Redirect URIs should contain all the domains you will be using to access Immich. Some examples include:
Mobile
- `app.immich:///oauth-callback` (You **MUST** include this for iOS and Android mobile apps to work properly)
Localhost
- `http://localhost:2283/auth/login`
- `http://localhost:2283/user-settings`
Local IP
- `http://192.168.0.200:2283/auth/login`
- `http://192.168.0.200:2283/user-settings`
Hostname
- `https://immich.example.com/auth/login`
- `https://immich.example.com/user-settings`
@@ -68,8 +62,9 @@ Once you have a new OAuth client application configured, Immich can be configure
| Scope | string | openid email profile | Full list of scopes to send with the request (space delimited) |
| Signing Algorithm | string | RS256 | The algorithm used to sign the id token (examples: RS256, HS256) |
| Storage Label Claim | string | preferred_username | Claim mapping for the user's storage label**¹** |
| Role Claim | string | immich_role | Claim mapping for the user's role. (should return "user" or "admin")**¹** |
| Storage Quota Claim | string | immich_quota | Claim mapping for the user's storage**¹** |
| Default Storage Quota (GiB) | number | 0 | Default quota for user without storage quota claim (Enter 0 for unlimited quota) |
| Default Storage Quota (GiB) | number | 0 | Default quota for user without storage quota claim (empty for unlimited quota) |
| Button Text | string | Login with OAuth | Text for the OAuth button on the web |
| Auto Register | boolean | true | When true, will automatically register a user the first time they sign in |
| [Auto Launch](#auto-launch) | boolean | false | When true, will skip the login page and automatically start the OAuth login process |
@@ -111,6 +106,89 @@ Immich has a route (`/api/oauth/mobile-redirect`) that is already configured to
## Example Configuration
<details>
<summary>Authelia Example</summary>
### Authelia Example
Here's an example of OAuth configured for Authelia:
This assumes there exist an attribute `immichquota` in the user schema, which is used to set the user's storage quota in Immich.
The configuration concerning the quota is optional.
```yaml
authentication_backend:
ldap:
# The LDAP server configuration goes here.
# See: https://www.authelia.com/c/ldap
attributes:
extra:
immichquota: # The attribute name from LDAP
name: 'immich_quota'
multi_valued: false
value_type: 'integer'
identity_providers:
oidc:
## The other portions of the mandatory OpenID Connect 1.0 configuration go here.
## See: https://www.authelia.com/c/oidc
claims_policies:
immich_policy:
custom_claims:
immich_quota:
attribute: 'immich_quota'
scopes:
immich_scope:
claims:
- 'immich_quota'
clients:
- client_id: 'immich'
client_name: 'Immich'
# https://www.authelia.com/integration/openid-connect/frequently-asked-questions/#how-do-i-generate-a-client-identifier-or-client-secret
client_secret: $pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng'
public: false
require_pkce: false
redirect_uris:
- 'https://example.immich.app/auth/login'
- 'https://example.immich.app/user-settings'
- 'app.immich:///oauth-callback'
scopes:
- 'openid'
- 'profile'
- 'email'
- 'immich_scope'
claims_policy: 'immich_policy'
response_types:
- 'code'
grant_types:
- 'authorization_code'
id_token_signed_response_alg: 'RS256'
userinfo_signed_response_alg: 'RS256'
token_endpoint_auth_method: 'client_secret_post'
```
Configuration of OAuth in Immich System Settings
| Setting | Value |
| ---------------------------------- | ------------------------------------------------------------------- |
| Issuer URL | `https://example.immich.app/.well-known/openid-configuration` |
| Client ID | immich |
| Client Secret | 0v89FXkQOWO\***\*\*\*\*\***\*\*\***\*\*\*\*\***mprbvXD549HH6s1iw... |
| Token Endpoint Auth Method | client_secret_post |
| Scope | openid email profile immich_scope |
| ID Token Signed Response Algorithm | RS256 |
| Userinfo Signed Response Algorithm | RS256 |
| Storage Label Claim | uid |
| Storage Quota Claim | immich_quota |
| Default Storage Quota (GiB) | 0 (empty for unlimited quota) |
| Button Text | Sign in with Authelia (optional) |
| Auto Register | Enabled (optional) |
| Auto Launch | Enabled (optional) |
| Mobile Redirect URI Override | Disable |
| Mobile Redirect URI | |
</details>
<details>
<summary>Authentik Example</summary>
@@ -133,7 +211,7 @@ Configuration of OAuth in Immich System Settings
| Signing Algorithm | RS256 |
| Storage Label Claim | preferred_username |
| Storage Quota Claim | immich_quota |
| Default Storage Quota (GiB) | 0 (0 for unlimited quota) |
| Default Storage Quota (GiB) | 0 (empty for unlimited quota) |
| Button Text | Sign in with Authentik (optional) |
| Auto Register | Enabled (optional) |
| Auto Launch | Enabled (optional) |
@@ -164,7 +242,7 @@ Configuration of OAuth in Immich System Settings
| Signing Algorithm | RS256 |
| Storage Label Claim | preferred_username |
| Storage Quota Claim | immich_quota |
| Default Storage Quota (GiB) | 0 (0 for unlimited quota) |
| Default Storage Quota (GiB) | 0 (empty for unlimited quota) |
| Button Text | Sign in with Google (optional) |
| Auto Register | Enabled (optional) |
| Auto Launch | Enabled |

View File

@@ -2,16 +2,17 @@
The `immich-server` docker image comes preinstalled with an administrative CLI (`immich-admin`) that supports the following commands:
| Command | Description |
| ------------------------ | ------------------------------------- |
| `help` | Display help |
| `reset-admin-password` | Reset the password for the admin user |
| `disable-password-login` | Disable password login |
| `enable-password-login` | Enable password login |
| `enable-oauth-login` | Enable OAuth login |
| `disable-oauth-login` | Disable OAuth login |
| `list-users` | List Immich users |
| `version` | Print Immich version |
| Command | Description |
| ------------------------ | ------------------------------------------------------------- |
| `help` | Display help |
| `reset-admin-password` | Reset the password for the admin user |
| `disable-password-login` | Disable password login |
| `enable-password-login` | Enable password login |
| `enable-oauth-login` | Enable OAuth login |
| `disable-oauth-login` | Disable OAuth login |
| `list-users` | List Immich users |
| `version` | Print Immich version |
| `change-media-location` | Change database file paths to align with a new media location |
## How to run a command
@@ -88,3 +89,21 @@ Print Immich Version
immich-admin version
v1.129.0
```
Change media location
```
immich-admin change-media-location
? Enter the previous value of IMMICH_MEDIA_LOCATION: /data
? Enter the new value of IMMICH_MEDIA_LOCATION: /my-data
...
Previous value: /data
Current value: /my-data
Changing database paths from "/data/*" to "/my-data/*"
? Do you want to proceed? [Y/n] y
Database file paths updated successfully! 🎉
...
```

View File

@@ -7,7 +7,7 @@ sidebar_position: 3
Dev Containers provide a consistent, reproducible development environment using Docker containers. With a single click, you can get started with an Immich development environment on Mac, Linux, Windows, or in the cloud using GitHub Codespaces.
[![Open in VSCode Containers](https://img.shields.io/static/v1?label=VSCode%20DevContainer&message=Immich&color=blue)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/immich-app/immich/)
Get started fast!
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/immich-app/immich/)
@@ -71,7 +71,7 @@ cd immich
The immich dev containers read environment variables from your shell environment, not from `.env` files. This allows them to work in cloud environments without pre-configuration.
:::important Required Configuration
:::important Configuration
When running locally, and if you want to create (or use an existing) DB and/or photo storage folder, you must set the `UPLOAD_LOCATION` variable in your shell environment before launching the Dev Container. This determines where uploaded files are stored and also where the DB stores it data.
```bash
@@ -88,6 +88,10 @@ source ~/.bashrc
### Step 3: Launch the Dev Container
:::tip
Immich development makes extensive use of specialized [base images](https://github.com/immich-app/base-images) for its docker-compose based development. For this reason, you won't be able to use VSCode's **_Clone Repository in a Container Volume_** command.
:::
#### Using VS Code UI:
1. Open the cloned repository in VS Code
@@ -199,13 +203,11 @@ To use your SSH key for commit signing, see the [GitHub guide on SSH commit sign
When the Dev Container starts, it automatically:
1. **Runs post-create script** (`container-server-post-create.sh`):
- Adjusts file permissions for the `node` user
- Installs dependencies: `npm install` in all packages
- Builds TypeScript SDK: `npm run build` in `open-api/typescript-sdk`
2. **Starts development servers** via VS Code tasks:
- `Immich API Server (Nest)` - API server with hot-reloading on port 2283
- `Immich Web Server (Vite)` - Web frontend with hot-reloading on port 3000
- Both servers watch for file changes and recompile automatically
@@ -335,14 +337,12 @@ make install-all # Install all dependencies
The Dev Container is pre-configured for debugging:
1. **API Server Debugging**:
- Set breakpoints in VS Code
- Press `F5` or use "Run and Debug" panel
- Select "Attach to Server" configuration
- Debug port: 9231
2. **Worker Debugging**:
- Use "Attach to Workers" configuration
- Debug port: 9230
@@ -428,7 +428,6 @@ While the Dev Container focuses on server and web development, you can connect m
```
2. **Configure mobile app**:
- Server URL: `http://YOUR_IP:2283/api`
- Ensure firewall allows port 2283

View File

@@ -38,6 +38,19 @@ Run all server checks with `npm run check:all`
You can use `npm run __:fix` to potentially correct some issues automatically for `npm run format` and `lint`.
:::
## Mobile Checks
The following commands must be executed from within the mobile app directory of the codebase.
- [ ] `make build` (auto-generate files using build_runner)
- [ ] `make analyze` (static analysis via Dart Analyzer and DCM)
- [ ] `make format` (formatting via Dart Formatter)
- [ ] `make test` (unit tests)
:::info Auto Fix
You can use `dart fix --apply` and `dcm fix lib` to potentially correct some issues automatically for `make analyze`.
:::
## OpenAPI
The OpenAPI client libraries need to be regenerated whenever there are changes to the `immich-openapi-specs.json` file. Note that you should not modify this file directly as it is auto-generated. See [OpenAPI](/docs/developer/open-api.md) for more details.

View File

@@ -2,7 +2,7 @@
Folder view provides an additional view besides the timeline that is similar to a file explorer. It allows you to navigate through the folders and files in the library. This feature is handy for a highly curated and customized external library or a nicely configured storage template.
You can enable this feature under [`Account Settings > Features > Folder View`](https://my.immich.app/user-settings?isOpen=feature+folders)
You can enable this feature under [`Account Settings > Features > Folders`](https://my.immich.app/user-settings?isOpen=feature+folders)
## Enable folder view

View File

@@ -56,9 +56,9 @@ Internally, Immich uses the [glob](https://www.npmjs.com/package/glob) package t
### Automatic watching (EXPERIMENTAL)
This feature - currently hidden in the config file - is considered experimental and for advanced users only. If enabled, it will allow automatic watching of the filesystem which means new assets are automatically imported to Immich without needing to rescan.
This feature is considered experimental and for advanced users only. If enabled, it will allow automatic watching of the filesystem which means new assets are automatically imported to Immich without needing to rescan.
If your photos are on a network drive, automatic file watching likely won't work. In that case, you will have to rely on a periodic library refresh to pull in your changes.
If your photos are on a network drive, automatic file watching likely won't work. In that case, you will have to rely on a [periodic library refresh](#set-custom-scan-interval) to pull in your changes.
#### Troubleshooting
@@ -72,7 +72,9 @@ In rare cases, the library watcher can hang, preventing Immich from starting up.
### Nightly job
There is an automatic scan job that is scheduled to run once a day. This job also cleans up any libraries stuck in deletion. It is possible to trigger the cleanup by clicking "Scan all libraries" in the library management page.
There is an automatic scan job that is scheduled to run once a day. Its schedule is configurable, see [Set Custom Scan Interval](#set-custom-scan-interval).
This job also cleans up any libraries stuck in deletion. It is possible to trigger the cleanup by clicking "Scan all libraries" in the library management page.
## Usage
@@ -91,7 +93,7 @@ The `immich-server` container will need access to the gallery. Modify your docke
```diff title="docker-compose.yml"
immich-server:
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- ${UPLOAD_LOCATION}:/data
+ - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro
+ - /home/user/old-pics:/mnt/media/old-pics:ro
+ - /mnt/media/videos:/mnt/media/videos:ro
@@ -112,7 +114,7 @@ _Remember to run `docker compose up -d` to register the changes. Make sure you c
These actions must be performed by the Immich administrator.
- Click on your avatar on the upper right corner
- Click on your avatar in the upper right corner
- Click on Administration -> External Libraries
- Click on Create an external library…
- Select which user owns the library, this can not be changed later
@@ -159,9 +161,7 @@ Within seconds, the assets from the old-pics and videos folders should show up i
Folder view provides an additional view besides the timeline that is similar to a file explorer. It allows you to navigate through the folders and files in the library. This feature is handy for a highly curated and customized external library or a nicely configured storage template.
You can enable this feature under [`Account Settings > Features > Folder View`](https://my.immich.app/user-settings?isOpen=feature+folders)
The UI is currently only available for the web; mobile will come in a subsequent release.
You can enable this feature under [`Account Settings > Features > Folders`](https://my.immich.app/user-settings?isOpen=feature+folders)
<img src={require('./img/folder-view-1.webp').default} width="100%" title='Folder-view' />
@@ -171,7 +171,7 @@ The UI is currently only available for the web; mobile will come in a subsequent
Only an admin can do this.
:::
You can define a custom interval for the trigger external library rescan under Administration -> Settings -> Library.
You can define a custom interval for the trigger external library rescan under Administration -> Settings -> External Library.
You can set the scanning interval using the preset or cron format. For more information you can refer to [Crontab Guru](https://crontab.guru/).
<img src={require('./img/library-custom-scan-interval.webp').default} width="75%" title='Set custom scan interval for external library' />

View File

@@ -88,9 +88,9 @@ It will only reflect files you add.
:::
If the same asset is in more than one album it will only sync to the first album it's in, after that it won't sync again even if the user clicks sync albums manually.
To overcome this limitation, the files must be removed from the blacklist by
To overcome this limitation, the files must be removed from the ignore list by
App settings -> Advanced -> Duplicate Assets -> Clear
:::info
Cleaning duplicate assets from the list will cause all the previously uploaded duplicate files to be re-uploaded, the files will not actually be uploaded and will be rejected on the server side (due to duplication) but will be synchronized to the album and at the end will be added to the black list again at the end of the synchronization.
Cleaning duplicate assets from the list will cause all the previously uploaded duplicate files to be re-uploaded, the files will not actually be uploaded and will be rejected on the server side (due to duplication) but will be synchronized to the album and at the end will be added to the ignore list again at the end of the synchronization.
:::

View File

@@ -16,7 +16,7 @@ For the full list, refer to the [Immich source code](https://github.com/immich-a
| `HEIC` | `.heic` | :white_check_mark: | |
| `HEIF` | `.heif` | :white_check_mark: | |
| `JPEG 2000` | `.jp2` | :white_check_mark: | |
| `JPEG` | `.webp` `.jpg` `.jpe` `.insp` | :white_check_mark: | |
| `JPEG` | `.jpeg` `.jpg` `.jpe` `.insp` | :white_check_mark: | |
| `JPEG XL` | `.jxl` | :white_check_mark: | |
| `PNG` | `.png` | :white_check_mark: | |
| `PSD` | `.psd` | :white_check_mark: | Adobe Photoshop |

View File

@@ -27,11 +27,11 @@ After defining the locations of these files, we will edit the `docker-compose.ym
services:
immich-server:
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
+ - ${THUMB_LOCATION}:/usr/src/app/upload/thumbs
+ - ${ENCODED_VIDEO_LOCATION}:/usr/src/app/upload/encoded-video
+ - ${PROFILE_LOCATION}:/usr/src/app/upload/profile
+ - ${BACKUP_LOCATION}:/usr/src/app/upload/backups
- ${UPLOAD_LOCATION}:/data
+ - ${THUMB_LOCATION}:/data/thumbs
+ - ${ENCODED_VIDEO_LOCATION}:/data/encoded-video
+ - ${PROFILE_LOCATION}:/data/profile
+ - ${BACKUP_LOCATION}:/data/backups
- /etc/localtime:/etc/localtime:ro
```
@@ -44,7 +44,7 @@ docker compose up -d
:::note
Because of the underlying properties of docker bind mounts, it is not recommended to mount the `upload/` and `library/` folders as separate bind mounts if they are on the same device.
For this reason, we mount the HDD or the network storage (NAS) to `/usr/src/app/upload` and then mount the folders we want to access under that folder.
For this reason, we mount the HDD or the network storage (NAS) to `/data` and then mount the folders we want to access under that folder.
The `thumbs/` folder contains both the small thumbnails displayed in the timeline and the larger previews shown when clicking into an image. These cannot be separated.

View File

@@ -12,118 +12,148 @@ Run `docker exec -it immich_postgres psql --dbname=<DB_DATABASE_NAME> --username
## Assets
### Name
:::note
The `"originalFileName"` column is the name of the file at time of upload, including the extension.
:::
```sql title="Find by original filename"
SELECT * FROM "assets" WHERE "originalFileName" = 'PXL_20230903_232542848.jpg';
SELECT * FROM "assets" WHERE "originalFileName" LIKE 'PXL_%'; -- all files starting with PXL_
SELECT * FROM "assets" WHERE "originalFileName" LIKE '%_2023_%'; -- all files with _2023_ in the middle
SELECT * FROM "asset" WHERE "originalFileName" = 'PXL_20230903_232542848.jpg';
SELECT * FROM "asset" WHERE "originalFileName" LIKE 'PXL_%'; -- all files starting with PXL_
SELECT * FROM "asset" WHERE "originalFileName" LIKE '%_2023_%'; -- all files with _2023_ in the middle
```
```sql title="Find by path"
SELECT * FROM "assets" WHERE "originalPath" = 'upload/library/admin/2023/2023-09-03/PXL_2023.jpg';
SELECT * FROM "assets" WHERE "originalPath" LIKE 'upload/library/admin/2023/%';
SELECT * FROM "asset" WHERE "originalPath" = 'upload/library/admin/2023/2023-09-03/PXL_2023.jpg';
SELECT * FROM "asset" WHERE "originalPath" LIKE 'upload/library/admin/2023/%';
```
### ID
```sql title="Find by ID"
SELECT * FROM "assets" WHERE "id" = '9f94e60f-65b6-47b7-ae44-a4df7b57f0e9';
SELECT * FROM "asset" WHERE "id" = '9f94e60f-65b6-47b7-ae44-a4df7b57f0e9';
```
```sql title="Find by partial ID"
SELECT * FROM "assets" WHERE "id"::text LIKE '%ab431d3a%';
SELECT * FROM "asset" WHERE "id"::text LIKE '%ab431d3a%';
```
### Checksum
:::note
You can calculate the checksum for a particular file by using the command `sha1sum <filename>`.
:::
```sql title="Find by checksum (SHA-1)"
SELECT encode("checksum", 'hex') FROM "assets";
SELECT * FROM "assets" WHERE "checksum" = decode('69de19c87658c4c15d9cacb9967b8e033bf74dd1', 'hex');
SELECT * FROM "assets" WHERE "checksum" = '\x69de19c87658c4c15d9cacb9967b8e033bf74dd1'; -- alternate notation
SELECT encode("checksum", 'hex') FROM "asset";
SELECT * FROM "asset" WHERE "checksum" = decode('69de19c87658c4c15d9cacb9967b8e033bf74dd1', 'hex');
SELECT * FROM "asset" WHERE "checksum" = '\x69de19c87658c4c15d9cacb9967b8e033bf74dd1'; -- alternate notation
```
```sql title="Find duplicate assets with identical checksum (SHA-1) (excluding trashed files)"
SELECT T1."checksum", array_agg(T2."id") ids FROM "assets" T1
INNER JOIN "assets" T2 ON T1."checksum" = T2."checksum" AND T1."id" != T2."id" AND T2."deletedAt" IS NULL
SELECT T1."checksum", array_agg(T2."id") ids FROM "asset" T1
INNER JOIN "asset" T2 ON T1."checksum" = T2."checksum" AND T1."id" != T2."id" AND T2."deletedAt" IS NULL
WHERE T1."deletedAt" IS NULL GROUP BY T1."checksum";
```
### Metadata
```sql title="Live photos"
SELECT * FROM "assets" WHERE "livePhotoVideoId" IS NOT NULL;
SELECT * FROM "asset" WHERE "livePhotoVideoId" IS NOT NULL;
```
```sql title="By description"
SELECT "assets".*, "exif"."description" FROM "exif"
JOIN "assets" ON "assets"."id" = "exif"."assetId"
WHERE TRIM("exif"."description") <> ''; -- all files with a description
SELECT "assets".*, "exif"."description" FROM "exif"
JOIN "assets" ON "assets"."id" = "exif"."assetId"
WHERE "exif"."description" ILIKE '%string to match%'; -- search by string
SELECT "asset".*, "asset_exif"."description" FROM "asset_exif"
JOIN "asset" ON "asset"."id" = "asset_exif"."assetId"
WHERE TRIM("asset_exif"."description") <> ''; -- all files with a description
SELECT "asset".*, "asset_exif"."description" FROM "asset_exif"
JOIN "asset" ON "asset"."id" = "asset_exif"."assetId"
WHERE "asset_exif"."description" ILIKE '%string to match%'; -- search by string
```
```sql title="Without metadata"
SELECT "assets".* FROM "exif"
LEFT JOIN "assets" ON "assets"."id" = "exif"."assetId"
WHERE "exif"."assetId" IS NULL;
SELECT "asset".* FROM "asset_exif"
LEFT JOIN "asset" ON "asset"."id" = "asset_exif"."assetId"
WHERE "asset_exif"."assetId" IS NULL;
```
```sql title="size < 100,000 bytes, smallest to largest"
SELECT * FROM "assets"
JOIN "exif" ON "assets"."id" = "exif"."assetId"
WHERE "exif"."fileSizeInByte" < 100000
ORDER BY "exif"."fileSizeInByte" ASC;
SELECT * FROM "asset"
JOIN "asset_exif" ON "asset"."id" = "asset_exif"."assetId"
WHERE "asset_exif"."fileSizeInByte" < 100000
ORDER BY "asset_exif"."fileSizeInByte" ASC;
```
```sql title="Without thumbnails"
SELECT * FROM "assets" WHERE "assets"."previewPath" IS NULL OR "assets"."thumbnailPath" IS NULL;
```
### Type
```sql title="By type"
SELECT * FROM "assets" WHERE "assets"."type" = 'VIDEO';
SELECT * FROM "assets" WHERE "assets"."type" = 'IMAGE';
SELECT * FROM "asset" WHERE "asset"."type" = 'VIDEO';
SELECT * FROM "asset" WHERE "asset"."type" = 'IMAGE';
```
```sql title="Count by type"
SELECT "assets"."type", COUNT(*) FROM "assets" GROUP BY "assets"."type";
SELECT "asset"."type", COUNT(*) FROM "asset" GROUP BY "asset"."type";
```
```sql title="Count by type (per user)"
SELECT "users"."email", "assets"."type", COUNT(*) FROM "assets"
JOIN "users" ON "assets"."ownerId" = "users"."id"
GROUP BY "assets"."type", "users"."email" ORDER BY "users"."email";
SELECT "user"."email", "asset"."type", COUNT(*) FROM "asset"
JOIN "user" ON "asset"."ownerId" = "user"."id"
GROUP BY "asset"."type", "user"."email" ORDER BY "user"."email";
```
```sql title="Failed file movements"
SELECT * FROM "move_history";
## Tags
```sql title="Count by tag"
SELECT "t"."value" AS "tag_name", COUNT(*) AS "number_assets" FROM "tag" "t"
JOIN "tag_asset" "ta" ON "t"."id" = "ta"."tagsId" JOIN "asset" "a" ON "ta"."assetsId" = "a"."id"
WHERE "a"."visibility" != 'hidden'
GROUP BY "t"."value" ORDER BY "number_assets" DESC;
```
```sql title="Count by tag (per user)"
SELECT "t"."value" AS "tag_name", "u"."email" as "user_email", COUNT(*) AS "number_assets" FROM "tag" "t"
JOIN "tag_asset" "ta" ON "t"."id" = "ta"."tagsId" JOIN "asset" "a" ON "ta"."assetsId" = "a"."id" JOIN "user" "u" ON "a"."ownerId" = "u"."id"
WHERE "a"."visibility" != 'hidden'
GROUP BY "t"."value", "u"."email" ORDER BY "number_assets" DESC;
```
## Users
```sql title="List all users"
SELECT * FROM "users";
SELECT * FROM "user";
```
```sql title="Get owner info from asset ID"
SELECT "users".* FROM "users" JOIN "assets" ON "users"."id" = "assets"."ownerId" WHERE "assets"."id" = 'fa310b01-2f26-4b7a-9042-d578226e021f';
SELECT "user".* FROM "user" JOIN "asset" ON "user"."id" = "asset"."ownerId" WHERE "asset"."id" = 'fa310b01-2f26-4b7a-9042-d578226e021f';
```
## System Config
```sql title="Custom settings"
SELECT "key", "value" FROM "system_metadata" WHERE "key" = 'system-config';
```
(Only used when not using the [config file](/docs/install/config-file))
## Persons
```sql title="Delete person and unset it for the faces it was associated with"
DELETE FROM "person" WHERE "name" = 'PersonNameHere';
```
## System
### Config
```sql title="Custom settings"
SELECT "key", "value" FROM "system_metadata" WHERE "key" = 'system-config';
```
(Only used when not using the [config file](/docs/install/config-file))
### File properties
```sql title="Without thumbnails"
SELECT * FROM "asset" WHERE "asset"."previewPath" IS NULL OR "asset"."thumbnailPath" IS NULL;
```
```sql title="Failed file movements"
SELECT * FROM "move_history";
```
## Postgres internal
```sql title="Change DB_PASSWORD"

View File

@@ -12,7 +12,7 @@ If you want Immich to be able to delete the images in the external library or ad
```diff
immich-server:
volumes:
- ${UPLOAD_LOCATION}:/usr/src/app/upload
- ${UPLOAD_LOCATION}:/data
+ - /home/user/photos1:/home/user/photos1:ro
+ - /mnt/photos2:/mnt/photos2:ro # you can delete this line if you only have one mount point, or you can add more lines if you have more than two
```
@@ -41,7 +41,7 @@ In the Immich web UI:
- Click Add path
<img src={require('./img/add-path-button.webp').default} width="50%" title="Add Path button" />
- Enter **/usr/src/app/external** as the path and click Add
- Enter **/home/user/photos1** as the path and click Add
<img src={require('./img/add-path-field.webp').default} width="50%" title="Add Path field" />
- Save the new path

View File

@@ -52,9 +52,9 @@ REMOTE_BACKUP_PATH="/path/to/remote/backup/directory"
### Local
# Backup Immich database
docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgres > "$UPLOAD_LOCATION"/database-backup/immich-database.sql
docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=<DB_USERNAME> > "$UPLOAD_LOCATION"/database-backup/immich-database.sql
# For deduplicating backup programs such as Borg or Restic, compressing the content can increase backup size by making it harder to deduplicate. If you are using a different program or still prefer to compress, you can use the following command instead:
# docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=postgres | /usr/bin/gzip --rsyncable > "$UPLOAD_LOCATION"/database-backup/immich-database.sql.gz
# docker exec -t immich_postgres pg_dumpall --clean --if-exists --username=<DB_USERNAME> | /usr/bin/gzip --rsyncable > "$UPLOAD_LOCATION"/database-backup/immich-database.sql.gz
### Append to local Borg repository
borg create "$BACKUP_PATH/immich-borg::{now}" "$UPLOAD_LOCATION" --exclude "$UPLOAD_LOCATION"/thumbs/ --exclude "$UPLOAD_LOCATION"/encoded-video/

View File

@@ -34,7 +34,7 @@ These environment variables are used by the `docker-compose.yml` file and do **N
| `TZ` | Timezone | <sup>\*1</sup> | server | microservices |
| `IMMICH_ENV` | Environment (production, development) | `production` | server, machine learning | api, microservices |
| `IMMICH_LOG_LEVEL` | Log level (verbose, debug, log, warn, error) | `log` | server, machine learning | api, microservices |
| `IMMICH_MEDIA_LOCATION` | Media location inside the container ⚠️**You probably shouldn't set this**<sup>\*2</sup>⚠️ | `./upload`<sup>\*3</sup> | server | api, microservices |
| `IMMICH_MEDIA_LOCATION` | Media location inside the container ⚠️**You probably shouldn't set this**<sup>\*2</sup>⚠️ | `/data` | server | api, microservices |
| `IMMICH_CONFIG_FILE` | Path to config file | | server | api, microservices |
| `NO_COLOR` | Set to `true` to disable color-coded log output | `false` | server, machine learning | |
| `CPU_CORES` | Number of cores available to the Immich server | auto-detected CPU core count | server | |
@@ -49,9 +49,6 @@ These environment variables are used by the `docker-compose.yml` file and do **N
\*2: This path is where the Immich code looks for the files, which is internal to the docker container. Setting it to a path on your host will certainly break things, you should use the `UPLOAD_LOCATION` variable instead.
\*3: With the default `WORKDIR` of `/usr/src/app`, this path will resolve to `/usr/src/app/upload`.
It only needs to be set if the Immich deployment method is changing.
## Workers
| Variable | Description | Default | Containers |
@@ -72,22 +69,25 @@ Information on the current workers can be found [here](/docs/administration/jobs
## Database
| Variable | Description | Default | Containers |
| :---------------------------------- | :--------------------------------------------------------------------------- | :--------: | :----------------------------- |
| `DB_URL` | Database URL | | server |
| `DB_HOSTNAME` | Database host | `database` | server |
| `DB_PORT` | Database port | `5432` | server |
| `DB_USERNAME` | Database user | `postgres` | server, database<sup>\*1</sup> |
| `DB_PASSWORD` | Database password | `postgres` | server, database<sup>\*1</sup> |
| `DB_DATABASE_NAME` | Database name | `immich` | server, database<sup>\*1</sup> |
| `DB_SSL_MODE` | Database SSL mode | | server |
| `DB_VECTOR_EXTENSION`<sup>\*2</sup> | Database vector extension (one of [`vectorchord`, `pgvector`, `pgvecto.rs`]) | | server |
| `DB_SKIP_MIGRATIONS` | Whether to skip running migrations on startup (one of [`true`, `false`]) | `false` | server |
| Variable | Description | Default | Containers |
| :---------------------------------- | :------------------------------------------------------------------------------------- | :--------: | :----------------------------- |
| `DB_URL` | Database URL | | server |
| `DB_HOSTNAME` | Database host | `database` | server |
| `DB_PORT` | Database port | `5432` | server |
| `DB_USERNAME` | Database user | `postgres` | server, database<sup>\*1</sup> |
| `DB_PASSWORD` | Database password | `postgres` | server, database<sup>\*1</sup> |
| `DB_DATABASE_NAME` | Database name | `immich` | server, database<sup>\*1</sup> |
| `DB_SSL_MODE` | Database SSL mode | | server |
| `DB_VECTOR_EXTENSION`<sup>\*2</sup> | Database vector extension (one of [`vectorchord`, `pgvector`, `pgvecto.rs`]) | | server |
| `DB_SKIP_MIGRATIONS` | Whether to skip running migrations on startup (one of [`true`, `false`]) | `false` | server |
| `DB_STORAGE_TYPE` | Optimize concurrent IO on SSDs or sequential IO on HDDs ([`SSD`, `HDD`])<sup>\*3</sup> | `SSD` | server |
\*1: The values of `DB_USERNAME`, `DB_PASSWORD`, and `DB_DATABASE_NAME` are passed to the Postgres container as the variables `POSTGRES_USER`, `POSTGRES_PASSWORD`, and `POSTGRES_DB` in `docker-compose.yml`.
\*2: If not provided, the appropriate extension to use is auto-detected at startup by introspecting the database. When multiple extensions are installed, the order of preference is VectorChord, pgvecto.rs, pgvector.
\*3: Uses either [`postgresql.ssd.conf`](https://github.com/immich-app/base-images/blob/main/postgres/postgresql.ssd.conf) or [`postgresql.hdd.conf`](https://github.com/immich-app/base-images/blob/main/postgres/postgresql.hdd.conf) which mainly controls the Postgres `effective_io_concurrency` setting to allow for concurrenct IO on SSDs and sequential IO on HDDs.
:::info
All `DB_` variables must be provided to all Immich workers, including `api` and `microservices`.
@@ -199,12 +199,11 @@ Additional machine learning parameters can be tuned from the admin UI.
| `IMMICH_TELEMETRY_INCLUDE` | Collect these telemetries. List of `host`, `api`, `io`, `repo`, `job`. Note: You can also specify `all` to enable all | | server | api, microservices |
| `IMMICH_TELEMETRY_EXCLUDE` | Do not collect these telemetries. List of `host`, `api`, `io`, `repo`, `job` | | server | api, microservices |
## Docker Secrets
## Secrets
The following variables support the use of [Docker secrets][docker-secrets] for additional security.
The following variables support reading from files, either via [Systemd Credentials][systemd-creds] or [Docker secrets][docker-secrets] for additional security.
To use any of these, replace the regular environment variable with the equivalent `_FILE` environment variable. The value of
the `_FILE` variable should be set to the path of a file containing the variable value.
To use any of these, either set `CREDENTIALS_DIRECTORY` to a directory that contains files whose name is the regular variable” name, and whose content is the secret. If using Docker Secrets, setting `CREDENTIALS_DIRECTORY=/run/secrets` will cause all secrets present to be used. Alternatively, replace the regular variable with the equivalent `_FILE` environment variable as below. The value of the `_FILE` variable should be set to the path of a file containing the variable value.
| Regular Variable | Equivalent Docker Secrets '\_FILE' Variable |
| :----------------- | :------------------------------------------ |
@@ -226,3 +225,4 @@ to use a Docker secret for the password in the Redis container.
[docker-secrets-docs]: https://github.com/docker-library/docs/tree/master/postgres#docker-secrets
[docker-secrets]: https://docs.docker.com/engine/swarm/secrets/
[ioredis]: https://ioredis.readthedocs.io/en/latest/README/#connect-to-redis
[systemd-creds]: https://systemd.io/CREDENTIALS/

View File

@@ -75,7 +75,6 @@ alt="Select Plugins > Compose.Manager > Add New Stack > Label it Immich"
5. Click "**Save Changes**", you will be prompted to edit stack UI labels, just leave this blank and click "**Ok**"
6. Select the cog ⚙️ next to Immich, click "**Edit Stack**", then click "**Env File**"
7. Paste the entire contents of the [Immich example.env](https://github.com/immich-app/immich/releases/latest/download/example.env) file into the Unraid editor, then **before saving** edit the following:
- `UPLOAD_LOCATION`: Create a folder in your Images Unraid share and place the **absolute** location here > For example my _"images"_ share has a folder within it called _"immich"_. If I browse to this directory in the terminal and type `pwd` the output is `/mnt/user/images/immich`. This is the exact value I need to enter as my `UPLOAD_LOCATION`
- `DB_DATA_LOCATION`: Change this to use an Unraid share (preferably a cache pool, e.g. `/mnt/user/appdata/postgresql/data`). This uses the `appdata` share. Do also create the `postgresql` folder, by running `mkdir /mnt/user/{share_location}/postgresql/data`. If left at default it will try to use Unraid's `/boot/config/plugins/compose.manager/projects/[stack_name]/postgres` folder which it doesn't have permissions to, resulting in this container continuously restarting.

1533
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,8 +16,9 @@
"write-heading-ids": "docusaurus write-heading-ids"
},
"dependencies": {
"@docusaurus/core": "~3.7.0",
"@docusaurus/preset-classic": "~3.7.0",
"@docusaurus/core": "~3.8.0",
"@docusaurus/preset-classic": "~3.8.0",
"@docusaurus/theme-common": "~3.8.0",
"@mdi/js": "^7.3.67",
"@mdi/react": "^1.6.1",
"@mdx-js/react": "^3.0.0",
@@ -26,6 +27,7 @@
"clsx": "^2.0.0",
"docusaurus-lunr-search": "^3.3.2",
"docusaurus-preset-openapi": "^0.7.5",
"lunr": "^2.3.9",
"postcss": "^8.4.25",
"prism-react-renderer": "^2.3.1",
"raw-loader": "^4.0.2",
@@ -35,7 +37,7 @@
"url": "^0.11.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "~3.7.0",
"@docusaurus/module-type-aliases": "~3.8.0",
"@docusaurus/tsconfig": "^3.7.0",
"@docusaurus/types": "^3.7.0",
"prettier": "^3.2.4",
@@ -57,6 +59,6 @@
"node": ">=20"
},
"volta": {
"node": "22.16.0"
"node": "22.18.0"
}
}

View File

@@ -58,6 +58,12 @@ const guides: CommunityGuidesProps[] = [
description: 'Access Immich with an end-to-end encrypted connection.',
url: 'https://meshnet.nordvpn.com/how-to/remote-files-media-access/immich-remote-access',
},
{
title: 'Trust Self Signed Certificates with Immich - OAuth Setup',
description:
'Set up Certificate Authority trust with Immich, and your private OAuth2/OpenID service, while using a private CA for HTTPS commication.',
url: 'https://github.com/immich-app/immich/discussions/18614',
},
];
function CommunityGuide({ title, description, url }: CommunityGuidesProps): JSX.Element {

View File

@@ -100,6 +100,11 @@ const projects: CommunityProjectProps[] = [
description: 'Automatically optimize files uploaded to Immich in order to save storage space',
url: 'https://github.com/miguelangel-nubla/immich-upload-optimizer',
},
{
title: 'Immich Machine Learning Load Balancer',
description: 'Speed up your machine learning by load balancing your requests to multiple computers',
url: 'https://github.com/apetersson/immich_ml_balancer',
},
];
function CommunityProject({ title, description, url }: CommunityProjectProps): JSX.Element {

View File

@@ -2,4 +2,23 @@
## TypeORM Upgrade
The upgrade to Immich `v2.x.x` has a required upgrade path to `v1.132.0+`. This means it is required to start up the application at least once on version `1.132.0` (or later). Doing so will complete database schema upgrades that are required for `v2.0.0`. After Immich has successfully booted on this version, shut the system down and try the `v2.x.x` upgrade again.
In order to update to Immich to `v1.137.0` (or above), the application must be started at least once on a version in the range between `1.132.0` and `1.136.0`. Doing so will complete database schema upgrades that are required for `v1.137.0` (and above). After Immich has successfully updated to a version in this range, you can now attempt to update to v1.137.0 (or above). We recommend users upgrade to `1.132.0` since it does not have any other breaking changes.
## Inconsistent Media Location
:::caution
This error is related to the location of media files _inside the container_. Never move files on the host system when you run into this error message.
:::
Immich automatically tries to detect where your Immich data is located. On start up, it compares the detected media location with the file paths in the database and throws an Inconsistent Media Location error when they do not match.
To fix this issue, verify that the `IMMICH_MEDIA_LOCATION` environment variable and `UPLOAD_LOCATION` volume mount are in sync with the database paths.
If you would like to migrate from one media location to another, simply successfully start Immich on `v1.136.0` or later, then do the following steps:
1. Stop Immich
2. Update `IMMICH_MEDIA_LOCATION` to the new location
3. Update the right-hand side of the `UPLOAD_LOCATION` volume mount to the new location
4. Start up Immich
After version `1.136.0`, Immich can detect when a media location has moved and will automatically update the database paths to keep them in sync.

View File

@@ -85,6 +85,7 @@ import React from 'react';
import { Item, Timeline } from '../components/timeline';
const releases = {
'v1.135.0': new Date(2025, 5, 18),
'v1.133.0': new Date(2025, 4, 21),
'v1.130.0': new Date(2025, 2, 25),
'v1.127.0': new Date(2025, 1, 26),
@@ -196,14 +197,6 @@ const roadmap: Item[] = [
description: 'Automate tasks with workflows',
getDateLabel: () => 'Planned for 2025',
},
{
done: false,
icon: mdiTableKey,
iconColor: 'gray',
title: 'Fine grained access controls',
description: 'Granular access controls for users and api keys',
getDateLabel: () => 'Planned for 2025',
},
{
done: false,
icon: mdiImageEdit,
@@ -239,12 +232,26 @@ const roadmap: Item[] = [
];
const milestones: Item[] = [
{
icon: mdiStar,
iconColor: 'gold',
title: '70,000 Stars',
description: 'Reached 70K Stars on GitHub!',
getDateLabel: withLanguage(new Date(2025, 6, 9)),
},
withRelease({
icon: mdiTableKey,
iconColor: 'gray',
title: 'Fine grained access controls',
description: 'Granular access controls for api keys',
release: 'v1.135.0',
}),
withRelease({
icon: mdiCast,
iconColor: 'aqua',
title: 'Google Cast (web)',
title: 'Google Cast (web and mobile)',
description: 'Cast assets to Google Cast/Chromecast compatible devices',
release: 'v1.133.0',
release: 'v1.135.0',
}),
withRelease({
icon: mdiLockOutline,

View File

@@ -1,4 +1,5 @@
/docs /docs/overview/introduction 307
/docs /docs/overview/welcome 307
/docs/ /docs/overview/welcome 307
/docs/mobile-app-beta-program /docs/features/mobile-app 307
/docs/contribution-guidelines /docs/overview/support-the-project#contributing 307
/docs/install /docs/install/docker-compose 307
@@ -30,4 +31,4 @@
/docs/guides/api-album-sync /docs/community-projects 307
/docs/guides/remove-offline-files /docs/community-projects 307
/milestones /roadmap 307
/docs/overview/introduction /docs/overview/welcome 307
/docs/overview/introduction /docs/overview/welcome 307

View File

@@ -1,4 +1,24 @@
[
{
"label": "v1.137.3",
"url": "https://v1.137.3.archive.immich.app"
},
{
"label": "v1.137.2",
"url": "https://v1.137.2.archive.immich.app"
},
{
"label": "v1.137.1",
"url": "https://v1.137.1.archive.immich.app"
},
{
"label": "v1.137.0",
"url": "https://v1.137.0.archive.immich.app"
},
{
"label": "v1.136.0",
"url": "https://v1.136.0.archive.immich.app"
},
{
"label": "v1.135.3",
"url": "https://v1.135.3.archive.immich.app"

View File

@@ -1 +1 @@
22.16.0
22.18.0

View File

@@ -3,7 +3,6 @@ name: immich-e2e
services:
immich-server:
container_name: immich-e2e-server
command: ['./start.sh']
image: immich-server:latest
build:
context: ../
@@ -36,10 +35,10 @@ services:
- 2285:2285
redis:
image: redis:6.2-alpine@sha256:3211c33a618c457e5d241922c975dbc4f446d0bdb2dc75694f5573ef8e2d01fa
image: redis:6.2-alpine@sha256:7fe72c486b910f6b1a9769c937dad5d63648ddee82e056f47417542dd40825bb
database:
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:3aef84a0a4fabbda17ef115c3019ba0c914ec73e9f6e59203674322d858b8eea
image: ghcr.io/immich-app/postgres:14-vectorchord0.3.0@sha256:0e763a2383d56f90364fcd72767ac41400cd30d2627f407f7e7960c9f1923c21
command: -c fsync=off -c shared_preload_libraries=vchord.so -c config_file=/var/lib/postgresql/data/postgresql.conf
environment:
POSTGRES_PASSWORD: postgres

7419
e2e/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "immich-e2e",
"version": "1.135.3",
"version": "1.137.3",
"description": "",
"main": "index.js",
"type": "module",
@@ -21,20 +21,21 @@
"devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.8.0",
"@immich/cli": "workspace:^",
"@immich/sdk": "workspace:^",
"@immich/cli": "file:../cli",
"@immich/sdk": "file:../open-api/typescript-sdk",
"@playwright/test": "^1.44.1",
"@socket.io/component-emitter": "^3.1.2",
"@types/luxon": "^3.4.2",
"@types/node": "^22.15.32",
"@types/node": "^22.17.0",
"@types/oidc-provider": "^9.0.0",
"@types/pg": "^8.15.1",
"@types/pngjs": "^6.0.4",
"@types/supertest": "^6.0.2",
"@vitest/coverage-v8": "^3.0.0",
"eslint": "^9.14.0",
"eslint-config-prettier": "^10.0.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-unicorn": "^59.0.0",
"eslint-plugin-unicorn": "^60.0.0",
"exiftool-vendored": "^28.3.1",
"globals": "^16.0.0",
"jose": "^5.6.3",
@@ -44,6 +45,7 @@
"pngjs": "^7.0.0",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^4.0.0",
"sharp": "^0.34.0",
"socket.io-client": "^4.7.4",
"supertest": "^7.0.0",
"typescript": "^5.3.3",
@@ -52,6 +54,6 @@
"vitest": "^3.0.0"
},
"volta": {
"node": "22.16.0"
"node": "22.18.0"
}
}

View File

@@ -7,6 +7,7 @@ import {
ReactionType,
createActivity as create,
createAlbum,
removeAssetFromAlbum,
} from '@immich/sdk';
import { createUserDto, uuidDto } from 'src/fixtures';
import { errorDto } from 'src/responses';
@@ -342,5 +343,36 @@ describe('/activities', () => {
expect(status).toBe(204);
});
it('should return empty list when asset is removed', async () => {
const album3 = await createAlbum(
{
createAlbumDto: {
albumName: 'Album 3',
assetIds: [asset.id],
},
},
{ headers: asBearerAuth(admin.accessToken) },
);
await createActivity({ albumId: album3.id, assetId: asset.id, type: ReactionType.Like });
await removeAssetFromAlbum(
{
id: album3.id,
bulkIdsDto: {
ids: [asset.id],
},
},
{ headers: asBearerAuth(admin.accessToken) },
);
const { status, body } = await request(app)
.get('/activities')
.query({ albumId: album.id })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toEqual(200);
expect(body).toEqual([]);
});
});
});

View File

@@ -470,7 +470,7 @@ describe('/albums', () => {
.send({ ids: [asset.id] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest('Not found or no album.addAsset access'));
expect(body).toEqual(errorDto.badRequest('Not found or no albumAsset.create access'));
});
it('should add duplicate assets only once', async () => {
@@ -599,7 +599,7 @@ describe('/albums', () => {
.send({ ids: [user1Asset1.id] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest('Not found or no album.removeAsset access'));
expect(body).toEqual(errorDto.badRequest('Not found or no albumAsset.delete access'));
});
it('should remove duplicate assets only once', async () => {

View File

@@ -20,7 +20,7 @@ describe('/api-keys', () => {
});
beforeEach(async () => {
await utils.resetDatabase(['api_keys']);
await utils.resetDatabase(['api_key']);
});
describe('POST /api-keys', () => {

View File

@@ -15,6 +15,7 @@ import { DateTime } from 'luxon';
import { randomBytes } from 'node:crypto';
import { readFile, writeFile } from 'node:fs/promises';
import { basename, join } from 'node:path';
import sharp from 'sharp';
import { Socket } from 'socket.io-client';
import { createUserDto, uuidDto } from 'src/fixtures';
import { makeRandomImage } from 'src/generators';
@@ -40,6 +41,40 @@ const today = DateTime.fromObject({
}) as DateTime<true>;
const yesterday = today.minus({ days: 1 });
const createTestImageWithExif = async (filename: string, exifData: Record<string, any>) => {
// Generate unique color to ensure different checksums for each image
const r = Math.floor(Math.random() * 256);
const g = Math.floor(Math.random() * 256);
const b = Math.floor(Math.random() * 256);
// Create a 100x100 solid color JPEG using Sharp
const imageBytes = await sharp({
create: {
width: 100,
height: 100,
channels: 3,
background: { r, g, b },
},
})
.jpeg({ quality: 90 })
.toBuffer();
// Add random suffix to filename to avoid collisions
const uniqueFilename = filename.replace('.jpg', `-${randomBytes(4).toString('hex')}.jpg`);
const filepath = join(tempDir, uniqueFilename);
await writeFile(filepath, imageBytes);
// Filter out undefined values before writing EXIF
const cleanExifData = Object.fromEntries(Object.entries(exifData).filter(([, value]) => value !== undefined));
await exiftool.write(filepath, cleanExifData);
// Re-read the image bytes after EXIF has been written
const finalImageBytes = await readFile(filepath);
return { filepath, imageBytes: finalImageBytes, filename: uniqueFilename };
};
describe('/asset', () => {
let admin: LoginResponseDto;
let websocket: Socket;
@@ -1190,6 +1225,411 @@ describe('/asset', () => {
});
});
describe('EXIF metadata extraction', () => {
describe('Additional date tag extraction', () => {
describe('Date-time vs time-only tag handling', () => {
it('should fall back to file timestamps when only time-only tags are available', async () => {
const { imageBytes, filename } = await createTestImageWithExif('time-only-fallback.jpg', {
TimeCreated: '2023:11:15 14:30:00', // Time-only tag, should not be used for dateTimeOriginal
// Exclude all date-time tags to force fallback to file timestamps
SubSecDateTimeOriginal: undefined,
DateTimeOriginal: undefined,
SubSecCreateDate: undefined,
SubSecMediaCreateDate: undefined,
CreateDate: undefined,
MediaCreateDate: undefined,
CreationDate: undefined,
DateTimeCreated: undefined,
GPSDateTime: undefined,
DateTimeUTC: undefined,
SonyDateTime2: undefined,
GPSDateStamp: undefined,
});
const oldDate = new Date('2020-01-01T00:00:00.000Z');
const asset = await utils.createAsset(admin.accessToken, {
assetData: {
filename,
bytes: imageBytes,
},
fileCreatedAt: oldDate.toISOString(),
fileModifiedAt: oldDate.toISOString(),
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
// Should fall back to file timestamps, which we set to 2020-01-01
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
new Date('2020-01-01T00:00:00.000Z').getTime(),
);
});
it('should prefer DateTimeOriginal over time-only tags', async () => {
const { imageBytes, filename } = await createTestImageWithExif('datetime-over-time.jpg', {
DateTimeOriginal: '2023:10:10 10:00:00', // Should be preferred
TimeCreated: '2023:11:15 14:30:00', // Should be ignored (time-only)
});
const asset = await utils.createAsset(admin.accessToken, {
assetData: {
filename,
bytes: imageBytes,
},
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
// Should use DateTimeOriginal, not TimeCreated
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
new Date('2023-10-10T10:00:00.000Z').getTime(),
);
});
});
describe('GPSDateTime tag extraction', () => {
it('should extract GPSDateTime with GPS coordinates', async () => {
const { imageBytes, filename } = await createTestImageWithExif('gps-datetime.jpg', {
GPSDateTime: '2023:11:15 12:30:00Z',
GPSLatitude: 37.7749,
GPSLongitude: -122.4194,
// Exclude other date tags
SubSecDateTimeOriginal: undefined,
DateTimeOriginal: undefined,
SubSecCreateDate: undefined,
SubSecMediaCreateDate: undefined,
CreateDate: undefined,
MediaCreateDate: undefined,
CreationDate: undefined,
DateTimeCreated: undefined,
TimeCreated: undefined,
});
const asset = await utils.createAsset(admin.accessToken, {
assetData: {
filename,
bytes: imageBytes,
},
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
expect(assetInfo.exifInfo?.latitude).toBeCloseTo(37.7749, 4);
expect(assetInfo.exifInfo?.longitude).toBeCloseTo(-122.4194, 4);
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
new Date('2023-11-15T12:30:00.000Z').getTime(),
);
});
});
describe('CreateDate tag extraction', () => {
it('should extract CreateDate when available', async () => {
const { imageBytes, filename } = await createTestImageWithExif('create-date.jpg', {
CreateDate: '2023:11:15 10:30:00',
// Exclude other higher priority date tags
SubSecDateTimeOriginal: undefined,
DateTimeOriginal: undefined,
SubSecCreateDate: undefined,
SubSecMediaCreateDate: undefined,
MediaCreateDate: undefined,
CreationDate: undefined,
DateTimeCreated: undefined,
TimeCreated: undefined,
GPSDateTime: undefined,
});
const asset = await utils.createAsset(admin.accessToken, {
assetData: {
filename,
bytes: imageBytes,
},
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
new Date('2023-11-15T10:30:00.000Z').getTime(),
);
});
});
describe('GPSDateStamp tag extraction', () => {
it('should fall back to file timestamps when only date-only tags are available', async () => {
const { imageBytes, filename } = await createTestImageWithExif('gps-datestamp.jpg', {
GPSDateStamp: '2023:11:15', // Date-only tag, should not be used for dateTimeOriginal
// Note: NOT including GPSTimeStamp to avoid automatic GPSDateTime creation
GPSLatitude: 51.5074,
GPSLongitude: -0.1278,
// Explicitly exclude all testable date-time tags to force fallback to file timestamps
DateTimeOriginal: undefined,
CreateDate: undefined,
CreationDate: undefined,
GPSDateTime: undefined,
});
const oldDate = new Date('2020-01-01T00:00:00.000Z');
const asset = await utils.createAsset(admin.accessToken, {
assetData: {
filename,
bytes: imageBytes,
},
fileCreatedAt: oldDate.toISOString(),
fileModifiedAt: oldDate.toISOString(),
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
expect(assetInfo.exifInfo?.latitude).toBeCloseTo(51.5074, 4);
expect(assetInfo.exifInfo?.longitude).toBeCloseTo(-0.1278, 4);
// Should fall back to file timestamps, which we set to 2020-01-01
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
new Date('2020-01-01T00:00:00.000Z').getTime(),
);
});
});
/*
* NOTE: The following EXIF date tags are NOT effectively usable with JPEG test files:
*
* NOT WRITABLE to JPEG:
* - MediaCreateDate: Can be read from video files but not written to JPEG
* - DateTimeCreated: Read-only tag in JPEG format
* - DateTimeUTC: Cannot be written to JPEG files
* - SonyDateTime2: Proprietary Sony tag, not writable to JPEG
* - SubSecMediaCreateDate: Tag not defined for JPEG format
* - SourceImageCreateTime: Non-standard insta360 tag, not writable to JPEG
*
* WRITABLE but NOT READABLE from JPEG:
* - SubSecDateTimeOriginal: Can be written but not read back from JPEG
* - SubSecCreateDate: Can be written but not read back from JPEG
*
* EFFECTIVELY TESTABLE TAGS (writable and readable):
* - DateTimeOriginal ✓
* - CreateDate ✓
* - CreationDate ✓
* - GPSDateTime ✓
*
* The metadata service correctly handles non-readable tags and will fall back to
* file timestamps when only non-readable tags are present.
*/
describe('Date tag priority order', () => {
it('should respect the complete date tag priority order', async () => {
// Test cases using only EFFECTIVELY TESTABLE tags (writable AND readable from JPEG)
const testCases = [
{
name: 'DateTimeOriginal has highest priority among testable tags',
exifData: {
DateTimeOriginal: '2023:04:04 04:00:00', // TESTABLE - highest priority among readable tags
CreateDate: '2023:05:05 05:00:00', // TESTABLE
CreationDate: '2023:07:07 07:00:00', // TESTABLE
GPSDateTime: '2023:10:10 10:00:00', // TESTABLE
},
expectedDate: '2023-04-04T04:00:00.000Z',
},
{
name: 'CreateDate when DateTimeOriginal missing',
exifData: {
CreateDate: '2023:05:05 05:00:00', // TESTABLE
CreationDate: '2023:07:07 07:00:00', // TESTABLE
GPSDateTime: '2023:10:10 10:00:00', // TESTABLE
},
expectedDate: '2023-05-05T05:00:00.000Z',
},
{
name: 'CreationDate when standard EXIF tags missing',
exifData: {
CreationDate: '2023:07:07 07:00:00', // TESTABLE
GPSDateTime: '2023:10:10 10:00:00', // TESTABLE
},
expectedDate: '2023-07-07T07:00:00.000Z',
},
{
name: 'GPSDateTime when no other testable date tags present',
exifData: {
GPSDateTime: '2023:10:10 10:00:00', // TESTABLE
Make: 'SONY',
},
expectedDate: '2023-10-10T10:00:00.000Z',
},
];
for (const testCase of testCases) {
const { imageBytes, filename } = await createTestImageWithExif(
`${testCase.name.replaceAll(/\s+/g, '-').toLowerCase()}.jpg`,
testCase.exifData,
);
const asset = await utils.createAsset(admin.accessToken, {
assetData: {
filename,
bytes: imageBytes,
},
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
expect(assetInfo.exifInfo?.dateTimeOriginal, `Failed for: ${testCase.name}`).toBeDefined();
expect(
new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime(),
`Date mismatch for: ${testCase.name}`,
).toBe(new Date(testCase.expectedDate).getTime());
}
});
});
describe('Edge cases for date tag handling', () => {
it('should fall back to file timestamps with GPSDateStamp alone', async () => {
const { imageBytes, filename } = await createTestImageWithExif('gps-datestamp-only.jpg', {
GPSDateStamp: '2023:08:08', // Date-only tag, should not be used for dateTimeOriginal
// Intentionally no GPSTimeStamp
// Exclude all other date tags
SubSecDateTimeOriginal: undefined,
DateTimeOriginal: undefined,
SubSecCreateDate: undefined,
SubSecMediaCreateDate: undefined,
CreateDate: undefined,
MediaCreateDate: undefined,
CreationDate: undefined,
DateTimeCreated: undefined,
TimeCreated: undefined,
GPSDateTime: undefined,
DateTimeUTC: undefined,
});
const oldDate = new Date('2020-01-01T00:00:00.000Z');
const asset = await utils.createAsset(admin.accessToken, {
assetData: {
filename,
bytes: imageBytes,
},
fileCreatedAt: oldDate.toISOString(),
fileModifiedAt: oldDate.toISOString(),
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
// Should fall back to file timestamps, which we set to 2020-01-01
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
new Date('2020-01-01T00:00:00.000Z').getTime(),
);
});
it('should handle all testable date tags present to verify complete priority order', async () => {
const { imageBytes, filename } = await createTestImageWithExif('all-testable-date-tags.jpg', {
// All TESTABLE date tags to JPEG format (writable AND readable)
DateTimeOriginal: '2023:04:04 04:00:00', // TESTABLE - highest priority among readable tags
CreateDate: '2023:05:05 05:00:00', // TESTABLE
CreationDate: '2023:07:07 07:00:00', // TESTABLE
GPSDateTime: '2023:10:10 10:00:00', // TESTABLE
// Note: Excluded non-testable tags:
// SubSec tags: writable but not readable from JPEG
// Non-writable tags: MediaCreateDate, DateTimeCreated, DateTimeUTC, SonyDateTime2, etc.
// Time-only/date-only tags: already excluded from EXIF_DATE_TAGS
});
const asset = await utils.createAsset(admin.accessToken, {
assetData: {
filename,
bytes: imageBytes,
},
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
// Should use DateTimeOriginal as it has the highest priority among testable tags
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
new Date('2023-04-04T04:00:00.000Z').getTime(),
);
});
it('should use CreationDate when SubSec tags are missing', async () => {
const { imageBytes, filename } = await createTestImageWithExif('creation-date-priority.jpg', {
CreationDate: '2023:07:07 07:00:00', // WRITABLE
GPSDateTime: '2023:10:10 10:00:00', // WRITABLE
// Note: DateTimeCreated, DateTimeUTC, SonyDateTime2 are NOT writable to JPEG
// Note: TimeCreated and GPSDateStamp are excluded from EXIF_DATE_TAGS (time-only/date-only)
// Exclude SubSec and standard EXIF tags
SubSecDateTimeOriginal: undefined,
DateTimeOriginal: undefined,
SubSecCreateDate: undefined,
CreateDate: undefined,
});
const asset = await utils.createAsset(admin.accessToken, {
assetData: {
filename,
bytes: imageBytes,
},
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
// Should use CreationDate when available
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
new Date('2023-07-07T07:00:00.000Z').getTime(),
);
});
it('should skip invalid date formats and use next valid tag', async () => {
const { imageBytes, filename } = await createTestImageWithExif('invalid-date-handling.jpg', {
// Note: Testing invalid date handling with only WRITABLE tags
GPSDateTime: '2023:10:10 10:00:00', // WRITABLE - Valid date
CreationDate: '2023:13:13 13:00:00', // WRITABLE - Valid date
// Note: TimeCreated excluded (time-only), DateTimeCreated not writable to JPEG
// Exclude other date tags
SubSecDateTimeOriginal: undefined,
DateTimeOriginal: undefined,
SubSecCreateDate: undefined,
CreateDate: undefined,
});
const asset = await utils.createAsset(admin.accessToken, {
assetData: {
filename,
bytes: imageBytes,
},
});
await utils.waitForWebsocketEvent({ event: 'assetUpload', id: asset.id });
const assetInfo = await getAssetInfo({ id: asset.id }, { headers: asBearerAuth(admin.accessToken) });
expect(assetInfo.exifInfo?.dateTimeOriginal).toBeDefined();
// Should skip invalid dates and use the first valid one (GPSDateTime)
expect(new Date(assetInfo.exifInfo!.dateTimeOriginal!).getTime()).toBe(
new Date('2023-10-10T10:00:00.000Z').getTime(),
);
});
});
});
});
describe('POST /assets/exist', () => {
it('ignores invalid deviceAssetIds', async () => {
const response = await utils.checkExistingAssets(user1.accessToken, {

View File

@@ -1,146 +0,0 @@
import { LoginResponseDto, login, signUpAdmin } from '@immich/sdk';
import { loginDto, signupDto } from 'src/fixtures';
import { errorDto, loginResponseDto, signupResponseDto } from 'src/responses';
import { app, utils } from 'src/utils';
import request from 'supertest';
import { beforeEach, describe, expect, it } from 'vitest';
const { email, password } = signupDto.admin;
describe(`/auth/admin-sign-up`, () => {
beforeEach(async () => {
await utils.resetDatabase();
});
describe('POST /auth/admin-sign-up', () => {
it(`should sign up the admin`, async () => {
const { status, body } = await request(app).post('/auth/admin-sign-up').send(signupDto.admin);
expect(status).toBe(201);
expect(body).toEqual(signupResponseDto.admin);
});
it('should not allow a second admin to sign up', async () => {
await signUpAdmin({ signUpDto: signupDto.admin });
const { status, body } = await request(app).post('/auth/admin-sign-up').send(signupDto.admin);
expect(status).toBe(400);
expect(body).toEqual(errorDto.alreadyHasAdmin);
});
});
});
describe('/auth/*', () => {
let admin: LoginResponseDto;
beforeEach(async () => {
await utils.resetDatabase();
await signUpAdmin({ signUpDto: signupDto.admin });
admin = await login({ loginCredentialDto: loginDto.admin });
});
describe(`POST /auth/login`, () => {
it('should reject an incorrect password', async () => {
const { status, body } = await request(app).post('/auth/login').send({ email, password: 'incorrect' });
expect(status).toBe(401);
expect(body).toEqual(errorDto.incorrectLogin);
});
it('should accept a correct password', async () => {
const { status, body, headers } = await request(app).post('/auth/login').send({ email, password });
expect(status).toBe(201);
expect(body).toEqual(loginResponseDto.admin);
const token = body.accessToken;
expect(token).toBeDefined();
const cookies = headers['set-cookie'];
expect(cookies).toHaveLength(3);
expect(cookies[0].split(';').map((item) => item.trim())).toEqual([
`immich_access_token=${token}`,
'Max-Age=34560000',
'Path=/',
expect.stringContaining('Expires='),
'HttpOnly',
'SameSite=Lax',
]);
expect(cookies[1].split(';').map((item) => item.trim())).toEqual([
'immich_auth_type=password',
'Max-Age=34560000',
'Path=/',
expect.stringContaining('Expires='),
'HttpOnly',
'SameSite=Lax',
]);
expect(cookies[2].split(';').map((item) => item.trim())).toEqual([
'immich_is_authenticated=true',
'Max-Age=34560000',
'Path=/',
expect.stringContaining('Expires='),
'SameSite=Lax',
]);
});
});
describe('POST /auth/validateToken', () => {
it('should reject an invalid token', async () => {
const { status, body } = await request(app).post(`/auth/validateToken`).set('Authorization', 'Bearer 123');
expect(status).toBe(401);
expect(body).toEqual(errorDto.invalidToken);
});
it('should accept a valid token', async () => {
const { status, body } = await request(app)
.post(`/auth/validateToken`)
.send({})
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual({ authStatus: true });
});
});
describe('POST /auth/change-password', () => {
it('should require the current password', async () => {
const { status, body } = await request(app)
.post(`/auth/change-password`)
.send({ password: 'wrong-password', newPassword: 'Password1234' })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.wrongPassword);
});
it('should change the password', async () => {
const { status } = await request(app)
.post(`/auth/change-password`)
.send({ password, newPassword: 'Password1234' })
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
await login({
loginCredentialDto: {
email: 'admin@immich.cloud',
password: 'Password1234',
},
});
});
});
describe('POST /auth/logout', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post(`/auth/logout`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should logout the user', async () => {
const { status, body } = await request(app)
.post(`/auth/logout`)
.set('Authorization', `Bearer ${admin.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual({
successful: true,
redirectUri: '/auth/login?autoLaunch=0',
});
});
});
});

View File

@@ -6,7 +6,7 @@ import {
createMemory,
getMemory,
} from '@immich/sdk';
import { createUserDto, uuidDto } from 'src/fixtures';
import { createUserDto } from 'src/fixtures';
import { errorDto } from 'src/responses';
import { app, asBearerAuth, utils } from 'src/utils';
import request from 'supertest';
@@ -17,7 +17,6 @@ describe('/memories', () => {
let user: LoginResponseDto;
let adminAsset: AssetMediaResponseDto;
let userAsset1: AssetMediaResponseDto;
let userAsset2: AssetMediaResponseDto;
let userMemory: MemoryResponseDto;
beforeAll(async () => {
@@ -25,10 +24,9 @@ describe('/memories', () => {
admin = await utils.adminSetup();
user = await utils.userSetup(admin.accessToken, createUserDto.user1);
[adminAsset, userAsset1, userAsset2] = await Promise.all([
[adminAsset, userAsset1] = await Promise.all([
utils.createAsset(admin.accessToken),
utils.createAsset(user.accessToken),
utils.createAsset(user.accessToken),
]);
userMemory = await createMemory(
{
@@ -43,121 +41,7 @@ describe('/memories', () => {
);
});
describe('GET /memories', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/memories');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
});
describe('POST /memories', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).post('/memories');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should validate data when type is on this day', async () => {
const { status, body } = await request(app)
.post('/memories')
.set('Authorization', `Bearer ${user.accessToken}`)
.send({
type: 'on_this_day',
data: {},
memoryAt: new Date(2021).toISOString(),
});
expect(status).toBe(400);
expect(body).toEqual(
errorDto.badRequest(['data.year must be a positive number', 'data.year must be an integer number']),
);
});
it('should create a new memory', async () => {
const { status, body } = await request(app)
.post('/memories')
.set('Authorization', `Bearer ${user.accessToken}`)
.send({
type: 'on_this_day',
data: { year: 2021 },
memoryAt: new Date(2021).toISOString(),
});
expect(status).toBe(201);
expect(body).toEqual({
id: expect.any(String),
type: 'on_this_day',
data: { year: 2021 },
createdAt: expect.any(String),
updatedAt: expect.any(String),
isSaved: false,
memoryAt: expect.any(String),
ownerId: user.userId,
assets: [],
});
});
it('should create a new memory (with assets)', async () => {
const { status, body } = await request(app)
.post('/memories')
.set('Authorization', `Bearer ${user.accessToken}`)
.send({
type: 'on_this_day',
data: { year: 2021 },
memoryAt: new Date(2021).toISOString(),
assetIds: [userAsset1.id, userAsset2.id],
});
expect(status).toBe(201);
expect(body).toMatchObject({
id: expect.any(String),
assets: expect.arrayContaining([
expect.objectContaining({ id: userAsset1.id }),
expect.objectContaining({ id: userAsset2.id }),
]),
});
expect(body.assets).toHaveLength(2);
});
it('should create a new memory and ignore assets the user does not have access to', async () => {
const { status, body } = await request(app)
.post('/memories')
.set('Authorization', `Bearer ${user.accessToken}`)
.send({
type: 'on_this_day',
data: { year: 2021 },
memoryAt: new Date(2021).toISOString(),
assetIds: [userAsset1.id, adminAsset.id],
});
expect(status).toBe(201);
expect(body).toMatchObject({
id: expect.any(String),
assets: [expect.objectContaining({ id: userAsset1.id })],
});
expect(body.assets).toHaveLength(1);
});
});
describe('GET /memories/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get(`/memories/${uuidDto.invalid}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require a valid id', async () => {
const { status, body } = await request(app)
.get(`/memories/${uuidDto.invalid}`)
.set('Authorization', `Bearer ${user.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
});
it('should require access', async () => {
const { status, body } = await request(app)
.get(`/memories/${userMemory.id}`)
@@ -176,22 +60,6 @@ describe('/memories', () => {
});
describe('PUT /memories/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put(`/memories/${uuidDto.invalid}`).send({ isSaved: true });
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require a valid id', async () => {
const { status, body } = await request(app)
.put(`/memories/${uuidDto.invalid}`)
.send({ isSaved: true })
.set('Authorization', `Bearer ${user.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
});
it('should require access', async () => {
const { status, body } = await request(app)
.put(`/memories/${userMemory.id}`)
@@ -218,23 +86,6 @@ describe('/memories', () => {
});
describe('PUT /memories/:id/assets', () => {
it('should require authentication', async () => {
const { status, body } = await request(app)
.put(`/memories/${userMemory.id}/assets`)
.send({ ids: [userAsset1.id] });
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require a valid id', async () => {
const { status, body } = await request(app)
.put(`/memories/${uuidDto.invalid}/assets`)
.send({ ids: [userAsset1.id] })
.set('Authorization', `Bearer ${user.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
});
it('should require access', async () => {
const { status, body } = await request(app)
.put(`/memories/${userMemory.id}/assets`)
@@ -244,15 +95,6 @@ describe('/memories', () => {
expect(body).toEqual(errorDto.noPermission);
});
it('should require a valid asset id', async () => {
const { status, body } = await request(app)
.put(`/memories/${userMemory.id}/assets`)
.send({ ids: [uuidDto.invalid] })
.set('Authorization', `Bearer ${user.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['each value in ids must be a UUID']));
});
it('should require asset access', async () => {
const { status, body } = await request(app)
.put(`/memories/${userMemory.id}/assets`)
@@ -279,23 +121,6 @@ describe('/memories', () => {
});
describe('DELETE /memories/:id/assets', () => {
it('should require authentication', async () => {
const { status, body } = await request(app)
.delete(`/memories/${userMemory.id}/assets`)
.send({ ids: [userAsset1.id] });
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require a valid id', async () => {
const { status, body } = await request(app)
.delete(`/memories/${uuidDto.invalid}/assets`)
.send({ ids: [userAsset1.id] })
.set('Authorization', `Bearer ${user.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
});
it('should require access', async () => {
const { status, body } = await request(app)
.delete(`/memories/${userMemory.id}/assets`)
@@ -305,15 +130,6 @@ describe('/memories', () => {
expect(body).toEqual(errorDto.noPermission);
});
it('should require a valid asset id', async () => {
const { status, body } = await request(app)
.delete(`/memories/${userMemory.id}/assets`)
.send({ ids: [uuidDto.invalid] })
.set('Authorization', `Bearer ${user.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['each value in ids must be a UUID']));
});
it('should only remove assets in the memory', async () => {
const { status, body } = await request(app)
.delete(`/memories/${userMemory.id}/assets`)
@@ -340,21 +156,6 @@ describe('/memories', () => {
});
describe('DELETE /memories/:id', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).delete(`/memories/${uuidDto.invalid}`);
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should require a valid id', async () => {
const { status, body } = await request(app)
.delete(`/memories/${uuidDto.invalid}`)
.set('Authorization', `Bearer ${user.accessToken}`);
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest(['id must be a UUID']));
});
it('should require access', async () => {
const { status, body } = await request(app)
.delete(`/memories/${userMemory.id}`)

View File

@@ -227,6 +227,21 @@ describe(`/oauth`, () => {
expect(user.storageLabel).toBe('user-username');
});
it('should set the admin status from a role claim', async () => {
const callbackParams = await loginWithOAuth(OAuthUser.WITH_ROLE);
const { status, body } = await request(app).post('/oauth/callback').send(callbackParams);
expect(status).toBe(201);
expect(body).toMatchObject({
accessToken: expect.any(String),
userId: expect.any(String),
userEmail: 'oauth-with-role@immich.app',
isAdmin: true,
});
const user = await getMyUser({ headers: asBearerAuth(body.accessToken) });
expect(user.isAdmin).toBe(true);
});
it('should work with RS256 signed tokens', async () => {
await setupOAuth(admin.accessToken, {
enabled: true,

View File

@@ -9,7 +9,7 @@ import {
} from '@immich/sdk';
import { createUserDto, uuidDto } from 'src/fixtures';
import { errorDto } from 'src/responses';
import { app, asBearerAuth, shareUrl, utils } from 'src/utils';
import { app, asBearerAuth, baseUrl, shareUrl, utils } from 'src/utils';
import request from 'supertest';
import { beforeAll, describe, expect, it } from 'vitest';
@@ -78,6 +78,7 @@ describe('/shared-links', () => {
type: SharedLinkType.Album,
albumId: metadataAlbum.id,
showMetadata: true,
slug: 'metadata-album',
}),
utils.createSharedLink(user1.accessToken, {
type: SharedLinkType.Album,
@@ -117,6 +118,13 @@ describe('/shared-links', () => {
const resp = await request(shareUrl).get(`/${linkWithAssets.key}`);
expect(resp.status).toBe(200);
expect(resp.header['content-type']).toContain('text/html');
expect(resp.text).toContain(`<meta property="og:image" content="http://127.0.0.1:2285`);
});
it('should fall back to my.immich.app og:image meta tag for shared asset if Host header is not present', async () => {
const resp = await request(shareUrl).get(`/${linkWithAssets.key}`).set('Host', '');
expect(resp.status).toBe(200);
expect(resp.header['content-type']).toContain('text/html');
expect(resp.text).toContain(`<meta property="og:image" content="https://my.immich.app`);
});
@@ -131,6 +139,17 @@ describe('/shared-links', () => {
});
});
describe('GET /s/:slug', () => {
it('should work for slug auth', async () => {
const resp = await request(baseUrl).get(`/s/${linkWithMetadata.slug}`);
expect(resp.status).toBe(200);
expect(resp.header['content-type']).toContain('text/html');
expect(resp.text).toContain(
`<meta name="description" content="${metadataAlbum.assets.length} shared photos &amp; videos" />`,
);
});
});
describe('GET /shared-links', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/shared-links');

View File

@@ -15,12 +15,6 @@ describe('/system-config', () => {
});
describe('PUT /system-config', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).put('/system-config');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should always return the new config', async () => {
const config = await getSystemConfig(admin.accessToken);

View File

@@ -37,7 +37,7 @@ describe('/tags', () => {
beforeEach(async () => {
// tagging assets eventually triggers metadata extraction which can impact other tests
await utils.waitForQueueFinish(admin.accessToken, 'metadataExtraction');
await utils.resetDatabase(['tags']);
await utils.resetDatabase(['tag']);
});
describe('POST /tags', () => {

View File

@@ -1,230 +0,0 @@
import {
AssetMediaResponseDto,
AssetVisibility,
LoginResponseDto,
SharedLinkType,
TimeBucketAssetResponseDto,
} from '@immich/sdk';
import { DateTime } from 'luxon';
import { createUserDto } from 'src/fixtures';
import { errorDto } from 'src/responses';
import { app, utils } from 'src/utils';
import request from 'supertest';
import { beforeAll, describe, expect, it } from 'vitest';
// TODO this should probably be a test util function
const today = DateTime.fromObject({
year: 2023,
month: 11,
day: 3,
}) as DateTime<true>;
const yesterday = today.minus({ days: 1 });
describe('/timeline', () => {
let admin: LoginResponseDto;
let user: LoginResponseDto;
let timeBucketUser: LoginResponseDto;
let user1Assets: AssetMediaResponseDto[];
let user2Assets: AssetMediaResponseDto[];
beforeAll(async () => {
await utils.resetDatabase();
admin = await utils.adminSetup({ onboarding: false });
[user, timeBucketUser] = await Promise.all([
utils.userSetup(admin.accessToken, createUserDto.create('1')),
utils.userSetup(admin.accessToken, createUserDto.create('time-bucket')),
]);
user1Assets = await Promise.all([
utils.createAsset(user.accessToken),
utils.createAsset(user.accessToken),
utils.createAsset(user.accessToken, {
isFavorite: true,
fileCreatedAt: yesterday.toISO(),
fileModifiedAt: yesterday.toISO(),
assetData: { filename: 'example.mp4' },
}),
utils.createAsset(user.accessToken),
utils.createAsset(user.accessToken),
]);
user2Assets = await Promise.all([
utils.createAsset(timeBucketUser.accessToken, { fileCreatedAt: new Date('1970-01-01').toISOString() }),
utils.createAsset(timeBucketUser.accessToken, { fileCreatedAt: new Date('1970-02-10').toISOString() }),
utils.createAsset(timeBucketUser.accessToken, { fileCreatedAt: new Date('1970-02-11').toISOString() }),
utils.createAsset(timeBucketUser.accessToken, { fileCreatedAt: new Date('1970-02-11').toISOString() }),
utils.createAsset(timeBucketUser.accessToken, { fileCreatedAt: new Date('1970-02-12').toISOString() }),
]);
await utils.deleteAssets(timeBucketUser.accessToken, [user2Assets[4].id]);
});
describe('GET /timeline/buckets', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/timeline/buckets');
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should get time buckets by month', async () => {
const { status, body } = await request(app)
.get('/timeline/buckets')
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual(
expect.arrayContaining([
{ count: 3, timeBucket: '1970-02-01' },
{ count: 1, timeBucket: '1970-01-01' },
]),
);
});
it('should not allow access for unrelated shared links', async () => {
const sharedLink = await utils.createSharedLink(user.accessToken, {
type: SharedLinkType.Individual,
assetIds: user1Assets.map(({ id }) => id),
});
const { status, body } = await request(app).get('/timeline/buckets').query({ key: sharedLink.key });
expect(status).toBe(400);
expect(body).toEqual(errorDto.noPermission);
});
it('should return error if time bucket is requested with partners asset and archived', async () => {
const req1 = await request(app)
.get('/timeline/buckets')
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`)
.query({ withPartners: true, visibility: AssetVisibility.Archive });
expect(req1.status).toBe(400);
expect(req1.body).toEqual(errorDto.badRequest());
const req2 = await request(app)
.get('/timeline/buckets')
.set('Authorization', `Bearer ${user.accessToken}`)
.query({ withPartners: true, visibility: undefined });
expect(req2.status).toBe(400);
expect(req2.body).toEqual(errorDto.badRequest());
});
it('should return error if time bucket is requested with partners asset and favorite', async () => {
const req1 = await request(app)
.get('/timeline/buckets')
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`)
.query({ withPartners: true, isFavorite: true });
expect(req1.status).toBe(400);
expect(req1.body).toEqual(errorDto.badRequest());
const req2 = await request(app)
.get('/timeline/buckets')
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`)
.query({ withPartners: true, isFavorite: false });
expect(req2.status).toBe(400);
expect(req2.body).toEqual(errorDto.badRequest());
});
it('should return error if time bucket is requested with partners asset and trash', async () => {
const req = await request(app)
.get('/timeline/buckets')
.set('Authorization', `Bearer ${user.accessToken}`)
.query({ withPartners: true, isTrashed: true });
expect(req.status).toBe(400);
expect(req.body).toEqual(errorDto.badRequest());
});
});
describe('GET /timeline/bucket', () => {
it('should require authentication', async () => {
const { status, body } = await request(app).get('/timeline/bucket').query({
timeBucket: '1900-01-01',
});
expect(status).toBe(401);
expect(body).toEqual(errorDto.unauthorized);
});
it('should handle 5 digit years', async () => {
const { status, body } = await request(app)
.get('/timeline/bucket')
.query({ timeBucket: '012345-01-01' })
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`);
expect(status).toBe(200);
expect(body).toEqual({
city: [],
country: [],
duration: [],
id: [],
visibility: [],
isFavorite: [],
isImage: [],
isTrashed: [],
livePhotoVideoId: [],
fileCreatedAt: [],
localOffsetHours: [],
ownerId: [],
projectionType: [],
ratio: [],
status: [],
thumbhash: [],
});
});
// TODO enable date string validation while still accepting 5 digit years
// it('should fail if time bucket is invalid', async () => {
// const { status, body } = await request(app)
// .get('/timeline/bucket')
// .set('Authorization', `Bearer ${user.accessToken}`)
// .query({ timeBucket: 'foo' });
// expect(status).toBe(400);
// expect(body).toEqual(errorDto.badRequest);
// });
it('should return time bucket', async () => {
const { status, body } = await request(app)
.get('/timeline/bucket')
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`)
.query({ timeBucket: '1970-02-10' });
expect(status).toBe(200);
expect(body).toEqual({
city: [],
country: [],
duration: [],
id: [],
visibility: [],
isFavorite: [],
isImage: [],
isTrashed: [],
livePhotoVideoId: [],
fileCreatedAt: [],
localOffsetHours: [],
ownerId: [],
projectionType: [],
ratio: [],
status: [],
thumbhash: [],
});
});
it('should return time bucket in trash', async () => {
const { status, body } = await request(app)
.get('/timeline/bucket')
.set('Authorization', `Bearer ${timeBucketUser.accessToken}`)
.query({ timeBucket: '1970-02-01T00:00:00.000Z', isTrashed: true });
expect(status).toBe(200);
const timeBucket: TimeBucketAssetResponseDto = body;
expect(timeBucket.isTrashed).toEqual([true]);
});
});
});

View File

@@ -97,7 +97,7 @@ describe(`immich upload`, () => {
});
beforeEach(async () => {
await utils.resetDatabase(['assets', 'albums']);
await utils.resetDatabase(['asset', 'album']);
});
describe(`immich upload /path/to/file.jpg`, () => {

View File

@@ -0,0 +1,178 @@
#!/usr/bin/env node
/**
* Script to generate test images with additional EXIF date tags
* This creates actual JPEG images with embedded metadata for testing
* Images are generated into e2e/test-assets/metadata/dates/
*/
import { execSync } from 'node:child_process';
import { writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import sharp from 'sharp';
interface TestImage {
filename: string;
description: string;
exifTags: Record<string, string>;
}
const testImages: TestImage[] = [
{
filename: 'time-created.jpg',
description: 'Image with TimeCreated tag',
exifTags: {
TimeCreated: '2023:11:15 14:30:00',
Make: 'Canon',
Model: 'EOS R5',
},
},
{
filename: 'gps-datetime.jpg',
description: 'Image with GPSDateTime and coordinates',
exifTags: {
GPSDateTime: '2023:11:15 12:30:00Z',
GPSLatitude: '37.7749',
GPSLongitude: '-122.4194',
GPSLatitudeRef: 'N',
GPSLongitudeRef: 'W',
},
},
{
filename: 'datetime-utc.jpg',
description: 'Image with DateTimeUTC tag',
exifTags: {
DateTimeUTC: '2023:11:15 10:30:00',
Make: 'Nikon',
Model: 'D850',
},
},
{
filename: 'gps-datestamp.jpg',
description: 'Image with GPSDateStamp and GPSTimeStamp',
exifTags: {
GPSDateStamp: '2023:11:15',
GPSTimeStamp: '08:30:00',
GPSLatitude: '51.5074',
GPSLongitude: '-0.1278',
GPSLatitudeRef: 'N',
GPSLongitudeRef: 'W',
},
},
{
filename: 'sony-datetime2.jpg',
description: 'Sony camera image with SonyDateTime2 tag',
exifTags: {
SonyDateTime2: '2023:11:15 06:30:00',
Make: 'SONY',
Model: 'ILCE-7RM5',
},
},
{
filename: 'date-priority-test.jpg',
description: 'Image with multiple date tags to test priority',
exifTags: {
SubSecDateTimeOriginal: '2023:01:01 01:00:00',
DateTimeOriginal: '2023:02:02 02:00:00',
SubSecCreateDate: '2023:03:03 03:00:00',
CreateDate: '2023:04:04 04:00:00',
CreationDate: '2023:05:05 05:00:00',
DateTimeCreated: '2023:06:06 06:00:00',
TimeCreated: '2023:07:07 07:00:00',
GPSDateTime: '2023:08:08 08:00:00',
DateTimeUTC: '2023:09:09 09:00:00',
GPSDateStamp: '2023:10:10',
SonyDateTime2: '2023:11:11 11:00:00',
},
},
{
filename: 'new-tags-only.jpg',
description: 'Image with only additional date tags (no standard tags)',
exifTags: {
TimeCreated: '2023:12:01 15:45:30',
GPSDateTime: '2023:12:01 13:45:30Z',
DateTimeUTC: '2023:12:01 13:45:30',
GPSDateStamp: '2023:12:01',
SonyDateTime2: '2023:12:01 08:45:30',
GPSLatitude: '40.7128',
GPSLongitude: '-74.0060',
GPSLatitudeRef: 'N',
GPSLongitudeRef: 'W',
},
},
];
const generateTestImages = async (): Promise<void> => {
// Target directory: e2e/test-assets/metadata/dates/
// Current file is in: e2e/src/
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const targetDir = join(__dirname, '..', 'test-assets', 'metadata', 'dates');
console.log('Generating test images with additional EXIF date tags...');
console.log(`Target directory: ${targetDir}`);
for (const image of testImages) {
try {
const imagePath = join(targetDir, image.filename);
// Create unique JPEG file using Sharp
const r = Math.floor(Math.random() * 256);
const g = Math.floor(Math.random() * 256);
const b = Math.floor(Math.random() * 256);
const jpegData = await sharp({
create: {
width: 100,
height: 100,
channels: 3,
background: { r, g, b },
},
})
.jpeg({ quality: 90 })
.toBuffer();
writeFileSync(imagePath, jpegData);
// Build exiftool command to add EXIF data
const exifArgs = Object.entries(image.exifTags)
.map(([tag, value]) => `-${tag}="${value}"`)
.join(' ');
const command = `exiftool ${exifArgs} -overwrite_original "${imagePath}"`;
console.log(`Creating ${image.filename}: ${image.description}`);
execSync(command, { stdio: 'pipe' });
// Verify the tags were written
const verifyCommand = `exiftool -json "${imagePath}"`;
const result = execSync(verifyCommand, { encoding: 'utf8' });
const metadata = JSON.parse(result)[0];
console.log(` ✓ Created with ${Object.keys(image.exifTags).length} EXIF tags`);
// Log first date tag found for verification
const firstDateTag = Object.keys(image.exifTags).find(
(tag) => tag.includes('Date') || tag.includes('Time') || tag.includes('Created'),
);
if (firstDateTag && metadata[firstDateTag]) {
console.log(` ✓ Verified ${firstDateTag}: ${metadata[firstDateTag]}`);
}
} catch (error) {
console.error(`Failed to create ${image.filename}:`, (error as Error).message);
}
}
console.log('\nTest image generation complete!');
console.log('Files created in:', targetDir);
console.log('\nTo test these images:');
console.log(`cd ${targetDir} && exiftool -time:all -gps:all *.jpg`);
};
export { generateTestImages };
// Run the generator if this file is executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
generateTestImages().catch(console.error);
}

View File

@@ -116,6 +116,7 @@ export const deviceDto = {
createdAt: expect.any(String),
updatedAt: expect.any(String),
current: true,
isPendingSyncReset: false,
deviceOS: '',
deviceType: '',
},

View File

@@ -12,6 +12,7 @@ export enum OAuthUser {
NO_NAME = 'no-name',
WITH_QUOTA = 'with-quota',
WITH_USERNAME = 'with-username',
WITH_ROLE = 'with-role',
}
const claims = [
@@ -34,6 +35,12 @@ const claims = [
preferred_username: 'user-quota',
immich_quota: 25,
},
{
sub: OAuthUser.WITH_ROLE,
email: 'oauth-with-role@immich.app',
email_verified: true,
immich_role: 'admin',
},
];
const withDefaultClaims = (sub: string) => ({
@@ -64,7 +71,15 @@ const setup = async () => {
claims: {
openid: ['sub'],
email: ['email', 'email_verified'],
profile: ['name', 'given_name', 'family_name', 'preferred_username', 'immich_quota', 'immich_username'],
profile: [
'name',
'given_name',
'family_name',
'preferred_username',
'immich_quota',
'immich_username',
'immich_role',
],
},
features: {
jwtUserinfo: {

View File

@@ -60,6 +60,7 @@ import { io, type Socket } from 'socket.io-client';
import { loginDto, signupDto } from 'src/fixtures';
import { makeRandomImage } from 'src/generators';
import request from 'supertest';
export type { Emitter } from '@socket.io/component-emitter';
type CommandResponse = { stdout: string; stderr: string; exitCode: number | null };
type EventType = 'assetUpload' | 'assetUpdate' | 'assetDelete' | 'userDelete' | 'assetHidden';
@@ -84,10 +85,10 @@ export const immichAdmin = (args: string[]) =>
export const specialCharStrings = ["'", '"', ',', '{', '}', '*'];
export const TEN_TIMES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const executeCommand = (command: string, args: string[]) => {
const executeCommand = (command: string, args: string[], options?: { cwd?: string }) => {
let _resolve: (value: CommandResponse) => void;
const promise = new Promise<CommandResponse>((resolve) => (_resolve = resolve));
const child = spawn(command, args, { stdio: 'pipe' });
const child = spawn(command, args, { stdio: 'pipe', cwd: options?.cwd });
let stdout = '';
let stderr = '';
@@ -153,19 +154,19 @@ export const utils = {
tables = tables || [
// TODO e2e test for deleting a stack, since it is quite complex
'asset_stack',
'libraries',
'shared_links',
'stack',
'library',
'shared_link',
'person',
'albums',
'assets',
'asset_faces',
'album',
'asset',
'asset_face',
'activity',
'api_keys',
'sessions',
'users',
'api_key',
'session',
'user',
'system_metadata',
'tags',
'tag',
];
const sql: string[] = [];
@@ -174,7 +175,7 @@ export const utils = {
if (table === 'system_metadata') {
sql.push(`DELETE FROM "system_metadata" where "key" NOT IN ('reverse-geocoding-state', 'system-flags');`);
} else {
sql.push(`DELETE FROM ${table} CASCADE;`);
sql.push(`DELETE FROM "${table}" CASCADE;`);
}
}
@@ -185,18 +186,6 @@ export const utils = {
}
},
resetFilesystem: async () => {
const mediaInternal = '/usr/src/app/upload';
const dirs = [
`"${mediaInternal}/thumbs"`,
`"${mediaInternal}/upload"`,
`"${mediaInternal}/library"`,
`"${mediaInternal}/encoded-video"`,
].join(' ');
await execPromise(`docker exec -i "immich-e2e-server" /bin/bash -c "rm -rf ${dirs} && mkdir ${dirs}"`);
},
unzip: async (input: string, output: string) => {
await execPromise(`unzip -o -d "${output}" "${input}"`);
},
@@ -450,7 +439,7 @@ export const utils = {
return;
}
await client.query('INSERT INTO asset_faces ("assetId", "personId") VALUES ($1, $2)', [assetId, personId]);
await client.query('INSERT INTO asset_face ("assetId", "personId") VALUES ($1, $2)', [assetId, personId]);
},
setPersonThumbnail: async (personId: string) => {

View File

@@ -37,6 +37,7 @@ test.describe('Registration', () => {
await page.getByRole('button', { name: 'Server Privacy' }).click();
await page.getByRole('button', { name: 'User Privacy' }).click();
await page.getByRole('button', { name: 'Storage Template' }).click();
await page.getByRole('button', { name: 'Backups' }).click();
await page.getByRole('button', { name: 'Done' }).click();
// success

View File

@@ -4,6 +4,7 @@
"account_settings": "Rekeninginstellings",
"acknowledge": "Erken",
"action": "Aksie",
"action_common_update": "Opdateur",
"actions": "Aksies",
"active": "Aktief",
"activity": "Aktiwiteite",
@@ -13,6 +14,7 @@
"add_a_location": "Voeg 'n ligging by",
"add_a_name": "Voeg 'n naam by",
"add_a_title": "Voeg 'n titel by",
"add_endpoint": "Voeg Koppelvlakpunt by",
"add_exclusion_pattern": "Voeg uitsgluitingspatrone by",
"add_import_path": "Voeg invoerpad by",
"add_location": "Voeg ligging by",
@@ -20,26 +22,30 @@
"add_partner": "Voeg vennoot by",
"add_path": "Voeg pad by",
"add_photos": "Voeg foto's by",
"add_tag": "Voeg tag by",
"add_to": "Voeg by…",
"add_to_album": "Voeg na album",
"add_to_shared_album": "Voeg na gedeelde album",
"add_to_album_bottom_sheet_added": "By {album} bygevoeg",
"add_to_album_bottom_sheet_already_exists": "Reeds in {album}",
"add_to_shared_album": "Voeg toe aan gedeelde album",
"add_url": "Voeg URL by",
"added_to_archive": "By argief gevoeg",
"added_to_favorites": "By gunstelinge gevoeg",
"added_to_favorites_count": "Het {count, number} by gunstelinge gevoeg",
"added_to_archive": "By argief toegevoegd",
"added_to_favorites": "By gunstelinge toegevoegd",
"added_to_favorites_count": "Het {count, number} by gunstelinge toegevoegd",
"admin": {
"add_exclusion_pattern_description": "Voeg uitsluitingspatrone by. Globbing met *, ** en ? word ondersteun. Om alle lêers in enige lêergids genaamd \"Raw\" te ignoreer, gebruik \"**/Raw/**\". Om alle lêers wat op \".tif\" eindig, te ignoreer, gebruik \"**/*.tif\". Om 'n absolute pad te ignoreer, gebruik \"/path/to/ignore/**\".",
"admin_user": "Admin gebruiker",
"asset_offline_description": "Hierdie eksterne biblioteekbate word nie meer op skyf gevind nie en is na die asblik geskuif. As die lêer binne die biblioteek geskuif is, gaan jou tydlyn na vir die nuwe ooreenstemmende bate. Om hierdie bate te herstel, maak asseblief seker dat die lêerpad hieronder deur Immich verkry kan word en skandeer die biblioteek.",
"authentication_settings": "Verifikasie instellings",
"authentication_settings_description": "Bestuur wagwoord, OAuth en ander verifikasie instellings",
"authentication_settings_disable_all": "Is jy seker jy wil alle aanmeldmetodes deaktiveer? Aanmelding sal heeltemal gedeaktiveer word.",
"authentication_settings_reenable": "Om te heraktiveer, gebruik 'n <link>Server Command</link>.",
"background_task_job": "Agtergrondtake",
"backup_database": "Rugsteun databasis",
"backup_database": "Skep Datastortlêer",
"backup_database_enable_description": "Aktiveer databasisrugsteun",
"backup_keep_last_amount": "Aantal vorige rugsteune om te hou",
"backup_settings": "Rugsteun instellings",
"backup_settings_description": "Bestuur databasis rugsteun instellings",
"backup_settings_description": "Bestuur databasis rugsteun instellings.",
"cleared_jobs": "Poste gevee vir: {job}",
"config_set_by_file": "Config word tans deur 'n konfigurasielêer gestel",
"confirm_delete_library": "Is jy seker jy wil {library}-biblioteek uitvee?",
@@ -47,6 +53,7 @@
"confirm_email_below": "Om te bevestig, tik \"{email}\" hieronder",
"confirm_reprocess_all_faces": "Is jy seker jy wil alle gesigte herverwerk? Dit sal ook genoemde mense skoonmaak.",
"confirm_user_password_reset": "Is jy seker jy wil {user} se wagwoord terugstel?",
"confirm_user_pin_code_reset": "Is jy seker jy wil {user} se PIN kode herstel?",
"create_job": "Skep werk",
"cron_expression": "Cron uitdrukking",
"cron_expression_description": "Stel die skanderingsinterval in met die cron-formaat. Vir meer inligting verwys asseblief na bv. <link>Crontab Guru</link>",
@@ -56,10 +63,14 @@
"exclusion_pattern_description": "Met uitsluitingspatrone kan jy lêers en vouers ignoreer wanneer jy jou biblioteek skandeer. Dit is nuttig as jy vouers het wat lêers bevat wat jy nie wil invoer nie, soos RAW-lêers.",
"external_library_management": "Eksterne Biblioteekbestuur",
"face_detection": "Gesig deteksie",
"face_detection_description": "Detecteer die gesigte in media deur middel van masjienleer. Vir videos word slegs die duimnaelskets oorweeg. “Herlaai” (ver)werk al die media weer. “Stel terug” verwyder boonop alle huidige gesigdata. “Onverwerk” plaas bates in die tou wat nog nie verwerk is nie. Gedekte gesigte sal ná voltooiing van Gesigdetectie vir Gesigherkenning in die tou geplaas word, om hulle in bestaande of nuwe persone te groepeer.",
"facial_recognition_job_description": "Groepeer gesigte in mense in. Die stap is vinniger nadat Gesig Deteksie klaar is. \"Herstel\" (her-)groepeer alle gesigte. \"Vermiste\" plaas gesigte in ry wat nie 'n persoon gekoppel het nie.",
"failed_job_command": "Opdrag {command} het misluk vir werk: {job}",
"force_delete_user_warning": "WAARSKUWING: Dit sal onmiddellik die gebruiker en alle bates verwyder. Dit kan nie ontdoen word nie en die lêers kan nie herstel word nie.",
"image_format": "Formaat",
"image_format_description": "WebP produseer kleiner lêers as JPEG, maar is stadiger om te enkodeer.",
"image_fullsize_description": "Vol grote prent met geen metadata, gebruik wanner ingezoem",
"image_fullsize_enabled": "Skakel aan vol grote prent generasie",
"image_prefer_embedded_preview": "Verkies ingebedde voorskou",
"image_prefer_wide_gamut": "Verkies wide gamut",
"image_prefer_wide_gamut_setting_description": "Gebruik Display P3 vir kleinkiekies. Dit behou die lewendheid van beelde met wye kleurruimtes beter, maar beelde kan anders verskyn op ou apparate met 'n ou blaaierweergawe. sRGB-beelde gebruik steeds sRGB om kleurverskuiwings te voorkom.",
@@ -77,8 +88,99 @@
"job_concurrency": "{job} gelyktydigheid",
"job_created": "Taak gemaak",
"job_not_concurrency_safe": "Hierdie taak kan nie gelyktydig uitgevoer word nie.",
"job_settings": "Agtergrondtaakinstellings"
"job_settings": "Agtergrondtaakinstellings",
"job_settings_description": "Bestuur werkgelyktydigheid",
"job_status": "Werkstatus",
"library_created": "Biblioteek geskep: {library}",
"library_deleted": "Biblioteek verwyder",
"library_import_path_description": "Spesifiseer 'n leer om in te neem. Hierdie leer, en al die sub leers, gaan geskandeer for vir prente en videos.",
"library_scanning": "Periodieke Skandering",
"library_scanning_description": "Stel periodieke skandering van biblioteek in",
"library_scanning_enable_description": "Aktiveer periodieke biblioteekskandering",
"library_settings": "Eksterne Biblioteek",
"map_settings": "Kaart",
"migration_job": "Migrasie",
"oauth_settings": "OAuth",
"transcoding_acceleration_vaapi": "VAAPI"
},
"administration": "Administrasie",
"advanced": "Gevorderde",
"albums": "Albums",
"all": "Alle",
"anti_clockwise": "Anti-kloksgewys",
"archive": "Argief",
"asset_skipped": "Oorgeslaan",
"asset_uploaded": "Opgelaai",
"asset_uploading": "Oplaai…",
"assets": "Bates",
"back": "Terug",
"backward": "Agteruit",
"build": "Bou",
"camera": "Kamera",
"cancel": "Kanselleer",
"city": "Stad",
"clockwise": "Kloksgewys",
"close": "Maak toe",
"color": "Kleur",
"confirm": "Bevestig",
"contain": "Bevat",
"context": "Konteks",
"continue": "Gaan voort",
"country": "Land",
"cover": "Bedek",
"create": "Skep",
"created": "Geskep",
"dark": "Donker",
"day": "Dag",
"delete": "Verwyder",
"description": "Beskrywing",
"details": "Besonderhede",
"direction": "Rigting",
"discover": "Ontdek",
"documentation": "Dokumentasie",
"done": "Klaar",
"download": "Aflaai",
"download_settings": "Aflaai",
"duplicates": "Duplikate",
"duration": "Duur",
"edit": "Wysig",
"edited": "Gewysigd",
"search_by_description": "Soek by beskrywing",
"search_by_description_example": "Stapdag in Sapa"
"search_by_description_example": "Stapdag in Sapa",
"version": "Weergawe",
"version_announcement_closing": "Jou friend, Alex",
"version_history": "Weergawegeskiedenis",
"version_history_item": "{version} geinstaleerd op {date}",
"video": "Video",
"videos": "Video's",
"view": "Bekyk",
"view_album": "Bekyk Album",
"view_all": "Bekyk alle",
"view_all_users": "Bekyk alle gebruikers",
"view_in_timeline": "Bekyk in tydlyn",
"view_link": "Bekyk skakel",
"view_links": "Bekyk skakels",
"view_name": "Bekyk",
"view_next_asset": "Bekyk volgende bate",
"view_previous_asset": "Bekyk vorige bate",
"view_qr_code": "Bekyk QR-kode",
"view_stack": "Bekyk stapel",
"view_user": "Bekyk gebruiker",
"viewer_remove_from_stack": "Verwyder van stapel",
"viewer_stack_use_as_main_asset": "Gebruik as hoofbate",
"viewer_unstack": "Ontstapel",
"visibility_changed": "Sigbaarheid verander voor {count, plural, one {# person} other {# people}}",
"waiting": "Wag",
"warning": "Waaskuwing",
"week": "Week",
"welcome": "Welkom",
"welcome_to_immich": "Welkom by Immich",
"wifi_name": "Wi-Fi Naam",
"wrong_pin_code": "Verkeerde PIN-kode",
"year": "Jaar",
"years_ago": "{years, plural, one {# year} other {# years}} gelede",
"yes": "Ja",
"you_dont_have_any_shared_links": "Jy het geen gedeelde skakels",
"your_wifi_name": "Jou Wi-Fi naam",
"zoom_image": "Vergroot Prent"
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
"action": "Дзеянне",
"action_common_update": "Абнавіць",
"actions": "Дзеянні",
"active": "Актыўны",
"active": "Актыўных",
"activity": "Актыўнасць",
"activity_changed": "Актыўнасць {enabled, select, true {уключана} other {адключана}}",
"add": "Дадаць",
@@ -22,6 +22,7 @@
"add_partner": "Дадаць партнёра",
"add_path": "Дадаць шлях",
"add_photos": "Дадаць фота",
"add_tag": "Дадаць тэг",
"add_to": "Дадаць у…",
"add_to_album": "Дадаць у альбом",
"add_to_album_bottom_sheet_added": "Дададзена да {album}",
@@ -33,28 +34,30 @@
"added_to_favorites_count": "Дададзена {count, number} да абранага",
"admin": {
"add_exclusion_pattern_description": "Дадайце шаблоны выключэнняў. Падтрымліваецца выкарыстанне сімвалаў * , ** і ?. Каб ігнараваць усе файлы ў любой дырэкторыі з назвай \"Raw\", выкарыстоўвайце \"**/Raw/**\". Каб ігнараваць усе файлы, якія заканчваюцца на \".tif\", выкарыстоўвайце \"**/.tif\". Каб ігнараваць абсолютны шлях, выкарыстоўвайце \"/path/to/ignore/**\".",
"admin_user": "Адміністратар",
"asset_offline_description": "Гэты знешні бібліятэчны актыў больш не знойдзены на дыску і быў перамешчаны ў сметніцу. Калі файл быў перамешчаны ў межах бібліятэкі, праверце вашу хроніку для новага адпаведнага актыва. Каб аднавіць гэты актыў, пераканайцеся, што шлях да файла ніжэй даступны для Immich і адскануйце бібліятэку.",
"authentication_settings": "Налады праверкі сапраўднасці",
"authentication_settings_description": "Кіраванне паролямі, OAuth, і іншыя налады праверкі сапраўднасці",
"authentication_settings_disable_all": "Вы ўпэўнены, што жадаеце адключыць усе спосабы логіну? Логін будзе цалкам адключаны.",
"authentication_settings_reenable": "Каб зноў уключыць, выкарыстайце <link>Каманду сервера</link>.",
"background_task_job": "Фонавыя заданні",
"backup_database": "Рэзервовая копія базы даных",
"backup_database": "Стварыць рэзервовую копію базы даных",
"backup_database_enable_description": "Уключыць рэзерваванне базы даных",
"backup_keep_last_amount": "Колькасць папярэдніх рэзервовых копій для захавання",
"backup_settings": "Налады рэзервовага капіявання",
"backup_settings_description": "Кіраванне наладамі дампа базы дадзеных. Заўвага: гэтыя задачы не кантралююцца, і ў выпадку няўдачы паведамленне адпраўлена не будзе.",
"backup_settings_description": "Кіраванне наладамі рэзервавання базы даных.",
"cleared_jobs": "Ачышчаны заданні для: {job}",
"config_set_by_file": "Канфігурацыя ў зараз усталявана праз файл канфігурацыі",
"confirm_delete_library": "Вы ўпэўнены што жадаеце выдаліць {library} бібліятэку?",
"config_set_by_file": "Канфігурацыя зараз усталявана праз файл канфігурацыі",
"confirm_delete_library": "Вы ўпэўнены што жадаеце выдаліць бібліятэку {library}?",
"confirm_delete_library_assets": "Вы ўпэўнены, што хочаце выдаліць гэтую бібліятэку? Гэта прывядзе да выдалення {count, plural, one {# актыву} other {усіх # актываў}}, якія змяшчаюцца ў Immich, і гэта дзеянне немагчыма будзе адмяніць. Файлы застануцца на дыску.",
"confirm_email_below": "Каб пацвердзіць, увядзіце \"{email}\" ніжэй",
"confirm_reprocess_all_faces": "Вы ўпэўнены, што хочаце пераапрацаваць усе твары? Гэта таксама прывядзе да выдалення імя людзей.",
"confirm_user_password_reset": "Вы ўпэўнены ў тым, што жадаеце скінуць пароль {user}?",
"confirm_user_pin_code_reset": "Вы ўпэўнены ў тым, што жадаеце скінуць PIN-код {user}?",
"create_job": "Стварыць заданне",
"cron_expression": "Выраз Cron",
"cron_expression_description": "Усталюйце інтэрвал сканавання, выкарыстоўваючы фармат cron. Для атрымання дадатковай інфармацыі, калі ласка, звярніцеся, напрыклад, да <link>Crontab Guru</link>",
"cron_expression_presets": "Прадустановкі выразаў Cron",
"cron_expression_presets": "Прадустаноўкі выразаў Cron",
"disable_login": "Адключыць уваход",
"duplicate_detection_job_description": "Запусціць машыннае навучанне на актывах для выяўлення падобных выяў. Залежыць ад Smart Search",
"exclusion_pattern_description": "Шаблоны выключэння дазваляюць ігнараваць файлы і папкі пры сканаванні вашай бібліятэкі. Гэта карысна, калі ў вас ёсць папкі, якія змяшчаюць файлы, якія вы не хочаце імпартаваць, напрыклад, файлы RAW.",
@@ -71,15 +74,361 @@
"image_fullsize_enabled_description": "Ствараць выяву ў поўным памеры для фарматаў, што не прыдатныя для вэб. Калі ўключана опцыя \"Аддаваць перавагу ўбудаванай праяве\", прагляды выкарыстоўваюцца непасрэдна без канвертацыі. Не ўплывае на вэб-прыдатныя фарматы, такія як JPEG.",
"image_fullsize_quality_description": "Якасць выявы ў поўным памеры ад 1 да 100. Больш высокае значэнне лепшае, але прыводзіць да павелічэння памеру файла.",
"image_fullsize_title": "Налады выявы ў поўным памеры",
"image_prefer_embedded_preview": "Аддаваць перавагу ўбудаванай праяве",
"image_prefer_embedded_preview_setting_description": "Выкарыстоўваць убудаваныя праявы ў RAW-фотаздымках ў якасці ўваходных дадзеных для апрацоўкі малюнкаў, калі магчыма. Гэта дазваляе атрымаць больш дакладныя колеры для некаторых відарысаў, але ж якасць праяў залежыць ад камеры, і на відарысе можа быць больш артэфактаў сціску.",
"image_prefer_wide_gamut": "Аддаць перавагу шырокай гаме",
"image_preview_description": "Відарыс сярэдняга памеру з выдаленымі метададзенымі, выкарыстоўваецца пры праглядзе асобнага рэсурсу і для машыннага навучання",
"image_preview_quality_description": "Якасць праявы ад 1 да 100. Чым вышэй, тым лепш, але пры гэтым ствараюцца файлы большага памеру і можа знізіцца хуткасць водгуку прыкладання. Ўстаноўка нізкага значэння можа паўплываць на якасць машыннага навучання.",
"image_preview_title": "Налады папярэдняга прагляду",
"image_quality": "Якасць",
"image_resolution": "Раздзяляльнасць",
"image_settings": "Налады відарыса",
"image_settings_description": "Кіруйце якасцю і раздзяляльнасцю сгенерыраваных відарысаў"
"image_settings_description": "Кіруйце якасцю і раздзяляльнасцю сгенерыраваных відарысаў",
"library_created": "Створана бібліятэка: {library}",
"library_deleted": "Бібліятэка выдалена",
"map_dark_style": "Цёмны стыль",
"map_enable_description": "Уключыць функцыі карты",
"map_gps_settings": "Налады карты і GPS",
"map_light_style": "Светлы стыль",
"map_settings": "Карта",
"map_settings_description": "Кіраванне наладамі карты",
"map_style_description": "URL-адрас style.json тэмы карты",
"metadata_settings": "Налады метаданых",
"oauth_button_text": "Тэкст кнопкі",
"oauth_settings": "OAuth",
"refreshing_all_libraries": "Абнаўленне ўсіх бібліятэк",
"registration": "Рэгістрацыя адміністратара",
"registration_description": "Вы з'яўляецеся першым карыстальнікам сістэмы, таму вы будзеце прызначаны адміністратарам. Вы будзеце адказваць за адміністрацыйныя задачы, а таксама ствараць новых карыстальнікаў.",
"require_password_change_on_login": "Патрабаваць змяніць пароль пры першым уваходзе ў сістэму",
"reset_settings_to_default": "Скінуць налады да прадвызначаных",
"reset_settings_to_recent_saved": "Скінуць налады да нядаўна захаваных",
"scanning_library": "Сканіраванне бібліятэкі",
"server_external_domain_settings": "Знешні дамен",
"server_settings": "Налады сервера",
"server_settings_description": "Кіраванне наладамі сервера",
"server_welcome_message": "Прывітальнае паведамленне",
"server_welcome_message_description": "Паведамленне, якое адлюстроўваецца на старонцы ўваходу.",
"system_settings": "Сістэмныя налады",
"tag_cleanup_job": "Ачыстка тэгаў",
"template_email_preview": "Перадпрагляд",
"theme_settings": "Налады тэмы",
"transcoding_acceleration_nvenc": "NVENC (патрабуецца відэакарта NVIDIA)",
"transcoding_acceleration_vaapi": "VAAPI",
"transcoding_accepted_containers": "Прынятыя кантэйнеры",
"transcoding_accepted_video_codecs": "Прынятыя відэакодэкі",
"transcoding_advanced_options_description": "Параметры, якія большасці карыстальнікаў не трэба змяняць",
"transcoding_audio_codec": "Аудыякодэк",
"transcoding_encoding_options": "Параметры кадзіравання",
"transcoding_video_codec": "Відэакодэк",
"trash_enabled_description": "Уключыць функцыі сметніцы",
"trash_number_of_days": "Колькасць дзён",
"trash_settings": "Налады сметніцы",
"trash_settings_description": "Кіраванне наладамі сметніцы",
"user_cleanup_job": "Ачыстка карыстальніка",
"user_management": "Кіраванне карыстальнікамі",
"user_password_has_been_reset": "Пароль карыстальніка быў скінуты:",
"user_password_reset_description": "Задайце карыстальніку часовы пароль і паведаміце яму, што пры наступным уваходзе ў сістэму яму трэба будзе змяніць пароль.",
"user_restore_description": "Уліковы запіс карыстальніка <b>{user}</b> будзе адноўлены.",
"user_settings": "Налады карыстальніка",
"user_settings_description": "Кіраванне наладамі карыстальніка",
"user_successfully_removed": "Карыстальнік {email} быў паспяхова выдалены.",
"version_check_enabled_description": "Уключыць праверку версіі",
"version_check_implications": "Функцыі праверкі версіі перыядычна звяртаецца да github.com",
"version_check_settings": "Праверка версіі",
"version_check_settings_description": "Уключыць/адключыць апавяшчэнні аб новай версіі"
},
"admin_email": "Электронная пошта адміністратара",
"admin_password": "Пароль адміністратара",
"administration": "Кіраванне серверам",
"advanced": "Пашыраныя",
"advanced_settings_log_level_title": "Узровень вядзення журнала: {level}",
"advanced_settings_proxy_headers_title": "Загалоўкі проксі",
"advanced_settings_tile_subtitle": "Пашыраныя налады карыстальніка",
"advanced_settings_troubleshooting_subtitle": "Уключыць дадатковыя функцыі для выпраўлення непаладак",
"advanced_settings_troubleshooting_title": "Выпраўленне непаладак",
"age_months": "Узрост {months, plural, one {# месяц} few {# месяцы} many {# месяцаў} other {# месяцаў}}",
"age_year_months": "Узрост 1 год, {months, plural, one {# месяц} few {# месяцы} many {# месяцаў} other {# месяцаў}}",
"age_years": "{years, plural, other {Узрост #}}",
"album_added": "Альбом дададзены",
"album_cover_updated": "Вокладка альбома абноўлена",
"album_delete_confirmation": "Вы ўпэўнены, што хочаце выдаліць альбом {album}?",
"album_delete_confirmation_description": "Калі гэты альбом абагулены, іншыя карыстальнікі больш не змогуць атрымаць да яго доступ.",
"album_deleted": "Альбом выдалены",
"album_info_card_backup_album_excluded": "ВЫКЛЮЧАНЫ",
"album_info_card_backup_album_included": "УКЛЮЧАНЫ",
"album_info_updated": "Інфармацыя пра альбом абноўлена",
"album_leave": "Пакінуць альбом?",
"album_leave_confirmation": "Вы ўпэўнены, што хочаце пакінуць {album}?",
"album_name": "Назва альбома",
"album_options": "Параметры альбома",
"album_remove_user": "Выдаліць карыстальніка?",
"album_remove_user_confirmation": "Вы ўпэўнены, што хочаце выдаліць {user}?",
"album_search_not_found": "Па вашым запыце не знойдзена альбомаў",
"album_share_no_users": "Здаецца, вы падзяліліся гэтым альбомам з усімі карыстальнікамі, або ў вас няма ніводнага карыстальніка, з якім можна падзяліцца.",
"album_updated": "Альбом абноўлены",
"album_user_left": "Вы пакінулі {album}",
"album_user_removed": "Карыстальнік {user} выдалены",
"album_viewer_appbar_delete_confirm": "Вы ўпэўнены, што хочаце выдаліць гэты альбом са свайго ўліковага запісу?",
"album_viewer_appbar_share_err_delete": "Не ўдалося выдаліць альбом",
"album_viewer_appbar_share_err_leave": "Не ўдалося пакінуць альбом",
"album_viewer_appbar_share_err_title": "Не ўдалося змяніць назву альбома",
"album_viewer_appbar_share_leave": "Пакінуць альбом",
"album_viewer_appbar_share_to": "Абагуліць з",
"album_viewer_page_share_add_users": "Дадаць карыстальнікаў",
"album_with_link_access": "Дазволіць усім, хто мае спасылку, бачыць фота і людзей у гэтым альбоме.",
"albums": "Альбомы",
"albums_count": "{count, plural, one {1 альбом} few {{count, number} альбомы} many {{count, number} альбомаў} other {{count, number} альбомаў}}",
"albums_default_sort_order": "Прадвызначаны парадак сартавання альбомаў",
"albums_on_device_count": "Альбомы на прыладзе ({count})",
"all": "Усе",
"all_albums": "Усе альбомы",
"all_people": "Усе людзі",
"all_videos": "Усе відэа",
"allow_dark_mode": "Дазволіць цёмны рэжым",
"allow_edits": "Дазволіць рэдагаванне",
"alt_text_qr_code": "Відарыс QR-кода",
"anti_clockwise": "Супраць гадзіннікавай стрэлкі",
"api_key": "Ключ API",
"api_key_empty": "Назва ключа API не павінна быць пустой",
"api_keys": "Ключы API",
"app_bar_signout_dialog_content": "Вы ўпэўнены, што хочаце выйсці?",
"app_bar_signout_dialog_ok": "Так",
"app_bar_signout_dialog_title": "Выйсці",
"app_settings": "Налады праграмы",
"archive": "Архіў",
"archive_page_title": "Архіў ({count})",
"archive_size": "Памер архіва",
"are_these_the_same_person": "Ці гэта адзін і той жа чалавек?",
"are_you_sure_to_do_this": "Вы ўпэўнены, што хочаце гэта зрабіць?",
"asset_added_to_album": "Дададзена ў альбом",
"asset_adding_to_album": "Дадаванне ў альбом…",
"asset_skipped": "Прапушчана",
"asset_skipped_in_trash": "У сметніцы",
"asset_uploaded": "Запампавана",
"asset_uploading": "Запампоўванне…",
"authorized_devices": "Аўтарызаваныя прылады",
"back": "Назад",
"backup_album_selection_page_albums_device": "Альбомы на прыладзе ({count})",
"backup_all": "Усе",
"backup_controller_page_background_wifi": "Толькі праз Wi-Fi",
"buy": "Купіць Immich",
"cache_settings_clear_cache_button": "Ачысціць кэш",
"cache_settings_tile_title": "Лакальнае сховішча",
"cancel": "Скасаваць",
"cancel_search": "Скасаваць пошук",
"canceled": "Скасавана",
"city": "Горад",
"clear": "Ачысціць",
"clear_all": "Ачысціць усё",
"client_cert_dialog_msg_confirm": "ОК",
"client_cert_enter_password": "Увядзіце пароль",
"client_cert_import": "Імпарт",
"close": "Закрыць",
"collapse": "Згарнуць",
"collapse_all": "Згарнуць усё",
"color": "Колер",
"color_theme": "Колеравая тэма",
"continue": "Працягнуць",
"control_bottom_app_bar_create_new_album": "Стварыць новы альбом",
"control_bottom_app_bar_delete_from_immich": "Выдаліць з Immich",
"control_bottom_app_bar_delete_from_local": "Выдаліць з прылады",
"control_bottom_app_bar_edit_location": "Рэдагаваць месцазнаходжанне",
"country": "Краіна",
"cover": "Вокладка",
"covers": "Вокладкі",
"create": "Стварыць",
"create_album": "Стварыць альбом",
"create_album_page_untitled": "Без назвы",
"create_library": "Стварыць бібліятэку",
"create_link": "Стварыць спасылку",
"create_new_user": "Стварыць новага карыстальніка",
"create_tag": "Стварыць тэг",
"create_user": "Стварыць карыстальніка",
"dark": "Цёмная",
"day": "Дзень",
"delete": "Выдаліць",
"delete_album": "Выдаліць альбом",
"delete_dialog_ok_force": "Усё адно выдаліць",
"delete_dialog_title": "Выдаліць назаўжды",
"delete_face": "Выдаліць твар",
"delete_key": "Выдаліць ключ",
"delete_library": "Выдаліць бібліятэку",
"delete_link": "Выдаліць спасылку",
"delete_local_dialog_ok_force": "Усё адно выдаліць",
"delete_others": "Выдаліць іншыя",
"delete_tag": "Выдаліць тэг",
"delete_user": "Выдаліць карыстальніка",
"discord": "Discord",
"documentation": "Дакументацыя",
"done": "Гатова",
"download": "Спампаваць",
"download_canceled": "Спампоўванне скасавана",
"download_complete": "Спампоўванне завершана",
"download_enqueue": "Спампоўванне дададзена ў чаргу",
"downloading": "Спампоўванне",
"edit": "Рэдагаваць",
"edit_album": "Рэдагаваць альбом",
"edit_avatar": "Рэдагаваць аватар",
"edit_date": "Рэдагаваць дату",
"edit_date_and_time": "Рэдагаваь дату і час",
"edit_description": "Рэдагаваць апісанне",
"edit_description_prompt": "Выберыце новае апісанне:",
"edit_faces": "Рэдагаваць твары",
"edit_import_path": "Рэдагаваць шлях імпарту",
"edit_import_paths": "Рэдагаваць шляхі імпарту",
"edit_key": "Рэдагаваць ключ",
"edit_link": "Рэдагаваць спасылку",
"edit_location": "Рэдагаваць месцазнаходжанне",
"edit_location_dialog_title": "Месцазнаходжанне",
"edit_name": "Рэдагаваць назву",
"edit_people": "Рэдагаваць людзей",
"edit_tag": "Рэдагаваць тэг",
"edit_title": "Рэдагаваць загаловак",
"edit_user": "Рэдагаваць карыстальніка",
"edited": "Адрэдагавана",
"editor": "Рэдактар",
"editor_close_without_save_prompt": "Змены не будуць захаваны",
"editor_close_without_save_title": "Закрыць рэдактар?",
"editor_crop_tool_h2_aspect_ratios": "Суадносіны бакоў",
"editor_crop_tool_h2_rotation": "Паварот",
"error": "Памылка",
"error_saving_image": "Памылка: {error}",
"exif": "Exif",
"exif_bottom_sheet_description": "Дадаць апісанне...",
"favorite": "У абраным",
"favorite_or_unfavorite_photo": "Дадаць або выдаліць фота з абранага",
"favorites": "Абраныя",
"file_name": "Назва файла",
"filename": "Назва файла",
"filetype": "Тып файла",
"filter": "Фільтр",
"forward": "Наперад",
"gcast_enabled": "Google Cast",
"general": "Агульныя",
"go_back": "Назад",
"go_to_folder": "Перайсці да папкі",
"hi_user": "Вітаем, {name} ({email})",
"hide_all_people": "Схаваць усіх людзей",
"hide_gallery": "Схаваць галерэю",
"hide_named_person": "Схаваць {name}",
"hide_password": "Схаваць пароль",
"hide_person": "Схаваць чалавека",
"image_viewer_page_state_provider_download_started": "Спампоўванне пачалося",
"immich_logo": "Лагатып Immich",
"interval": {
"day_at_onepm": "Кожны дзень а 13-й гадзіне",
"hours": "{hours, plural, one {Кожную гадзіну} few {Кожныя {hours, number} гадзіны} many {Кожныя {hours, number} гадзін} other {Кожныя {hours, number} гадзін}}",
"night_at_midnight": "Кожную ноч апоўначы",
"night_at_twoam": "Кожную ноч а 2-й гадзіне"
},
"language": "Мова",
"library": "Бібліятэка",
"light": "Светлая",
"login_form_back_button_text": "Назад",
"login_form_email_hint": "youremail@email.com",
"login_form_endpoint_hint": "http://your-server-ip:port",
"login_form_password_hint": "пароль",
"login_form_save_login": "Заставацца ў сістэме",
"main_menu": "Галоўнае меню",
"map_location_dialog_yes": "Так",
"map_settings_dark_mode": "Цёмны рэжым",
"map_settings_date_range_option_day": "Апошнія 24 гадзіны",
"map_settings_date_range_option_days": "Апошніх дзён: {days}",
"map_settings_date_range_option_year": "Апошні год",
"map_settings_date_range_option_years": "Апошніх год: {years}",
"map_settings_dialog_title": "Налады карты",
"map_settings_theme_settings": "Тэма карты",
"menu": "Меню",
"minute": "Хвіліна",
"month": "Месяц",
"monthly_title_text_date_format": "MMMM y",
"my_albums": "Мае альбомы",
"name": "Імя",
"name_or_nickname": "Імя або псеўданім",
"next": "Далей",
"no": "Не",
"offline": "Па-за сеткай",
"ok": "ОК",
"online": "У сетцы",
"open": "Адкрыць",
"or": "або",
"partner_list_user_photos": "Фота карыстальніка {user}",
"pause": "Прыпыніць",
"people": "Людзі",
"permission_onboarding_back": "Назад",
"permission_onboarding_continue_anyway": "Усё адно працягнуць",
"photos": "Фота",
"photos_and_videos": "Фота і відэа",
"place": "Месца",
"places": "Месцы",
"port": "Порт",
"previous": "Папярэдняе",
"profile": "Профіль",
"profile_drawer_app_logs": "Журналы",
"profile_drawer_github": "GitHub",
"purchase_button_buy": "Купіць",
"purchase_button_buy_immich": "Купіць Immich",
"purchase_button_select": "Выбраць",
"remove": "Выдаліць",
"remove_from_album": "Выдаліць з альбома",
"remove_from_favorites": "Выдаліць з абраных",
"remove_tag": "Выдаліць тэг",
"remove_url": "Выдаліць URL-адрас",
"remove_user": "Выдаліць карыстальніка",
"rename": "Перайменаваць",
"repository": "Рэпазіторый",
"reset": "Скінуць",
"reset_password": "Скінуць пароль",
"restore": "Аднавіць",
"restore_all": "Аднавіць усё",
"restore_user": "Аднавіць карыстальніка",
"resume": "Узнавіць",
"role": "Роля",
"role_editor": "Рэдактар",
"role_viewer": "Глядач",
"save": "Захаваць",
"save_to_gallery": "Захаваць у галерэю",
"search_filter_date": "Дата",
"search_filter_location": "Месцазнаходжанне",
"search_filter_location_title": "Выберыце месцазнаходжанне",
"search_filter_media_type": "Тып медыя",
"search_filter_media_type_title": "Выберыце тып медыя",
"search_page_screenshots": "Здымкі экрана",
"search_page_selfies": "Сэлфі",
"search_page_things": "Рэчы",
"search_page_your_map": "Ваша карта",
"second": "Секунда",
"send_message": "Адправіць паведамленне",
"setting_languages_apply": "Ужыць",
"setting_notifications_notify_never": "ніколі",
"settings": "Налады",
"share_add_photos": "Дадаць фота",
"shared_album_section_people_title": "ЛЮДЗІ",
"shared_link_info_chip_metadata": "EXIF",
"sharing_page_empty_list": "ПУСТЫ СПІС",
"sign_out": "Выйсці",
"sign_up": "Зарэгістравацца",
"size": "Памер",
"sort_title": "Загаловак",
"source": "Крыніца",
"tag": "Тэг",
"tags": "Тэгі",
"theme": "Тэма",
"theme_selection": "Выбар тэмы",
"timeline": "Хроніка",
"total": "Усяго",
"trash": "Сметніца",
"trash_page_delete_all": "Выдаліць усе",
"trash_page_restore_all": "Аднавіць усе",
"trash_page_title": "Сметніца ({count})",
"type": "Тып",
"undo": "Адрабіць",
"upload": "Запампаваць",
"upload_status_errors": "Памылкі",
"uploading": "Запампоўванне",
"url": "URL-адрас",
"user": "Карыстальнік",
"user_has_been_deleted": "Гэты карыстальнік быў выдалены.",
"user_id": "ID карыстальніка",
"user_purchase_settings": "Купля",
"user_purchase_settings_description": "Кіруйце пакупкамі",
@@ -112,14 +461,14 @@
"view_next_asset": "Паказаць наступны аб'ект",
"view_previous_asset": "Праглядзець папярэдні аб'ект",
"view_stack": "Прагляд стэка",
"visibility_changed": "Відзімасць змянілася для {count, plural, one {# чалавек(-аў)} астатніх {# чалавек}}",
"visibility_changed": "Бачнасць змянілася для {count, plural, one {# чалавека} other {# чалавек}}",
"waiting": "Чакаюць",
"warning": "Папярэджанне",
"week": "Тыдзень",
"welcome": "Вітаем",
"welcome_to_immich": "Вітаем у Immich",
"year": "Год",
"years_ago": "{years, plural, one {# год} other {# гадоў}} таму",
"years_ago": "{years, plural, one {# год} few {# гады} many {# гадоў} other {# гадоў}} таму",
"yes": "Так",
"you_dont_have_any_shared_links": "У вас няма абагуленых спасылак",
"zoom_image": "Павялічыць відарыс"

View File

@@ -166,6 +166,20 @@
"metadata_settings_description": "Управление на настройките за метаданни",
"migration_job": "Миграция",
"migration_job_description": "Мигриране на миниатюрите за елементи и лица към най-новата структура на папките",
"nightly_tasks_cluster_faces_setting_description": "Изпълни разпознаване на лице за открити нови лица",
"nightly_tasks_cluster_new_faces_setting": "Разпознаване на нови лица",
"nightly_tasks_database_cleanup_setting": "Задачи по почистване на базата данни",
"nightly_tasks_database_cleanup_setting_description": "Премахни стари, ненужни записи от базата данни",
"nightly_tasks_generate_memories_setting": "Създаване на спомени",
"nightly_tasks_generate_memories_setting_description": "Създаване на нови спомени от съществуващи обекти",
"nightly_tasks_missing_thumbnails_setting": "Генериране на липсващи миниатюри",
"nightly_tasks_missing_thumbnails_setting_description": "Добавяне на обекти без миниатюра в опашката за създаване на миниатюра",
"nightly_tasks_settings": "Настройка на задачи за през нощта",
"nightly_tasks_settings_description": "Управление на задачите, изпълнявани през нощта",
"nightly_tasks_start_time_setting": "Време за начало",
"nightly_tasks_start_time_setting_description": "Време, когато сървъра ще започне изпълнение на нощни задачи",
"nightly_tasks_sync_quota_usage_setting": "Квота за синхронизация",
"nightly_tasks_sync_quota_usage_setting_description": "Обновяване на квотата според текущото потребление",
"no_paths_added": "Няма добавени пътища",
"no_pattern_added": "Няма добавен модел",
"note_apply_storage_label_previous_assets": "Забележка: За да приложите етикета за съхранение към предварително качени файлове, стартирайте",
@@ -196,6 +210,8 @@
"oauth_mobile_redirect_uri": "URI за мобилно пренасочване",
"oauth_mobile_redirect_uri_override": "URI пренасочване за мобилни устройства",
"oauth_mobile_redirect_uri_override_description": "Разреши когато доставчика за OAuth удостоверяване не позволява за мобилни URI идентификатори, като ''{callback}''",
"oauth_role_claim": "Потвърждение на роля",
"oauth_role_claim_description": "Автоматично предоставяне на административни права при наличие на това потвържение. Потвърждението може да има стойност 'user' или 'admin'.",
"oauth_settings": "OAuth",
"oauth_settings_description": "Управление на настройките за вход с OAuth",
"oauth_settings_more_details": "За повече информация за функционалността, се потърсете в <link>docs</link>.",
@@ -357,6 +373,8 @@
"admin_password": "Администраторска парола",
"administration": "Администрация",
"advanced": "Разширено",
"advanced_settings_beta_timeline_subtitle": "Опитайте новите функции на приложението",
"advanced_settings_beta_timeline_title": "Бета версия на времевата линия",
"advanced_settings_enable_alternate_media_filter_subtitle": "При синхронизация, използвайте тази опция като филтър, основан на промяна на даден критерии. Опитайте само в случай, че приложението има проблем с откриване на всички албуми.",
"advanced_settings_enable_alternate_media_filter_title": "[ЕКСПЕРИМЕНТАЛНО] Използвай филтъра на алтернативното устройство за синхронизация на албуми",
"advanced_settings_log_level_title": "Ниво на запис в дневника: {level}",
@@ -427,6 +445,7 @@
"app_settings": "Настройки ма приложението",
"appears_in": "Излиза в",
"archive": "Архив",
"archive_action_prompt": "{count} са добавени в Архива",
"archive_or_unarchive_photo": "Архивиране или деархивиране на снимка",
"archive_page_no_archived_assets": "Не са намерени обекти в архива",
"archive_page_title": "Архив ({count})",
@@ -464,7 +483,6 @@
"assets": "Елементи",
"assets_added_count": "Добавено {count, plural, one {# asset} other {# assets}}",
"assets_added_to_album_count": "Добавен(и) са {count, plural, one {# актив} other {# актива}} в албума",
"assets_added_to_name_count": "Добавен(и) са {count, plural, one {# актив} other {# актива}} към {hasName, select, true {<b>{name}</b>} other {нов албум}}",
"assets_cannot_be_added_to_album_count": "{count, plural, one {Обекта не може да се добави} other {Обектите не може да се добавят}} в албума",
"assets_count": "{count, plural, one {# актив} other {# актива}}",
"assets_deleted_permanently": "{count} обекта са изтрити завинаги",
@@ -490,6 +508,7 @@
"back_close_deselect": "Назад, затваряне или премахване на избора",
"background_location_permission": "Разрешение за достъп до местоположението във фонов режим",
"background_location_permission_content": "За да може да чете имената на Wi-Fi мрежите и да ги превключва при работа във фонов режим, Immich трябва *винаги* да има достъп до точното местоположение",
"backup": "Архивиране",
"backup_album_selection_page_albums_device": "Албуми на устройството ({count})",
"backup_album_selection_page_albums_tap": "Натисни за да включиш, двойно за да изключиш",
"backup_album_selection_page_assets_scatter": "Обектите могат да бъдат разпръснати в няколко албума. По този начин албумите могат да бъдат включени или изключени по време на процеса на архивиране.",
@@ -703,7 +722,7 @@
"daily_title_text_date": "E, dd MMM",
"daily_title_text_date_year": "E, dd MMM yyyy",
"dark": "Тъмен",
"darkTheme": "Превключи на тъмна тема",
"dark_theme": "Тъмна тема",
"date_after": "Дата след",
"date_and_time": "Дата и час",
"date_before": "Дата преди",
@@ -719,6 +738,7 @@
"default_locale": "Локализация по подразбиране",
"default_locale_description": "Форматиране на дати и числа в зависимост от езиковата настройка на браузъра",
"delete": "Изтрий",
"delete_action_prompt": "{count} са изтрити завинаги",
"delete_album": "Изтрий албум",
"delete_api_key_prompt": "Сигурни ли сте, че искате да изтриете този API ключ?",
"delete_dialog_alert": "Тези обекти ще бъдат изтрити завинаги и от Immich сървъра и от устройството",
@@ -732,19 +752,20 @@
"delete_key": "Изтрий ключ",
"delete_library": "Изтрий библиотека",
"delete_link": "Изтрий линк",
"delete_local_action_prompt": "{count} са изтрити локално",
"delete_local_dialog_ok_backed_up_only": "Изтрий локално само архивираните",
"delete_local_dialog_ok_force": "Въпреки това изтрий",
"delete_others": "Изтрий останалите",
"delete_shared_link": "Изтриване на споделен линк",
"delete_shared_link_dialog_title": "Изтрий споделената връзка",
"delete_tag": "Изтрий таг",
"delete_tag_confirmation_prompt": "Сигурни ли сте, че искате да изтриете таг {tagName}?",
"delete_tag_confirmation_prompt": "Сигурни ли сте, че искате да изтриете тага {tagName}?",
"delete_user": "Изтрий потребител",
"deleted_shared_link": "Изтрит споделен линк",
"deletes_missing_assets": "Изтрива файлове, които липсват на диска",
"description": "Описание",
"description_input_hint_text": "Добави описание...",
"description_input_submit_error": "Неуспешно обновяване на описанието. За подробности виж в дневника",
"description_input_submit_error": "Неуспешно обновяване на описанието. За подробности вижте в дневника",
"details": "Детайли",
"direction": "Посока",
"disabled": "Изключено",
@@ -762,6 +783,7 @@
"documentation": "Документация",
"done": "Готово",
"download": "Изтегли",
"download_action_prompt": "Зареждане на {count} обекта",
"download_canceled": "Изтеглянето е отменено",
"download_complete": "Изтеглянето завърши",
"download_enqueue": "Изтеглянето е добавено в опашката",
@@ -799,6 +821,7 @@
"edit_key": "Редактиране на ключ",
"edit_link": "Редактиране на линк",
"edit_location": "Редактиране на местоположението",
"edit_location_action_prompt": "{count} локации са редактирани",
"edit_location_dialog_title": "Местоположение",
"edit_name": "Редактиране на име",
"edit_people": "Редактиране на хора",
@@ -984,6 +1007,7 @@
"failed_to_load_assets": "Неуспешно зареждане на елементи",
"failed_to_load_folder": "Неуспешно зареждане на папка",
"favorite": "Любим",
"favorite_action_prompt": "{count} са добавени в Любими",
"favorite_or_unfavorite_photo": "Добави или премахни снимка от Любими",
"favorites": "Любими",
"favorites_page_no_favorites": "Не са намерени любими обекти",
@@ -1127,10 +1151,10 @@
"library_page_sort_created": "Дата на създаване",
"library_page_sort_last_modified": "Последна промяна",
"library_page_sort_title": "Заглавие на албума",
"licenses": "Лицензи",
"light": "Светло",
"like_deleted": "Като изтрит",
"link_motion_video": "Линк към видео",
"link_options": "Опции на линк за споделяне",
"link_to_oauth": "Линк към OAuth",
"linked_oauth_account": "Свързан OAuth акаунт",
"list": "Лист",
@@ -1193,7 +1217,6 @@
"manage_your_devices": "Управление на влезлите в системата устройства",
"manage_your_oauth_connection": "Управление на OAuth връзката",
"map": "Карта",
"map_assets_in_bound": "{count} снимки",
"map_assets_in_bounds": "{count} снимки",
"map_cannot_get_user_location": "Не можах да получа местоположението",
"map_location_dialog_yes": "Да",
@@ -1246,6 +1269,7 @@
"more": "Още",
"move": "Премести",
"move_off_locked_folder": "Извади от заключената папка",
"move_to_lock_folder_action_prompt": "{count} са добавени в заключената папка",
"move_to_locked_folder": "Премести в заключена папка",
"move_to_locked_folder_confirmation": "Тези снимки и видеа ще бъдат изтрити от всички албуми и ще са достъпни само в заключената папка",
"moved_to_archive": "{count, plural, one {# обект е преместен} many {# обекта са преместени} other {# обекта са преместени}} в архива",
@@ -1495,7 +1519,9 @@
"remove_custom_date_range": "Премахни зададения диапазон от дати",
"remove_deleted_assets": "Премахни Изтритите Елементи",
"remove_from_album": "Премахни от албума",
"remove_from_album_action_prompt": "{count} са премахнати от албума",
"remove_from_favorites": "Премахни от Любими",
"remove_from_lock_folder_action_prompt": "{count} са премахнати от заключената папка",
"remove_from_locked_folder": "Махни от заключената папка",
"remove_from_locked_folder_confirmation": "Сигурни ли си, че искате тези снимки и видеа да бъдат извадени от заключената папка? Те ще бъдат видими в библиотеката.",
"remove_from_shared_link": "Премахни от споделения линк",
@@ -1667,6 +1693,7 @@
"settings_saved": "Настройките са запазени",
"setup_pin_code": "Задай PIN код",
"share": "Споделяне",
"share_action_prompt": "{count} споделени обекта",
"share_add_photos": "Добави снимки",
"share_assets_selected": "{count} избрани",
"share_dialog_preparing": "Подготовка...",
@@ -1768,6 +1795,7 @@
"sort_title": "Заглавие",
"source": "Код",
"stack": "Събери",
"stack_action_prompt": "{count} са групирани",
"stack_duplicates": "Подреждане на дубликати",
"stack_select_one_photo": "Избери една главна снимка за събраните снимки",
"stack_selected_photos": "Подреждане на избрани снимки",
@@ -1838,6 +1866,7 @@
"total": "Общо",
"total_usage": "Общо използвано",
"trash": "Кошче",
"trash_action_prompt": "{count} са преместени в коша",
"trash_all": "Изхвърли всички",
"trash_count": "В Кошчето {count, number}",
"trash_delete_asset": "Вкарай в Кошчето/Изтрий елемент",
@@ -1855,9 +1884,11 @@
"unable_to_change_pin_code": "Невъзможна промяна на PIN кода",
"unable_to_setup_pin_code": "Неуспешно задаване на PIN кода",
"unarchive": "Разархивирай",
"unarchive_action_prompt": "{count} са премахнати от Архива",
"unarchived_count": "{count, plural, other {Неархивирани #}}",
"undo": "Отмени",
"unfavorite": "Премахване от любимите",
"unfavorite_action_prompt": "{count} са премахнати от Любими",
"unhide_person": "Покажи отново човека",
"unknown": "Неизвестно",
"unknown_country": "Непозната Държава",
@@ -1875,7 +1906,9 @@
"unselect_all_duplicates": "От маркирай всички дубликати",
"unselect_all_in": "Премахни избора на всички от групата {group}",
"unstack": "Разкачи",
"unstack_action_prompt": "{count} са разгрупирани",
"unstacked_assets_count": "Разкачени {count, plural, one {# елемент} other {# елементи}}",
"untagged": "Немаркирани",
"up_next": "Следващ",
"updated_at": "Обновено",
"updated_password": "Паролата е актуализирана",

View File

@@ -8,6 +8,7 @@
"actions": "কর্ম",
"active": "সচল",
"activity": "কার্যকলাপ",
"activity_changed": "একটিভিটি এখন {enabled, select, true {চালু} other {বন্ধ}} আছে",
"add": "যোগ করুন",
"add_a_description": "একটি বিবরণ যোগ করুন",
"add_a_location": "একটি অবস্থান যোগ করুন",
@@ -15,5 +16,84 @@
"add_a_title": "একটি শিরোনাম যোগ করুন",
"add_endpoint": "এন্ডপয়েন্ট যোগ করুন",
"add_exclusion_pattern": "বহির্ভূতকরণ নমুনা",
"add_url": "লিঙ্ক যোগ করুন"
"add_import_path": "ইমপোর্ট করার পাথ যুক্ত করুন",
"add_location": "অবস্থান যুক্ত করুন",
"add_more_users": "আরো ব্যবহারকারী যুক্ত করুন",
"add_partner": "অংশীদার যোগ করুন",
"add_path": "পাথ যুক্ত করুন",
"add_photos": "ছবি যুক্ত করুন",
"add_tag": "ট্যাগ যুক্ত করুন",
"add_to": "যুক্ত করুন…",
"add_to_album": "এলবাম এ যোগ করুন",
"add_to_album_bottom_sheet_added": "{album} এ যোগ করা হয়েছে",
"add_to_album_bottom_sheet_already_exists": "{album} এ আগে থেকেই আছে",
"add_to_shared_album": "শেয়ার করা অ্যালবামে যোগ করুন",
"add_url": "লিঙ্ক যোগ করুন",
"added_to_archive": "আর্কাইভ এ যোগ করা হয়েছে",
"added_to_favorites": "ফেভারিটে যোগ করা হয়েছে",
"added_to_favorites_count": "পছন্দের তালিকায় {count, number} যোগ করা হয়েছে",
"admin": {
"add_exclusion_pattern_description": "এক্সক্লুশন প্যাটার্ন যোগ করুন। *, **, এবং ? ব্যবহার করে গ্লোবিং করা সম্ভব। \"Raw\" নামের যেকোনো ডিরেক্টরিতে থাকা সমস্ত ফাইল বাদ দিতে \"**/Raw/**\" ব্যবহার করুন। \".tif\" দিয়ে শেষ হওয়া সমস্ত ফাইল বাদ দিতে \"**/*.tif\" ব্যবহার করুন। একটি সম্পূর্ণ পাথ বাদ দিতে, \"/path/to/ignore/**\" ব্যবহার করুন।",
"admin_user": "এডমিন ইউজার",
"asset_offline_description": "এই বহিরাগত লাইব্রেরি সম্পদটি আর ডিস্কে পাওয়া যাচ্ছে না এবং ট্র্যাশে সরানো হয়েছে। যদি ফাইলটি লাইব্রেরির মধ্যে সরানো হয়ে থাকে, তাহলে নতুন সংশ্লিষ্ট সম্পদের জন্য আপনার টাইমলাইন পরীক্ষা করুন। এই সম্পদটি পুনরুদ্ধার করতে, দয়া করে নিশ্চিত করুন যে নীচের ফাইল পাথটি Immich দ্বারা অ্যাক্সেস করা যেতে পারে এবং লাইব্রেরিটি স্ক্যান করুন।",
"authentication_settings": "প্রমাণীকরণ সেটিংস",
"authentication_settings_description": "পাসওয়ার্ড, OAuth এবং অন্যান্য প্রমাণীকরণ সেটিংস পরিচালনা করুন",
"authentication_settings_disable_all": "আপনি কি নিশ্চিত যে আপনি সমস্ত লগইন পদ্ধতি অক্ষম করতে চান? লগইন সম্পূর্ণরূপে অক্ষম করা হবে।",
"authentication_settings_reenable": "পুনরায় সক্ষম করতে, একটি <link>সার্ভার কমান্ড</link> ব্যবহার করুন।",
"background_task_job": "ব্যাকগ্রাউন্ড টাস্ক",
"backup_database": "ডাটাবেস ডাম্প তৈরি করুন",
"backup_database_enable_description": "ডাটাবেস ডাম্প সক্রিয় করুন",
"backup_keep_last_amount": "আগের ডাম্পের পরিমাণ রাখা হবে",
"backup_settings": "ডাটাবেস ডাম্প সেটিংস",
"backup_settings_description": "ডাটাবেস ডাম্প সেটিংস পরিচালনা করুন।",
"cleared_jobs": "{job} এর জন্য jobs খালি করা হয়েছে",
"config_set_by_file": "কনফিগ বর্তমানে একটি কনফিগ ফাইল দ্বারা সেট করা আছে",
"confirm_delete_library": "আপনি কি নিশ্চিত যে আপনি {library} লাইব্রেরি মুছে ফেলতে চান?",
"confirm_delete_library_assets": "আপনি কি নিশ্চিত যে আপনি এই লাইব্রেরিটি মুছে ফেলতে চান? এটি Immich থেকে {count, plural, one {# contained asset} other {all # contained asset}} মুছে ফেলবে এবং পূর্বাবস্থায় ফেরানো যাবে না। ফাইলগুলি ডিস্কে থাকবে।",
"confirm_email_below": "নিশ্চিত করতে, নিচে \"{email}\" টাইপ করুন",
"confirm_reprocess_all_faces": "আপনি কি নিশ্চিত যে আপনি সমস্ত মুখ পুনরায় প্রক্রিয়া করতে চান? এটি নামযুক্ত ব্যক্তিদেরও মুছে ফেলবে।",
"confirm_user_password_reset": "আপনি কি নিশ্চিত যে আপনি {user} এর পাসওয়ার্ড রিসেট করতে চান?",
"confirm_user_pin_code_reset": "আপনি কি নিশ্চিত যে আপনি {user} এর পিন কোড রিসেট করতে চান?",
"create_job": "job তৈরি করুন",
"cron_expression": "ক্রোন এক্সপ্রেশন",
"cron_expression_description": "ক্রোন ফর্ম্যাট ব্যবহার করে স্ক্যানিং ব্যবধান সেট করুন। আরও তথ্যের জন্য দয়া করে দেখুন যেমন <link>Crontab Guru</link>",
"cron_expression_presets": "ক্রোন এক্সপ্রেশন প্রিসেট",
"disable_login": "লগইন অক্ষম করুন",
"duplicate_detection_job_description": "অনুরূপ ছবি সনাক্ত করতে সম্পদগুলিতে মেশিন লার্নিং চালান। স্মার্ট অনুসন্ধানের উপর নির্ভর করে",
"exclusion_pattern_description": "এক্সক্লুশন প্যাটার্ন ব্যবহার করে আপনি আপনার লাইব্রেরি স্ক্যান করার সময় ফাইল এবং ফোল্ডারগুলিকে উপেক্ষা করতে পারবেন। যদি আপনার এমন ফোল্ডার থাকে যেখানে এমন ফাইল থাকে যা আপনি আমদানি করতে চান না, যেমন RAW ফাইল।",
"external_library_management": "বহিরাগত গ্রন্থাগার ব্যবস্থাপনা",
"face_detection": "মুখ সনাক্তকরণ",
"face_detection_description": "মেশিন লার্নিং ব্যবহার করে অ্যাসেটে থাকা মুখ/চেহারা গুলি সনাক্ত করুন। ভিডিও গুলির জন্য, শুধুমাত্র থাম্বনেইল বিবেচনা করা হয়। \"রিফ্রেশ\" (পুনরায়) সমস্ত অ্যাসেট প্রক্রিয়া করে। \"রিসেট\" করার মাধ্যমে অতিরিক্তভাবে সমস্ত বর্তমান মুখের ডেটা সাফ করে। \"অনুপস্থিত\" অ্যাসেটগুলিকে সারিবদ্ধ করে যা এখনও প্রক্রিয়া করা হয়নি। সনাক্ত করা মুখগুলিকে ফেসিয়াল রিকগনিশনের জন্য সারিবদ্ধ করা হবে, ফেসিয়াল ডিটেকশন সম্পূর্ণ হওয়ার পরে, বিদ্যমান বা নতুন ব্যক্তিদের মধ্যে গোষ্ঠীবদ্ধ করে।",
"facial_recognition_job_description": "শনাক্ত করা মুখগুলিকে মানুষের মধ্যে গোষ্ঠীভুক্ত করুন। মুখ সনাক্তকরণ সম্পূর্ণ হওয়ার পরে এই ধাপটি চলে। \"রিসেট\" (পুনরায়) সমস্ত মুখকে ক্লাস্টার করে। \"অনুপস্থিত\" মুখগুলিকে সারিতে রাখে যেখানে কোনও ব্যক্তিকে বরাদ্দ করা হয়নি।",
"failed_job_command": "কমান্ড {command} কাজের জন্য ব্যর্থ হয়েছে: {job}",
"force_delete_user_warning": "সতর্কতা: এটি ব্যবহারকারী এবং সমস্ত সম্পদ অবিলম্বে সরিয়ে ফেলবে। এটি পূর্বাবস্থায় ফেরানো যাবে না এবং ফাইলগুলি পুনরুদ্ধার করা যাবে না।",
"image_format": "ফরম্যাট",
"image_format_description": "WebP JPEG এর তুলনায় ছোট ফাইল তৈরি করে, কিন্তু এনকোড করতে ধীর।",
"image_fullsize_description": "জুম ইন করার সময় ব্যবহৃত স্ট্রিপড মেটাডেটা সহ পূর্ণ আকারের ছবি",
"image_fullsize_enabled": "পূর্ণ-আকারের ছবি তৈরি সক্ষম করুন",
"image_fullsize_enabled_description": "ওয়েব-বান্ধব নয় এমন ফর্ম্যাটের জন্য পূর্ণ-আকারের ছবি তৈরি করুন। \"এমবেডেড প্রিভিউ পছন্দ করুন\" সক্ষম করা থাকলে, রূপান্তর ছাড়াই এমবেডেড প্রিভিউ সরাসরি ব্যবহার করা হয়। JPEG-এর মতো ওয়েব-বান্ধব ফর্ম্যাটগুলিকে প্রভাবিত করে না।",
"image_fullsize_quality_description": "পূর্ণ-আকারের ছবির মান ১-১০০। উচ্চতর হলে ভালো, কিন্তু আরও বড় ফাইল তৈরি হয়।",
"image_fullsize_title": "পূর্ণ-আকারের চিত্র সেটিংস",
"image_prefer_embedded_preview": "এম্বেড করা প্রিভিউ পছন্দ করুন",
"image_prefer_embedded_preview_setting_description": "ছবি প্রক্রিয়াকরণের জন্য এবং যখনই উপলব্ধ থাকবে তখন RAW ফটোতে এমবেডেড প্রিভিউ ব্যবহার করুন। এটি কিছু ছবির জন্য আরও সঠিক রঙ তৈরি করতে পারে, তবে প্রিভিউয়ের মান ক্যামেরা-নির্ভর এবং ছবিতে আরও কম্প্রেশন আর্টিফ্যাক্ট থাকতে পারে।",
"image_prefer_wide_gamut": "প্রশস্ত পরিসর পছন্দ করুন",
"image_prefer_wide_gamut_setting_description": "থাম্বনেইলের জন্য ডিসপ্লে P3 ব্যবহার করুন। এটি প্রশস্ত রঙের স্থান সহ ছবির প্রাণবন্ততা আরও ভালভাবে সংরক্ষণ করে, তবে পুরানো ব্রাউজার সংস্করণ সহ পুরানো ডিভাইসগুলিতে ছবিগুলি ভিন্নভাবে প্রদর্শিত হতে পারে। রঙের পরিবর্তন এড়াতে sRGB ছবিগুলিকে sRGB হিসাবে রাখা হয়।",
"image_preview_description": "স্ট্রিপড মেটাডেটা সহ মাঝারি আকারের ছবি, একটি একক সম্পদ দেখার সময় এবং মেশিন লার্নিংয়ের জন্য ব্যবহৃত হয়",
"image_preview_quality_description": "১-১০০ এর মধ্যে প্রিভিউ কোয়ালিটি। বেশি হলে ভালো, কিন্তু বড় ফাইল তৈরি হয় এবং অ্যাপের প্রতিক্রিয়াশীলতা কমাতে পারে। কম মান সেট করলে মেশিন লার্নিং কোয়ালিটির উপর প্রভাব পড়তে পারে।",
"image_preview_title": "প্রিভিউ সেটিংস",
"image_quality": "গুণমান",
"image_resolution": "রেজোলিউশন",
"image_resolution_description": "উচ্চ রেজোলিউশনের ক্ষেত্রে আরও বিস্তারিত তথ্য সংরক্ষণ করা সম্ভব কিন্তু এনকোড করতে বেশি সময় লাগে, ফাইলের আকার বড় হয় এবং অ্যাপের প্রতিক্রিয়াশীলতা কমাতে পারে।",
"image_settings": "চিত্র সেটিংস",
"image_settings_description": "তৈরি করা ছবির মান এবং রেজোলিউশন পরিচালনা করুন",
"image_thumbnail_description": "মেটাডেটা বাদ দেওয়া ছোট থাম্বনেইল, মূল টাইমলাইনের মতো ছবির গ্রুপ দেখার সময় ব্যবহৃত হয়",
"image_thumbnail_quality_description": "থাম্বনেইলের মান ১-১০০। বেশি হলে ভালো, কিন্তু বড় ফাইল তৈরি হয় এবং অ্যাপের প্রতিক্রিয়াশীলতা কমাতে পারে।",
"image_thumbnail_title": "থাম্বনেল সেটিংস",
"job_concurrency": "{job} কনকারেন্সি",
"job_created": "Job তৈরি হয়েছে",
"job_not_concurrency_safe": "এই কাজটি সমকালীন-নিরাপদ নয়।",
"job_settings": "কাজের সেটিংস",
"job_settings_description": "কাজের সমান্তরালতা পরিচালনা করুন",
"job_status": "চাকরির অবস্থা"
}
}

View File

@@ -166,6 +166,10 @@
"metadata_settings_description": "Administrar la configuració de les metadades",
"migration_job": "Migració",
"migration_job_description": "Migra les miniatures d'elements i cares cap a la nova estructura de carpetes",
"nightly_tasks_cluster_new_faces_setting": "Agrupa cares noves",
"nightly_tasks_database_cleanup_setting": "Tasques de neteja de la base de dades",
"nightly_tasks_database_cleanup_setting_description": "Netegeu les dades antigues i caducades de la base de dades",
"nightly_tasks_missing_thumbnails_setting": "Generar les miniatures restants",
"no_paths_added": "No s'ha afegit cap ruta",
"no_pattern_added": "Cap patró aplicat",
"note_apply_storage_label_previous_assets": "Nota: Per aplicar l'etiquetatge d'emmagatzematge a elements pujats prèviament, executeu la",
@@ -196,6 +200,8 @@
"oauth_mobile_redirect_uri": "URI de redirecció mòbil",
"oauth_mobile_redirect_uri_override": "Sobreescriu l'URI de redirecció mòbil",
"oauth_mobile_redirect_uri_override_description": "Habilita quan el proveïdor d'OAuth no permet una URI mòbil, com ara ''{callback}''",
"oauth_role_claim": "Concessió de rol",
"oauth_role_claim_description": "Atorgar accés d'administrador automàticament segons la presència d'aquesta concessió. La concessió pot ser 'usuari' o 'admin'.",
"oauth_settings": "OAuth",
"oauth_settings_description": "Gestiona la configuració de l'inici de sessió OAuth",
"oauth_settings_more_details": "Per a més detalls sobre aquesta funcionalitat, consulteu la <link>documentació</link>.",
@@ -244,6 +250,7 @@
"storage_template_migration_info": "Les extensions es convertiran a minúscules. Els canvis de plantilla només s'aplicaran a nous elements. Per aplicar la plantilla rectroactivament a elements pujats prèviament, executeu la <link>{job}</link>.",
"storage_template_migration_job": "Tasca de migració de la plantilla d'emmagatzematge",
"storage_template_more_details": "Per obtenir més detalls sobre aquesta funció, consulteu la <template-link>Storage Template</template-link> i les seves <implications-link>implications</implications-link>",
"storage_template_onboarding_description_v2": "Un cop habilitada, aquesta funció organitzarà automàticament els fitxers a partir d'una plantilla definida per l'usuari. Per a més informació, podeu consultar la <link>documentació</link>.",
"storage_template_path_length": "Límit aproximat de longitud de la ruta: <b>{length, number}</b>/{limit, number}",
"storage_template_settings": "Plantilla d'emmagatzematge",
"storage_template_settings_description": "Gestiona l'estructura de les carpetes i el nom del fitxers dels elements pujats",
@@ -359,7 +366,7 @@
"advanced_settings_enable_alternate_media_filter_subtitle": "Feu servir aquesta opció per filtrar els continguts multimèdia durant la sincronització segons criteris alternatius. Només proveu-ho si teniu problemes amb l'aplicació per detectar tots els àlbums.",
"advanced_settings_enable_alternate_media_filter_title": "Utilitza el filtre de sincronització d'àlbums de dispositius alternatius",
"advanced_settings_log_level_title": "Nivell de registre: {level}",
"advanced_settings_prefer_remote_subtitle": "Alguns dispositius són molt lents en carregar miniatures dels elements del dispositiu. Activeu aquest paràmetre per carregar imatges remotes en el seu lloc.",
"advanced_settings_prefer_remote_subtitle": "Alguns dispositius són molt lents en carregar miniatures dels elements locals. Activeu aquest paràmetre per carregar imatges remotes en el seu lloc.",
"advanced_settings_prefer_remote_title": "Prefereix imatges remotes",
"advanced_settings_proxy_headers_subtitle": "Definiu les capçaleres de proxy que Immich per enviar amb cada sol·licitud de xarxa",
"advanced_settings_proxy_headers_title": "Capçaleres de proxy",
@@ -426,6 +433,7 @@
"app_settings": "Configuració de l'app",
"appears_in": "Apareix a",
"archive": "Arxiu",
"archive_action_prompt": "{count} afegit a Arxiu",
"archive_or_unarchive_photo": "Arxivar o desarxivar fotografia",
"archive_page_no_archived_assets": "No s'ha trobat res arxivat",
"archive_page_title": "Arxiu({count})",
@@ -463,7 +471,6 @@
"assets": "Elements",
"assets_added_count": "{count, plural, one {Afegit un element} other {Afegits # elements}}",
"assets_added_to_album_count": "{count, plural, one {Afegit un element} other {Afegits # elements}} a l'àlbum",
"assets_added_to_name_count": "{count, plural, one {S'ha afegit # recurs} other {S'han afegit # recursos}} a {hasName, select, true {<b>{name}</b>} other {new album}}",
"assets_cannot_be_added_to_album_count": "{count, plural, one {Asset} other {Assets}} no es pot afegir a l'àlbum",
"assets_count": "{count, plural, one {# recurs} other {# recursos}}",
"assets_deleted_permanently": "{count} element(s) esborrats permanentment",
@@ -489,6 +496,7 @@
"back_close_deselect": "Tornar, tancar o anul·lar la selecció",
"background_location_permission": "Permís d'ubicació en segon pla",
"background_location_permission_content": "Per canviar de xarxa quan s'executa en segon pla, Immich ha de *sempre* tenir accés a la ubicació precisa perquè l'aplicació pugui llegir el nom de la xarxa Wi-Fi",
"backup": "Còpia",
"backup_album_selection_page_albums_device": "Àlbums al dispositiu ({count})",
"backup_album_selection_page_albums_tap": "Un toc per incloure, doble toc per excloure",
"backup_album_selection_page_assets_scatter": "Els elements poden dispersar-se en diversos àlbums. Per tant, els àlbums es poden incloure o excloure durant el procés de còpia de seguretat.",
@@ -702,7 +710,7 @@
"daily_title_text_date": "E, dd MMM",
"daily_title_text_date_year": "E, dd MMM, yyyy",
"dark": "Fosc",
"darkTheme": "Activa/desactiva el tema fosc",
"dark_theme": "Canviar a tema fosc",
"date_after": "Data posterior a",
"date_and_time": "Data i hora",
"date_before": "Data anterior a",
@@ -718,6 +726,7 @@
"default_locale": "Localització predeterminada",
"default_locale_description": "Format de dates i números segons la configuració del navegador",
"delete": "Esborra",
"delete_action_prompt": "{count} eliminats permanentment",
"delete_album": "Esborra l'àlbum",
"delete_api_key_prompt": "Esteu segurs que voleu eliminar aquesta clau API?",
"delete_dialog_alert": "Aquests elements seran eliminats de manera permanent d'Immich i del vostre dispositiu",
@@ -798,6 +807,7 @@
"edit_key": "Edita clau",
"edit_link": "Edita enllaç",
"edit_location": "Edita ubicació",
"edit_location_action_prompt": "{count} ubicacions editades",
"edit_location_dialog_title": "Ubicació",
"edit_name": "Edita el nom",
"edit_people": "Edita la gent",
@@ -983,6 +993,7 @@
"failed_to_load_assets": "Error carregant recursos",
"failed_to_load_folder": "No s'ha pogut carregar la carpeta",
"favorite": "Preferit",
"favorite_action_prompt": "{count} afegit a Favorits",
"favorite_or_unfavorite_photo": "Foto preferida o no preferida",
"favorites": "Preferits",
"favorites_page_no_favorites": "No s'han trobat preferits",
@@ -1129,7 +1140,6 @@
"light": "Llum",
"like_deleted": "M'agrada suprimit",
"link_motion_video": "Enllaçar vídeo en moviment",
"link_options": "Opcions d'enllaç",
"link_to_oauth": "Enllaç a OAuth",
"linked_oauth_account": "Compte OAuth enllaçat",
"list": "Llista",
@@ -1149,6 +1159,7 @@
"locked_folder": "Carpeta bloquejada",
"log_out": "Tanca la sessió",
"log_out_all_devices": "Tanqueu la sessió de tots els dispositius",
"logged_in_as": "Sessió iniciada com a {user}",
"logged_out_all_devices": "S'ha tancat la sessió de tots els dispositius",
"logged_out_device": "Dispositiu tancat",
"login": "Iniciar sessió",
@@ -1191,7 +1202,6 @@
"manage_your_devices": "Gestioneu els vostres dispositius connectats",
"manage_your_oauth_connection": "Gestioneu la vostra connexió OAuth",
"map": "Mapa",
"map_assets_in_bound": "{count} foto",
"map_assets_in_bounds": "{count} fotos",
"map_cannot_get_user_location": "No es pot obtenir la ubicació de l'usuari",
"map_location_dialog_yes": "Sí",
@@ -1244,6 +1254,7 @@
"more": "Més",
"move": "Moure",
"move_off_locked_folder": "Moure fora de la carpeta bloquejada",
"move_to_lock_folder_action_prompt": "{count} afegides a la carpeta protegida",
"move_to_locked_folder": "Moure a la carpeta bloquejada",
"move_to_locked_folder_confirmation": "Aquestes fotos i vídeos seran eliminades de tots els àlbums, i només podran ser vistes des de la carpeta bloquejada",
"moved_to_archive": "S'han mogut {count, plural, one {# asset} other {# assets}} a l'arxiu",
@@ -1494,6 +1505,7 @@
"remove_deleted_assets": "Suprimeix fitxers fora de línia",
"remove_from_album": "Treu de l'àlbum",
"remove_from_favorites": "Eliminar dels preferits",
"remove_from_lock_folder_action_prompt": "{count} eliminades de la carpeta protegida",
"remove_from_locked_folder": "Elimina de la carpeta bloquejada",
"remove_from_locked_folder_confirmation": "Segur que vols moure aquestes fotos i vídeos fora de la carpeta bloquejada? Seran visibles a la teva biblioteca.",
"remove_from_shared_link": "Eliminar de l'enllaç compartit",
@@ -1606,6 +1618,7 @@
"select_album_cover": "Seleccionar la portada de l'àlbum",
"select_all": "Selecciona-ho tot",
"select_all_duplicates": "Seleccioneu tots els duplicats",
"select_all_in": "Selecciona tot en {group}",
"select_avatar_color": "Tria color de l'avatar",
"select_face": "Selecciona cara",
"select_featured_photo": "Selecciona foto principal",
@@ -1835,6 +1848,7 @@
"total": "Total",
"total_usage": "Ús total",
"trash": "Paperera",
"trash_action_prompt": "{count} mogudes a la brossa",
"trash_all": "Envia-ho tot a la paperera",
"trash_count": "Paperera {count, number}",
"trash_delete_asset": "Esborra/Elimina element",
@@ -1852,9 +1866,11 @@
"unable_to_change_pin_code": "No es pot canviar el codi PIN",
"unable_to_setup_pin_code": "No s'ha pogut configurar el codi PIN",
"unarchive": "Desarxivar",
"unarchive_action_prompt": "{count} eliminades de l'arxiu",
"unarchived_count": "{count, plural, other {# elements desarxivats}}",
"undo": "Desfer",
"unfavorite": "Reverteix preferit",
"unfavorite_action_prompt": "{count} eliminades de preferits",
"unhide_person": "Mostra persona",
"unknown": "Desconegut",
"unknown_country": "País Desconegut",
@@ -1870,6 +1886,7 @@
"unsaved_change": "Canvi no desat",
"unselect_all": "Deselecciona-ho tot",
"unselect_all_duplicates": "Desmarqueu tots els duplicats",
"unselect_all_in": "Desseleccionar tots els elements de {group}",
"unstack": "Desapila",
"unstacked_assets_count": "No apilat {count, plural, one {# recurs} other {# recursos}}",
"up_next": "Pròxim",

View File

@@ -14,6 +14,7 @@
"add_a_location": "Přidat polohu",
"add_a_name": "Přidat jméno",
"add_a_title": "Přidat název",
"add_birthday": "Přidat datum narození",
"add_endpoint": "Přidat koncový bod",
"add_exclusion_pattern": "Přidat vzor vyloučení",
"add_import_path": "Přidat cestu importu",
@@ -44,7 +45,14 @@
"backup_database": "Vytvořit výpis databáze",
"backup_database_enable_description": "Povolit výpisy z databáze",
"backup_keep_last_amount": "Počet předchozích výpisů, které se mají ponechat",
"backup_settings": "Nastavení výpisu databáze",
"backup_onboarding_1_description": "kopie v cloudu nebo na jiném fyzickém místě.",
"backup_onboarding_2_description": "místní kopie na různých zařízeních. To zahrnuje hlavní soubory a jejich místní zálohu.",
"backup_onboarding_3_description": "kompletní kopie vašich dat, včetně původních souborů. To zahrnuje 1 kopii na jiném místě a 2 místní kopie.",
"backup_onboarding_description": "K ochraně vašich dat doporučujeme strategii zálohování <backblaze-link>3-2-1</backblaze-link>. Pro komplexní zálohování byste měli uchovávat kopie nahraných fotografií/videí i databáze Immich.",
"backup_onboarding_footer": "Další informace o zálohování Immiche naleznete v <link>dokumentaci</link>.",
"backup_onboarding_parts_title": "Záloha 3-2-1 zahrnuje:",
"backup_onboarding_title": "Zálohy",
"backup_settings": "Zálohování databáze",
"backup_settings_description": "Správa nastavení výpisu databáze.",
"cleared_jobs": "Hotové úlohy pro: {job}",
"config_set_by_file": "Konfigurace je aktuálně prováděna konfiguračním souborem",
@@ -166,6 +174,20 @@
"metadata_settings_description": "Správa nastavení metadat",
"migration_job": "Migrace",
"migration_job_description": "Migrace miniatur snímků a obličejů do nejnovější struktury složek",
"nightly_tasks_cluster_faces_setting_description": "Spustit rozpoznávání obličeje na nově nalezených obličejích",
"nightly_tasks_cluster_new_faces_setting": "Seskupit nové tváře",
"nightly_tasks_database_cleanup_setting": "Úlohy čištění databáze",
"nightly_tasks_database_cleanup_setting_description": "Vyčistit databázi od starých dat, jejichž platnost vypršela",
"nightly_tasks_generate_memories_setting": "Vytváření vzpomínek",
"nightly_tasks_generate_memories_setting_description": "Vytváření nových vzpomínek z položek",
"nightly_tasks_missing_thumbnails_setting": "Generovat chybějící miniatury",
"nightly_tasks_missing_thumbnails_setting_description": "Řadit položky bez miniatur do fronty pro generování miniatur",
"nightly_tasks_settings": "Noční úlohy",
"nightly_tasks_settings_description": "Správa nočních úkolů",
"nightly_tasks_start_time_setting": "Čas zahájení",
"nightly_tasks_start_time_setting_description": "Čas, kdy server spustí noční úlohy",
"nightly_tasks_sync_quota_usage_setting": "Synchronizace využití kvóty",
"nightly_tasks_sync_quota_usage_setting_description": "Aktualizovat kvótu úložiště uživatele na základě aktuálního využití",
"no_paths_added": "Nebyly přidány žádné cesty",
"no_pattern_added": "Nebyl přidán žádný vzor",
"note_apply_storage_label_previous_assets": "Upozornění: Pro uplatnění Štítku úložiště na dříve nahrané položky spusťte",
@@ -196,6 +218,8 @@
"oauth_mobile_redirect_uri": "Mobilní přesměrování URI",
"oauth_mobile_redirect_uri_override": "Přepsat mobilní přesměrování URI",
"oauth_mobile_redirect_uri_override_description": "Povolit, pokud poskytovatel OAuth nepovoluje mobilní URI, například ''{callback}''",
"oauth_role_claim": "Deklarace Role",
"oauth_role_claim_description": "Automaticky udělit přístup správce na základě přítomnosti této deklarace. Deklarace může mít hodnotu 'user' nebo 'admin'.",
"oauth_settings": "OAuth",
"oauth_settings_description": "Správa nastavení OAuth přihlášení",
"oauth_settings_more_details": "Další podrobnosti o této funkci naleznete v <link>dokumentaci</link>.",
@@ -357,10 +381,12 @@
"admin_password": "Heslo správce",
"administration": "Administrace",
"advanced": "Pokročilé",
"advanced_settings_beta_timeline_subtitle": "Vyzkoušejte nové prostředí aplikace",
"advanced_settings_beta_timeline_title": "Beta verze časové osy",
"advanced_settings_enable_alternate_media_filter_subtitle": "Tuto možnost použijte k filtrování médií během synchronizace na základě alternativních kritérií. Tuto možnost vyzkoušejte pouze v případě, že máte problémy s detekcí všech alb v aplikaci.",
"advanced_settings_enable_alternate_media_filter_title": "[EXPERIMENTÁLNÍ] Použít alternativní filtr pro synchronizaci alb zařízení",
"advanced_settings_log_level_title": "Úroveň protokolování: {level}",
"advanced_settings_prefer_remote_subtitle": "U některých zařízení je načítání miniatur z prostředků v zařízení velmi pomalé. Aktivujte toto nastavení, aby se místo toho načítaly vzdálené obrázky.",
"advanced_settings_prefer_remote_subtitle": "U některých zařízení je načítání miniatur z lokálních prostředků velmi pomalé. Aktivujte toto nastavení, aby se místo toho načítaly vzdálené obrázky.",
"advanced_settings_prefer_remote_title": "Preferovat vzdálené obrázky",
"advanced_settings_proxy_headers_subtitle": "Definice hlaviček proxy serveru, které by měl Immich odesílat s každým síťovým požadavkem",
"advanced_settings_proxy_headers_title": "Proxy hlavičky",
@@ -379,6 +405,7 @@
"album_cover_updated": "Obal alba aktualizován",
"album_delete_confirmation": "Opravdu chcete album {album} odstranit?",
"album_delete_confirmation_description": "Pokud je toto album sdíleno, ostatní uživatelé k němu již nebudou mít přístup.",
"album_deleted": "Album smazáno",
"album_info_card_backup_album_excluded": "VYLOUČENO",
"album_info_card_backup_album_included": "ZAHRNUTO",
"album_info_updated": "Informace o albu aktualizovány",
@@ -388,6 +415,7 @@
"album_options": "Možnosti alba",
"album_remove_user": "Odebrat uživatele?",
"album_remove_user_confirmation": "Opravdu chcete odebrat uživatele {user}?",
"album_search_not_found": "Nebyla nalezena žádná alba odpovídající vašemu hledání",
"album_share_no_users": "Zřejmě jste toto album sdíleli se všemi uživateli, nebo nemáte žádného uživatele, se kterým byste ho mohli sdílet.",
"album_updated": "Album aktualizováno",
"album_updated_setting_description": "Dostávat e-mailová oznámení o nových položkách sdíleného alba",
@@ -407,6 +435,7 @@
"albums_default_sort_order": "Výchozí řazení alb",
"albums_default_sort_order_description": "Výchozí řazení položek při vytváření nových alb.",
"albums_feature_description": "Sbírky položek, které lze sdílet s ostatními uživateli.",
"albums_on_device_count": "Alba v zařízení ({count})",
"all": "Vše",
"all_albums": "Všechna alba",
"all_people": "Všichni lidé",
@@ -427,7 +456,8 @@
"app_settings": "Aplikace",
"appears_in": "Vyskytuje se v",
"archive": "Archiv",
"archive_or_unarchive_photo": "Archivovat nebo odarchivovat fotku",
"archive_action_prompt": "{count} přidaných do archivu",
"archive_or_unarchive_photo": "Přidat nebo odebrat fotku z archivu",
"archive_page_no_archived_assets": "Nebyla nalezena žádná archivovaná média",
"archive_page_title": "Archiv ({count})",
"archive_size": "Velikost archivu",
@@ -464,14 +494,13 @@
"assets": "Položky",
"assets_added_count": "{count, plural, one {Přidána # položka} few {Přidány # položky} other {Přidáno # položek}}",
"assets_added_to_album_count": "Do alba {count, plural, one {byla přidána # položka} few {byly přidány # položky} other {bylo přidáno # položek}}",
"assets_added_to_name_count": "{count, plural, one {Přidána # položka} few {Přidány # položky} other {Přidáno # položek}} do {hasName, select, true {alba <b>{name}</b>} other {nového alba}}",
"assets_cannot_be_added_to_album_count": "{count, plural, one {Položku} other {Položky}} nelze přidat do alba",
"assets_count": "{count, plural, one {# položka} few {# položky} other {# položek}}",
"assets_deleted_permanently": "{count} položek trvale odstraněno",
"assets_deleted_permanently_from_server": "{count} položek trvale odstraněno z Immich serveru",
"assets_downloaded_failed": "{count, plural, one {Stažen # soubor - {error} souborů selhalo} few {Staženy # soubory - {error} souborů selhalo} other {Staženo # souborů - {error} souborů selhalo}}",
"assets_downloaded_successfully": "{count, plural, one {Úspěšně stažen # soubor} few {Úspěšně staženy # soubory} other {Úspěšně staženo # souborů}}",
"assets_moved_to_trash_count": "Do koše {count, plural, one {přesunuta # položka} few {přesunuty # položky} other {přesunuto # položek}}",
"assets_moved_to_trash_count": "{count, plural, one {# položka přesunuta} few {# položky přesunuty} other {# položek přesunuto}} do koše",
"assets_permanently_deleted_count": "Trvale {count, plural, one {smazána # položka} few {smazány # položky} other {smazáno # položek}}",
"assets_removed_count": "{count, plural, one {Odstraněna # položka} few {Odstraněny # položky} other {Odstraněno # položek}}",
"assets_removed_permanently_from_device": "{count} položek trvale odstraněno z vašeho zařízení",
@@ -490,6 +519,7 @@
"back_close_deselect": "Zpět, zavřít nebo zrušit výběr",
"background_location_permission": "Povolení polohy na pozadí",
"background_location_permission_content": "Aby bylo možné přepínat sítě při běhu na pozadí, musí mít Immich *vždy* přístup k přesné poloze, aby mohl zjistit název Wi-Fi sítě",
"backup": "Záloha",
"backup_album_selection_page_albums_device": "Alba v zařízení ({count})",
"backup_album_selection_page_albums_tap": "Klepnutím na položku ji zahrnete, opětovným klepnutím ji vyloučíte",
"backup_album_selection_page_assets_scatter": "Položky mohou být roztroušeny ve více albech. To umožňuje zahrnout nebo vyloučit alba během procesu zálohování.",
@@ -553,6 +583,8 @@
"backup_options_page_title": "Nastavení záloh",
"backup_setting_subtitle": "Správa nastavení zálohování na pozadí a na popředí",
"backward": "Pozpátku",
"beta_sync": "Stav synchronizace (beta)",
"beta_sync_subtitle": "Správa nového systému synchronizace",
"biometric_auth_enabled": "Biometrické ověřování je povoleno",
"biometric_locked_out": "Jste vyloučeni z biometrického ověřování",
"biometric_no_options": "Biometrické možnosti nejsou k dispozici",
@@ -570,7 +602,7 @@
"cache_settings_clear_cache_button": "Vymazat vyrovnávací paměť",
"cache_settings_clear_cache_button_title": "Vymaže vyrovnávací paměť aplikace. To výrazně ovlivní výkon aplikace, dokud se vyrovnávací paměť neobnoví.",
"cache_settings_duplicated_assets_clear_button": "VYMAZAT",
"cache_settings_duplicated_assets_subtitle": "Fotografie a videa, které aplikace zařadila na černou listinu",
"cache_settings_duplicated_assets_subtitle": "Fotografie a videa, které aplikace ignoruje",
"cache_settings_duplicated_assets_title": "Duplicitní položky ({count})",
"cache_settings_statistics_album": "Knihovna náhledů",
"cache_settings_statistics_full": "Kompletní fotografie",
@@ -587,6 +619,7 @@
"cancel": "Zrušit",
"cancel_search": "Zrušit vyhledávání",
"canceled": "Zrušeno",
"canceling": "Rušení",
"cannot_merge_people": "Nelze sloučit osoby",
"cannot_undo_this_action": "Tuto akci nelze vrátit zpět!",
"cannot_update_the_description": "Nelze aktualizovat popis",
@@ -700,10 +733,11 @@
"current_server_address": "Aktuální adresa serveru",
"custom_locale": "Vlastní lokalizace",
"custom_locale_description": "Formátovat datumy a čísla podle jazyka a oblasti",
"custom_url": "Vlastní URL",
"daily_title_text_date": "EEEE, d. MMMM",
"daily_title_text_date_year": "EEEE, d. MMMM y",
"dark": "Tmavý",
"darkTheme": "Přepnout tmavý motiv",
"dark_theme": "Přepnout tmavý motiv",
"date_after": "Datum po",
"date_and_time": "Datum a čas",
"date_before": "Datum před",
@@ -719,6 +753,8 @@
"default_locale": "Výchozí jazyk",
"default_locale_description": "Formátovat datumy a čísla podle místního prostředí prohlížeče",
"delete": "Smazat",
"delete_action_confirmation_message": "Opravdu chcete odstranit tuto položku? Tato akce přesune položku do serverového koše a zeptá se vás, zda ji chcete odstranit lokálně",
"delete_action_prompt": "{count} smazáno",
"delete_album": "Smazat album",
"delete_api_key_prompt": "Opravdu chcete tento API klíč odstranit?",
"delete_dialog_alert": "Tyto položky budou trvale smazány z aplikace Immich i z vašeho zařízení",
@@ -732,9 +768,12 @@
"delete_key": "Smazat klíč",
"delete_library": "Smazat knihovnu",
"delete_link": "Smazat odkaz",
"delete_local_action_prompt": "{count} smazáno lokálně",
"delete_local_dialog_ok_backed_up_only": "Smazat pouze zálohované",
"delete_local_dialog_ok_force": "Přesto smazat",
"delete_others": "Odstranit ostatní",
"delete_others": "Smazat ostatní",
"delete_permanently": "Trvale smazat",
"delete_permanently_action_prompt": "{count} trvale smazáno",
"delete_shared_link": "Smazat sdílený odkaz",
"delete_shared_link_dialog_title": "Odstranit sdílený odkaz",
"delete_tag": "Smazat značku",
@@ -745,6 +784,7 @@
"description": "Popis",
"description_input_hint_text": "Přidat popis...",
"description_input_submit_error": "Chyba aktualizace popisu, další podrobnosti najdete v logu",
"deselect_all": "Zrušit výběr všech",
"details": "Podrobnosti",
"direction": "Směr",
"disabled": "Zakázáno",
@@ -762,6 +802,7 @@
"documentation": "Dokumentace",
"done": "Hotovo",
"download": "Stáhnout",
"download_action_prompt": "Stahování {count} položek",
"download_canceled": "Stahování zrušeno",
"download_complete": "Stahování kompletní",
"download_enqueue": "Stahování ve frontě",
@@ -788,6 +829,7 @@
"edit": "Upravit",
"edit_album": "Upravit album",
"edit_avatar": "Upravit avatar",
"edit_birthday": "Upravit datum narození",
"edit_date": "Upravit datum",
"edit_date_and_time": "Upravit datum a čas",
"edit_description": "Upravit popis",
@@ -799,6 +841,7 @@
"edit_key": "Upravit klíč",
"edit_link": "Upravit odkaz",
"edit_location": "Upravit polohu",
"edit_location_action_prompt": "{count} upravených poloh",
"edit_location_dialog_title": "Poloha",
"edit_name": "Upravit jméno",
"edit_people": "Upravit lidi",
@@ -817,6 +860,7 @@
"empty_trash": "Vyprázdnit koš",
"empty_trash_confirmation": "Opravdu chcete vysypat koš? Tím se z Immiche trvale odstraní všechny položky v koši.\nTuto akci nelze vrátit zpět!",
"enable": "Povolit",
"enable_backup": "Povolit zálohování",
"enable_biometric_auth_description": "Zadejte váš PIN kód pro povolení biometrického ověřování",
"enabled": "Povoleno",
"end_date": "Konečné datum",
@@ -861,7 +905,7 @@
"failed_to_load_people": "Chyba načítání osob",
"failed_to_remove_product_key": "Nepodařilo se odebrat klíč produktu",
"failed_to_stack_assets": "Nepodařilo se seskupit položky",
"failed_to_unstack_assets": "Nepodařilo se rozložit položky",
"failed_to_unstack_assets": "Nepodařilo se zrušit seskupení položek",
"failed_to_update_notification_status": "Nepodařilo se aktualizovat stav oznámení",
"import_path_already_exists": "Tato cesta importu již existuje.",
"incorrect_email_or_password": "Nesprávný e-mail nebo heslo",
@@ -876,7 +920,7 @@
"unable_to_add_partners": "Nelze přidat partnery",
"unable_to_add_remove_archive": "Nelze {archived, select, true {odstranit položku z} other {přidat položku do}} archivu",
"unable_to_add_remove_favorites": "Nelze {favorite, select, true {oblíbit položku} other {zrušit oblíbení položky}}",
"unable_to_archive_unarchive": "Nelze {archived, select, true {archivovat} other {odarchivovat}}",
"unable_to_archive_unarchive": "Nelze {archived, select, true {archivovat} other {odebrat z archivu}}",
"unable_to_change_album_user_role": "Nelze změnit roli uživatele alba",
"unable_to_change_date": "Nelze změnit datum",
"unable_to_change_description": "Nelze změnit popis",
@@ -953,6 +997,7 @@
},
"exif": "Exif",
"exif_bottom_sheet_description": "Přidat popis...",
"exif_bottom_sheet_description_error": "Chyba při aktualizaci popisu",
"exif_bottom_sheet_details": "PODROBNOSTI",
"exif_bottom_sheet_location": "POLOHA",
"exif_bottom_sheet_people": "LIDÉ",
@@ -973,6 +1018,8 @@
"explorer": "Průzkumník",
"export": "Export",
"export_as_json": "Exportovat jako JSON",
"export_database": "Exportovat databázi",
"export_database_description": "Exportovat databázi SQLite",
"extension": "Přípona",
"external": "Externí",
"external_libraries": "Externí knihovny",
@@ -984,6 +1031,7 @@
"failed_to_load_assets": "Nepodařilo se načíst položky",
"failed_to_load_folder": "Nepodařilo se načíst složku",
"favorite": "Oblíbit",
"favorite_action_prompt": "{count} přidáno do Oblíbených",
"favorite_or_unfavorite_photo": "Oblíbit nebo zrušit oblíbení fotky",
"favorites": "Oblíbené",
"favorites_page_no_favorites": "Nebyla nalezena žádná oblíbená média",
@@ -1023,6 +1071,9 @@
"haptic_feedback_switch": "Povolit dotykovou zpětnou vazbu",
"haptic_feedback_title": "Dotyková zpětná vazba",
"has_quota": "Má kvótu",
"hash_asset": "Hash položky",
"hashed_assets": "Hashované položky",
"hashing": "Hashování",
"header_settings_add_header_tip": "Přidat hlavičku",
"header_settings_field_validator_msg": "Hodnota nemůže být prázdná",
"header_settings_header_name_input": "Název hlavičky",
@@ -1055,6 +1106,7 @@
"host": "Hostitel",
"hour": "Hodina",
"id": "ID",
"idle": "Nečinnost",
"ignore_icloud_photos": "Ignorovat fotografie na iCloudu",
"ignore_icloud_photos_description": "Fotografie uložené na iCloudu se nebudou nahrávat na Immich server",
"image": "Obrázek",
@@ -1112,6 +1164,7 @@
"language_no_results_title": "Nebyly nalezeny žádné jazyky",
"language_search_hint": "Vyhledat jazyk...",
"language_setting_description": "Vyberte upřednostňovaný jazyk",
"large_files": "Velké soubory",
"last_seen": "Naposledy viděno",
"latest_version": "Nejnovější verze",
"latitude": "Zeměpisná šířka",
@@ -1127,16 +1180,18 @@
"library_page_sort_created": "Naposledy vytvořené",
"library_page_sort_last_modified": "Naposledy upraveno",
"library_page_sort_title": "Podle názvu alba",
"licenses": "Licence",
"light": "Světlý",
"like_deleted": "Lajk smazán",
"link_motion_video": "Připojit pohyblivé video",
"link_options": "Možnosti odkazu",
"link_to_oauth": "Propojit s OAuth",
"linked_oauth_account": "Propojený OAuth účet",
"list": "Seznam",
"loading": "Načítání",
"loading_search_results_failed": "Načítání výsledků vyhledávání se nezdařilo",
"local": "Místní",
"local_asset_cast_failed": "Nelze odeslat položku, která není nahraná na serveru",
"local_assets": "Místní položky",
"local_network": "Místní síť",
"local_network_sheet_info": "Aplikace se při použití zadané sítě Wi-Fi připojí k serveru prostřednictvím tohoto URL",
"location_permission": "Oprávnění polohy",
@@ -1193,8 +1248,7 @@
"manage_your_devices": "Správa přihlášených zařízení",
"manage_your_oauth_connection": "Správa OAuth propojení",
"map": "Mapa",
"map_assets_in_bound": "{count} fotka",
"map_assets_in_bounds": "{count} fotek",
"map_assets_in_bounds": "{count, plural, one {# fotka} few{# fotky} other {# fotek}}",
"map_cannot_get_user_location": "Nelze zjistit polohu uživatele",
"map_location_dialog_yes": "Ano",
"map_location_picker_page_use_location": "Použít tuto polohu",
@@ -1246,10 +1300,11 @@
"more": "Více",
"move": "Přesunout",
"move_off_locked_folder": "Přesunout z uzamčené složky",
"move_to_lock_folder_action_prompt": "{count} přidaných do uzamčené složky",
"move_to_locked_folder": "Přesunout do uzamčené složky",
"move_to_locked_folder_confirmation": "Tyto fotky a videa budou odstraněny ze všech alb a bude je možné zobrazit pouze v uzamčené složce",
"moved_to_archive": "{count, plural, one {Přesunuta # položka} few {Přesunuty # položky} other {Přesunuto # položek}} do archivu",
"moved_to_library": "{count, plural, one {Přesunuta # položka} few {Přesunuty # položky} other {Přesunuto # položek}} do knihovny",
"moved_to_archive": "{count, plural, one {# položka přesunuta} few {# položky přesunuty} other {# položek přesunuto}} do archivu",
"moved_to_library": "{count, plural, one {# položka přesunuta} few {# položky přesunuty} other {# položek přesunuto}} do knihovny",
"moved_to_trash": "Přesunuto do koše",
"multiselect_grid_edit_date_time_err_read_only": "Nelze upravit datum položek pouze pro čtení, přeskakuji",
"multiselect_grid_edit_gps_err_read_only": "Nelze upravit polohu položek pouze pro čtení, přeskakuji",
@@ -1292,6 +1347,7 @@
"no_results": "Žádné výsledky",
"no_results_description": "Zkuste použít synonymum nebo obecnější klíčové slovo",
"no_shared_albums_message": "Vytvořte si album a sdílejte fotografie a videa s lidmi ve své síti",
"no_uploads_in_progress": "Neprobíhá žádné nahrávání",
"not_in_any_album": "Bez alba",
"not_selected": "Není vybráno",
"note_apply_storage_label_to_previously_uploaded assets": "Upozornění: Chcete-li použít štítek úložiště na dříve nahrané položky, spusťte příkaz",
@@ -1329,6 +1385,7 @@
"original": "originál",
"other": "Ostatní",
"other_devices": "Ostatní zařízení",
"other_entities": "Ostatní entity",
"other_variables": "Další proměnné",
"owned": "Vlastní",
"owner": "Vlastník",
@@ -1460,6 +1517,7 @@
"purchase_server_description_2": "Stav podporovatele",
"purchase_server_title": "Server",
"purchase_settings_server_activated": "Produktový klíč serveru spravuje správce",
"queue_status": "Ve frontě {count}/{total}",
"rating": "Hodnocení hvězdičkami",
"rating_clear": "Vyčistit hodnocení",
"rating_count": "{count, plural, one {# hvězdička} few {# hvězdičky} other {# hvězdček}}",
@@ -1488,6 +1546,8 @@
"refreshing_faces": "Obnovování obličejů",
"refreshing_metadata": "Obnovování metadat",
"regenerating_thumbnails": "Regenerace miniatur",
"remote": "Vzdálený",
"remote_assets": "Vzdálené položky",
"remove": "Odstranit",
"remove_assets_album_confirmation": "Opravdu chcete z alba odstranit {count, plural, one {# položku} few {# položky} other {# položek}}?",
"remove_assets_shared_link_confirmation": "Opravdu chcete ze sdíleného odkazu odstranit {count, plural, one {# položku} few {# položky} other {# položek}}?",
@@ -1495,7 +1555,9 @@
"remove_custom_date_range": "Odstranit vlastní rozsah datumů",
"remove_deleted_assets": "Odstranit offline soubory",
"remove_from_album": "Odstranit z alba",
"remove_from_album_action_prompt": "{count} odstraněných z alba",
"remove_from_favorites": "Odstranit z oblíbených",
"remove_from_lock_folder_action_prompt": "{count} odebraných z uzamčené složky",
"remove_from_locked_folder": "Odstranit z uzamčené složky",
"remove_from_locked_folder_confirmation": "Opravdu chcete tyto fotky a videa přesunout z uzamčené složky? Budou viditelné ve vaší knihovně.",
"remove_from_shared_link": "Odstranit ze sdíleného odkazu",
@@ -1523,19 +1585,25 @@
"reset_password": "Obnovit heslo",
"reset_people_visibility": "Obnovit viditelnost lidí",
"reset_pin_code": "Resetovat PIN kód",
"reset_sqlite": "Obnovit SQLite databázi",
"reset_sqlite_confirmation": "Jste si jisti, že chcete obnovit SQLite databázi? Pro opětovnou synchronizaci dat se budete muset odhlásit a znovu přihlásit",
"reset_sqlite_success": "Obnovení SQLite databáze proběhlo úspěšně",
"reset_to_default": "Obnovit výchozí nastavení",
"resolve_duplicates": "Vyřešit duplicity",
"resolved_all_duplicates": "Vyřešeny všechny duplicity",
"restore": "Obnovit",
"restore_all": "Obnovit vše",
"restore_trash_action_prompt": "{count} obnoveno z koše",
"restore_user": "Obnovit uživatele",
"restored_asset": "Položka obnovena",
"resume": "Pokračovat",
"retry_upload": "Opakování nahrávání",
"review_duplicates": "Kontrola duplicit",
"review_large_files": "Kontrola velkých souborů",
"role": "Role",
"role_editor": "Editor",
"role_viewer": "Divák",
"running": "Probíhá",
"save": "Uložit",
"save_to_gallery": "Uložit do galerie",
"saved_api_key": "API klíč uložen",
@@ -1667,6 +1735,7 @@
"settings_saved": "Nastavení uloženo",
"setup_pin_code": "Nastavení PIN kódu",
"share": "Sdílet",
"share_action_prompt": "Sdíleno {count} položek",
"share_add_photos": "Přidat fotografie",
"share_assets_selected": "{count} vybráno",
"share_dialog_preparing": "Připravuji...",
@@ -1688,6 +1757,7 @@
"shared_link_clipboard_copied_massage": "Zkopírováno do schránky",
"shared_link_clipboard_text": "Odkaz: {link}\nHeslo: {password}",
"shared_link_create_error": "Chyba při vytváření sdíleného odkazu",
"shared_link_custom_url_description": "Přístup k tomuto sdílenému odkazu pomocí vlastního URL",
"shared_link_edit_description_hint": "Zadejte popis sdílení",
"shared_link_edit_expire_after_option_day": "1 den",
"shared_link_edit_expire_after_option_days": "{count} dní",
@@ -1713,6 +1783,7 @@
"shared_link_info_chip_metadata": "EXIF",
"shared_link_manage_links": "Spravovat sdílené odkazy",
"shared_link_options": "Možnosti sdíleného odkazu",
"shared_link_password_description": "Vyžadovat heslo pro přístup k tomuto sdílenému odkazu",
"shared_links": "Sdílené odkazy",
"shared_links_description": "Sdílet fotky a videa pomocí odkazu",
"shared_photos_and_videos_count": "{assetCount, plural, one {# sdílená fotografie a video.} few {# sdílené fotografie a videa.} other {# sdílených fotografií a videí.}}",
@@ -1768,6 +1839,7 @@
"sort_title": "Název alba",
"source": "Zdroj",
"stack": "Seskupit",
"stack_action_prompt": "{count} seskupeno",
"stack_duplicates": "Seskupit duplicity",
"stack_select_one_photo": "Vyberte jednu hlavní fotografii pro seskupení",
"stack_selected_photos": "Seskupení vybraných fotografií",
@@ -1787,6 +1859,7 @@
"storage_quota": "Kvóta úložiště",
"storage_usage": "Využito {used} z {available}",
"submit": "Odeslat",
"success": "Úspěch",
"suggestions": "Návrhy",
"sunrise_on_the_beach": "Východ slunce na pláži",
"support": "Podpora",
@@ -1796,6 +1869,8 @@
"sync": "Synchronizovat",
"sync_albums": "Synchronizovat alba",
"sync_albums_manual_subtitle": "Synchronizovat všechna nahraná videa a fotografie do vybraných záložních alb",
"sync_local": "Synchronizovat místní",
"sync_remote": "Synchronizovat vzdálené",
"sync_upload_album_setting_subtitle": "Vytvořit a nahrát fotografie a videa do vybraných alb na Immich",
"tag": "Značka",
"tag_assets": "Přiřadit značku",
@@ -1806,6 +1881,7 @@
"tag_updated": "Aktualizována značka: {tag}",
"tagged_assets": "Přiřazena značka {count, plural, one {# položce} other {# položkám}}",
"tags": "Značky",
"tap_to_run_job": "Klepnutím na spustíte úlohu",
"template": "Šablona",
"theme": "Motiv",
"theme_selection": "Výběr motivu",
@@ -1838,6 +1914,7 @@
"total": "Celkem",
"total_usage": "Celkové využití",
"trash": "Koš",
"trash_action_prompt": "{count} přesunutých do koše",
"trash_all": "Vyhodit vše",
"trash_count": "Vyhodit {count, number}",
"trash_delete_asset": "Vyhodit/Smazat položku",
@@ -1854,10 +1931,12 @@
"type": "Typ",
"unable_to_change_pin_code": "Nelze změnit PIN kód",
"unable_to_setup_pin_code": "Nelze nastavit PIN kód",
"unarchive": "Odarchivovat",
"unarchive": "Odebrat z archivu",
"unarchive_action_prompt": "{count} odstraněných z archivu",
"unarchived_count": "{count, plural, one {Odarchivována #} few {Odarchivovány #} other {Odarchivováno #}}",
"undo": "Vrátit zpět",
"unfavorite": "Zrušit oblíbení",
"unfavorite_action_prompt": "{count} odstraněných z oblíbených",
"unhide_person": "Zrušit skrytí osoby",
"unknown": "Neznámý",
"unknown_country": "Neznámá země",
@@ -1875,15 +1954,20 @@
"unselect_all_duplicates": "Zrušit výběr všech duplicit",
"unselect_all_in": "Zrušit výběr ve skupině {group}",
"unstack": "Zrušit seskupení",
"unstacked_assets_count": "{count, plural, one {Rozložená # položka} few {Rozložené # položky} other {Rozložených # položiek}}",
"unstack_action_prompt": "{count} seskupených zrušeno",
"unstacked_assets_count": "{count, plural, one {Rozložená # položka} few {Rozložené # položky} other {Rozložených # položek}}",
"untagged": "Neoznačeno",
"up_next": "To je prozatím vše",
"updated_at": "Aktualizováno",
"updated_password": "Heslo aktualizováno",
"upload": "Nahrát",
"upload_action_prompt": "{count} ve frontě pro nahrání",
"upload_concurrency": "Souběžnost nahrávání",
"upload_details": "Detaily nahrávání",
"upload_dialog_info": "Chcete zálohovat vybrané položky na server?",
"upload_dialog_title": "Nahrát položku",
"upload_errors": "Nahrávání bylo dokončeno s {count, plural, one {# chybou} other {# chybami}}, obnovte stránku pro zobrazení nových položek.",
"upload_finished": "Nahrávání dokončeno",
"upload_progress": "Zbývá {remaining, number} - Zpracováno {processed, number}/{total, number}",
"upload_skipped_duplicates": "{count, plural, one {Přeskočena # duplicitní položka} few {Přeskočeny # duplicitní položky} other {Přeskočeno # duplicitních položek}}",
"upload_status_duplicates": "Duplicity",
@@ -1892,6 +1976,7 @@
"upload_success": "Nahrání proběhlo úspěšně, obnovením stránky se zobrazí nově nahrané položky.",
"upload_to_immich": "Nahrát do Immich ({count})",
"uploading": "Nahrávání",
"uploading_media": "Nahrávání médií",
"url": "URL",
"usage": "Využití",
"use_biometric": "Použít biometrické údaje",
@@ -1912,6 +1997,7 @@
"user_usage_stats_description": "Zobrazit statistiky používání účtu",
"username": "Uživateleské jméno",
"users": "Uživatelé",
"users_added_to_album_count": "{count, plural, one {Přidán # uživatel} few {Přidány # uživatelé} other {Přidáno # uživatelů}} do alba",
"utilities": "Nástroje",
"validate": "Ověřit",
"validate_endpoint_error": "Zadejte platné URL",
@@ -1930,6 +2016,7 @@
"view_album": "Zobrazit album",
"view_all": "Zobrazit vše",
"view_all_users": "Zobrazit všechny uživatele",
"view_details": "Zobrazit podrobnosti",
"view_in_timeline": "Zobrazit na časové ose",
"view_link": "Zobrazit odkaz",
"view_links": "Zobrazit odkazy",
@@ -1941,7 +2028,7 @@
"view_user": "Zobrazit uživatele",
"viewer_remove_from_stack": "Odstranit ze zásobníku",
"viewer_stack_use_as_main_asset": "Použít jako hlavní položku",
"viewer_unstack": "Rozbalit zásobník",
"viewer_unstack": "Zrušit zásobník",
"visibility_changed": "Viditelnost změněna u {count, plural, one {# osoby} few {# osob} other {# lidí}}",
"waiting": "Čekající",
"warning": "Upozornění",

View File

@@ -34,6 +34,7 @@
"added_to_favorites_count": "Tilføjet {count, number} til favoritter",
"admin": {
"add_exclusion_pattern_description": "Tilføj udelukkelsesmønstre. Globbing ved hjælp af *, ** og ? understøttes. For at ignorere alle filer i enhver mappe med navnet \"Raw\", brug \"**/Raw/**\". For at ignorere alle filer, der slutter på \".tif\", brug \"**/*.tif\". For at ignorere en absolut sti, brug \"/sti/til/ignoreret/**\".",
"admin_user": "Administrator bruger",
"asset_offline_description": "Denne eksterne biblioteksressource findes ikke længere på disken og er blevet flyttet til papirkurven. Hvis filen blev flyttet inde i biblioteket, skal du tjekke din tidslinje for den nye tilsvarende ressource. For at gendanne denne ressource skal du sikre, at filstien nedenfor kan tilgås af Immich og scanne biblioteket.",
"authentication_settings": "Godkendelsesindstillinger",
"authentication_settings_description": "Administrer adgangskode, OAuth og andre godkendelsesindstillinger",
@@ -165,6 +166,20 @@
"metadata_settings_description": "Håndtér metadataindstillinger",
"migration_job": "Migrering",
"migration_job_description": "Migrér miniaturebilleder for aktiver og ansigter til den seneste mappestruktur",
"nightly_tasks_cluster_faces_setting_description": "Kør ansigtsgenkendelse på nye ansigter",
"nightly_tasks_cluster_new_faces_setting": "Gruppér nye ansigter",
"nightly_tasks_database_cleanup_setting": "Databaseoprydning opgaver",
"nightly_tasks_database_cleanup_setting_description": "Ryd op i gamle, udløbne data fra databasen",
"nightly_tasks_generate_memories_setting": "Generer minder",
"nightly_tasks_generate_memories_setting_description": "Skab nye minder ud fra dine medier",
"nightly_tasks_missing_thumbnails_setting": "Generer manglende miniaturebilleder",
"nightly_tasks_missing_thumbnails_setting_description": "Sæt medier uden thumbnails i kø til generering af thumbnails",
"nightly_tasks_settings": "Indstillinger for opgaver om natten",
"nightly_tasks_settings_description": "Administrér opgaver om natten",
"nightly_tasks_start_time_setting": "Starttidspunkt",
"nightly_tasks_start_time_setting_description": "Tidspunktet hvor serveren begynder at køre opgaver om natten",
"nightly_tasks_sync_quota_usage_setting": "Synkronisér kvoteforbrug",
"nightly_tasks_sync_quota_usage_setting_description": "Opdater brugerens lagerkvote baseret på aktuelt forbrug",
"no_paths_added": "Ingen stier tilføjet",
"no_pattern_added": "Intet mønster tilføjet",
"note_apply_storage_label_previous_assets": "Bemærk: For at anvende Lagringsmærkatet på tidligere uploadede mediefiler, kør",
@@ -203,7 +218,7 @@
"oauth_storage_quota_claim": "Lagringskvotefordring",
"oauth_storage_quota_claim_description": "Sæt automatisk brugeres lagringskvote til denne nye fordrings værdi.",
"oauth_storage_quota_default": "Standard lagringskvote (GiB)",
"oauth_storage_quota_default_description": "Kvote i GiB som bruges, når der ikke bliver oplyst en fordring (Indtast 0 for uendelig kvote).",
"oauth_storage_quota_default_description": "Kvote i GiB som bruges, når der ikke bliver oplyst en fordring.",
"oauth_timeout": "Forespørgslen udløb",
"oauth_timeout_description": "Udløbstid for forespørgsel i milisekunder",
"password_enable_description": "Log ind med email og adgangskode",
@@ -462,7 +477,6 @@
"assets": "elementer",
"assets_added_count": "Tilføjet {count, plural, one {# mediefil} other {# mediefiler}}",
"assets_added_to_album_count": "{count, plural, one {# mediefil} other {# mediefiler}} tilføjet til albummet",
"assets_added_to_name_count": "Tilføjet {count, plural, one {# mediefil} other {# mediefiler}} til {hasName, select, true {<b>{name}</b>} other {nyt album}}",
"assets_cannot_be_added_to_album_count": "{count, plural, one {Billed} other {Billeder}} kan ikke blive tilføjet til album",
"assets_count": "{count, plural, one {# mediefil} other {# mediefiler}}",
"assets_deleted_permanently": "{count} element(er) blev fjernet permanent",
@@ -488,6 +502,7 @@
"back_close_deselect": "Tilbage, luk eller fravælg",
"background_location_permission": "Tilladelse til baggrundsplacering",
"background_location_permission_content": "For at skifte netværk, når appen kører i baggrunden, skal Immich *altid* have præcis placeringsadgang, så appen kan læse WiFi-netværkets navn",
"backup": "Sikkerhedskopier",
"backup_album_selection_page_albums_device": "Albummer på enheden ({count})",
"backup_album_selection_page_albums_tap": "Tryk en gang for at inkludere, tryk to gange for at ekskludere",
"backup_album_selection_page_assets_scatter": "Elementer kan være spredt på tværs af flere albummer. Albummer kan således inkluderes eller udelukkes under sikkerhedskopieringsprocessen.",
@@ -701,7 +716,6 @@
"daily_title_text_date": "E, dd MMM",
"daily_title_text_date_year": "E, dd MMM, yyyy",
"dark": "Mørk",
"darkTheme": "Skift til mørkt tema",
"date_after": "Dato efter",
"date_and_time": "Dato og klokkeslæt",
"date_before": "Dato før",
@@ -1128,7 +1142,6 @@
"light": "Lys",
"like_deleted": "Ligesom slettet",
"link_motion_video": "Link bevægelsesvideo",
"link_options": "Link-indstillinger",
"link_to_oauth": "Link til OAuth",
"linked_oauth_account": "Tilsluttet OAuth-konto",
"list": "Liste",
@@ -1190,7 +1203,6 @@
"manage_your_devices": "Administrér dine enheder der er logget ind",
"manage_your_oauth_connection": "Administrér din OAuth-tilslutning",
"map": "Kort",
"map_assets_in_bound": "{count} billede",
"map_assets_in_bounds": "{count} billeder",
"map_cannot_get_user_location": "Kan ikke finde brugerens placering",
"map_location_dialog_yes": "Ja",

View File

@@ -14,6 +14,7 @@
"add_a_location": "Standort hinzufügen",
"add_a_name": "Name hinzufügen",
"add_a_title": "Titel hinzufügen",
"add_birthday": "Geburtsdatum hinzufügen",
"add_endpoint": "Endpunkt hinzufügen",
"add_exclusion_pattern": "Ausschlussmuster hinzufügen",
"add_import_path": "Importpfad hinzufügen",
@@ -41,9 +42,16 @@
"authentication_settings_disable_all": "Bist du sicher, dass du alle Anmeldemethoden deaktivieren willst? Die Anmeldung wird vollständig deaktiviert.",
"authentication_settings_reenable": "Nutze einen <link>Server-Befehl</link> zur Reaktivierung.",
"background_task_job": "Hintergrundaufgaben",
"backup_database": "Datenbanksicherung regelmäßig erstellen",
"backup_database": "Datenbanksicherung erstellen",
"backup_database_enable_description": "Datenbank regelmäßig sichern",
"backup_keep_last_amount": "Anzahl der aufzubewahrenden früheren Backups",
"backup_onboarding_1_description": "Offsite-Kopie in der Cloud oder an einem anderen physischen Ort.",
"backup_onboarding_2_description": "Lokale Kopien auf verschiedenen Geräten. Dazu gehören die Hauptdateien und eine lokale Sicherung dieser Dateien.",
"backup_onboarding_3_description": "3 komplette Kopien deiner Daten, inkl. der Originaldateien. Dies umfasst 1 Kopie an einem anderen Ort und 2 lokale Kopie.",
"backup_onboarding_description": "Eine <backblaze-link>3-2-1 Backup-Strategie</backblaze-link> wird empfohlen, um deine Daten zu schützen. Du solltest sowohl Kopien deiner hochgeladenen Fotos/Videos als auch der Immich-Datenbank aufbewahren, um eine umfassende Backup-Lösung zu haben.",
"backup_onboarding_footer": "Weitere Informationen zum Sichern von Immich findest du in der <link>Dokumentation</link>.",
"backup_onboarding_parts_title": "Eine 3-2-1-Sicherung umfasst:",
"backup_onboarding_title": "Backups",
"backup_settings": "Einstellungen für Datenbanksicherung",
"backup_settings_description": "Einstellungen zur regelmäßigen Sicherung der Datenbank. Hinweis: Diese Jobs werden nicht überwacht und du wirst nicht über Fehler informiert.",
"cleared_jobs": "Folgende Aufgaben zurückgesetzt: {job}",
@@ -56,9 +64,9 @@
"confirm_user_pin_code_reset": "Bist du sicher, dass du den PIN Code von {user} zurücksetzen möchtest?",
"create_job": "Aufgabe erstellen",
"cron_expression": "Cron Zeitangabe",
"cron_expression_description": "Setze ein Intervall für die Sicherung mittels cron. Hilfe mit dem Format bietet dir dabei z.B der <link>Crontab Guru</link>",
"cron_expression_description": "Setze ein Intervall für die Sicherung mittels cron. Hilfe mit dem Format bietet dir dabei z. B. der <link>Crontab Guru</link>",
"cron_expression_presets": "Nützliche Zeitangaben für Cron",
"disable_login": "Login deaktvieren",
"disable_login": "Login deaktivieren",
"duplicate_detection_job_description": "Diese Aufgabe führt das maschinelle Lernen für jede Datei aus, um Duplikate zu finden. Diese Aufgabe beruht auf der intelligenten Suche",
"exclusion_pattern_description": "Mit Ausschlussmustern können Dateien und Ordner beim Scannen Ihrer Bibliothek ignoriert werden. Dies ist nützlich, wenn du Ordner hast, die Dateien enthalten, die du nicht importieren möchtest, wie z. B. RAW-Dateien.",
"external_library_management": "Verwaltung externer Bibliotheken",
@@ -120,7 +128,7 @@
"machine_learning_duplicate_detection_setting_description": "Verwendung von CLIP-Embeddings zum Erkennen möglicher Duplikate",
"machine_learning_enabled": "Maschinelles Lernen aktivieren",
"machine_learning_enabled_description": "Wenn diese Option deaktiviert ist, werden alle ML-Funktionen unabhängig von den unten aufgeführten Einstellungen deaktiviert.",
"machine_learning_facial_recognition": "Gesichtsidentifikation",
"machine_learning_facial_recognition": "Gesichtsidentifizierung",
"machine_learning_facial_recognition_description": "Erkenne, identifiziere und gruppiere Gesichter in Bildern",
"machine_learning_facial_recognition_model": "Gesichtserkennungs-Modell",
"machine_learning_facial_recognition_model_description": "Die Modelle sind in absteigender Reihenfolge ihrer Größe aufgeführt. Größere Modelle sind langsamer und verbrauchen mehr Speicher, liefern aber bessere Ergebnisse. Bitte beachte dabei, dass du die Gesichtserkennungsaufgabe für alle Bilder neu starten musst, wenn du ein Modell änderst.",
@@ -166,6 +174,20 @@
"metadata_settings_description": "Metadaten-Einstellungen verwalten",
"migration_job": "Migration",
"migration_job_description": "Diese Aufgabe migriert Miniaturansichten für Dateien und Gesichter in die neueste Ordnerstruktur",
"nightly_tasks_cluster_faces_setting_description": "Gesichtsidentifikation auf neu erkannten Gesichtern ausführen",
"nightly_tasks_cluster_new_faces_setting": "Neue Gesichter gruppieren",
"nightly_tasks_database_cleanup_setting": "Datenbankbereinigungs-Aufgaben",
"nightly_tasks_database_cleanup_setting_description": "Alte, abgelaufene Daten aus der Datenbank bereinigen",
"nightly_tasks_generate_memories_setting": "Erinnerungen generieren",
"nightly_tasks_generate_memories_setting_description": "Neue Erinnerungen aus Dateien erstellen",
"nightly_tasks_missing_thumbnails_setting": "Fehlende Miniaturansichten generieren",
"nightly_tasks_missing_thumbnails_setting_description": "Dateien ohne Miniaturansicht in die Warteschlange zur Miniaturansicht-Generierung hinzufügen",
"nightly_tasks_settings": "Einstellungen für nächtliche Aufgaben",
"nightly_tasks_settings_description": "Nächtliche Aufgaben verwalten",
"nightly_tasks_start_time_setting": "Startzeit",
"nightly_tasks_start_time_setting_description": "Die Zeit, zu der der Server mit der Ausführung der nächtlichen Aufgaben beginnt",
"nightly_tasks_sync_quota_usage_setting": "Kontingentnutzung synchronisieren",
"nightly_tasks_sync_quota_usage_setting_description": "Benutzerspeicherkontingent basierend auf der aktuellen Nutzung aktualisieren",
"no_paths_added": "Keine Pfade hinzugefügt",
"no_pattern_added": "Kein Ausschlussmuster hinzugefügt",
"note_apply_storage_label_previous_assets": "Hinweis: Um den Speicherpfad auf die vorher hochgeladenen Dateien anzuwenden, starte den",
@@ -196,6 +218,8 @@
"oauth_mobile_redirect_uri": "Mobile Umleitungs-URI",
"oauth_mobile_redirect_uri_override": "Mobile Umleitungs-URI überschreiben",
"oauth_mobile_redirect_uri_override_description": "Einschalten, wenn der OAuth-Anbieter keine mobile URI wie ''{callback}'' erlaubt",
"oauth_role_claim": "Rollen-Claim",
"oauth_role_claim_description": "Gewähre automatisch Admin-Zugriff basierend auf dem Vorhandensein dieses Claims. Der Claim kann entweder 'user' oder 'admin' sein.",
"oauth_settings": "OAuth",
"oauth_settings_description": "OAuth-Anmeldeeinstellungen verwalten",
"oauth_settings_more_details": "Weitere Informationen zu dieser Funktion findest du in der <link>Dokumentation</link>.",
@@ -244,6 +268,7 @@
"storage_template_migration_info": "Die Speichervorlage wird alle Dateierweiterungen in Kleinbuchstaben umwandeln. Vorlagenänderungen gelten nur für neue Dateien. Um die Vorlage rückwirkend auf bereits hochgeladene Assets anzuwenden, führe den <link>{job}</link> aus.",
"storage_template_migration_job": "Speichervorlagenmigrations-Aufgabe",
"storage_template_more_details": "Weitere Details zu dieser Funktion findest du unter <template-link>Speichervorlage</template-link> und dessen <implications-link>Implikationen</implications-link>",
"storage_template_onboarding_description_v2": "Wenn aktiviert, werden Dateien automatisch nach einer benutzerdefinierten Vorlage organisiert. Für mehr Informationen siehe die <link>Dokumentation</link>.",
"storage_template_path_length": "Ungefähres Pfadlängen-Limit: <b>{length, number}</b>/{limit, number}",
"storage_template_settings": "Speichervorlage",
"storage_template_settings_description": "Die Ordnerstruktur und den Dateinamen der hochgeladenen Datei verwalten",
@@ -356,17 +381,19 @@
"admin_password": "Administrator Passwort",
"administration": "Verwaltung",
"advanced": "Erweitert",
"advanced_settings_beta_timeline_subtitle": "Probier die neue App-Erfahrung aus",
"advanced_settings_beta_timeline_title": "Beta-Timeline",
"advanced_settings_enable_alternate_media_filter_subtitle": "Verwende diese Option, um Medien während der Synchronisierung nach anderen Kriterien zu filtern. Versuchen dies nur, wenn Probleme mit der Erkennung aller Alben durch die App auftreten.",
"advanced_settings_enable_alternate_media_filter_title": "[EXPERIMENTELL] Benutze alternativen Filter für Synchronisierung der Gerätealben",
"advanced_settings_log_level_title": "Log-Level: {level}",
"advanced_settings_prefer_remote_subtitle": "Einige Geräte sind sehr langsam beim Laden von Miniaturbildern direkt aus dem Gerät. Aktivieren Sie diese Einstellung, um stattdessen die Server-Bilder zu laden.",
"advanced_settings_prefer_remote_subtitle": "Einige Geräte sind sehr langsam beim Laden von lokalen Vorschaubildern. Aktivieren Sie diese Einstellung, um stattdessen die Server-Bilder zu laden.",
"advanced_settings_prefer_remote_title": "Server-Bilder bevorzugen",
"advanced_settings_proxy_headers_subtitle": "Definiere einen Proxy-Header, den Immich bei jeder Netzwerkanfrage mitschicken soll",
"advanced_settings_proxy_headers_title": "Proxy-Headers",
"advanced_settings_self_signed_ssl_subtitle": "Verifizierung von SSL-Zertifikaten vom Server überspringen. Notwendig bei selbstsignierten Zertifikaten.",
"advanced_settings_self_signed_ssl_title": "Selbstsignierte SSL-Zertifikate erlauben",
"advanced_settings_sync_remote_deletions_subtitle": "Automatisches Löschen oder Wiederherstellen einer Datei auf diesem Gerät, wenn diese Aktion im Web durchgeführt wird",
"advanced_settings_sync_remote_deletions_title": "Synchrone Remote-Löschungen [Experimentell]",
"advanced_settings_sync_remote_deletions_title": "Mit Server-Löschungen synchronisieren [Experimentell]",
"advanced_settings_tile_subtitle": "Erweiterte Benutzereinstellungen",
"advanced_settings_troubleshooting_subtitle": "Erweiterte Funktionen zur Fehlersuche aktivieren",
"advanced_settings_troubleshooting_title": "Fehlersuche",
@@ -378,6 +405,7 @@
"album_cover_updated": "Album-Cover aktualisiert",
"album_delete_confirmation": "Bist du sicher, dass du das Album {album} löschen willst?",
"album_delete_confirmation_description": "Falls dieses Album geteilt wurde, können andere Benutzer nicht mehr darauf zugreifen.",
"album_deleted": "Album gelöscht",
"album_info_card_backup_album_excluded": "AUSGESCHLOSSEN",
"album_info_card_backup_album_included": "EINGESCHLOSSEN",
"album_info_updated": "Album-Infos aktualisiert",
@@ -387,6 +415,7 @@
"album_options": "Albumoptionen",
"album_remove_user": "Nutzer entfernen?",
"album_remove_user_confirmation": "Bist du sicher, dass du {user} entfernen willst?",
"album_search_not_found": "Keine Alben gefunden, die zur Suche passen",
"album_share_no_users": "Es sieht so aus, als hättest du dieses Album mit allen Benutzern geteilt oder du hast keine Benutzer, mit denen du teilen kannst.",
"album_updated": "Album aktualisiert",
"album_updated_setting_description": "Erhalte eine E-Mail-Benachrichtigung, wenn ein freigegebenes Album neue Dateien enthält",
@@ -406,6 +435,7 @@
"albums_default_sort_order": "Standard Album Sortierung",
"albums_default_sort_order_description": "Sortierreihenfolge der Dateien bei der Erstellung neuer Alben.",
"albums_feature_description": "Sammlung an Alben die mit anderen Benutzern geteilt werden können.",
"albums_on_device_count": "Alben auf dem Gerät ({count})",
"all": "Alle",
"all_albums": "Alle Alben",
"all_people": "Alle Personen",
@@ -426,6 +456,7 @@
"app_settings": "App-Einstellungen",
"appears_in": "Erscheint in",
"archive": "Archiv",
"archive_action_prompt": "{count} zum Archiv hinzugefügt",
"archive_or_unarchive_photo": "Foto archivieren bzw. Archivierung aufheben",
"archive_page_no_archived_assets": "Keine archivierten Inhalte gefunden",
"archive_page_title": "Archiv ({count})",
@@ -463,7 +494,6 @@
"assets": "Dateien",
"assets_added_count": "{count, plural, one {# Datei} other {# Dateien}} hinzugefügt",
"assets_added_to_album_count": "{count, plural, one {# Datei} other {# Dateien}} zum Album hinzugefügt",
"assets_added_to_name_count": "{count, plural, one {# Element} other {# Elemente}} zu {hasName, select, true {<b>{name}</b>} other {neuem Album}} hinzugefügt",
"assets_cannot_be_added_to_album_count": "{count, plural, one {Datei kann}other {Dateien können}} nicht zum Album hinzugefügt werden",
"assets_count": "{count, plural, one {# Datei} other {# Dateien}}",
"assets_deleted_permanently": "{count} Element(e) permanent gelöscht",
@@ -489,6 +519,7 @@
"back_close_deselect": "Zurück, Schließen oder Abwählen",
"background_location_permission": "Hintergrund Standortfreigabe",
"background_location_permission_content": "Um im Hintergrund zwischen den Netzwerken wechseln zu können, muss Immich *immer* Zugriff auf den genauen Standort haben, damit die App den Namen des WLAN-Netzwerks ermitteln kann",
"backup": "Sicherung",
"backup_album_selection_page_albums_device": "Alben auf dem Gerät ({count})",
"backup_album_selection_page_albums_tap": "Einmalig das Album antippen um es zu sichern, doppelt antippen um es nicht mehr zu sichern",
"backup_album_selection_page_assets_scatter": "Elemente (Fotos / Videos) können sich über mehrere Alben verteilen. Daher können diese vor der Sicherung eingeschlossen oder ausgeschlossen werden.",
@@ -552,6 +583,8 @@
"backup_options_page_title": "Sicherungsoptionen",
"backup_setting_subtitle": "Verwaltung der Upload-Einstellungen im Hintergrund und im Vordergrund",
"backward": "Rückwärts",
"beta_sync": "Status der Beta-Synchronisierung",
"beta_sync_subtitle": "Verwalte das neue Synchronisierungssystem",
"biometric_auth_enabled": "Biometrische Authentifizierung aktiviert",
"biometric_locked_out": "Du bist von der biometrischen Authentifizierung ausgeschlossen",
"biometric_no_options": "Keine biometrischen Optionen verfügbar",
@@ -586,6 +619,7 @@
"cancel": "Abbrechen",
"cancel_search": "Suche abbrechen",
"canceled": "Abgebrochen",
"canceling": "Abbrechen",
"cannot_merge_people": "Personen können nicht zusammengeführt werden",
"cannot_undo_this_action": "Diese Aktion kann nicht rückgängig gemacht werden!",
"cannot_update_the_description": "Beschreibung kann nicht aktualisiert werden",
@@ -699,10 +733,11 @@
"current_server_address": "Aktuelle Serveradresse",
"custom_locale": "Benutzerdefinierte Sprache",
"custom_locale_description": "Datumsangaben und Zahlen je nach Sprache und Land formatieren",
"custom_url": "Benutzerdefinierte URL",
"daily_title_text_date": "E, dd MMM",
"daily_title_text_date_year": "E, dd MMM, yyyy",
"dark": "Dunkel",
"darkTheme": "Dunkles Theme umschalten",
"dark_theme": "Dunkle Ansicht umschalten",
"date_after": "Datum nach",
"date_and_time": "Datum und Zeit",
"date_before": "Datum vor",
@@ -718,6 +753,8 @@
"default_locale": "Standard-Sprache",
"default_locale_description": "Datumsangaben und Zahlen basierend auf dem Gebietsschema des Browsers formatieren",
"delete": "Löschen",
"delete_action_confirmation_message": "Bist du sicher, dass du dieses Objekt löschen willst? Diese Aktion wird das Objekt in den Papierkorb des Servers verschieben und fragen, ob du es lokal löschen willst",
"delete_action_prompt": "{count} gelöscht",
"delete_album": "Album löschen",
"delete_api_key_prompt": "Bist du sicher, dass du diesen API-Schlüssel löschen willst?",
"delete_dialog_alert": "Diese Elemente werden unwiderruflich von Immich und dem Gerät entfernt",
@@ -731,9 +768,12 @@
"delete_key": "Schlüssel löschen",
"delete_library": "Bibliothek löschen",
"delete_link": "Link löschen",
"delete_local_action_prompt": "{count} lokal gelöscht",
"delete_local_dialog_ok_backed_up_only": "Nur gesicherte Inhalte löschen",
"delete_local_dialog_ok_force": "Trotzdem löschen",
"delete_others": "Andere löschen",
"delete_permanently": "Endgültig löschen",
"delete_permanently_action_prompt": "{count} endgültig gelöscht",
"delete_shared_link": "geteilten Link löschen",
"delete_shared_link_dialog_title": "Geteilten Link löschen",
"delete_tag": "Tag löschen",
@@ -744,6 +784,7 @@
"description": "Beschreibung",
"description_input_hint_text": "Beschreibung hinzufügen...",
"description_input_submit_error": "Beschreibung konnte nicht geändert werden, bitte im Log für mehr Details nachsehen",
"deselect_all": "Alle abwählen",
"details": "Details",
"direction": "Richtung",
"disabled": "Deaktiviert",
@@ -761,6 +802,7 @@
"documentation": "Dokumentation",
"done": "Fertig",
"download": "Herunterladen",
"download_action_prompt": "Herunterladen von {count} Dateien",
"download_canceled": "Download abgebrochen",
"download_complete": "Download vollständig",
"download_enqueue": "Download in die Warteschlange gesetzt",
@@ -787,6 +829,7 @@
"edit": "Bearbeiten",
"edit_album": "Album bearbeiten",
"edit_avatar": "Avatar bearbeiten",
"edit_birthday": "Geburtsdatum bearbeiten",
"edit_date": "Datum bearbeiten",
"edit_date_and_time": "Datum und Uhrzeit bearbeiten",
"edit_description": "Beschreibung bearbeiten",
@@ -798,6 +841,7 @@
"edit_key": "Schlüssel bearbeiten",
"edit_link": "Link bearbeiten",
"edit_location": "Standort bearbeiten",
"edit_location_action_prompt": "{count} Geolokationen angepasst",
"edit_location_dialog_title": "Ort bearbeiten",
"edit_name": "Name bearbeiten",
"edit_people": "Personen bearbeiten",
@@ -816,6 +860,7 @@
"empty_trash": "Papierkorb leeren",
"empty_trash_confirmation": "Bist du sicher, dass du den Papierkorb leeren willst?\nDies entfernt alle Dateien im Papierkorb endgültig aus Immich und kann nicht rückgängig gemacht werden!",
"enable": "Aktivieren",
"enable_backup": "Sicherung aktivieren",
"enable_biometric_auth_description": "Gib deinen PIN Code ein, um die biometrische Authentifizierung zu aktivieren",
"enabled": "Aktiviert",
"end_date": "Enddatum",
@@ -952,6 +997,7 @@
},
"exif": "EXIF",
"exif_bottom_sheet_description": "Beschreibung hinzufügen...",
"exif_bottom_sheet_description_error": "Fehler bei der Aktualisierung der Beschreibung",
"exif_bottom_sheet_details": "DETAILS",
"exif_bottom_sheet_location": "STANDORT",
"exif_bottom_sheet_people": "PERSONEN",
@@ -972,6 +1018,8 @@
"explorer": "Datei-Explorer",
"export": "Exportieren",
"export_as_json": "Als JSON exportieren",
"export_database": "Datenbank exportieren",
"export_database_description": "Exportiert die SQLite Datenbank",
"extension": "Erweiterung",
"external": "Extern",
"external_libraries": "Externe Bibliotheken",
@@ -983,6 +1031,7 @@
"failed_to_load_assets": "Laden der Assets fehlgeschlagen",
"failed_to_load_folder": "Fehler beim Laden des Ordners",
"favorite": "Favorit",
"favorite_action_prompt": "{count} zu den Favoriten hinzugefügt",
"favorite_or_unfavorite_photo": "Favorisiertes oder nicht favorisiertes Foto",
"favorites": "Favoriten",
"favorites_page_no_favorites": "Keine favorisierten Inhalte gefunden",
@@ -1022,6 +1071,9 @@
"haptic_feedback_switch": "Haptisches Feedback aktivieren",
"haptic_feedback_title": "Haptisches Feedback",
"has_quota": "Kontingent",
"hash_asset": "Dateihash",
"hashed_assets": "Gehashte Dateien",
"hashing": "Hashen",
"header_settings_add_header_tip": "Header hinzufügen",
"header_settings_field_validator_msg": "Der Wert darf nicht leer sein",
"header_settings_header_name_input": "Header-Name",
@@ -1043,7 +1095,7 @@
"home_page_archive_err_partner": "Inhalte von Partnern können nicht archiviert werden",
"home_page_building_timeline": "Zeitachse wird erstellt",
"home_page_delete_err_partner": "Inhalte von Partnern können nicht gelöscht werden, überspringe",
"home_page_delete_remote_err_local": "Lokale Inhalte in der Auswahl, überspringen",
"home_page_delete_remote_err_local": "Lokale Elemente in der Auswahl zum Entfernen von Remote-Elementen, Überspringe",
"home_page_favorite_err_local": "Kann lokale Elemente noch nicht favorisieren, überspringen",
"home_page_favorite_err_partner": "Inhalte von Partnern können nicht favorisiert werden, überspringe",
"home_page_first_time_notice": "Wenn dies das erste Mal ist dass Du Immich nutzt, stelle bitte sicher, dass mindestens ein Album zur Sicherung ausgewählt ist, sodass die Zeitachse mit Fotos und Videos gefüllt werden kann",
@@ -1054,6 +1106,7 @@
"host": "Host",
"hour": "Stunde",
"id": "ID",
"idle": "Untätig",
"ignore_icloud_photos": "iCloud Fotos ignorieren",
"ignore_icloud_photos_description": "Fotos, die in der iCloud gespeichert sind, werden nicht auf den immich Server hochgeladen",
"image": "Bild",
@@ -1111,6 +1164,7 @@
"language_no_results_title": "Keine Sprachen gefunden",
"language_search_hint": "Sprachen durchsuchen...",
"language_setting_description": "Wähle deine bevorzugte Sprache",
"large_files": "Große Dateien",
"last_seen": "Zuletzt gesehen",
"latest_version": "Aktuellste Version",
"latitude": "Breitengrad",
@@ -1126,16 +1180,18 @@
"library_page_sort_created": "Zuletzt erstellt",
"library_page_sort_last_modified": "Zuletzt bearbeitet",
"library_page_sort_title": "Titel des Albums",
"licenses": "Lizenzen",
"light": "Hell",
"like_deleted": "Like gelöscht",
"link_motion_video": "Bewegungsvideo verknüpfen",
"link_options": "Link-Optionen",
"link_to_oauth": "Mit OAuth verknüpfen",
"linked_oauth_account": "Verknüpftes OAuth-Konto",
"list": "Liste",
"loading": "Laden",
"loading_search_results_failed": "Laden von Suchergebnissen fehlgeschlagen",
"local": "Lokal",
"local_asset_cast_failed": "Eine Datei, die nicht auf den Server hochgeladen wurde, kann nicht gecastet werden",
"local_assets": "Lokale Dateien",
"local_network": "Lokales Netzwerk",
"local_network_sheet_info": "Die App stellt über diese URL eine Verbindung zum Server her, wenn sie das angegebene WLAN-Netzwerk verwendet",
"location_permission": "Standort Genehmigung",
@@ -1192,8 +1248,7 @@
"manage_your_devices": "Deine eingeloggten Geräte verwalten",
"manage_your_oauth_connection": "Deine OAuth-Verknüpfung verwalten",
"map": "Karte",
"map_assets_in_bound": "{count} Foto",
"map_assets_in_bounds": "{count} Fotos",
"map_assets_in_bounds": "{count, plural, one {# Foto} other {# Fotos}}",
"map_cannot_get_user_location": "Standort konnte nicht ermittelt werden",
"map_location_dialog_yes": "Ja",
"map_location_picker_page_use_location": "Aufnahmeort verwenden",
@@ -1245,6 +1300,7 @@
"more": "Mehr",
"move": "Verschieben",
"move_off_locked_folder": "Aus dem gesperrten Ordner verschieben",
"move_to_lock_folder_action_prompt": "{count} zum gesperrten Ordner hinzugefügt",
"move_to_locked_folder": "In den gesperrten Ordner verschieben",
"move_to_locked_folder_confirmation": "Diese Fotos und Videos werden aus allen Alben entfernt und können nur noch im gesperrten Ordner angezeigt werden",
"moved_to_archive": "{count, plural, one {# Datei} other {# Dateien}} archiviert",
@@ -1291,6 +1347,7 @@
"no_results": "Keine Ergebnisse",
"no_results_description": "Versuche es mit einem Synonym oder einem allgemeineren Stichwort",
"no_shared_albums_message": "Erstelle ein Album, um Fotos und Videos mit Personen in deinem Netzwerk zu teilen",
"no_uploads_in_progress": "Kein Upload in Bearbeitung",
"not_in_any_album": "In keinem Album",
"not_selected": "Nicht ausgewählt",
"note_apply_storage_label_to_previously_uploaded assets": "Hinweis: Um eine Speicherpfadbezeichnung anzuwenden, starte den",
@@ -1328,6 +1385,7 @@
"original": "Original",
"other": "Sonstiges",
"other_devices": "Andere Geräte",
"other_entities": "Andere Entitäten",
"other_variables": "Sonstige Variablen",
"owned": "Eigenes",
"owner": "Besitzer",
@@ -1459,6 +1517,7 @@
"purchase_server_description_2": "Unterstützerstatus",
"purchase_server_title": "Server",
"purchase_settings_server_activated": "Der Server-Produktschlüssel wird durch den Administrator verwaltet",
"queue_status": "Warteschlange {count}/{total}",
"rating": "Bewertung",
"rating_clear": "Bewertung löschen",
"rating_count": "{count, plural, one {# Stern} other {# Sterne}}",
@@ -1487,6 +1546,8 @@
"refreshing_faces": "Gesichter werden aktualisiert",
"refreshing_metadata": "Metadaten werden aktualisiert",
"regenerating_thumbnails": "Miniaturansichten werden neu erstellt",
"remote": "Server",
"remote_assets": "Server-Dateien",
"remove": "Entfernen",
"remove_assets_album_confirmation": "Bist du sicher, dass du {count, plural, one {# Datei} other {# Dateien}} aus dem Album entfernen willst?",
"remove_assets_shared_link_confirmation": "Bist du sicher, dass du {count, plural, one {# Datei} other {# Dateien}} von diesem geteilten Link entfernen willst?",
@@ -1494,7 +1555,9 @@
"remove_custom_date_range": "Benutzerdefinierten Datumsbereich entfernen",
"remove_deleted_assets": "Offline-Dateien entfernen",
"remove_from_album": "Aus Album entfernen",
"remove_from_album_action_prompt": "{count} vom Album entfernt",
"remove_from_favorites": "Aus Favoriten entfernen",
"remove_from_lock_folder_action_prompt": "{count} aus dem gesperrten Ordner entfernt",
"remove_from_locked_folder": "Aus gesperrtem Ordner entfernen",
"remove_from_locked_folder_confirmation": "Bist du sicher, dass du diese Fotos und Videos aus dem gesperrten Ordner entfernen möchtest? Sie werden wieder in deiner Bibliothek sichtbar sein.",
"remove_from_shared_link": "Aus geteiltem Link entfernen",
@@ -1522,19 +1585,25 @@
"reset_password": "Passwort zurücksetzen",
"reset_people_visibility": "Sichtbarkeit von Personen zurücksetzen",
"reset_pin_code": "PIN Code zurücksetzen",
"reset_sqlite": "SQLite Datenbank zurücksetzen",
"reset_sqlite_confirmation": "Bist du sicher, dass du die SQLite-Datenbank zurücksetzen willst? Du musst dich ab- und wieder anmelden, um die Daten neu zu synchronisieren",
"reset_sqlite_success": "SQLite Datenbank erfolgreich zurückgesetzt",
"reset_to_default": "Auf Standard zurücksetzen",
"resolve_duplicates": "Duplikate entfernen",
"resolved_all_duplicates": "Alle Duplikate aufgelöst",
"restore": "Wiederherstellen",
"restore_all": "Alle wiederherstellen",
"restore_trash_action_prompt": "{count} aus dem Papierkorb wiederhergestellt",
"restore_user": "Nutzer wiederherstellen",
"restored_asset": "Datei wiederhergestellt",
"resume": "Fortsetzen",
"retry_upload": "Upload wiederholen",
"review_duplicates": "Duplikate überprüfen",
"review_large_files": "Große Dateien überprüfen",
"role": "Rolle",
"role_editor": "Bearbeiter",
"role_viewer": "Betrachter",
"running": "Läuft",
"save": "Speichern",
"save_to_gallery": "In Galerie speichern",
"saved_api_key": "API-Schlüssel wurde gespeichert",
@@ -1666,6 +1735,7 @@
"settings_saved": "Einstellungen gespeichert",
"setup_pin_code": "Einen PIN Code festlegen",
"share": "Teilen",
"share_action_prompt": "{count} Dateien geteilt",
"share_add_photos": "Fotos hinzufügen",
"share_assets_selected": "{count} ausgewählt",
"share_dialog_preparing": "Vorbereiten...",
@@ -1687,6 +1757,7 @@
"shared_link_clipboard_copied_massage": "Link kopiert",
"shared_link_clipboard_text": "Link: {link}\nPasswort: {password}",
"shared_link_create_error": "Fehler beim Erstellen der Linkfreigabe",
"shared_link_custom_url_description": "Greife über eine benutzerdefinierte URL auf diesen Freigabelink zu",
"shared_link_edit_description_hint": "Beschreibung eingeben",
"shared_link_edit_expire_after_option_day": "1 Tag",
"shared_link_edit_expire_after_option_days": "{count} Tagen",
@@ -1712,6 +1783,7 @@
"shared_link_info_chip_metadata": "EXIF",
"shared_link_manage_links": "Geteilte Links verwalten",
"shared_link_options": "Optionen für geteilten Link",
"shared_link_password_description": "Für den Zugriff auf diesen freigegebenen Link ist ein Passwort erforderlich",
"shared_links": "Geteilte Links",
"shared_links_description": "Teile Fotos und Videos mit einem Link",
"shared_photos_and_videos_count": "{assetCount, plural, one {# geteiltes Foto oder Video.} other {# geteilte Fotos & Videos.}}",
@@ -1767,6 +1839,7 @@
"sort_title": "Titel",
"source": "Quellcode",
"stack": "Stapel",
"stack_action_prompt": "{count} gestapelt",
"stack_duplicates": "Duplikate stapeln",
"stack_select_one_photo": "Hauptfoto für den Stapel auswählen",
"stack_selected_photos": "Ausgewählte Fotos stapeln",
@@ -1786,6 +1859,7 @@
"storage_quota": "Speicherplatz-Kontingent",
"storage_usage": "{used} von {available} verwendet",
"submit": "Bestätigen",
"success": "Erfolgreich",
"suggestions": "Vorschläge",
"sunrise_on_the_beach": "Sonnenaufgang am Strand",
"support": "Unterstützung",
@@ -1795,6 +1869,8 @@
"sync": "Synchronisieren",
"sync_albums": "Alben synchronisieren",
"sync_albums_manual_subtitle": "Synchronisiere alle hochgeladenen Videos und Fotos in die ausgewählten Backup-Alben",
"sync_local": "Lokal synchronisieren",
"sync_remote": "mit Server synchronisieren",
"sync_upload_album_setting_subtitle": "Erstelle deine ausgewählten Alben in Immich und lade die Fotos und Videos dort hoch",
"tag": "Tag",
"tag_assets": "Dateien taggen",
@@ -1805,11 +1881,12 @@
"tag_updated": "Tag aktualisiert: {tag}",
"tagged_assets": "{count, plural, one {# Datei} other {# Dateien}} getagged",
"tags": "Tags",
"tap_to_run_job": "Tippen um den Job zu starten",
"template": "Vorlage",
"theme": "Theme",
"theme_selection": "Themenauswahl",
"theme_selection_description": "Automatische Einstellung des Themes auf Hell oder Dunkel, je nach Systemeinstellung des Browsers",
"theme_setting_asset_list_storage_indicator_title": "Forschrittsbalken der Sicherung auf dem Vorschaubild",
"theme_setting_asset_list_storage_indicator_title": "Fortschrittsbalken der Sicherung auf dem Vorschaubild",
"theme_setting_asset_list_tiles_per_row_title": "Anzahl der Elemente pro Reihe ({count})",
"theme_setting_colorful_interface_subtitle": "Primärfarbe auf App-Hintergrund anwenden.",
"theme_setting_colorful_interface_title": "Farbige UI-Oberfläche",
@@ -1837,6 +1914,7 @@
"total": "Gesamt",
"total_usage": "Gesamtnutzung",
"trash": "Papierkorb",
"trash_action_prompt": "{count} in den Papierkorb verschoben",
"trash_all": "Alle löschen",
"trash_count": "Papierkorb {count, number}",
"trash_delete_asset": "Datei löschen/in den Papierkorb verschieben",
@@ -1854,9 +1932,11 @@
"unable_to_change_pin_code": "PIN Code konnte nicht geändert werden",
"unable_to_setup_pin_code": "PIN Code konnte nicht festgelegt werden",
"unarchive": "Entarchivieren",
"unarchive_action_prompt": "{count} aus dem Archiv entfernt",
"unarchived_count": "{count, plural, other {# entarchiviert}}",
"undo": "Rückgängig",
"unfavorite": "Entfavorisieren",
"unfavorite_action_prompt": "{count} aus den Favoriten entfernt",
"unhide_person": "Person einblenden",
"unknown": "Unbekannt",
"unknown_country": "Unbekanntes Land",
@@ -1874,15 +1954,20 @@
"unselect_all_duplicates": "Alle Duplikate abwählen",
"unselect_all_in": "Alle in {group} abwählen",
"unstack": "Entstapeln",
"unstack_action_prompt": "{count} entstapelt",
"unstacked_assets_count": "{count, plural, one {# Datei} other {# Dateien}} entstapelt",
"untagged": "Ohne Tag",
"up_next": "Weiter",
"updated_at": "Aktualisiert",
"updated_password": "Passwort aktualisiert",
"upload": "Hochladen",
"upload_action_prompt": "{count} in der Warteschlange für Upload",
"upload_concurrency": "Parallelität beim Hochladen",
"upload_details": "Upload Details",
"upload_dialog_info": "Willst du die ausgewählten Elemente auf dem Server sichern?",
"upload_dialog_title": "Element hochladen",
"upload_errors": "Hochladen mit {count, plural, one {# Fehler} other {# Fehlern}} abgeschlossen, aktualisiere die Seite, um neu hochgeladene Dateien zu sehen.",
"upload_finished": "Upload fertig",
"upload_progress": "{remaining, number} verbleibend - {processed, number}/{total, number} verarbeitet",
"upload_skipped_duplicates": "{count, plural, one {# doppelte Datei} other {# doppelte Dateien}} ausgelassen",
"upload_status_duplicates": "Duplikate",
@@ -1891,6 +1976,7 @@
"upload_success": "Hochladen erfolgreich. Aktualisiere die Seite, um neue hochgeladene Dateien zu sehen.",
"upload_to_immich": "Auf Immich hochladen ({count})",
"uploading": "Wird hochgeladen",
"uploading_media": "Medien werden hochgeladen",
"url": "URL",
"usage": "Verwendung",
"use_biometric": "Biometrie verwenden",
@@ -1911,6 +1997,7 @@
"user_usage_stats_description": "Statistiken zur Kontonutzung anzeigen",
"username": "Nutzername",
"users": "Benutzer",
"users_added_to_album_count": "{count, plural, one {# Benutzer} other {# Benutzer}} zum Album hinzugefügt",
"utilities": "Hilfsmittel",
"validate": "Validieren",
"validate_endpoint_error": "Bitte gib eine gültige URL ein",
@@ -1929,6 +2016,7 @@
"view_album": "Album anzeigen",
"view_all": "Alles anzeigen",
"view_all_users": "Alle Nutzer anzeigen",
"view_details": "Details ansehen",
"view_in_timeline": "In Zeitleiste anzeigen",
"view_link": "Link anzeigen",
"view_links": "Links anzeigen",

View File

@@ -166,6 +166,20 @@
"metadata_settings_description": "Διαχείρηση ρυθμίσεων μεταδεδομένων",
"migration_job": "Μεταφορά δεδομένων (Migration)",
"migration_job_description": "Μεταφορά των εικονιδίων για αρχεία και πρόσωπα στην πιο πρόσφατη δομή αρχείων",
"nightly_tasks_cluster_faces_setting_description": "Εκτέλεση αναγνώρισης προσώπου σε νέα ανιχνευμένα πρόσωπα",
"nightly_tasks_cluster_new_faces_setting": "Ομαδοποίηση νέων προσώπων",
"nightly_tasks_database_cleanup_setting": "Εργασίες καθαρισμού βάσης δεδομένων",
"nightly_tasks_database_cleanup_setting_description": "Εκκαθάριση παλιών και ληγμένων δεδομένων από τη βάση δεδομένων",
"nightly_tasks_generate_memories_setting": "Δημιουργία αναμνήσεων",
"nightly_tasks_generate_memories_setting_description": "Δημιουργία νέων αναμνήσεων από αντικείμενα",
"nightly_tasks_missing_thumbnails_setting": "Δημιουργία ελλειπόντων μικρογραφιών",
"nightly_tasks_missing_thumbnails_setting_description": "Τοποθέτηση στη ουρά των αρχείων χωρίς μικρογραφίες για δημιουργία μικρογραφιών",
"nightly_tasks_settings": "Ρυθμίσεις για τις νυχτερινές εργασίες",
"nightly_tasks_settings_description": "Διαχείριση νυχτερινών εργασιών",
"nightly_tasks_start_time_setting": "Ώρα έναρξης",
"nightly_tasks_start_time_setting_description": "Η ώρα κατά την οποία ο διακομιστής ξεκινάει να εκτελεί τις νυχτερινές εργασίες",
"nightly_tasks_sync_quota_usage_setting": "Συγχρονισμός χρήσης χώρου",
"nightly_tasks_sync_quota_usage_setting_description": "Ενημέρωση του διαθέσιμου χώρου χρήστη, με βάση την τρέχουσα χρήση",
"no_paths_added": "Δεν προστέθηκαν διαδρομές",
"no_pattern_added": "Δεν προστέθηκε μοτίβο",
"note_apply_storage_label_previous_assets": "Σημείωση: Για να εφαρμοστεί η Ετικέτα Αποθήκευσης σε στοιχεία που είχαν αναρτηθεί παλαιότερα, εκτέλεσε το",
@@ -196,6 +210,8 @@
"oauth_mobile_redirect_uri": "URI Ανακατεύθυνσης για κινητά τηλέφωνα",
"oauth_mobile_redirect_uri_override": "Προσπέλαση URI ανακατεύθυνσης για κινητά τηλέφωνα",
"oauth_mobile_redirect_uri_override_description": "Ενεργοποιήστε το όταν ο πάροχος OAuth δεν επιτρέπει μια URI για κινητά, όπως το ''{callback}''",
"oauth_role_claim": "Ανάθεση ρόλου",
"oauth_role_claim_description": "Αυτόματη παραχώρηση πρόσβασης διαχειριστή με βάση την ύπαρξη αυτής της ανάθεσης. Η ανάθεση μπορεί να είναι είτε 'χρήστης' είτε 'διαχειριστής'.",
"oauth_settings": "OAuth",
"oauth_settings_description": "Διαχείριση ρυθμίσεων σύνδεσης OAuth",
"oauth_settings_more_details": "Για περισσότερες λεπτομέρειες σχετικά με αυτήν τη δυνατότητα, ανατρέξτε στην <link>τεκμηρίωση</link>.",
@@ -357,10 +373,12 @@
"admin_password": "Κωδικός πρόσβασης Διαχειριστή",
"administration": "Διαχείριση",
"advanced": "Για προχωρημένους",
"advanced_settings_beta_timeline_subtitle": "Δοκίμασε τη νέα εμπειρία της εφαρμογής",
"advanced_settings_beta_timeline_title": "Δοκιμαστικό χρονολόγιο",
"advanced_settings_enable_alternate_media_filter_subtitle": "Χρησιμοποιήστε αυτήν την επιλογή για να φιλτράρετε τα μέσα ενημέρωσης κατά τον συγχρονισμό με βάση εναλλακτικά κριτήρια. Δοκιμάστε αυτή τη δυνατότητα μόνο αν έχετε προβλήματα με την εφαρμογή που εντοπίζει όλα τα άλμπουμ.",
"advanced_settings_enable_alternate_media_filter_title": "[ΠΕΙΡΑΜΑΤΙΚΟ] Χρήση εναλλακτικού φίλτρου συγχρονισμού άλμπουμ συσκευής",
"advanced_settings_log_level_title": "Επίπεδο σύνδεσης: {level}",
"advanced_settings_prefer_remote_subtitle": "Μερικές συσκευές αργούν πολύ να φορτώσουν μικρογραφίες από αρχεία στη συσκευή. Ενεργοποιήστε αυτήν τη ρύθμιση για να φορτώνονται αντί αυτού απομακρυσμένες εικόνες.",
"advanced_settings_prefer_remote_subtitle": "Μερικές συσκευές αργούν πολύ να φορτώσουν μικρογραφίες από τοπικά αρχεία. Ενεργοποιήστε αυτήν τη ρύθμιση για να φορτώνονται αντί αυτού απομακρυσμένες εικόνες.",
"advanced_settings_prefer_remote_title": "Προτίμηση απομακρυσμένων εικόνων",
"advanced_settings_proxy_headers_subtitle": "Καθορισμός κεφαλίδων διακομιστή μεσολάβησης που το Immich πρέπει να στέλνει με κάθε αίτημα δικτύου",
"advanced_settings_proxy_headers_title": "Κεφαλίδες διακομιστή μεσολάβησης",
@@ -379,6 +397,7 @@
"album_cover_updated": "Το εξώφυλλο του άλμπουμ, ενημερώθηκε",
"album_delete_confirmation": "Είστε σίγουροι ότι θέλετε να διαγράψετε το άλμπουμ {album};",
"album_delete_confirmation_description": "Εάν αυτό το άλμπουμ είναι κοινόχρηστο, οι άλλοι χρήστες δεν θα μπορούν να έχουν πρόσβαση.",
"album_deleted": "Το άλμπουμ διαγράφηκε",
"album_info_card_backup_album_excluded": "ΕΞΑΙΡΟΥΜΕΝΟ",
"album_info_card_backup_album_included": "ΣΥΜΠΕΡΙΛΑΜΒΑΝΟΜΕΝΟ",
"album_info_updated": "Οι πληροφορίες του άλμπουμ, ενημερώθηκαν",
@@ -388,6 +407,7 @@
"album_options": "Επιλογές άλμπουμ",
"album_remove_user": "Διαγραφή χρήστη;",
"album_remove_user_confirmation": "Είστε σίγουροι ότι θέλετε να αφαιρέσετε τον/την {user};",
"album_search_not_found": "Δε βρέθηκαν άλμπουμ που να ταιριάζουν με την αναζήτησή σας",
"album_share_no_users": "Φαίνεται ότι έχετε κοινοποιήσει αυτό το άλμπουμ σε όλους τους χρήστες ή δεν έχετε χρήστες για να το κοινοποιήσετε.",
"album_updated": "Το άλμπουμ, ενημερώθηκε",
"album_updated_setting_description": "Λάβετε ειδοποίηση μέσω email όταν ένα κοινόχρηστο άλμπουμ έχει νέα αρχεία",
@@ -407,6 +427,7 @@
"albums_default_sort_order": "Προεπιλεγμένη ταξινόμηση άλμπουμ",
"albums_default_sort_order_description": "Αρχική ταξινόμηση κατά τη δημιουργία νέων άλμπουμ.",
"albums_feature_description": "Συλλογές στοιχείων που μπορούν να κοινοποιηθούν σε άλλους χρήστες.",
"albums_on_device_count": "Άλμπουμ στη συσκευή ({count})",
"all": "Όλα",
"all_albums": "Όλα τα άλμπουμ",
"all_people": "Όλα τα άτομα",
@@ -427,6 +448,7 @@
"app_settings": "Ρυθμίσεις εφαρμογής",
"appears_in": "Εμφανίζεται σε",
"archive": "Αρχείο",
"archive_action_prompt": "Προστέθηκαν {count} στο Αρχείο",
"archive_or_unarchive_photo": "Αρχειοθέτηση ή αποαρχειοθέτηση φωτογραφίας",
"archive_page_no_archived_assets": "Δε βρέθηκαν αρχειοθετημένα στοιχεία",
"archive_page_title": "Αρχείο ({count})",
@@ -464,7 +486,6 @@
"assets": "Αντικείμενα",
"assets_added_count": "Προστέθηκε {count, plural, one {# αρχείο} other {# αρχεία}}",
"assets_added_to_album_count": "Προστέθηκε {count, plural, one {# αρχείο} other {# αρχεία}} στο άλμπουμ",
"assets_added_to_name_count": "Προστέθηκε {count, plural, one {# αρχείο} other {# αρχεία}} στο {hasName, select, true {<b>{name}</b>} other {νέο άλμπουμ}}",
"assets_cannot_be_added_to_album_count": "{count, plural, one {Στοιχείο} other {Στοιχεία}} δεν μπορούν να προστεθούν στο άλμπουμ",
"assets_count": "{count, plural, one {# αρχείο} other {# αρχεία}}",
"assets_deleted_permanently": "{count} τα στοιχεία διαγράφηκαν οριστικά",
@@ -490,6 +511,7 @@
"back_close_deselect": "Πίσω, κλείσιμο ή αποεπιλογή",
"background_location_permission": "Άδεια τοποθεσίας στο παρασκήνιο",
"background_location_permission_content": "Το Immich για να μπορεί να αλλάζει δίκτυα όταν τρέχει στο παρασκήνιο, πρέπει *πάντα* να έχει πρόσβαση στην ακριβή τοποθεσία ώστε η εφαρμογή να μπορεί να διαβάζει το όνομα του δικτύου Wi-Fi",
"backup": "Αντίγραφα ασφαλείας",
"backup_album_selection_page_albums_device": "Άλμπουμ στη συσκευή ({count})",
"backup_album_selection_page_albums_tap": "Πάτημα για συμπερίληψη, διπλό πάτημα για εξαίρεση",
"backup_album_selection_page_assets_scatter": "Τα στοιχεία μπορεί να διασκορπιστούν σε πολλά άλμπουμ. Έτσι, τα άλμπουμ μπορούν να περιληφθούν ή να εξαιρεθούν κατά τη διαδικασία δημιουργίας αντιγράφων ασφαλείας.",
@@ -553,6 +575,8 @@
"backup_options_page_title": "Επιλογές αντιγράφων ασφαλείας",
"backup_setting_subtitle": "Διαχείριση ρυθμίσεων μεταφόρτωσης στο παρασκήνιο και στο προσκήνιο",
"backward": "Προς τα πίσω",
"beta_sync": "Κατάσταση Συγχρονισμού Beta (δοκιμαστική)",
"beta_sync_subtitle": "Διαχείριση του νέου συστήματος συγχρονισμού",
"biometric_auth_enabled": "Βιομετρική ταυτοποίηση ενεργοποιήθηκε",
"biometric_locked_out": "Είστε κλειδωμένοι εκτός της βιομετρικής ταυτοποίησης",
"biometric_no_options": "Δεν υπάρχουν διαθέσιμοι τρόποι βιομετρικής ταυτοποίησης",
@@ -587,6 +611,7 @@
"cancel": "Ακύρωση",
"cancel_search": "Ακύρωση αναζήτησης",
"canceled": "Ακυρωμένο",
"canceling": "Ακυρώνεται",
"cannot_merge_people": "Αδύνατη η συγχώνευση ατόμων",
"cannot_undo_this_action": "Δεν μπορείτε να αναιρέσετε αυτήν την ενέργεια!",
"cannot_update_the_description": "Αδύνατη η ενημέρωση της περιγραφής",
@@ -700,10 +725,11 @@
"current_server_address": "Τρέχουσα διεύθυνση διακομιστή",
"custom_locale": "Προσαρμοσμένη Τοπική Ρύθμιση",
"custom_locale_description": "Μορφοποιήστε τις ημερομηνίες και τους αριθμούς, σύμφωνα με τη γλώσσα και την περιοχή",
"custom_url": "Προσαρμοσμένη διεύθυνση URL",
"daily_title_text_date": "Ε, MMM dd",
"daily_title_text_date_year": "Ε, MMM dd, yyyy",
"dark": "Σκούρο",
"darkTheme": "Εναλλαγή σκούρου θέματος",
"dark_theme": "Εναλλαγή σκοτεινής εμφάνισης",
"date_after": "Ημερομηνία μετά",
"date_and_time": "Ημερομηνία και ώρα",
"date_before": "Ημερομηνία πριν",
@@ -719,6 +745,8 @@
"default_locale": "Προεπιλεγμένη Τοπική Ρύθμιση",
"default_locale_description": "Μορφοποιήστε τις ημερομηνίες και τους αριθμούς με βάση την τοπική ρύθμιση του προγράμματος περιήγησής σας",
"delete": "Διαγραφή",
"delete_action_confirmation_message": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το αρχείο; Αυτή η ενέργεια θα το μετακινήσει στον κάδο απορριμμάτων του διακομιστή και θα εμφανιστεί μήνυμα για το αν θέλετε να το διαγράψετε και τοπικά",
"delete_action_prompt": "{count} διαγράφηκαν",
"delete_album": "Διαγραφή άλμπουμ",
"delete_api_key_prompt": "Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό κλειδί API;",
"delete_dialog_alert": "Αυτά τα αντικείμενα θα διαγραφούν οριστικά από το Immich και από τη συσκευή σας",
@@ -732,9 +760,12 @@
"delete_key": "Διαγραφή κλειδιού",
"delete_library": "Διαγραφή Βιβλιοθήκης",
"delete_link": "Διαγραφή συνδέσμου",
"delete_local_action_prompt": "{count} διαγράφηκαν τοπικά",
"delete_local_dialog_ok_backed_up_only": "Διαγραφή μόνο των αντιγράφων ασφαλείας",
"delete_local_dialog_ok_force": "Διαγραφή όπως και να έχει",
"delete_others": "Διαγραφή υπολοίπων",
"delete_permanently": "Διαγραφή οριστικά",
"delete_permanently_action_prompt": "{count} διαγράφηκε οριστικά",
"delete_shared_link": "Διαγραφή κοινόχρηστου συνδέσμου",
"delete_shared_link_dialog_title": "Διαγραφή Κοινοποιημένου Συνδέσμου",
"delete_tag": "Διαγραφή ετικέτας",
@@ -745,6 +776,7 @@
"description": "Περιγραφή",
"description_input_hint_text": "Προσθήκη περιγραφής...",
"description_input_submit_error": "Σφάλμα κατά την ενημέρωση της περιγραφής, ελέγξτε το αρχείο καταγραφής για περισσότερες λεπτομέρειες",
"deselect_all": "Ακύρωση όλων των επιλογών",
"details": "Λεπτομέρειες",
"direction": "Κατεύθυνση",
"disabled": "Απενεργοποιημένο",
@@ -762,6 +794,7 @@
"documentation": "Τεκμηρίωση",
"done": "Έγινε",
"download": "Λήψη",
"download_action_prompt": "Κατέβασμα {count} στοιχείων",
"download_canceled": "Η λήψη ακυρώθηκε",
"download_complete": "Η λήψη ολοκληρώθηκε",
"download_enqueue": "Η λήψη τέθηκε σε ουρά",
@@ -799,6 +832,7 @@
"edit_key": "Επεξεργασία κλειδιού",
"edit_link": "Επεξεργασία συνδέσμου",
"edit_location": "Επεξεργασία τοποθεσίας",
"edit_location_action_prompt": "Επεξεργάστηκαν {count} τοποθεσίες",
"edit_location_dialog_title": "Τοποθεσία",
"edit_name": "Επεξεργασία ονόματος",
"edit_people": "Επεξεργασία ατόμων",
@@ -817,6 +851,7 @@
"empty_trash": "Άδειασμα κάδου απορριμμάτων",
"empty_trash_confirmation": "Είστε σίγουροι οτι θέλετε να αδειάσετε τον κάδο απορριμμάτων; Αυτό θα αφαιρέσει μόνιμα όλα τα στοιχεία του κάδου απορριμμάτων του Immich. \nΑυτή η ενέργεια δεν μπορεί να αναιρεθεί!",
"enable": "Ενεργοποίηση",
"enable_backup": "Ενεργοποίηση αντιγράφου ασφαλείας",
"enable_biometric_auth_description": "Εισάγετε τον κωδικό PIN σας για να ενεργοποιήσετε την βιομετρική ταυτοποίηση",
"enabled": "Ενεργοποιημένο",
"end_date": "Τελική ημερομηνία",
@@ -973,6 +1008,8 @@
"explorer": "Περιηγητής",
"export": "Εξαγωγή",
"export_as_json": "Εξαγωγή ως JSON",
"export_database": "Εξαγωγή βάσης δεδομένων",
"export_database_description": "Εξαγωγή της SQLite βάσης δεδομένων",
"extension": "Επέκταση",
"external": "Εξωτερικός",
"external_libraries": "Εξωτερικές βιβλιοθήκες",
@@ -984,6 +1021,7 @@
"failed_to_load_assets": "Αποτυχία φόρτωσης στοιχείων",
"failed_to_load_folder": "Αποτυχία φόρτωσης φακέλου",
"favorite": "Αγαπημένο",
"favorite_action_prompt": "Προστέθηκαν {count} στα Αγαπημένα",
"favorite_or_unfavorite_photo": "Ορίστε μία φωτογραφία ως αγαπημένη ή αφαιρέστε την από τα αγαπημένα",
"favorites": "Αγαπημένα",
"favorites_page_no_favorites": "Δεν βρέθηκαν αγαπημένα στοιχεία",
@@ -1023,6 +1061,9 @@
"haptic_feedback_switch": "Ενεργοποίηση απτικής ανάδρασης",
"haptic_feedback_title": "Απτική Ανάδραση",
"has_quota": "Έχει ποσόστωση",
"hash_asset": "Κατακερματισμός στοιχείου",
"hashed_assets": "Κατακερματισμένα στοιχεία",
"hashing": "Κατακερματισμός",
"header_settings_add_header_tip": "Προσθήκη Κεφαλίδας",
"header_settings_field_validator_msg": "Η τιμή δεν μπορεί να είναι κενή",
"header_settings_header_name_input": "Όνομα κεφαλίδας",
@@ -1055,6 +1096,7 @@
"host": "Φιλοξενία",
"hour": "Ώρα",
"id": "ID",
"idle": "Αδράνεια",
"ignore_icloud_photos": "Αγνοήστε τις φωτογραφίες iCloud",
"ignore_icloud_photos_description": "Οι φωτογραφίες που είναι αποθηκευμένες στο iCloud δεν θα μεταφορτωθούν στον διακομιστή Immich",
"image": "Εικόνα",
@@ -1112,6 +1154,7 @@
"language_no_results_title": "Δε βρέθηκαν γλώσσες",
"language_search_hint": "Αναζήτηση γλωσσών...",
"language_setting_description": "Επιλέξτε τη γλώσσα που προτιμάτε",
"large_files": "Μεγάλα Αρχεία",
"last_seen": "Τελευταία προβολή",
"latest_version": "Τελευταία Έκδοση",
"latitude": "Γεωγραφικό πλάτος",
@@ -1127,16 +1170,18 @@
"library_page_sort_created": "Ημερομηνία δημιουργίας",
"library_page_sort_last_modified": "Τελευταία τροποποίηση",
"library_page_sort_title": "Τίτλος άλμπουμ",
"licenses": "Άδειες",
"light": "Φωτεινό",
"like_deleted": "Το \"μου αρέσει\" διαγράφηκε",
"link_motion_video": "Σύνδεσε βίντεο κίνησης",
"link_options": "Επιλογές συνδέσμου",
"link_to_oauth": "Σύνδεση στον OAuth",
"linked_oauth_account": "Ο OAuth λογαριασμός συνδέθηκε",
"list": "Λίστα",
"loading": "Φόρτωση",
"loading_search_results_failed": "Η φόρτωση αποτελεσμάτων αναζήτησης απέτυχε",
"local": "Τοπικά",
"local_asset_cast_failed": "Αδυναμία μετάδοσης στοιχείου που δεν έχει ανέβει στον διακομιστή",
"local_assets": "Τοπικά στοιχεία",
"local_network": "Τοπικό δίκτυο",
"local_network_sheet_info": "Η εφαρμογή θα συνδεθεί με τον διακομιστή μέσω αυτού του URL όταν χρησιμοποιείται το καθορισμένο δίκτυο Wi-Fi",
"location_permission": "Άδεια τοποθεσίας",
@@ -1193,8 +1238,7 @@
"manage_your_devices": "Διαχειριστείτε τις συνδεδεμένες συσκευές σας",
"manage_your_oauth_connection": "Διαχειριστείτε τη σύνδεσή σας OAuth",
"map": "Χάρτης",
"map_assets_in_bound": "{count} φωτογραφία",
"map_assets_in_bounds": "{count} φωτογραφίες",
"map_assets_in_bounds": "{count, plural, one {# φωτογραφία} other {# φωτογραφίες}}",
"map_cannot_get_user_location": "Δεν είναι δυνατή η λήψη της τοποθεσίας του χρήστη",
"map_location_dialog_yes": "Ναι",
"map_location_picker_page_use_location": "Χρησιμοποιήστε αυτήν την τοποθεσία",
@@ -1246,6 +1290,7 @@
"more": "Περισσότερα",
"move": "Μετακίνηση",
"move_off_locked_folder": "Μετακίνηση έξω από τον κλειδωμένο φάκελο",
"move_to_lock_folder_action_prompt": "Προστέθηκαν {count} στον κλειδωμένο φάκελο",
"move_to_locked_folder": "Μετακίνηση σε κλειδωμένο φάκελο",
"move_to_locked_folder_confirmation": "Αυτές οι φωτογραφίες και τα βίντεο θα αφαιρεθούν από όλα τα άλμπουμ και θα μπορούν να προβληθούν μόνο από τον κλειδωμένο φάκελο",
"moved_to_archive": "Μετακινήθηκαν {count, plural, one {# στοιχείο} other {# στοιχεία}} στο αρχείο",
@@ -1292,6 +1337,7 @@
"no_results": "Κανένα αποτέλεσμα",
"no_results_description": "Δοκιμάστε ένα συνώνυμο ή πιο γενική λέξη-κλειδί",
"no_shared_albums_message": "Δημιουργήστε ένα άλμπουμ για να μοιράζεστε φωτογραφίες και βίντεο με άτομα στο δίκτυό σας",
"no_uploads_in_progress": "Καμία μεταφόρτωση σε εξέλιξη",
"not_in_any_album": "Σε κανένα άλμπουμ",
"not_selected": "Δεν επιλέχθηκε",
"note_apply_storage_label_to_previously_uploaded assets": "Σημείωση: Για να εφαρμόσετε την Ετικέτα Αποθήκευσης σε στοιχεία που έχουν μεταφορτωθεί προηγουμένως, εκτελέστε το",
@@ -1329,6 +1375,7 @@
"original": "πρωτότυπο",
"other": "Άλλες",
"other_devices": "Άλλες συσκευές",
"other_entities": "Άλλες οντότητες",
"other_variables": "Άλλες μεταβλητές",
"owned": "Δικά μου",
"owner": "Κάτοχος",
@@ -1460,6 +1507,7 @@
"purchase_server_description_2": "Κατάσταση υποστηρικτή",
"purchase_server_title": "Διακομιστής",
"purchase_settings_server_activated": "Η διαχείριση του κλειδιού προϊόντος του διακομιστή γίνεται από τον διαχειριστή",
"queue_status": "Τοποθέτηση στη ουρά {count} από {total}",
"rating": "Αξιολόγηση με αστέρια",
"rating_clear": "Εκκαθάριση αξιολόγησης",
"rating_count": "{count, plural, one {# αστέρι} other {# αστέρια}}",
@@ -1488,6 +1536,8 @@
"refreshing_faces": "Ανανεώνονται πρόσωπα",
"refreshing_metadata": "Τα μεταδεδομένα ανανεώνονται",
"regenerating_thumbnails": "Οι μικρογραφίες αναγεννώνται",
"remote": "Απομακρυσμένος",
"remote_assets": "Απομακρυσμένα στοιχεία",
"remove": "Αφαίρεση",
"remove_assets_album_confirmation": "Είστε σίγουροι ότι θέλετε να αφαιρέσετε {count, plural, one {# στοιχείο} other {# στοιχεία}} από το άλμπουμ;",
"remove_assets_shared_link_confirmation": "Είστε σίγουροι ότι θέλετε να αφαιρέσετε {count, plural, one {# στοιχείο} other {# στοιχεία}} από αυτόν τον κοινόχρηστο σύνδεσμο;",
@@ -1495,7 +1545,9 @@
"remove_custom_date_range": "Αφαίρεση προσαρμοσμένης χρονικής περιόδου",
"remove_deleted_assets": "Αφαίρεση Διεγραμμένων Στοιχείων",
"remove_from_album": "Αφαίρεση από το άλμπουμ",
"remove_from_album_action_prompt": "{count} αφαιρέθηκαν από το άλμπουμ",
"remove_from_favorites": "Αφαίρεση από τα αγαπημένα",
"remove_from_lock_folder_action_prompt": "{count} αφαιρέθηκαν από τον κλειδωμένο φάκελο",
"remove_from_locked_folder": "Αφαίρεση από κλειδωμένο φάκελο",
"remove_from_locked_folder_confirmation": "Είστε σίγουροι ότι θέλετε να μετακινήσετε αυτές τις φωτογραφίες και τα βίντεο από τον κλειδωμένο φάκελο; Θα είναι πλέον ορατές στη βιβλιοθήκη σας.",
"remove_from_shared_link": "Αφαίρεση από τον κοινόχρηστο σύνδεσμο",
@@ -1523,19 +1575,25 @@
"reset_password": "Επαναφορά κωδικού πρόσβασης",
"reset_people_visibility": "Επαναφορά προβολής ατόμων",
"reset_pin_code": "Επαναφορά κωδικού PIN",
"reset_sqlite": "Επαναφορά SQLite βάσης δεδομένων",
"reset_sqlite_confirmation": "Είσαι σίγουρος ότι θέλεις να επαναφέρεις τη βάση δεδομένων SQLite; Θα χρειαστεί να κάνεις αποσύνδεση και επανασύνδεση για να επανασυγχρονίσεις τα δεδομένα",
"reset_sqlite_success": "Η επαναφορά της SQLite βάσης δεδομένων ολοκληρώθηκε με επιτυχία",
"reset_to_default": "Επαναφορά στις προεπιλογές",
"resolve_duplicates": "Επίλυση διπλοτύπων",
"resolved_all_duplicates": "Επιλύθηκαν όλα τα διπλότυπα",
"restore": "Ανάκτηση",
"restore_all": "Ανάκτηση όλων",
"restore_trash_action_prompt": "{count} ανακτήθηκαν από τα απορρίμματα",
"restore_user": "Επαναφορά χρήστη",
"restored_asset": "Ανακτήθηκε το αρχείο",
"resume": "Συνέχιση",
"retry_upload": "Επανάληψη ανεβάσματος",
"review_duplicates": "Προβολή διπλότυπων",
"review_large_files": "Επισκόπηση μεγάλων αρχείων",
"role": "Ρόλος",
"role_editor": "Επεξεργαστής",
"role_viewer": "Θεατής",
"running": "Σε λειτουργία",
"save": "Αποθήκευση",
"save_to_gallery": "Αποθήκευση στη συλλογή",
"saved_api_key": "Αποθηκευμένο API key",
@@ -1667,6 +1725,7 @@
"settings_saved": "Οι ρυθμίσεις αποθηκεύτηκαν",
"setup_pin_code": "Ρύθμιση κωδικού PIN",
"share": "Κοινοποίηση",
"share_action_prompt": "Κοινή χρήση {count} στοιχείων",
"share_add_photos": "Προσθήκη φωτογραφιών",
"share_assets_selected": "{count} επιλεγμένα",
"share_dialog_preparing": "Προετοιμασία...",
@@ -1688,6 +1747,7 @@
"shared_link_clipboard_copied_massage": "Αντιγράφηκε στο πρόχειρο",
"shared_link_clipboard_text": "Σύνδεσμος: {link}\nΚωδικός πρόσβασης: {password}",
"shared_link_create_error": "Σφάλμα κατά τη δημιουργία κοινόχρηστου συνδέσμου",
"shared_link_custom_url_description": "Αποκτήστε πρόσβαση σε αυτόν τον κοινόχρηστο σύνδεσμο με μια προσαρμοσμένη διεύθυνση URL",
"shared_link_edit_description_hint": "Εισαγάγετε την περιγραφή της κοινής χρήσης",
"shared_link_edit_expire_after_option_day": "1 ημέρα",
"shared_link_edit_expire_after_option_days": "{count} ημέρες",
@@ -1713,6 +1773,7 @@
"shared_link_info_chip_metadata": "EXIF",
"shared_link_manage_links": "Διαχείριση Κοινόχρηστων Συνδέσμων",
"shared_link_options": "Επιλογές κοινόχρηστου συνδέσμου",
"shared_link_password_description": "Απαίτηση κωδικού για πρόσβαση στον κοινοποιημένο σύνδεσμο",
"shared_links": "Κοινόχρηστοι σύνδεσμοι",
"shared_links_description": "Μοιραστείτε φωτογραφίες και βίντεο με σύνδεσμο",
"shared_photos_and_videos_count": "{assetCount, plural, other {# κοινόχρηστες φωτογραφίες & βίντεο.}}",
@@ -1768,6 +1829,7 @@
"sort_title": "Τίτλος",
"source": "Πηγή",
"stack": "Στοίβα",
"stack_action_prompt": "{count} συσσωρεύτηκαν",
"stack_duplicates": "Στοίβαξη διπλότυπων",
"stack_select_one_photo": "Επιλέξτε μια κύρια φωτογραφία για τη στοίβαξη",
"stack_selected_photos": "Στοίβαγμα επιλεγμένων φωτογραφιών",
@@ -1787,6 +1849,7 @@
"storage_quota": "Ποσοστό αποθηκευτικού χώρου",
"storage_usage": "{used} από {available} σε χρήση",
"submit": "Υποβολή",
"success": "Επιτυχία",
"suggestions": "Προτάσεις",
"sunrise_on_the_beach": "Ηλιοβασίλεμα στην παραλία",
"support": "Υποστήριξη",
@@ -1796,6 +1859,8 @@
"sync": "Συγχρονισμός",
"sync_albums": "Συγχρονισμός άλμπουμ",
"sync_albums_manual_subtitle": "Συγχρονίστε όλα τα μεταφορτωμένα βίντεο και φωτογραφίες με τα επιλεγμένα εφεδρικά άλμπουμ",
"sync_local": "Τοπικός Συγχρονισμός",
"sync_remote": "Απομακρυσμένος Συγχρονισμός",
"sync_upload_album_setting_subtitle": "Δημιουργήστε και ανεβάστε τις φωτογραφίες και τα βίντεό σας στα επιλεγμένα άλμπουμ στο Immich",
"tag": "Ετικέτα",
"tag_assets": "Ετικετοποίηση στοιχείων",
@@ -1806,6 +1871,7 @@
"tag_updated": "Ενημερώθηκε η ετικέτα: {tag}",
"tagged_assets": "Ετικετοποιημένο/α {count, plural, one {# στοιχείο} other {# στοιχεία}}",
"tags": "Ετικέτες",
"tap_to_run_job": "Πατήστε για να ξεκινήσει η εργασία",
"template": "Πρότυπο",
"theme": "Θέμα",
"theme_selection": "Επιλογή θέματος",
@@ -1838,6 +1904,7 @@
"total": "Σύνολο",
"total_usage": "Συνολικη χρηση",
"trash": "Κάδος απορριμμάτων",
"trash_action_prompt": "{count} μετακινήθηκαν στα απορρίμματα",
"trash_all": "Διαγραφή Όλων",
"trash_count": "Διαγραφή {count, number}",
"trash_delete_asset": "Διαγραφή/Οριστ. Διαγραφή Αντικειμένου",
@@ -1855,9 +1922,11 @@
"unable_to_change_pin_code": "Αδυναμία αλλαγής κωδικού PIN",
"unable_to_setup_pin_code": "Αδυναμία ρύθμισης κωδικού PIN",
"unarchive": "Αναίρεση αρχειοθέτησης",
"unarchive_action_prompt": "{count} αφαιρέθηκαν από το Αρχείο",
"unarchived_count": "{count, plural, other {Αρχειοθετήσεις αναιρέθηκαν #}}",
"undo": "Αναίρεση",
"unfavorite": "Αποεπιλογή από τα αγαπημένα",
"unfavorite_action_prompt": "{count} αφαιρέθηκαν από τα Αγαπημένα",
"unhide_person": "Αναίρεση απόκρυψης ατόμου",
"unknown": "Άγνωστο",
"unknown_country": "Άγνωστη Χώρα",
@@ -1875,15 +1944,20 @@
"unselect_all_duplicates": "Αποεπιλογή όλων των διπλότυπων",
"unselect_all_in": "Αποεπιλογή όλων στο {group}",
"unstack": "Αποστοίβαξη",
"unstack_action_prompt": "{count} αποσυσσωρεύτηκαν",
"unstacked_assets_count": "Αποστοιβάξατε {count, plural, one {# στοιχείο} other {# στοιχεία}}",
"untagged": "Χωρίς ετικέτα",
"up_next": "Ακολουθεί",
"updated_at": "Ενημερωμένο",
"updated_password": "Ο κωδικός πρόσβασης ενημερώθηκε",
"upload": "Μεταφόρτωση",
"upload_action_prompt": "{count} τοποθετήθηκαν στην ουρά για μεταφόρτωση",
"upload_concurrency": "Ταυτόχρονη μεταφόρτωση",
"upload_details": "Λεπτομέρειες μεταφόρτωσης",
"upload_dialog_info": "Θέλετε να αντιγράψετε (κάνετε backup) τα επιλεγμένo(α) στοιχείο(α) στο διακομιστή;",
"upload_dialog_title": "Ανέβασμα στοιχείου",
"upload_errors": "Η μεταφόρτωση ολοκληρώθηκε με {count, plural, one {# σφάλμα} other {# σφάλματα}}, ανανεώστε τη σελίδα για να δείτε νέα στοιχεία μεταφόρτωσης.",
"upload_finished": "Ολοκλήρωση μεταφόρτωσης",
"upload_progress": "Απομένουν {remaining, number} - Ολοκληρώθηκαν {processed, number}/{total, number}",
"upload_skipped_duplicates": "Παραλείφθηκαν {count, plural, one {# διπλότυπο στοιχείο} other {# διπλότυπα στοιχεία}}",
"upload_status_duplicates": "Διπλότυπα",
@@ -1892,6 +1966,7 @@
"upload_success": "Η μεταφόρτωση ολοκληρώθηκε, ανανεώστε τη σελίδα για να δείτε τα νέα αντικείμενα.",
"upload_to_immich": "Μεταφόρτωση στο Immich ({count})",
"uploading": "Μεταφορτώνεται",
"uploading_media": "Μεταφόρτωση πολυμέσων",
"url": "URL",
"usage": "Χρήση",
"use_biometric": "Χρήση βιομετρικών στοιχείων",
@@ -1912,6 +1987,7 @@
"user_usage_stats_description": "Προβολή στατιστικών χρήσης λογαριασμού",
"username": "Όνομα Χρήστη",
"users": "Χρήστες",
"users_added_to_album_count": "Προστέθηκε {count, plural, one {# χρήστης} other {# χρήστες}} στο άλμπουμ",
"utilities": "Βοηθητικά προγράμματα",
"validate": "Επικύρωση",
"validate_endpoint_error": "Παρακαλώ εισάγετε ένα έγκυρο URL",
@@ -1930,6 +2006,7 @@
"view_album": "Προβολή Άλμπουμ",
"view_all": "Προβολή Όλων",
"view_all_users": "Προβολή όλων των χρηστών",
"view_details": "Προβολή Λεπτομερειών",
"view_in_timeline": "Προβολή στο χρονοδιάγραμμα",
"view_link": "Προβολή σύνδεσμου",
"view_links": "Προβολή συνδέσμων",

View File

@@ -14,6 +14,7 @@
"add_a_location": "Add a location",
"add_a_name": "Add a name",
"add_a_title": "Add a title",
"add_birthday": "Add a birthday",
"add_endpoint": "Add endpoint",
"add_exclusion_pattern": "Add exclusion pattern",
"add_import_path": "Add import path",
@@ -44,6 +45,13 @@
"backup_database": "Create Database Dump",
"backup_database_enable_description": "Enable database dumps",
"backup_keep_last_amount": "Amount of previous dumps to keep",
"backup_onboarding_1_description": "offsite copy in the cloud or at another physical location.",
"backup_onboarding_2_description": "local copies on different devices. This includes the main files and a backup of those files locally.",
"backup_onboarding_3_description": "total copies of your data, including the original files. This includes 1 offsite copy and 2 local copies.",
"backup_onboarding_description": "A <backblaze-link>3-2-1 backup strategy</backblaze-link> is recommended to protect your data. You should keep copies of your uploaded photos/videos as well as the Immich database for a comprehensive backup solution.",
"backup_onboarding_footer": "For more information about backing up Immich, please refer to the <link>documentation</link>.",
"backup_onboarding_parts_title": "A 3-2-1 backup includes:",
"backup_onboarding_title": "Backups",
"backup_settings": "Database Dump Settings",
"backup_settings_description": "Manage database dump settings.",
"cleared_jobs": "Cleared jobs for: {job}",
@@ -166,6 +174,20 @@
"metadata_settings_description": "Manage metadata settings",
"migration_job": "Migration",
"migration_job_description": "Migrate thumbnails for assets and faces to the latest folder structure",
"nightly_tasks_cluster_faces_setting_description": "Run facial recognition on newly detected faces",
"nightly_tasks_cluster_new_faces_setting": "Cluster new faces",
"nightly_tasks_database_cleanup_setting": "Database cleanup tasks",
"nightly_tasks_database_cleanup_setting_description": "Clean up old, expired data from the database",
"nightly_tasks_generate_memories_setting": "Generate memories",
"nightly_tasks_generate_memories_setting_description": "Create new memories from assets",
"nightly_tasks_missing_thumbnails_setting": "Generate missing thumbnails",
"nightly_tasks_missing_thumbnails_setting_description": "Queue assets without thumbnails for thumbnail generation",
"nightly_tasks_settings": "Nightly Tasks Settings",
"nightly_tasks_settings_description": "Manage nightly tasks",
"nightly_tasks_start_time_setting": "Start time",
"nightly_tasks_start_time_setting_description": "The time at which the server starts running the nightly tasks",
"nightly_tasks_sync_quota_usage_setting": "Sync quota usage",
"nightly_tasks_sync_quota_usage_setting_description": "Update user storage quota, based on current usage",
"no_paths_added": "No paths added",
"no_pattern_added": "No pattern added",
"note_apply_storage_label_previous_assets": "Note: To apply the Storage Label to previously uploaded assets, run the",
@@ -196,6 +218,8 @@
"oauth_mobile_redirect_uri": "Mobile redirect URI",
"oauth_mobile_redirect_uri_override": "Mobile redirect URI override",
"oauth_mobile_redirect_uri_override_description": "Enable when OAuth provider does not allow a mobile URI, like ''{callback}''",
"oauth_role_claim": "Role Claim",
"oauth_role_claim_description": "Automatically grant admin access based on the presence of this claim. The claim may have either 'user' or 'admin'.",
"oauth_settings": "OAuth",
"oauth_settings_description": "Manage OAuth login settings",
"oauth_settings_more_details": "For more details about this feature, refer to the <link>docs</link>.",
@@ -357,10 +381,12 @@
"admin_password": "Admin Password",
"administration": "Administration",
"advanced": "Advanced",
"advanced_settings_beta_timeline_subtitle": "Try the new app experience",
"advanced_settings_beta_timeline_title": "Beta Timeline",
"advanced_settings_enable_alternate_media_filter_subtitle": "Use this option to filter media during sync based on alternate criteria. Only try this if you have issues with the app detecting all albums.",
"advanced_settings_enable_alternate_media_filter_title": "[EXPERIMENTAL] Use alternate device album sync filter",
"advanced_settings_log_level_title": "Log level: {level}",
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from assets on the device. Activate this setting to load remote images instead.",
"advanced_settings_prefer_remote_subtitle": "Some devices are painfully slow to load thumbnails from local assets. Activate this setting to load remote images instead.",
"advanced_settings_prefer_remote_title": "Prefer remote images",
"advanced_settings_proxy_headers_subtitle": "Define proxy headers Immich should send with each network request",
"advanced_settings_proxy_headers_title": "Proxy Headers",
@@ -379,6 +405,7 @@
"album_cover_updated": "Album cover updated",
"album_delete_confirmation": "Are you sure you want to delete the album {album}?",
"album_delete_confirmation_description": "If this album is shared, other users will not be able to access it anymore.",
"album_deleted": "Album deleted",
"album_info_card_backup_album_excluded": "EXCLUDED",
"album_info_card_backup_album_included": "INCLUDED",
"album_info_updated": "Album info updated",
@@ -388,6 +415,7 @@
"album_options": "Album options",
"album_remove_user": "Remove user?",
"album_remove_user_confirmation": "Are you sure you want to remove {user}?",
"album_search_not_found": "No albums found matching your search",
"album_share_no_users": "Looks like you have shared this album with all users or you don't have any user to share with.",
"album_updated": "Album updated",
"album_updated_setting_description": "Receive an email notification when a shared album has new assets",
@@ -407,6 +435,7 @@
"albums_default_sort_order": "Default album sort order",
"albums_default_sort_order_description": "Initial asset sort order when creating new albums.",
"albums_feature_description": "Collections of assets that can be shared with other users.",
"albums_on_device_count": "Albums on device ({count})",
"all": "All",
"all_albums": "All albums",
"all_people": "All people",
@@ -427,6 +456,7 @@
"app_settings": "App Settings",
"appears_in": "Appears in",
"archive": "Archive",
"archive_action_prompt": "{count} added to Archive",
"archive_or_unarchive_photo": "Archive or unarchive photo",
"archive_page_no_archived_assets": "No archived assets found",
"archive_page_title": "Archive ({count})",
@@ -489,6 +519,7 @@
"back_close_deselect": "Back, close, or deselect",
"background_location_permission": "Background location permission",
"background_location_permission_content": "In order to switch networks when running in the background, Immich must *always* have precise location access so the app can read the Wi-Fi network's name",
"backup": "Backup",
"backup_album_selection_page_albums_device": "Albums on device ({count})",
"backup_album_selection_page_albums_tap": "Tap to include, double tap to exclude",
"backup_album_selection_page_assets_scatter": "Assets can scatter across multiple albums. Thus, albums can be included or excluded during the backup process.",
@@ -549,9 +580,13 @@
"backup_manual_in_progress": "Upload already in progress. Try after sometime",
"backup_manual_success": "Success",
"backup_manual_title": "Upload status",
"backup_options": "Backup Options",
"backup_options_page_title": "Backup options",
"backup_setting_subtitle": "Manage background and foreground upload settings",
"backup_settings_subtitle": "Manage upload settings",
"backward": "Backward",
"beta_sync": "Beta Sync Status",
"beta_sync_subtitle": "Manage the new sync system",
"biometric_auth_enabled": "Biometric authentication enabled",
"biometric_locked_out": "You are locked out of biometric authentication",
"biometric_no_options": "No biometric options available",
@@ -569,7 +604,7 @@
"cache_settings_clear_cache_button": "Clear cache",
"cache_settings_clear_cache_button_title": "Clears the app's cache. This will significantly impact the app's performance until the cache has rebuilt.",
"cache_settings_duplicated_assets_clear_button": "CLEAR",
"cache_settings_duplicated_assets_subtitle": "Photos and videos that are black listed by the app",
"cache_settings_duplicated_assets_subtitle": "Photos and videos that are ignore listed by the app",
"cache_settings_duplicated_assets_title": "Duplicated Assets ({count})",
"cache_settings_statistics_album": "Library thumbnails",
"cache_settings_statistics_full": "Full images",
@@ -586,6 +621,7 @@
"cancel": "Cancel",
"cancel_search": "Cancel search",
"canceled": "Canceled",
"canceling": "Canceling",
"cannot_merge_people": "Cannot merge people",
"cannot_undo_this_action": "You cannot undo this action!",
"cannot_update_the_description": "Cannot update the description",
@@ -617,6 +653,7 @@
"clear": "Clear",
"clear_all": "Clear all",
"clear_all_recent_searches": "Clear all recent searches",
"clear_file_cache": "Clear File Cache",
"clear_message": "Clear message",
"clear_value": "Clear value",
"client_cert_dialog_msg_confirm": "OK",
@@ -687,6 +724,7 @@
"create_new_user": "Create new user",
"create_shared_album_page_share_add_assets": "ADD ASSETS",
"create_shared_album_page_share_select_photos": "Select Photos",
"create_shared_link": "Create shared link",
"create_tag": "Create tag",
"create_tag_description": "Create a new tag. For nested tags, please enter the full path of the tag including forward slashes.",
"create_user": "Create user",
@@ -699,10 +737,11 @@
"current_server_address": "Current server address",
"custom_locale": "Custom Locale",
"custom_locale_description": "Format dates and numbers based on the language and the region",
"custom_url": "Custom URL",
"daily_title_text_date": "E, MMM dd",
"daily_title_text_date_year": "E, MMM dd, yyyy",
"dark": "Dark",
"darkTheme": "Toggle dark theme",
"dark_theme": "Toggle dark theme",
"date_after": "Date after",
"date_and_time": "Date and Time",
"date_before": "Date before",
@@ -718,6 +757,8 @@
"default_locale": "Default Locale",
"default_locale_description": "Format dates and numbers based on your browser locale",
"delete": "Delete",
"delete_action_confirmation_message": "Are you sure you want to delete this asset? This action will move the asset to the server's trash and will prompt if you want to delete it locally",
"delete_action_prompt": "{count} deleted",
"delete_album": "Delete album",
"delete_api_key_prompt": "Are you sure you want to delete this API key?",
"delete_dialog_alert": "These items will be permanently deleted from Immich and from your device",
@@ -731,9 +772,12 @@
"delete_key": "Delete key",
"delete_library": "Delete Library",
"delete_link": "Delete link",
"delete_local_action_prompt": "{count} deleted locally",
"delete_local_dialog_ok_backed_up_only": "Delete Backed Up Only",
"delete_local_dialog_ok_force": "Delete Anyway",
"delete_others": "Delete others",
"delete_permanently": "Delete permanently",
"delete_permanently_action_prompt": "{count} deleted permanently",
"delete_shared_link": "Delete shared link",
"delete_shared_link_dialog_title": "Delete Shared Link",
"delete_tag": "Delete tag",
@@ -744,6 +788,7 @@
"description": "Description",
"description_input_hint_text": "Add description...",
"description_input_submit_error": "Error updating description, check the log for more details",
"deselect_all": "Deselect All",
"details": "Details",
"direction": "Direction",
"disabled": "Disabled",
@@ -761,6 +806,7 @@
"documentation": "Documentation",
"done": "Done",
"download": "Download",
"download_action_prompt": "Downloading {count} assets",
"download_canceled": "Download canceled",
"download_complete": "Download complete",
"download_enqueue": "Download enqueued",
@@ -787,8 +833,10 @@
"edit": "Edit",
"edit_album": "Edit album",
"edit_avatar": "Edit avatar",
"edit_birthday": "Edit Birthday",
"edit_date": "Edit date",
"edit_date_and_time": "Edit date and time",
"edit_date_and_time_action_prompt": "{count} date and time edited",
"edit_description": "Edit description",
"edit_description_prompt": "Please select a new description:",
"edit_exclusion_pattern": "Edit exclusion pattern",
@@ -798,6 +846,7 @@
"edit_key": "Edit key",
"edit_link": "Edit link",
"edit_location": "Edit location",
"edit_location_action_prompt": "{count} location edited",
"edit_location_dialog_title": "Location",
"edit_name": "Edit name",
"edit_people": "Edit people",
@@ -816,6 +865,7 @@
"empty_trash": "Empty trash",
"empty_trash_confirmation": "Are you sure you want to empty the trash? This will remove all the assets in trash permanently from Immich.\nYou cannot undo this action!",
"enable": "Enable",
"enable_backup": "Enable Backup",
"enable_biometric_auth_description": "Enter your PIN code to enable biometric authentication",
"enabled": "Enabled",
"end_date": "End date",
@@ -952,6 +1002,7 @@
},
"exif": "Exif",
"exif_bottom_sheet_description": "Add Description...",
"exif_bottom_sheet_description_error": "Error updating description",
"exif_bottom_sheet_details": "DETAILS",
"exif_bottom_sheet_location": "LOCATION",
"exif_bottom_sheet_people": "PEOPLE",
@@ -972,6 +1023,8 @@
"explorer": "Explorer",
"export": "Export",
"export_as_json": "Export as JSON",
"export_database": "Export Database",
"export_database_description": "Export the SQLite database",
"extension": "Extension",
"external": "External",
"external_libraries": "External Libraries",
@@ -983,6 +1036,7 @@
"failed_to_load_assets": "Failed to load assets",
"failed_to_load_folder": "Failed to load folder",
"favorite": "Favorite",
"favorite_action_prompt": "{count} added to Favorites",
"favorite_or_unfavorite_photo": "Favorite or unfavorite photo",
"favorites": "Favorites",
"favorites_page_no_favorites": "No favorite assets found",
@@ -1022,6 +1076,9 @@
"haptic_feedback_switch": "Enable haptic feedback",
"haptic_feedback_title": "Haptic Feedback",
"has_quota": "Has quota",
"hash_asset": "Hash asset",
"hashed_assets": "Hashed assets",
"hashing": "Hashing",
"header_settings_add_header_tip": "Add Header",
"header_settings_field_validator_msg": "Value cannot be empty",
"header_settings_header_name_input": "Header name",
@@ -1054,6 +1111,7 @@
"host": "Host",
"hour": "Hour",
"id": "ID",
"idle": "Idle",
"ignore_icloud_photos": "Ignore iCloud photos",
"ignore_icloud_photos_description": "Photos that are stored on iCloud will not be uploaded to the Immich server",
"image": "Image",
@@ -1111,10 +1169,12 @@
"language_no_results_title": "No languages found",
"language_search_hint": "Search languages...",
"language_setting_description": "Select your preferred language",
"large_files": "Large Files",
"last_seen": "Last seen",
"latest_version": "Latest Version",
"latitude": "Latitude",
"leave": "Leave",
"leave_album": "Leave album",
"lens_model": "Lens model",
"let_others_respond": "Let others respond",
"level": "Level",
@@ -1126,16 +1186,18 @@
"library_page_sort_created": "Created date",
"library_page_sort_last_modified": "Last modified",
"library_page_sort_title": "Album title",
"licenses": "Licenses",
"light": "Light",
"like_deleted": "Like deleted",
"link_motion_video": "Link motion video",
"link_options": "Link options",
"link_to_oauth": "Link to OAuth",
"linked_oauth_account": "Linked OAuth account",
"list": "List",
"loading": "Loading",
"loading_search_results_failed": "Loading search results failed",
"local": "Local",
"local_asset_cast_failed": "Unable to cast an asset that is not uploaded to the server",
"local_assets": "Local Assets",
"local_network": "Local network",
"local_network_sheet_info": "The app will connect to the server through this URL when using the specified Wi-Fi network",
"location_permission": "Location permission",
@@ -1192,8 +1254,7 @@
"manage_your_devices": "Manage your logged-in devices",
"manage_your_oauth_connection": "Manage your OAuth connection",
"map": "Map",
"map_assets_in_bound": "{count} photo",
"map_assets_in_bounds": "{count} photos",
"map_assets_in_bounds": "{count, plural, =0 {No photos in this area} one {# photo} other {# photos}}",
"map_cannot_get_user_location": "Cannot get user's location",
"map_location_dialog_yes": "Yes",
"map_location_picker_page_use_location": "Use this location",
@@ -1201,7 +1262,6 @@
"map_location_service_disabled_title": "Location Service disabled",
"map_marker_for_images": "Map marker for images taken in {city}, {country}",
"map_marker_with_image": "Map marker with image",
"map_no_assets_in_bounds": "No photos in this area",
"map_no_location_permission_content": "Location permission is needed to display assets from your current location. Do you want to allow it now?",
"map_no_location_permission_title": "Location Permission denied",
"map_settings": "Map settings",
@@ -1245,6 +1305,7 @@
"more": "More",
"move": "Move",
"move_off_locked_folder": "Move out of locked folder",
"move_to_lock_folder_action_prompt": "{count} added to the locked folder",
"move_to_locked_folder": "Move to locked folder",
"move_to_locked_folder_confirmation": "These photos and video will be removed from all albums, and only viewable from the locked folder",
"moved_to_archive": "Moved {count, plural, one {# asset} other {# assets}} to archive",
@@ -1256,6 +1317,9 @@
"my_albums": "My albums",
"name": "Name",
"name_or_nickname": "Name or nickname",
"network_requirement_photos_upload": "Use cellular data to backup photos",
"network_requirement_videos_upload": "Use cellular data to backup videos",
"network_requirements_updated": "Network requirements changed, resetting backup queue",
"networking_settings": "Networking",
"networking_subtitle": "Manage the server endpoint settings",
"never": "Never",
@@ -1291,6 +1355,7 @@
"no_results": "No results",
"no_results_description": "Try a synonym or more general keyword",
"no_shared_albums_message": "Create an album to share photos and videos with people in your network",
"no_uploads_in_progress": "No uploads in progress",
"not_in_any_album": "Not in any album",
"not_selected": "Not selected",
"note_apply_storage_label_to_previously_uploaded assets": "Note: To apply the Storage Label to previously uploaded assets, run the",
@@ -1328,6 +1393,7 @@
"original": "original",
"other": "Other",
"other_devices": "Other devices",
"other_entities": "Other entities",
"other_variables": "Other variables",
"owned": "Owned",
"owner": "Owner",
@@ -1459,6 +1525,7 @@
"purchase_server_description_2": "Supporter status",
"purchase_server_title": "Server",
"purchase_settings_server_activated": "The server product key is managed by the admin",
"queue_status": "Queuing {count}/{total}",
"rating": "Star rating",
"rating_clear": "Clear rating",
"rating_count": "{count, plural, one {# star} other {# stars}}",
@@ -1487,6 +1554,8 @@
"refreshing_faces": "Refreshing faces",
"refreshing_metadata": "Refreshing metadata",
"regenerating_thumbnails": "Regenerating thumbnails",
"remote": "Remote",
"remote_assets": "Remote Assets",
"remove": "Remove",
"remove_assets_album_confirmation": "Are you sure you want to remove {count, plural, one {# asset} other {# assets}} from the album?",
"remove_assets_shared_link_confirmation": "Are you sure you want to remove {count, plural, one {# asset} other {# assets}} from this shared link?",
@@ -1494,7 +1563,9 @@
"remove_custom_date_range": "Remove custom date range",
"remove_deleted_assets": "Remove Deleted Assets",
"remove_from_album": "Remove from album",
"remove_from_album_action_prompt": "{count} removed from the album",
"remove_from_favorites": "Remove from favorites",
"remove_from_lock_folder_action_prompt": "{count} removed from the locked folder",
"remove_from_locked_folder": "Remove from locked folder",
"remove_from_locked_folder_confirmation": "Are you sure you want to move these photos and videos out of the locked folder? They will be visible in your library.",
"remove_from_shared_link": "Remove from shared link",
@@ -1522,19 +1593,25 @@
"reset_password": "Reset password",
"reset_people_visibility": "Reset people visibility",
"reset_pin_code": "Reset PIN code",
"reset_sqlite": "Reset SQLite Database",
"reset_sqlite_confirmation": "Are you sure you want to reset the SQLite database? You will need to log out and log in again to resync the data",
"reset_sqlite_success": "Successfully reset the SQLite database",
"reset_to_default": "Reset to default",
"resolve_duplicates": "Resolve duplicates",
"resolved_all_duplicates": "Resolved all duplicates",
"restore": "Restore",
"restore_all": "Restore all",
"restore_trash_action_prompt": "{count} restored from trash",
"restore_user": "Restore user",
"restored_asset": "Restored asset",
"resume": "Resume",
"retry_upload": "Retry upload",
"review_duplicates": "Review duplicates",
"review_large_files": "Review large files",
"role": "Role",
"role_editor": "Editor",
"role_viewer": "Viewer",
"running": "Running",
"save": "Save",
"save_to_gallery": "Save to gallery",
"saved_api_key": "Saved API Key",
@@ -1666,6 +1743,7 @@
"settings_saved": "Settings saved",
"setup_pin_code": "Setup a PIN code",
"share": "Share",
"share_action_prompt": "Shared {count} assets",
"share_add_photos": "Add photos",
"share_assets_selected": "{count} selected",
"share_dialog_preparing": "Preparing...",
@@ -1687,6 +1765,7 @@
"shared_link_clipboard_copied_massage": "Copied to clipboard",
"shared_link_clipboard_text": "Link: {link}\nPassword: {password}",
"shared_link_create_error": "Error while creating shared link",
"shared_link_custom_url_description": "Access this shared link with a custom URL",
"shared_link_edit_description_hint": "Enter the share description",
"shared_link_edit_expire_after_option_day": "1 day",
"shared_link_edit_expire_after_option_days": "{count} days",
@@ -1712,6 +1791,7 @@
"shared_link_info_chip_metadata": "EXIF",
"shared_link_manage_links": "Manage Shared links",
"shared_link_options": "Shared link options",
"shared_link_password_description": "Require a password to access this shared link",
"shared_links": "Shared links",
"shared_links_description": "Share photos and videos with a link",
"shared_photos_and_videos_count": "{assetCount, plural, other {# shared photos & videos.}}",
@@ -1767,6 +1847,7 @@
"sort_title": "Title",
"source": "Source",
"stack": "Stack",
"stack_action_prompt": "{count} stacked",
"stack_duplicates": "Stack duplicates",
"stack_select_one_photo": "Select one main photo for the stack",
"stack_selected_photos": "Stack selected photos",
@@ -1786,6 +1867,7 @@
"storage_quota": "Storage Quota",
"storage_usage": "{used} of {available} used",
"submit": "Submit",
"success": "Success",
"suggestions": "Suggestions",
"sunrise_on_the_beach": "Sunrise on the beach",
"support": "Support",
@@ -1795,6 +1877,8 @@
"sync": "Sync",
"sync_albums": "Sync albums",
"sync_albums_manual_subtitle": "Sync all uploaded videos and photos to the selected backup albums",
"sync_local": "Sync Local",
"sync_remote": "Sync Remote",
"sync_upload_album_setting_subtitle": "Create and upload your photos and videos to the selected albums on Immich",
"tag": "Tag",
"tag_assets": "Tag assets",
@@ -1805,6 +1889,7 @@
"tag_updated": "Updated tag: {tag}",
"tagged_assets": "Tagged {count, plural, one {# asset} other {# assets}}",
"tags": "Tags",
"tap_to_run_job": "Tap to run job",
"template": "Template",
"theme": "Theme",
"theme_selection": "Theme selection",
@@ -1837,6 +1922,7 @@
"total": "Total",
"total_usage": "Total usage",
"trash": "Trash",
"trash_action_prompt": "{count} moved to trash",
"trash_all": "Trash All",
"trash_count": "Trash {count, number}",
"trash_delete_asset": "Trash/Delete Asset",
@@ -1854,9 +1940,11 @@
"unable_to_change_pin_code": "Unable to change PIN code",
"unable_to_setup_pin_code": "Unable to setup PIN code",
"unarchive": "Unarchive",
"unarchive_action_prompt": "{count} removed from Archive",
"unarchived_count": "{count, plural, other {Unarchived #}}",
"undo": "Undo",
"unfavorite": "Unfavorite",
"unfavorite_action_prompt": "{count} removed from Favorites",
"unhide_person": "Unhide person",
"unknown": "Unknown",
"unknown_country": "Unknown Country",
@@ -1874,15 +1962,20 @@
"unselect_all_duplicates": "Unselect all duplicates",
"unselect_all_in": "Unselect all in {group}",
"unstack": "Un-stack",
"unstack_action_prompt": "{count} unstacked",
"unstacked_assets_count": "Un-stacked {count, plural, one {# asset} other {# assets}}",
"untagged": "Untagged",
"up_next": "Up next",
"updated_at": "Updated",
"updated_password": "Updated password",
"upload": "Upload",
"upload_action_prompt": "{count} queued for upload",
"upload_concurrency": "Upload concurrency",
"upload_details": "Upload Details",
"upload_dialog_info": "Do you want to backup the selected Asset(s) to the server?",
"upload_dialog_title": "Upload Asset",
"upload_errors": "Upload completed with {count, plural, one {# error} other {# errors}}, refresh the page to see new upload assets.",
"upload_finished": "Upload finished",
"upload_progress": "Remaining {remaining, number} - Processed {processed, number}/{total, number}",
"upload_skipped_duplicates": "Skipped {count, plural, one {# duplicate asset} other {# duplicate assets}}",
"upload_status_duplicates": "Duplicates",
@@ -1891,6 +1984,7 @@
"upload_success": "Upload success, refresh the page to see new upload assets.",
"upload_to_immich": "Upload to Immich ({count})",
"uploading": "Uploading",
"uploading_media": "Uploading media",
"url": "URL",
"usage": "Usage",
"use_biometric": "Use biometric",
@@ -1911,6 +2005,7 @@
"user_usage_stats_description": "View account usage statistics",
"username": "Username",
"users": "Users",
"users_added_to_album_count": "Added {count, plural, one {# user} other {# users}} to the album",
"utilities": "Utilities",
"validate": "Validate",
"validate_endpoint_error": "Please enter a valid URL",
@@ -1929,6 +2024,7 @@
"view_album": "View Album",
"view_all": "View All",
"view_all_users": "View all users",
"view_details": "View Details",
"view_in_timeline": "View in timeline",
"view_link": "View link",
"view_links": "View links",

View File

@@ -2,7 +2,7 @@
"about": "Acerca de",
"account": "Cuenta",
"account_settings": "Ajustes de la cuenta",
"acknowledge": "De acuerdo",
"acknowledge": "Aceptar",
"action": "Acción",
"action_common_update": "Actualizar",
"actions": "Acciones",
@@ -14,13 +14,13 @@
"add_a_location": "Agregar ubicación",
"add_a_name": "Agregar nombre",
"add_a_title": "Agregar título",
"add_endpoint": "Añadir endpoint",
"add_endpoint": "Agregar endpoint",
"add_exclusion_pattern": "Agregar patrón de exclusión",
"add_import_path": "Agregar ruta de importación",
"add_location": "Agregar ubicación",
"add_more_users": "Agregar más usuarios",
"add_partner": "Agregar compañero",
"add_path": "Agregar carpeta",
"add_path": "Agregar ruta",
"add_photos": "Agregar fotos",
"add_tag": "Agregar etiqueta",
"add_to": "Agregar a…",
@@ -63,8 +63,8 @@
"exclusion_pattern_description": "Los patrones de exclusión te permiten ignorar archivos y carpetas al escanear tu biblioteca. Es útil si tienes carpetas que contienen archivos que no deseas importar, por ejemplo archivos RAW.",
"external_library_management": "Gestión de bibliotecas externas",
"face_detection": "Detección de caras",
"face_detection_description": "Detecta las caras en los activos mediante aprendizaje automático. En el caso de los vídeos, solo se tiene en cuenta la miniatura. \"Actualizar\" (re)procesará todos los elementos. \"Restablecer\" borra además todos los datos de caras actuales. \"Falta\" pone en cola los elementos que aún no se han procesado. Las caras detectadas se pondrán en cola para el reconocimiento facial una vez finalizada la detección, agrupándolos en personas existentes o nuevas.",
"facial_recognition_job_description": "Agrupa las caras detectadas en personas. Este paso se ejecuta una vez finalizada la detección de caras. \"Restablecer\" (re)agrupa todas las caras. \"Falta\" pone en cola las caras que no tienen asignada una persona.",
"face_detection_description": "Detecta las caras en los elementos mediante aprendizaje automático. En el caso de los vídeos, solo se tiene en cuenta la miniatura. \"Actualizar\" (re)procesará todos los elementos. \"Restablecer\" borra además todos los datos de caras actuales. \"Faltante\" pone en cola los elementos que aún no se han procesado. Las caras detectadas se pondrán en cola para el reconocimiento facial una vez finalizada la detección, agrupándolos en personas existentes o nuevas.",
"facial_recognition_job_description": "Agrupa las caras detectadas en personas. Este paso se realiza después de completar la detección de caras. \"Restablecer\" (re)agrupa todas las caras. \"Faltante\" pone en cola las caras que no tienen una persona asignada.",
"failed_job_command": "El comando {command} ha fallado para la tarea: {job}",
"force_delete_user_warning": "CUIDADO: Esta acción eliminará inmediatamente el usuario y todos los elementos. Esta accion no se puede deshacer y los archivos no pueden ser recuperados.",
"image_format": "Formato",
@@ -166,9 +166,23 @@
"metadata_settings_description": "Administrar la configuración de metadatos",
"migration_job": "Migración",
"migration_job_description": "Migrar miniaturas de archivos y caras a la estructura de carpetas más reciente",
"nightly_tasks_cluster_faces_setting_description": "Ejecutar reconocimiento facial en caras detectadas recientemente",
"nightly_tasks_cluster_new_faces_setting": "Agrupar caras nuevas",
"nightly_tasks_database_cleanup_setting": "Tareas de limpieza de base de datos",
"nightly_tasks_database_cleanup_setting_description": "Limpiar datos antiguos y caducados de la base de datos",
"nightly_tasks_generate_memories_setting": "Generar recuerdos",
"nightly_tasks_generate_memories_setting_description": "Crear nuevos recuerdos a partir de activos",
"nightly_tasks_missing_thumbnails_setting": "Generar miniaturas faltantes",
"nightly_tasks_missing_thumbnails_setting_description": "Poner en cola a activos sin miniaturas para la generación de miniaturas",
"nightly_tasks_settings": "Configuración de Tareas Nocturnas",
"nightly_tasks_settings_description": "Gestionar Tareas Nocturnas",
"nightly_tasks_start_time_setting": "Tiempo de inicio",
"nightly_tasks_start_time_setting_description": "El tiempo cuando el servidor comienza a ejecutar las tareas nocturnas",
"nightly_tasks_sync_quota_usage_setting": "Uso de la cuota de sincronización",
"nightly_tasks_sync_quota_usage_setting_description": "Actualizar la cuota de almacenamiento del usuario, según el uso actual",
"no_paths_added": "No se han añadido carpetas",
"no_pattern_added": "No se han añadido patrones",
"note_apply_storage_label_previous_assets": "Nota: para aplicar una Etiqueta de Almacenamiento a un elemento anteriormente cargado, lanza el",
"note_apply_storage_label_previous_assets": "Nota: para aplicar una Etiqueta de Almacenamiento a un elemento anteriormente subido, lanza el",
"note_cannot_be_changed_later": "NOTA: ¡No se puede cambiar posteriormente!",
"notification_email_from_address": "Desde",
"notification_email_from_address_description": "Dirección de correo electrónico del remitente, por ejemplo: \"Immich Photo Server <noreply@example.com>\". Asegúrate de utilizar una dirección desde la que puedas enviar correos electrónicos.",
@@ -196,6 +210,8 @@
"oauth_mobile_redirect_uri": "URI de redireccionamiento móvil",
"oauth_mobile_redirect_uri_override": "Sobreescribir URI de redirección móvil",
"oauth_mobile_redirect_uri_override_description": "Habilitar cuando el proveedor de OAuth no permite una URI móvil, como ''{callback}''",
"oauth_role_claim": "Concesión de rol",
"oauth_role_claim_description": "Otorgar acceso de administrador automáticamente según la presencia de esta concesión. La concesión puede tener \"usuario\" o \"admin\".",
"oauth_settings": "OAuth",
"oauth_settings_description": "Administrar la configuración de inicio de sesión de OAuth",
"oauth_settings_more_details": "Para más detalles acerca de esta característica, consulte la <link>documentación</link>.",
@@ -205,7 +221,7 @@
"oauth_storage_quota_claim_description": "Establezca automáticamente la cuota de almacenamiento del usuario al valor de esta solicitud.",
"oauth_storage_quota_default": "Cuota de almacenamiento predeterminada (GiB)",
"oauth_storage_quota_default_description": "Cuota en GiB que se utilizará cuando no se proporcione ninguna por defecto.",
"oauth_timeout": "Expiración de solicitud",
"oauth_timeout": "Límite de tiempo para la solicitud",
"oauth_timeout_description": "Tiempo de espera de solicitudes en milisegundos",
"password_enable_description": "Iniciar sesión con correo electrónico y contraseña",
"password_settings": "Contraseña de Acceso",
@@ -247,7 +263,7 @@
"storage_template_onboarding_description_v2": "Al habilitar esta función, los archivos se organizarán automáticamente según la plantilla definida por el usuario. Para más información, consulte la <link>documentación</link>.",
"storage_template_path_length": "Límite aproximado de la longitud de la ruta: <b>{length, number}</b>/{limit, number}",
"storage_template_settings": "Plantilla de almacenamiento",
"storage_template_settings_description": "Administrar la estructura de carpetas y el nombre de archivo del recurso cargado",
"storage_template_settings_description": "Administrar la estructura de carpetas y el nombre de archivo del recurso subido",
"storage_template_user_label": "<code>{label}</code> es la etiqueta de almacenamiento del usuario",
"system_settings": "Ajustes del Sistema",
"tag_cleanup_job": "Limpieza de etiquetas",
@@ -357,10 +373,12 @@
"admin_password": "Contraseña del Administrador",
"administration": "Administración",
"advanced": "Avanzada",
"advanced_settings_beta_timeline_subtitle": "Prueba la nueva experiencia de la aplicación",
"advanced_settings_beta_timeline_title": "Cronología beta",
"advanced_settings_enable_alternate_media_filter_subtitle": "Usa esta opción para filtrar medios durante la sincronización según criterios alternativos. Intenta esto solo si tienes problemas con que la aplicación detecte todos los álbumes.",
"advanced_settings_enable_alternate_media_filter_title": "[EXPERIMENTAL] Usar filtro alternativo de sincronización de álbumes del dispositivo",
"advanced_settings_log_level_title": "Nivel de registro: {level}",
"advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas de los elementos encontrados en el dispositivo. Activa esta opción para cargar imágenes remotas en su lugar.",
"advanced_settings_prefer_remote_subtitle": "Algunos dispositivos tardan mucho en cargar las miniaturas desde los archivos locales. Activa esta opción para cargar imágenes remotas en su lugar.",
"advanced_settings_prefer_remote_title": "Preferir imágenes remotas",
"advanced_settings_proxy_headers_subtitle": "Configura headers HTTP que Immich incluirá en cada petición de red",
"advanced_settings_proxy_headers_title": "Cabeceras Proxy",
@@ -379,6 +397,7 @@
"album_cover_updated": "Portada del álbum actualizada",
"album_delete_confirmation": "¿Estás seguro de que deseas eliminar el álbum {album}?",
"album_delete_confirmation_description": "Si este álbum se comparte, otros usuarios ya no podrán acceder a él.",
"album_deleted": "Álbum eliminado",
"album_info_card_backup_album_excluded": "EXCLUIDOS",
"album_info_card_backup_album_included": "INCLUIDOS",
"album_info_updated": "Información del álbum actualizada",
@@ -388,6 +407,7 @@
"album_options": "Opciones del Album",
"album_remove_user": "¿Eliminar usuario?",
"album_remove_user_confirmation": "¿Estás seguro de que quieres eliminar a {user}?",
"album_search_not_found": "No se encontraron álbumes que coincidan con tu búsqueda",
"album_share_no_users": "Parece que has compartido este álbum con todos los usuarios o no tienes ningún usuario con quien compartirlo.",
"album_updated": "Album actualizado",
"album_updated_setting_description": "Reciba una notificación por correo electrónico cuando un álbum compartido tenga nuevos archivos",
@@ -405,8 +425,9 @@
"albums": "Álbumes",
"albums_count": "{count, plural, one {{count, number} Álbum} other {{count, number} Álbumes}}",
"albums_default_sort_order": "Ordenación por defecto de los álbumes",
"albums_default_sort_order_description": "Orden de clasificación inicial de los activos al crear nuevos álbumes.",
"albums_feature_description": "Colecciones de activos que pueden compartirse con otros usuarios.",
"albums_default_sort_order_description": "Orden de clasificación inicial de los recursos al crear nuevos álbumes.",
"albums_feature_description": "Colecciones de recursos que pueden ser compartidos con otros usuarios.",
"albums_on_device_count": "Álbumes en el dispositivo ({count})",
"all": "Todos",
"all_albums": "Todos los albums",
"all_people": "Todas las personas",
@@ -427,6 +448,7 @@
"app_settings": "Ajustes de Aplicacion",
"appears_in": "Aparece en",
"archive": "Archivo",
"archive_action_prompt": "{count} añadidos al Archivo",
"archive_or_unarchive_photo": "Archivar o restaurar foto",
"archive_page_no_archived_assets": "No se encontraron elementos archivados",
"archive_page_title": "Archivo ({count})",
@@ -464,13 +486,12 @@
"assets": "elementos",
"assets_added_count": "Añadido {count, plural, one {# asset} other {# assets}}",
"assets_added_to_album_count": "Añadido {count, plural, one {# asset} other {# assets}} al álbum",
"assets_added_to_name_count": "Añadido {count, plural, one {# asset} other {# assets}} a {hasName, select, true {<b>{name}</b>} other {new album}}",
"assets_cannot_be_added_to_album_count": "{count, plural, one {Asset} other {Assets}} no pueden ser añadidos al album",
"assets_cannot_be_added_to_album_count": "{count, plural, one {El recurso no puede ser añadido al álbum} other {Los recursos no pueden ser añadidos al álbum}}",
"assets_count": "{count, plural, one {# activo} other {# activos}}",
"assets_deleted_permanently": "{count} elemento(s) eliminado(s) permanentemente",
"assets_deleted_permanently_from_server": "{count} recurso(s) eliminado(s) de forma permanente del servidor de Immich",
"assets_downloaded_failed": "{count, plural, one {Descargado archivo # - {error} archivo fallido} other {Descargados # archivos - {error} archivos fallidos}}",
"assets_downloaded_successfully": "{count, plural, one {Archivo # descargado correctamente} other {Archivos # descargados correctamente}}",
"assets_downloaded_failed": "{count, plural, one {# archivo descargado - {error} archivo fallido} other {# archivos descargados - {error} archivos fallidos}}",
"assets_downloaded_successfully": "{count, plural, one {# archivo descargado exitosamente} other {# archivos descargados exitosamente}}",
"assets_moved_to_trash_count": "{count, plural, one {# elemento movido} other {# elementos movidos}} a la papelera",
"assets_permanently_deleted_count": "Eliminado permanentemente {count, plural, one {# elemento} other {# elementos}}",
"assets_removed_count": "Eliminado {count, plural, one {# elemento} other {# elementos}}",
@@ -490,6 +511,7 @@
"back_close_deselect": "Atrás, cerrar o anular la selección",
"background_location_permission": "Permiso de ubicación en segundo plano",
"background_location_permission_content": "Para poder cambiar de red mientras se ejecuta en segundo plano, Immich debe tener *siempre* acceso a la ubicación precisa para que la aplicación pueda leer el nombre de la red Wi-Fi",
"backup": "Copia de Seguridad",
"backup_album_selection_page_albums_device": "Álbumes en el dispositivo ({count})",
"backup_album_selection_page_albums_tap": "Toque para incluir, doble toque para excluir",
"backup_album_selection_page_assets_scatter": "Los elementos pueden dispersarse en varios álbumes. De este modo, los álbumes pueden ser incluidos o excluidos durante el proceso de copia de seguridad.",
@@ -553,6 +575,8 @@
"backup_options_page_title": "Opciones de Copia de Seguridad",
"backup_setting_subtitle": "Administra las configuraciones de respaldo en segundo y primer plano",
"backward": "Retroceder",
"beta_sync": "Estado de Sincronización Beta",
"beta_sync_subtitle": "Administrar el nuevo sistema de sincronización",
"biometric_auth_enabled": "Autentificación biométrica habilitada",
"biometric_locked_out": "Estás bloqueado de la autentificación biométrica",
"biometric_no_options": "Sin opciones biométricas disponibles",
@@ -570,7 +594,7 @@
"cache_settings_clear_cache_button": "Borrar caché",
"cache_settings_clear_cache_button_title": "Borra la caché de la aplicación. Esto afectará significativamente el rendimiento de la aplicación hasta que se reconstruya la caché.",
"cache_settings_duplicated_assets_clear_button": "LIMPIAR",
"cache_settings_duplicated_assets_subtitle": "Fotos y vídeos en la lista negra de la app",
"cache_settings_duplicated_assets_subtitle": "Fotos y vídeos ignorados por la aplicación",
"cache_settings_duplicated_assets_title": "Elementos duplicados ({count})",
"cache_settings_statistics_album": "Miniaturas de la biblioteca",
"cache_settings_statistics_full": "Imágenes completas",
@@ -587,6 +611,7 @@
"cancel": "Cancelar",
"cancel_search": "Cancelar búsqueda",
"canceled": "Cancelado",
"canceling": "Cancelando",
"cannot_merge_people": "No se pueden fusionar personas",
"cannot_undo_this_action": "¡No puedes deshacer esta acción!",
"cannot_update_the_description": "No se puede actualizar la descripción",
@@ -700,10 +725,11 @@
"current_server_address": "Dirección actual del servidor",
"custom_locale": "Configuración regional personalizada",
"custom_locale_description": "Formatear fechas y números según el idioma y la región",
"custom_url": "URL personalizada",
"daily_title_text_date": "E dd, MMM",
"daily_title_text_date_year": "E dd de MMM, yyyy",
"dark": "Oscuro",
"darkTheme": "Activar tema oscuro",
"dark_theme": "Alternar tema oscuro",
"date_after": "Fecha posterior",
"date_and_time": "Fecha y Hora",
"date_before": "Fecha anterior",
@@ -719,12 +745,14 @@
"default_locale": "Configuración regional predeterminada",
"default_locale_description": "Formatee fechas y números según la configuración regional de su navegador",
"delete": "Eliminar",
"delete_action_confirmation_message": "¿Está seguro que desea eliminar este archivo? Esta acción lo moverá a la papelera del servidor y le preguntará si desea eliminarlo localmente",
"delete_action_prompt": "{count} eliminados",
"delete_album": "Eliminar álbum",
"delete_api_key_prompt": "¿Está seguro de que desea eliminar esta clave API?",
"delete_dialog_alert": "Estos elementos serán eliminados permanentemente de Immich y de tu dispositivo",
"delete_dialog_alert_local": "Estas imágenes van a ser borradas de tu dispositivo, pero seguirán disponibles en el servidor Immich",
"delete_dialog_alert_local_non_backed_up": "Algunas de las imágenes no tienen copia de seguridad y serán borradas de forma permanente de tu dispositivo",
"delete_dialog_alert_remote": "Estas imágenes van a ser borradas de forma permanente del servidor Immich",
"delete_dialog_alert_local": "Estos elementos se eliminarán permanente de tu dispositivo pero seguirán disponibles en el servidor de Immich",
"delete_dialog_alert_local_non_backed_up": "Algunos de los elementos no tienen copia de seguridad en Immich y serán borrados permanentemente de tu dispositivo",
"delete_dialog_alert_remote": "Estas imágenes van a ser borradas permanentemente del servidor de Immich",
"delete_dialog_ok_force": "Borrar de todos modos",
"delete_dialog_title": "Eliminar Permanentemente",
"delete_duplicates_confirmation": "¿Está seguro de que desea eliminar permanentemente estos duplicados?",
@@ -732,9 +760,12 @@
"delete_key": "Eliminar clave",
"delete_library": "Eliminar biblioteca",
"delete_link": "Eliminar enlace",
"delete_local_action_prompt": "{count} eliminados localmente",
"delete_local_dialog_ok_backed_up_only": "Borrar solo las que tengan copia de seguridad",
"delete_local_dialog_ok_force": "Borrar de todos modos",
"delete_others": "Eliminar otros",
"delete_permanently": "Eliminar permanentemente",
"delete_permanently_action_prompt": "{count} eliminados permanentemente",
"delete_shared_link": "Eliminar enlace compartido",
"delete_shared_link_dialog_title": "Eliminar enlace compartido",
"delete_tag": "Eliminar etiqueta",
@@ -745,10 +776,12 @@
"description": "Descripción",
"description_input_hint_text": "Agregar descripción...",
"description_input_submit_error": "Error al actualizar la descripción, verifica el registro para obtener más detalles",
"deselect_all": "Deseleccionar Todo",
"details": "Detalles",
"direction": "Dirección",
"disabled": "Deshabilitado",
"disallow_edits": "Bloquear edición",
"discord": "Discord",
"discover": "Descubrir",
"discovered_devices": "Dispositivos descubiertos",
"dismiss_all_errors": "Descartar todos los errores",
@@ -761,6 +794,7 @@
"documentation": "Documentación",
"done": "Hecho",
"download": "Descargar",
"download_action_prompt": "Descargando {count} archivos",
"download_canceled": "Descarga cancelada",
"download_complete": "Descarga completada",
"download_enqueue": "Descarga en cola",
@@ -798,6 +832,7 @@
"edit_key": "Editar clave",
"edit_link": "Editar enlace",
"edit_location": "Editar ubicación",
"edit_location_action_prompt": "{count} ubicaciones actualizadas",
"edit_location_dialog_title": "Ubicación",
"edit_name": "Cambiar nombre",
"edit_people": "Editar persona",
@@ -816,6 +851,7 @@
"empty_trash": "Vaciar papelera",
"empty_trash_confirmation": "¿Estás seguro de que quieres vaciar la papelera? Esto eliminará permanentemente todos los archivos de la basura de Immich.\n¡No puedes deshacer esta acción!",
"enable": "Habilitar",
"enable_backup": "Habilitar Copia de Seguridad",
"enable_biometric_auth_description": "Introduce tu código PIN para habilitar la autentificación biométrica",
"enabled": "Habilitado",
"end_date": "Fecha final",
@@ -972,6 +1008,8 @@
"explorer": "Explorador",
"export": "Exportar",
"export_as_json": "Exportar a JSON",
"export_database": "Exportar Base de Datos",
"export_database_description": "Exportar la Base de Datos SQLite",
"extension": "Extensión",
"external": "Externo",
"external_libraries": "Bibliotecas Externas",
@@ -983,6 +1021,7 @@
"failed_to_load_assets": "Error al cargar los activos",
"failed_to_load_folder": "No se pudo cargar la carpeta",
"favorite": "Favorito",
"favorite_action_prompt": "{count} añadidos a Favoritos",
"favorite_or_unfavorite_photo": "Foto favorita o no favorita",
"favorites": "Favoritos",
"favorites_page_no_favorites": "No se encontraron elementos marcados como favoritos",
@@ -1022,6 +1061,9 @@
"haptic_feedback_switch": "Activar respuesta háptica",
"haptic_feedback_title": "Respuesta Háptica",
"has_quota": "Su cuota",
"hash_asset": "Generar hash del archivo",
"hashed_assets": "Archivos con hash generado",
"hashing": "Generando hash",
"header_settings_add_header_tip": "Añadir cabecera",
"header_settings_field_validator_msg": "El valor no puede estar vacío",
"header_settings_header_name_input": "Nombre de la cabecera",
@@ -1054,6 +1096,7 @@
"host": "Host",
"hour": "Hora",
"id": "ID",
"idle": "Inactivo",
"ignore_icloud_photos": "Ignorar fotos de iCloud",
"ignore_icloud_photos_description": "Las fotos almacenadas en iCloud no se subirán a Immich",
"image": "Imagen",
@@ -1111,6 +1154,7 @@
"language_no_results_title": "No se han encontrado idiomas",
"language_search_hint": "Buscar idiomas...",
"language_setting_description": "Selecciona tu idioma preferido",
"large_files": "Archivos Grandes",
"last_seen": "Ultima vez visto",
"latest_version": "Última versión",
"latitude": "Latitud",
@@ -1126,16 +1170,18 @@
"library_page_sort_created": "Creado más recientemente",
"library_page_sort_last_modified": "Última modificación",
"library_page_sort_title": "Título del álbum",
"licenses": "Licencias",
"light": "Claro",
"like_deleted": "Me gusta eliminado",
"link_motion_video": "Enlazar vídeo en movimiento",
"link_options": "Opciones de enlace",
"link_to_oauth": "Enlace a OAuth",
"linked_oauth_account": "Cuenta OAuth vinculada",
"list": "Listar",
"loading": "Cargando",
"loading_search_results_failed": "Error al cargar los resultados de la búsqueda",
"local_asset_cast_failed": "No se puede emitir un activo que no está cargado en el servidor",
"local": "Local",
"local_asset_cast_failed": "No es posible transmitir un recurso que no está subido al servidor",
"local_assets": "Archivos Locales",
"local_network": "Red local",
"local_network_sheet_info": "La aplicación se conectará al servidor a través de esta URL cuando utilice la red Wi-Fi especificada",
"location_permission": "Permiso de ubicación",
@@ -1192,8 +1238,7 @@
"manage_your_devices": "Administre sus dispositivos conectados",
"manage_your_oauth_connection": "Administra tu conexión OAuth",
"map": "Mapa",
"map_assets_in_bound": "{count} foto",
"map_assets_in_bounds": "{count} fotos",
"map_assets_in_bounds": "{count, plural, one {# foto} other {# fotos}}",
"map_cannot_get_user_location": "No se pudo obtener la posición del usuario",
"map_location_dialog_yes": "Sí",
"map_location_picker_page_use_location": "Usar esta ubicación",
@@ -1238,13 +1283,14 @@
"merged_people_count": "Fusionada {count, plural, one {# persona} other {# personas}}",
"minimize": "Minimizar",
"minute": "Minuto",
"missing": "Perdido",
"missing": "Faltante",
"model": "Modelo",
"month": "Mes",
"monthly_title_text_date_format": "MMMM y",
"monthly_title_text_date_format": "MMMM a",
"more": "Mas",
"move": "Mover",
"move_off_locked_folder": "Mover fuera de la carpeta protegida",
"move_to_lock_folder_action_prompt": "{count} añadidos a la carpeta protegida",
"move_to_locked_folder": "Mover a la carpeta protegida",
"move_to_locked_folder_confirmation": "Estas fotos y vídeos serán eliminados de todos los álbumes y sólo podrán ser vistos desde la carpeta protegida",
"moved_to_archive": "Movido(s) {count, plural, one {# recurso} other {# recursos}} a archivo",
@@ -1277,7 +1323,7 @@
"no_archived_assets_message": "Archive fotos y videos para ocultarlos de su vista de Fotos",
"no_assets_message": "HAZ CLIC PARA SUBIR TU PRIMERA FOTO",
"no_assets_to_show": "No hay elementos a mostrar",
"no_cast_devices_found": "Dispositivos de difusión no encontrados",
"no_cast_devices_found": "No se encontraron dispositivos de transmisión",
"no_duplicates_found": "No se encontraron duplicados.",
"no_exif_info_available": "No hay información exif disponible",
"no_explore_results_message": "Sube más fotos para explorar tu colección.",
@@ -1291,6 +1337,7 @@
"no_results": "Sin resultados",
"no_results_description": "Pruebe con un sinónimo o una palabra clave más general",
"no_shared_albums_message": "Crea un álbum para compartir fotos y vídeos con personas de tu red",
"no_uploads_in_progress": "No hay cargas en progreso",
"not_in_any_album": "Sin álbum",
"not_selected": "No seleccionado",
"note_apply_storage_label_to_previously_uploaded assets": "Nota: Para aplicar la etiqueta de almacenamiento a los archivos subidos previamente, ejecute el",
@@ -1328,6 +1375,7 @@
"original": "original",
"other": "Otro",
"other_devices": "Otro dispositivo",
"other_entities": "Otras entidades",
"other_variables": "Otras variables",
"owned": "Propio",
"owner": "Propietario",
@@ -1459,6 +1507,7 @@
"purchase_server_description_2": "Estado del soporte",
"purchase_server_title": "Servidor",
"purchase_settings_server_activated": "La clave del producto del servidor la administra el administrador",
"queue_status": "Poniendo en cola {count}/{total}",
"rating": "Valoración",
"rating_clear": "Borrar calificación",
"rating_count": "{count, plural, one {# estrella} other {# estrellas}}",
@@ -1487,6 +1536,8 @@
"refreshing_faces": "Recargando caras",
"refreshing_metadata": "Recargando metadatos",
"regenerating_thumbnails": "Recargando miniaturas",
"remote": "Remoto",
"remote_assets": "Elementos remotos",
"remove": "Eliminar",
"remove_assets_album_confirmation": "¿Estás seguro que quieres eliminar {count, plural, one {# elemento} other {# elementos}} del álbum?",
"remove_assets_shared_link_confirmation": "¿Estás seguro que quieres eliminar {count, plural, one {# elemento} other {# elementos}} del enlace compartido?",
@@ -1494,7 +1545,9 @@
"remove_custom_date_range": "Eliminar intervalo de fechas personalizado",
"remove_deleted_assets": "Eliminar archivos sin conexión",
"remove_from_album": "Eliminar del álbum",
"remove_from_album_action_prompt": "{count} eliminado del álbum",
"remove_from_favorites": "Quitar de favoritos",
"remove_from_lock_folder_action_prompt": "{count} eliminado de la carpeta protegida",
"remove_from_locked_folder": "Eliminar de la carpeta protegida",
"remove_from_locked_folder_confirmation": "¿Estás seguro de que deseas mover estas fotos y vídeos fuera de la carpeta protegida? Serán visibles en tu biblioteca.",
"remove_from_shared_link": "Eliminar desde enlace compartido",
@@ -1522,19 +1575,25 @@
"reset_password": "Restablecer la contraseña",
"reset_people_visibility": "Restablecer la visibilidad de las personas",
"reset_pin_code": "Restablecer PIN",
"reset_sqlite": "Restablecer la Base de Datos SQLite",
"reset_sqlite_confirmation": "¿Estás seguro que deseas restablecer la base de datos SQLite? Deberás cerrar sesión y volver a iniciarla para resincronizar los datos",
"reset_sqlite_success": "Restablecer exitosamente la base de datos SQLite",
"reset_to_default": "Restablecer los valores predeterminados",
"resolve_duplicates": "Resolver duplicados",
"resolved_all_duplicates": "Todos los duplicados resueltos",
"restore": "Restaurar",
"restore_all": "Restaurar todo",
"restore_trash_action_prompt": "{count} restaurado de la papelera",
"restore_user": "Restaurar usuario",
"restored_asset": "Archivo restaurado",
"resume": "Continuar",
"retry_upload": "Reintentar subida",
"review_duplicates": "Revisar duplicados",
"review_large_files": "Revisar archivos grandes",
"role": "Rol",
"role_editor": "Editor",
"role_viewer": "Visor",
"running": "En ejecución",
"save": "Guardar",
"save_to_gallery": "Guardado en la galería",
"saved_api_key": "Clave API guardada",
@@ -1558,17 +1617,17 @@
"search_city": "Buscar ciudad...",
"search_country": "Buscar país...",
"search_filter_apply": "Aplicar filtros",
"search_filter_camera_title": "Elige tipo de cámara",
"search_filter_camera_title": "Elegir tipo de cámara",
"search_filter_date": "Fecha",
"search_filter_date_interval": "{start} al {end}",
"search_filter_date_title": "Selecciona un intervalo de fechas",
"search_filter_date_title": "Seleccionar un intervalo de fechas",
"search_filter_display_option_not_in_album": "No en álbum",
"search_filter_display_options": "Opciones de visualización",
"search_filter_filename": "Buscar por nombre de archivo",
"search_filter_location": "Ubicación",
"search_filter_location_title": "Seleccionar una ubicación",
"search_filter_media_type": "Tipo de archivo",
"search_filter_media_type_title": "Selecciona el tipo de archivo",
"search_filter_media_type_title": "Seleccionar el tipo de archivo",
"search_filter_people_title": "Seleccionar personas",
"search_for": "Buscar",
"search_for_existing_person": "Buscar persona existente",
@@ -1591,23 +1650,23 @@
"search_people": "Buscar personas",
"search_places": "Buscar lugar",
"search_rating": "Buscar por calificación...",
"search_result_page_new_search_hint": "Nueva Busqueda",
"search_result_page_new_search_hint": "Nueva Búsqueda",
"search_settings": "Ajustes de la búsqueda",
"search_state": "Buscar región/estado...",
"search_suggestion_list_smart_search_hint_1": "La búsqueda inteligente está habilitada por defecto, para buscar metadatos utiliza esta sintaxis ",
"search_suggestion_list_smart_search_hint_2": "m:tu-término-de-búsqueda",
"search_tags": "Buscando etiquetas...",
"search_tags": "Buscar etiquetas...",
"search_timezone": "Buscar zona horaria...",
"search_type": "Tipo de búsqueda",
"search_your_photos": "Busca tus fotos",
"searching_locales": "Buscando sitios...",
"second": "Segundo",
"see_all_people": "Ver todas las personas",
"select": "Selecciona",
"select": "Seleccionar",
"select_album_cover": "Seleccionar portada del álbum",
"select_all": "Seleccionar todo",
"select_all_duplicates": "Seleccionar todos los duplicados",
"select_all_in": "Selecciona todos en {group}",
"select_all_in": "Seleccionar todos en {group}",
"select_avatar_color": "Seleccionar color del avatar",
"select_face": "Seleccionar cara",
"select_featured_photo": "Seleccionar foto principal",
@@ -1638,7 +1697,7 @@
"set_date_of_birth": "Establecer fecha de nacimiento",
"set_profile_picture": "Establecer foto de perfil",
"set_slideshow_to_fullscreen": "Mostrar diapositivas en pantalla completa",
"set_stack_primary_asset": "Establecer como activo principal",
"set_stack_primary_asset": "Establecer como recurso principal",
"setting_image_viewer_help": "El visor de detalles carga primero la miniatura pequeña, luego carga la vista previa de tamaño mediano (si está habilitada), finalmente carga la original (si está habilitada).",
"setting_image_viewer_original_subtitle": "Activar para cargar la imagen en resolución original (¡muy grande!). Deshabilitar para reducir el consumo de datos (de red y caché).",
"setting_image_viewer_original_title": "Cargar imagen original",
@@ -1666,6 +1725,7 @@
"settings_saved": "Ajustes guardados",
"setup_pin_code": "Establecer un PIN",
"share": "Compartir",
"share_action_prompt": "{count} recursos compartidos",
"share_add_photos": "Agregar fotos",
"share_assets_selected": "{count} seleccionado(s)",
"share_dialog_preparing": "Preparando...",
@@ -1687,6 +1747,7 @@
"shared_link_clipboard_copied_massage": "Copiado al portapapeles",
"shared_link_clipboard_text": "Enlace: {link}\nContraseña: {password}",
"shared_link_create_error": "Error creando el enlace compartido",
"shared_link_custom_url_description": "Accede a este enlace compartido con una URL personalizada",
"shared_link_edit_description_hint": "Introduce la descripción del enlace",
"shared_link_edit_expire_after_option_day": "1 día",
"shared_link_edit_expire_after_option_days": "{count} días",
@@ -1712,6 +1773,7 @@
"shared_link_info_chip_metadata": "EXIF",
"shared_link_manage_links": "Administrar enlaces compartidos",
"shared_link_options": "Opciones de enlaces compartidos",
"shared_link_password_description": "Requerir una contraseña para acceder a este enlace compartido",
"shared_links": "Enlaces compartidos",
"shared_links_description": "Comparte fotos y vídeos con un enlace",
"shared_photos_and_videos_count": "{assetCount, plural, other {# Fotos y vídeos compartidos.}}",
@@ -1767,6 +1829,7 @@
"sort_title": "Título",
"source": "Origen",
"stack": "Apilar",
"stack_action_prompt": "{count} apilados",
"stack_duplicates": "Apilar duplicados",
"stack_select_one_photo": "Selecciona una imagen principal para la pila",
"stack_selected_photos": "Apilar fotos seleccionadas",
@@ -1776,7 +1839,7 @@
"start_date": "Fecha de inicio",
"state": "Estado",
"status": "Estado",
"stop_casting": "Parar difusión",
"stop_casting": "Detener transmisión",
"stop_motion_photo": "Parar foto en movimiento",
"stop_photo_sharing": "¿Dejar de compartir tus fotos?",
"stop_photo_sharing_description": "{partner} ya no podrá acceder a tus fotos.",
@@ -1786,6 +1849,7 @@
"storage_quota": "Cuota de Almacenamiento",
"storage_usage": "{used} de {available} en uso",
"submit": "Enviar",
"success": "Éxito",
"suggestions": "Sugerencias",
"sunrise_on_the_beach": "Amanecer en la playa",
"support": "Soporte",
@@ -1795,6 +1859,8 @@
"sync": "Sincronizar",
"sync_albums": "Sincronizar álbumes",
"sync_albums_manual_subtitle": "Sincroniza todos los videos y fotos subidos con los álbumes seleccionados a respaldar",
"sync_local": "Sincronización Local",
"sync_remote": "Sincronización Remota",
"sync_upload_album_setting_subtitle": "Crea y sube tus fotos y videos a los álbumes seleccionados en Immich",
"tag": "Etiqueta",
"tag_assets": "Etiquetar activos",
@@ -1805,6 +1871,7 @@
"tag_updated": "Etiqueta actualizada: {tag}",
"tagged_assets": "Etiquetado(s) {count, plural, one {# activo} other {# activos}}",
"tags": "Etiquetas",
"tap_to_run_job": "Toca para ejecutar la tarea",
"template": "Plantilla",
"theme": "Tema",
"theme_selection": "Selección de tema",
@@ -1837,6 +1904,7 @@
"total": "Total",
"total_usage": "Uso total",
"trash": "Papelera",
"trash_action_prompt": "{count} movidos a la papelera",
"trash_all": "Descartar todo",
"trash_count": "Descartar {count, number}",
"trash_delete_asset": "Borrar/Eliminar archivo",
@@ -1854,9 +1922,11 @@
"unable_to_change_pin_code": "No se ha podido cambiar el PIN",
"unable_to_setup_pin_code": "No se ha podido establecer el PIN",
"unarchive": "Desarchivar",
"unarchive_action_prompt": "{count} eliminados del archivo",
"unarchived_count": "{count, plural, one {# No archivado} other {# No archivados}}",
"undo": "Deshacer",
"unfavorite": "Retirar favorito",
"unfavorite_action_prompt": "{count} eliminados de favoritos",
"unhide_person": "Mostrar persona",
"unknown": "Desconocido",
"unknown_country": "País desconocido",
@@ -1874,15 +1944,20 @@
"unselect_all_duplicates": "Deseleccionar todos los duplicados",
"unselect_all_in": "Deselecciona todos en {group}",
"unstack": "Desapilar",
"unstack_action_prompt": "{count} desapilado(s)",
"unstacked_assets_count": "Desapilado(s) {count, plural, one {# elemento} other {# elementos}}",
"untagged": "Sin etiqueta",
"up_next": "A continuación",
"updated_at": "Actualizado",
"updated_password": "Contraseña actualizada",
"upload": "Subir",
"upload_action_prompt": "{count} en cola para carga",
"upload_concurrency": "Subidas simultáneas",
"upload_details": "Cargar Detalles",
"upload_dialog_info": "¿Quieres hacer una copia de seguridad al servidor de los elementos seleccionados?",
"upload_dialog_title": "Subir elementos",
"upload_errors": "Subida completada con {count, plural, one {# error} other {# errores}}, actualice la página para ver los nuevos recursos de la subida.",
"upload_finished": "Carga finalizada",
"upload_progress": "Restante {remaining, number} - Procesado {processed, number}/{total, number}",
"upload_skipped_duplicates": "Saltado {count, plural, one {# duplicate asset} other {# duplicate assets}}",
"upload_status_duplicates": "Duplicados",
@@ -1891,6 +1966,7 @@
"upload_success": "Subida realizada correctamente, actualice la página para ver los nuevos recursos de subida.",
"upload_to_immich": "Subir a Immich ({count})",
"uploading": "Subiendo",
"uploading_media": "Subiendo medios",
"url": "URL",
"usage": "Uso",
"use_biometric": "Uso biométrico",
@@ -1911,6 +1987,7 @@
"user_usage_stats_description": "Ver estadísticas de uso de la cuenta",
"username": "Nombre de usuario",
"users": "Usuarios",
"users_added_to_album_count": "{count, plural, one {# usuario agregado} other {# usuarios agregados}} al álbum",
"utilities": "Utilidades",
"validate": "Validar",
"validate_endpoint_error": "Por favor, introduce una URL válida",
@@ -1929,6 +2006,7 @@
"view_album": "Ver Álbum",
"view_all": "Ver todas",
"view_all_users": "Mostrar todos los usuarios",
"view_details": "Ver Detalles",
"view_in_timeline": "Mostrar en la línea de tiempo",
"view_link": "Ver enlace",
"view_links": "Mostrar enlaces",

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